diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2006-06-16 19:55:45 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-06-19 12:39:23 -0400 |
commit | 9e0c7afd0ec6e6d788df14270b2b1b8f21a384a8 (patch) | |
tree | 40ab41d3405e393c94b01b9d863263df94f39744 /arch/mips/pci/ops-bridge.c | |
parent | 3a11545615dedd8dd52ff110ddf6e970bfac963a (diff) |
[MIPS] IP27: Extract pci_ops into separate file.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/pci/ops-bridge.c')
-rw-r--r-- | arch/mips/pci/ops-bridge.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/arch/mips/pci/ops-bridge.c b/arch/mips/pci/ops-bridge.c new file mode 100644 index 000000000000..1fa09929cd7a --- /dev/null +++ b/arch/mips/pci/ops-bridge.c | |||
@@ -0,0 +1,306 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 1999, 2000, 04, 06 Ralf Baechle (ralf@linux-mips.org) | ||
7 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | ||
8 | */ | ||
9 | #include <linux/pci.h> | ||
10 | #include <asm/paccess.h> | ||
11 | #include <asm/pci/bridge.h> | ||
12 | #include <asm/sn/arch.h> | ||
13 | #include <asm/sn/intr.h> | ||
14 | #include <asm/sn/sn0/hub.h> | ||
15 | |||
16 | /* | ||
17 | * The Bridge ASIC supports both type 0 and type 1 access. Type 1 is | ||
18 | * not really documented, so right now I can't write code which uses it. | ||
19 | * Therefore we use type 0 accesses for now even though they won't work | ||
20 | * correcly for PCI-to-PCI bridges. | ||
21 | * | ||
22 | * The function is complicated by the ultimate brokeness of the IOC3 chip | ||
23 | * which is used in SGI systems. The IOC3 can only handle 32-bit PCI | ||
24 | * accesses and does only decode parts of it's address space. | ||
25 | */ | ||
26 | |||
27 | static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn, | ||
28 | int where, int size, u32 * value) | ||
29 | { | ||
30 | struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); | ||
31 | bridge_t *bridge = bc->base; | ||
32 | int slot = PCI_SLOT(devfn); | ||
33 | int fn = PCI_FUNC(devfn); | ||
34 | volatile void *addr; | ||
35 | u32 cf, shift, mask; | ||
36 | int res; | ||
37 | |||
38 | addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID]; | ||
39 | if (get_dbe(cf, (u32 *) addr)) | ||
40 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
41 | |||
42 | /* | ||
43 | * IOC3 is fucked fucked beyond believe ... Don't even give the | ||
44 | * generic PCI code a chance to look at it for real ... | ||
45 | */ | ||
46 | if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) | ||
47 | goto oh_my_gawd; | ||
48 | |||
49 | addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)]; | ||
50 | |||
51 | if (size == 1) | ||
52 | res = get_dbe(*value, (u8 *) addr); | ||
53 | else if (size == 2) | ||
54 | res = get_dbe(*value, (u16 *) addr); | ||
55 | else | ||
56 | res = get_dbe(*value, (u32 *) addr); | ||
57 | |||
58 | return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; | ||
59 | |||
60 | oh_my_gawd: | ||
61 | |||
62 | /* | ||
63 | * IOC3 is fucked fucked beyond believe ... Don't even give the | ||
64 | * generic PCI code a chance to look at the wrong register. | ||
65 | */ | ||
66 | if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) { | ||
67 | *value = 0; | ||
68 | return PCIBIOS_SUCCESSFUL; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * IOC3 is fucked fucked beyond believe ... Don't try to access | ||
73 | * anything but 32-bit words ... | ||
74 | */ | ||
75 | addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; | ||
76 | |||
77 | if (get_dbe(cf, (u32 *) addr)) | ||
78 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
79 | |||
80 | shift = ((where & 3) << 3); | ||
81 | mask = (0xffffffffU >> ((4 - size) << 3)); | ||
82 | *value = (cf >> shift) & mask; | ||
83 | |||
84 | return PCIBIOS_SUCCESSFUL; | ||
85 | } | ||
86 | |||
87 | static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn, | ||
88 | int where, int size, u32 * value) | ||
89 | { | ||
90 | struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); | ||
91 | bridge_t *bridge = bc->base; | ||
92 | int busno = bus->number; | ||
93 | int slot = PCI_SLOT(devfn); | ||
94 | int fn = PCI_FUNC(devfn); | ||
95 | volatile void *addr; | ||
96 | u32 cf, shift, mask; | ||
97 | int res; | ||
98 | |||
99 | bridge->b_pci_cfg = (busno << 16) | (slot << 11); | ||
100 | addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID]; | ||
101 | if (get_dbe(cf, (u32 *) addr)) | ||
102 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
103 | |||
104 | /* | ||
105 | * IOC3 is fucked fucked beyond believe ... Don't even give the | ||
106 | * generic PCI code a chance to look at it for real ... | ||
107 | */ | ||
108 | if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) | ||
109 | goto oh_my_gawd; | ||
110 | |||
111 | bridge->b_pci_cfg = (busno << 16) | (slot << 11); | ||
112 | addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))]; | ||
113 | |||
114 | if (size == 1) | ||
115 | res = get_dbe(*value, (u8 *) addr); | ||
116 | else if (size == 2) | ||
117 | res = get_dbe(*value, (u16 *) addr); | ||
118 | else | ||
119 | res = get_dbe(*value, (u32 *) addr); | ||
120 | |||
121 | return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; | ||
122 | |||
123 | oh_my_gawd: | ||
124 | |||
125 | /* | ||
126 | * IOC3 is fucked fucked beyond believe ... Don't even give the | ||
127 | * generic PCI code a chance to look at the wrong register. | ||
128 | */ | ||
129 | if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) { | ||
130 | *value = 0; | ||
131 | return PCIBIOS_SUCCESSFUL; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * IOC3 is fucked fucked beyond believe ... Don't try to access | ||
136 | * anything but 32-bit words ... | ||
137 | */ | ||
138 | bridge->b_pci_cfg = (busno << 16) | (slot << 11); | ||
139 | addr = &bridge->b_type1_cfg.c[(fn << 8) | where]; | ||
140 | |||
141 | if (get_dbe(cf, (u32 *) addr)) | ||
142 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
143 | |||
144 | shift = ((where & 3) << 3); | ||
145 | mask = (0xffffffffU >> ((4 - size) << 3)); | ||
146 | *value = (cf >> shift) & mask; | ||
147 | |||
148 | return PCIBIOS_SUCCESSFUL; | ||
149 | } | ||
150 | |||
151 | static int pci_read_config(struct pci_bus *bus, unsigned int devfn, | ||
152 | int where, int size, u32 * value) | ||
153 | { | ||
154 | if (bus->number > 0) | ||
155 | return pci_conf1_read_config(bus, devfn, where, size, value); | ||
156 | |||
157 | return pci_conf0_read_config(bus, devfn, where, size, value); | ||
158 | } | ||
159 | |||
160 | static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn, | ||
161 | int where, int size, u32 value) | ||
162 | { | ||
163 | struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); | ||
164 | bridge_t *bridge = bc->base; | ||
165 | int slot = PCI_SLOT(devfn); | ||
166 | int fn = PCI_FUNC(devfn); | ||
167 | volatile void *addr; | ||
168 | u32 cf, shift, mask, smask; | ||
169 | int res; | ||
170 | |||
171 | addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID]; | ||
172 | if (get_dbe(cf, (u32 *) addr)) | ||
173 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
174 | |||
175 | /* | ||
176 | * IOC3 is fucked fucked beyond believe ... Don't even give the | ||
177 | * generic PCI code a chance to look at it for real ... | ||
178 | */ | ||
179 | if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) | ||
180 | goto oh_my_gawd; | ||
181 | |||
182 | addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)]; | ||
183 | |||
184 | if (size == 1) { | ||
185 | res = put_dbe(value, (u8 *) addr); | ||
186 | } else if (size == 2) { | ||
187 | res = put_dbe(value, (u16 *) addr); | ||
188 | } else { | ||
189 | res = put_dbe(value, (u32 *) addr); | ||
190 | } | ||
191 | |||
192 | if (res) | ||
193 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
194 | |||
195 | return PCIBIOS_SUCCESSFUL; | ||
196 | |||
197 | oh_my_gawd: | ||
198 | |||
199 | /* | ||
200 | * IOC3 is fucked fucked beyond believe ... Don't even give the | ||
201 | * generic PCI code a chance to touch the wrong register. | ||
202 | */ | ||
203 | if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) | ||
204 | return PCIBIOS_SUCCESSFUL; | ||
205 | |||
206 | /* | ||
207 | * IOC3 is fucked fucked beyond believe ... Don't try to access | ||
208 | * anything but 32-bit words ... | ||
209 | */ | ||
210 | addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; | ||
211 | |||
212 | if (get_dbe(cf, (u32 *) addr)) | ||
213 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
214 | |||
215 | shift = ((where & 3) << 3); | ||
216 | mask = (0xffffffffU >> ((4 - size) << 3)); | ||
217 | smask = mask << shift; | ||
218 | |||
219 | cf = (cf & ~smask) | ((value & mask) << shift); | ||
220 | if (put_dbe(cf, (u32 *) addr)) | ||
221 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
222 | |||
223 | return PCIBIOS_SUCCESSFUL; | ||
224 | } | ||
225 | |||
226 | static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn, | ||
227 | int where, int size, u32 value) | ||
228 | { | ||
229 | struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); | ||
230 | bridge_t *bridge = bc->base; | ||
231 | int slot = PCI_SLOT(devfn); | ||
232 | int fn = PCI_FUNC(devfn); | ||
233 | int busno = bus->number; | ||
234 | volatile void *addr; | ||
235 | u32 cf, shift, mask, smask; | ||
236 | int res; | ||
237 | |||
238 | bridge->b_pci_cfg = (busno << 16) | (slot << 11); | ||
239 | addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID]; | ||
240 | if (get_dbe(cf, (u32 *) addr)) | ||
241 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
242 | |||
243 | /* | ||
244 | * IOC3 is fucked fucked beyond believe ... Don't even give the | ||
245 | * generic PCI code a chance to look at it for real ... | ||
246 | */ | ||
247 | if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) | ||
248 | goto oh_my_gawd; | ||
249 | |||
250 | addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))]; | ||
251 | |||
252 | if (size == 1) { | ||
253 | res = put_dbe(value, (u8 *) addr); | ||
254 | } else if (size == 2) { | ||
255 | res = put_dbe(value, (u16 *) addr); | ||
256 | } else { | ||
257 | res = put_dbe(value, (u32 *) addr); | ||
258 | } | ||
259 | |||
260 | if (res) | ||
261 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
262 | |||
263 | return PCIBIOS_SUCCESSFUL; | ||
264 | |||
265 | oh_my_gawd: | ||
266 | |||
267 | /* | ||
268 | * IOC3 is fucked fucked beyond believe ... Don't even give the | ||
269 | * generic PCI code a chance to touch the wrong register. | ||
270 | */ | ||
271 | if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) | ||
272 | return PCIBIOS_SUCCESSFUL; | ||
273 | |||
274 | /* | ||
275 | * IOC3 is fucked fucked beyond believe ... Don't try to access | ||
276 | * anything but 32-bit words ... | ||
277 | */ | ||
278 | addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; | ||
279 | |||
280 | if (get_dbe(cf, (u32 *) addr)) | ||
281 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
282 | |||
283 | shift = ((where & 3) << 3); | ||
284 | mask = (0xffffffffU >> ((4 - size) << 3)); | ||
285 | smask = mask << shift; | ||
286 | |||
287 | cf = (cf & ~smask) | ((value & mask) << shift); | ||
288 | if (put_dbe(cf, (u32 *) addr)) | ||
289 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
290 | |||
291 | return PCIBIOS_SUCCESSFUL; | ||
292 | } | ||
293 | |||
294 | static int pci_write_config(struct pci_bus *bus, unsigned int devfn, | ||
295 | int where, int size, u32 value) | ||
296 | { | ||
297 | if (bus->number > 0) | ||
298 | return pci_conf1_write_config(bus, devfn, where, size, value); | ||
299 | |||
300 | return pci_conf0_write_config(bus, devfn, where, size, value); | ||
301 | } | ||
302 | |||
303 | struct pci_ops bridge_pci_ops = { | ||
304 | .read = pci_read_config, | ||
305 | .write = pci_write_config, | ||
306 | }; | ||