Skip to contentSkip to conversation

hw:xen:xen_pt: register isa bridge specific to IGD passthrough

RFC PATCH In review Tiejun Chen 2 participants 11 messages Nov 5, 2014 – Nov 17, 2014

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/2 hw:xen:xen_pt: register isa bridge specific to IGD passthrough

We need this instance to passthrough some config fields of PCH.

---
 hw/xen/xen_pt.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)
hw/xen/xen_pt.c +112 -0
index c1bf357..403c33f 100644
@@ -60,6 +60,7 @@
 #include "xen_pt.h"
 #include "qemu/range.h"
 #include "exec/address-spaces.h"
+#include "qapi/visitor.h"
 
 #define XEN_PT_NR_IRQS (256)
 static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0};
@@ -829,3 +830,114 @@ static void xen_pci_passthrough_register_types(void)
 }
 
 type_init(xen_pci_passthrough_register_types)
+
+typedef struct {
+    uint16_t gpu_device_id;
+    uint16_t pch_device_id;
+} XenIGDDeviceIDInfo;
+
+/* In real world different GPU should have different PCH. But actually
+ * the different PCH DIDs likely map to different PCH SKUs. We do the
+ * same thing for the GPU. For PCH, the different SKUs are going to be
+ * all the same silicon design and implementation, just different
+ * features turn on and off with fuses. The SW interfaces should be
+ * consistent across all SKUs in a given family (eg LPT). But just same
+ * features may not be supported.
+ *
+ * Most of these different PCH features probably don't matter to the
+ * Gfx driver, but obviously any difference in display port connections
+ * will so it should be fine with any PCH in case of passthrough.
+ *
+ * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
+ * scenarios, 0x9cc3 for BDW(Broadwell).
+ */
+static const XenIGDDeviceIDInfo xen_igd_combo_id_infos[] = {
+    /* HSW Classic */
+    {0x0402, 0x8c4e}, /* HSWGT1D, HSWD_w7 */
+    {0x0406, 0x8c4e}, /* HSWGT1M, HSWM_w7 */
+    {0x0412, 0x8c4e}, /* HSWGT2D, HSWD_w7 */
+    {0x0416, 0x8c4e}, /* HSWGT2M, HSWM_w7 */
+    {0x041E, 0x8c4e}, /* HSWGT15D, HSWD_w7 */
+    /* HSW ULT */
+    {0x0A06, 0x8c4e}, /* HSWGT1UT, HSWM_w7 */
+    {0x0A16, 0x8c4e}, /* HSWGT2UT, HSWM_w7 */
+    {0x0A26, 0x8c4e}, /* HSWGT3UT, HSWM_w7 */
+    {0x0A2E, 0x8c4e}, /* HSWGT3UT28W, HSWM_w7 */
+    {0x0A1E, 0x8c4e}, /* HSWGT2UX, HSWM_w7 */
+    {0x0A0E, 0x8c4e}, /* HSWGT1ULX, HSWM_w7 */
+    /* HSW CRW */
+    {0x0D26, 0x8c4e}, /* HSWGT3CW, HSWM_w7 */
+    {0x0D22, 0x8c4e}, /* HSWGT3CWDT, HSWD_w7 */
+    /* HSW Server */
+    {0x041A, 0x8c4e}, /* HSWSVGT2, HSWD_w7 */
+    /* HSW SRVR */
+    {0x040A, 0x8c4e}, /* HSWSVGT1, HSWD_w7 */
+    /* BSW */
+    {0x1606, 0x9cc3}, /* BDWULTGT1, BDWM_w7 */
+    {0x1616, 0x9cc3}, /* BDWULTGT2, BDWM_w7 */
+    {0x1626, 0x9cc3}, /* BDWULTGT3, BDWM_w7 */
+    {0x160E, 0x9cc3}, /* BDWULXGT1, BDWM_w7 */
+    {0x161E, 0x9cc3}, /* BDWULXGT2, BDWM_w7 */
+    {0x1602, 0x9cc3}, /* BDWHALOGT1, BDWM_w7 */
+    {0x1612, 0x9cc3}, /* BDWHALOGT2, BDWM_w7 */
+    {0x1622, 0x9cc3}, /* BDWHALOGT3, BDWM_w7 */
+    {0x162B, 0x9cc3}, /* BDWHALO28W, BDWM_w7 */
+    {0x162A, 0x9cc3}, /* BDWGT3WRKS, BDWM_w7 */
+    {0x162D, 0x9cc3}, /* BDWGT3SRVR, BDWM_w7 */
+};
+
+static void xen_igd_passthrough_pciisabridge_get_pci_device_id(Object *obj,
+                                                               Visitor *v,
+                                                               void *opaque,
+                                                               const char *name,
+                                                               Error **errp)
+{
+    uint32_t gpu_id = 0xffff, pch_id = 0xffff;
+    XenHostPCIDevice hdev;
+    int r = 0, num;
+
+    r = xen_host_pci_device_get(&hdev, 0, 0, 0x02, 0);
+    if (!r) {
+        gpu_id = hdev.device_id;
+
+        num = ARRAY_SIZE(xen_igd_combo_id_infos);
+        for (r = 0; r < num; r++)
+            if (gpu_id == xen_igd_combo_id_infos[r].gpu_device_id)
+                pch_id = xen_igd_combo_id_infos[r].pch_device_id;
+    }
+
+    visit_type_uint32(v, &pch_id, name, errp);
+}
+
+static void xen_igd_passthrough_isa_bridge_initfn(Object *obj)
+{
+    object_property_add(obj, "device-id", "int",
+                        xen_igd_passthrough_pciisabridge_get_pci_device_id,
+                        NULL, NULL, NULL, NULL);
+}
+
+static void xen_igd_passthrough_isa_bridge_class_init(ObjectClass *klass,
+                                                      void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    dc->desc        = "XEN IGD PASSTHROUGH ISA bridge";
+    k->class_id     = PCI_CLASS_BRIDGE_ISA;
+    k->vendor_id    = PCI_VENDOR_ID_INTEL;
+};
+
+static TypeInfo xen_igd_passthrough_isa_bridge_info = {
+    .name           = "xen-igd-passthrough-isa-bridge",
+    .parent         = TYPE_PCI_DEVICE,
+    .instance_size  = sizeof(PCIDevice),
+    .instance_init  = xen_igd_passthrough_isa_bridge_initfn,
+    .class_init     = xen_igd_passthrough_isa_bridge_class_init,
+};
+
+static void xen_igd_passthrough_isa_bridge_register_types(void)
+{
+    type_register_static(&xen_igd_passthrough_isa_bridge_info);
+}
+
+type_init(xen_igd_passthrough_isa_bridge_register_types);
Signature · 1 line
1.9.1
#1 lore raw

RFC PATCH 2/2 xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---
 hw/i386/pc_piix.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)
hw/i386/pc_piix.c +27 -1
index b559181..b19c7a9 100644
@@ -50,7 +50,7 @@
 #include "cpu.h"
 #include "qemu/error-report.h"
 #ifdef CONFIG_XEN
-#  include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/hvm_info_table.h>
 #endif
 
 #define MAX_IDE_BUS 2
@@ -452,6 +452,31 @@ static void pc_init_isa(MachineState *machine)
 }
 
 #ifdef CONFIG_XEN
+static void xen_igd_passthrough_isa_bridge_create(PCIBus *bus)
+{
+    struct PCIDevice *dev;
+    Error *local_err = NULL;
+    uint16_t device_id = 0xffff;
+
+    /* Currently IGD drivers always need to access PCH by 1f.0. */
+    dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
+                            "xen-igd-passthrough-isa-bridge");
+
+    /* Identify PCH card with its own real vendor/device ids.
+     * Here that vendor id is always PCI_VENDOR_ID_INTEL.
+     */
+    if (dev) {
+        device_id = object_property_get_int(OBJECT(dev), "device-id",
+                                            &local_err);
+        if (!local_err && device_id != 0xffff) {
+            pci_config_set_device_id(dev->config, device_id);
+            return;
+        }
+    }
+
+    fprintf(stderr, "xen set xen-igd-passthrough-isa-bridge failed\n");
+}
+
 static void pc_xen_hvm_init(MachineState *machine)
 {
     PCIBus *bus;
@@ -461,6 +486,7 @@ static void pc_xen_hvm_init(MachineState *machine)
     bus = pci_find_primary_bus();
     if (bus != NULL) {
         pci_create_simple(bus, -1, "xen-platform");
+        xen_igd_passthrough_isa_bridge_create(bus);
     }
 }
 #endif
Signature · 1 line
1.9.1
#2 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 54 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---
 hw/i386/pc_piix.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)
hw/i386/pc_piix.c +26 -1
index b559181..b19c7a9 100644
@@ -50,7 +50,7 @@
 #include "cpu.h"
 #include "qemu/error-report.h"
 #ifdef CONFIG_XEN
-#  include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/hvm_info_table.h>
 #endif
 
 #define MAX_IDE_BUS 2
@@ -452,6 +452,31 @@ static void pc_init_isa(MachineState *machine)
 }
 
 #ifdef CONFIG_XEN
+static void xen_igd_passthrough_isa_bridge_create(PCIBus *bus)
+{
+    struct PCIDevice *dev;
+    Error *local_err = NULL;
+    uint16_t device_id = 0xffff;
+
+    /* Currently IGD drivers always need to access PCH by 1f.0. */
+    dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
+                            "xen-igd-passthrough-isa-bridge");
+
+    /* Identify PCH card with its own real vendor/device ids.
+     * Here that vendor id is always PCI_VENDOR_ID_INTEL.
+     */
+    if (dev) {
+        device_id = object_property_get_int(OBJECT(dev), "device-id",
+                                            &local_err);
+        if (!local_err && device_id != 0xffff) {
+            pci_config_set_device_id(dev->config, device_id);
+            return;
+        }
+    }
+
+    fprintf(stderr, "xen set xen-igd-passthrough-isa-bridge failed\n");
+}
+
 static void pc_xen_hvm_init(MachineState *machine)
 {
     PCIBus *bus;

hw/i386/pc_piix.c static void pc_xen_hvm_init(MachineState *machine) · line 492

Quoted 7 lines
hw/i386/pc_piix.c +1 -0
@@ -461,6 +486,7 @@ static void pc_xen_hvm_init(MachineState *machine)
     bus = pci_find_primary_bus();
     if (bus != NULL) {
         pci_create_simple(bus, -1, "xen-platform");
+        xen_igd_passthrough_isa_bridge_create(bus);
     }
 }
 #endif

Can't we defer this step until the GPU is added?
This way there won't be need to poke at host device directly, you could get all info from dev->config
of the host device.
Additionally the correct bridge would be initialized automatically.

