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>
This commit is contained in:
Родитель
f0b85c0cfd
Коммит
73c59afc65
|
@ -455,3 +455,26 @@ void pcibios_disable_device (struct pci_dev *dev)
|
|||
if (!dev->msi_enabled && pcibios_disable_irq)
|
||||
pcibios_disable_irq(dev);
|
||||
}
|
||||
|
||||
struct pci_bus *pci_scan_bus_with_sysdata(int busno)
|
||||
{
|
||||
struct pci_bus *bus = NULL;
|
||||
struct pci_sysdata *sd;
|
||||
|
||||
/*
|
||||
* Allocate per-root-bus (not per bus) arch-specific data.
|
||||
* TODO: leak; this memory is never freed.
|
||||
* It's arguable whether it's worth the trouble to care.
|
||||
*/
|
||||
sd = kzalloc(sizeof(*sd), GFP_KERNEL);
|
||||
if (!sd) {
|
||||
printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno);
|
||||
return NULL;
|
||||
}
|
||||
sd->node = -1;
|
||||
bus = pci_scan_bus(busno, &pci_root_ops, sd);
|
||||
if (!bus)
|
||||
kfree(sd);
|
||||
|
||||
return bus;
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
|
|||
pci_read_config_byte(d, reg++, &subb);
|
||||
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
|
||||
if (busno)
|
||||
pci_scan_bus(busno, &pci_root_ops, NULL); /* Bus A */
|
||||
pci_scan_bus_with_sysdata(busno); /* Bus A */
|
||||
if (suba < subb)
|
||||
pci_scan_bus(suba+1, &pci_root_ops, NULL); /* Bus B */
|
||||
pci_scan_bus_with_sysdata(suba+1); /* Bus B */
|
||||
}
|
||||
pcibios_last_bus = -1;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d)
|
|||
u8 busno;
|
||||
pci_read_config_byte(d, 0x4a, &busno);
|
||||
printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno);
|
||||
pci_scan_bus(busno, &pci_root_ops, NULL);
|
||||
pci_scan_bus_with_sysdata(busno);
|
||||
pcibios_last_bus = -1;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx);
|
||||
|
|
|
@ -138,8 +138,9 @@ static void __init pirq_peer_trick(void)
|
|||
for(i = 1; i < 256; i++) {
|
||||
if (!busmap[i] || pci_find_bus(0, i))
|
||||
continue;
|
||||
if (pci_scan_bus(i, &pci_root_ops, NULL))
|
||||
printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
|
||||
if (pci_scan_bus_with_sysdata(i))
|
||||
printk(KERN_INFO "PCI: Discovered primary peer "
|
||||
"bus %02x [IRQ]\n", i);
|
||||
}
|
||||
pcibios_last_bus = -1;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ static void __devinit pcibios_fixup_peer_bridges(void)
|
|||
l != 0x0000 && l != 0xffff) {
|
||||
DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l);
|
||||
printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
|
||||
pci_scan_bus(n, &pci_root_ops, NULL);
|
||||
pci_scan_bus_with_sysdata(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,10 +96,14 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
|
|||
pci_read_config_byte(d, reg++, &suba);
|
||||
pci_read_config_byte(d, reg++, &subb);
|
||||
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
|
||||
if (busno)
|
||||
pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops, NULL); /* Bus A */
|
||||
if (suba < subb)
|
||||
pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops, NULL); /* Bus B */
|
||||
if (busno) {
|
||||
/* Bus A */
|
||||
pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno));
|
||||
}
|
||||
if (suba < subb) {
|
||||
/* Bus B */
|
||||
pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1));
|
||||
}
|
||||
}
|
||||
pcibios_last_bus = -1;
|
||||
}
|
||||
|
@ -123,8 +127,7 @@ static int __init pci_numa_init(void)
|
|||
continue;
|
||||
printk("Scanning PCI bus %d for quad %d\n",
|
||||
QUADLOCAL2BUS(quad,0), quad);
|
||||
pci_scan_bus(QUADLOCAL2BUS(quad,0),
|
||||
&pci_root_ops, NULL);
|
||||
pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -101,8 +101,8 @@ static int __init pcibios_init(void)
|
|||
"bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0);
|
||||
|
||||
raw_pci_ops = &pci_direct_conf1;
|
||||
pci_scan_bus(pci_bus0, &pci_root_ops, NULL);
|
||||
pci_scan_bus(pci_bus1, &pci_root_ops, NULL);
|
||||
pci_scan_bus_with_sysdata(pci_bus0);
|
||||
pci_scan_bus_with_sysdata(pci_bus1);
|
||||
pci_fixup_irqs(visws_swizzle, visws_map_irq);
|
||||
pcibios_resource_survey();
|
||||
return 0;
|
||||
|
|
|
@ -8,6 +8,9 @@ struct pci_sysdata {
|
|||
int node; /* NUMA node */
|
||||
};
|
||||
|
||||
/* scan a bus after allocating a pci_sysdata for it */
|
||||
extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
|
||||
|
||||
#include <linux/mm.h> /* for struct page */
|
||||
|
||||
/* Can be used to override the logic in pci_scan_bus for skipping
|
||||
|
|
|
@ -10,6 +10,8 @@ struct pci_sysdata {
|
|||
void* iommu; /* IOMMU private data */
|
||||
};
|
||||
|
||||
extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
|
||||
|
||||
#ifdef CONFIG_CALGARY_IOMMU
|
||||
static inline void* pci_iommu(struct pci_bus *bus)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче