mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-13 00:29:50 +00:00
[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>
This commit is contained in:
parent
00ab956f2f
commit
46ba6d7d8b
@ -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,
|
|||||||
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,
|
|||||||
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[] = {
|
|||||||
/*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[] = {
|
|||||||
/*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[] = {
|
|||||||
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 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* 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
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user