Quoted 2 lines
Signature · 1 line
1.9.1
#3 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 56 lines · Michael S. Tsirkin
Quoted 55 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---
  hw/i386/pc_piix.c | 28 +++++++++++++++++++++++++++-
  1 file changed, 27 insertions(+), 1 deletion(-)
hw/i386/pc_piix.c +26 -1
index b559181..b19c7a9 100644
@@ -50,7 +50,7 @@
  #include "cpu.h"
  #include "qemu/error-report.h"
  #ifdef CONFIG_XEN
-#  include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/hvm_info_table.h>
  #endif
 
  #define MAX_IDE_BUS 2
@@ -452,6 +452,31 @@ static void pc_init_isa(MachineState *machine)
  }
 
  #ifdef CONFIG_XEN
+static void xen_igd_passthrough_isa_bridge_create(PCIBus *bus)
+{
+    struct PCIDevice *dev;
+    Error *local_err = NULL;
+    uint16_t device_id = 0xffff;
+
+    /* Currently IGD drivers always need to access PCH by 1f.0. */
+    dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
+                            "xen-igd-passthrough-isa-bridge");
+
+    /* Identify PCH card with its own real vendor/device ids.
+     * Here that vendor id is always PCI_VENDOR_ID_INTEL.
+     */
+    if (dev) {
+        device_id = object_property_get_int(OBJECT(dev), "device-id",
+                                            &local_err);
+        if (!local_err && device_id != 0xffff) {
+            pci_config_set_device_id(dev->config, device_id);
+            return;
+        }
+    }
+
+    fprintf(stderr, "xen set xen-igd-passthrough-isa-bridge failed\n");
+}
+
  static void pc_xen_hvm_init(MachineState *machine)
  {
      PCIBus *bus;
@@ -461,6 +486,7 @@ static void pc_xen_hvm_init(MachineState *machine)
      bus = pci_find_primary_bus();
Quoted 8 lines

hw/i386/pc_piix.c static void pc_xen_hvm_init(MachineState *machine) · line 492

Quoted 6 lines
hw/i386/pc_piix.c +1 -0
      if (bus != NULL) {
          pci_create_simple(bus, -1, "xen-platform");
+        xen_igd_passthrough_isa_bridge_create(bus);
      }
  }
  #endif

Can't we defer this step until the GPU is added?

Sounds great but I can't figure out where we can to do this exactly.

Quoted 3 lines

This way there won't be need to poke at host device directly, you could get all info from dev->config of the host device.

As I understand We have two steps here:

#1 At first I have to write something to check if we're registering 00:02.0 & IGD, right? But where? While registering each pci device?

#2 Then if that condition is matched, we register this ISA bridge on its associated bus.

Thanks
Tiejun

Quoted 6 lines

Additionally the correct bridge would be initialized automatically.

Quoted 2 lines

--
1.9.1

#4 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 68 lines · Tiejun
Quoted 56 lines · Michael S. Tsirkin
Quoted 55 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---
 hw/i386/pc_piix.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)
hw/i386/pc_piix.c +26 -1
index b559181..b19c7a9 100644
@@ -50,7 +50,7 @@
 #include "cpu.h"
 #include "qemu/error-report.h"
 #ifdef CONFIG_XEN
-#  include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/hvm_info_table.h>
 #endif
 
 #define MAX_IDE_BUS 2
@@ -452,6 +452,31 @@ static void pc_init_isa(MachineState *machine)
 }
 
 #ifdef CONFIG_XEN
+static void xen_igd_passthrough_isa_bridge_create(PCIBus *bus)
+{
+    struct PCIDevice *dev;
+    Error *local_err = NULL;
+    uint16_t device_id = 0xffff;
+
+    /* Currently IGD drivers always need to access PCH by 1f.0. */
+    dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
+                            "xen-igd-passthrough-isa-bridge");
+
+    /* Identify PCH card with its own real vendor/device ids.
+     * Here that vendor id is always PCI_VENDOR_ID_INTEL.
+     */
+    if (dev) {
+        device_id = object_property_get_int(OBJECT(dev), "device-id",
+                                            &local_err);
+        if (!local_err && device_id != 0xffff) {
+            pci_config_set_device_id(dev->config, device_id);
+            return;
+        }
+    }
+
+    fprintf(stderr, "xen set xen-igd-passthrough-isa-bridge failed\n");
+}
+
 static void pc_xen_hvm_init(MachineState *machine)
 {
     PCIBus *bus;
@@ -461,6 +486,7 @@ static void pc_xen_hvm_init(MachineState *machine)
     bus = pci_find_primary_bus();
Quoted 8 lines

hw/i386/pc_piix.c static void pc_xen_hvm_init(MachineState *machine) · line 492

Quoted 6 lines
hw/i386/pc_piix.c +1 -0
     if (bus != NULL) {
         pci_create_simple(bus, -1, "xen-platform");
+        xen_igd_passthrough_isa_bridge_create(bus);
     }
 }
 #endif

Can't we defer this step until the GPU is added?

Sounds great but I can't figure out where we can to do this exactly.

Quoted 8 lines
Quoted 3 lines

This way there won't be need to poke at host device directly, you could get all info from dev->config of the host device.

As I understand We have two steps here:

#1 At first I have to write something to check if we're registering 00:02.0 & IGD, right? But where? While registering each pci device?

In xen_pt_initfn.
Just check the device and vendor ID against the table you have.

Quoted 5 lines

#2 Then if that condition is matched, we register this ISA bridge on its associated bus.

Thanks
Tiejun

Yep.

Quoted 6 lines
Quoted 6 lines

