[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 11/23] xen/pt: handle PCIe Extended Capabilities Next register
The patch adds new xen_pt_ext_cap_ptr_reg_init function which is used to initialize the emulated next pcie extended capability pointer. Primary mission of this function is to have a method to selectively hide some extended capabilities from the capability linked list, skipping them by altering the Next capability pointer value. Signed-off-by: Alexey Gerasimenko <x1917x@xxxxxxxxx> Signed-off-by: Joel Upham <jupham125@xxxxxxxxx> --- hw/xen/xen_pt_config_init.c | 87 +++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 32 deletions(-) diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index 34ed9c25c5..ed36edbc4a 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -27,7 +27,10 @@ static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg, uint32_t real_offset, uint32_t *data); - +static int xen_pt_ext_cap_ptr_reg_init(XenPCIPassthroughState *s, + XenPTRegInfo *reg, + uint32_t real_offset, + uint32_t *data); /* helper */ @@ -1928,48 +1931,68 @@ out: return 0; } +#define PCIE_EXT_CAP_NEXT_SHIFT 4 +#define PCIE_EXT_CAP_VER_MASK 0xF -/************* - * Main - */ - -static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap) +static int xen_pt_ext_cap_ptr_reg_init(XenPCIPassthroughState *s, + XenPTRegInfo *reg, + uint32_t real_offset, + uint32_t *data) { - uint8_t id; - unsigned max_cap = XEN_PCI_CAP_MAX; - uint8_t pos = PCI_CAPABILITY_LIST; - uint8_t status = 0; + int i, rc; + XenHostPCIDevice *d = &s->real_device; + uint16_t reg_field; + uint16_t cur_offset, version, cap_id; + uint32_t header; - if (xen_host_pci_get_byte(&s->real_device, PCI_STATUS, &status)) { - return 0; - } - if ((status & PCI_STATUS_CAP_LIST) == 0) { - return 0; + if (real_offset < 0x0010) { + XEN_PT_ERR(&s->dev, "Incorrect PCIe extended capability offset " + "encountered: 0x%04x\n", real_offset); + return -EINVAL; } - while (max_cap--) { - if (xen_host_pci_get_byte(&s->real_device, pos, &pos)) { - break; - } - if (pos < PCI_CONFIG_HEADER_SIZE) { - break; - } + rc = xen_host_pci_get_word(d, real_offset, ®_field); + if (rc) + return rc; - pos &= ~3; - if (xen_host_pci_get_byte(&s->real_device, - pos + PCI_CAP_LIST_ID, &id)) { - break; - } + /* preserve version field */ + version = reg_field & PCIE_EXT_CAP_VER_MASK; + cur_offset = reg_field >> PCIE_EXT_CAP_NEXT_SHIFT; - if (id == 0xff) { - break; + while (cur_offset && cur_offset != 0xFFF) { + rc = xen_host_pci_get_long(d, cur_offset, &header); + if (rc) { + XEN_PT_ERR(&s->dev, "Failed to read PCIe extended capability " + "@0x%x (rc:%d)\n", cur_offset, rc); + return rc; } - if (id == cap) { - return pos; + + cap_id = PCI_EXT_CAP_ID(header); + + for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) { + uint32_t cur_grp_id = xen_pt_emu_reg_grps[i].grp_id; + + if (!IS_PCIE_EXT_CAP_ID(cur_grp_id)) + continue; + + if (xen_pt_hide_dev_cap(d, cur_grp_id)) + continue; + + if (GET_PCIE_EXT_CAP_ID(cur_grp_id) == cap_id) { + if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) + goto out; + + /* skip TYPE_HARDWIRED capability, move the ptr to next one */ + break; + } } - pos += PCI_CAP_LIST_NEXT; + /* next capability */ + cur_offset = PCI_EXT_CAP_NEXT(header); } + +out: + *data = (cur_offset << PCIE_EXT_CAP_NEXT_SHIFT) | version; return 0; } -- 2.34.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |