From patchwork Mon Jun 30 18:15:42 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 4453701 Return-Path: X-Original-To: patchwork-linux-mmc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id D2845BEEAA for ; Mon, 30 Jun 2014 18:15:50 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D975720379 for ; Mon, 30 Jun 2014 18:15:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 102772024F for ; Mon, 30 Jun 2014 18:15:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756386AbaF3SPr (ORCPT ); Mon, 30 Jun 2014 14:15:47 -0400 Received: from mail-qc0-f202.google.com ([209.85.216.202]:42938 "EHLO mail-qc0-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754472AbaF3SPq (ORCPT ); Mon, 30 Jun 2014 14:15:46 -0400 Received: by mail-qc0-f202.google.com with SMTP id x13so841321qcv.5 for ; Mon, 30 Jun 2014 11:15:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6lC+L6PChAGHGXk8XPfyLf/dbDBzfpvAYsRFQvdgnmQ=; b=FN6DLtgFnRylMLt8OYPOOvSglixn5EpC4og18M/MfrBeEH2+N9taqdUHIIiFmdUWmv yIwBQzvQk8pUi0pkVF33x4gCeHQczubwP2ilg/8WfH9SMtQMhZHGLA+EJ4KW2FhCviL7 mNfrl0tuwekXp6nr93qiDb13v0l+nRIdeK4CanPQl9QZOAopOqz8/E7vIYvlWICm3PDc GkhBOkeC4bVUms/6G/ESXLeeHZaXNtQu8K3IWj3FWXA/1GM/XC73pLndT6A1UqbkyAw+ BFbBIF92pFUwjFMzh7j5d2MMaP4ZVW6QNzc4dcjsaHFR23fCEdytM+thieNlDYMfyTW/ Trdw== X-Gm-Message-State: ALoCoQktMmYRNWjvYgTfS87dveRThv7Bjywjods6u2EWfoxGZlPlgzXRE6q5zVlxbuu2UcvqhoSE X-Received: by 10.236.14.99 with SMTP id c63mr1147057yhc.40.1404152145422; Mon, 30 Jun 2014 11:15:45 -0700 (PDT) Received: from corp2gmr1-2.hot.corp.google.com (corp2gmr1-2.hot.corp.google.com [172.24.189.93]) by gmr-mx.google.com with ESMTPS id b39si867216yhj.0.2014.06.30.11.15.45 for (version=TLSv1.1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 30 Jun 2014 11:15:45 -0700 (PDT) Received: from gwendal.mtv.corp.google.com (gwendal.mtv.corp.google.com [172.22.72.115]) by corp2gmr1-2.hot.corp.google.com (Postfix) with ESMTP id 1B44F5A49AC; Mon, 30 Jun 2014 11:15:45 -0700 (PDT) Received: by gwendal.mtv.corp.google.com (Postfix, from userid 60833) id AC1FA14173F; Mon, 30 Jun 2014 11:15:44 -0700 (PDT) From: Gwendal Grignou To: chanho.min@lge.com, youssef.triki@st.com, cjb@laptop.org, chris@printf.net Cc: linux-mmc@vger.kernel.org, hankyung.yu@lge.com, shawn.guo@linaro.org, b29396@freescale.com, kliu5@marvell.com, Gwendal Grignou Subject: [PATCH] mmc:sdhci:handle busy-end interrupt during command Date: Mon, 30 Jun 2014 11:15:42 -0700 Message-Id: <1404152142-12714-1-git-send-email-gwendal@chromium.org> X-Mailer: git-send-email 2.0.0.526.g5318336 In-Reply-To: References: Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Chanho Min When controller supports busy-end interrupts, they may send it before commands complete. If the host sends a new command too early, it will result in CRC errors. CMD : CMD | ,,,, | RESPONSE | DATA : | busy | . . . . sdhci_cmd_irq (command interupt) . . sdhci_data_irq ("busy end" interrupt) Before this patch, if the CPU is very fast, when sdhci_data_irq is executed, it would complete the command and issue a new one while CMD line is still driven by the device, resulting in a CRC error. With this patch, we wait for both interrupts to be received before completing the command. Change-Id: I43b7467d59eb133d8c545115b48a5acbc450c2dd Signed-off-by: Hankyung Yu Signed-off-by: Chanho Min Signed-off-by: Gwendal Grignou --- I reformated your patch. I also fix an issue when SDHCI_QUIRK_NO_BUSY_IRQ is enabled. On fast chromebooks with Tohisba eMMC, check the error messages: mmc0: Got command interrupt 0x00000001 even though no command operation was in progress. and mmc0: unexpected status 0x800800 after switch are gone. drivers/mmc/host/sdhci.c | 29 ++++++++++++++++++++++++----- include/linux/mmc/sdhci.h | 1 + 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 04f0314..acfb2aa 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1007,6 +1007,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mod_timer(&host->timer, jiffies + 10 * HZ); host->cmd = cmd; + host->busy_handle = 0; sdhci_prepare_data(host, cmd); @@ -2282,11 +2283,21 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) if (host->cmd->data) DBG("Cannot wait for busy signal when also " "doing a data transfer"); - else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)) + else if (host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) { + /* + * The controller does not support the end-of-busy IRQ, + * fall through and take the SDHCI_INT_RESPONSE + */ + } else if (host->busy_handle == 0) { + /* Mark that command complete before busy is ended */ + host->busy_handle = 1; return; - - /* The controller does not support the end-of-busy IRQ, - * fall through and take the SDHCI_INT_RESPONSE */ + } else { + /* + * We already received end-of-busy IRQ, + * process commnad now. + */ + } } if (intmask & SDHCI_INT_RESPONSE) @@ -2346,7 +2357,15 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) */ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) { if (intmask & SDHCI_INT_DATA_END) { - sdhci_finish_command(host); + /* + * Some cards handle busy-end interrupt + * before the command completed, so make + * sure we do things in the proper order. + */ + if (host->busy_handle) + sdhci_finish_command(host); + else + host->busy_handle = 1; return; } } diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 796216c..7fa83aa 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -150,6 +150,7 @@ struct sdhci_host { struct mmc_command *cmd; /* Current command */ struct mmc_data *data; /* Current data request */ unsigned int data_early:1; /* Data finished before cmd */ + unsigned int busy_handle:1; /* Handling the order of Busy-end */ struct sg_mapping_iter sg_miter; /* SG state for PIO */ unsigned int blocks; /* remaining PIO blocks */