aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/of_device.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-07-13 02:19:31 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-07-13 04:50:15 -0400
commita83f982313bc60dd3d87e50f8c88d6a169e8a5a0 (patch)
treeccbf0bd78ad540d870c295712fd60e49f9206d8a /arch/sparc64/kernel/of_device.c
parent9bbd952e7f965757b5c913b6f98ad37a191137bd (diff)
[SPARC]: Fix OF register translations under sub-PCI busses.
There is an implicit assumption in the code that ranges will translate to something that can fit in 2 32-bit cells, or a 64-bit value. For certain kinds of things below PCI this isn't necessarily true. Here is what the relevant OF device hierarchy looks like for one of the serial controllers on an Ultra5: Node 0xf005f1e0 ranges: 00000000.00000000.00000000.000001fe.01000000.00000000.01000000 01000000.00000000.00000000.000001fe.02000000.00000000.01000000 02000000.00000000.00000000.000001ff.00000000.00000001.00000000 03000000.00000000.00000000.000001ff.00000000.00000001.00000000 device_type: 'pci' model: 'SUNW,sabre' Node 0xf005f9d4 device_type: 'pci' model: 'SUNW,simba' Node 0xf0060d24 ranges: 00000010.00000000 82010810.00000000.f0000000 01000000 00000014.00000000 82010814.00000000.f1000000 00800000 name: 'ebus' Node 0xf0062dac reg: 00000014.003083f8.00000008 --> 0x1ff.f13083f8 device_type: 'serial' name: 'su' So the correct translation here is: 1) Match "su" register to second ranges entry of 'ebus', which translates into a PCI triplet "82010814.00000000.f1000000" of size 00800000, which gives us "82010814.00000000.f13083f8". 2) Pass-through "SUNW,simba" since it lacks ranges property 3) Match "82010814.00000000.f13083f8" to third ranges property of PCI controller node 'SUNW,sabre', and we arrive at the final physical MMIO address of "0x1fff13083f8". Due to the 2-cell assumption, we couldn't translate to a PCI 3-cell value, and we couldn't perform a pass-thru on it either. It was easiest to just stop splitting the ranges application operation between two methods, ->map and ->translate, and just let ->map do all the work. That way it would work purely on 32-bit cell arrays instead of having to "return" some value like a u64. It's still not %100 correct because the out-of-range check is still done using the 64 least significant bits of the range and address. But it does work for all the cases I've thrown at it so far. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/of_device.c')
-rw-r--r--arch/sparc64/kernel/of_device.c308
1 files changed, 162 insertions, 146 deletions
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 8e177a0abc1c..7064cee290ae 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -210,7 +210,7 @@ struct bus_type of_bus_type = {
210}; 210};
211EXPORT_SYMBOL(of_bus_type); 211EXPORT_SYMBOL(of_bus_type);
212 212
213static inline u64 of_read_addr(u32 *cell, int size) 213static inline u64 of_read_addr(const u32 *cell, int size)
214{ 214{
215 u64 r = 0; 215 u64 r = 0;
216 while (size--) 216 while (size--)
@@ -236,8 +236,8 @@ struct of_bus {
236 int (*match)(struct device_node *parent); 236 int (*match)(struct device_node *parent);
237 void (*count_cells)(struct device_node *child, 237 void (*count_cells)(struct device_node *child,
238 int *addrc, int *sizec); 238 int *addrc, int *sizec);
239 u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); 239 int (*map)(u32 *addr, const u32 *range,
240 int (*translate)(u32 *addr, u64 offset, int na); 240 int na, int ns, int pna);
241 unsigned int (*get_flags)(u32 *addr); 241 unsigned int (*get_flags)(u32 *addr);
242}; 242};
243 243
@@ -251,27 +251,49 @@ static void of_bus_default_count_cells(struct device_node *dev,
251 get_cells(dev, addrc, sizec); 251 get_cells(dev, addrc, sizec);
252} 252}
253 253
254static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) 254/* Make sure the least significant 64-bits are in-range. Even
255 * for 3 or 4 cell values it is a good enough approximation.
256 */
257static int of_out_of_range(const u32 *addr, const u32 *base,
258 const u32 *size, int na, int ns)
255{ 259{
256 u64 cp, s, da; 260 u64 a = of_read_addr(addr, na);
261 u64 b = of_read_addr(base, na);
257 262
258 cp = of_read_addr(range, na); 263 if (a < b)
259 s = of_read_addr(range + na + pna, ns); 264 return 1;
260 da = of_read_addr(addr, na);
261 265
262 if (da < cp || da >= (cp + s)) 266 b += of_read_addr(size, ns);
263 return OF_BAD_ADDR; 267 if (a >= b)
264 return da - cp; 268 return 1;
269
270 return 0;
265} 271}
266 272
267static int of_bus_default_translate(u32 *addr, u64 offset, int na) 273static int of_bus_default_map(u32 *addr, const u32 *range,
274 int na, int ns, int pna)
268{ 275{
269 u64 a = of_read_addr(addr, na); 276 u32 result[OF_MAX_ADDR_CELLS];
270 memset(addr, 0, na * 4); 277 int i;
271 a += offset; 278
272 if (na > 1) 279 if (ns > 2) {
273 addr[na - 2] = a >> 32; 280 printk("of_device: Cannot handle size cells (%d) > 2.", ns);
274 addr[na - 1] = a & 0xffffffffu; 281 return -EINVAL;
282 }
283
284 if (of_out_of_range(addr, range, range + na + pna, na, ns))
285 return -EINVAL;
286
287 /* Start with the parent range base. */
288 memcpy(result, range + na, pna * 4);
289
290 /* Add in the child address offset. */
291 for (i = 0; i < na; i++)
292 result[pna - 1 - i] +=
293 (addr[na - 1 - i] -
294 range[na - 1 - i]);
295
296 memcpy(addr, result, pna * 4);
275 297
276 return 0; 298 return 0;
277} 299}
@@ -287,7 +309,20 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
287 309
288static int of_bus_pci_match(struct device_node *np) 310static int of_bus_pci_match(struct device_node *np)
289{ 311{
290 return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); 312 if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
313 /* Do not do PCI specific frobbing if the
314 * PCI bridge lacks a ranges property. We
315 * want to pass it through up to the next
316 * parent as-is, not with the PCI translate
317 * method which chops off the top address cell.
318 */
319 if (!of_find_property(np, "ranges", NULL))
320 return 0;
321
322 return 1;
323 }
324
325 return 0;
291} 326}
292 327
293static void of_bus_pci_count_cells(struct device_node *np, 328static void of_bus_pci_count_cells(struct device_node *np,
@@ -299,27 +334,32 @@ static void of_bus_pci_count_cells(struct device_node *np,
299 *sizec = 2; 334 *sizec = 2;
300} 335}
301 336
302static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) 337static int of_bus_pci_map(u32 *addr, const u32 *range,
338 int na, int ns, int pna)
303{ 339{
304 u64 cp, s, da; 340 u32 result[OF_MAX_ADDR_CELLS];
341 int i;
305 342
306 /* Check address type match */ 343 /* Check address type match */
307 if ((addr[0] ^ range[0]) & 0x03000000) 344 if ((addr[0] ^ range[0]) & 0x03000000)
308 return OF_BAD_ADDR; 345 return -EINVAL;
309 346
310 /* Read address values, skipping high cell */ 347 if (of_out_of_range(addr + 1, range + 1, range + na + pna,
311 cp = of_read_addr(range + 1, na - 1); 348 na - 1, ns))
312 s = of_read_addr(range + na + pna, ns); 349 return -EINVAL;
313 da = of_read_addr(addr + 1, na - 1);
314 350
315 if (da < cp || da >= (cp + s)) 351 /* Start with the parent range base. */
316 return OF_BAD_ADDR; 352 memcpy(result, range + na, pna * 4);
317 return da - cp;
318}
319 353
320static int of_bus_pci_translate(u32 *addr, u64 offset, int na) 354 /* Add in the child address offset, skipping high cell. */
321{ 355 for (i = 0; i < na - 1; i++)
322 return of_bus_default_translate(addr + 1, offset, na - 1); 356 result[pna - 1 - i] +=
357 (addr[na - 1 - i] -
358 range[na - 1 - i]);
359
360 memcpy(addr, result, pna * 4);
361
362 return 0;
323} 363}
324 364
325static unsigned int of_bus_pci_get_flags(u32 *addr) 365static unsigned int of_bus_pci_get_flags(u32 *addr)
@@ -340,59 +380,6 @@ static unsigned int of_bus_pci_get_flags(u32 *addr)
340} 380}
341 381
342/* 382/*
343 * ISA bus specific translator
344 */
345
346static int of_bus_isa_match(struct device_node *np)
347{
348 return !strcmp(np->name, "isa");
349}
350
351static void of_bus_isa_count_cells(struct device_node *child,
352 int *addrc, int *sizec)
353{
354 if (addrc)
355 *addrc = 2;
356 if (sizec)
357 *sizec = 1;
358}
359
360static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
361{
362 u64 cp, s, da;
363
364 /* Check address type match */
365 if ((addr[0] ^ range[0]) & 0x00000001)
366 return OF_BAD_ADDR;
367
368 /* Read address values, skipping high cell */
369 cp = of_read_addr(range + 1, na - 1);
370 s = of_read_addr(range + na + pna, ns);
371 da = of_read_addr(addr + 1, na - 1);
372
373 if (da < cp || da >= (cp + s))
374 return OF_BAD_ADDR;
375 return da - cp;
376}
377
378static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
379{
380 return of_bus_default_translate(addr + 1, offset, na - 1);
381}
382
383static unsigned int of_bus_isa_get_flags(u32 *addr)
384{
385 unsigned int flags = 0;
386 u32 w = addr[0];
387
388 if (w & 1)
389 flags |= IORESOURCE_IO;
390 else
391 flags |= IORESOURCE_MEM;
392 return flags;
393}
394
395/*
396 * SBUS bus specific translator 383 * SBUS bus specific translator
397 */ 384 */
398 385
@@ -411,16 +398,11 @@ static void of_bus_sbus_count_cells(struct device_node *child,
411 *sizec = 1; 398 *sizec = 1;
412} 399}
413 400
414static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) 401static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
415{ 402{
416 return of_bus_default_map(addr, range, na, ns, pna); 403 return of_bus_default_map(addr, range, na, ns, pna);
417} 404}
418 405
419static int of_bus_sbus_translate(u32 *addr, u64 offset, int na)
420{
421 return of_bus_default_translate(addr, offset, na);
422}
423
424static unsigned int of_bus_sbus_get_flags(u32 *addr) 406static unsigned int of_bus_sbus_get_flags(u32 *addr)
425{ 407{
426 return IORESOURCE_MEM; 408 return IORESOURCE_MEM;
@@ -439,19 +421,8 @@ static struct of_bus of_busses[] = {
439 .match = of_bus_pci_match, 421 .match = of_bus_pci_match,
440 .count_cells = of_bus_pci_count_cells, 422 .count_cells = of_bus_pci_count_cells,
441 .map = of_bus_pci_map, 423 .map = of_bus_pci_map,
442 .translate = of_bus_pci_translate,
443 .get_flags = of_bus_pci_get_flags, 424 .get_flags = of_bus_pci_get_flags,
444 }, 425 },
445 /* ISA */
446 {
447 .name = "isa",
448 .addr_prop_name = "reg",
449 .match = of_bus_isa_match,
450 .count_cells = of_bus_isa_count_cells,
451 .map = of_bus_isa_map,
452 .translate = of_bus_isa_translate,
453 .get_flags = of_bus_isa_get_flags,
454 },
455 /* SBUS */ 426 /* SBUS */
456 { 427 {
457 .name = "sbus", 428 .name = "sbus",
@@ -459,7 +430,6 @@ static struct of_bus of_busses[] = {
459 .match = of_bus_sbus_match, 430 .match = of_bus_sbus_match,
460 .count_cells = of_bus_sbus_count_cells, 431 .count_cells = of_bus_sbus_count_cells,
461 .map = of_bus_sbus_map, 432 .map = of_bus_sbus_map,
462 .translate = of_bus_sbus_translate,
463 .get_flags = of_bus_sbus_get_flags, 433 .get_flags = of_bus_sbus_get_flags,
464 }, 434 },
465 /* Default */ 435 /* Default */
@@ -469,7 +439,6 @@ static struct of_bus of_busses[] = {
469 .match = NULL, 439 .match = NULL,
470 .count_cells = of_bus_default_count_cells, 440 .count_cells = of_bus_default_count_cells,
471 .map = of_bus_default_map, 441 .map = of_bus_default_map,
472 .translate = of_bus_default_translate,
473 .get_flags = of_bus_default_get_flags, 442 .get_flags = of_bus_default_get_flags,
474 }, 443 },
475}; 444};
@@ -494,33 +463,62 @@ static int __init build_one_resource(struct device_node *parent,
494 u32 *ranges; 463 u32 *ranges;
495 unsigned int rlen; 464 unsigned int rlen;
496 int rone; 465 int rone;
497 u64 offset = OF_BAD_ADDR;
498 466
499 ranges = of_get_property(parent, "ranges", &rlen); 467 ranges = of_get_property(parent, "ranges", &rlen);
500 if (ranges == NULL || rlen == 0) { 468 if (ranges == NULL || rlen == 0) {
501 offset = of_read_addr(addr, na); 469 u32 result[OF_MAX_ADDR_CELLS];
502 memset(addr, 0, pna * 4); 470 int i;
503 goto finish; 471
472 memset(result, 0, pna * 4);
473 for (i = 0; i < na; i++)
474 result[pna - 1 - i] =
475 addr[na - 1 - i];
476
477 memcpy(addr, result, pna * 4);
478 return 0;
504 } 479 }
505 480
506 /* Now walk through the ranges */ 481 /* Now walk through the ranges */
507 rlen /= 4; 482 rlen /= 4;
508 rone = na + pna + ns; 483 rone = na + pna + ns;
509 for (; rlen >= rone; rlen -= rone, ranges += rone) { 484 for (; rlen >= rone; rlen -= rone, ranges += rone) {
510 offset = bus->map(addr, ranges, na, ns, pna); 485 if (!bus->map(addr, ranges, na, ns, pna))
511 if (offset != OF_BAD_ADDR) 486 return 0;
512 break;
513 } 487 }
514 if (offset == OF_BAD_ADDR) 488
489 return 1;
490}
491
492static int __init use_1to1_mapping(struct device_node *pp)
493{
494 char *model;
495
496 /* If this is on the PMU bus, don't try to translate it even
497 * if a ranges property exists.
498 */
499 if (!strcmp(pp->name, "pmu"))
515 return 1; 500 return 1;
516 501
517 memcpy(addr, ranges + na, 4 * pna); 502 /* If we have a ranges property in the parent, use it. */
503 if (of_find_property(pp, "ranges", NULL) != NULL)
504 return 0;
518 505
519finish: 506 /* If the parent is the dma node of an ISA bus, pass
520 /* Translate it into parent bus space */ 507 * the translation up to the root.
521 return pbus->translate(addr, offset, pna); 508 */
509 if (!strcmp(pp->name, "dma"))
510 return 0;
511
512 /* Similarly for Simba PCI bridges. */
513 model = of_get_property(pp, "model", NULL);
514 if (model && !strcmp(model, "SUNW,simba"))
515 return 0;
516
517 return 1;
522} 518}
523 519
520static int of_resource_verbose;
521
524static void __init build_device_resources(struct of_device *op, 522static void __init build_device_resources(struct of_device *op,
525 struct device *parent) 523 struct device *parent)
526{ 524{
@@ -564,15 +562,7 @@ static void __init build_device_resources(struct of_device *op,
564 562
565 memcpy(addr, reg, na * 4); 563 memcpy(addr, reg, na * 4);
566 564
567 /* If the immediate parent has no ranges property to apply, 565 if (use_1to1_mapping(pp)) {
568 * just use a 1<->1 mapping. Unless it is the 'dma' child
569 * of an isa bus, which must be passed up towards the root.
570 *
571 * Also, don't try to translate PMU bus device registers.
572 */
573 if ((of_find_property(pp, "ranges", NULL) == NULL &&
574 strcmp(pp->name, "dma") != 0) ||
575 !strcmp(pp->name, "pmu")) {
576 result = of_read_addr(addr, na); 566 result = of_read_addr(addr, na);
577 goto build_res; 567 goto build_res;
578 } 568 }
@@ -591,7 +581,8 @@ static void __init build_device_resources(struct of_device *op,
591 pbus = of_match_bus(pp); 581 pbus = of_match_bus(pp);
592 pbus->count_cells(dp, &pna, &pns); 582 pbus->count_cells(dp, &pna, &pns);
593 583
594 if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) 584 if (build_one_resource(dp, bus, pbus, addr,
585 dna, dns, pna))
595 break; 586 break;
596 587
597 dna = pna; 588 dna = pna;
@@ -601,6 +592,12 @@ static void __init build_device_resources(struct of_device *op,
601 592
602 build_res: 593 build_res:
603 memset(r, 0, sizeof(*r)); 594 memset(r, 0, sizeof(*r));
595
596 if (of_resource_verbose)
597 printk("%s reg[%d] -> %lx\n",
598 op->node->full_name, index,
599 result);
600
604 if (result != OF_BAD_ADDR) { 601 if (result != OF_BAD_ADDR) {
605 if (tlb_type == hypervisor) 602 if (tlb_type == hypervisor)
606 result &= 0x0fffffffffffffffUL; 603 result &= 0x0fffffffffffffffUL;
@@ -684,6 +681,8 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,
684 return ret; 681 return ret;
685} 682}
686 683
684static int of_irq_verbose;
685
687static unsigned int __init build_one_device_irq(struct of_device *op, 686static unsigned int __init build_one_device_irq(struct of_device *op,
688 struct device *parent, 687 struct device *parent,
689 unsigned int irq) 688 unsigned int irq)
@@ -698,10 +697,11 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
698 if (dp->irq_trans) { 697 if (dp->irq_trans) {
699 irq = dp->irq_trans->irq_build(dp, irq, 698 irq = dp->irq_trans->irq_build(dp, irq,
700 dp->irq_trans->data); 699 dp->irq_trans->data);
701#if 1 700
702 printk("%s: direct translate %x --> %x\n", 701 if (of_irq_verbose)
703 dp->full_name, orig_irq, irq); 702 printk("%s: direct translate %x --> %x\n",
704#endif 703 dp->full_name, orig_irq, irq);
704
705 return irq; 705 return irq;
706 } 706 }
707 707
@@ -728,12 +728,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
728 iret = apply_interrupt_map(dp, pp, 728 iret = apply_interrupt_map(dp, pp,
729 imap, imlen, imsk, 729 imap, imlen, imsk,
730 &irq); 730 &irq);
731#if 1 731
732 printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", 732 if (of_irq_verbose)
733 op->node->full_name, 733 printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
734 pp->full_name, this_orig_irq, 734 op->node->full_name,
735 (iret ? iret->full_name : "NULL"), irq); 735 pp->full_name, this_orig_irq,
736#endif 736 (iret ? iret->full_name : "NULL"), irq);
737
737 if (!iret) 738 if (!iret)
738 break; 739 break;
739 740
@@ -747,11 +748,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
747 unsigned int this_orig_irq = irq; 748 unsigned int this_orig_irq = irq;
748 749
749 irq = pci_irq_swizzle(dp, pp, irq); 750 irq = pci_irq_swizzle(dp, pp, irq);
750#if 1 751 if (of_irq_verbose)
751 printk("%s: PCI swizzle [%s] %x --> %x\n", 752 printk("%s: PCI swizzle [%s] "
752 op->node->full_name, 753 "%x --> %x\n",
753 pp->full_name, this_orig_irq, irq); 754 op->node->full_name,
754#endif 755 pp->full_name, this_orig_irq,
756 irq);
757
755 } 758 }
756 759
757 if (pp->irq_trans) { 760 if (pp->irq_trans) {
@@ -767,10 +770,9 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
767 770
768 irq = ip->irq_trans->irq_build(op->node, irq, 771 irq = ip->irq_trans->irq_build(op->node, irq,
769 ip->irq_trans->data); 772 ip->irq_trans->data);
770#if 1 773 if (of_irq_verbose)
771 printk("%s: Apply IRQ trans [%s] %x --> %x\n", 774 printk("%s: Apply IRQ trans [%s] %x --> %x\n",
772 op->node->full_name, ip->full_name, orig_irq, irq); 775 op->node->full_name, ip->full_name, orig_irq, irq);
773#endif
774 776
775 return irq; 777 return irq;
776} 778}
@@ -870,6 +872,20 @@ static int __init of_bus_driver_init(void)
870 872
871postcore_initcall(of_bus_driver_init); 873postcore_initcall(of_bus_driver_init);
872 874
875static int __init of_debug(char *str)
876{
877 int val = 0;
878
879 get_option(&str, &val);
880 if (val & 1)
881 of_resource_verbose = 1;
882 if (val & 2)
883 of_irq_verbose = 1;
884 return 1;
885}
886
887__setup("of_debug=", of_debug);
888
873int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) 889int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
874{ 890{
875 /* initialize common driver fields */ 891 /* initialize common driver fields */