diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-07-17 01:10:44 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-07-21 17:17:52 -0400 |
commit | 46ba6d7d8b0486e9d565729880ddfb2b84d3af31 (patch) | |
tree | 53f6eb1eb20d9adb45af5a78b440ae7ae3257990 /arch/sparc64/kernel/of_device.c | |
parent | 00ab956f2fefd3673edc16df55beed21834b7bdd (diff) |
[SPARC64]: Fix more of_device layer IRQ bugs, and correct PROMREG_MAX.
Sabre and Psycho PCI controllers can have partial interrupt-map
properties, meaning that on-board devices don't match up to any
entries. Instead, they are fully specified from the beginning and
we should pass them directly to the IRQ translator as-is.
Also, fill in the necessary translator slots for the "graphics"
and "expansion UPA" interrupts on Sabre, Psycho, and SYSIO SBUS.
Increase PROMREG_MAX to 24, as seen on SUNW,ffb devices.
Finally, prevent accidentally writing past the end of the of_device
struct resource[] and irqs[] arrays. Spit out a log message when
we ignore some entries because there are too many of them.
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.c | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 7064cee290ae..238bbf6de07d 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c | |||
@@ -542,9 +542,17 @@ static void __init build_device_resources(struct of_device *op, | |||
542 | /* Convert to num-cells. */ | 542 | /* Convert to num-cells. */ |
543 | num_reg /= 4; | 543 | num_reg /= 4; |
544 | 544 | ||
545 | /* Conver to num-entries. */ | 545 | /* Convert to num-entries. */ |
546 | num_reg /= na + ns; | 546 | num_reg /= na + ns; |
547 | 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 | |||
548 | for (index = 0; index < num_reg; index++) { | 556 | for (index = 0; index < num_reg; index++) { |
549 | struct resource *r = &op->resource[index]; | 557 | struct resource *r = &op->resource[index]; |
550 | u32 addr[OF_MAX_ADDR_CELLS]; | 558 | u32 addr[OF_MAX_ADDR_CELLS]; |
@@ -650,8 +658,22 @@ apply_interrupt_map(struct device_node *dp, struct device_node *pp, | |||
650 | next: | 658 | next: |
651 | imap += (na + 3); | 659 | imap += (na + 3); |
652 | } | 660 | } |
653 | 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 | |||
654 | return NULL; | 675 | return NULL; |
676 | } | ||
655 | 677 | ||
656 | *irq_p = irq; | 678 | *irq_p = irq; |
657 | cp = of_find_node_by_phandle(handle); | 679 | cp = of_find_node_by_phandle(handle); |
@@ -803,6 +825,14 @@ static struct of_device * __init scan_one_device(struct device_node *dp, | |||
803 | op->num_irqs = 0; | 825 | op->num_irqs = 0; |
804 | } | 826 | } |
805 | 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 | |||
806 | build_device_resources(op, parent); | 836 | build_device_resources(op, parent); |
807 | for (i = 0; i < op->num_irqs; i++) | 837 | for (i = 0; i < op->num_irqs; i++) |
808 | 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]); |