From patchwork Fri Feb 20 20:31:56 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 5858391 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.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id BD3A4BF440 for ; Fri, 20 Feb 2015 20:32:07 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CDB85204AB for ; Fri, 20 Feb 2015 20:32:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E7FF3204B5 for ; Fri, 20 Feb 2015 20:32:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754575AbbBTUcE (ORCPT ); Fri, 20 Feb 2015 15:32:04 -0500 Received: from mail-ie0-f179.google.com ([209.85.223.179]:38740 "EHLO mail-ie0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752484AbbBTUcD (ORCPT ); Fri, 20 Feb 2015 15:32:03 -0500 Received: by iecrd18 with SMTP id rd18so10744407iec.5 for ; Fri, 20 Feb 2015 12:32:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id; bh=QV9gOr1HwgGPqIm245dmG11iEHWbUupa1DXhu8QigRQ=; b=W0p7NCBqt/2Dxspitn82qZSX2Zt9AHVmQCgbvv5w3+RMrxm47XKXOCNLqAajHdJQAH +Z63OCQN9+SDcWEV7uYVUx+ZpQw4460Ivv9+F620cbo2LbVeCvsgJaB5KQbv5VRFrBPo ppRT4ytUP374LiTnqExEw+RuUMbWzv1iHqi5M= 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; bh=QV9gOr1HwgGPqIm245dmG11iEHWbUupa1DXhu8QigRQ=; b=a//Lmmef1m9j7ov96+crLLcon9fBXNH5ZJ4i35DjBNdCIyziZgKMl871hqeRJ6oUQS bMfg2xqb3iyB4NCbNEpAknO0r1EFpqUlbm2Lazj2e5Tgq+wxW+Z14nIxJSdIYRwgzeLm nz8cqMFtpwh54CguzSARd1shzOM/w2vSc/4eGvDVsKY435RB5zFs/G4/4lcRSQ38qeOG hizNfcQ6TUCXNCE+8NHa706o+g2vQZ3QaAYs2/WphfwcVr+Xw6WVMCO8OVnOPBo/thCm lV+g8pK3LAA4ff5PuX9KFGknTMO9I7WfDT7YuwuHv1BZyUsdxv9wEmuHttMVL3XZtQdP qHDQ== X-Gm-Message-State: ALoCoQnouG8Kof1mFWz3Pbs7RWXrg4dZKU/uYTvud4U96mEjhXkrKO3cDAxBNRZ7N3pyPiHAmUYN X-Received: by 10.50.82.68 with SMTP id g4mr990079igy.26.1424464322307; Fri, 20 Feb 2015 12:32:02 -0800 (PST) Received: from tictac.mtv.corp.google.com ([172.22.65.76]) by mx.google.com with ESMTPSA id s17sm1584351igr.2.2015.02.20.12.32.00 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 20 Feb 2015 12:32:01 -0800 (PST) From: Doug Anderson To: Jaehoon Chung , Seungwon Jeon , Ulf Hansson Cc: Alim Akhtar , Sonny Rao , Andrew Bresticker , Heiko Stuebner , Addy Ke , Alexandru Stan , javier.martinez@collabora.co.uk, Doug Anderson , chris@printf.net, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2] mmc: dw_mmc: Don't start commands while busy Date: Fri, 20 Feb 2015 12:31:56 -0800 Message-Id: <1424464316-4397-1-git-send-email-dianders@chromium.org> X-Mailer: git-send-email 2.2.0.rc0.207.ga3a616c Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Spam-Status: No, score=-7.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,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 We've seen problems on some WiFi modules where we seem to send a CMD53 (which requires the data lines) while the module is asserting busy. We shouldn't do that. The Designware Databook says that before issuing a new data transfer command we should check for busy, so that's what we'll do. We'll leverage the existing dw_mmc knowledge about whether it should wait for the previous command to finish to know whether we should check for busy before sending the command. This means we won't end up incorrectly waiting for things like CMD52 (SDIO) or CMD13 (SD) which don't use the data line. Note that this also has the advantage of making sure that we don't change the clock while the card is busy, too. Signed-off-by: Doug Anderson Tested-by: Javier Martinez Canillas --- Changes in v2: - Also check for busy in in mci_send_cmd() drivers/mmc/host/dw_mmc.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 4d2e3c2..7733c5c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -102,6 +102,7 @@ struct idmac_desc { static bool dw_mci_reset(struct dw_mci *host); static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); +static int dw_mci_card_busy(struct mmc_host *mmc); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -335,6 +336,31 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) return cmdr; } +static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(500); + + /* + * Databook says that before issuing a new data transfer command + * we need to check to see if the card is busy. Data transfer commands + * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that. + * + * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is + * expected. + */ + if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) && + !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) { + while (mci_readl(host, STATUS) & SDMMC_STATUS_BUSY) { + if (time_after(jiffies, timeout)) { + /* Command will fail; we'll pass error then */ + dev_err(host->dev, "Busy; trying anyway\n"); + break; + } + udelay(10); + } + } +} + static void dw_mci_start_command(struct dw_mci *host, struct mmc_command *cmd, u32 cmd_flags) { @@ -345,6 +371,7 @@ static void dw_mci_start_command(struct dw_mci *host, mci_writel(host, CMDARG, cmd->arg); wmb(); + dw_mci_wait_while_busy(host, cmd_flags); mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); } @@ -876,6 +903,7 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) mci_writel(host, CMDARG, arg); wmb(); + dw_mci_wait_while_busy(host, cmd); mci_writel(host, CMD, SDMMC_CMD_START | cmd); while (time_before(jiffies, timeout)) {