Additionally the correct bridge would be initialized automatically.

Quoted 2 lines

--
1.9.1

#5 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 73 lines · Michael S. Tsirkin
Quoted 72 lines · Tiejun
Quoted 56 lines · Michael S. Tsirkin
Quoted 55 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---
  hw/i386/pc_piix.c | 28 +++++++++++++++++++++++++++-
  1 file changed, 27 insertions(+), 1 deletion(-)
hw/i386/pc_piix.c +26 -1
index b559181..b19c7a9 100644
@@ -50,7 +50,7 @@
  #include "cpu.h"
  #include "qemu/error-report.h"
  #ifdef CONFIG_XEN
-#  include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/hvm_info_table.h>
  #endif
 
  #define MAX_IDE_BUS 2
@@ -452,6 +452,31 @@ static void pc_init_isa(MachineState *machine)
  }
 
  #ifdef CONFIG_XEN
+static void xen_igd_passthrough_isa_bridge_create(PCIBus *bus)
+{
+    struct PCIDevice *dev;
+    Error *local_err = NULL;
+    uint16_t device_id = 0xffff;
+
+    /* Currently IGD drivers always need to access PCH by 1f.0. */
+    dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
+                            "xen-igd-passthrough-isa-bridge");
+
+    /* Identify PCH card with its own real vendor/device ids.
+     * Here that vendor id is always PCI_VENDOR_ID_INTEL.
+     */
+    if (dev) {
+        device_id = object_property_get_int(OBJECT(dev), "device-id",
+                                            &local_err);
+        if (!local_err && device_id != 0xffff) {
+            pci_config_set_device_id(dev->config, device_id);
+            return;
+        }
+    }
+
+    fprintf(stderr, "xen set xen-igd-passthrough-isa-bridge failed\n");
+}
+
  static void pc_xen_hvm_init(MachineState *machine)
  {
      PCIBus *bus;
@@ -461,6 +486,7 @@ static void pc_xen_hvm_init(MachineState *machine)
      bus = pci_find_primary_bus();
Quoted 8 lines

hw/i386/pc_piix.c static void pc_xen_hvm_init(MachineState *machine) · line 492

Quoted 6 lines
hw/i386/pc_piix.c +1 -0
      if (bus != NULL) {
          pci_create_simple(bus, -1, "xen-platform");
+        xen_igd_passthrough_isa_bridge_create(bus);
      }
  }
  #endif

Can't we defer this step until the GPU is added?

Sounds great but I can't figure out where we can to do this exactly.

Quoted 3 lines

This way there won't be need to poke at host device directly, you could get all info from dev->config of the host device.

Quoted 8 lines
Quoted 4 lines

As I understand We have two steps here:

#1 At first I have to write something to check if we're registering 00:02.0 & IGD, right? But where? While registering each pci device?

In xen_pt_initfn.
Just check the device and vendor ID against the table you have.

Okay. Please see the follows which is just compiled:

hw/xen/xen_pt.c +91 -0
index c6466dc..f3ea313 100644
@@ -632,6 +632,94 @@ static const MemoryListener xen_pt_io_listener = {
     .priority = 10,
 };
 
