finish i386 and x86-64 sysdata conversion

This patch finishes the i386 and x86-64 ->sysdata conversion and hopefully
also fixes Riku's and Andy's observed bugs. It is based on Yinghai Lu's
and Andy Whitcroft's patches (thanks!) with some changes:

- introduce pci_scan_bus_with_sysdata() and use it instead of
pci_scan_bus() where appropriate. pci_scan_bus_with_sysdata() will
allocate the sysdata structure and then call pci_scan_bus().
- always allocate pci_sysdata dynamically. The whole point of this
sysdata work is to make it easy to do root-bus specific things
(e.g., support PCI domains and IOMMU's). I dislike using a default
struct pci_sysdata in some places and a dynamically allocated
pci_sysdata elsewhere - the potential for someone indavertantly
changing the default structure is too high.
- this patch only makes the minimal changes necessary, i.e., the NUMA node is
always initialized to -1. Patches to do the right thing with regards
to the NUMA node can build on top of this (either add a 'node'
parameter to pci_scan_bus_with_sysdata() or just update the node
when it becomes known).

The patch was compile tested with various configurations (e.g., NUMAQ,
VISWS) and run-time tested on i386 and x86-64. Unfortunately none of my
machines exhibited the bugs so caveat emptor.

Andy, could you please see if this fixes the NUMA issues you've seen?
Riku, does this fix "pci=noacpi" on your laptop?

Signed-off-by: Muli Ben-Yehuda <muli@il.ibm.com>
Cc: Yinghai Lu <yhlu.kernel@gmail.com>
Cc: Andi Kleen <ak@suse.de>
Cc: Chuck Ebbert <cebbert@redhat.com>
Cc: <riku.seppala@kymp.net>
Cc: Andy Whitcroft <apw@shadowen.org>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Muli Ben-Yehuda and committed by Linus Torvalds 73c59afc f0b85c0c

+46 -14
+23
arch/i386/pci/common.c
··· 455 if (!dev->msi_enabled && pcibios_disable_irq) 456 pcibios_disable_irq(dev); 457 }
··· 455 if (!dev->msi_enabled && pcibios_disable_irq) 456 pcibios_disable_irq(dev); 457 } 458 + 459 + struct pci_bus *pci_scan_bus_with_sysdata(int busno) 460 + { 461 + struct pci_bus *bus = NULL; 462 + struct pci_sysdata *sd; 463 + 464 + /* 465 + * Allocate per-root-bus (not per bus) arch-specific data. 466 + * TODO: leak; this memory is never freed. 467 + * It's arguable whether it's worth the trouble to care. 468 + */ 469 + sd = kzalloc(sizeof(*sd), GFP_KERNEL); 470 + if (!sd) { 471 + printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); 472 + return NULL; 473 + } 474 + sd->node = -1; 475 + bus = pci_scan_bus(busno, &pci_root_ops, sd); 476 + if (!bus) 477 + kfree(sd); 478 + 479 + return bus; 480 + }
+3 -3
arch/i386/pci/fixup.c
··· 25 pci_read_config_byte(d, reg++, &subb); 26 DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); 27 if (busno) 28 - pci_scan_bus(busno, &pci_root_ops, NULL); /* Bus A */ 29 if (suba < subb) 30 - pci_scan_bus(suba+1, &pci_root_ops, NULL); /* Bus B */ 31 } 32 pcibios_last_bus = -1; 33 } ··· 42 u8 busno; 43 pci_read_config_byte(d, 0x4a, &busno); 44 printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno); 45 - pci_scan_bus(busno, &pci_root_ops, NULL); 46 pcibios_last_bus = -1; 47 } 48 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx);
··· 25 pci_read_config_byte(d, reg++, &subb); 26 DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); 27 if (busno) 28 + pci_scan_bus_with_sysdata(busno); /* Bus A */ 29 if (suba < subb) 30 + pci_scan_bus_with_sysdata(suba+1); /* Bus B */ 31 } 32 pcibios_last_bus = -1; 33 } ··· 42 u8 busno; 43 pci_read_config_byte(d, 0x4a, &busno); 44 printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno); 45 + pci_scan_bus_with_sysdata(busno); 46 pcibios_last_bus = -1; 47 } 48 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx);
+3 -2
arch/i386/pci/irq.c
··· 138 for(i = 1; i < 256; i++) { 139 if (!busmap[i] || pci_find_bus(0, i)) 140 continue; 141 - if (pci_scan_bus(i, &pci_root_ops, NULL)) 142 - printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); 143 } 144 pcibios_last_bus = -1; 145 }
··· 138 for(i = 1; i < 256; i++) { 139 if (!busmap[i] || pci_find_bus(0, i)) 140 continue; 141 + if (pci_scan_bus_with_sysdata(i)) 142 + printk(KERN_INFO "PCI: Discovered primary peer " 143 + "bus %02x [IRQ]\n", i); 144 } 145 pcibios_last_bus = -1; 146 }
+1 -1
arch/i386/pci/legacy.c
··· 26 l != 0x0000 && l != 0xffff) { 27 DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); 28 printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); 29 - pci_scan_bus(n, &pci_root_ops, NULL); 30 break; 31 } 32 }
··· 26 l != 0x0000 && l != 0xffff) { 27 DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); 28 printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); 29 + pci_scan_bus_with_sysdata(n); 30 break; 31 } 32 }
+9 -6
arch/i386/pci/numa.c
··· 96 pci_read_config_byte(d, reg++, &suba); 97 pci_read_config_byte(d, reg++, &subb); 98 DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); 99 - if (busno) 100 - pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops, NULL); /* Bus A */ 101 - if (suba < subb) 102 - pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops, NULL); /* Bus B */ 103 } 104 pcibios_last_bus = -1; 105 } ··· 127 continue; 128 printk("Scanning PCI bus %d for quad %d\n", 129 QUADLOCAL2BUS(quad,0), quad); 130 - pci_scan_bus(QUADLOCAL2BUS(quad,0), 131 - &pci_root_ops, NULL); 132 } 133 return 0; 134 }
··· 96 pci_read_config_byte(d, reg++, &suba); 97 pci_read_config_byte(d, reg++, &subb); 98 DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); 99 + if (busno) { 100 + /* Bus A */ 101 + pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno)); 102 + } 103 + if (suba < subb) { 104 + /* Bus B */ 105 + pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1)); 106 + } 107 } 108 pcibios_last_bus = -1; 109 } ··· 123 continue; 124 printk("Scanning PCI bus %d for quad %d\n", 125 QUADLOCAL2BUS(quad,0), quad); 126 + pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0)); 127 } 128 return 0; 129 }
+2 -2
arch/i386/pci/visws.c
··· 101 "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0); 102 103 raw_pci_ops = &pci_direct_conf1; 104 - pci_scan_bus(pci_bus0, &pci_root_ops, NULL); 105 - pci_scan_bus(pci_bus1, &pci_root_ops, NULL); 106 pci_fixup_irqs(visws_swizzle, visws_map_irq); 107 pcibios_resource_survey(); 108 return 0;
··· 101 "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0); 102 103 raw_pci_ops = &pci_direct_conf1; 104 + pci_scan_bus_with_sysdata(pci_bus0); 105 + pci_scan_bus_with_sysdata(pci_bus1); 106 pci_fixup_irqs(visws_swizzle, visws_map_irq); 107 pcibios_resource_survey(); 108 return 0;
+3
include/asm-i386/pci.h
··· 8 int node; /* NUMA node */ 9 }; 10 11 #include <linux/mm.h> /* for struct page */ 12 13 /* Can be used to override the logic in pci_scan_bus for skipping
··· 8 int node; /* NUMA node */ 9 }; 10 11 + /* scan a bus after allocating a pci_sysdata for it */ 12 + extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); 13 + 14 #include <linux/mm.h> /* for struct page */ 15 16 /* Can be used to override the logic in pci_scan_bus for skipping
+2
include/asm-x86_64/pci.h
··· 10 void* iommu; /* IOMMU private data */ 11 }; 12 13 #ifdef CONFIG_CALGARY_IOMMU 14 static inline void* pci_iommu(struct pci_bus *bus) 15 {
··· 10 void* iommu; /* IOMMU private data */ 11 }; 12 13 + extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); 14 + 15 #ifdef CONFIG_CALGARY_IOMMU 16 static inline void* pci_iommu(struct pci_bus *bus) 17 {