Skip to content

Commit

Permalink
sunhme: Fix Quattro HME irq registration on proble failures
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
meelisroos authored and davem330 committed Feb 11, 2009
1 parent fcffd0d commit 7b7a799
Showing 1 changed file with 28 additions and 6 deletions.
34 changes: 28 additions & 6 deletions drivers/net/sunhme.c
Original file line number Diff line number Diff line change
Expand Up @@ -2543,25 +2543,36 @@ static struct quattro * __devinit quattro_sbus_find(struct of_device *child)
}

/* After all quattro cards have been probed, we call these functions
* to register the IRQ handlers.
* to register the IRQ handlers for the cards that have been
* successfully probed and skip the cards that failed to initialize
*/
static void __init quattro_sbus_register_irqs(void)
static int __init quattro_sbus_register_irqs(void)
{
struct quattro *qp;

for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
struct of_device *op = qp->quattro_dev;
int err;
int err, qfe_slot, skip = 0;

for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) {
if (!qp->happy_meals[qfe_slot])
skip = 1;
}
if (skip)
continue;

err = request_irq(op->irqs[0],
quattro_sbus_interrupt,
IRQF_SHARED, "Quattro",
qp);
if (err != 0) {
printk(KERN_ERR "Quattro: Fatal IRQ registery error %d.\n", err);
panic("QFE request irq");
printk(KERN_ERR "Quattro HME: IRQ registration "
"error %d.\n", err);
return err;
}
}

return 0;
}

static void quattro_sbus_free_irqs(void)
Expand All @@ -2570,6 +2581,14 @@ static void quattro_sbus_free_irqs(void)

for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
struct of_device *op = qp->quattro_dev;
int qfe_slot, skip = 0;

for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) {
if (!qp->happy_meals[qfe_slot])
skip = 1;
}
if (skip)
continue;

free_irq(op->irqs[0], qp);
}
Expand Down Expand Up @@ -2828,6 +2847,9 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
if (hp->tcvregs)
of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);

if (qp)
qp->happy_meals[qfe_slot] = NULL;

err_out_free_netdev:
free_netdev(dev);

Expand Down Expand Up @@ -3285,7 +3307,7 @@ static int __init happy_meal_sbus_init(void)

err = of_register_driver(&hme_sbus_driver, &of_bus_type);
if (!err)
quattro_sbus_register_irqs();
err = quattro_sbus_register_irqs();

return err;
}
Expand Down

0 comments on commit 7b7a799

Please sign in to comment.