Message ID | 1401440369-29929-4-git-send-email-tiejun.chen@intel.com |
---|---|
State | New |
Headers | show |
On Fri, May 30, 2014 at 04:59:27PM +0800, Tiejun Chen wrote: > Some registers of Intel IGD are mapped in host bridge, so it needs to > passthrough these registers of physical host bridge to guest because > emulated host bridge in guest doesn't have these mappings. > > The original patch is from Weidong Han < weidong.han @ intel.com > > > Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com> > Signed-off-by: Tiejun Chen <tiejun.chen@intel.com> > Cc: Weidong Han <weidong.han@intel.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> > --- > v4: > > * Given that pci_create_pch() is called unconditionally, so we just return 0 > even if its failed to check xen_has_gfx_passthru. > * Remove one spurious change. > > v3: > > * Improve comments to make that readable. > > v2: > > * To introduce is_igd_passthrough() to make sure we touch physical host bridge > only in IGD case. > > hw/xen/xen_pt.h | 4 ++ > hw/xen/xen_pt_graphics.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 166 insertions(+) > > diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h > index 4d3a18d..507165c 100644 > --- a/hw/xen/xen_pt.h > +++ b/hw/xen/xen_pt.h > @@ -302,5 +302,9 @@ extern int xen_has_gfx_passthru; > int xen_pt_register_vga_regions(XenHostPCIDevice *dev); > int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev); > int xen_pt_setup_vga(XenHostPCIDevice *dev); > +int pci_create_pch(PCIBus *bus); > +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); > > #endif /* !XEN_PT_H */ > diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c > index 236b13a..c1f314a 100644 > --- a/hw/xen/xen_pt_graphics.c > +++ b/hw/xen/xen_pt_graphics.c > @@ -4,6 +4,7 @@ > #include "xen_pt.h" > #include "xen-host-pci-device.h" > #include "hw/xen/xen_backend.h" > +#include "hw/pci/pci_bus.h" > > static int is_vga_passthrough(XenHostPCIDevice *dev) > { > @@ -289,3 +290,164 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev) > XEN_PT_LOG(dev, "Intel PCH ISA bridge created.\n"); > return 0; > } > + > +int pci_create_pch(PCIBus *bus) > +{ > + XenHostPCIDevice hdev; > + int r = 0; > + > + if (!xen_has_gfx_passthru) { > + return r; > + } > + > + r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0); > + if (r) { > + XEN_PT_ERR(NULL, "Failed to find Intel PCH on host\n"); > + goto err; > + } > + > + if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) { > + r = create_pch_isa_bridge(bus, &hdev); > + if (r) { > + XEN_PT_ERR(NULL, "Failed to create PCH ISA bridge.\n"); > + goto err; > + } > + } > + > + xen_host_pci_device_put(&hdev); > + > +err: > + return r; > +} > + > +/* > + * Currently we just pass this physical host bridge for IGD, 00:02.0. > + * > + * Here pci_dev is just that host bridge, so we have to get that real > + * passthrough device by that given devfn to further confirm. > + */ > +static int is_igd_passthrough(PCIDevice *pci_dev) > +{ > + PCIDevice *f = pci_dev->bus->devices[PCI_DEVFN(2, 0)]; > + if (pci_dev->bus->devices[PCI_DEVFN(2, 0)]) { > + XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, f); > + return (is_vga_passthrough(&s->real_device) > + && (s->real_device.vendor_id == PCI_VENDOR_ID_INTEL)); > + } else { > + return 0; > + } > +} > + > +void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, > + uint32_t val, int len) > +{ > + XenHostPCIDevice dev; > + int r; > + > + /* IGD read/write is through the host bridge. > + * ISA bridge is only for detect purpose. In i915 driver it will > + * probe ISA bridge to discover the IGD, see comment in i915_drv.c: > + * intel_detect_pch(): > + * The reason to probe ISA bridge instead of Dev31:Fun0 is to > + * make graphics device passthrough work easy for VMM, that only > + * need to expose ISA bridge to let driver know the real hardware > + * underneath. This is a requirement from virtualization team. > + */ > + > + assert(pci_dev->devfn == 0x00); > + > + if (!is_igd_passthrough(pci_dev)) { > + goto write_default; > + } > + > + switch (config_addr) { > + case 0x58: /* PAVPC Offset */ > + break; > + default: > + /* Just sets the emulated values. */ > + goto write_default; > + } > + > + /* Host write */ > + r = xen_host_pci_device_get(&dev, 0, 0, 0, 0); > + if (r) { > + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); > + abort(); > + } > + > + r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len); > + if (r) { > + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); > + abort(); > + } > + > + xen_host_pci_device_put(&dev); > + > + return; > + > +write_default: > + pci_default_write_config(pci_dev, config_addr, val, len); > +} > + > +uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len) > +{ > + XenHostPCIDevice dev; > + uint32_t val; > + int r; > + > + /* IGD read/write is through the host bridge. > + * ISA bridge is only for detect purpose. In i915 driver it will > + * probe ISA bridge to discover the IGD, see comment in i915_drv.c: > + * intel_detect_pch(): > + * The reason to probe ISA bridge instead of Dev31:Fun0 is to > + * make graphics device passthrough work easy for VMM, that only > + * need to expose ISA bridge to let driver know the real hardware > + * underneath. This is a requirement from virtualization team. > + */ > + assert(pci_dev->devfn == 0x00); > + > + if (!is_igd_passthrough(pci_dev)) { > + goto read_default; > + } > + > + switch (config_addr) { > + case 0x00: /* vendor id */ > + case 0x02: /* device id */ > + case 0x08: /* revision id */ > + case 0x2c: /* sybsystem vendor id */ > + case 0x2e: /* sybsystem id */ > + case 0x50: /* SNB: processor graphics control register */ > + case 0x52: /* processor graphics control register */ > + case 0xa0: /* top of memory */ > + case 0xb0: /* ILK: BSM: should read from dev 2 offset 0x5c */ > + case 0x58: /* SNB: PAVPC Offset */ > + case 0xa4: /* SNB: graphics base of stolen memory */ > + case 0xa8: /* SNB: base of GTT stolen memory */ > + break; > + default: > + /* Just gets the emulated values. */ > + goto read_default; > + } > + > + /* Host read */ > + r = xen_host_pci_device_get(&dev, 0, 0, 0, 0); > + if (r) { > + goto err_out; > + } > + > + r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len); > + if (r) { > + goto err_out; > + } > + > + xen_host_pci_device_put(&dev); > + > + return val; > + > +read_default: > + return pci_default_read_config(pci_dev, config_addr, len); > + > +err_out: > + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); > + return -1; > +} > -- > 1.9.1 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
On Fri, 30 May 2014, Tiejun Chen wrote: > Some registers of Intel IGD are mapped in host bridge, so it needs to > passthrough these registers of physical host bridge to guest because > emulated host bridge in guest doesn't have these mappings. > > The original patch is from Weidong Han < weidong.han @ intel.com > > > Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com> > Signed-off-by: Tiejun Chen <tiejun.chen@intel.com> > Cc: Weidong Han <weidong.han@intel.com> Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > v4: > > * Given that pci_create_pch() is called unconditionally, so we just return 0 > even if its failed to check xen_has_gfx_passthru. > * Remove one spurious change. > > v3: > > * Improve comments to make that readable. > > v2: > > * To introduce is_igd_passthrough() to make sure we touch physical host bridge > only in IGD case. > > hw/xen/xen_pt.h | 4 ++ > hw/xen/xen_pt_graphics.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 166 insertions(+) > > diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h > index 4d3a18d..507165c 100644 > --- a/hw/xen/xen_pt.h > +++ b/hw/xen/xen_pt.h > @@ -302,5 +302,9 @@ extern int xen_has_gfx_passthru; > int xen_pt_register_vga_regions(XenHostPCIDevice *dev); > int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev); > int xen_pt_setup_vga(XenHostPCIDevice *dev); > +int pci_create_pch(PCIBus *bus); > +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); > > #endif /* !XEN_PT_H */ > diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c > index 236b13a..c1f314a 100644 > --- a/hw/xen/xen_pt_graphics.c > +++ b/hw/xen/xen_pt_graphics.c > @@ -4,6 +4,7 @@ > #include "xen_pt.h" > #include "xen-host-pci-device.h" > #include "hw/xen/xen_backend.h" > +#include "hw/pci/pci_bus.h" > > static int is_vga_passthrough(XenHostPCIDevice *dev) > { > @@ -289,3 +290,164 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev) > XEN_PT_LOG(dev, "Intel PCH ISA bridge created.\n"); > return 0; > } > + > +int pci_create_pch(PCIBus *bus) > +{ > + XenHostPCIDevice hdev; > + int r = 0; > + > + if (!xen_has_gfx_passthru) { > + return r; > + } > + > + r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0); > + if (r) { > + XEN_PT_ERR(NULL, "Failed to find Intel PCH on host\n"); > + goto err; > + } > + > + if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) { > + r = create_pch_isa_bridge(bus, &hdev); > + if (r) { > + XEN_PT_ERR(NULL, "Failed to create PCH ISA bridge.\n"); > + goto err; > + } > + } > + > + xen_host_pci_device_put(&hdev); > + > +err: > + return r; > +} > + > +/* > + * Currently we just pass this physical host bridge for IGD, 00:02.0. > + * > + * Here pci_dev is just that host bridge, so we have to get that real > + * passthrough device by that given devfn to further confirm. > + */ > +static int is_igd_passthrough(PCIDevice *pci_dev) > +{ > + PCIDevice *f = pci_dev->bus->devices[PCI_DEVFN(2, 0)]; > + if (pci_dev->bus->devices[PCI_DEVFN(2, 0)]) { > + XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, f); > + return (is_vga_passthrough(&s->real_device) > + && (s->real_device.vendor_id == PCI_VENDOR_ID_INTEL)); > + } else { > + return 0; > + } > +} > + > +void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, > + uint32_t val, int len) > +{ > + XenHostPCIDevice dev; > + int r; > + > + /* IGD read/write is through the host bridge. > + * ISA bridge is only for detect purpose. In i915 driver it will > + * probe ISA bridge to discover the IGD, see comment in i915_drv.c: > + * intel_detect_pch(): > + * The reason to probe ISA bridge instead of Dev31:Fun0 is to > + * make graphics device passthrough work easy for VMM, that only > + * need to expose ISA bridge to let driver know the real hardware > + * underneath. This is a requirement from virtualization team. > + */ > + > + assert(pci_dev->devfn == 0x00); > + > + if (!is_igd_passthrough(pci_dev)) { > + goto write_default; > + } > + > + switch (config_addr) { > + case 0x58: /* PAVPC Offset */ > + break; > + default: > + /* Just sets the emulated values. */ > + goto write_default; > + } > + > + /* Host write */ > + r = xen_host_pci_device_get(&dev, 0, 0, 0, 0); > + if (r) { > + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); > + abort(); > + } > + > + r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len); > + if (r) { > + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); > + abort(); > + } > + > + xen_host_pci_device_put(&dev); > + > + return; > + > +write_default: > + pci_default_write_config(pci_dev, config_addr, val, len); > +} > + > +uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len) > +{ > + XenHostPCIDevice dev; > + uint32_t val; > + int r; > + > + /* IGD read/write is through the host bridge. > + * ISA bridge is only for detect purpose. In i915 driver it will > + * probe ISA bridge to discover the IGD, see comment in i915_drv.c: > + * intel_detect_pch(): > + * The reason to probe ISA bridge instead of Dev31:Fun0 is to > + * make graphics device passthrough work easy for VMM, that only > + * need to expose ISA bridge to let driver know the real hardware > + * underneath. This is a requirement from virtualization team. > + */ > + assert(pci_dev->devfn == 0x00); > + > + if (!is_igd_passthrough(pci_dev)) { > + goto read_default; > + } > + > + switch (config_addr) { > + case 0x00: /* vendor id */ > + case 0x02: /* device id */ > + case 0x08: /* revision id */ > + case 0x2c: /* sybsystem vendor id */ > + case 0x2e: /* sybsystem id */ > + case 0x50: /* SNB: processor graphics control register */ > + case 0x52: /* processor graphics control register */ > + case 0xa0: /* top of memory */ > + case 0xb0: /* ILK: BSM: should read from dev 2 offset 0x5c */ > + case 0x58: /* SNB: PAVPC Offset */ > + case 0xa4: /* SNB: graphics base of stolen memory */ > + case 0xa8: /* SNB: base of GTT stolen memory */ > + break; > + default: > + /* Just gets the emulated values. */ > + goto read_default; > + } > + > + /* Host read */ > + r = xen_host_pci_device_get(&dev, 0, 0, 0, 0); > + if (r) { > + goto err_out; > + } > + > + r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len); > + if (r) { > + goto err_out; > + } > + > + xen_host_pci_device_put(&dev); > + > + return val; > + > +read_default: > + return pci_default_read_config(pci_dev, config_addr, len); > + > +err_out: > + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); > + return -1; > +} > -- > 1.9.1 >
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 4d3a18d..507165c 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -302,5 +302,9 @@ extern int xen_has_gfx_passthru; int xen_pt_register_vga_regions(XenHostPCIDevice *dev); int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev); int xen_pt_setup_vga(XenHostPCIDevice *dev); +int pci_create_pch(PCIBus *bus); +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); #endif /* !XEN_PT_H */ diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index 236b13a..c1f314a 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -4,6 +4,7 @@ #include "xen_pt.h" #include "xen-host-pci-device.h" #include "hw/xen/xen_backend.h" +#include "hw/pci/pci_bus.h" static int is_vga_passthrough(XenHostPCIDevice *dev) { @@ -289,3 +290,164 @@ static int create_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev) XEN_PT_LOG(dev, "Intel PCH ISA bridge created.\n"); return 0; } + +int pci_create_pch(PCIBus *bus) +{ + XenHostPCIDevice hdev; + int r = 0; + + if (!xen_has_gfx_passthru) { + return r; + } + + r = xen_host_pci_device_get(&hdev, 0, 0, 0x1f, 0); + if (r) { + XEN_PT_ERR(NULL, "Failed to find Intel PCH on host\n"); + goto err; + } + + if (hdev.vendor_id == PCI_VENDOR_ID_INTEL) { + r = create_pch_isa_bridge(bus, &hdev); + if (r) { + XEN_PT_ERR(NULL, "Failed to create PCH ISA bridge.\n"); + goto err; + } + } + + xen_host_pci_device_put(&hdev); + +err: + return r; +} + +/* + * Currently we just pass this physical host bridge for IGD, 00:02.0. + * + * Here pci_dev is just that host bridge, so we have to get that real + * passthrough device by that given devfn to further confirm. + */ +static int is_igd_passthrough(PCIDevice *pci_dev) +{ + PCIDevice *f = pci_dev->bus->devices[PCI_DEVFN(2, 0)]; + if (pci_dev->bus->devices[PCI_DEVFN(2, 0)]) { + XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, f); + return (is_vga_passthrough(&s->real_device) + && (s->real_device.vendor_id == PCI_VENDOR_ID_INTEL)); + } else { + return 0; + } +} + +void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, + uint32_t val, int len) +{ + XenHostPCIDevice dev; + int r; + + /* IGD read/write is through the host bridge. + * ISA bridge is only for detect purpose. In i915 driver it will + * probe ISA bridge to discover the IGD, see comment in i915_drv.c: + * intel_detect_pch(): + * The reason to probe ISA bridge instead of Dev31:Fun0 is to + * make graphics device passthrough work easy for VMM, that only + * need to expose ISA bridge to let driver know the real hardware + * underneath. This is a requirement from virtualization team. + */ + + assert(pci_dev->devfn == 0x00); + + if (!is_igd_passthrough(pci_dev)) { + goto write_default; + } + + switch (config_addr) { + case 0x58: /* PAVPC Offset */ + break; + default: + /* Just sets the emulated values. */ + goto write_default; + } + + /* Host write */ + r = xen_host_pci_device_get(&dev, 0, 0, 0, 0); + if (r) { + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); + abort(); + } + + r = xen_host_pci_set_block(&dev, config_addr, (uint8_t *)&val, len); + if (r) { + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); + abort(); + } + + xen_host_pci_device_put(&dev); + + return; + +write_default: + pci_default_write_config(pci_dev, config_addr, val, len); +} + +uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len) +{ + XenHostPCIDevice dev; + uint32_t val; + int r; + + /* IGD read/write is through the host bridge. + * ISA bridge is only for detect purpose. In i915 driver it will + * probe ISA bridge to discover the IGD, see comment in i915_drv.c: + * intel_detect_pch(): + * The reason to probe ISA bridge instead of Dev31:Fun0 is to + * make graphics device passthrough work easy for VMM, that only + * need to expose ISA bridge to let driver know the real hardware + * underneath. This is a requirement from virtualization team. + */ + assert(pci_dev->devfn == 0x00); + + if (!is_igd_passthrough(pci_dev)) { + goto read_default; + } + + switch (config_addr) { + case 0x00: /* vendor id */ + case 0x02: /* device id */ + case 0x08: /* revision id */ + case 0x2c: /* sybsystem vendor id */ + case 0x2e: /* sybsystem id */ + case 0x50: /* SNB: processor graphics control register */ + case 0x52: /* processor graphics control register */ + case 0xa0: /* top of memory */ + case 0xb0: /* ILK: BSM: should read from dev 2 offset 0x5c */ + case 0x58: /* SNB: PAVPC Offset */ + case 0xa4: /* SNB: graphics base of stolen memory */ + case 0xa8: /* SNB: base of GTT stolen memory */ + break; + default: + /* Just gets the emulated values. */ + goto read_default; + } + + /* Host read */ + r = xen_host_pci_device_get(&dev, 0, 0, 0, 0); + if (r) { + goto err_out; + } + + r = xen_host_pci_get_block(&dev, config_addr, (uint8_t *)&val, len); + if (r) { + goto err_out; + } + + xen_host_pci_device_put(&dev); + + return val; + +read_default: + return pci_default_read_config(pci_dev, config_addr, len); + +err_out: + XEN_PT_ERR(pci_dev, "Can't get pci_dev_host_bridge\n"); + return -1; +}