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