summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-05-24 18:35:48 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-05-24 18:35:48 -0700
commita5d436c4dfeff1cf15efa5bbb17271727be55102 (patch)
treee18a58eaa717da8a16ff2e1d0349bb0d54cf9403
parent1c7481042ac10ef187e308a54aeb85a4487c87eb (diff)
[PATCH] ppc64: avoid bogus real IRQ numbers
Signed-off-by: Paul Mackerras <paulus@samba.org> Early in the boot process on pSeries machines, we look in the Open Firmware device tree for information about the interrupt assignments, and assign virtual IRQ numbers for each physical IRQ. There is currently a couple of bugs in this code which result in us assigning virtual IRQs for nonexistent physical IRQs. This causes problems when we call the firmware to enable or disable those nonexistent physical IRQs. Some versions at least of the firmware will hit an assertion failure and crash the machine when this happens. This patch fixes the bugs and ensures that we don't try and use nonexistent physical IRQ numbers. One bug was that we were mapping ISA interrupts, which is unnecessary since virtual IRQ numbers 0 - 15 are reserved for them. The other was that when we had a PCI interrupt (which is always in the range 1 to 4, corresponding to INTA to INTD) which didn't have a mapping in the PCI host bridge above it, we were just using the original number (usually 1) rather than ignoring it.
-rw-r--r--arch/ppc64/kernel/prom.c39
1 files changed, 24 insertions, 15 deletions
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index 527c1eea130e..76216f3fb411 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -2189,11 +2189,13 @@ map_interrupt(unsigned int **irq, struct device_node **ictrler,
ints = imap - nintrc;
reg = ints - naddrc;
}
+ if (p == NULL) {
#ifdef DEBUG_IRQ
- if (p == NULL)
printk("hmmm, int tree for %s doesn't have ctrler\n",
np->full_name);
#endif
+ return 0;
+ }
*irq = ints;
*ictrler = p;
return nintrc;
@@ -2204,7 +2206,7 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start,
int measure_only)
{
unsigned int *ints;
- int intlen, intrcells;
+ int intlen, intrcells, intrcount;
int i, j, n;
unsigned int *irq, virq;
struct device_node *ic;
@@ -2214,34 +2216,40 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start,
return mem_start;
intrcells = prom_n_intr_cells(np);
intlen /= intrcells * sizeof(unsigned int);
- np->n_intrs = intlen;
np->intrs = (struct interrupt_info *) mem_start;
mem_start += intlen * sizeof(struct interrupt_info);
if (measure_only)
return mem_start;
- for (i = 0; i < intlen; ++i) {
- np->intrs[i].line = 0;
- np->intrs[i].sense = 1;
+ intrcount = 0;
+ for (i = 0; i < intlen; ++i, ints += intrcells) {
n = map_interrupt(&irq, &ic, np, ints, intrcells);
if (n <= 0)
continue;
- virq = virt_irq_create_mapping(irq[0]);
- if (virq == NO_IRQ) {
- printk(KERN_CRIT "Could not allocate interrupt "
- "number for %s\n", np->full_name);
- } else
- np->intrs[i].line = irq_offset_up(virq);
+
+ /* don't map IRQ numbers under a cascaded 8259 controller */
+ if (ic && device_is_compatible(ic, "chrp,iic")) {
+ np->intrs[intrcount].line = irq[0];
+ } else {
+ virq = virt_irq_create_mapping(irq[0]);
+ if (virq == NO_IRQ) {
+ printk(KERN_CRIT "Could not allocate interrupt"
+ " number for %s\n", np->full_name);
+ continue;
+ }
+ np->intrs[intrcount].line = irq_offset_up(virq);
+ }
/* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) {
char *name = get_property(ic->parent, "name", NULL);
if (name && !strcmp(name, "u3"))
- np->intrs[i].line += 128;
+ np->intrs[intrcount].line += 128;
}
+ np->intrs[intrcount].sense = 1;
if (n > 1)
- np->intrs[i].sense = irq[1];
+ np->intrs[intrcount].sense = irq[1];
if (n > 2) {
printk("hmmm, got %d intr cells for %s:", n,
np->full_name);
@@ -2249,8 +2257,9 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start,
printk(" %d", irq[j]);
printk("\n");
}
- ints += intrcells;
+ ++intrcount;
}
+ np->n_intrs = intrcount;
return mem_start;
}