diff options
Diffstat (limited to 'arch/i386/pci')
-rw-r--r-- | arch/i386/pci/common.c | 23 | ||||
-rw-r--r-- | arch/i386/pci/fixup.c | 6 | ||||
-rw-r--r-- | arch/i386/pci/irq.c | 5 | ||||
-rw-r--r-- | arch/i386/pci/legacy.c | 2 | ||||
-rw-r--r-- | arch/i386/pci/mmconfig.c | 14 | ||||
-rw-r--r-- | arch/i386/pci/numa.c | 15 | ||||
-rw-r--r-- | arch/i386/pci/pci.h | 43 | ||||
-rw-r--r-- | arch/i386/pci/visws.c | 4 |
8 files changed, 90 insertions, 22 deletions
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 85503deeda4..ebc6f3c6634 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -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; +} diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index e7306dbf6c4..c82cbf4c722 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -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); diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index f2cb942f828..665db063a40 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -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; } diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c index 149a9588c25..5565d7016b7 100644 --- a/arch/i386/pci/legacy.c +++ b/arch/i386/pci/legacy.c @@ -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; } } diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index bb1afd9e589..1bf5816d34c 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -82,16 +82,15 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, switch (len) { case 1: - *value = readb(mmcfg_virt_addr + reg); + *value = mmio_config_readb(mmcfg_virt_addr + reg); break; case 2: - *value = readw(mmcfg_virt_addr + reg); + *value = mmio_config_readw(mmcfg_virt_addr + reg); break; case 4: - *value = readl(mmcfg_virt_addr + reg); + *value = mmio_config_readl(mmcfg_virt_addr + reg); break; } - spin_unlock_irqrestore(&pci_config_lock, flags); return 0; @@ -116,16 +115,15 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, switch (len) { case 1: - writeb(value, mmcfg_virt_addr + reg); + mmio_config_writeb(mmcfg_virt_addr + reg, value); break; case 2: - writew(value, mmcfg_virt_addr + reg); + mmio_config_writew(mmcfg_virt_addr + reg, value); break; case 4: - writel(value, mmcfg_virt_addr + reg); + mmio_config_writel(mmcfg_virt_addr + reg, value); break; } - spin_unlock_irqrestore(&pci_config_lock, flags); return 0; diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c index adbe17a38f6..f5f165f69e0 100644 --- a/arch/i386/pci/numa.c +++ b/arch/i386/pci/numa.c @@ -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; } diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index e58bae2076a..8c66f275756 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h @@ -104,3 +104,46 @@ extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); extern int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, unsigned int devfn); extern int __init pci_mmcfg_arch_init(void); + +/* + * AMD Fam10h CPUs are buggy, and cannot access MMIO config space + * on their northbrige except through the * %eax register. As such, you MUST + * NOT use normal IOMEM accesses, you need to only use the magic mmio-config + * accessor functions. + * In fact just use pci_config_*, nothing else please. + */ +static inline unsigned char mmio_config_readb(void __iomem *pos) +{ + u8 val; + asm volatile("movb (%1),%%al" : "=a" (val) : "r" (pos)); + return val; +} + +static inline unsigned short mmio_config_readw(void __iomem *pos) +{ + u16 val; + asm volatile("movw (%1),%%ax" : "=a" (val) : "r" (pos)); + return val; +} + +static inline unsigned int mmio_config_readl(void __iomem *pos) +{ + u32 val; + asm volatile("movl (%1),%%eax" : "=a" (val) : "r" (pos)); + return val; +} + +static inline void mmio_config_writeb(void __iomem *pos, u8 val) +{ + asm volatile("movb %%al,(%1)" :: "a" (val), "r" (pos) : "memory"); +} + +static inline void mmio_config_writew(void __iomem *pos, u16 val) +{ + asm volatile("movw %%ax,(%1)" :: "a" (val), "r" (pos) : "memory"); +} + +static inline void mmio_config_writel(void __iomem *pos, u32 val) +{ + asm volatile("movl %%eax,(%1)" :: "a" (val), "r" (pos) : "memory"); +} diff --git a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c index f1b486d4190..8ecb1c72259 100644 --- a/arch/i386/pci/visws.c +++ b/arch/i386/pci/visws.c @@ -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; |