On Sat, May 26, 2012 at 2:54 AM, Jiang Liu <jiang.liu@xxxxxxxxxx> wrote: > This patch changes mmconfig logic on x86 platforms to add MMCFG > information on demand instead of adding all MMCFG entries from > the ACPI MCFG table at boot time. So only MMCFG address ranges > used by active PCI host bridges will be actually mapped. > > Signed-off-by: Jiang Liu <liuj97@xxxxxxxxx> > --- > arch/x86/include/asm/pci_x86.h | 5 +++ > arch/x86/pci/legacy.c | 1 + > arch/x86/pci/mmconfig-shared.c | 54 +++++++++++++++++++++++++++++++++++++--- > 3 files changed, 56 insertions(+), 4 deletions(-) > > diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h > index 3e5f43c..4a1a9aa 100644 > --- a/arch/x86/include/asm/pci_x86.h > +++ b/arch/x86/include/asm/pci_x86.h > @@ -142,6 +142,11 @@ extern int __devinit pci_mmconfig_insert(struct device *dev, > uint16_t seg, uint8_t start, > uint8_t end, phys_addr_t addr); > extern int pci_mmconfig_delete(uint16_t seg, uint8_t start, uint8_t end); > +#ifdef CONFIG_ACPI > +extern void pci_mmconfig_probe(uint8_t start); > +#else > +static inline void pci_mmconfig_probe(uint8_t start) { } > +#endif > extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus); > > extern struct list_head pci_mmcfg_list; > diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c > index a1df191..e9a2384 100644 > --- a/arch/x86/pci/legacy.c > +++ b/arch/x86/pci/legacy.c > @@ -49,6 +49,7 @@ void __devinit pcibios_scan_specific_bus(int busn) > l != 0x0000 && l != 0xffff) { > DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l); > printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn); > + pci_mmconfig_probe(busn); > pci_scan_bus_on_node(busn, &pci_root_ops, node); > return; > } > diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c > index fa0aa90..e80b5c2 100644 > --- a/arch/x86/pci/mmconfig-shared.c > +++ b/arch/x86/pci/mmconfig-shared.c > @@ -19,6 +19,7 @@ > #include <linux/slab.h> > #include <linux/mutex.h> > #include <linux/rculist.h> > +#include <linux/pci-acpi.h> > #include <asm/e820.h> > #include <asm/pci_x86.h> > #include <asm/acpi.h> > @@ -616,6 +617,16 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header) > return -ENODEV; > } > > + /* > + * MMCFG information for host brideges will be added on demand > + * by pci_root driver if ACPI is enabled. But there are special > + * requirements for devices on segment 0, MMCFG information may > + * be needed for fixing hardware quirks and probing for hidden > + * buses. > + */ > + if (!acpi_disabled && cfg->pci_segment) > + continue; > + > if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number, > cfg->end_bus_number, cfg->address) == NULL) { > printk(KERN_WARNING PREFIX > @@ -625,6 +636,13 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header) > } > } > > + i = entries * sizeof(*cfg_table); > + pci_acpi_mcfg_array = kmalloc(i, GFP_KERNEL); > + if (pci_acpi_mcfg_array) { > + memcpy(pci_acpi_mcfg_array, cfg_table, i); > + pci_acpi_mcfg_entries = entries; > + } > + here cache cfg too early. should do that after pci_mmcfg_reject_broken(). otherwise will use mcfg even try to reject that before. > return 0; > } > > @@ -634,14 +652,14 @@ static void __init __pci_mmcfg_init(int early) > 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; > > + /* MMCONFIG already enabled */ > + if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF)) > + goto out; > + > if (early) { > if (pci_mmcfg_check_hostbridge()) > known_bridge = 1; > @@ -675,6 +693,14 @@ static void __init __pci_mmcfg_init(int early) > pci_mmcfg_resources_inserted = 1; > pci_mmcfg_arch_init_failed = true; > } > + > +out: > + /* > + * Free all MCFG entries if ACPI is enabled. MCFG information will > + * be added back on demand by the pci_root driver later. > + */ > + if (!early && !acpi_disabled && !known_bridge && pci_acpi_mcfg_array) > + free_all_mmcfg(); that really change the logic. looks like it will break mrst/sfi path. the scan from pci_legacy_init() for mrst/sfi will not have ext_pci_ops set for bus 0. | int __init pci_subsys_init(void) | { | /* | * The init function returns an non zero value when | * pci_legacy_init should be invoked. | */ | if (x86_init.pci.init()) | pci_legacy_init(); | | pcibios_fixup_peer_bridges(); Yinghai > } > > void __init pci_mmcfg_early_init(void) > @@ -809,3 +835,23 @@ int pci_mmconfig_delete(uint16_t seg, uint8_t start, uint8_t end) > > return -ENOENT; > } > + > +/* Probe MMCFG information for PCI bus blind probe */ > +void __devinit pci_mmconfig_probe(uint8_t start) > +{ > + int end_bus, temp; > + phys_addr_t addr; > + > + if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed) > + return; > + > + addr = acpi_pci_root_get_mcfg_addr(NULL, 0, start, &end_bus); > + if (addr && end_bus >= 0 && end_bus <= 255) { > + for (temp = start + 1; temp <= end_bus; temp++) > + if (pci_find_bus(0, temp)) > + break; > + > + temp--; > + pci_mmconfig_insert(NULL, 0, start, (uint8_t)temp, addr); > + } > +} > -- > 1.7.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