+typedef struct {
+    uint16_t gpu_device_id;
+    uint16_t pch_device_id;
+} XenIGDDeviceIDInfo;
+
+/* In real world different GPU should have different PCH. But actually
+ * the different PCH DIDs likely map to different PCH SKUs. We do the
+ * same thing for the GPU. For PCH, the different SKUs are going to be
+ * all the same silicon design and implementation, just different
+ * features turn on and off with fuses. The SW interfaces should be
+ * consistent across all SKUs in a given family (eg LPT). But just same
+ * features may not be supported.
+ *
+ * Most of these different PCH features probably don't matter to the
+ * Gfx driver, but obviously any difference in display port connections
+ * will so it should be fine with any PCH in case of passthrough.
+ *
+ * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
+ * scenarios, 0x9cc3 for BDW(Broadwell).
+ */
+static const XenIGDDeviceIDInfo xen_igd_combo_id_infos[] = {
+    /* HSW Classic */
+    {0x0402, 0x8c4e}, /* HSWGT1D, HSWD_w7 */
+    {0x0406, 0x8c4e}, /* HSWGT1M, HSWM_w7 */
+    {0x0412, 0x8c4e}, /* HSWGT2D, HSWD_w7 */
+    {0x0416, 0x8c4e}, /* HSWGT2M, HSWM_w7 */
+    {0x041E, 0x8c4e}, /* HSWGT15D, HSWD_w7 */
+    /* HSW ULT */
+    {0x0A06, 0x8c4e}, /* HSWGT1UT, HSWM_w7 */
+    {0x0A16, 0x8c4e}, /* HSWGT2UT, HSWM_w7 */
+    {0x0A26, 0x8c4e}, /* HSWGT3UT, HSWM_w7 */
+    {0x0A2E, 0x8c4e}, /* HSWGT3UT28W, HSWM_w7 */
+    {0x0A1E, 0x8c4e}, /* HSWGT2UX, HSWM_w7 */
+    {0x0A0E, 0x8c4e}, /* HSWGT1ULX, HSWM_w7 */
+    /* HSW CRW */
+    {0x0D26, 0x8c4e}, /* HSWGT3CW, HSWM_w7 */
+    {0x0D22, 0x8c4e}, /* HSWGT3CWDT, HSWD_w7 */
+    /* HSW Server */
+    {0x041A, 0x8c4e}, /* HSWSVGT2, HSWD_w7 */
+    /* HSW SRVR */
+    {0x040A, 0x8c4e}, /* HSWSVGT1, HSWD_w7 */
+    /* BSW */
+    {0x1606, 0x9cc3}, /* BDWULTGT1, BDWM_w7 */
+    {0x1616, 0x9cc3}, /* BDWULTGT2, BDWM_w7 */
+    {0x1626, 0x9cc3}, /* BDWULTGT3, BDWM_w7 */
+    {0x160E, 0x9cc3}, /* BDWULXGT1, BDWM_w7 */
+    {0x161E, 0x9cc3}, /* BDWULXGT2, BDWM_w7 */
+    {0x1602, 0x9cc3}, /* BDWHALOGT1, BDWM_w7 */
+    {0x1612, 0x9cc3}, /* BDWHALOGT2, BDWM_w7 */
+    {0x1622, 0x9cc3}, /* BDWHALOGT3, BDWM_w7 */
+    {0x162B, 0x9cc3}, /* BDWHALO28W, BDWM_w7 */
+    {0x162A, 0x9cc3}, /* BDWGT3WRKS, BDWM_w7 */
+    {0x162D, 0x9cc3}, /* BDWGT3SRVR, BDWM_w7 */
+};
+
+static void
+xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
+                                      XenHostPCIDevice *dev)
+{
+    struct PCIDevice *pci_dev;
+    int i, num;
+    uint16_t gpu_id = 0xffff, pch_id = 0xffff;
+    PCIDevice *d = &s->dev;
+
+    if (is_vga_passthrough(dev)) {
+        gpu_id = dev->device_id;
+        num = ARRAY_SIZE(xen_igd_combo_id_infos);
+        for (i = 0; i < num; i++)
+            if (gpu_id == xen_igd_combo_id_infos[i].gpu_device_id)
+                pch_id = xen_igd_combo_id_infos[i].pch_device_id;
+
+        /* Currently IGD drivers always need to access PCH by 1f.0. */
+        pci_dev = pci_create_simple(d->bus, PCI_DEVFN(0x1f, 0),
+                                    "xen-igd-passthrough-isa-bridge");
+
+        /*
+         * Identify PCH card with its own real vendor/device ids.
+         * Here that vendor id is always PCI_VENDOR_ID_INTEL.
+         */
+        if (pci_dev) {
+            pci_config_set_device_id(pci_dev->config, pch_id);
+            return;
+        }
+
+        fprintf(stderr, "xen set xen-igd-passthrough-isa-bridge failed!\n");
+    }
+}
+
 /* init */
 
 static int xen_pt_initfn(PCIDevice *d)
@@ -682,6 +770,9 @@ static int xen_pt_initfn(PCIDevice *d)
         return -1;
     }
 
+    /* Register ISA bridge for passthrough GFX. */
+    xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
+
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
         XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");

Note I will introduce a inline function in another patch,

+static inline int is_vga_passthrough(XenHostPCIDevice *dev) +{
+ return (xen_has_gfx_passthru && (dev->vendor_id == PCI_VENDOR_ID_INTEL)
+ && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
+}

Thanks
Tiejun

#6 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 145 lines · Tiejun
Quoted 73 lines · Michael S. Tsirkin
Quoted 72 lines · Tiejun
Quoted 56 lines · Michael S. Tsirkin
Quoted 55 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---
 hw/i386/pc_piix.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)
hw/i386/pc_piix.c +26 -1
index b559181..b19c7a9 100644
@@ -50,7 +50,7 @@
 #include "cpu.h"
 #include "qemu/error-report.h"
 #ifdef CONFIG_XEN
-#  include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/hvm_info_table.h>
 #endif
 
 #define MAX_IDE_BUS 2
@@ -452,6 +452,31 @@ static void pc_init_isa(MachineState *machine)
 }
 
 #ifdef CONFIG_XEN
+static void xen_igd_passthrough_isa_bridge_create(PCIBus *bus)
+{
+    struct PCIDevice *dev;
+    Error *local_err = NULL;
+    uint16_t device_id = 0xffff;
+
+    /* Currently IGD drivers always need to access PCH by 1f.0. */
+    dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
+                            "xen-igd-passthrough-isa-bridge");
+
+    /* Identify PCH card with its own real vendor/device ids.
+     * Here that vendor id is always PCI_VENDOR_ID_INTEL.
+     */
+    if (dev) {
+        device_id = object_property_get_int(OBJECT(dev), "device-id",
+                                            &local_err);
+        if (!local_err && device_id != 0xffff) {
+            pci_config_set_device_id(dev->config, device_id);
+            return;
+        }
+    }
+
+    fprintf(stderr, "xen set xen-igd-passthrough-isa-bridge failed\n");
+}
+
 static void pc_xen_hvm_init(MachineState *machine)
 {
     PCIBus *bus;
@@ -461,6 +486,7 @@ static void pc_xen_hvm_init(MachineState *machine)
     bus = pci_find_primary_bus();
Quoted 8 lines

hw/i386/pc_piix.c static void pc_xen_hvm_init(MachineState *machine) · line 492

Quoted 6 lines
hw/i386/pc_piix.c +1 -0
     if (bus != NULL) {
         pci_create_simple(bus, -1, "xen-platform");
+        xen_igd_passthrough_isa_bridge_create(bus);
     }
 }
 #endif

Can't we defer this step until the GPU is added?

Sounds great but I can't figure out where we can to do this exactly.

Quoted 3 lines

