Commit d2ac49fe authored by Daniel Drake's avatar Daniel Drake Committed by John W. Linville

libertas_sdio: handle spurious interrupts

Commit 06e8935f adds an IRQ handling
optimization for single-function SDIO cards like this one, but at the
same time exposes a small hardware bug.

During hardware init, an interrupt is generated with (apparently) no
source. Previously, mmc threw this interrupt away, but now (due to the
optimization), the mmc layer passes this onto libertas, before it is ready
(and before it has enabled interrupts), causing a crash.

Work around this hardware bug by registering the IRQ handler later and
making it capable of handling interrupts with no cause. The change that
makes the IRQ handler registration happen later actually eliminates
the spurious interrupt as well.
Signed-off-by: default avatarDaniel Drake <dsd@laptop.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 59e7e707
...@@ -907,7 +907,7 @@ static void if_sdio_interrupt(struct sdio_func *func) ...@@ -907,7 +907,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
card = sdio_get_drvdata(func); card = sdio_get_drvdata(func);
cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret); cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
if (ret) if (ret || !cause)
goto out; goto out;
lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause); lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
...@@ -1008,10 +1008,6 @@ static int if_sdio_probe(struct sdio_func *func, ...@@ -1008,10 +1008,6 @@ static int if_sdio_probe(struct sdio_func *func,
if (ret) if (ret)
goto release; goto release;
ret = sdio_claim_irq(func, if_sdio_interrupt);
if (ret)
goto disable;
/* For 1-bit transfers to the 8686 model, we need to enable the /* For 1-bit transfers to the 8686 model, we need to enable the
* interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
* bit to allow access to non-vendor registers. */ * bit to allow access to non-vendor registers. */
...@@ -1082,6 +1078,21 @@ static int if_sdio_probe(struct sdio_func *func, ...@@ -1082,6 +1078,21 @@ static int if_sdio_probe(struct sdio_func *func,
else else
card->rx_unit = 0; card->rx_unit = 0;
/*
* Set up the interrupt handler late.
*
* If we set it up earlier, the (buggy) hardware generates a spurious
* interrupt, even before the interrupt has been enabled, with
* CCCR_INTx = 0.
*
* We register the interrupt handler late so that we can handle any
* spurious interrupts, and also to avoid generation of that known
* spurious interrupt in the first place.
*/
ret = sdio_claim_irq(func, if_sdio_interrupt);
if (ret)
goto disable;
/* /*
* Enable interrupts now that everything is set up * Enable interrupts now that everything is set up
*/ */
......
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