diff options
Diffstat (limited to 'arch/sparc64/kernel/of_device.c')
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 348 |
1 files changed, 198 insertions, 150 deletions
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 169b017eec0b..238bbf6de07d 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 | }; |
211 | EXPORT_SYMBOL(of_bus_type); | 211 | EXPORT_SYMBOL(of_bus_type); |
212 | 212 | ||
213 | static inline u64 of_read_addr(u32 *cell, int size) | 213 | static 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 | ||
254 | static 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 | */ | ||
257 | static 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); | ||
262 | |||
263 | if (a < b) | ||
264 | return 1; | ||
257 | 265 | ||
258 | cp = of_read_addr(range, na); | 266 | b += of_read_addr(size, ns); |
259 | s = of_read_addr(range + na + pna, ns); | 267 | if (a >= b) |
260 | da = of_read_addr(addr, na); | 268 | return 1; |
261 | 269 | ||
262 | if (da < cp || da >= (cp + s)) | 270 | return 0; |
263 | return OF_BAD_ADDR; | ||
264 | return da - cp; | ||
265 | } | 271 | } |
266 | 272 | ||
267 | static int of_bus_default_translate(u32 *addr, u64 offset, int na) | 273 | static 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 | ||
288 | static int of_bus_pci_match(struct device_node *np) | 310 | static 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 | ||
293 | static void of_bus_pci_count_cells(struct device_node *np, | 328 | static 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 | ||
302 | static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) | 337 | static 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 | ||
320 | static 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 | ||
325 | static unsigned int of_bus_pci_get_flags(u32 *addr) | 365 | static 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 | |||
346 | static int of_bus_isa_match(struct device_node *np) | ||
347 | { | ||
348 | return !strcmp(np->name, "isa"); | ||
349 | } | ||
350 | |||
351 | static 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 | |||
360 | static 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 | |||
378 | static 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 | |||
383 | static 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 | ||
414 | static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) | 401 | static 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 | ||
419 | static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) | ||
420 | { | ||
421 | return of_bus_default_translate(addr, offset, na); | ||
422 | } | ||
423 | |||
424 | static unsigned int of_bus_sbus_get_flags(u32 *addr) | 406 | static 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 | |||
492 | static 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; | ||
505 | |||
506 | /* If the parent is the dma node of an ISA bus, pass | ||
507 | * the translation up to the root. | ||
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; | ||
518 | 516 | ||
519 | finish: | 517 | return 1; |
520 | /* Translate it into parent bus space */ | ||
521 | return pbus->translate(addr, offset, pna); | ||
522 | } | 518 | } |
523 | 519 | ||
520 | static int of_resource_verbose; | ||
521 | |||
524 | static void __init build_device_resources(struct of_device *op, | 522 | static void __init build_device_resources(struct of_device *op, |
525 | struct device *parent) | 523 | struct device *parent) |
526 | { | 524 | { |
@@ -544,9 +542,17 @@ static void __init build_device_resources(struct of_device *op, | |||
544 | /* Convert to num-cells. */ | 542 | /* Convert to num-cells. */ |
545 | num_reg /= 4; | 543 | num_reg /= 4; |
546 | 544 | ||
547 | /* Conver to num-entries. */ | 545 | /* Convert to num-entries. */ |
548 | num_reg /= na + ns; | 546 | num_reg /= na + ns; |
549 | 547 | ||
548 | /* Prevent overruning the op->resources[] array. */ | ||
549 | if (num_reg > PROMREG_MAX) { | ||
550 | printk(KERN_WARNING "%s: Too many regs (%d), " | ||
551 | "limiting to %d.\n", | ||
552 | op->node->full_name, num_reg, PROMREG_MAX); | ||
553 | num_reg = PROMREG_MAX; | ||
554 | } | ||
555 | |||
550 | for (index = 0; index < num_reg; index++) { | 556 | for (index = 0; index < num_reg; index++) { |
551 | struct resource *r = &op->resource[index]; | 557 | struct resource *r = &op->resource[index]; |
552 | u32 addr[OF_MAX_ADDR_CELLS]; | 558 | u32 addr[OF_MAX_ADDR_CELLS]; |
@@ -564,15 +570,7 @@ static void __init build_device_resources(struct of_device *op, | |||
564 | 570 | ||
565 | memcpy(addr, reg, na * 4); | 571 | memcpy(addr, reg, na * 4); |
566 | 572 | ||
567 | /* If the immediate parent has no ranges property to apply, | 573 | 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); | 574 | result = of_read_addr(addr, na); |
577 | goto build_res; | 575 | goto build_res; |
578 | } | 576 | } |
@@ -591,7 +589,8 @@ static void __init build_device_resources(struct of_device *op, | |||
591 | pbus = of_match_bus(pp); | 589 | pbus = of_match_bus(pp); |
592 | pbus->count_cells(dp, &pna, &pns); | 590 | pbus->count_cells(dp, &pna, &pns); |
593 | 591 | ||
594 | if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) | 592 | if (build_one_resource(dp, bus, pbus, addr, |
593 | dna, dns, pna)) | ||
595 | break; | 594 | break; |
596 | 595 | ||
597 | dna = pna; | 596 | dna = pna; |
@@ -601,6 +600,12 @@ static void __init build_device_resources(struct of_device *op, | |||
601 | 600 | ||
602 | build_res: | 601 | build_res: |
603 | memset(r, 0, sizeof(*r)); | 602 | memset(r, 0, sizeof(*r)); |
603 | |||
604 | if (of_resource_verbose) | ||
605 | printk("%s reg[%d] -> %lx\n", | ||
606 | op->node->full_name, index, | ||
607 | result); | ||
608 | |||
604 | if (result != OF_BAD_ADDR) { | 609 | if (result != OF_BAD_ADDR) { |
605 | if (tlb_type == hypervisor) | 610 | if (tlb_type == hypervisor) |
606 | result &= 0x0fffffffffffffffUL; | 611 | result &= 0x0fffffffffffffffUL; |
@@ -653,8 +658,22 @@ apply_interrupt_map(struct device_node *dp, struct device_node *pp, | |||
653 | next: | 658 | next: |
654 | imap += (na + 3); | 659 | imap += (na + 3); |
655 | } | 660 | } |
656 | if (i == imlen) | 661 | if (i == imlen) { |
662 | /* Psycho and Sabre PCI controllers can have 'interrupt-map' | ||
663 | * properties that do not include the on-board device | ||
664 | * interrupts. Instead, the device's 'interrupts' property | ||
665 | * is already a fully specified INO value. | ||
666 | * | ||
667 | * Handle this by deciding that, if we didn't get a | ||
668 | * match in the parent's 'interrupt-map', and the | ||
669 | * parent is an IRQ translater, then use the parent as | ||
670 | * our IRQ controller. | ||
671 | */ | ||
672 | if (pp->irq_trans) | ||
673 | return pp; | ||
674 | |||
657 | return NULL; | 675 | return NULL; |
676 | } | ||
658 | 677 | ||
659 | *irq_p = irq; | 678 | *irq_p = irq; |
660 | cp = of_find_node_by_phandle(handle); | 679 | cp = of_find_node_by_phandle(handle); |
@@ -684,6 +703,8 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, | |||
684 | return ret; | 703 | return ret; |
685 | } | 704 | } |
686 | 705 | ||
706 | static int of_irq_verbose; | ||
707 | |||
687 | static unsigned int __init build_one_device_irq(struct of_device *op, | 708 | static unsigned int __init build_one_device_irq(struct of_device *op, |
688 | struct device *parent, | 709 | struct device *parent, |
689 | unsigned int irq) | 710 | unsigned int irq) |
@@ -698,10 +719,11 @@ static unsigned int __init build_one_device_irq(struct of_device *op, | |||
698 | if (dp->irq_trans) { | 719 | if (dp->irq_trans) { |
699 | irq = dp->irq_trans->irq_build(dp, irq, | 720 | irq = dp->irq_trans->irq_build(dp, irq, |
700 | dp->irq_trans->data); | 721 | dp->irq_trans->data); |
701 | #if 1 | 722 | |
702 | printk("%s: direct translate %x --> %x\n", | 723 | if (of_irq_verbose) |
703 | dp->full_name, orig_irq, irq); | 724 | printk("%s: direct translate %x --> %x\n", |
704 | #endif | 725 | dp->full_name, orig_irq, irq); |
726 | |||
705 | return irq; | 727 | return irq; |
706 | } | 728 | } |
707 | 729 | ||
@@ -728,12 +750,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op, | |||
728 | iret = apply_interrupt_map(dp, pp, | 750 | iret = apply_interrupt_map(dp, pp, |
729 | imap, imlen, imsk, | 751 | imap, imlen, imsk, |
730 | &irq); | 752 | &irq); |
731 | #if 1 | 753 | |
732 | printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", | 754 | if (of_irq_verbose) |
733 | op->node->full_name, | 755 | printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", |
734 | pp->full_name, this_orig_irq, | 756 | op->node->full_name, |
735 | (iret ? iret->full_name : "NULL"), irq); | 757 | pp->full_name, this_orig_irq, |
736 | #endif | 758 | (iret ? iret->full_name : "NULL"), irq); |
759 | |||
737 | if (!iret) | 760 | if (!iret) |
738 | break; | 761 | break; |
739 | 762 | ||
@@ -747,11 +770,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op, | |||
747 | unsigned int this_orig_irq = irq; | 770 | unsigned int this_orig_irq = irq; |
748 | 771 | ||
749 | irq = pci_irq_swizzle(dp, pp, irq); | 772 | irq = pci_irq_swizzle(dp, pp, irq); |
750 | #if 1 | 773 | if (of_irq_verbose) |
751 | printk("%s: PCI swizzle [%s] %x --> %x\n", | 774 | printk("%s: PCI swizzle [%s] " |
752 | op->node->full_name, | 775 | "%x --> %x\n", |
753 | pp->full_name, this_orig_irq, irq); | 776 | op->node->full_name, |
754 | #endif | 777 | pp->full_name, this_orig_irq, |
778 | irq); | ||
779 | |||
755 | } | 780 | } |
756 | 781 | ||
757 | if (pp->irq_trans) { | 782 | if (pp->irq_trans) { |
@@ -767,10 +792,9 @@ static unsigned int __init build_one_device_irq(struct of_device *op, | |||
767 | 792 | ||
768 | irq = ip->irq_trans->irq_build(op->node, irq, | 793 | irq = ip->irq_trans->irq_build(op->node, irq, |
769 | ip->irq_trans->data); | 794 | ip->irq_trans->data); |
770 | #if 1 | 795 | if (of_irq_verbose) |
771 | printk("%s: Apply IRQ trans [%s] %x --> %x\n", | 796 | printk("%s: Apply IRQ trans [%s] %x --> %x\n", |
772 | op->node->full_name, ip->full_name, orig_irq, irq); | 797 | op->node->full_name, ip->full_name, orig_irq, irq); |
773 | #endif | ||
774 | 798 | ||
775 | return irq; | 799 | return irq; |
776 | } | 800 | } |
@@ -801,6 +825,14 @@ static struct of_device * __init scan_one_device(struct device_node *dp, | |||
801 | op->num_irqs = 0; | 825 | op->num_irqs = 0; |
802 | } | 826 | } |
803 | 827 | ||
828 | /* Prevent overruning the op->irqs[] array. */ | ||
829 | if (op->num_irqs > PROMINTR_MAX) { | ||
830 | printk(KERN_WARNING "%s: Too many irqs (%d), " | ||
831 | "limiting to %d.\n", | ||
832 | dp->full_name, op->num_irqs, PROMINTR_MAX); | ||
833 | op->num_irqs = PROMINTR_MAX; | ||
834 | } | ||
835 | |||
804 | build_device_resources(op, parent); | 836 | build_device_resources(op, parent); |
805 | for (i = 0; i < op->num_irqs; i++) | 837 | for (i = 0; i < op->num_irqs; i++) |
806 | op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]); | 838 | op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]); |
@@ -870,6 +902,20 @@ static int __init of_bus_driver_init(void) | |||
870 | 902 | ||
871 | postcore_initcall(of_bus_driver_init); | 903 | postcore_initcall(of_bus_driver_init); |
872 | 904 | ||
905 | static int __init of_debug(char *str) | ||
906 | { | ||
907 | int val = 0; | ||
908 | |||
909 | get_option(&str, &val); | ||
910 | if (val & 1) | ||
911 | of_resource_verbose = 1; | ||
912 | if (val & 2) | ||
913 | of_irq_verbose = 1; | ||
914 | return 1; | ||
915 | } | ||
916 | |||
917 | __setup("of_debug=", of_debug); | ||
918 | |||
873 | int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) | 919 | int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) |
874 | { | 920 | { |
875 | /* initialize common driver fields */ | 921 | /* initialize common driver fields */ |
@@ -922,9 +968,11 @@ int of_device_register(struct of_device *ofdev) | |||
922 | if (rc) | 968 | if (rc) |
923 | return rc; | 969 | return rc; |
924 | 970 | ||
925 | device_create_file(&ofdev->dev, &dev_attr_devspec); | 971 | rc = device_create_file(&ofdev->dev, &dev_attr_devspec); |
972 | if (rc) | ||
973 | device_unregister(&ofdev->dev); | ||
926 | 974 | ||
927 | return 0; | 975 | return rc; |
928 | } | 976 | } |
929 | 977 | ||
930 | void of_device_unregister(struct of_device *ofdev) | 978 | void of_device_unregister(struct of_device *ofdev) |