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

[Xen-changelog] [qemu-xen-unstable] passthrough: Intel GPU passthrough, fix OpRegion mapping



commit b7469189669c4de0a5161a869f443738d84539ec
Author: Jean Guyader <jean.guyader@xxxxxxxxxxxxx>
Date:   Fri May 11 12:40:42 2012 +0100

    passthrough: Intel GPU passthrough, fix OpRegion mapping
    
    The OpRegion shouldn't be mapped 1:1 because the address in the host
    can't be used in the guest directly.
    
    This patch traps read and write access to the opregion of the Intel
    GPU config space (offset 0xfc).
    
    To work correctly this patch needs a change in hvmloader.
    
    HVMloader will allocate 2 pages for the OpRegion and write this address
    on the config space of the Intel GPU. Qemu will trap and map the host
    OpRegion to the guest. Any write to this offset after that won't have
    any effect. Any read of this config space offset will return the address
    in the guest.
    
    Signed-off-by: Jean Guyader <jean.guyader@xxxxxxxxxxxxx>
    Acked-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
---
 hw/pass-through.c |   49 ++++++++++++++++++++++++++++++++++-
 hw/pass-through.h |    2 +
 hw/pt-graphics.c  |   73 +++++++++++++++++++++++++++++++++++++++--------------
 3 files changed, 104 insertions(+), 20 deletions(-)

diff --git a/hw/pass-through.c b/hw/pass-through.c
index f832c5a..8581253 100644
--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -238,6 +238,14 @@ static int pt_bar_reg_restore(struct pt_dev *ptdev,
 static int pt_exp_rom_bar_reg_restore(struct pt_dev *ptdev,
     struct pt_reg_tbl *cfg_entry,
     uint32_t real_offset, uint32_t dev_value, uint32_t *value);
+static int pt_intel_opregion_read(struct pt_dev *ptdev,
+        struct pt_reg_tbl *cfg_entry,
+        uint32_t *value, uint32_t valid_mask);
+static int pt_intel_opregion_write(struct pt_dev *ptdev,
+        struct pt_reg_tbl *cfg_entry,
+        uint32_t *value, uint32_t dev_value, uint32_t valid_mask);
+static uint8_t pt_reg_grp_header0_size_init(struct pt_dev *ptdev,
+        struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset);
 
 /* pt_reg_info_tbl declaration
  * - only for emulated register (either a part or whole bit).
@@ -444,6 +452,16 @@ static struct pt_reg_info_tbl pt_emu_reg_header0_tbl[] = {
         .u.dw.write = pt_exp_rom_bar_reg_write,
         .u.dw.restore = pt_exp_rom_bar_reg_restore,
     },
+    /* Intel IGFX OpRegion reg */
+    {
+        .offset     = PCI_INTEL_OPREGION,
+        .size       = 4,
+        .init_val   = 0,
+        .no_wb      = 1,
+        .u.dw.read   = pt_intel_opregion_read,
+        .u.dw.write  = pt_intel_opregion_write,
+        .u.dw.restore  = NULL,
+    },
     {
         .size = 0,
     },
@@ -737,7 +755,7 @@ static const struct pt_reg_grp_info_tbl 
pt_emu_reg_grp_tbl[] = {
         .grp_id     = 0xFF,
         .grp_type   = GRP_TYPE_EMU,
         .grp_size   = 0x40,
-        .size_init  = pt_reg_grp_size_init,
+        .size_init  = pt_reg_grp_header0_size_init,
         .emu_reg_tbl= pt_emu_reg_header0_tbl,
     },
     /* PCI PowerManagement Capability reg group */
@@ -3004,6 +3022,19 @@ static uint32_t pt_msixctrl_reg_init(struct pt_dev 
*ptdev,
     return reg->init_val;
 }
 
+static uint8_t pt_reg_grp_header0_size_init(struct pt_dev *ptdev,
+        struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset)
+{
+    /*
+    ** By default we will trap up to 0x40 in the cfg space.
+    ** If an intel device is pass through we need to trap 0xfc,
+    ** therefore the size should be 0xff.
+    */
+    if (igd_passthru)
+        return 0xFF;
+    return grp_reg->grp_size;
+}
+
 /* get register group size */
 static uint8_t pt_reg_grp_size_init(struct pt_dev *ptdev,
         struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset)
@@ -4152,6 +4183,22 @@ static int pt_pmcsr_reg_restore(struct pt_dev *ptdev,
     return 0;
 }
 
+static int pt_intel_opregion_read(struct pt_dev *ptdev,
+        struct pt_reg_tbl *cfg_entry,
+        uint32_t *value, uint32_t valid_mask)
+{
+    *value = igd_read_opregion(ptdev);
+    return 0;
+}
+
+static int pt_intel_opregion_write(struct pt_dev *ptdev,
+        struct pt_reg_tbl *cfg_entry,
+        uint32_t *value, uint32_t dev_value, uint32_t valid_mask)
+{
+    igd_write_opregion(ptdev, *value);
+    return 0;
+}
+
 static struct pt_dev * register_real_device(PCIBus *e_bus,
         const char *e_dev_name, int e_devfn, uint8_t r_bus, uint8_t r_dev,
         uint8_t r_func, uint32_t machine_irq, struct pci_access *pci_access,
diff --git a/hw/pass-through.h b/hw/pass-through.h
index e641b56..d7d837c 100644
--- a/hw/pass-through.h
+++ b/hw/pass-through.h
@@ -424,6 +424,8 @@ PCIBus *intel_pci_bridge_init(PCIBus *bus, int devfn, 
uint16_t vid,
            uint16_t did, const char *name, uint16_t revision);
 void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, uint32_t val, int 
len);
 uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len);
