[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] qemu-xen: Intel GPU passthrough, fix OpRegion mapping.
On Sun, Nov 27, 2011 at 04:23:26PM +0000, Jean Guyader wrote: > > 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> > --- > hw/pass-through.c | 8 ++-- > hw/pass-through.h | 4 ++ > hw/pt-graphics.c | 96 ++++++++++++++++++++++++++++++++++++++++++---------- > 3 files changed, 85 insertions(+), 23 deletions(-) > > diff --git a/hw/pass-through.c b/hw/pass-through.c > index 919937f..976d28f 100644 > --- a/hw/pass-through.c > +++ b/hw/pass-through.c > @@ -1455,8 +1455,7 @@ out: > return index; > } > > -static void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, > - int len) > +void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, int > len) > { > struct pt_dev *assigned_device = (struct pt_dev *)d; > struct pci_dev *pci_dev = assigned_device->pci_dev; > @@ -1637,7 +1636,7 @@ exit: > return; > } > > -static uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len) > +uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len) > { > struct pt_dev *assigned_device = (struct pt_dev *)d; > struct pci_dev *pci_dev = assigned_device->pci_dev; > @@ -4191,7 +4190,8 @@ static struct pt_dev * register_real_device(PCIBus > *e_bus, > /* Register device */ > assigned_device = (struct pt_dev *) pci_register_device(e_bus, > e_dev_name, > sizeof(struct pt_dev), e_devfn, > - pt_pci_read_config, pt_pci_write_config); > + gfx_passthru ? vgapt_pci_read_config : > pt_pci_read_config, > + gfx_passthru ? vgapt_pci_write_config : > pt_pci_write_config); > if ( assigned_device == NULL ) > { > PT_LOG("Error: couldn't register real device\n"); > diff --git a/hw/pass-through.h b/hw/pass-through.h > index 884139c..c898c7c 100644 > --- a/hw/pass-through.h > +++ b/hw/pass-through.h > @@ -422,6 +422,10 @@ 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); > +void vgapt_pci_write_config(PCIDevice *pci_dev, uint32_t config_addr, > uint32_t val, int len); > +uint32_t vgapt_pci_read_config(PCIDevice *pci_dev, uint32_t config_addr, int > len); > +uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len); > +void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, int > len); > > #endif /* __PASSTHROUGH_H__ */ > > diff --git a/hw/pt-graphics.c b/hw/pt-graphics.c > index fec7390..33cbff5 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"); > @@ -37,6 +39,77 @@ void intel_pch_init(PCIBus *bus) > pch_map_irq, "intel_bridge_1f"); > } > > +static void igd_write_opregion(PCIDevice *pci_dev, uint32_t val, int len) > +{ > + struct pt_dev *real_dev = (struct pt_dev *)pci_dev; > + uint32_t host_opregion = 0; > + int ret; > + > + if ( igd_guest_opregion || len != 4 ) > + return; > + > + host_opregion = pt_pci_host_read(real_dev->pci_dev, > + PCI_INTEL_OPREGION, len); The tabs here are a bit weird. > + 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); > + Shouldn't you unmap the older region first? > + if ( ret != 0 ) > + { > + PT_LOG("Error: Can't map opregion\n"); > + igd_guest_opregion = 0; > + } > +} > + > +void vgapt_pci_write_config(PCIDevice *pci_dev, uint32_t config_addr, > uint32_t val, int len) > +{ > +#ifdef PT_DEBUG_PCI_CONFIG_ACCESS > + PT_LOG("vgapt_pci_write_config: %x:%x.%x: addr=%x len=%x val=%x\n", > + pci_bus_num(pci_dev->bus), PCI_SLOT(pci_dev->devfn), > + PCI_FUNC(pci_dev->devfn), config_addr, len, val); > +#endif > + > + if ( igd_passthru ) > + { > + switch ( config_addr ) > + { > + case 0xfc : /* Opregion */ > + igd_write_opregion(pci_dev, val, len); > + return; No default case? I would think the compiler would throw a fit for that. > + } > + } > + > + pt_pci_write_config(pci_dev, config_addr, val, len); > +} > + > +uint32_t vgapt_pci_read_config(PCIDevice *pci_dev, uint32_t config_addr, int > len) > +{ > + uint32_t val; > + > + val = pt_pci_read_config(pci_dev, config_addr, len); > + > + if ( igd_passthru ) > + { > + switch ( config_addr ) > + { > + case 0xfc: /* OpRegion */ > + if ( igd_guest_opregion ) > + val = igd_guest_opregion; > + break; > + } > + } > +#ifdef PT_DEBUG_PCI_CONFIG_ACCESS > + PT_LOG_DEV(pci_dev, "vgapt_pci_read_config: %x:%x.%x: addr=%x len=%x > val=%x\n", > + config_addr, len, val); > +#endif > + return val; > +} > + > void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, uint32_t val, > int len) > { > struct pci_dev *pci_dev_host_bridge = pt_pci_get_dev(0, 0, 0); > @@ -99,7 +172,6 @@ uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t > config_addr, int len) > 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 ) > @@ -117,19 +189,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"); > > @@ -141,7 +200,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 ) > @@ -160,12 +219,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); > } > _______________________________________________ > Xen-devel mailing list > Xen-devel@xxxxxxxxxxxxxxxxxxx > http://lists.xensource.com/xen-devel _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |