All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2][VTD] pci mmconfig support to be used for ATS
@ 2008-11-20  1:42 Kay, Allen M
  2008-11-20  8:56 ` Jan Beulich
  2008-11-20 11:54 ` [PATCH 1/2][VTD] pci mmconfig support to be used for ATS Espen Skoglund
  0 siblings, 2 replies; 7+ messages in thread
From: Kay, Allen M @ 2008-11-20  1:42 UTC (permalink / raw)
  To: xen-devel@lists.xensource.com; +Cc: Han, Weidong, Cui, Dexuan

[-- Attachment #1: Type: text/plain, Size: 410 bytes --]

ATS (Address Translation Service) is a PCI specification used for synchronizing iotlb translations between chipset iommu such as vt-d with iotlb on board a PCI device.

This patch enables PCI mmconfig for Intel64 systems.  Most of the code were copied from Linux.  This functionality is need for parsing ATS capability in PCIe extended configuration space.

Signed-off-by: Allen Kay <allen.m.kay@intel.com>

[-- Attachment #2: mmconfig_1119.patch --]
[-- Type: application/octet-stream, Size: 22166 bytes --]

diff -r 98d48f7680db xen/arch/x86/acpi/boot.c
--- a/xen/arch/x86/acpi/boot.c	Wed Nov 19 19:13:22 2008 +0000
+++ b/xen/arch/x86/acpi/boot.c	Wed Nov 19 04:04:50 2008 -0800
@@ -986,6 +986,8 @@ int __init acpi_boot_init(void)
 
 	acpi_dmar_init();
 
+	acpi_mmcfg_init();
+
 	return 0;
 }
 
diff -r 98d48f7680db xen/drivers/passthrough/vtd/x86/Makefile
--- a/xen/drivers/passthrough/vtd/x86/Makefile	Wed Nov 19 19:13:22 2008 +0000
+++ b/xen/drivers/passthrough/vtd/x86/Makefile	Wed Nov 19 04:24:55 2008 -0800
@@ -1,1 +1,4 @@ obj-y += vtd.o
 obj-y += vtd.o
+obj-y += acpi_mmcfg.o
+obj-y += mmconfig-shared.o
+obj-y += mmconfig_64.o
diff -r 98d48f7680db xen/include/asm-x86/acpi.h
--- a/xen/include/asm-x86/acpi.h	Wed Nov 19 19:13:22 2008 +0000
+++ b/xen/include/asm-x86/acpi.h	Wed Nov 19 04:04:50 2008 -0800
@@ -164,7 +164,8 @@ extern u8 x86_acpiid_to_apicid[];
 extern u8 x86_acpiid_to_apicid[];
 #define MAX_LOCAL_APIC 256
 
-extern int acpi_dmar_init(void);
+int acpi_dmar_init(void);
+void acpi_mmcfg_init(void);
 
 /* Incremented whenever we transition through S3. Value is 1 during boot. */
 extern uint32_t system_reset_counter;
diff -r 98d48f7680db xen/include/asm-x86/fixmap.h
--- a/xen/include/asm-x86/fixmap.h	Wed Nov 19 19:13:22 2008 +0000
+++ b/xen/include/asm-x86/fixmap.h	Wed Nov 19 04:04:50 2008 -0800
@@ -20,6 +20,7 @@
 #include <xen/iommu.h>
 #include <asm/amd-iommu.h>
 #include <asm/msi.h>
+#include <xen/pci.h>
 
 /*
  * Here we define all the compile-time 'special' virtual
@@ -51,6 +52,8 @@ enum fixed_addresses {
     FIX_TBOOT_SHARED_BASE,
     FIX_MSIX_IO_RESERV_BASE,
     FIX_MSIX_IO_RESERV_END = FIX_MSIX_IO_RESERV_BASE + MAX_MSIX_PAGES -1,
+    FIX_PCI_MMCFG_BASE,
+    FIX_PCI_MMCFG_END = FIX_PCI_MMCFG_BASE + MAX_SEGMENTS * PER_SEGMENT_ADDR_SPACE,
     __end_of_fixed_addresses
 };
 
diff -r 98d48f7680db xen/include/xen/pci.h
--- a/xen/include/xen/pci.h	Wed Nov 19 19:13:22 2008 +0000
+++ b/xen/include/xen/pci.h	Wed Nov 19 04:04:50 2008 -0800
@@ -12,6 +12,14 @@
 #include <xen/list.h>
 #include <xen/spinlock.h>
 
+#if defined(__x86_64__)
+#define MAX_SEGMENTS    4    /* support 4 pci segments for now */
+#else
+#define MAX_SEGMENTS    0
+#endif
+
+#define PER_SEGMENT_ADDR_SPACE     ((256 << 20) >> PAGE_SHIFT)
+ 
 /*
  * The PCI interface treats multi-function devices as independent
  * devices.  The slot/function address of each device is encoded
@@ -30,12 +38,14 @@
 #define PCI_BDF2(b,df)  ((((b) & 0xff) << 8) | ((df) & 0xff))
 
 struct pci_dev {
+    struct list_head list;          /* non-shared generic list head */
     struct list_head alldevs_list;
     struct list_head domain_list;
     struct list_head msi_list;
     struct domain *domain;
-    const u8 bus;
-    const u8 devfn;
+    u8 bus;
+    u8 devfn;
+    u16 ats_queue_depth;    /* ATS device invalidation queue depth */
     spinlock_t lock;
 };
 