This way there won't be need to poke at host device directly, you could get all info from dev->config of the host device.

Quoted 8 lines
Quoted 4 lines

As I understand We have two steps here:

#1 At first I have to write something to check if we're registering 00:02.0 & IGD, right? But where? While registering each pci device?

In xen_pt_initfn.
Just check the device and vendor ID against the table you have.

Okay. Please see the follows which is just compiled:

hw/xen/xen_pt.c +52 -0
index c6466dc..f3ea313 100644
@@ -632,6 +632,94 @@ static const MemoryListener xen_pt_io_listener = {
     .priority = 10,
 };
 
+typedef struct {
+    uint16_t gpu_device_id;
+    uint16_t pch_device_id;
+} XenIGDDeviceIDInfo;
+
+/* In real world different GPU should have different PCH. But actually
+ * the different PCH DIDs likely map to different PCH SKUs. We do the
+ * same thing for the GPU. For PCH, the different SKUs are going to be
+ * all the same silicon design and implementation, just different
+ * features turn on and off with fuses. The SW interfaces should be
+ * consistent across all SKUs in a given family (eg LPT). But just same
+ * features may not be supported.
+ *
+ * Most of these different PCH features probably don't matter to the
+ * Gfx driver, but obviously any difference in display port connections
+ * will so it should be fine with any PCH in case of passthrough.
+ *
+ * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
+ * scenarios, 0x9cc3 for BDW(Broadwell).
+ */
+static const XenIGDDeviceIDInfo xen_igd_combo_id_infos[] = {
+    /* HSW Classic */
+    {0x0402, 0x8c4e}, /* HSWGT1D, HSWD_w7 */
+    {0x0406, 0x8c4e}, /* HSWGT1M, HSWM_w7 */
+    {0x0412, 0x8c4e}, /* HSWGT2D, HSWD_w7 */
+    {0x0416, 0x8c4e}, /* HSWGT2M, HSWM_w7 */
+    {0x041E, 0x8c4e}, /* HSWGT15D, HSWD_w7 */
+    /* HSW ULT */
+    {0x0A06, 0x8c4e}, /* HSWGT1UT, HSWM_w7 */
+    {0x0A16, 0x8c4e}, /* HSWGT2UT, HSWM_w7 */
+    {0x0A26, 0x8c4e}, /* HSWGT3UT, HSWM_w7 */
+    {0x0A2E, 0x8c4e}, /* HSWGT3UT28W, HSWM_w7 */
+    {0x0A1E, 0x8c4e}, /* HSWGT2UX, HSWM_w7 */
+    {0x0A0E, 0x8c4e}, /* HSWGT1ULX, HSWM_w7 */
+    /* HSW CRW */
+    {0x0D26, 0x8c4e}, /* HSWGT3CW, HSWM_w7 */
+    {0x0D22, 0x8c4e}, /* HSWGT3CWDT, HSWD_w7 */
+    /* HSW Server */
+    {0x041A, 0x8c4e}, /* HSWSVGT2, HSWD_w7 */
+    /* HSW SRVR */
+    {0x040A, 0x8c4e}, /* HSWSVGT1, HSWD_w7 */
+    /* BSW */
+    {0x1606, 0x9cc3}, /* BDWULTGT1, BDWM_w7 */
+    {0x1616, 0x9cc3}, /* BDWULTGT2, BDWM_w7 */
+    {0x1626, 0x9cc3}, /* BDWULTGT3, BDWM_w7 */
+    {0x160E, 0x9cc3}, /* BDWULXGT1, BDWM_w7 */
+    {0x161E, 0x9cc3}, /* BDWULXGT2, BDWM_w7 */
+    {0x1602, 0x9cc3}, /* BDWHALOGT1, BDWM_w7 */
+    {0x1612, 0x9cc3}, /* BDWHALOGT2, BDWM_w7 */
+    {0x1622, 0x9cc3}, /* BDWHALOGT3, BDWM_w7 */
+    {0x162B, 0x9cc3}, /* BDWHALO28W, BDWM_w7 */
+    {0x162A, 0x9cc3}, /* BDWGT3WRKS, BDWM_w7 */

hw/xen/xen_pt.c static const MemoryListener xen_pt_io_listener = { · line 696

Quoted 10 lines
hw/xen/xen_pt.c +10 -0
+    {0x162D, 0x9cc3}, /* BDWGT3SRVR, BDWM_w7 */
+};
+
+static void
+xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
+                                      XenHostPCIDevice *dev)
+{
+    struct PCIDevice *pci_dev;
+    int i, num;
+    uint16_t gpu_id = 0xffff,

no need to init gpu_id.

hw/xen/xen_pt.c static const MemoryListener xen_pt_io_listener = { · line 699

Quoted 4 lines
hw/xen/xen_pt.c +3 -0
 pch_id = 0xffff;
+    PCIDevice *d = &s->dev;
+
+    if (is_vga_passthrough(dev)) {

I would do if (!is_vga_passthrough) { return; } here. Makes following code shorter.

hw/xen/xen_pt.c static const MemoryListener xen_pt_io_listener = { · line 704

Quoted 5 lines
hw/xen/xen_pt.c +5 -0
+        gpu_id = dev->device_id;
+        num = ARRAY_SIZE(xen_igd_combo_id_infos);
+        for (i = 0; i < num; i++)
+            if (gpu_id == xen_igd_combo_id_infos[i].gpu_device_id)
+                pch_id = xen_igd_combo_id_infos[i].pch_device_id;

Add {} to match our coding style please.

At this point I would do

if (pch_id == 0xffff) {
	return;
}

maybe replace 0xffff with 0x0, then you can do if (!pch_id) { return; }.

hw/xen/xen_pt.c static const MemoryListener xen_pt_io_listener = { · line 712

Quoted 8 lines
hw/xen/xen_pt.c +8 -0
+
+        /* Currently IGD drivers always need to access PCH by 1f.0. */
+        pci_dev = pci_create_simple(d->bus, PCI_DEVFN(0x1f, 0),
+                                    "xen-igd-passthrough-isa-bridge");
+
+        /*
+         * Identify PCH card with its own real vendor/device ids.
+         * Here that vendor id is always PCI_VENDOR_ID_INTEL.

s/Here/Note/

hw/xen/xen_pt.c static const MemoryListener xen_pt_io_listener = {

Quoted 8 lines
hw/xen/xen_pt.c +7 -0
+         */
+        if (pci_dev) {
+            pci_config_set_device_id(pci_dev->config, pch_id);
+            return;
+        }
+
+        fprintf(stderr, "xen set xen-igd-passthrough-isa-bridge
 failed!\n");

Cleaner:

	 if (!pci_dev) {
		fprintf
		return;
	}
         pci_config_set_device_id(pci_dev->config, pch_id);
Quoted 25 lines
hw/xen/xen_pt.c +3 -0
+    }
+}
+
 /* init */

static int xen_pt_initfn(PCIDevice *d)

hw/xen/xen_pt.c +3 -0
@@ -682,6 +770,9 @@ static int xen_pt_initfn(PCIDevice *d)
         return -1;
     }
 
+    /* Register ISA bridge for passthrough GFX. */
+    xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
+
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
         XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");

Note I will introduce a inline function in another patch,

hw/xen/xen_pt.c +5 -0
+static inline int is_vga_passthrough(XenHostPCIDevice *dev)
+{
+    return (xen_has_gfx_passthru && (dev->vendor_id == PCI_VENDOR_ID_INTEL)
+            && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
+}
Quoted 2 lines

Thanks
Tiejun

Why bother with all these conditions?
Won't it be enough to check dev->vendor_id == PCI_VENDOR_ID_INTEL?

Signature · 1 line
MST
#7 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 10 lines · Michael S. Tsirkin
Quoted 9 lines · Tiejun
Quoted 8 lines · Michael S. Tsirkin
Quoted 7 lines · Tiejun
Quoted 6 lines · Michael S. Tsirkin
Quoted 5 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---

[snip]

Quoted 6 lines

Cleaner:

	 if (!pci_dev) {
		fprintf
		return;
	}
          pci_config_set_device_id(pci_dev->config, pch_id);

I will address all comments and thanks.

Quoted 26 lines
Quoted 26 lines
hw/xen/xen_pt.c +6 -0
+    }
+}
+
  /* init */
 
  static int xen_pt_initfn(PCIDevice *d)
@@ -682,6 +770,9 @@ static int xen_pt_initfn(PCIDevice *d)
          return -1;
      }
 
+    /* Register ISA bridge for passthrough GFX. */
+    xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
+
      /* reinitialize each config register to be emulated */
      if (xen_pt_config_init(s)) {
          XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");

Note I will introduce a inline function in another patch,

(quoted diff) +5 -0
+static inline int is_vga_passthrough(XenHostPCIDevice *dev)
+{
+    return (xen_has_gfx_passthru && (dev->vendor_id == PCI_VENDOR_ID_INTEL)
+            && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
+}
Quoted 6 lines
Quoted 2 lines

Thanks
Tiejun

Why bother with all these conditions?
Won't it be enough to check dev->vendor_id == PCI_VENDOR_ID_INTEL?

If this is just used for IGD, its always fine without checking vendor_id.

So after remove that check, I guess I need to rename that as is_igd_vga_passthrough() to make sense.

Thanks
Tiejun

#8 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 49 lines · Tiejun
Quoted 10 lines · Michael S. Tsirkin
Quoted 9 lines · Tiejun
Quoted 8 lines · Michael S. Tsirkin
Quoted 7 lines · Tiejun
Quoted 6 lines · Michael S. Tsirkin
Quoted 5 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---

[snip]

Quoted 6 lines

Cleaner:

	 if (!pci_dev) {
		fprintf
		return;
	}
         pci_config_set_device_id(pci_dev->config, pch_id);

I will address all comments and thanks.

Quoted 26 lines
Quoted 26 lines
hw/xen/xen_pt.c +6 -0
+    }
+}
+
 /* init */
 
 static int xen_pt_initfn(PCIDevice *d)
@@ -682,6 +770,9 @@ static int xen_pt_initfn(PCIDevice *d)
         return -1;
     }
 
+    /* Register ISA bridge for passthrough GFX. */
+    xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
+
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
         XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");

Note I will introduce a inline function in another patch,

(quoted diff) +5 -0
+static inline int is_vga_passthrough(XenHostPCIDevice *dev)
+{
+    return (xen_has_gfx_passthru && (dev->vendor_id == PCI_VENDOR_ID_INTEL)
+            && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
+}
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

Thanks
Tiejun

Why bother with all these conditions?
Won't it be enough to check dev->vendor_id == PCI_VENDOR_ID_INTEL?

If this is just used for IGD, its always fine without checking vendor_id.

You need to match device ID to *know* it's IGD.

Quoted 5 lines

So after remove that check, I guess I need to rename that as is_igd_vga_passthrough() to make sense.

Thanks
Tiejun

There is no need to check class code or xen_has_gfx_passthru flag. Device ID + vendor ID identifies each device uniquely.

Signature · 1 line
MST
#9 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 61 lines · Michael S. Tsirkin
Quoted 49 lines · Tiejun
Quoted 10 lines · Michael S. Tsirkin
Quoted 9 lines · Tiejun
Quoted 8 lines · Michael S. Tsirkin
Quoted 7 lines · Tiejun
Quoted 6 lines · Michael S. Tsirkin
Quoted 5 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---

[snip]

Quoted 6 lines

Cleaner:

	 if (!pci_dev) {
		fprintf
		return;
	}
          pci_config_set_device_id(pci_dev->config, pch_id);

I will address all comments and thanks.

Quoted 26 lines
Quoted 26 lines
hw/xen/xen_pt.c +6 -0
+    }
+}
+
  /* init */
 
  static int xen_pt_initfn(PCIDevice *d)
