===================================================================
@@ -1599,7 +1599,7 @@ config PCI_DIRECT
config PCI_MMCONFIG
def_bool y
- depends on X86_32 && PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
+ depends on X86_32 && PCI && (PCI_GOMMCONFIG || PCI_GOANY)
config PCI_OLPC
def_bool y
@@ -1611,7 +1611,11 @@ config PCI_DOMAINS
config PCI_MMCONFIG
bool "Support mmconfig PCI config space access"
- depends on X86_64 && PCI && ACPI
+ depends on X86_64 && PCI
+
+config ACPI_MMCONFIG
+ def_bool y
+ depends on PCI_MMCONFIG && ACPI
config DMAR
bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
===================================================================
@@ -155,10 +155,9 @@ char *__init __acpi_map_table(unsigned l
return ((unsigned char *)base + offset);
}
-#ifdef CONFIG_PCI_MMCONFIG
-/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
-struct acpi_mcfg_allocation *pci_mmcfg_config;
-int pci_mmcfg_config_num;
+#ifdef CONFIG_ACPI_MMCONFIG
+extern __init int extend_mmcfg(int num);
+extern __init void fill_one_mmcfg(u64 addr, int segment, int start, int end);
static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
{
@@ -170,53 +169,55 @@ static int __init acpi_mcfg_oem_check(st
int __init acpi_parse_mcfg(struct acpi_table_header *header)
{
- struct acpi_table_mcfg *mcfg;
+ struct acpi_mcfg_allocation *config;
+ int config_num;
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;
+ config_num = 0;
i = header->length - sizeof(struct acpi_table_mcfg);
while (i >= sizeof(struct acpi_mcfg_allocation)) {
- ++pci_mmcfg_config_num;
+ ++config_num;
i -= sizeof(struct acpi_mcfg_allocation);
};
- if (pci_mmcfg_config_num == 0) {
+ if (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 = kmalloc(config_size, GFP_KERNEL);
- 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);
+ acpi_mcfg_oem_check((struct acpi_table_mcfg *)header);
- acpi_mcfg_oem_check(mcfg);
+ config = (struct acpi_mcfg_allocation *)(
+ (u8 *)header + sizeof(struct acpi_table_mcfg *));
- for (i = 0; i < pci_mmcfg_config_num; ++i) {
- if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
+ for (i = 0; i < config_num; ++i) {
+ if ((config[i].address > 0xFFFFFFFF) &&
!acpi_mcfg_64bit_base_addr) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
- kfree(pci_mmcfg_config);
- pci_mmcfg_config_num = 0;
return -ENODEV;
}
}
+ if (!extend_mmcfg(config_num)) {
+ printk(KERN_WARNING PREFIX
+ "No memory for MCFG config tables\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < config_num; ++i) {
+ fill_one_mmcfg(config[i].address,
+ config[i].pci_segment,
+ config[i].start_bus_number,
+ config[i].end_bus_number);
+ }
+
return 0;
}
-#endif /* CONFIG_PCI_MMCONFIG */
+#endif /* CONFIG_ACPI_MMCONFIG */
#ifdef CONFIG_X86_LOCAL_APIC
static int __init acpi_parse_madt(struct acpi_table_header *table)
===================================================================
@@ -4,7 +4,6 @@
*
* This code does:
* - known chipset handling
- * - ACPI decoding and validation
*
* Per-architecture code takes care of the mappings and accesses
* themselves.
@@ -19,6 +18,9 @@
#include "pci.h"
+struct pci_mcfg_allocation *pci_mmcfg_config;
+int pci_mmcfg_config_num;
+
/* aperture is up to 256MB but BIOS may reserve less */
#define MMCONFIG_APER_MIN (2 * 1024*1024)
#define MMCONFIG_APER_MAX (256 * 1024*1024)
@@ -26,9 +28,9 @@
/* Indicate if the mmcfg resources have been placed into the resource table. */
static int __initdata pci_mmcfg_resources_inserted;
-static __init int extend_mmcfg(int num)
+__init int extend_mmcfg(int num)
{
- struct acpi_mcfg_allocation *new;
+ struct pci_mcfg_allocation *new;
int new_num = pci_mmcfg_config_num + num;
new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL);
@@ -45,7 +47,7 @@ static __init int extend_mmcfg(int num)
return 0;
}
-static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end)
+__init void fill_one_mmcfg(u64 addr, int segment, int start, int end)
{
int i = pci_mmcfg_config_num;
@@ -187,8 +189,12 @@ static const char __init *pci_mmcfg_nvid
/*
* do check if amd fam10h already took over
*/
- if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked)
+ if (pci_mmcfg_config_num || mcp55_checked)
+ return NULL;
+#ifdef CONFIG_ACPI_MMCONFIG
+ if (!acpi_disabled)
return NULL;
+#endif
mcp55_checked = true;
for (bus = 0; bus < 256; bus++) {
@@ -346,7 +352,7 @@ static void __init pci_mmcfg_insert_reso
names = (void *)&res[pci_mmcfg_config_num];
for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
- struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
+ struct pci_mcfg_allocation *cfg = &pci_mmcfg_config[i];
num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
res->name = names;
snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN,
@@ -363,165 +369,6 @@ static void __init pci_mmcfg_insert_reso
pci_mmcfg_resources_inserted = 1;
}
-static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
- void *data)
-{
- struct resource *mcfg_res = data;
- struct acpi_resource_address64 address;
- acpi_status status;
-
- if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
- struct acpi_resource_fixed_memory32 *fixmem32 =
- &res->data.fixed_memory32;
- if (!fixmem32)
- return AE_OK;
- if ((mcfg_res->start >= fixmem32->address) &&
- (mcfg_res->end < (fixmem32->address +
- fixmem32->address_length))) {
- mcfg_res->flags = 1;
- return AE_CTRL_TERMINATE;
- }
- }
- if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
- (res->type != ACPI_RESOURCE_TYPE_ADDRESS64))
- return AE_OK;
-
- status = acpi_resource_to_address64(res, &address);
- if (ACPI_FAILURE(status) ||
- (address.address_length <= 0) ||
- (address.resource_type != ACPI_MEMORY_RANGE))
- return AE_OK;
-
- if ((mcfg_res->start >= address.minimum) &&
- (mcfg_res->end < (address.minimum + address.address_length))) {
- mcfg_res->flags = 1;
- return AE_CTRL_TERMINATE;
- }
- return AE_OK;
-}
-
-static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- struct resource *mcfg_res = context;
-
- acpi_walk_resources(handle, METHOD_NAME__CRS,
- check_mcfg_resource, context);
-
- if (mcfg_res->flags)
- return AE_CTRL_TERMINATE;
-
- return AE_OK;
-}
-
-static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
-{
- struct resource mcfg_res;
-
- mcfg_res.start = start;
- mcfg_res.end = end;
- mcfg_res.flags = 0;
-
- acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL);
-
- if (!mcfg_res.flags)
- acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res,
- NULL);
-
- return mcfg_res.flags;
-}
-
-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;
-
- 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 (!early)
- valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0);
-
- 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);
-
- /* Don't try to do this check unless configuration
- type 1 is available. how about type 2 ?*/
- if (raw_pci_ops)
- 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();
- kfree(pci_mmcfg_config);
- pci_mmcfg_config = NULL;
- pci_mmcfg_config_num = 0;
-}
-
static int __initdata known_bridge;
static void __init __pci_mmcfg_init(int early)
@@ -543,10 +390,7 @@ static void __init __pci_mmcfg_init(int
known_bridge = 1;
}
- if (!known_bridge)
- acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
-
- pci_mmcfg_reject_broken(early);
+ pci_detect_acpi_mmcfg(early);
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
===================================================================
@@ -118,9 +118,6 @@ int acpi_unregister_ioapic(acpi_handle h
void acpi_irq_stats_init(void);
extern u32 acpi_irq_handled;
-extern struct acpi_mcfg_allocation *pci_mmcfg_config;
-extern int pci_mmcfg_config_num;
-
extern int sbf_port;
extern unsigned long acpi_realmode_flags;
===================================================================
@@ -159,3 +159,23 @@ static inline void mmio_config_writel(vo
{
asm volatile("movl %%eax,(%1)" :: "a" (val), "r" (pos) : "memory");
}
+
+#ifdef CONFIG_PCI_MMCONFIG
+
+struct pci_mcfg_allocation {
+ u64 address; /* Base address, processor-relative */
+ u16 pci_segment; /* PCI segment group number */
+ u8 start_bus_number; /* Starting PCI Bus number */
+ u8 end_bus_number; /* Final PCI Bus number */
+};
+
+extern struct pci_mcfg_allocation *pci_mmcfg_config;
+extern int pci_mmcfg_config_num;
+
+#endif
+
+#ifdef CONFIG_ACPI_MMCONFIG
+extern void __init pci_detect_acpi_mmcfg(int early);
+#else
+inline static void __init pci_detect_acpi_mmcfg(int early) { }
+#endif
===================================================================
@@ -27,7 +27,7 @@ static int mmcfg_last_accessed_cpu;
*/
static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
{
- struct acpi_mcfg_allocation *cfg;
+ struct pci_mcfg_allocation *cfg;
int cfg_num;
for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
===================================================================
@@ -7,7 +7,6 @@
#include <linux/pci.h>
#include <linux/init.h>
-#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <asm/e820.h>
@@ -15,14 +14,14 @@
/* Static virtual mapping of the MMCONFIG aperture */
struct mmcfg_virt {
- struct acpi_mcfg_allocation *cfg;
+ struct pci_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;
+ struct pci_mcfg_allocation *cfg;
int cfg_num;
for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
@@ -110,7 +109,7 @@ static struct pci_raw_ops pci_mmcfg = {
.write = pci_mmcfg_write,
};
-static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
+static void __iomem * __init mcfg_ioremap(struct pci_mcfg_allocation *cfg)
{
void __iomem *addr;
u64 start, size;
===================================================================
@@ -0,0 +1,173 @@
+/*
+ * mmconfig-acpi.c - Low-level direct PCI config space access via
+ * MMCONFIG - setup from ACPI MCFG table.
+ *
+ * This code does:
+ * - ACPI decoding and validation
+ */
+
+#include <linux/acpi.h>
+#include <asm/e820.h>
+
+#include "pci.h"
+
+static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
+ void *data)
+{
+ struct resource *mcfg_res = data;
+ struct acpi_resource_address64 address;
+ acpi_status status;
+
+ if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
+ struct acpi_resource_fixed_memory32 *fixmem32 =
+ &res->data.fixed_memory32;
+ if (!fixmem32)
+ return AE_OK;
+ if ((mcfg_res->start >= fixmem32->address) &&
+ (mcfg_res->end < (fixmem32->address +
+ fixmem32->address_length))) {
+ mcfg_res->flags = 1;
+ return AE_CTRL_TERMINATE;
+ }
+ }
+ if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
+ (res->type != ACPI_RESOURCE_TYPE_ADDRESS64))
+ return AE_OK;
+
+ status = acpi_resource_to_address64(res, &address);
+ if (ACPI_FAILURE(status) ||
+ (address.address_length <= 0) ||
+ (address.resource_type != ACPI_MEMORY_RANGE))
+ return AE_OK;
+
+ if ((mcfg_res->start >= address.minimum) &&
+ (mcfg_res->end < (address.minimum + address.address_length))) {
+ mcfg_res->flags = 1;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ struct resource *mcfg_res = context;
+
+ acpi_walk_resources(handle, METHOD_NAME__CRS,
+ check_mcfg_resource, context);
+
+ if (mcfg_res->flags)
+ return AE_CTRL_TERMINATE;
+
+ return AE_OK;
+}
+
+static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
+{
+ struct resource mcfg_res;
+
+ mcfg_res.start = start;
+ mcfg_res.end = end;
+ mcfg_res.flags = 0;
+
+ acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL);
+
+ if (!mcfg_res.flags)
+ acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res,
+ NULL);
+
+ return mcfg_res.flags;
+}
+
+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;
+}
+
+void __init pci_detect_acpi_mmcfg(int early)
+{
+ typeof(pci_mmcfg_config[0]) *cfg;
+ int i;
+
+ 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;
+
+ 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 (!early)
+ valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0);
+
+ 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);
+
+ /* Don't try to do this check unless configuration
+ type 1 is available. how about type 2 ?*/
+ if (raw_pci_ops)
+ 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();
+ kfree(pci_mmcfg_config);
+ pci_mmcfg_config = NULL;
+ pci_mmcfg_config_num = 0;
+}