1/* 2 * numa.c - Low-level PCI access for NUMA-Q machines 3 */ 4 5#include <linux/pci.h> 6#include <linux/init.h> 7#include <linux/nodemask.h> 8#include "pci.h" 9 10#define BUS2QUAD(global) (mp_bus_id_to_node[global]) 11#define BUS2LOCAL(global) (mp_bus_id_to_local[global]) 12#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) 13 14#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \ 15 (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3)) 16 17static int pci_conf1_mq_read(unsigned int seg, unsigned int bus, 18 unsigned int devfn, int reg, int len, u32 *value) 19{ 20 unsigned long flags; 21 22 if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 23 return -EINVAL; 24 25 spin_lock_irqsave(&pci_config_lock, flags); 26 27 outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus)); 28 29 switch (len) { 30 case 1: 31 *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus)); 32 break; 33 case 2: 34 *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus)); 35 break; 36 case 4: 37 *value = inl_quad(0xCFC, BUS2QUAD(bus)); 38 break; 39 } 40 41 spin_unlock_irqrestore(&pci_config_lock, flags); 42 43 return 0; 44} 45 46static int pci_conf1_mq_write(unsigned int seg, unsigned int bus, 47 unsigned int devfn, int reg, int len, u32 value) 48{ 49 unsigned long flags; 50 51 if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 52 return -EINVAL; 53 54 spin_lock_irqsave(&pci_config_lock, flags); 55 56 outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus)); 57 58 switch (len) { 59 case 1: 60 outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus)); 61 break; 62 case 2: 63 outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus)); 64 break; 65 case 4: 66 outl_quad((u32)value, 0xCFC, BUS2QUAD(bus)); 67 break; 68 } 69 70 spin_unlock_irqrestore(&pci_config_lock, flags); 71 72 return 0; 73} 74 75#undef PCI_CONF1_MQ_ADDRESS 76 77static struct pci_raw_ops pci_direct_conf1_mq = { 78 .read = pci_conf1_mq_read, 79 .write = pci_conf1_mq_write 80}; 81 82 83static void __devinit pci_fixup_i450nx(struct pci_dev *d) 84{ 85 /* 86 * i450NX -- Find and scan all secondary buses on all PXB's. 87 */ 88 int pxb, reg; 89 u8 busno, suba, subb; 90 int quad = BUS2QUAD(d->bus->number); 91 92 printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); 93 reg = 0xd0; 94 for(pxb=0; pxb<2; pxb++) { 95 pci_read_config_byte(d, reg++, &busno); 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} 106DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); 107 108static int __init pci_numa_init(void) 109{ 110 int quad; 111 112 raw_pci_ops = &pci_direct_conf1_mq; 113 114 if (pcibios_scanned++) 115 return 0; 116 117 pci_root_bus = pcibios_scan_root(0); 118 if (pci_root_bus) 119 pci_bus_add_devices(pci_root_bus); 120 if (num_online_nodes() > 1) 121 for_each_online_node(quad) { 122 if (quad == 0) 123 continue; 124 printk("Scanning PCI bus %d for quad %d\n", 125 QUADLOCAL2BUS(quad,0), quad); 126 pci_scan_bus(QUADLOCAL2BUS(quad,0), 127 &pci_root_ops, NULL); 128 } 129 return 0; 130} 131 132subsys_initcall(pci_numa_init); 133