[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 3/3] qemu-xen-trad: IGD passthrough: Expose vendor specific pci cap on host bridge.



Some versions of the Windows Intel GPU driver expect the vendor
PCI capability to be there on the host bridge config space when
passing through a Intel GPU.

As part of the change, the init for pt_pci_host() return value
has to be modified. With an init of -1 all the return value
smaller than a double word will be prefixed with "f"s.

Signed-off-by: Jean Guyader <jean.guyader@xxxxxxxxx>,
               Rui Guo <firemeteor@xxxxxxxxxxxxxxxxxxxxx>
Tested-by: Rui Guo <firemeteor@xxxxxxxxxxxxxxxxxxxxx>
Xen-devel: http://marc.info/?l=xen-devel&m=135748187808766
---
 hw/pass-through.c |    2 +-
 hw/pt-graphics.c  |   69 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/hw/pass-through.c b/hw/pass-through.c
index 304c438..2e795e1 100644
--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -2101,7 +2101,7 @@ struct pci_dev *pt_pci_get_dev(int bus, int dev, int fn)
 
 u32 pt_pci_host_read(struct pci_dev *pci_dev, u32 addr, int len)
 {
-    u32 val = -1;
+    u32 val = 0;
 
     pci_access_init();
     pci_read_block(pci_dev, addr, (u8 *) &val, len);
diff --git a/hw/pt-graphics.c b/hw/pt-graphics.c
index 5d4cf4a..269aade 100644
--- a/hw/pt-graphics.c
+++ b/hw/pt-graphics.c
@@ -144,6 +144,53 @@ write_default:
     pci_default_write_config(pci_dev, config_addr, val, len);
 }
 
+#define PCI_INTEL_VENDOR_CAP            0x34
+#define PCI_INTEL_VENDOR_CAP_TYPE       0x09
+/*
+ * This function returns 0 is the value hasn't been
+ * updated. That mean the offset doesn't anything to
+ * do with the vendor capability.
+ */
+static uint32_t igd_pci_read_vendor_cap(PCIDevice *pci_dev, uint32_t 
config_addr, int len,
+                                        uint32_t *val)
+{
+    struct pci_dev *pci_dev_host_bridge = pt_pci_get_dev(0, 0, 0);
+    uint32_t vendor_cap = 0;
+    uint32_t cap_type = 0;
+    uint32_t cap_size = 0;
+
+    vendor_cap = pt_pci_host_read(pci_dev_host_bridge, PCI_INTEL_VENDOR_CAP, 
1);
+    if (!vendor_cap)
+        return 0;
+
+    cap_type = pt_pci_host_read(pci_dev_host_bridge, vendor_cap, 1);
+    if (cap_type != PCI_INTEL_VENDOR_CAP_TYPE)
+        return 0;
+
+    if (config_addr == PCI_INTEL_VENDOR_CAP)
+    {
+        *val = vendor_cap;
+        return 1;
+    }
+
+    /* Remove the next capability link */
+    if (config_addr == vendor_cap + 1)
+    {
+        *val = 0;
+        return 1;
+    }
+
+    cap_size = pt_pci_host_read(pci_dev_host_bridge, vendor_cap + 2, 1);
+    if (config_addr >= vendor_cap &&
+            config_addr + len <= vendor_cap + cap_size)
+    {
+        *val = pt_pci_host_read(pci_dev_host_bridge, config_addr, len);
+        return 1;
+    }
+
+    return 0;
+}
+
 uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len)
 {
     struct pci_dev *pci_dev_host_bridge;
@@ -151,12 +198,22 @@ uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t 
config_addr, int len)
 
     assert(pci_dev->devfn == 0x00);
     if ( !igd_passthru )
-        goto read_default;
+    {
+        val = pci_default_read_config(pci_dev, config_addr, len);
+        goto read_return;
+    }
 
+    /* Exposing writable register does not lead to security risk since this
+       only apply to read. This may confuse the guest, but it works good so 
far.
+       Will switch to mask & merge style only if this is proved broken.
+       Note: Always expose aligned address if any byte of the dword is to be
+       exposed. This provides a consistent view, at least for read. */
     switch (config_addr)
     {
         case 0x00:        /* vendor id */
         case 0x02:        /* device id */
+        case 0x04:        /* command */
+        case 0x06:        /* status, needed for the cap list bit*/
         case 0x08:        /* revision id */
         case 0x2c:        /* sybsystem vendor id */
         case 0x2e:        /* sybsystem id */
@@ -169,7 +226,9 @@ uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t 
config_addr, int len)
         case 0xa8:        /* SNB: base of GTT stolen memory */
             break;
         default:
-            goto read_default;
+            if (!(igd_passthru && igd_pci_read_vendor_cap(pci_dev, 
config_addr, len, &val)))
+                val = pci_default_read_config(pci_dev, config_addr, len);
+            goto read_return;
     }
 
     /* Host read */
@@ -180,15 +239,13 @@ uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t 
config_addr, int len)
     }
 
     val = pt_pci_host_read(pci_dev_host_bridge, config_addr, len);
+
+read_return:
 #ifdef PT_DEBUG_PCI_CONFIG_ACCESS
     PT_LOG_DEV(pci_dev, "addr=%x len=%x val=%x\n",
                config_addr, len, val);
 #endif
     return val;
-   
-read_default:
-   
-   return pci_default_read_config(pci_dev, config_addr, len);
 }
 
 /*
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.