aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/acpi/boot.c2
-rw-r--r--xen/arch/x86/e820.c34
-rw-r--r--xen/arch/x86/pci.c49
-rw-r--r--xen/arch/x86/traps.c2
-rw-r--r--xen/arch/x86/x86_32/Makefile1
-rw-r--r--xen/arch/x86/x86_32/pci.c70
-rw-r--r--xen/arch/x86/x86_64/Makefile4
-rw-r--r--xen/arch/x86/x86_64/acpi_mmcfg.c98
-rw-r--r--xen/arch/x86/x86_64/mmconfig-shared.c382
-rw-r--r--xen/arch/x86/x86_64/mmconfig.h85
-rw-r--r--xen/arch/x86/x86_64/mmconfig_64.c180
-rw-r--r--xen/arch/x86/x86_64/pci.c109
-rw-r--r--xen/drivers/passthrough/vtd/extern.h6
-rw-r--r--xen/drivers/passthrough/vtd/ia64/ats.c8
-rw-r--r--xen/drivers/passthrough/vtd/iommu.c2
-rw-r--r--xen/drivers/passthrough/vtd/qinval.c2
-rw-r--r--xen/drivers/passthrough/vtd/x86/ats.c8
-rw-r--r--xen/include/asm-x86/acpi.h3
-rw-r--r--xen/include/asm-x86/config.h8
-rw-r--r--xen/include/asm-x86/e820.h1
-rw-r--r--xen/include/asm-x86/msr-index.h2
-rw-r--r--xen/include/xen/pci.h5
22 files changed, 988 insertions, 73 deletions
diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c
index 95e7fff467..f966be21db 100644
--- a/xen/arch/x86/acpi/boot.c
+++ b/xen/arch/x86/acpi/boot.c
@@ -937,6 +937,8 @@ int __init acpi_boot_init(void)
acpi_dmar_init();
+ acpi_mmcfg_init();
+
return 0;
}
diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c
index c496e377d1..db258ecc82 100644
--- a/xen/arch/x86/e820.c
+++ b/xen/arch/x86/e820.c
@@ -25,6 +25,40 @@ boolean_param("e820-verbose", e820_verbose);
struct e820map e820;
+/*
+ * This function checks if the entire range <start,end> is mapped with type.
+ *
+ * Note: this function only works correct if the e820 table is sorted and
+ * not-overlapping, which is the case
+ */
+int __init e820_all_mapped(u64 start, u64 end, unsigned type)
+{
+ int i;
+
+ for (i = 0; i < e820.nr_map; i++) {
+ struct e820entry *ei = &e820.map[i];
+
+ if (type && ei->type != type)
+ continue;
+ /* is the region (part) in overlap with the current region ?*/
+ if (ei->addr >= end || ei->addr + ei->size <= start)
+ continue;
+
+ /* if the region is at the beginning of <start,end> we move
+ * start to the end of the region since it's ok until there
+ */
+ if (ei->addr <= start)
+ start = ei->addr + ei->size;
+ /*
+ * if start is now at or beyond end, we're done, full
+ * coverage
+ */
+ if (start >= end)
+ return 1;
+ }
+ return 0;
+}
+
static void __init add_memory_region(unsigned long long start,
unsigned long long size, int type)
{
diff --git a/xen/arch/x86/pci.c b/xen/arch/x86/pci.c
index e7e5f81dd4..ea2cef9832 100644
--- a/xen/arch/x86/pci.c
+++ b/xen/arch/x86/pci.c
@@ -7,9 +7,6 @@
#include <xen/spinlock.h>
#include <asm/io.h>
-#define PCI_CONF_ADDRESS(bus, dev, func, reg) \
- (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3))
-
static DEFINE_SPINLOCK(pci_config_lock);
uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes)
@@ -69,49 +66,3 @@ void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data)
spin_unlock_irqrestore(&pci_config_lock, flags);
}
-
-uint8_t pci_conf_read8(
- unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
-{
- BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
- return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1);
-}
-
-uint16_t pci_conf_read16(
- unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
-{
- BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
- return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2);
-}
-
-uint32_t pci_conf_read32(
- unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
-{
- BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
- return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4);
-}
-
-void pci_conf_write8(
- unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
- uint8_t data)
-{
- BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
- pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1, data);
-}
-
-void pci_conf_write16(
- unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
- uint16_t data)
-{
- BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
- pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2, data);
-}
-
-void pci_conf_write32(
- unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
- uint32_t data)
-{
- BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
- pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4, data);
-}
-
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 0b134a3c10..261d97cc9a 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -2186,7 +2186,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
break;
if ( (rdmsr_safe(MSR_FAM10H_MMIO_CONF_BASE, l, h) != 0) ||
(((((u64)h << 32) | l) ^ res) &
- ~((1 << FAM10H_MMIO_CONF_ENABLE_BIT) |
+ ~( FAM10H_MMIO_CONF_ENABLE |
(FAM10H_MMIO_CONF_BUSRANGE_MASK <<
FAM10H_MMIO_CONF_BUSRANGE_SHIFT) |
((u64)FAM10H_MMIO_CONF_BASE_MASK <<
diff --git a/xen/arch/x86/x86_32/Makefile b/xen/arch/x86/x86_32/Makefile
index 619b1b1959..4e6889601c 100644
--- a/xen/arch/x86/x86_32/Makefile
+++ b/xen/arch/x86/x86_32/Makefile
@@ -5,6 +5,7 @@ obj-y += mm.o
obj-y += seg_fixup.o
obj-y += traps.o
obj-y += machine_kexec.o
+obj-y += pci.o
obj-$(crash_debug) += gdbstub.o
diff --git a/xen/arch/x86/x86_32/pci.c b/xen/arch/x86/x86_32/pci.c
new file mode 100644
index 0000000000..a5b8646e36
--- /dev/null
+++ b/xen/arch/x86/x86_32/pci.c
@@ -0,0 +1,70 @@
+/******************************************************************************
+ * pci.c
+ *
+ * Architecture-dependent PCI access functions.
+ */
+
+#include <xen/spinlock.h>
+#include <xen/pci.h>
+#include <asm/io.h>
+
+#define PCI_CONF_ADDRESS(bus, dev, func, reg) \
+ (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3))
+
+uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes);
+void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data);
+
+uint8_t pci_conf_read8(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+ return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1);
+}
+
+uint16_t pci_conf_read16(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+ return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2);
+}
+
+uint32_t pci_conf_read32(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+ return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4);
+}
+
+void pci_conf_write8(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+ uint8_t data)
+{
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+ pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1, data);
+}
+
+void pci_conf_write16(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+ uint16_t data)
+{
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+ pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2, data);
+}
+
+void pci_conf_write32(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+ uint32_t data)
+{
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+ pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4, data);
+}
+
+int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
+{
+ return 0;
+}
+
+void acpi_mmcfg_init(void)
+{
+ return;
+}
diff --git a/xen/arch/x86/x86_64/Makefile b/xen/arch/x86/x86_64/Makefile
index a1428273eb..dd340c48c3 100644
--- a/xen/arch/x86/x86_64/Makefile
+++ b/xen/arch/x86/x86_64/Makefile
@@ -5,6 +5,10 @@ obj-y += gpr_switch.o
obj-y += mm.o
obj-y += traps.o
obj-y += machine_kexec.o
+obj-y += pci.o
+obj-y += acpi_mmcfg.o
+obj-y += mmconfig_64.o
+obj-y += mmconfig-shared.o
obj-$(crash_debug) += gdbstub.o
obj-$(CONFIG_COMPAT) += compat.o
diff --git a/xen/arch/x86/x86_64/acpi_mmcfg.c b/xen/arch/x86/x86_64/acpi_mmcfg.c
new file mode 100644
index 0000000000..0663c1204d
--- /dev/null
+++ b/xen/arch/x86/x86_64/acpi_mmcfg.c
@@ -0,0 +1,98 @@
+/*
+ * 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 "mmconfig.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 (!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 --git a/xen/arch/x86/x86_64/mmconfig-shared.c b/xen/arch/x86/x86_64/mmconfig-shared.c
new file mode 100644
index 0000000000..9f8e034cd3
--- /dev/null
+++ b/xen/arch/x86/x86_64/mmconfig-shared.c
@@ -0,0 +1,382 @@
+/*
+ * 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 <asm/e820.h>
+#include <asm/msr.h>
+#include <asm/msr-index.h>
+
+#include "mmconfig.h"
+
+static int __initdata known_bridge;
+unsigned int pci_probe = PCI_PROBE_CONF1 | PCI_PROBE_MMCONF;
+
+static const char __init *pci_mmcfg_e7520(void)
+{
+ u32 win;
+ win = pci_conf_read16(0, 0, 0, 0xce);
+
+ 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;
+
+ pciexbar = pci_conf_read32(0, 0, 0, 0x48);
+
+ /* 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";
+}
+
+static const char __init *pci_mmcfg_amd_fam10h(void)
+{
+ u32 low, high, address;
+ u64 base, msr;
+ int i;
+ unsigned segnbits = 0, busnbits;
+
+ if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
+ return NULL;
+
+ address = MSR_FAM10H_MMIO_CONF_BASE;
+ if (rdmsr_safe(address, low, high))
+ return NULL;
+
+ msr = high;
+ msr <<= 32;
+ msr |= low;
+
+ /* mmconfig is not enable */
+ if (!(msr & FAM10H_MMIO_CONF_ENABLE))
+ return NULL;
+
+ base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
+
+ busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
+ FAM10H_MMIO_CONF_BUSRANGE_MASK;
+
+ /*
+ * only handle bus 0 ?
+ * need to skip it
+ */
+ if (!busnbits)
+ return NULL;
+
+ if (busnbits > 8) {
+ segnbits = busnbits - 8;
+ busnbits = 8;
+ }
+
+ pci_mmcfg_config_num = (1 << segnbits);
+ pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]) *
+ pci_mmcfg_config_num);
+ if (!pci_mmcfg_config)
+ return NULL;
+
+ for (i = 0; i < (1 << segnbits); i++) {
+ pci_mmcfg_config[i].address = base + (1<<28) * i;
+ pci_mmcfg_config[i].pci_segment = i;
+ pci_mmcfg_config[i].start_bus_number = 0;
+ pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
+ }
+
+ return "AMD Family 10h NB";
+}
+
+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 },
+ { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
+ 0x1200, pci_mmcfg_amd_fam10h },
+ { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
+ 0x1200, pci_mmcfg_amd_fam10h },
+};
+
+static int __init pci_mmcfg_check_hostbridge(void)
+{
+ u32 l;
+ u32 bus, devfn;
+ u16 vendor, device;
+ int i;
+ const char *name;
+
+ 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;
+ l = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
+ 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;
+}
+
+typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
+
+static int __init is_mmconf_reserved(
+ check_reserved_t is_reserved,
+ u64 addr, u64 size, int i,
+ typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
+{
+ u64 old_size = size;
+ int valid = 0;
+
+ while (!is_reserved(addr, addr + size - 1, E820_RESERVED)) {
+ size >>= 1;
+ if (size < (16UL<<20))
+ break;
+ }
+
+ if (size >= (16UL<<20) || size == old_size) {
+ printk(KERN_NOTICE
+ "PCI: MCFG area at %lx reserved in %s\n",
+ addr, with_e820?"E820":"ACPI motherboard resources");
+ valid = 1;
+
+ if (old_size != size) {
+ /* update end_bus_number */
+ cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
+ printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
+ "segment %hu buses %u - %u\n",
+ i, (unsigned long)cfg->address, cfg->pci_segment,
+ (unsigned int)cfg->start_bus_number,
+ (unsigned int)cfg->end_bus_number);
+ }
+ }
+
+ return valid;
+}
+
+static void __init pci_mmcfg_reject_broken(int early)
+{
+ typeof(pci_mmcfg_config[0]) *cfg;
+ int i;
+
+ if ((pci_mmcfg_config_num == 0) ||
+ (pci_mmcfg_config == NULL) ||
+ (pci_mmcfg_config[0].address == 0))
+ return;
+
+ cfg = &pci_mmcfg_config[0];
+
+ for (i = 0; i < pci_mmcfg_config_num; i++) {
+ int valid = 0;
+ u64 addr, size;
+
+ cfg = &pci_mmcfg_config[i];
+ addr = cfg->start_bus_number;
+ addr <<= 20;
+ addr += cfg->address;
+ size = cfg->end_bus_number + 1 - cfg->start_bus_number;
+ size <<= 20;
+ printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
+ "segment %hu buses %u - %u\n",
+ i, (unsigned long)cfg->address, cfg->pci_segment,
+ (unsigned int)cfg->start_bus_number,
+ (unsigned int)cfg->end_bus_number);
+
+ if (valid)
+ continue;
+
+ if (!early)
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not"
+ " reserved in ACPI motherboard resources\n",
+ cfg->address);
+
+ valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1);
+
+ if (!valid)
+ goto reject;
+ }
+
+ return;
+
+reject:
+ printk(KERN_INFO "PCI: Not using MMCONFIG.\n");
+ pci_mmcfg_arch_free();
+ xfree(pci_mmcfg_config);
+ pci_mmcfg_config = NULL;
+ pci_mmcfg_config_num = 0;
+}
+
+void __init __pci_mmcfg_init(int early)
+{
+ /* 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);
+ pci_mmcfg_reject_broken(early);
+ }
+
+ 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;
+ }
+}
+
+void acpi_mmcfg_init(void)
+{
+ __pci_mmcfg_init(1);
+}
+
+/**
+ * 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;
+
+ header = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
+
+ /*
+ * 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;
+ header = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
+ }
+ return 0;
+}
diff --git a/xen/arch/x86/x86_64/mmconfig.h b/xen/arch/x86/x86_64/mmconfig.h
new file mode 100644
index 0000000000..baab62aa0d
--- /dev/null
+++ b/xen/arch/x86/x86_64/mmconfig.h
@@ -0,0 +1,85 @@
+/*
+ * 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
+
+#define PCI_VENDOR_ID_AMD 0x1022
+#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000
+
+/*
+ * AMD Fam10h CPUs are buggy, and cannot access MMIO config space
+ * on their northbrige except through the * %eax register. As such, you MUST
+ * NOT use normal IOMEM accesses, you need to only use the magic mmio-config
+ * accessor functions.
+ * In fact just use pci_config_*, nothing else please.
+ */
+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 int pci_mmcfg_config_num;
+extern struct acpi_mcfg_allocation *pci_mmcfg_config;
+
+/* fucntion prototypes */
+int __init acpi_parse_mcfg(struct acpi_table_header *header);
+int __init pci_mmcfg_arch_init(void);
+void __init pci_mmcfg_arch_free(void);
diff --git a/xen/arch/x86/x86_64/mmconfig_64.c b/xen/arch/x86/x86_64/mmconfig_64.c
new file mode 100644
index 0000000000..81b72f6402
--- /dev/null
+++ b/xen/arch/x86/x86_64/mmconfig_64.c
@@ -0,0 +1,180 @@
+/*
+ * 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 "mmconfig.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));
+}
+
+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;
+}
+
+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 void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
+{
+ void __iomem *addr;
+ unsigned long virt;
+ unsigned long mfn;
+ unsigned long size, nr_mfn;
+
+ printk("amk_mcfg_ioremap: PCI_MCFG_VIRT_START %lx\n", (u64)PCI_MCFG_VIRT_START);
+ printk("amk_mcfg_ioremap: start_bus %x end_bus %x\n",
+ cfg->start_bus_number, cfg->end_bus_number);
+
+ virt = PCI_MCFG_VIRT_START + (cfg->pci_segment * (1 << 22)) +
+ (cfg->start_bus_number * (1 << 20));
+ mfn = cfg->address >> PAGE_SHIFT;
+ size = (cfg->end_bus_number - cfg->start_bus_number) << 20;
+ nr_mfn = size >> PAGE_SHIFT;
+
+ printk("amk_mcfg_ioremap: virt %lx mfn = %lx size %lx\n", virt, mfn, size);
+
+ map_pages_to_xen(virt, mfn, nr_mfn, PAGE_HYPERVISOR_NOCACHE);
+ addr = (void __iomem *) virt;
+
+ printk("amk_mcfg_ioremap: PCI_MCFG_VIRT_START %lx\n",
+ (u64)PCI_MCFG_VIRT_START);
+ printk("amk_mcfg_ioremap: virt %lx size %lx\n", virt, size);
+
+ 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;
+ }
+ }
+ 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 --git a/xen/arch/x86/x86_64/pci.c b/xen/arch/x86/x86_64/pci.c
new file mode 100644
index 0000000000..a8a24db3b0
--- /dev/null
+++ b/xen/arch/x86/x86_64/pci.c
@@ -0,0 +1,109 @@
+/******************************************************************************
+ * pci.c
+ *
+ * Architecture-dependent PCI access functions.
+ */
+
+#include <xen/spinlock.h>
+#include <xen/pci.h>
+#include <asm/io.h>
+
+#define PCI_CONF_ADDRESS(bus, dev, func, reg) \
+ (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3))
+
+int pci_mmcfg_read(unsigned int seg, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *value);
+int pci_mmcfg_write(unsigned int seg, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 value);
+uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes);
+void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data);
+
+uint8_t pci_conf_read8(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+ u32 value;
+
+ if ( reg > 255 )
+ {
+ pci_mmcfg_read(0, bus, PCI_DEVFN(dev, func), reg, 1, &value);
+ return value;
+ }
+ else
+ {
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7));
+ return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1);
+ }
+}
+
+uint16_t pci_conf_read16(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+ u32 value;
+
+ if ( reg > 255 )
+ {
+ pci_mmcfg_read(0, bus, PCI_DEVFN(dev, func), reg, 2, &value);
+ return value;
+ }
+ else
+ {
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7));
+ return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2);
+ }
+}
+
+uint32_t pci_conf_read32(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+ u32 value;
+
+ if ( reg > 255 )
+ {
+ pci_mmcfg_read(0, bus, PCI_DEVFN(dev, func), reg, 4, &value);
+ return value;
+ }
+ else
+ {
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7));
+ return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4);
+ }
+}
+
+void pci_conf_write8(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+ uint8_t data)
+{
+ if ( reg > 255 )
+ pci_mmcfg_write(0, bus, PCI_DEVFN(dev, func), reg, 1, data);
+ else
+ {
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7));
+ pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1, data);
+ }
+}
+
+void pci_conf_write16(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+ uint16_t data)
+{
+ if ( reg > 255 )
+ pci_mmcfg_write(0, bus, PCI_DEVFN(dev, func), reg, 2, data);
+ else
+ {
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7));
+ pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2, data);
+ }
+}
+
+void pci_conf_write32(
+ unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+ uint32_t data)
+{
+ if ( reg > 255 )
+ pci_mmcfg_write(0, bus, PCI_DEVFN(dev, func), reg, 4, data);
+ else
+ {
+ BUG_ON((bus > 255) || (dev > 31) || (func > 7));
+ pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4, data);
+ }
+}
diff --git a/xen/drivers/passthrough/vtd/extern.h b/xen/drivers/passthrough/vtd/extern.h
index 10e8d26cb8..0a20d34ac8 100644
--- a/xen/drivers/passthrough/vtd/extern.h
+++ b/xen/drivers/passthrough/vtd/extern.h
@@ -48,8 +48,14 @@ int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx);
struct iommu * ioapic_to_iommu(unsigned int apic_id);
struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id);
void clear_fault_bits(struct iommu *iommu);
+int ats_device(int seg, int bus, int devfn);
+int enable_ats_device(int seg, int bus, int devfn);
+int disable_ats_device(int seg, int bus, int devfn);
+int invalidate_ats_tcs(struct iommu *iommu);
int qinval_device_iotlb(struct iommu *iommu,
u32 max_invs_pend, u16 sid, u16 size, u64 addr);
+int dev_invalidate_iotlb(struct iommu *iommu, u16 did,
+ u64 addr, unsigned int size_order, u64 type);
struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu);
#endif // _VTD_EXTERN_H_
diff --git a/xen/drivers/passthrough/vtd/ia64/ats.c b/xen/drivers/passthrough/vtd/ia64/ats.c
index 436dc50372..0591888ebc 100644
--- a/xen/drivers/passthrough/vtd/ia64/ats.c
+++ b/xen/drivers/passthrough/vtd/ia64/ats.c
@@ -35,14 +35,6 @@ struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu)
return NULL;
}
-/*
- * BUGBUG: return 0 until pcimmcfg is checked in.
- */
-int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
-{
- return 0;
-}
-
int ats_device(int seg, int bus, int devfn)
{
return 0;
diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index 2cb3b3e664..4826a1ae45 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -1663,10 +1663,8 @@ static void setup_dom0_devices(struct domain *d)
pdev->domain = d;
list_add(&pdev->domain_list, &d->arch.pdev_list);
domain_context_mapping(d, pdev->bus, pdev->devfn);
-#if defined(NOT_YET)
if ( ats_device(0, pdev->bus, pdev->devfn) )
enable_ats_device(0, pdev->bus, pdev->devfn);
-#endif
}
}
}
diff --git a/xen/drivers/passthrough/vtd/qinval.c b/xen/drivers/passthrough/vtd/qinval.c
index 1d343d1939..5df55dcbd6 100644
--- a/xen/drivers/passthrough/vtd/qinval.c
+++ b/xen/drivers/passthrough/vtd/qinval.c
@@ -409,10 +409,8 @@ static int flush_iotlb_qi(
ret = queue_invalidate_iotlb(iommu,
(type >> DMA_TLB_FLUSH_GRANU_OFFSET), dr,
dw, did, (u8)size_order, 0, addr);
-#if defined(NOT_YET)
if ( flush_dev_iotlb )
ret |= dev_invalidate_iotlb(iommu, did, addr, size_order, type);
-#endif
ret |= invalidate_sync(iommu);
}
return ret;
diff --git a/xen/drivers/passthrough/vtd/x86/ats.c b/xen/drivers/passthrough/vtd/x86/ats.c
index cbce010485..0afad61e4d 100644
--- a/xen/drivers/passthrough/vtd/x86/ats.c
+++ b/xen/drivers/passthrough/vtd/x86/ats.c
@@ -81,14 +81,6 @@ struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu)
return NULL;
}
-/*
- * BUGBUG: return 0 until pcimmcfg is checked in.
- */
-int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
-{
- return 0;
-}
-
int ats_device(int seg, int bus, int devfn)
{
struct acpi_drhd_unit *drhd, *ats_drhd, *new_drhd;
diff --git a/xen/include/asm-x86/acpi.h b/xen/include/asm-x86/acpi.h
index 459978e491..b758095137 100644
--- a/xen/include/asm-x86/acpi.h
+++ b/xen/include/asm-x86/acpi.h
@@ -164,7 +164,8 @@ struct acpi_sleep_info {
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 --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h
index 3f4b94905d..2246145cd8 100644
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -135,7 +135,7 @@ extern unsigned int video_mode, video_flags;
* 0xffff804000000000 - 0xffff807fffffffff [256GB, 2^38 bytes, PML4:256]
* Reserved for future shared info with the guest OS (GUEST ACCESSIBLE).
* 0xffff808000000000 - 0xffff80ffffffffff [512GB, 2^39 bytes, PML4:257]
- * Reserved for future use.
+ * ioremap for PCI mmconfig space
* 0xffff810000000000 - 0xffff817fffffffff [512GB, 2^39 bytes, PML4:258]
* Guest linear page table.
* 0xffff818000000000 - 0xffff81ffffffffff [512GB, 2^39 bytes, PML4:259]
@@ -188,6 +188,12 @@ extern unsigned int video_mode, video_flags;
/* Slot 256: read-only guest-accessible machine-to-phys translation table. */
#define RO_MPT_VIRT_START (PML4_ADDR(256))
#define RO_MPT_VIRT_END (RO_MPT_VIRT_START + PML4_ENTRY_BYTES/2)
+/* Slot 257: ioremap for PCI mmconfig space for 2048 segments (512GB)
+ * - full 16-bit segment support needs 44 bits
+ * - since PML4 slot has 39 bits, we limit segments to 2048 (11-bits)
+ */
+#define PCI_MCFG_VIRT_START (PML4_ADDR(257))
+#define PCI_MCFG_VIRT_END (RDWR_MPT_VIRT_START + PML4_ENTRY_BYTES)
/* Slot 258: linear page table (guest table). */
#define LINEAR_PT_VIRT_START (PML4_ADDR(258))
#define LINEAR_PT_VIRT_END (LINEAR_PT_VIRT_START + PML4_ENTRY_BYTES)
diff --git a/xen/include/asm-x86/e820.h b/xen/include/asm-x86/e820.h
index a420ba9f80..d0486ae7c5 100644
--- a/xen/include/asm-x86/e820.h
+++ b/xen/include/asm-x86/e820.h
@@ -23,6 +23,7 @@ struct e820map {
struct e820entry map[E820MAX];
};
+extern int e820_all_mapped(u64 start, u64 end, unsigned type);
extern int reserve_e820_ram(struct e820map *e820, uint64_t s, uint64_t e);
extern int e820_change_range_type(
struct e820map *e820, uint64_t s, uint64_t e,
diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h
index ab3b2a62fb..2a2cfa6eac 100644
--- a/xen/include/asm-x86/msr-index.h
+++ b/xen/include/asm-x86/msr-index.h
@@ -231,7 +231,7 @@
/* Other AMD Fam10h MSRs */
#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058
-#define FAM10H_MMIO_CONF_ENABLE_BIT 0
+#define FAM10H_MMIO_CONF_ENABLE (1<<0)
#define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf
#define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2
#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffff
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
index 6827e0d677..86abf2e85f 100644
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -93,8 +93,13 @@ void pci_conf_write16(
void pci_conf_write32(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint32_t data);
+int pci_mmcfg_read(unsigned int seg, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *value);
+int pci_mmcfg_write(unsigned int seg, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 value);
int pci_find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap);
int pci_find_next_cap(u8 bus, unsigned int devfn, u8 pos, int cap);
+int pci_find_ext_capability(int seg, int bus, int devfn, int cap);
int msixtbl_pt_register(struct domain *d, int pirq, uint64_t gtable);
void msixtbl_pt_unregister(struct domain *d, int pirq);