From patchwork Wed Jun 25 02:17:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tiejun Chen X-Patchwork-Id: 363808 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 929FF1400A7 for ; Wed, 25 Jun 2014 12:21:39 +1000 (EST) Received: from localhost ([::1]:34716 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wzcq9-00084j-Nx for incoming@patchwork.ozlabs.org; Tue, 24 Jun 2014 22:21:37 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40442) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wzcnv-0004W2-RE for qemu-devel@nongnu.org; Tue, 24 Jun 2014 22:19:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Wzcnq-0005d1-LJ for qemu-devel@nongnu.org; Tue, 24 Jun 2014 22:19:19 -0400 Received: from mga11.intel.com ([192.55.52.93]:60950) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wzcnq-0005co-8e for qemu-devel@nongnu.org; Tue, 24 Jun 2014 22:19:14 -0400 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 24 Jun 2014 19:19:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.01,542,1400050800"; d="scan'208";a="560524767" Received: from tchen0-linux.bj.intel.com ([10.238.154.58]) by fmsmga002.fm.intel.com with ESMTP; 24 Jun 2014 19:19:10 -0700 From: Tiejun Chen To: pbonzini@redhat.com, anthony.perard@citrix.com, stefano.stabellini@eu.citrix.com, mst@redhat.com, Kelly.Zytaruk@amd.com Date: Wed, 25 Jun 2014 10:17:19 +0800 Message-Id: <1403662641-28526-4-git-send-email-tiejun.chen@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1403662641-28526-1-git-send-email-tiejun.chen@intel.com> References: <1403662641-28526-1-git-send-email-tiejun.chen@intel.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 192.55.52.93 Cc: peter.maydell@linaro.org, xen-devel@lists.xensource.com, allen.m.kay@intel.com, qemu-devel@nongnu.org, anthony@codemonkey.ws, yang.z.zhang@intel.com Subject: [Qemu-devel] [v5][PATCH 3/5] xen, gfx passthrough: support Intel IGD passthrough with VT-D X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 Signed-off-by: Yang Zhang Signed-off-by: Tiejun Chen Cc: Weidong Han --- v5: * Don't pass vendor/device ids in igd_pci_read(). * Add to support offset 0x44/0x48. 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 | 156 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 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 974b7e9..f3fbfed 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) { @@ -291,3 +292,158 @@ static int create_pseudo_pch_isa_bridge(PCIBus *bus, XenHostPCIDevice *hdev) XEN_PT_LOG(dev, "The pseudo 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_pseudo_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(). + */ + + assert(pci_dev->devfn == 0x00); + + if (!is_igd_passthrough(pci_dev)) { + goto write_default; + } + + /* Just work for the i915 driver. */ + 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(). + */ + assert(pci_dev->devfn == 0x00); + + if (!is_igd_passthrough(pci_dev)) { + goto read_default; + } + + /* Just work for the i915 driver. */ + switch (config_addr) { + case 0x08: /* revision id */ + case 0x2c: /* sybsystem vendor id */ + case 0x2e: /* sybsystem id */ + case 0x44: /* MCHBAR I915 */ + case 0x48: /* MCHBAR I965 */ + 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; +}