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