diff -r 98d48f7680db xen/drivers/passthrough/vtd/x86/acpi_mmcfg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/x86/acpi_mmcfg.c	Wed Nov 19 04:04:50 2008 -0800
@@ -0,0 +1,103 @@
+/*
+ *  acpi_mmconfig.c - Architecture-Specific Low-Level ACPI Boot Support
+ *
+ *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * copied from Linux
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/acpi.h>
+#include <xen/irq.h>
+#include <xen/dmi.h>
+#include <asm/fixmap.h>
+#include <asm/page.h>
+#include <asm/apic.h>
+#include <asm/io_apic.h>
+#include <asm/apic.h>
+#include <asm/io.h>
+#include <asm/mpspec.h>
+#include <asm/processor.h>
+#include <mach_apic.h>
+#include <mach_mpparse.h>
+
+#include "pci.h"
+
+/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
+struct acpi_mcfg_allocation *pci_mmcfg_config;
+int pci_mmcfg_config_num;
+
+static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
+
+int acpi_parse_mcfg(struct acpi_table_header *header)
+{
+	struct acpi_table_mcfg *mcfg;
+	unsigned long i;
+	int config_size;
+
+#if !defined(__x86_64__)
+        /* only supporting x86_64 for now */ 
+	return -EINVAL;
+#endif
+
+	if (!header)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *)header;
+
+	/* how many config structures do we have */
+	pci_mmcfg_config_num = 0;
+	i = header->length - sizeof(struct acpi_table_mcfg);
+	while (i >= sizeof(struct acpi_mcfg_allocation)) {
+		++pci_mmcfg_config_num;
+		i -= sizeof(struct acpi_mcfg_allocation);
+	};
+	if (pci_mmcfg_config_num == 0) {
+		printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
+		return -ENODEV;
+	}
+
+	config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
+	pci_mmcfg_config = xmalloc_bytes(config_size);
+	if (!pci_mmcfg_config) {
+		printk(KERN_WARNING PREFIX
+		       "No memory for MCFG config tables\n");
+		return -ENOMEM;
+	}
+
+	memcpy(pci_mmcfg_config, &mcfg[1], config_size);
+
+	for (i = 0; i < pci_mmcfg_config_num; ++i) {
+		if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
+		    !acpi_mcfg_64bit_base_addr) {
+			printk(KERN_ERR PREFIX
+			       "MMCONFIG not in low 4GB of memory\n");
+			xfree(pci_mmcfg_config);
+			pci_mmcfg_config_num = 0;
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
diff -r 98d48f7680db xen/drivers/passthrough/vtd/x86/mmconfig-shared.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/x86/mmconfig-shared.c	Wed Nov 19 04:04:50 2008 -0800
@@ -0,0 +1,327 @@
+/*
+ * mmconfig-shared.c - Low-level direct PCI config space access via
+ *                     MMCONFIG - common code between i386 and x86-64.
+ *
+ * This code does:
+ * - known chipset handling
+ * - ACPI decoding and validation
+ *
+ * Per-architecture code takes care of the mappings and accesses
+ * themselves.
+ *
+ * Author: Allen Kay <allen.m.kay@intel.com> -  adapted to xen from Linux
+ */
+
+#include <xen/mm.h>
+#include <xen/acpi.h>
+#include <xen/xmalloc.h>
+#include <xen/pci.h>
+#include <xen/pci_regs.h>
+
+#include "pci.h"
+
+struct pci_raw_ops *raw_pci_ext_ops;
+struct pci_raw_ops *raw_pci_ops;
+
+/* aperture is up to 256MB but BIOS may reserve less */
+#define MMCONFIG_APER_MIN	(2 * 1024*1024)
+#define MMCONFIG_APER_MAX	(256 * 1024*1024)
+
+/* Indicate if the mmcfg resources have been placed into the resource table. */
+static int __initdata pci_mmcfg_resources_inserted;
+
+static const char __init *pci_mmcfg_e7520(void)
+{
+	u32 win;
+
+	raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
+
+	win = win & 0xf000;
+	if(win == 0x0000 || win == 0xf000)
+		pci_mmcfg_config_num = 0;
+	else {
+		pci_mmcfg_config_num = 1;
+		pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]));
+		if (!pci_mmcfg_config)
+			return NULL;
+		memset(pci_mmcfg_config, 0, sizeof(pci_mmcfg_config[0]));
+		pci_mmcfg_config[0].address = win << 16;
+		pci_mmcfg_config[0].pci_segment = 0;
+		pci_mmcfg_config[0].start_bus_number = 0;
+		pci_mmcfg_config[0].end_bus_number = 255;
+	}
+
+	return "Intel Corporation E7520 Memory Controller Hub";
+}
+
+static const char __init *pci_mmcfg_intel_945(void)
+{
+	u32 pciexbar, mask = 0, len = 0;
+
+	pci_mmcfg_config_num = 1;
+
+	raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar);
+
+	/* Enable bit */
+	if (!(pciexbar & 1))
+		pci_mmcfg_config_num = 0;
+
+	/* Size bits */
+	switch ((pciexbar >> 1) & 3) {
+	case 0:
+		mask = 0xf0000000U;
+		len  = 0x10000000U;
+		break;
+	case 1:
+		mask = 0xf8000000U;
+		len  = 0x08000000U;
+		break;
+	case 2:
+		mask = 0xfc000000U;
+		len  = 0x04000000U;
+		break;
+	default:
+		pci_mmcfg_config_num = 0;
+	}
+
+	/* Errata #2, things break when not aligned on a 256Mb boundary */
+	/* Can only happen in 64M/128M mode */
+
+	if ((pciexbar & mask) & 0x0fffffffU)
+		pci_mmcfg_config_num = 0;
+
+	/* Don't hit the APIC registers and their friends */
+	if ((pciexbar & mask) >= 0xf0000000U)
+		pci_mmcfg_config_num = 0;
+
+	if (pci_mmcfg_config_num) {
+		pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]));
+		if (!pci_mmcfg_config)
+			return NULL;
+		memset(pci_mmcfg_config, 0, sizeof(pci_mmcfg_config[0]));
+		pci_mmcfg_config[0].address = pciexbar & mask;
+		pci_mmcfg_config[0].pci_segment = 0;
+		pci_mmcfg_config[0].start_bus_number = 0;
+		pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
+	}
+
+	return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
+}
+
+struct pci_mmcfg_hostbridge_probe {
+	u32 bus;
+	u32 devfn;
+	u32 vendor;
+	u32 device;
+	const char *(*probe)(void);
+};
+
+static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
+	{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
+	  PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
+	{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
+	  PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
+};
+
+static int __init pci_mmcfg_check_hostbridge(void)
+{
+	u32 l;
+	u32 bus, devfn;
+	u16 vendor, device;
+	int i;
+	const char *name;
+
+	if (!raw_pci_ops)
+		return 0;
+
+	pci_mmcfg_config_num = 0;
+	pci_mmcfg_config = NULL;
+	name = NULL;
+
+	for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
+		bus =  pci_mmcfg_probes[i].bus;
+		devfn = pci_mmcfg_probes[i].devfn;
+		raw_pci_ops->read(0, bus, devfn, 0, 4, &l);
+		vendor = l & 0xffff;
+		device = (l >> 16) & 0xffff;
+
+		if (pci_mmcfg_probes[i].vendor == vendor &&
+		    pci_mmcfg_probes[i].device == device)
+			name = pci_mmcfg_probes[i].probe();
+	}
+
+	if (name) {
+		printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
+		       name, pci_mmcfg_config_num ? "with" : "without");
+	}
+
+	return name != NULL;
+}
+
+static int __initdata known_bridge;
+
+static struct pci_raw_ops pci_iocfg = {
+	.read =		pci_conf1_read,
+	.write =	pci_conf1_write,
+};
+
+unsigned int pci_probe = PCI_PROBE_CONF1 | PCI_PROBE_MMCONF;
+
+static void __init __pci_mmcfg_init(int early)
+{
+	raw_pci_ops = &pci_iocfg;
+	/* MMCONFIG disabled */
+	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+		return;
+
+	/* MMCONFIG already enabled */
+	if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
+		return;
+
+	/* for late to exit */
+	if (known_bridge)
+		return;
+
+	if (early) {
+		if (pci_mmcfg_check_hostbridge())
+			known_bridge = 1;
+	}
+
+	if (!known_bridge) {
+		acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
+	}
+
+	if ((pci_mmcfg_config_num == 0) ||
+	    (pci_mmcfg_config == NULL) ||
+	    (pci_mmcfg_config[0].address == 0))
+		return;
+
+	if (pci_mmcfg_arch_init()) {
+		pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+	} else {
+		/*
+		 * Signal not to attempt to insert mmcfg resources because
+		 * the architecture mmcfg setup could not initialize.
+		 */
+		pci_mmcfg_resources_inserted = 1;
+	}
+}
+
+void __init pci_mmcfg_early_init(void)
+{
+	__pci_mmcfg_init(1);
+}
+
+void __init pci_mmcfg_late_init(void)
+{
+	__pci_mmcfg_init(0);
+}
+
+void acpi_mmcfg_init(void)
+{
+	__pci_mmcfg_init(1);
+}
+
+void __iomem * ioremap_nocache(unsigned long offset, unsigned long size)
+{
+	void __iomem *addr = NULL;
+
+	BUG_ON((FIX_PCI_MMCFG_BASE + (size >> PAGE_SHIFT)) >= 
+		__end_of_fixed_addresses);
+
+	map_pages_to_xen(fix_to_virt(FIX_PCI_MMCFG_END),
+			(offset >> PAGE_SHIFT),
+			(size >> PAGE_SHIFT),
+			PAGE_HYPERVISOR_NOCACHE);
+	addr = (void __iomem *) fix_to_virt(FIX_PCI_MMCFG_END);
+
+	return(addr);
+}
+
+int pci_conf1_read(unsigned int seg, unsigned int bus,
+		unsigned int devfn, int reg, int len, u32 *value)
+{
+	switch (len) {
+	case 1:
+		*value = pci_conf_read8(bus, PCI_SLOT(devfn),
+					PCI_FUNC(devfn), reg);
+		break;
+	case 2:
+		*value = pci_conf_read16(bus, PCI_SLOT(devfn),
+					PCI_FUNC(devfn), reg);
+		break;
+	case 4:
+		*value = pci_conf_read32(bus, PCI_SLOT(devfn),
+					PCI_FUNC(devfn), reg);
+		break;
+	}
+	return 0;
+}
+
+int pci_conf1_write(unsigned int seg, unsigned int bus,
+		unsigned int devfn, int reg, int len, u32 value)
+{
+	switch (len) {
+	case 1:
+		pci_conf_write8(bus, PCI_SLOT(devfn),
+				PCI_FUNC(devfn), reg, value);
+		break;
+	case 2:
+		pci_conf_write16(bus, PCI_SLOT(devfn),
+				PCI_FUNC(devfn), reg, value);
+		break;
+	case 4:
+		pci_conf_write32(bus, PCI_SLOT(devfn),
+				PCI_FUNC(devfn), reg, value);
+		break;
+	}
+	return 0;
+}
+
+/**
+ * pci_find_ext_capability - Find an extended capability
+ * @dev: PCI device to query
+ * @cap: capability code
+ *
+ * Returns the address of the requested extended capability structure
+ * within the device's PCI configuration space or 0 if the device does
+ * not support it.  Possible values for @cap:
+ *
+ *  %PCI_EXT_CAP_ID_ERR         Advanced Error Reporting
+ *  %PCI_EXT_CAP_ID_VC          Virtual Channel
+ *  %PCI_EXT_CAP_ID_DSN         Device Serial Number
+ *  %PCI_EXT_CAP_ID_PWR         Power Budgeting
+ */
+int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
+{
+    u32 header;
+    int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
+    int pos = 0x100;
+
+    if ( !raw_pci_ext_ops)
+        return 0; 
+
+    raw_pci_ext_ops->read(0, bus, devfn, pos, 4, &header);
+
+    /*
+     * If we have no capabilities, this is indicated by cap ID,
+     * cap version and next pointer all being 0.
+     */
+    if ( (header == 0) || (header == -1) )
+    {
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "next cap:%x:%x.%x:  no extended config\n",
+                bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+        return 0;
+    }
+
+    while ( ttl-- > 0 ) {
+        if ( PCI_EXT_CAP_ID(header) == cap )
+            return pos;
+        pos = PCI_EXT_CAP_NEXT(header);
+        if ( pos < 0x100 )
+            break;
+        raw_pci_ext_ops->read(0, bus, devfn, pos, 4, &header);
+    }
+    return 0;
+}
diff -r 98d48f7680db xen/drivers/passthrough/vtd/x86/mmconfig_64.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/x86/mmconfig_64.c	Wed Nov 19 04:04:50 2008 -0800
@@ -0,0 +1,171 @@
+/*
+ * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
+ *
+ * This is an 64bit optimized version that always keeps the full mmconfig
+ * space mapped. This allows lockless config space operation.
+ *
+ * copied from Linux
+ */
+
+#include <xen/mm.h>
+#include <xen/acpi.h>
+#include <xen/xmalloc.h>
+#include <xen/pci.h>
+#include <xen/pci_regs.h>
+
+#include "pci.h"
+
+/* Static virtual mapping of the MMCONFIG aperture */
+struct mmcfg_virt {
+	struct acpi_mcfg_allocation *cfg;
+	char __iomem *virt;
+};
+static struct mmcfg_virt *pci_mmcfg_virt;
+
+static char __iomem *get_virt(unsigned int seg, unsigned bus)
+{
+	struct acpi_mcfg_allocation *cfg;
+	int cfg_num;
+
+	for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
+		cfg = pci_mmcfg_virt[cfg_num].cfg;
+		if (cfg->pci_segment == seg &&
+		    (cfg->start_bus_number <= bus) &&
+		    (cfg->end_bus_number >= bus))
+			return pci_mmcfg_virt[cfg_num].virt;
+	}
+
+	/* Fall back to type 0 */
+	return NULL;
+}
+
+static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
+{
+	char __iomem *addr;
+
+	addr = get_virt(seg, bus);
+	if (!addr)
+		return NULL;
+ 	return addr + ((bus << 20) | (devfn << 12));
+}
+
+static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
+			  unsigned int devfn, int reg, int len, u32 *value)
+{
+	char __iomem *addr;
+
+	/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
+	if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
+err:		*value = -1;
+		return -EINVAL;
+	}
+
+	addr = pci_dev_base(seg, bus, devfn);
+	if (!addr)
+		goto err;
+
+	switch (len) {
+	case 1:
+		*value = mmio_config_readb(addr + reg);
+		break;
+	case 2:
+		*value = mmio_config_readw(addr + reg);
+		break;
+	case 4:
+		*value = mmio_config_readl(addr + reg);
+		break;
+	}
+
+	return 0;
+}
+
+static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
+			   unsigned int devfn, int reg, int len, u32 value)
+{
+	char __iomem *addr;
+
+	/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
+	if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
+		return -EINVAL;
+
+	addr = pci_dev_base(seg, bus, devfn);
+	if (!addr)
+		return -EINVAL;
+
+	switch (len) {
+	case 1:
+		mmio_config_writeb(addr + reg, value);
+		break;
+	case 2:
+		mmio_config_writew(addr + reg, value);
+		break;
+	case 4:
+		mmio_config_writel(addr + reg, value);
+		break;
+	}
+
+	return 0;
+}
+
+static struct pci_raw_ops pci_mmcfg = {
+	.read =		pci_mmcfg_read,
+	.write =	pci_mmcfg_write,
+};
+
+static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
+{
+	void __iomem *addr;
+	u32 size;
+
+	size = (cfg->end_bus_number + 1) << 20;
+	addr = ioremap_nocache(cfg->address, size);
+	if (addr) {
+		printk(KERN_INFO "PCI: Using MMCONFIG at %"PRIx64" - %"PRIx64"\n",
+		       cfg->address, cfg->address + size - 1);
+	}
+	return addr;
+}
+
+int __init pci_mmcfg_arch_init(void)
+{
+	int i;
+	pci_mmcfg_virt = xmalloc_bytes(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num);
+	if (pci_mmcfg_virt == NULL) {
+		printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
+		return 0;
+	}
+	memset(pci_mmcfg_virt, 0, sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num);
+
+	for (i = 0; i < pci_mmcfg_config_num; ++i) {
+		pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
+		pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]);
+		if (!pci_mmcfg_virt[i].virt) {
+			printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
+					"segment %d\n",
+				pci_mmcfg_config[i].pci_segment);
+			pci_mmcfg_arch_free();
+			return 0;
+		}
+	}
+	raw_pci_ext_ops = &pci_mmcfg;
+	return 1;
+}
+
+void __init pci_mmcfg_arch_free(void)
+{
+	int i;
+
+	if (pci_mmcfg_virt == NULL)
+		return;
+
+	for (i = 0; i < pci_mmcfg_config_num; ++i) {
+		if (pci_mmcfg_virt[i].virt) {
+			iounmap(pci_mmcfg_virt[i].virt);
+			pci_mmcfg_virt[i].virt = NULL;
+			pci_mmcfg_virt[i].cfg = NULL;
+		}
+	}
+
+	xfree(pci_mmcfg_virt);
+	pci_mmcfg_virt = NULL;
+}
diff -r 98d48f7680db xen/drivers/passthrough/vtd/x86/pci.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/passthrough/vtd/x86/pci.h	Wed Nov 19 04:04:50 2008 -0800
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Allen Kay <allen.m.kay@intel.com> - adapted from linux
+ */
+
+#define PCI_VENDOR_ID_INTEL		0x8086
+#define PCI_DEVICE_ID_INTEL_E7520_MCH	0x3590
+#define PCI_DEVICE_ID_INTEL_82945G_HB	0x2770
+
+/* ioport ends */
+#define PCI_PROBE_BIOS		0x0001
+#define PCI_PROBE_CONF1		0x0002
+#define PCI_PROBE_CONF2		0x0004
+#define PCI_PROBE_MMCONF	0x0008
+#define PCI_PROBE_MASK		0x000f
+#define PCI_PROBE_NOEARLY	0x0010
+
+struct pci_raw_ops {
+        int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
+                                                int reg, int len, u32 *val);
+        int (*write)(unsigned int domain, unsigned int bus, unsigned int devfn,
+                                                int reg, int len, u32 val);
+};
+
+static inline unsigned char mmio_config_readb(void __iomem *pos)
+{
+	u8 val;
+	asm volatile("movb (%1),%%al" : "=a" (val) : "r" (pos));
+	return val;
+}
+
+static inline unsigned short mmio_config_readw(void __iomem *pos)
+{
+	u16 val;
+	asm volatile("movw (%1),%%ax" : "=a" (val) : "r" (pos));
+	return val;
+}
+
+static inline unsigned int mmio_config_readl(void __iomem *pos)
+{
+	u32 val;
+	asm volatile("movl (%1),%%eax" : "=a" (val) : "r" (pos));
+	return val;
+}
+
+static inline void mmio_config_writeb(void __iomem *pos, u8 val)
+{
+	asm volatile("movb %%al,(%1)" :: "a" (val), "r" (pos) : "memory");
+}
+
+static inline void mmio_config_writew(void __iomem *pos, u16 val)
+{
+	asm volatile("movw %%ax,(%1)" :: "a" (val), "r" (pos) : "memory");
+}
+
+static inline void mmio_config_writel(void __iomem *pos, u32 val)
+{
+	asm volatile("movl %%eax,(%1)" :: "a" (val), "r" (pos) : "memory");
+}
+
+/* external variable defines */
+extern unsigned int pci_probe;
+extern int pci_mmcfg_config_num;
+extern struct acpi_mcfg_allocation *pci_mmcfg_config;
+extern struct pci_raw_ops *raw_pci_ext_ops;
+
+/* fucntion prototypes */
+int __init acpi_parse_mcfg(struct acpi_table_header *header);
+int pci_conf1_read(unsigned int seg, unsigned int bus,
+                   unsigned int devfn, int reg, int len, u32 *value);
+int pci_conf1_write(unsigned int seg, unsigned int bus,
+                    unsigned int devfn, int reg, int len, u32 value);
+int __init pci_mmcfg_arch_init(void);
+void __init pci_mmcfg_arch_free(void);
+void __iomem * ioremap_nocache(unsigned long offset, unsigned long size);
+int pci_find_ext_capability(int seg, int bus, int devfn, int cap);

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

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

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2008-11-21 10:32 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-20  1:42 [PATCH 1/2][VTD] pci mmconfig support to be used for ATS Kay, Allen M
2008-11-20  8:56 ` Jan Beulich
2008-11-20 20:10   ` Kay, Allen M
2008-11-20 20:20     ` Keir Fraser
2008-11-21 10:32       ` [PATCH 1/2][VTD] pci mmconfig support to be usedfor ATS Jan Beulich
2008-11-20 11:54 ` [PATCH 1/2][VTD] pci mmconfig support to be used for ATS Espen Skoglund
2008-11-20 20:04   ` Kay, Allen M

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.