The igd_combo_id_infos[] data is more than 10 years out of date with many Intel IGD devices missing from igd_combo_id_infos[]. This means that many devices that could be supported will not work with the current implementation.
For newer devices not listed in igd_combo_id_infos[], get infos from the host sysfs to enable support for the newer devices not listed in igd_combo_id_infos[]. Introduce the helper function xen_pt_get_host_pch_info to facilitate getting the necessary information from sysfs. Also, use errp in xen_igd_passthrough_isa_bridge_create to propagate errors from xen_pt_get_host_pch_info. Signed-off-by: Chuck Zmudzinski <[email protected]> --- hw/xen/xen_pt.c | 2 +- hw/xen/xen_pt_graphics.c | 82 ++++++++++++++++++++++++++++++++++++++-- include/hw/xen/xen_igd.h | 3 +- 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 0fe9c0a..474606e 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -867,7 +867,7 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) } /* Register ISA bridge for passthrough GFX. */ - xen_igd_passthrough_isa_bridge_create(s, &s->real_device); + xen_igd_passthrough_isa_bridge_create(s, &s->real_device, errp); } /* Handle real device's MMIO/PIO BARs */ diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index 7df9344..54f0d54 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -376,8 +376,75 @@ static void pt_graphics_register_types(void) } type_init(pt_graphics_register_types) +static void xen_pt_get_host_pch_info(PCIDevice *dev, uint16_t *pch_dev_id, + uint8_t *pch_rev_id, Error **errp) +{ + FILE *fp1, *fp2; + char *endptr; + char device_id[7], rev[5]; + size_t len; + const char *device = "/sys/bus/pci/devices/0000:00:1f.0/device"; + const char *revision = "/sys/bus/pci/devices/0000:00:1f.0/revision"; + unsigned long val; + + fp1 = fopen(device, "r"); + if (fp1 == NULL) { + error_setg_errno(errp, errno, "Cannot open %s", device); + return; + } + fp2 = fopen(revision, "r"); + if (fp2 == NULL) { + error_setg_errno(errp, errno, "Cannot open %s", revision); + fclose(fp1); + return; + } + + len = fread(device_id, 1, 7, fp1); + if (!len) { + error_setg(errp, "Cannot read %s", device); + fclose(fp1); + fclose(fp2); + return; + } + len = fread(rev, 1, 5, fp2); + if (!len) { + error_setg(errp, "Cannot read %s", revision); + fclose(fp1); + fclose(fp2); + return; + } + fclose(fp1); + fclose(fp2); + + val = strtoul(device_id, &endptr, 16); + if (val > 0xffff) { + error_setg(errp, "PCH device id is out of range: 0x%lx", val); + return; + } + if ((endptr > device_id) && (errno != ERANGE) && + (errno != EINVAL)) { + *pch_dev_id = (uint16_t)val; + } else { + error_setg_errno(errp, errno, "device id strtoul " + "conversion failed"); + return; + } + val = strtoul(rev, &endptr, 16); + if (val > 0xff) { + error_setg(errp, "PCH revision is out of range: 0x%lx", val); + return; + } + if ((endptr > rev) && (errno != ERANGE) && (errno != EINVAL)) { + *pch_rev_id = (uint8_t)val; + } else { + error_setg_errno(errp, errno, "revision strtoul " + "conversion failed"); + } +} + void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, - XenHostPCIDevice *dev) + XenHostPCIDevice *dev, + Error **errp) { PCIBus *bus = pci_get_bus(&s->dev); struct PCIDevice *bridge_dev; @@ -394,7 +461,16 @@ void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, } } - if (pch_dev_id == 0xffff) { + /* Newer devices get PCH infos from host sysfs */ + if ((pch_dev_id == 0xffff) || !pch_rev_id) { + xen_pt_get_host_pch_info(&s->dev, &pch_dev_id, &pch_rev_id, errp); + } + + XEN_PT_LOG(&s->dev, "PCH device id: 0x%x\n", pch_dev_id); + XEN_PT_LOG(&s->dev, "PCH revision: 0x%x\n", pch_rev_id); + + if ((pch_dev_id == 0xffff) || !pch_rev_id) { + error_setg(errp, "failed to get PCH device id or revision"); return; } @@ -406,7 +482,7 @@ void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, * Note that vendor id is always PCI_VENDOR_ID_INTEL. */ if (!bridge_dev) { - fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n"); + error_setg(errp, "set igd-passthrough-isa-bridge failed!"); return; } pci_config_set_device_id(bridge_dev->config, pch_dev_id); diff --git a/include/hw/xen/xen_igd.h b/include/hw/xen/xen_igd.h index 7ffca06..da51f09 100644 --- a/include/hw/xen/xen_igd.h +++ b/include/hw/xen/xen_igd.h @@ -22,7 +22,8 @@ uint32_t igd_read_opregion(XenPCIPassthroughState *s); void xen_igd_reserve_slot(PCIBus *pci_bus); void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val); void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, - XenHostPCIDevice *dev); + XenHostPCIDevice *dev, + Error **errp); static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev) { -- 2.52.0
