]> git.karo-electronics.de Git - linux-beck.git/blob - arch/x86/pci/numa.c
x86: move mp_bus_id_to_node to numa.c
[linux-beck.git] / arch / x86 / pci / numa.c
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 <mach_apic.h>
9 #include "pci.h"
10
11 #define XQUAD_PORTIO_BASE 0xfe400000
12 #define XQUAD_PORTIO_QUAD 0x40000  /* 256k per quad. */
13
14 int mp_bus_id_to_node[MAX_MP_BUSSES];
15 #define BUS2QUAD(global) (mp_bus_id_to_node[global])
16
17 int mp_bus_id_to_local[MAX_MP_BUSSES];
18 #define BUS2LOCAL(global) (mp_bus_id_to_local[global])
19
20 int quad_local_to_mp_bus_id [NR_CPUS/4][4];
21 #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
22
23 extern void *xquad_portio;    /* Where the IO area was mapped */
24 #define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
25
26 #define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
27         (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
28
29 static void write_cf8(unsigned bus, unsigned devfn, unsigned reg)
30 {
31         unsigned val = PCI_CONF1_MQ_ADDRESS(bus, devfn, reg);
32         if (xquad_portio)
33                 writel(val, XQUAD_PORT_ADDR(0xcf8, BUS2QUAD(bus)));
34         else
35                 outl(val, 0xCF8);
36 }
37
38 static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
39                              unsigned int devfn, int reg, int len, u32 *value)
40 {
41         unsigned long flags;
42         void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
43
44         if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
45                 return -EINVAL;
46
47         spin_lock_irqsave(&pci_config_lock, flags);
48
49         write_cf8(bus, devfn, reg);
50
51         switch (len) {
52         case 1:
53                 if (xquad_portio)
54                         *value = readb(adr + (reg & 3));
55                 else
56                         *value = inb(0xCFC + (reg & 3));
57                 break;
58         case 2:
59                 if (xquad_portio)
60                         *value = readw(adr + (reg & 2));
61                 else
62                         *value = inw(0xCFC + (reg & 2));
63                 break;
64         case 4:
65                 if (xquad_portio)
66                         *value = readl(adr);
67                 else
68                         *value = inl(0xCFC);
69                 break;
70         }
71
72         spin_unlock_irqrestore(&pci_config_lock, flags);
73
74         return 0;
75 }
76
77 static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
78                               unsigned int devfn, int reg, int len, u32 value)
79 {
80         unsigned long flags;
81         void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
82
83         if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
84                 return -EINVAL;
85
86         spin_lock_irqsave(&pci_config_lock, flags);
87
88         write_cf8(bus, devfn, reg);
89
90         switch (len) {
91         case 1:
92                 if (xquad_portio)
93                         writeb(value, adr + (reg & 3));
94                 else
95                         outb((u8)value, 0xCFC + (reg & 3));
96                 break;
97         case 2:
98                 if (xquad_portio)
99                         writew(value, adr + (reg & 2));
100                 else
101                         outw((u16)value, 0xCFC + (reg & 2));
102                 break;
103         case 4:
104                 if (xquad_portio)
105                         writel(value, adr + reg);
106                 else
107                         outl((u32)value, 0xCFC);
108                 break;
109         }
110
111         spin_unlock_irqrestore(&pci_config_lock, flags);
112
113         return 0;
114 }
115
116 #undef PCI_CONF1_MQ_ADDRESS
117
118 static struct pci_raw_ops pci_direct_conf1_mq = {
119         .read   = pci_conf1_mq_read,
120         .write  = pci_conf1_mq_write
121 };
122
123
124 static void __devinit pci_fixup_i450nx(struct pci_dev *d)
125 {
126         /*
127          * i450NX -- Find and scan all secondary buses on all PXB's.
128          */
129         int pxb, reg;
130         u8 busno, suba, subb;
131         int quad = BUS2QUAD(d->bus->number);
132
133         printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
134         reg = 0xd0;
135         for(pxb=0; pxb<2; pxb++) {
136                 pci_read_config_byte(d, reg++, &busno);
137                 pci_read_config_byte(d, reg++, &suba);
138                 pci_read_config_byte(d, reg++, &subb);
139                 DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
140                 if (busno) {
141                         /* Bus A */
142                         pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno));
143                 }
144                 if (suba < subb) {
145                         /* Bus B */
146                         pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1));
147                 }
148         }
149         pcibios_last_bus = -1;
150 }
151 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx);
152
153 static int __init pci_numa_init(void)
154 {
155         int quad;
156
157         raw_pci_ops = &pci_direct_conf1_mq;
158
159         if (pcibios_scanned++)
160                 return 0;
161
162         pci_root_bus = pcibios_scan_root(0);
163         if (pci_root_bus)
164                 pci_bus_add_devices(pci_root_bus);
165         if (num_online_nodes() > 1)
166                 for_each_online_node(quad) {
167                         if (quad == 0)
168                                 continue;
169                         printk("Scanning PCI bus %d for quad %d\n", 
170                                 QUADLOCAL2BUS(quad,0), quad);
171                         pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0));
172                 }
173         return 0;
174 }
175
176 subsys_initcall(pci_numa_init);