Commit a5d436c4 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ppc64: avoid bogus real IRQ numbers

Signed-off-by: default avatarPaul 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.
parent 1c748104
...@@ -2189,11 +2189,13 @@ map_interrupt(unsigned int **irq, struct device_node **ictrler, ...@@ -2189,11 +2189,13 @@ map_interrupt(unsigned int **irq, struct device_node **ictrler,
ints = imap - nintrc; ints = imap - nintrc;
reg = ints - naddrc; reg = ints - naddrc;
} }
if (p == NULL) {
#ifdef DEBUG_IRQ #ifdef DEBUG_IRQ
if (p == NULL)
printk("hmmm, int tree for %s doesn't have ctrler\n", printk("hmmm, int tree for %s doesn't have ctrler\n",
np->full_name); np->full_name);
#endif #endif
return 0;
}
*irq = ints; *irq = ints;
*ictrler = p; *ictrler = p;
return nintrc; return nintrc;
...@@ -2204,7 +2206,7 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start, ...@@ -2204,7 +2206,7 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start,
int measure_only) int measure_only)
{ {
unsigned int *ints; unsigned int *ints;
int intlen, intrcells; int intlen, intrcells, intrcount;
int i, j, n; int i, j, n;
unsigned int *irq, virq; unsigned int *irq, virq;
struct device_node *ic; struct device_node *ic;
...@@ -2214,34 +2216,40 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start, ...@@ -2214,34 +2216,40 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start,
return mem_start; return mem_start;
intrcells = prom_n_intr_cells(np); intrcells = prom_n_intr_cells(np);
intlen /= intrcells * sizeof(unsigned int); intlen /= intrcells * sizeof(unsigned int);
np->n_intrs = intlen;
np->intrs = (struct interrupt_info *) mem_start; np->intrs = (struct interrupt_info *) mem_start;
mem_start += intlen * sizeof(struct interrupt_info); mem_start += intlen * sizeof(struct interrupt_info);
if (measure_only) if (measure_only)
return mem_start; return mem_start;
for (i = 0; i < intlen; ++i) { intrcount = 0;
np->intrs[i].line = 0; for (i = 0; i < intlen; ++i, ints += intrcells) {
np->intrs[i].sense = 1;
n = map_interrupt(&irq, &ic, np, ints, intrcells); n = map_interrupt(&irq, &ic, np, ints, intrcells);
if (n <= 0) if (n <= 0)
continue; continue;
/* 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]); virq = virt_irq_create_mapping(irq[0]);
if (virq == NO_IRQ) { if (virq == NO_IRQ) {
printk(KERN_CRIT "Could not allocate interrupt " printk(KERN_CRIT "Could not allocate interrupt"
"number for %s\n", np->full_name); " number for %s\n", np->full_name);
} else continue;
np->intrs[i].line = irq_offset_up(virq); }
np->intrs[intrcount].line = irq_offset_up(virq);
}
/* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) { if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) {
char *name = get_property(ic->parent, "name", NULL); char *name = get_property(ic->parent, "name", NULL);
if (name && !strcmp(name, "u3")) if (name && !strcmp(name, "u3"))
np->intrs[i].line += 128; np->intrs[intrcount].line += 128;
} }
np->intrs[intrcount].sense = 1;
if (n > 1) if (n > 1)
np->intrs[i].sense = irq[1]; np->intrs[intrcount].sense = irq[1];
if (n > 2) { if (n > 2) {
printk("hmmm, got %d intr cells for %s:", n, printk("hmmm, got %d intr cells for %s:", n,
np->full_name); np->full_name);
...@@ -2249,8 +2257,9 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start, ...@@ -2249,8 +2257,9 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start,
printk(" %d", irq[j]); printk(" %d", irq[j]);
printk("\n"); printk("\n");
} }
ints += intrcells; ++intrcount;
} }
np->n_intrs = intrcount;
return mem_start; return mem_start;
} }
......
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