From patchwork Thu Jun 2 23:13:26 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Drake X-Patchwork-Id: 845292 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p52NXY94016721 for ; Thu, 2 Jun 2011 23:33:34 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753368Ab1FBXdd (ORCPT ); Thu, 2 Jun 2011 19:33:33 -0400 Received: from queueout04-winn.ispmail.ntl.com ([81.103.221.58]:13640 "EHLO queueout04-winn.ispmail.ntl.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752410Ab1FBXdc (ORCPT ); Thu, 2 Jun 2011 19:33:32 -0400 Received: from aamtaout04-winn.ispmail.ntl.com ([81.103.221.35]) by mtaout01-winn.ispmail.ntl.com (InterMail vM.7.08.04.00 201-2186-134-20080326) with ESMTP id <20110602231329.ILJD14839.mtaout01-winn.ispmail.ntl.com@aamtaout04-winn.ispmail.ntl.com>; Fri, 3 Jun 2011 00:13:29 +0100 Received: from zog.reactivated.net ([86.14.215.141]) by aamtaout04-winn.ispmail.ntl.com (InterMail vG.3.00.04.00 201-2196-133-20080908) with ESMTP id <20110602231329.ZVIV25656.aamtaout04-winn.ispmail.ntl.com@zog.reactivated.net>; Fri, 3 Jun 2011 00:13:29 +0100 Received: by zog.reactivated.net (Postfix, from userid 1000) id 116A79D401C; Fri, 3 Jun 2011 00:13:26 +0100 (BST) From: Daniel Drake To: linville@tuxdriver.com Cc: dcbw@redhat.com Cc: linux-wireless@vger.kernel.org Cc: libertas-dev@lists.infradead.org Cc: linux-mmc@vger.kernel.org Subject: [PATCH] libertas_sdio: handle spurious interrupts Message-Id: <20110602231327.116A79D401C@zog.reactivated.net> Date: Fri, 3 Jun 2011 00:13:26 +0100 (BST) X-Cloudmark-Analysis: v=1.1 cv=JvdXmxIgLJv2/GthKqHpGJEEHukvLcvELVXUanXFreg= c=1 sm=0 a=aLAU4cMdAMUA:10 a=vJ1w_8FsMGIA:10 a=Op-mwl0xAAAA:8 a=-C1Mlz9HH_h7xtznlooA:9 a=bEx5M0tb8w9VmMzgYj0A:7 a=d4CUUju0HPYA:10 a=aDdW-UGuuPsuXKU8:21 a=ekJcej9v7Kz4nXB7:21 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 02 Jun 2011 23:33:34 +0000 (UTC) Commit 06e8935febe687e2a561707d4c7ca4245d261dbe 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: Daniel Drake Acked-by: Dan Williams --- drivers/net/wireless/libertas/if_sdio.c | 21 ++++++++++++++++----- 1 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index a7b5cb0..224e985 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -907,7 +907,7 @@ static void if_sdio_interrupt(struct sdio_func *func) card = sdio_get_drvdata(func); cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret); - if (ret) + if (ret || !cause) goto out; lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause); @@ -1008,10 +1008,6 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) 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 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 * bit to allow access to non-vendor registers. */ @@ -1083,6 +1079,21 @@ static int if_sdio_probe(struct sdio_func *func, 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 */ sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);