@@ -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 */
@@ -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)
{
@@ -293,3 +294,161 @@ 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 -1;
+ }
+
+ 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.
+ */
+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;
+}