+uint32_t igd_read_opregion(struct pt_dev *pci_dev);
+void igd_write_opregion(struct pt_dev *real_dev, uint32_t val);
 
 #endif /* __PASSTHROUGH_H__ */
 
diff --git a/hw/pt-graphics.c b/hw/pt-graphics.c
index 9c41f3e..c6f8869 100644
--- a/hw/pt-graphics.c
+++ b/hw/pt-graphics.c
@@ -13,6 +13,8 @@
 extern int gfx_passthru;
 extern int igd_passthru;
 
+static uint32_t igd_guest_opregion = 0;
+
 static int pch_map_irq(PCIDevice *pci_dev, int irq_num)
 {
     PT_LOG("pch_map_irq called\n");
@@ -43,6 +45,54 @@ void intel_pch_init(PCIBus *bus)
                         pch_map_irq, "intel_bridge_1f");
 }
 
+uint32_t igd_read_opregion(struct pt_dev *pci_dev)
+{
+    uint32_t val = -1;
+
+    if ( igd_guest_opregion == 0 )
+        return -1;
+
+    val = igd_guest_opregion;
+#ifdef PT_DEBUG_PCI_CONFIG_ACCESS
+    PT_LOG_DEV((PCIDevice*)pci_dev, "addr=%x len=%x val=%x\n",
+            PCI_INTEL_OPREGION, 4, val);
+#endif
+    return val;
+}
+
+void igd_write_opregion(struct pt_dev *real_dev, uint32_t val)
+{
+    uint32_t host_opregion = 0;
+    int ret;
+
+    if ( igd_guest_opregion )
+    {
+        PT_LOG("opregion register already been set, ignoring %x\n", val);
+        return;
+    }
+
+    host_opregion = pt_pci_host_read(real_dev->pci_dev, PCI_INTEL_OPREGION, 4);
+    igd_guest_opregion = (val & ~0xfff) | (host_opregion & 0xfff);
+    PT_LOG("Map OpRegion: %x -> %x\n", host_opregion, igd_guest_opregion);
+
+    ret = xc_domain_memory_mapping(xc_handle, domid,
+            igd_guest_opregion >> XC_PAGE_SHIFT,
+            host_opregion >> XC_PAGE_SHIFT,
+            2,
+            DPCI_ADD_MAPPING);
+
+    if ( ret != 0 )
+    {
+        PT_LOG("Error: Can't map opregion\n");
+        igd_guest_opregion = 0;
+    }
+#ifdef PT_DEBUG_PCI_CONFIG_ACCESS
+    PT_LOG_DEV((PCIDevice*)real_dev, "addr=%x len=%lx val=%x\n",
+            PCI_INTEL_OPREGION, len, val);
+#endif
+
+}
+
 void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, uint32_t val, int 
len)
 {
     struct pci_dev *pci_dev_host_bridge;
@@ -129,7 +179,6 @@ read_default:
 int register_vga_regions(struct pt_dev *real_device)
 {
     u16 vendor_id;
-    int igd_opregion;
     int ret = 0;
 
     if ( !gfx_passthru || real_device->pci_dev->device_class != 0x0300 )
@@ -147,19 +196,6 @@ int register_vga_regions(struct pt_dev *real_device)
             0x20,
             DPCI_ADD_MAPPING);
 
-    /* 1:1 map ASL Storage register value */
-    vendor_id = pt_pci_host_read(real_device->pci_dev, 0, 2);
-    igd_opregion = pt_pci_host_read(real_device->pci_dev, PCI_INTEL_OPREGION, 
4);
-    if ( (vendor_id == PCI_VENDOR_ID_INTEL ) && igd_opregion )
-    {
-        ret |= xc_domain_memory_mapping(xc_handle, domid,
-                igd_opregion >> XC_PAGE_SHIFT,
-                igd_opregion >> XC_PAGE_SHIFT,
-                2,
-                DPCI_ADD_MAPPING);
-        PT_LOG("register_vga: igd_opregion = %x\n", igd_opregion);
-    }
-
     if ( ret != 0 )
         PT_LOG("VGA region mapping failed\n");
 
@@ -171,7 +207,7 @@ int register_vga_regions(struct pt_dev *real_device)
  */
 int unregister_vga_regions(struct pt_dev *real_device)
 {
-    u32 vendor_id, igd_opregion;
+    u32 vendor_id;
     int ret = 0;
 
     if ( !gfx_passthru || real_device->pci_dev->device_class != 0x0300 )
@@ -190,12 +226,11 @@ int unregister_vga_regions(struct pt_dev *real_device)
             DPCI_REMOVE_MAPPING);
 
     vendor_id = pt_pci_host_read(real_device->pci_dev, PCI_VENDOR_ID, 2);
-    igd_opregion = pt_pci_host_read(real_device->pci_dev, PCI_INTEL_OPREGION, 
4);
-    if ( (vendor_id == PCI_VENDOR_ID_INTEL) && igd_opregion )
+    if ( (vendor_id == PCI_VENDOR_ID_INTEL) && igd_guest_opregion )
     {
         ret |= xc_domain_memory_mapping(xc_handle, domid,
-                igd_opregion >> XC_PAGE_SHIFT,
-                igd_opregion >> XC_PAGE_SHIFT,
+                igd_guest_opregion >> XC_PAGE_SHIFT,
+                igd_guest_opregion >> XC_PAGE_SHIFT,
                 2,
                 DPCI_REMOVE_MAPPING);
     }
--
generated by git-patchbot for /home/xen/git/qemu-xen-unstable.git

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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