Commit 46ba6d7d authored by David S. Miller's avatar David S. Miller

[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: default avatarDavid S. Miller <davem@davemloft.net>
parent 00ab956f
...@@ -542,9 +542,17 @@ static void __init build_device_resources(struct of_device *op, ...@@ -542,9 +542,17 @@ static void __init build_device_resources(struct of_device *op,
/* Convert to num-cells. */ /* Convert to num-cells. */
num_reg /= 4; num_reg /= 4;
/* Conver to num-entries. */ /* Convert to num-entries. */
num_reg /= na + ns; 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++) { for (index = 0; index < num_reg; index++) {
struct resource *r = &op->resource[index]; struct resource *r = &op->resource[index];
u32 addr[OF_MAX_ADDR_CELLS]; u32 addr[OF_MAX_ADDR_CELLS];
...@@ -650,8 +658,22 @@ apply_interrupt_map(struct device_node *dp, struct device_node *pp, ...@@ -650,8 +658,22 @@ apply_interrupt_map(struct device_node *dp, struct device_node *pp,
next: next:
imap += (na + 3); 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; return NULL;
}
*irq_p = irq; *irq_p = irq;
cp = of_find_node_by_phandle(handle); cp = of_find_node_by_phandle(handle);
...@@ -803,6 +825,14 @@ static struct of_device * __init scan_one_device(struct device_node *dp, ...@@ -803,6 +825,14 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
op->num_irqs = 0; 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); build_device_resources(op, parent);
for (i = 0; i < op->num_irqs; i++) for (i = 0; i < op->num_irqs; i++)
op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]); op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
......
...@@ -344,10 +344,12 @@ static unsigned long __psycho_onboard_imap_off[] = { ...@@ -344,10 +344,12 @@ static unsigned long __psycho_onboard_imap_off[] = {
/*0x2f*/ PSYCHO_IMAP_CE, /*0x2f*/ PSYCHO_IMAP_CE,
/*0x30*/ PSYCHO_IMAP_A_ERR, /*0x30*/ PSYCHO_IMAP_A_ERR,
/*0x31*/ PSYCHO_IMAP_B_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_BASE 0x20
#define PSYCHO_ONBOARD_IRQ_LAST 0x32 #define PSYCHO_ONBOARD_IRQ_LAST 0x34
#define psycho_onboard_imap_offset(__ino) \ #define psycho_onboard_imap_offset(__ino) \
__psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]
...@@ -529,6 +531,10 @@ static unsigned long __sabre_onboard_imap_off[] = { ...@@ -529,6 +531,10 @@ static unsigned long __sabre_onboard_imap_off[] = {
/*0x2e*/ SABRE_IMAP_UE, /*0x2e*/ SABRE_IMAP_UE,
/*0x2f*/ SABRE_IMAP_CE, /*0x2f*/ SABRE_IMAP_CE,
/*0x30*/ SABRE_IMAP_PCIERR, /*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_BASE 0x20
#define SABRE_ONBOARD_IRQ_LAST 0x30 #define SABRE_ONBOARD_IRQ_LAST 0x30
...@@ -895,6 +901,8 @@ static unsigned long sysio_irq_offsets[] = { ...@@ -895,6 +901,8 @@ static unsigned long sysio_irq_offsets[] = {
SYSIO_IMAP_CE, SYSIO_IMAP_CE,
SYSIO_IMAP_SBERR, SYSIO_IMAP_SBERR,
SYSIO_IMAP_PMGMT, SYSIO_IMAP_PMGMT,
SYSIO_IMAP_GFX,
SYSIO_IMAP_EUPA,
}; };
#undef bogon #undef bogon
......
...@@ -175,7 +175,7 @@ struct linux_nodeops { ...@@ -175,7 +175,7 @@ struct linux_nodeops {
}; };
/* More fun PROM structures for device probing. */ /* More fun PROM structures for device probing. */
#define PROMREG_MAX 16 #define PROMREG_MAX 24
#define PROMVADDR_MAX 16 #define PROMVADDR_MAX 16
#define PROMINTR_MAX 15 #define PROMINTR_MAX 15
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment