xref: /openbmc/qemu/hw/xen/xen_pt_graphics.c (revision 7489f7f3f81dcb776df8c1b9a9db281fc21bf05f)
179814179STiejun Chen /*
279814179STiejun Chen  * graphics passthrough
379814179STiejun Chen  */
421cbfe5fSPeter Maydell #include "qemu/osdep.h"
5da34e65cSMarkus Armbruster #include "qapi/error.h"
6*f28b958cSPhilippe Mathieu-Daudé #include "hw/xen/xen_pt.h"
7*f28b958cSPhilippe Mathieu-Daudé #include "hw/xen/xen_igd.h"
879814179STiejun Chen #include "xen-host-pci-device.h"
979814179STiejun Chen 
105cec8aa3STiejun Chen static unsigned long igd_guest_opregion;
115cec8aa3STiejun Chen static unsigned long igd_host_opregion;
125cec8aa3STiejun Chen 
135cec8aa3STiejun Chen #define XEN_PCI_INTEL_OPREGION_MASK 0xfff
145cec8aa3STiejun Chen 
1579814179STiejun Chen typedef struct VGARegion {
1679814179STiejun Chen     int type;           /* Memory or port I/O */
1779814179STiejun Chen     uint64_t guest_base_addr;
1879814179STiejun Chen     uint64_t machine_base_addr;
1979814179STiejun Chen     uint64_t size;    /* size of the region */
2079814179STiejun Chen     int rc;
2179814179STiejun Chen } VGARegion;
2279814179STiejun Chen 
2379814179STiejun Chen #define IORESOURCE_IO           0x00000100
2479814179STiejun Chen #define IORESOURCE_MEM          0x00000200
2579814179STiejun Chen 
2679814179STiejun Chen static struct VGARegion vga_args[] = {
2779814179STiejun Chen     {
2879814179STiejun Chen         .type = IORESOURCE_IO,
2979814179STiejun Chen         .guest_base_addr = 0x3B0,
3079814179STiejun Chen         .machine_base_addr = 0x3B0,
3179814179STiejun Chen         .size = 0xC,
3279814179STiejun Chen         .rc = -1,
3379814179STiejun Chen     },
3479814179STiejun Chen     {
3579814179STiejun Chen         .type = IORESOURCE_IO,
3679814179STiejun Chen         .guest_base_addr = 0x3C0,
3779814179STiejun Chen         .machine_base_addr = 0x3C0,
3879814179STiejun Chen         .size = 0x20,
3979814179STiejun Chen         .rc = -1,
4079814179STiejun Chen     },
4179814179STiejun Chen     {
4279814179STiejun Chen         .type = IORESOURCE_MEM,
4379814179STiejun Chen         .guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
4479814179STiejun Chen         .machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
4579814179STiejun Chen         .size = 0x20,
4679814179STiejun Chen         .rc = -1,
4779814179STiejun Chen     },
4879814179STiejun Chen };
4979814179STiejun Chen 
5079814179STiejun Chen /*
5179814179STiejun Chen  * register VGA resources for the domain with assigned gfx
5279814179STiejun Chen  */
xen_pt_register_vga_regions(XenHostPCIDevice * dev)5379814179STiejun Chen int xen_pt_register_vga_regions(XenHostPCIDevice *dev)
5479814179STiejun Chen {
5579814179STiejun Chen     int i = 0;
5679814179STiejun Chen 
5779814179STiejun Chen     if (!is_igd_vga_passthrough(dev)) {
5879814179STiejun Chen         return 0;
5979814179STiejun Chen     }
6079814179STiejun Chen 
6179814179STiejun Chen     for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
6279814179STiejun Chen         if (vga_args[i].type == IORESOURCE_IO) {
6379814179STiejun Chen             vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
6479814179STiejun Chen                             vga_args[i].guest_base_addr,
6579814179STiejun Chen                             vga_args[i].machine_base_addr,
6679814179STiejun Chen                             vga_args[i].size, DPCI_ADD_MAPPING);
6779814179STiejun Chen         } else {
6879814179STiejun Chen             vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
6979814179STiejun Chen                             vga_args[i].guest_base_addr,
7079814179STiejun Chen                             vga_args[i].machine_base_addr,
7179814179STiejun Chen                             vga_args[i].size, DPCI_ADD_MAPPING);
7279814179STiejun Chen         }
7379814179STiejun Chen 
7479814179STiejun Chen         if (vga_args[i].rc) {
7579814179STiejun Chen             XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n",
7679814179STiejun Chen                     vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
7779814179STiejun Chen                     vga_args[i].rc);
7879814179STiejun Chen             return vga_args[i].rc;
7979814179STiejun Chen         }
8079814179STiejun Chen     }
8179814179STiejun Chen 
8279814179STiejun Chen     return 0;
8379814179STiejun Chen }
8479814179STiejun Chen 
8579814179STiejun Chen /*
8679814179STiejun Chen  * unregister VGA resources for the domain with assigned gfx
8779814179STiejun Chen  */
xen_pt_unregister_vga_regions(XenHostPCIDevice * dev)8879814179STiejun Chen int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev)
8979814179STiejun Chen {
9079814179STiejun Chen     int i = 0;
915cec8aa3STiejun Chen     int ret = 0;
9279814179STiejun Chen 
9379814179STiejun Chen     if (!is_igd_vga_passthrough(dev)) {
9479814179STiejun Chen         return 0;
9579814179STiejun Chen     }
9679814179STiejun Chen 
9779814179STiejun Chen     for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
9879814179STiejun Chen         if (vga_args[i].type == IORESOURCE_IO) {
9979814179STiejun Chen             vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
10079814179STiejun Chen                             vga_args[i].guest_base_addr,
10179814179STiejun Chen                             vga_args[i].machine_base_addr,
10279814179STiejun Chen                             vga_args[i].size, DPCI_REMOVE_MAPPING);
10379814179STiejun Chen         } else {
10479814179STiejun Chen             vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
10579814179STiejun Chen                             vga_args[i].guest_base_addr,
10679814179STiejun Chen                             vga_args[i].machine_base_addr,
10779814179STiejun Chen                             vga_args[i].size, DPCI_REMOVE_MAPPING);
10879814179STiejun Chen         }
10979814179STiejun Chen 
11079814179STiejun Chen         if (vga_args[i].rc) {
11179814179STiejun Chen             XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n",
11279814179STiejun Chen                     vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
11379814179STiejun Chen                     vga_args[i].rc);
11479814179STiejun Chen             return vga_args[i].rc;
11579814179STiejun Chen         }
11679814179STiejun Chen     }
11779814179STiejun Chen 
1185cec8aa3STiejun Chen     if (igd_guest_opregion) {
1195cec8aa3STiejun Chen         ret = xc_domain_memory_mapping(xen_xc, xen_domid,
1205cec8aa3STiejun Chen                 (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
1215cec8aa3STiejun Chen                 (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
1225cec8aa3STiejun Chen                 3,
1235cec8aa3STiejun Chen                 DPCI_REMOVE_MAPPING);
1245cec8aa3STiejun Chen         if (ret) {
1255cec8aa3STiejun Chen             return ret;
1265cec8aa3STiejun Chen         }
1275cec8aa3STiejun Chen     }
1285cec8aa3STiejun Chen 
12979814179STiejun Chen     return 0;
13079814179STiejun Chen }
131881213f1STiejun Chen 
get_vgabios(XenPCIPassthroughState * s,int * size,XenHostPCIDevice * dev)132881213f1STiejun Chen static void *get_vgabios(XenPCIPassthroughState *s, int *size,
133881213f1STiejun Chen                        XenHostPCIDevice *dev)
134881213f1STiejun Chen {
1356dad8260SPeter Maydell     return pci_assign_dev_load_option_rom(&s->dev, size,
136881213f1STiejun Chen                                           dev->domain, dev->bus,
137881213f1STiejun Chen                                           dev->dev, dev->func);
138881213f1STiejun Chen }
139881213f1STiejun Chen 
140881213f1STiejun Chen /* Refer to Seabios. */
141881213f1STiejun Chen struct rom_header {
142881213f1STiejun Chen     uint16_t signature;
143881213f1STiejun Chen     uint8_t size;
144881213f1STiejun Chen     uint8_t initVector[4];
145881213f1STiejun Chen     uint8_t reserved[17];
146881213f1STiejun Chen     uint16_t pcioffset;
147881213f1STiejun Chen     uint16_t pnpoffset;
148881213f1STiejun Chen } __attribute__((packed));
149881213f1STiejun Chen 
150881213f1STiejun Chen struct pci_data {
151881213f1STiejun Chen     uint32_t signature;
152881213f1STiejun Chen     uint16_t vendor;
153881213f1STiejun Chen     uint16_t device;
154881213f1STiejun Chen     uint16_t vitaldata;
155881213f1STiejun Chen     uint16_t dlen;
156881213f1STiejun Chen     uint8_t drevision;
157881213f1STiejun Chen     uint8_t class_lo;
158881213f1STiejun Chen     uint16_t class_hi;
159881213f1STiejun Chen     uint16_t ilen;
160881213f1STiejun Chen     uint16_t irevision;
161881213f1STiejun Chen     uint8_t type;
162881213f1STiejun Chen     uint8_t indicator;
163881213f1STiejun Chen     uint16_t reserved;
164881213f1STiejun Chen } __attribute__((packed));
165881213f1STiejun Chen 
xen_pt_setup_vga(XenPCIPassthroughState * s,XenHostPCIDevice * dev,Error ** errp)1665226bb59SCao jin void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
1675226bb59SCao jin                      Error **errp)
168881213f1STiejun Chen {
169881213f1STiejun Chen     unsigned char *bios = NULL;
170881213f1STiejun Chen     struct rom_header *rom;
171881213f1STiejun Chen     int bios_size;
172881213f1STiejun Chen     char *c = NULL;
173881213f1STiejun Chen     char checksum = 0;
174881213f1STiejun Chen     uint32_t len = 0;
175881213f1STiejun Chen     struct pci_data *pd = NULL;
176881213f1STiejun Chen 
177881213f1STiejun Chen     if (!is_igd_vga_passthrough(dev)) {
1785226bb59SCao jin         error_setg(errp, "Need to enable igd-passthrough");
1795226bb59SCao jin         return;
180881213f1STiejun Chen     }
181881213f1STiejun Chen 
182881213f1STiejun Chen     bios = get_vgabios(s, &bios_size, dev);
183881213f1STiejun Chen     if (!bios) {
1845226bb59SCao jin         error_setg(errp, "VGA: Can't get VBIOS");
1855226bb59SCao jin         return;
186881213f1STiejun Chen     }
187881213f1STiejun Chen 
1886c4f9844SPeter Maydell     if (bios_size < sizeof(struct rom_header)) {
1896c4f9844SPeter Maydell         error_setg(errp, "VGA: VBIOS image corrupt (too small)");
1906c4f9844SPeter Maydell         return;
1916c4f9844SPeter Maydell     }
1926c4f9844SPeter Maydell 
193881213f1STiejun Chen     /* Currently we fixed this address as a primary. */
194881213f1STiejun Chen     rom = (struct rom_header *)bios;
1956c4f9844SPeter Maydell 
1966c4f9844SPeter Maydell     if (rom->pcioffset + sizeof(struct pci_data) > bios_size) {
1976c4f9844SPeter Maydell         error_setg(errp, "VGA: VBIOS image corrupt (bad pcioffset field)");
1986c4f9844SPeter Maydell         return;
1996c4f9844SPeter Maydell     }
2006c4f9844SPeter Maydell 
201881213f1STiejun Chen     pd = (void *)(bios + (unsigned char)rom->pcioffset);
202881213f1STiejun Chen 
203881213f1STiejun Chen     /* We may need to fixup Device Identification. */
204881213f1STiejun Chen     if (pd->device != s->real_device.device_id) {
205881213f1STiejun Chen         pd->device = s->real_device.device_id;
206881213f1STiejun Chen 
207881213f1STiejun Chen         len = rom->size * 512;
2086c4f9844SPeter Maydell         if (len > bios_size) {
2096c4f9844SPeter Maydell             error_setg(errp, "VGA: VBIOS image corrupt (bad size field)");
2106c4f9844SPeter Maydell             return;
2116c4f9844SPeter Maydell         }
2126c4f9844SPeter Maydell 
213881213f1STiejun Chen         /* Then adjust the bios checksum */
214881213f1STiejun Chen         for (c = (char *)bios; c < ((char *)bios + len); c++) {
215881213f1STiejun Chen             checksum += *c;
216881213f1STiejun Chen         }
217881213f1STiejun Chen         if (checksum) {
218881213f1STiejun Chen             bios[len - 1] -= checksum;
219881213f1STiejun Chen             XEN_PT_LOG(&s->dev, "vga bios checksum is adjusted %x!\n",
220881213f1STiejun Chen                        checksum);
221881213f1STiejun Chen         }
222881213f1STiejun Chen     }
223881213f1STiejun Chen 
224881213f1STiejun Chen     /* Currently we fixed this address as a primary for legacy BIOS. */
225adeefe01SPhilippe Mathieu-Daudé     cpu_physical_memory_write(0xc0000, bios, bios_size);
226881213f1STiejun Chen }
2275cec8aa3STiejun Chen 
igd_read_opregion(XenPCIPassthroughState * s)2285cec8aa3STiejun Chen uint32_t igd_read_opregion(XenPCIPassthroughState *s)
2295cec8aa3STiejun Chen {
2305cec8aa3STiejun Chen     uint32_t val = 0;
2315cec8aa3STiejun Chen 
2325cec8aa3STiejun Chen     if (!igd_guest_opregion) {
2335cec8aa3STiejun Chen         return val;
2345cec8aa3STiejun Chen     }
2355cec8aa3STiejun Chen 
2365cec8aa3STiejun Chen     val = igd_guest_opregion;
2375cec8aa3STiejun Chen 
2385cec8aa3STiejun Chen     XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val);
2395cec8aa3STiejun Chen     return val;
2405cec8aa3STiejun Chen }
2415cec8aa3STiejun Chen 
2425cec8aa3STiejun Chen #define XEN_PCI_INTEL_OPREGION_PAGES 0x3
2435cec8aa3STiejun Chen #define XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED 0x1
igd_write_opregion(XenPCIPassthroughState * s,uint32_t val)2445cec8aa3STiejun Chen void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
2455cec8aa3STiejun Chen {
2465cec8aa3STiejun Chen     int ret;
2475cec8aa3STiejun Chen 
2485cec8aa3STiejun Chen     if (igd_guest_opregion) {
2495cec8aa3STiejun Chen         XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n",
2505cec8aa3STiejun Chen                    val);
2515cec8aa3STiejun Chen         return;
2525cec8aa3STiejun Chen     }
2535cec8aa3STiejun Chen 
2545cec8aa3STiejun Chen     /* We just work with LE. */
2555cec8aa3STiejun Chen     xen_host_pci_get_block(&s->real_device, XEN_PCI_INTEL_OPREGION,
2565cec8aa3STiejun Chen             (uint8_t *)&igd_host_opregion, 4);
2575cec8aa3STiejun Chen     igd_guest_opregion = (unsigned long)(val & ~XEN_PCI_INTEL_OPREGION_MASK)
2585cec8aa3STiejun Chen                             | (igd_host_opregion & XEN_PCI_INTEL_OPREGION_MASK);
2595cec8aa3STiejun Chen 
2605cec8aa3STiejun Chen     ret = xc_domain_iomem_permission(xen_xc, xen_domid,
2615cec8aa3STiejun Chen             (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
2625cec8aa3STiejun Chen             XEN_PCI_INTEL_OPREGION_PAGES,
2635cec8aa3STiejun Chen             XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED);
2645cec8aa3STiejun Chen 
2655cec8aa3STiejun Chen     if (ret) {
2665cec8aa3STiejun Chen         XEN_PT_ERR(&s->dev, "[%d]:Can't enable to access IGD host opregion:"
2675cec8aa3STiejun Chen                     " 0x%lx.\n", ret,
2685cec8aa3STiejun Chen                     (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT)),
2695cec8aa3STiejun Chen         igd_guest_opregion = 0;
2705cec8aa3STiejun Chen         return;
2715cec8aa3STiejun Chen     }
2725cec8aa3STiejun Chen 
2735cec8aa3STiejun Chen     ret = xc_domain_memory_mapping(xen_xc, xen_domid,
2745cec8aa3STiejun Chen             (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
2755cec8aa3STiejun Chen             (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
2765cec8aa3STiejun Chen             XEN_PCI_INTEL_OPREGION_PAGES,
2775cec8aa3STiejun Chen             DPCI_ADD_MAPPING);
2785cec8aa3STiejun Chen 
2795cec8aa3STiejun Chen     if (ret) {
2805cec8aa3STiejun Chen         XEN_PT_ERR(&s->dev, "[%d]:Can't map IGD host opregion:0x%lx to"
2815cec8aa3STiejun Chen                     " guest opregion:0x%lx.\n", ret,
2825cec8aa3STiejun Chen                     (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
2835cec8aa3STiejun Chen                     (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
2845cec8aa3STiejun Chen         igd_guest_opregion = 0;
2855cec8aa3STiejun Chen         return;
2865cec8aa3STiejun Chen     }
2875cec8aa3STiejun Chen 
2885cec8aa3STiejun Chen     XEN_PT_LOG(&s->dev, "Map OpRegion: 0x%lx -> 0x%lx\n",
2895cec8aa3STiejun Chen                     (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
2905cec8aa3STiejun Chen                     (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
2915cec8aa3STiejun Chen }
2924a802736SBernhard Beschow 
2934a802736SBernhard Beschow typedef struct {
2944a802736SBernhard Beschow     uint16_t gpu_device_id;
2954a802736SBernhard Beschow     uint16_t pch_device_id;
2964a802736SBernhard Beschow     uint8_t pch_revision_id;
2974a802736SBernhard Beschow } IGDDeviceIDInfo;
2984a802736SBernhard Beschow 
2994a802736SBernhard Beschow /*
3004a802736SBernhard Beschow  * In real world different GPU should have different PCH. But actually
3014a802736SBernhard Beschow  * the different PCH DIDs likely map to different PCH SKUs. We do the
3024a802736SBernhard Beschow  * same thing for the GPU. For PCH, the different SKUs are going to be
3034a802736SBernhard Beschow  * all the same silicon design and implementation, just different
3044a802736SBernhard Beschow  * features turn on and off with fuses. The SW interfaces should be
3054a802736SBernhard Beschow  * consistent across all SKUs in a given family (eg LPT). But just same
3064a802736SBernhard Beschow  * features may not be supported.
3074a802736SBernhard Beschow  *
3084a802736SBernhard Beschow  * Most of these different PCH features probably don't matter to the
3094a802736SBernhard Beschow  * Gfx driver, but obviously any difference in display port connections
3104a802736SBernhard Beschow  * will so it should be fine with any PCH in case of passthrough.
3114a802736SBernhard Beschow  *
3124a802736SBernhard Beschow  * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
3134a802736SBernhard Beschow  * scenarios, 0x9cc3 for BDW(Broadwell).
3144a802736SBernhard Beschow  */
3154a802736SBernhard Beschow static const IGDDeviceIDInfo igd_combo_id_infos[] = {
3164a802736SBernhard Beschow     /* HSW Classic */
3174a802736SBernhard Beschow     {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */
3184a802736SBernhard Beschow     {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */
3194a802736SBernhard Beschow     {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */
3204a802736SBernhard Beschow     {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */
3214a802736SBernhard Beschow     {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */
3224a802736SBernhard Beschow     /* HSW ULT */
3234a802736SBernhard Beschow     {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */
3244a802736SBernhard Beschow     {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */
3254a802736SBernhard Beschow     {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */
3264a802736SBernhard Beschow     {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */
3274a802736SBernhard Beschow     {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */
3284a802736SBernhard Beschow     {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */
3294a802736SBernhard Beschow     /* HSW CRW */
3304a802736SBernhard Beschow     {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */
3314a802736SBernhard Beschow     {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */
3324a802736SBernhard Beschow     /* HSW Server */
3334a802736SBernhard Beschow     {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */
3344a802736SBernhard Beschow     /* HSW SRVR */
3354a802736SBernhard Beschow     {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */
3364a802736SBernhard Beschow     /* BSW */
3374a802736SBernhard Beschow     {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */
3384a802736SBernhard Beschow     {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */
3394a802736SBernhard Beschow     {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */
3404a802736SBernhard Beschow     {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */
3414a802736SBernhard Beschow     {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */
3424a802736SBernhard Beschow     {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */
3434a802736SBernhard Beschow     {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */
3444a802736SBernhard Beschow     {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */
3454a802736SBernhard Beschow     {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */
3464a802736SBernhard Beschow     {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */
3474a802736SBernhard Beschow     {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
3484a802736SBernhard Beschow };
3494a802736SBernhard Beschow 
isa_bridge_class_init(ObjectClass * klass,void * data)3504a802736SBernhard Beschow static void isa_bridge_class_init(ObjectClass *klass, void *data)
3514a802736SBernhard Beschow {
3524a802736SBernhard Beschow     DeviceClass *dc = DEVICE_CLASS(klass);
3534a802736SBernhard Beschow     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
3544a802736SBernhard Beschow 
3554a802736SBernhard Beschow     dc->desc        = "ISA bridge faked to support IGD PT";
3564a802736SBernhard Beschow     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
3574a802736SBernhard Beschow     k->vendor_id    = PCI_VENDOR_ID_INTEL;
3584a802736SBernhard Beschow     k->class_id     = PCI_CLASS_BRIDGE_ISA;
3594a802736SBernhard Beschow };
3604a802736SBernhard Beschow 
3614a802736SBernhard Beschow static const TypeInfo isa_bridge_info = {
3624a802736SBernhard Beschow     .name          = "igd-passthrough-isa-bridge",
3634a802736SBernhard Beschow     .parent        = TYPE_PCI_DEVICE,
3644a802736SBernhard Beschow     .instance_size = sizeof(PCIDevice),
3654a802736SBernhard Beschow     .class_init = isa_bridge_class_init,
3664a802736SBernhard Beschow     .interfaces = (InterfaceInfo[]) {
3674a802736SBernhard Beschow         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
3684a802736SBernhard Beschow         { },
3694a802736SBernhard Beschow     },
3704a802736SBernhard Beschow };
3714a802736SBernhard Beschow 
pt_graphics_register_types(void)3724a802736SBernhard Beschow static void pt_graphics_register_types(void)
3734a802736SBernhard Beschow {
3744a802736SBernhard Beschow     type_register_static(&isa_bridge_info);
3754a802736SBernhard Beschow }
type_init(pt_graphics_register_types)3764a802736SBernhard Beschow type_init(pt_graphics_register_types)
3774a802736SBernhard Beschow 
37876acef2bSBernhard Beschow void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
37976acef2bSBernhard Beschow                                            XenHostPCIDevice *dev)
3804a802736SBernhard Beschow {
38176acef2bSBernhard Beschow     PCIBus *bus = pci_get_bus(&s->dev);
3824a802736SBernhard Beschow     struct PCIDevice *bridge_dev;
3834a802736SBernhard Beschow     int i, num;
38476acef2bSBernhard Beschow     const uint16_t gpu_dev_id = dev->device_id;
3854a802736SBernhard Beschow     uint16_t pch_dev_id = 0xffff;
3864a802736SBernhard Beschow     uint8_t pch_rev_id = 0;
3874a802736SBernhard Beschow 
3884a802736SBernhard Beschow     num = ARRAY_SIZE(igd_combo_id_infos);
3894a802736SBernhard Beschow     for (i = 0; i < num; i++) {
3904a802736SBernhard Beschow         if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) {
3914a802736SBernhard Beschow             pch_dev_id = igd_combo_id_infos[i].pch_device_id;
3924a802736SBernhard Beschow             pch_rev_id = igd_combo_id_infos[i].pch_revision_id;
3934a802736SBernhard Beschow         }
3944a802736SBernhard Beschow     }
3954a802736SBernhard Beschow 
3964a802736SBernhard Beschow     if (pch_dev_id == 0xffff) {
3974a802736SBernhard Beschow         return;
3984a802736SBernhard Beschow     }
3994a802736SBernhard Beschow 
4004a802736SBernhard Beschow     /* Currently IGD drivers always need to access PCH by 1f.0. */
4014a802736SBernhard Beschow     bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
4024a802736SBernhard Beschow                                    "igd-passthrough-isa-bridge");
4034a802736SBernhard Beschow 
4044a802736SBernhard Beschow     /*
4054a802736SBernhard Beschow      * Note that vendor id is always PCI_VENDOR_ID_INTEL.
4064a802736SBernhard Beschow      */
4074a802736SBernhard Beschow     if (!bridge_dev) {
4084a802736SBernhard Beschow         fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n");
4094a802736SBernhard Beschow         return;
4104a802736SBernhard Beschow     }
4114a802736SBernhard Beschow     pci_config_set_device_id(bridge_dev->config, pch_dev_id);
4124a802736SBernhard Beschow     pci_config_set_revision(bridge_dev->config, pch_rev_id);
4134a802736SBernhard Beschow }
414