aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMeelis Roos <mroos@linux.ee>2009-02-10 20:29:42 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-10 20:29:42 -0500
commit7b7a799d664a46eec6cb7de200c90f40730497a7 (patch)
tree8d14ebfbfcf4285388736e1b45a5d6dd7e17220b
parentfcffd0d8bbddac757cd856e635ac75e8eb4518bc (diff)
sunhme: Fix Quattro HME irq registration on proble failures
Currently, the sunhme driver installs SBus Quattro interrupt handler when at least one HME card was initialized correctly and at least one Quattro card is present. This breaks when a Quattro card fails initialization for whatever reason - IRQ is registered and OOPS happens when it fires. The solution, as suggested by David Miller, was to keep track which cards of the Quattro bundles have been initialized, and request/free the Quattro IRQ only when all four devices have been successfully initialized. The patch only touches SBus initialization - PCI init already resets the card pointer to NULL on init failure. The patch has been tested on Sun E3500 with SBus and PCI single HME cards and one PCI Quattro HME card in a situation where any PCI card failed init when the SBus routines tried to init them by mistake. Additionally it replaces Quattro request_irq panic with error return - if this card fails to work, at least let the others work. Tested on E450 with PCI HME and PCI Quad HME. [ Minor coding style fixups -DaveM ] Signed-off-by: Meelis Roos <mroos@linux.ee> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/sunhme.c34
1 files changed, 28 insertions, 6 deletions
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index cc4013be5e18..d4fb4acdbebd 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2543,25 +2543,36 @@ static struct quattro * __devinit quattro_sbus_find(struct of_device *child)
2543} 2543}
2544 2544
2545/* After all quattro cards have been probed, we call these functions 2545/* After all quattro cards have been probed, we call these functions
2546 * to register the IRQ handlers. 2546 * to register the IRQ handlers for the cards that have been
2547 * successfully probed and skip the cards that failed to initialize
2547 */ 2548 */
2548static void __init quattro_sbus_register_irqs(void) 2549static int __init quattro_sbus_register_irqs(void)
2549{ 2550{
2550 struct quattro *qp; 2551 struct quattro *qp;
2551 2552
2552 for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { 2553 for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
2553 struct of_device *op = qp->quattro_dev; 2554 struct of_device *op = qp->quattro_dev;
2554 int err; 2555 int err, qfe_slot, skip = 0;
2556
2557 for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) {
2558 if (!qp->happy_meals[qfe_slot])
2559 skip = 1;
2560 }
2561 if (skip)
2562 continue;
2555 2563
2556 err = request_irq(op->irqs[0], 2564 err = request_irq(op->irqs[0],
2557 quattro_sbus_interrupt, 2565 quattro_sbus_interrupt,
2558 IRQF_SHARED, "Quattro", 2566 IRQF_SHARED, "Quattro",
2559 qp); 2567 qp);
2560 if (err != 0) { 2568 if (err != 0) {
2561 printk(KERN_ERR "Quattro: Fatal IRQ registery error %d.\n", err); 2569 printk(KERN_ERR "Quattro HME: IRQ registration "
2562 panic("QFE request irq"); 2570 "error %d.\n", err);
2571 return err;
2563 } 2572 }
2564 } 2573 }
2574
2575 return 0;
2565} 2576}
2566 2577
2567static void quattro_sbus_free_irqs(void) 2578static void quattro_sbus_free_irqs(void)
@@ -2570,6 +2581,14 @@ static void quattro_sbus_free_irqs(void)
2570 2581
2571 for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { 2582 for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
2572 struct of_device *op = qp->quattro_dev; 2583 struct of_device *op = qp->quattro_dev;
2584 int qfe_slot, skip = 0;
2585
2586 for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) {
2587 if (!qp->happy_meals[qfe_slot])
2588 skip = 1;
2589 }
2590 if (skip)
2591 continue;
2573 2592
2574 free_irq(op->irqs[0], qp); 2593 free_irq(op->irqs[0], qp);
2575 } 2594 }
@@ -2828,6 +2847,9 @@ err_out_iounmap:
2828 if (hp->tcvregs) 2847 if (hp->tcvregs)
2829 of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); 2848 of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
2830 2849
2850 if (qp)
2851 qp->happy_meals[qfe_slot] = NULL;
2852
2831err_out_free_netdev: 2853err_out_free_netdev:
2832 free_netdev(dev); 2854 free_netdev(dev);
2833 2855
@@ -3285,7 +3307,7 @@ static int __init happy_meal_sbus_init(void)
3285 3307
3286 err = of_register_driver(&hme_sbus_driver, &of_bus_type); 3308 err = of_register_driver(&hme_sbus_driver, &of_bus_type);
3287 if (!err) 3309 if (!err)
3288 quattro_sbus_register_irqs(); 3310 err = quattro_sbus_register_irqs();
3289 3311
3290 return err; 3312 return err;
3291} 3313}