diff options
Diffstat (limited to 'arch/powerpc/kernel/rtas_pci.c')
-rw-r--r-- | arch/powerpc/kernel/rtas_pci.c | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c new file mode 100644 index 000000000000..0e5a8e116653 --- /dev/null +++ b/arch/powerpc/kernel/rtas_pci.c | |||
@@ -0,0 +1,513 @@ | |||
1 | /* | ||
2 | * arch/ppc64/kernel/rtas_pci.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Dave Engebretsen, IBM Corporation | ||
5 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM | ||
6 | * | ||
7 | * RTAS specific routines for PCI. | ||
8 | * | ||
9 | * Based on code from pci.c, chrp_pci.c and pSeries_pci.c | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/threads.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/bootmem.h> | ||
32 | |||
33 | #include <asm/io.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/prom.h> | ||
37 | #include <asm/machdep.h> | ||
38 | #include <asm/pci-bridge.h> | ||
39 | #include <asm/iommu.h> | ||
40 | #include <asm/rtas.h> | ||
41 | #include <asm/mpic.h> | ||
42 | #include <asm/ppc-pci.h> | ||
43 | |||
44 | /* RTAS tokens */ | ||
45 | static int read_pci_config; | ||
46 | static int write_pci_config; | ||
47 | static int ibm_read_pci_config; | ||
48 | static int ibm_write_pci_config; | ||
49 | |||
50 | static inline int config_access_valid(struct pci_dn *dn, int where) | ||
51 | { | ||
52 | if (where < 256) | ||
53 | return 1; | ||
54 | if (where < 4096 && dn->pci_ext_config_space) | ||
55 | return 1; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int of_device_available(struct device_node * dn) | ||
61 | { | ||
62 | char * status; | ||
63 | |||
64 | status = get_property(dn, "status", NULL); | ||
65 | |||
66 | if (!status) | ||
67 | return 1; | ||
68 | |||
69 | if (!strcmp(status, "okay")) | ||
70 | return 1; | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) | ||
76 | { | ||
77 | int returnval = -1; | ||
78 | unsigned long buid, addr; | ||
79 | int ret; | ||
80 | |||
81 | if (!pdn) | ||
82 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
83 | if (!config_access_valid(pdn, where)) | ||
84 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
85 | |||
86 | addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | | ||
87 | (pdn->devfn << 8) | (where & 0xff); | ||
88 | buid = pdn->phb->buid; | ||
89 | if (buid) { | ||
90 | ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, | ||
91 | addr, BUID_HI(buid), BUID_LO(buid), size); | ||
92 | } else { | ||
93 | ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); | ||
94 | } | ||
95 | *val = returnval; | ||
96 | |||
97 | if (ret) | ||
98 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
99 | |||
100 | if (returnval == EEH_IO_ERROR_VALUE(size) && | ||
101 | eeh_dn_check_failure (pdn->node, NULL)) | ||
102 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
103 | |||
104 | return PCIBIOS_SUCCESSFUL; | ||
105 | } | ||
106 | |||
107 | static int rtas_pci_read_config(struct pci_bus *bus, | ||
108 | unsigned int devfn, | ||
109 | int where, int size, u32 *val) | ||
110 | { | ||
111 | struct device_node *busdn, *dn; | ||
112 | |||
113 | if (bus->self) | ||
114 | busdn = pci_device_to_OF_node(bus->self); | ||
115 | else | ||
116 | busdn = bus->sysdata; /* must be a phb */ | ||
117 | |||
118 | /* Search only direct children of the bus */ | ||
119 | for (dn = busdn->child; dn; dn = dn->sibling) { | ||
120 | struct pci_dn *pdn = PCI_DN(dn); | ||
121 | if (pdn && pdn->devfn == devfn | ||
122 | && of_device_available(dn)) | ||
123 | return rtas_read_config(pdn, where, size, val); | ||
124 | } | ||
125 | |||
126 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
127 | } | ||
128 | |||
129 | int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val) | ||
130 | { | ||
131 | unsigned long buid, addr; | ||
132 | int ret; | ||
133 | |||
134 | if (!pdn) | ||
135 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
136 | if (!config_access_valid(pdn, where)) | ||
137 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
138 | |||
139 | addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | | ||
140 | (pdn->devfn << 8) | (where & 0xff); | ||
141 | buid = pdn->phb->buid; | ||
142 | if (buid) { | ||
143 | ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, | ||
144 | BUID_HI(buid), BUID_LO(buid), size, (ulong) val); | ||
145 | } else { | ||
146 | ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); | ||
147 | } | ||
148 | |||
149 | if (ret) | ||
150 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
151 | |||
152 | return PCIBIOS_SUCCESSFUL; | ||
153 | } | ||
154 | |||
155 | static int rtas_pci_write_config(struct pci_bus *bus, | ||
156 | unsigned int devfn, | ||
157 | int where, int size, u32 val) | ||
158 | { | ||
159 | struct device_node *busdn, *dn; | ||
160 | |||
161 | if (bus->self) | ||
162 | busdn = pci_device_to_OF_node(bus->self); | ||
163 | else | ||
164 | busdn = bus->sysdata; /* must be a phb */ | ||
165 | |||
166 | /* Search only direct children of the bus */ | ||
167 | for (dn = busdn->child; dn; dn = dn->sibling) { | ||
168 | struct pci_dn *pdn = PCI_DN(dn); | ||
169 | if (pdn && pdn->devfn == devfn | ||
170 | && of_device_available(dn)) | ||
171 | return rtas_write_config(pdn, where, size, val); | ||
172 | } | ||
173 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
174 | } | ||
175 | |||
176 | struct pci_ops rtas_pci_ops = { | ||
177 | rtas_pci_read_config, | ||
178 | rtas_pci_write_config | ||
179 | }; | ||
180 | |||
181 | int is_python(struct device_node *dev) | ||
182 | { | ||
183 | char *model = (char *)get_property(dev, "model", NULL); | ||
184 | |||
185 | if (model && strstr(model, "Python")) | ||
186 | return 1; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int get_phb_reg_prop(struct device_node *dev, | ||
192 | unsigned int addr_size_words, | ||
193 | struct reg_property64 *reg) | ||
194 | { | ||
195 | unsigned int *ui_ptr = NULL, len; | ||
196 | |||
197 | /* Found a PHB, now figure out where his registers are mapped. */ | ||
198 | ui_ptr = (unsigned int *)get_property(dev, "reg", &len); | ||
199 | if (ui_ptr == NULL) | ||
200 | return 1; | ||
201 | |||
202 | if (addr_size_words == 1) { | ||
203 | reg->address = ((struct reg_property32 *)ui_ptr)->address; | ||
204 | reg->size = ((struct reg_property32 *)ui_ptr)->size; | ||
205 | } else { | ||
206 | *reg = *((struct reg_property64 *)ui_ptr); | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static void python_countermeasures(struct device_node *dev, | ||
213 | unsigned int addr_size_words) | ||
214 | { | ||
215 | struct reg_property64 reg_struct; | ||
216 | void __iomem *chip_regs; | ||
217 | volatile u32 val; | ||
218 | |||
219 | if (get_phb_reg_prop(dev, addr_size_words, ®_struct)) | ||
220 | return; | ||
221 | |||
222 | /* Python's register file is 1 MB in size. */ | ||
223 | chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); | ||
224 | |||
225 | /* | ||
226 | * Firmware doesn't always clear this bit which is critical | ||
227 | * for good performance - Anton | ||
228 | */ | ||
229 | |||
230 | #define PRG_CL_RESET_VALID 0x00010000 | ||
231 | |||
232 | val = in_be32(chip_regs + 0xf6030); | ||
233 | if (val & PRG_CL_RESET_VALID) { | ||
234 | printk(KERN_INFO "Python workaround: "); | ||
235 | val &= ~PRG_CL_RESET_VALID; | ||
236 | out_be32(chip_regs + 0xf6030, val); | ||
237 | /* | ||
238 | * We must read it back for changes to | ||
239 | * take effect | ||
240 | */ | ||
241 | val = in_be32(chip_regs + 0xf6030); | ||
242 | printk("reg0: %x\n", val); | ||
243 | } | ||
244 | |||
245 | iounmap(chip_regs); | ||
246 | } | ||
247 | |||
248 | void __init init_pci_config_tokens (void) | ||
249 | { | ||
250 | read_pci_config = rtas_token("read-pci-config"); | ||
251 | write_pci_config = rtas_token("write-pci-config"); | ||
252 | ibm_read_pci_config = rtas_token("ibm,read-pci-config"); | ||
253 | ibm_write_pci_config = rtas_token("ibm,write-pci-config"); | ||
254 | } | ||
255 | |||
256 | unsigned long __devinit get_phb_buid (struct device_node *phb) | ||
257 | { | ||
258 | int addr_cells; | ||
259 | unsigned int *buid_vals; | ||
260 | unsigned int len; | ||
261 | unsigned long buid; | ||
262 | |||
263 | if (ibm_read_pci_config == -1) return 0; | ||
264 | |||
265 | /* PHB's will always be children of the root node, | ||
266 | * or so it is promised by the current firmware. */ | ||
267 | if (phb->parent == NULL) | ||
268 | return 0; | ||
269 | if (phb->parent->parent) | ||
270 | return 0; | ||
271 | |||
272 | buid_vals = (unsigned int *) get_property(phb, "reg", &len); | ||
273 | if (buid_vals == NULL) | ||
274 | return 0; | ||
275 | |||
276 | addr_cells = prom_n_addr_cells(phb); | ||
277 | if (addr_cells == 1) { | ||
278 | buid = (unsigned long) buid_vals[0]; | ||
279 | } else { | ||
280 | buid = (((unsigned long)buid_vals[0]) << 32UL) | | ||
281 | (((unsigned long)buid_vals[1]) & 0xffffffff); | ||
282 | } | ||
283 | return buid; | ||
284 | } | ||
285 | |||
286 | static int phb_set_bus_ranges(struct device_node *dev, | ||
287 | struct pci_controller *phb) | ||
288 | { | ||
289 | int *bus_range; | ||
290 | unsigned int len; | ||
291 | |||
292 | bus_range = (int *) get_property(dev, "bus-range", &len); | ||
293 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | phb->first_busno = bus_range[0]; | ||
298 | phb->last_busno = bus_range[1]; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int __devinit setup_phb(struct device_node *dev, | ||
304 | struct pci_controller *phb, | ||
305 | unsigned int addr_size_words) | ||
306 | { | ||
307 | pci_setup_pci_controller(phb); | ||
308 | |||
309 | if (is_python(dev)) | ||
310 | python_countermeasures(dev, addr_size_words); | ||
311 | |||
312 | if (phb_set_bus_ranges(dev, phb)) | ||
313 | return 1; | ||
314 | |||
315 | phb->arch_data = dev; | ||
316 | phb->ops = &rtas_pci_ops; | ||
317 | phb->buid = get_phb_buid(dev); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static void __devinit add_linux_pci_domain(struct device_node *dev, | ||
323 | struct pci_controller *phb, | ||
324 | struct property *of_prop) | ||
325 | { | ||
326 | memset(of_prop, 0, sizeof(struct property)); | ||
327 | of_prop->name = "linux,pci-domain"; | ||
328 | of_prop->length = sizeof(phb->global_number); | ||
329 | of_prop->value = (unsigned char *)&of_prop[1]; | ||
330 | memcpy(of_prop->value, &phb->global_number, sizeof(phb->global_number)); | ||
331 | prom_add_property(dev, of_prop); | ||
332 | } | ||
333 | |||
334 | static struct pci_controller * __init alloc_phb(struct device_node *dev, | ||
335 | unsigned int addr_size_words) | ||
336 | { | ||
337 | struct pci_controller *phb; | ||
338 | struct property *of_prop; | ||
339 | |||
340 | phb = alloc_bootmem(sizeof(struct pci_controller)); | ||
341 | if (phb == NULL) | ||
342 | return NULL; | ||
343 | |||
344 | of_prop = alloc_bootmem(sizeof(struct property) + | ||
345 | sizeof(phb->global_number)); | ||
346 | if (!of_prop) | ||
347 | return NULL; | ||
348 | |||
349 | if (setup_phb(dev, phb, addr_size_words)) | ||
350 | return NULL; | ||
351 | |||
352 | add_linux_pci_domain(dev, phb, of_prop); | ||
353 | |||
354 | return phb; | ||
355 | } | ||
356 | |||
357 | static struct pci_controller * __devinit alloc_phb_dynamic(struct device_node *dev, unsigned int addr_size_words) | ||
358 | { | ||
359 | struct pci_controller *phb; | ||
360 | |||
361 | phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), | ||
362 | GFP_KERNEL); | ||
363 | if (phb == NULL) | ||
364 | return NULL; | ||
365 | |||
366 | if (setup_phb(dev, phb, addr_size_words)) | ||
367 | return NULL; | ||
368 | |||
369 | phb->is_dynamic = 1; | ||
370 | |||
371 | /* TODO: linux,pci-domain? */ | ||
372 | |||
373 | return phb; | ||
374 | } | ||
375 | |||
376 | unsigned long __init find_and_init_phbs(void) | ||
377 | { | ||
378 | struct device_node *node; | ||
379 | struct pci_controller *phb; | ||
380 | unsigned int root_size_cells = 0; | ||
381 | unsigned int index; | ||
382 | unsigned int *opprop = NULL; | ||
383 | struct device_node *root = of_find_node_by_path("/"); | ||
384 | |||
385 | if (ppc64_interrupt_controller == IC_OPEN_PIC) { | ||
386 | opprop = (unsigned int *)get_property(root, | ||
387 | "platform-open-pic", NULL); | ||
388 | } | ||
389 | |||
390 | root_size_cells = prom_n_size_cells(root); | ||
391 | |||
392 | index = 0; | ||
393 | |||
394 | for (node = of_get_next_child(root, NULL); | ||
395 | node != NULL; | ||
396 | node = of_get_next_child(root, node)) { | ||
397 | if (node->type == NULL || strcmp(node->type, "pci") != 0) | ||
398 | continue; | ||
399 | |||
400 | phb = alloc_phb(node, root_size_cells); | ||
401 | if (!phb) | ||
402 | continue; | ||
403 | |||
404 | pci_process_bridge_OF_ranges(phb, node, 0); | ||
405 | pci_setup_phb_io(phb, index == 0); | ||
406 | #ifdef CONFIG_PPC_PSERIES | ||
407 | if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { | ||
408 | int addr = root_size_cells * (index + 2) - 1; | ||
409 | mpic_assign_isu(pSeries_mpic, index, opprop[addr]); | ||
410 | } | ||
411 | #endif | ||
412 | index++; | ||
413 | } | ||
414 | |||
415 | of_node_put(root); | ||
416 | pci_devs_phb_init(); | ||
417 | |||
418 | /* | ||
419 | * pci_probe_only and pci_assign_all_buses can be set via properties | ||
420 | * in chosen. | ||
421 | */ | ||
422 | if (of_chosen) { | ||
423 | int *prop; | ||
424 | |||
425 | prop = (int *)get_property(of_chosen, "linux,pci-probe-only", | ||
426 | NULL); | ||
427 | if (prop) | ||
428 | pci_probe_only = *prop; | ||
429 | |||
430 | prop = (int *)get_property(of_chosen, | ||
431 | "linux,pci-assign-all-buses", NULL); | ||
432 | if (prop) | ||
433 | pci_assign_all_buses = *prop; | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | ||
440 | { | ||
441 | struct device_node *root = of_find_node_by_path("/"); | ||
442 | unsigned int root_size_cells = 0; | ||
443 | struct pci_controller *phb; | ||
444 | int primary; | ||
445 | |||
446 | root_size_cells = prom_n_size_cells(root); | ||
447 | |||
448 | primary = list_empty(&hose_list); | ||
449 | phb = alloc_phb_dynamic(dn, root_size_cells); | ||
450 | if (!phb) | ||
451 | return NULL; | ||
452 | |||
453 | pci_process_bridge_OF_ranges(phb, dn, primary); | ||
454 | |||
455 | pci_setup_phb_io_dynamic(phb, primary); | ||
456 | of_node_put(root); | ||
457 | |||
458 | pci_devs_phb_init_dynamic(phb); | ||
459 | scan_phb(phb); | ||
460 | |||
461 | return phb; | ||
462 | } | ||
463 | EXPORT_SYMBOL(init_phb_dynamic); | ||
464 | |||
465 | /* RPA-specific bits for removing PHBs */ | ||
466 | int pcibios_remove_root_bus(struct pci_controller *phb) | ||
467 | { | ||
468 | struct pci_bus *b = phb->bus; | ||
469 | struct resource *res; | ||
470 | int rc, i; | ||
471 | |||
472 | res = b->resource[0]; | ||
473 | if (!res->flags) { | ||
474 | printk(KERN_ERR "%s: no IO resource for PHB %s\n", __FUNCTION__, | ||
475 | b->name); | ||
476 | return 1; | ||
477 | } | ||
478 | |||
479 | rc = unmap_bus_range(b); | ||
480 | if (rc) { | ||
481 | printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", | ||
482 | __FUNCTION__, b->name); | ||
483 | return 1; | ||
484 | } | ||
485 | |||
486 | if (release_resource(res)) { | ||
487 | printk(KERN_ERR "%s: failed to release IO on bus %s\n", | ||
488 | __FUNCTION__, b->name); | ||
489 | return 1; | ||
490 | } | ||
491 | |||
492 | for (i = 1; i < 3; ++i) { | ||
493 | res = b->resource[i]; | ||
494 | if (!res->flags && i == 0) { | ||
495 | printk(KERN_ERR "%s: no MEM resource for PHB %s\n", | ||
496 | __FUNCTION__, b->name); | ||
497 | return 1; | ||
498 | } | ||
499 | if (res->flags && release_resource(res)) { | ||
500 | printk(KERN_ERR | ||
501 | "%s: failed to release IO %d on bus %s\n", | ||
502 | __FUNCTION__, i, b->name); | ||
503 | return 1; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | list_del(&phb->list_node); | ||
508 | if (phb->is_dynamic) | ||
509 | kfree(phb); | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | EXPORT_SYMBOL(pcibios_remove_root_bus); | ||