[SPARC64]: Fix more of_device layer IRQ bugs, and correct PROMREG_MAX.
authorDavid S. Miller <davem@sunset.davemloft.net>
Mon, 17 Jul 2006 05:10:44 +0000 (22:10 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Fri, 21 Jul 2006 21:17:52 +0000 (14:17 -0700)
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>
arch/sparc64/kernel/of_device.c
arch/sparc64/kernel/prom.c
include/asm-sparc64/openprom.h

index 7064cee290ae15d78b8888429660fc9caba9d399..238bbf6de07d1603b5ab7e225442ef1eabab2177 100644 (file)
@@ -542,9 +542,17 @@ static void __init build_device_resources(struct of_device *op,
        /* Convert to num-cells.  */
        num_reg /= 4;
 
-       /* Conver to num-entries.  */
+       /* Convert to num-entries.  */
        num_reg /= na + ns;
 
+       /* Prevent overruning the op->resources[] array.  */
+       if (num_reg > PROMREG_MAX) {
+               printk(KERN_WARNING "%s: Too many regs (%d), "
+                      "limiting to %d.\n",
+                      op->node->full_name, num_reg, PROMREG_MAX);
+               num_reg = PROMREG_MAX;
+       }
+
        for (index = 0; index < num_reg; index++) {
                struct resource *r = &op->resource[index];
                u32 addr[OF_MAX_ADDR_CELLS];
@@ -650,8 +658,22 @@ apply_interrupt_map(struct device_node *dp, struct device_node *pp,
        next:
                imap += (na + 3);
        }
-       if (i == imlen)
+       if (i == imlen) {
+               /* Psycho and Sabre PCI controllers can have 'interrupt-map'
+                * properties that do not include the on-board device
+                * interrupts.  Instead, the device's 'interrupts' property
+                * is already a fully specified INO value.
+                *
+                * Handle this by deciding that, if we didn't get a
+                * match in the parent's 'interrupt-map', and the
+                * parent is an IRQ translater, then use the parent as
+                * our IRQ controller.
+                */
+               if (pp->irq_trans)
+                       return pp;
+
                return NULL;
+       }
 
        *irq_p = irq;
        cp = of_find_node_by_phandle(handle);
@@ -803,6 +825,14 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
                op->num_irqs = 0;
        }
 
+       /* Prevent overruning the op->irqs[] array.  */
+       if (op->num_irqs > PROMINTR_MAX) {
+               printk(KERN_WARNING "%s: Too many irqs (%d), "
+                      "limiting to %d.\n",
+                      dp->full_name, op->num_irqs, PROMINTR_MAX);
+               op->num_irqs = PROMINTR_MAX;
+       }
+
        build_device_resources(op, parent);
        for (i = 0; i < op->num_irqs; i++)
                op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
index c86007a2aa3f251493606edb38a37edea7298b0d..5cc5ab63293fa912188053b8d7a9a360e60fd3e5 100644 (file)
@@ -344,10 +344,12 @@ static unsigned long __psycho_onboard_imap_off[] = {
 /*0x2f*/       PSYCHO_IMAP_CE,
 /*0x30*/       PSYCHO_IMAP_A_ERR,
 /*0x31*/       PSYCHO_IMAP_B_ERR,
-/*0x32*/       PSYCHO_IMAP_PMGMT
+/*0x32*/       PSYCHO_IMAP_PMGMT,
+/*0x33*/       PSYCHO_IMAP_GFX,
+/*0x34*/       PSYCHO_IMAP_EUPA,
 };
 #define PSYCHO_ONBOARD_IRQ_BASE                0x20
-#define PSYCHO_ONBOARD_IRQ_LAST                0x32
+#define PSYCHO_ONBOARD_IRQ_LAST                0x34
 #define psycho_onboard_imap_offset(__ino) \
        __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]
 
@@ -529,6 +531,10 @@ static unsigned long __sabre_onboard_imap_off[] = {
 /*0x2e*/       SABRE_IMAP_UE,
 /*0x2f*/       SABRE_IMAP_CE,
 /*0x30*/       SABRE_IMAP_PCIERR,
+/*0x31*/       0 /* reserved */,
+/*0x32*/       0 /* reserved */,
+/*0x33*/       SABRE_IMAP_GFX,
+/*0x34*/       SABRE_IMAP_EUPA,
 };
 #define SABRE_ONBOARD_IRQ_BASE         0x20
 #define SABRE_ONBOARD_IRQ_LAST         0x30
@@ -895,6 +901,8 @@ static unsigned long sysio_irq_offsets[] = {
        SYSIO_IMAP_CE,
        SYSIO_IMAP_SBERR,
        SYSIO_IMAP_PMGMT,
+       SYSIO_IMAP_GFX,
+       SYSIO_IMAP_EUPA,
 };
 
 #undef bogon
index b4959d2b0d991712cc4114644804d17a9152061f..e01b80559c93f164c8ec056aa624bffae6104038 100644 (file)
@@ -175,7 +175,7 @@ struct linux_nodeops {
 };
 
 /* More fun PROM structures for device probing. */
-#define PROMREG_MAX     16
+#define PROMREG_MAX     24
 #define PROMVADDR_MAX   16
 #define PROMINTR_MAX    15