diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/ras.c')
| -rw-r--r-- | arch/powerpc/platforms/pseries/ras.c | 82 | 
1 files changed, 53 insertions, 29 deletions
| diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 9639c66b453d..9df783088b61 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -72,32 +72,62 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id,  /* #define DEBUG */ -static void request_ras_irqs(struct device_node *np, char *propname, + +static void request_ras_irqs(struct device_node *np,  			irqreturn_t (*handler)(int, void *, struct pt_regs *),  			const char *name)  { -	unsigned int *ireg, len, i; -	int virq, n_intr; - -	ireg = (unsigned int *)get_property(np, propname, &len); -	if (ireg == NULL) -		return; -	n_intr = prom_n_intr_cells(np); -	len /= n_intr * sizeof(*ireg); - -	for (i = 0; i < len; i++) { -		virq = virt_irq_create_mapping(*ireg); -		if (virq == NO_IRQ) { -			printk(KERN_ERR "Unable to allocate interrupt " -			       "number for %s\n", np->full_name); -			return; +	int i, index, count = 0; +	struct of_irq oirq; +	u32 *opicprop; +	unsigned int opicplen; +	unsigned int virqs[16]; + +	/* Check for obsolete "open-pic-interrupt" property. If present, then +	 * map those interrupts using the default interrupt host and default +	 * trigger +	 */ +	opicprop = (u32 *)get_property(np, "open-pic-interrupt", &opicplen); +	if (opicprop) { +		opicplen /= sizeof(u32); +		for (i = 0; i < opicplen; i++) { +			if (count > 15) +				break; +			virqs[count] = irq_create_mapping(NULL, *(opicprop++), +							 IRQ_TYPE_NONE); +			if (virqs[count] == NO_IRQ) +				printk(KERN_ERR "Unable to allocate interrupt " +				       "number for %s\n", np->full_name); +			else +				count++; +  		} -		if (request_irq(irq_offset_up(virq), handler, 0, name, NULL)) { +	} +	/* Else use normal interrupt tree parsing */ +	else { +		/* First try to do a proper OF tree parsing */ +		for (index = 0; of_irq_map_one(np, index, &oirq) == 0; +		     index++) { +			if (count > 15) +				break; +			virqs[count] = irq_create_of_mapping(oirq.controller, +							    oirq.specifier, +							    oirq.size); +			if (virqs[count] == NO_IRQ) +				printk(KERN_ERR "Unable to allocate interrupt " +				       "number for %s\n", np->full_name); +			else +				count++; +		} +	} + +	/* Now request them */ +	for (i = 0; i < count; i++) { +		if (request_irq(virqs[i], handler, 0, name, NULL)) {  			printk(KERN_ERR "Unable to request interrupt %d for " -			       "%s\n", irq_offset_up(virq), np->full_name); +			       "%s\n", virqs[i], np->full_name);  			return;  		} -		ireg += n_intr;  	}  } @@ -115,20 +145,14 @@ static int __init init_ras_IRQ(void)  	/* Internal Errors */  	np = of_find_node_by_path("/event-sources/internal-errors");  	if (np != NULL) { -		request_ras_irqs(np, "open-pic-interrupt", ras_error_interrupt, -				 "RAS_ERROR"); -		request_ras_irqs(np, "interrupts", ras_error_interrupt, -				 "RAS_ERROR"); +		request_ras_irqs(np, ras_error_interrupt, "RAS_ERROR");  		of_node_put(np);  	}  	/* EPOW Events */  	np = of_find_node_by_path("/event-sources/epow-events");  	if (np != NULL) { -		request_ras_irqs(np, "open-pic-interrupt", ras_epow_interrupt, -				 "RAS_EPOW"); -		request_ras_irqs(np, "interrupts", ras_epow_interrupt, -				 "RAS_EPOW"); +		request_ras_irqs(np, ras_epow_interrupt, "RAS_EPOW");  		of_node_put(np);  	} @@ -162,7 +186,7 @@ ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)  	status = rtas_call(ras_check_exception_token, 6, 1, NULL,  			   RAS_VECTOR_OFFSET, -			   virt_irq_to_real(irq_offset_down(irq)), +			   irq_map[irq].hwirq,  			   RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS,  			   critical, __pa(&ras_log_buf),  				rtas_get_error_log_max()); @@ -198,7 +222,7 @@ ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs)  	status = rtas_call(ras_check_exception_token, 6, 1, NULL,  			   RAS_VECTOR_OFFSET, -			   virt_irq_to_real(irq_offset_down(irq)), +			   irq_map[irq].hwirq,  			   RTAS_INTERNAL_ERROR, 1 /*Time Critical */,  			   __pa(&ras_log_buf),  				rtas_get_error_log_max()); | 
