This patch replaces pci_mmconfig_add() and introduces pci_mmconfig_delte() for adding or deleting MCFG region. The newly pci_mmconfig_add() does the following: - region check - insert_resource - ioremap - add new pci_mmcfg_region entry to pci_mmcfg_list Signed-off-by: Taku Izumi <izumi.taku@xxxxxxxxxxxxxx> --- arch/x86/include/asm/pci_x86.h | 3 arch/x86/pci/mmconfig-shared.c | 142 ++++++++++++++++++++++++++++++----------- arch/x86/pci/mmconfig_64.c | 11 --- 3 files changed, 109 insertions(+), 47 deletions(-) Index: bjorn-next/arch/x86/include/asm/pci_x86.h =================================================================== --- bjorn-next.orig/arch/x86/include/asm/pci_x86.h +++ bjorn-next/arch/x86/include/asm/pci_x86.h @@ -138,7 +138,8 @@ extern void __init pci_mmcfg_arch_free(v extern int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg); extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg); extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus); - +extern int __devinit pci_mmconfig_add(int seg, int start, int end, u64 addr); +extern int pci_mmconfig_delete(int seg, int start, int end); extern struct list_head pci_mmcfg_list; #define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20) Index: bjorn-next/arch/x86/pci/mmconfig-shared.c =================================================================== --- bjorn-next.orig/arch/x86/pci/mmconfig-shared.c +++ bjorn-next/arch/x86/pci/mmconfig-shared.c @@ -17,6 +17,7 @@ #include <linux/bitmap.h> #include <linux/dmi.h> #include <linux/slab.h> +#include <linux/mutex.h> #include <linux/rculist.h> #include <asm/e820.h> #include <asm/pci_x86.h> @@ -96,18 +97,6 @@ static __devinit struct pci_mmcfg_region return new; } -static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start, - int end, u64 addr) -{ - struct pci_mmcfg_region *new; - - new = pci_mmconfig_alloc(segment, start, end, addr); - if (new) - list_add_sorted(new); - - return new; -} - struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus) { struct pci_mmcfg_region *cfg; @@ -129,7 +118,7 @@ static const char __init *pci_mmcfg_e752 if (win == 0x0000 || win == 0xf000) return NULL; - if (pci_mmconfig_add(0, 0, 255, win << 16) == NULL) + if (pci_mmconfig_add(0, 0, 255, win << 16)) return NULL; return "Intel Corporation E7520 Memory Controller Hub"; @@ -173,7 +162,7 @@ static const char __init *pci_mmcfg_inte if ((pciexbar & mask) >= 0xf0000000U) return NULL; - if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask) == NULL) + if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask)) return NULL; return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; @@ -221,7 +210,7 @@ static const char __init *pci_mmcfg_amd_ end_bus = (1 << busnbits) - 1; for (i = 0; i < (1 << segnbits); i++) if (pci_mmconfig_add(i, 0, end_bus, - base + (1<<28) * i) == NULL) { + base + (1<<28) * i)) { free_all_mmcfg(); return NULL; } @@ -278,7 +267,7 @@ static const char __init *pci_mmcfg_nvid base <<= extcfg_base_lshift; start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; end = start + extcfg_sizebus[size_index] - 1; - if (pci_mmconfig_add(0, start, end, base) == NULL) + if (pci_mmconfig_add(0, start, end, base)) continue; mcp55_mmconf_found++; } @@ -376,7 +365,7 @@ static void __init pci_mmcfg_insert_reso pci_mmcfg_resources_inserted = 1; } -static acpi_status __init check_mcfg_resource(struct acpi_resource *res, +static acpi_status __devinit check_mcfg_resource(struct acpi_resource *res, void *data) { struct resource *mcfg_res = data; @@ -413,7 +402,7 @@ static acpi_status __init check_mcfg_res return AE_OK; } -static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl, +static acpi_status __devinit find_mboard_resource(acpi_handle handle, u32 lvl, void *context, void **rv) { struct resource *mcfg_res = context; @@ -427,7 +416,7 @@ static acpi_status __init find_mboard_re return AE_OK; } -static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used) +static int __devinit is_acpi_reserved(u64 start, u64 end, unsigned not_used) { struct resource mcfg_res; @@ -446,7 +435,7 @@ static int __init is_acpi_reserved(u64 s typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); -static int __init is_mmconf_reserved(check_reserved_t is_reserved, +static int __devinit is_mmconf_reserved(check_reserved_t is_reserved, struct pci_mmcfg_region *cfg, int with_e820) { u64 addr = cfg->res.start; @@ -507,19 +496,6 @@ static int __devinit pci_mmcfg_check_res return false; } -static void __init pci_mmcfg_reject_broken(int early) -{ - struct pci_mmcfg_region *cfg; - - list_for_each_entry(cfg, &pci_mmcfg_list, list) { - if (pci_mmcfg_check_reserved(cfg, early) == false) { - printk(KERN_INFO PREFIX "not using MMCONFIG\n"); - free_all_mmcfg(); - return; - } - } -} - static int __initdata known_bridge; static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, @@ -613,8 +589,6 @@ static void __init __pci_mmcfg_init(int if (!known_bridge) acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg); - pci_mmcfg_reject_broken(early); - if (list_empty(&pci_mmcfg_list)) return; @@ -676,3 +650,101 @@ static int __init pci_mmcfg_late_insert_ * with other system resources. */ late_initcall(pci_mmcfg_late_insert_resources); + +static DEFINE_MUTEX(pci_mmcfg_lock); + +int __devinit pci_mmconfig_add(int segment, int start, int end, u64 addr) +{ + int rc = 0; + struct pci_mmcfg_region *cfg, *new = NULL; + + if (segment < 0 || segment > USHRT_MAX || + start < 0 || start > 255 || end < start || end > 255) + return -EINVAL; + + mutex_lock(&pci_mmcfg_lock); + cfg = pci_mmconfig_lookup(segment, start); + if (cfg) { + if (cfg->start_bus <= start && cfg->end_bus >= end) { + rc = -EEXIST; + } else { + rc = -EINVAL; + printk(KERN_WARNING PREFIX + "MMCONFIG for domain %04x [bus %02x-%02x] " + "conflicts with domain %04x [bus %02x-%02x]\n", + segment, start, end, + cfg->segment, cfg->start_bus, cfg->end_bus); + } + goto out; + } + + new = pci_mmconfig_alloc(segment, start, end, addr); + if (new == NULL) { + rc = -ENOMEM; + goto out; + } + + if (!pci_mmcfg_check_reserved(new, 0)) { + rc = -EINVAL; + printk(KERN_WARNING PREFIX + "MMCONFIG for domain %04x [bus %02x-%02x] " + "isn't reserved\n", segment, start, end); + goto out; + } + + if (pci_mmcfg_resources_inserted && + insert_resource(&iomem_resource, &new->res)) { + rc = -EBUSY; + printk(KERN_WARNING PREFIX + "failed to insert resource for domain " + "%04x [bus %02x-%02x]\n", segment, start, end); + goto out; + } + + if (pci_mmcfg_arch_map(new)) { + rc = -EBUSY; + printk(KERN_WARNING PREFIX + "failed to map resource for domain " + "%04x [bus %02x-%02x]\n", segment, start, end); + goto out; + } + + list_add_sorted(new); + new = NULL; + +out: + if (new) { + if (new->res.parent) + release_resource(&new->res); + kfree(new); + } + + mutex_unlock(&pci_mmcfg_lock); + + return rc; +} + +/* Delete MMCFG information at runtime */ +int pci_mmconfig_delete(int segment, int start, int end) +{ + struct pci_mmcfg_region *cfg; + + mutex_lock(&pci_mmcfg_lock); + list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) { + if (cfg->segment == segment && cfg->start_bus == start && + cfg->end_bus == end) { + list_del_rcu(&cfg->list); + synchronize_rcu(); + pci_mmcfg_arch_unmap(cfg); + if (cfg->res.parent) + release_resource(&cfg->res); + mutex_unlock(&pci_mmcfg_lock); + kfree(cfg); + return 0; + } + } + mutex_unlock(&pci_mmcfg_lock); + + return -ENOENT; +} + Index: bjorn-next/arch/x86/pci/mmconfig_64.c =================================================================== --- bjorn-next.orig/arch/x86/pci/mmconfig_64.c +++ bjorn-next/arch/x86/pci/mmconfig_64.c @@ -112,17 +112,6 @@ static void __iomem * __devinit mcfg_ior int __init pci_mmcfg_arch_init(void) { - struct pci_mmcfg_region *cfg; - - list_for_each_entry(cfg, &pci_mmcfg_list, list) { - cfg->virt = mcfg_ioremap(cfg); - if (!cfg->virt) { - printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR\n", - &cfg->res); - pci_mmcfg_arch_free(); - return 0; - } - } raw_pci_ext_ops = &pci_mmcfg; return 1; } -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html