aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-07-17 01:10:44 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-07-21 17:17:52 -0400
commit46ba6d7d8b0486e9d565729880ddfb2b84d3af31 (patch)
tree53f6eb1eb20d9adb45af5a78b440ae7ae3257990 /arch/sparc64/kernel
parent00ab956f2fefd3673edc16df55beed21834b7bdd (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')
-rw-r--r--arch/sparc64/kernel/of_device.c34
-rw-r--r--arch/sparc64/kernel/prom.c12
2 files changed, 42 insertions, 4 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]);
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index c86007a2aa3f..5cc5ab63293f 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -344,10 +344,12 @@ static unsigned long __psycho_onboard_imap_off[] = {
344/*0x2f*/ PSYCHO_IMAP_CE, 344/*0x2f*/ PSYCHO_IMAP_CE,
345/*0x30*/ PSYCHO_IMAP_A_ERR, 345/*0x30*/ PSYCHO_IMAP_A_ERR,
346/*0x31*/ PSYCHO_IMAP_B_ERR, 346/*0x31*/ PSYCHO_IMAP_B_ERR,
347/*0x32*/ PSYCHO_IMAP_PMGMT 347/*0x32*/ PSYCHO_IMAP_PMGMT,
348/*0x33*/ PSYCHO_IMAP_GFX,
349/*0x34*/ PSYCHO_IMAP_EUPA,
348}; 350};
349#define PSYCHO_ONBOARD_IRQ_BASE 0x20 351#define PSYCHO_ONBOARD_IRQ_BASE 0x20
350#define PSYCHO_ONBOARD_IRQ_LAST 0x32 352#define PSYCHO_ONBOARD_IRQ_LAST 0x34
351#define psycho_onboard_imap_offset(__ino) \ 353#define psycho_onboard_imap_offset(__ino) \
352 __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] 354 __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]
353 355
@@ -529,6 +531,10 @@ static unsigned long __sabre_onboard_imap_off[] = {
529/*0x2e*/ SABRE_IMAP_UE, 531/*0x2e*/ SABRE_IMAP_UE,
530/*0x2f*/ SABRE_IMAP_CE, 532/*0x2f*/ SABRE_IMAP_CE,
531/*0x30*/ SABRE_IMAP_PCIERR, 533/*0x30*/ SABRE_IMAP_PCIERR,
534/*0x31*/ 0 /* reserved */,
535/*0x32*/ 0 /* reserved */,
536/*0x33*/ SABRE_IMAP_GFX,
537/*0x34*/ SABRE_IMAP_EUPA,
532}; 538};
533#define SABRE_ONBOARD_IRQ_BASE 0x20 539#define SABRE_ONBOARD_IRQ_BASE 0x20
534#define SABRE_ONBOARD_IRQ_LAST 0x30 540#define SABRE_ONBOARD_IRQ_LAST 0x30
@@ -895,6 +901,8 @@ static unsigned long sysio_irq_offsets[] = {
895 SYSIO_IMAP_CE, 901 SYSIO_IMAP_CE,
896 SYSIO_IMAP_SBERR, 902 SYSIO_IMAP_SBERR,
897 SYSIO_IMAP_PMGMT, 903 SYSIO_IMAP_PMGMT,
904 SYSIO_IMAP_GFX,
905 SYSIO_IMAP_EUPA,
898}; 906};
899 907
900#undef bogon 908#undef bogon