@@ -682,6 +770,9 @@ static int xen_pt_initfn(PCIDevice *d)
          return -1;
      }
 
+    /* Register ISA bridge for passthrough GFX. */
+    xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
+
      /* reinitialize each config register to be emulated */
      if (xen_pt_config_init(s)) {
          XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");

Note I will introduce a inline function in another patch,

(quoted diff) +5 -0
+static inline int is_vga_passthrough(XenHostPCIDevice *dev)
+{
+    return (xen_has_gfx_passthru && (dev->vendor_id == PCI_VENDOR_ID_INTEL)
+            && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
+}
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

Thanks
Tiejun

Why bother with all these conditions?
Won't it be enough to check dev->vendor_id == PCI_VENDOR_ID_INTEL?

If this is just used for IGD, its always fine without checking vendor_id.

You need to match device ID to *know* it's IGD.

Quoted 9 lines
Quoted 5 lines

So after remove that check, I guess I need to rename that as is_igd_vga_passthrough() to make sense.

Thanks
Tiejun

There is no need to check class code or xen_has_gfx_passthru flag. Device ID + vendor ID identifies each device uniquely.

Yeah.

Here I assume vendor ID is always PCI_VENDOR_ID_INTEL so looks you means I also need to check that table to do something like,

is_igd_vga_passthugh(dev)

{	
	int i;
	int num = ARRAY_SIZE(xen_igd_combo_id_infos);
	for (i = 0; i < num; i++) {
		if (dev->device_id == xen_igd_combo_id_infos[i].gpu_device_id)
			return 1;
	return 0;
}

Then we can simplify the subsequent codes based on this, right?

Thanks
Tiejun

#10 lore raw

Re: [Qemu-devel] [RFC][PATCH 2/2] xen:i386:pc_piix: create isa bridge specific to IGD passthrough

Quoted 87 lines · Tiejun
Quoted 61 lines · Michael S. Tsirkin
Quoted 49 lines · Tiejun
Quoted 10 lines · Michael S. Tsirkin
Quoted 9 lines · Tiejun
Quoted 8 lines · Michael S. Tsirkin
Quoted 7 lines · Tiejun
Quoted 6 lines · Michael S. Tsirkin
Quoted 5 lines · Tiejun Chen

Currently IGD drivers always need to access PCH by 1f.0, and PCH vendor/device id is used to identify the card.

---

[snip]

Quoted 6 lines

Cleaner:

	 if (!pci_dev) {
		fprintf
		return;
	}
         pci_config_set_device_id(pci_dev->config, pch_id);

I will address all comments and thanks.

Quoted 26 lines
Quoted 26 lines
hw/xen/xen_pt.c +6 -0
+    }
+}
+
 /* init */
 
 static int xen_pt_initfn(PCIDevice *d)
@@ -682,6 +770,9 @@ static int xen_pt_initfn(PCIDevice *d)
         return -1;
     }
 
+    /* Register ISA bridge for passthrough GFX. */
+    xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
+
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
         XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");

Note I will introduce a inline function in another patch,

(quoted diff) +5 -0
+static inline int is_vga_passthrough(XenHostPCIDevice *dev)
+{
+    return (xen_has_gfx_passthru && (dev->vendor_id == PCI_VENDOR_ID_INTEL)
+            && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
+}
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

Thanks
Tiejun

Why bother with all these conditions?
Won't it be enough to check dev->vendor_id == PCI_VENDOR_ID_INTEL?

If this is just used for IGD, its always fine without checking vendor_id.

You need to match device ID to *know* it's IGD.

Quoted 9 lines
Quoted 5 lines

So after remove that check, I guess I need to rename that as is_igd_vga_passthrough() to make sense.

Thanks
Tiejun

There is no need to check class code or xen_has_gfx_passthru flag. Device ID + vendor ID identifies each device uniquely.

Yeah.

Here I assume vendor ID is always PCI_VENDOR_ID_INTEL so looks you means I also need to check that table to do something like,

is_igd_vga_passthugh(dev)

{	
	int i;
	int num = ARRAY_SIZE(xen_igd_combo_id_infos);
	for (i = 0; i < num; i++) {
		if (dev->device_id == xen_igd_combo_id_infos[i].gpu_device_id)
			return 1;
	return 0;
}
Quoted 4 lines

Then we can simplify the subsequent codes based on this, right?

Thanks
Tiejun

Yea.
Basically let's try to treat this simply as a device quirk, and see where this gets us.

Signature · 1 line
MST