From patchwork Tue May 31 21:52:57 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Drake X-Patchwork-Id: 98088 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Received: from canuck.infradead.org (canuck.infradead.org [134.117.69.58]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DE1CAB6F76 for ; Wed, 1 Jun 2011 08:39:10 +1000 (EST) Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QRWs6-0005n5-Qj; Tue, 31 May 2011 21:53:06 +0000 Received: from mail-px0-f171.google.com ([209.85.212.171]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QRWs1-0005m2-Pw for linux-arm-kernel@lists.infradead.org; Tue, 31 May 2011 21:53:03 +0000 Received: by pxi7 with SMTP id 7so3391714pxi.16 for ; Tue, 31 May 2011 14:52:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:cc:content-type; bh=18Mtzeyrd+JHGyjl2qUy5wZ5+4bivu3A1sl1SPmNcQQ=; b=lvGV2CpdPVq0lsCLU79tRkhQHMrhZb81Wj1LewHZHgQBsGaPBpxJNsKs0k12+gGm1t 6z5p6nUIFjapMpLZr4c44Y98OZOe81Q6R5IaQfMj9cU7yZXreeJOwPQplbT/5lYAaQ/Q TNlNnBCMhWpUCEjLSakmH53ZMshTnnRkgaqpc= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:cc:content-type; b=jCMN8CfS4IA8xtdqpPKOuGvDmPwaJtAmyRC5+Cz2PurI+tugpulGusrv0WHh45sh/q jgEJwUDwW+XSribVIwSSYjZW6dGaArSmxYPYh28akAr2/U071EM9aHDK33zrh10NgA8d seigIWbxHEIh8GbC/EnRvYK22yj2lbnOuem0g= MIME-Version: 1.0 Received: by 10.68.4.194 with SMTP id m2mr2520846pbm.228.1306878777866; Tue, 31 May 2011 14:52:57 -0700 (PDT) Received: by 10.68.40.41 with HTTP; Tue, 31 May 2011 14:52:57 -0700 (PDT) In-Reply-To: <1306874008-28867-1-git-send-email-per.forlin@linaro.org> References: <1306874008-28867-1-git-send-email-per.forlin@linaro.org> Date: Tue, 31 May 2011 22:52:57 +0100 X-Google-Sender-Auth: wjWQrmvG01N-in2Rh4uswAB8-J0 Message-ID: Subject: Re: [PATCH 0/2] sdio: make sdio_single_irq optional due to suprious IRQ From: Daniel Drake To: Per Forlin X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110531_175302_191445_E3C9CD28 X-CRM114-Status: GOOD ( 23.45 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is freemail (dsd.olpc[at]gmail.com) -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.212.171 listed in list.dnswl.org] 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.0 RFC_ABUSE_POST Both abuse and postmaster missing on sender domain Cc: Nicolas Pitre , linaro-dev@lists.linaro.org, Chris Ball , linux-mmc@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org On 31 May 2011 21:33, Per Forlin wrote: > Daniel Drake reported an issue in the libertas sdio client that was > triggered by the sdio_single_irq functionality. His SDIO device seems to > raise an interrupt even though there are no bits set in the CCCR_INTx > register. This behaviour is not supported by the sdio_single_irq feature nor > the SDIO spec. The purpose of the sdio_single_irq feature is to avoid the > overhead of checking the CCCR_INTx registers, this result in no error > handling of the case if there is a pending IRQ with none CCCR_INTx bits set. Thanks a lot for diagnosing this and nice work on figuring out the root cause presumably without even having access to the hardware! I've looked further, based on your findings, and have found that you are correct. During initialisation, exactly one interrupt is received with CCCR_INTx=0. Previously the mmc stack threw this interrupt away, after the optimization it now calls into libertas before it is ready to handle interrupts, leading to the crash. From that point, all other interrupts that come in are "normal". This is definitely a weird hardware issue, and it would annoy me for this hardware to cause a second generic mmc layer feature be disabled by default! And actually it is not much work to harden up the libertas driver to be able to accept that spurious IRQ, and during the process of fixing that it actually made the spurious IRQ go away completely. Patch attached. So, I vote for that we work around this little hardware issue in the libertas driver, and leave this optimization enabled by default until we find a hardware issue that is more difficult to workaround. I can take on submission of the libertas patch. Thoughts? Daniel 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);