From patchwork Mon Jul 25 08:48:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "(Exiting) Baolin Wang" X-Patchwork-Id: 9245423 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id BF238607FD for ; Mon, 25 Jul 2016 08:49:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AEB3120587 for ; Mon, 25 Jul 2016 08:49:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A2E35269E2; Mon, 25 Jul 2016 08:49:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0918E20587 for ; Mon, 25 Jul 2016 08:49:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752254AbcGYIs7 (ORCPT ); Mon, 25 Jul 2016 04:48:59 -0400 Received: from mail-pa0-f54.google.com ([209.85.220.54]:33600 "EHLO mail-pa0-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751953AbcGYIs6 (ORCPT ); Mon, 25 Jul 2016 04:48:58 -0400 Received: by mail-pa0-f54.google.com with SMTP id ks6so59464334pab.0 for ; Mon, 25 Jul 2016 01:48:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=8P+HGd9zQEEwAQtyNR3UaZapEyFIe9k8p4SgLfN2SSI=; b=B3pGNobk4EKy9IZgxOEeruDUKjvistJQ0+w0aJbNWdSLo/7j1+oELxpFBKAxChzEIb 6YcyDYq3M6gpKusax3XnoJW/hJ28c69ffsP2IAz/RJPxHFlaoIEmG+3BoAbFFmEF8bIe Q5LzXmSN2cXS/KQyiBnKB82EZtzvNu8kINXAA= 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=8P+HGd9zQEEwAQtyNR3UaZapEyFIe9k8p4SgLfN2SSI=; b=PtWvTyY4JkeQ1peEne/tvPNtkvDX/HYkSDBuvhwT7vH2gupLD9vlbwurwT7xHwrePx 6975YuTH3CNo+lIJuBLXtsWru+dIdGAsnYY6EjPUxdSKisvy5qEI/Lrw3FNMwSKRPrXM 8r77IVp8SpAq7vRrdYtc2w/4A4QZRkfz5AheOnKnJ7MdNuKy5ngH8j13y1OMzCphmF2r Asa+zm+WbMG7jidxOTN8UJyXcWzO482LLhRnZSqWtYI7G6+O29cAzNU2tq0AeQwmrW/y 5to5WagUWnirskZZrkqINrZ9YHE5p4dxi5oCkVfDmnPzTXqdx89RPJsscdyZvOIyKqg3 CrYw== X-Gm-Message-State: AEkoouu4JgHhOpTjoHBJ4IB6ViML/LKmkOgk2X88zFhg0LnGcyFIhfCqpxlyutpAcm1kDSQr X-Received: by 10.66.72.195 with SMTP id f3mr27166974pav.141.1469436537782; Mon, 25 Jul 2016 01:48:57 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([175.111.195.49]) by smtp.gmail.com with ESMTPSA id tm1sm38153971pab.31.2016.07.25.01.48.53 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Jul 2016 01:48:57 -0700 (PDT) From: Baolin Wang To: ulf.hansson@linaro.org Cc: adrian.hunter@intel.com, rmk+kernel@arm.linux.org.uk, shawn.lin@rock-chips.com, dianders@chromium.org, heiko@sntech.de, david@protonic.nl, hdegoede@redhat.com, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, broonie@kernel.org, linus.walleij@linaro.org, baolin.wang@linaro.org Subject: [PATCH v3] mmc: Change the max discard sectors and erase response if mmc host supports busy signalling Date: Mon, 25 Jul 2016 16:48:39 +0800 Message-Id: <01d645020004fe135bb5374ecb9f5f6ac0884b6b.1469436431.git.baolin.wang@linaro.org> X-Mailer: git-send-email 1.7.9.5 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When mmc host HW supports busy signalling (using R1B as response), We shouldn't use 'host->max_busy_timeout' as the limitation when deciding the max discard sectors that we tell the generic BLOCK layer about. Instead, we should pick one preferred erase size as the max discard sectors. If the host controller supports busy signalling and the timeout for the erase operation does not exceed the max_busy_timeout, we should use R1B response. Or we need to prevent the host from doing hw busy detection, which is done by converting to a R1 response instead. Signed-off-by: Baolin Wang --- Changes since v2: - Remove the 'MMC_CAP_WAIT_WHILE_BUSY' flag checking when deciding if we can use R1B response. - Avoid polling CMD13 when using R1B response. - Use earlier calculated erase timeout as the polling time. Changes since v1: - Remove the 'MMC_CAP_WAIT_WHILE_BUSY' flag checking when deciding the max discard sectors. --- drivers/mmc/core/core.c | 60 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8b4dfd4..b4c08d1a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2060,7 +2060,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, unsigned int to, unsigned int arg) { struct mmc_command cmd = {0}; - unsigned int qty = 0; + unsigned int qty = 0, busy_timeout = 0; + bool use_r1b_resp = false; unsigned long timeout; int err; @@ -2128,8 +2129,22 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_ERASE; cmd.arg = arg; - cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - cmd.busy_timeout = mmc_erase_timeout(card, arg, qty); + busy_timeout = mmc_erase_timeout(card, arg, qty); + /* + * If the host controller supports busy signalling and the timeout for + * the erase operation does not exceed the max_busy_timeout, we should + * use R1B response. Or we need to prevent the host from doing hw busy + * detection, which is done by converting to a R1 response instead. + */ + if (card->host->max_busy_timeout && + busy_timeout > card->host->max_busy_timeout) { + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + } else { + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; + cmd.busy_timeout = busy_timeout; + use_r1b_resp = true; + } + err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_err("mmc_erase: erase error %d, status %#x\n", @@ -2141,7 +2156,14 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, if (mmc_host_is_spi(card->host)) goto out; - timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS); + /* + * In case of when R1B + MMC_CAP_WAIT_WHILE_BUSY is used, the polling + * shall be avoided. + */ + if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) + goto out; + + timeout = jiffies + msecs_to_jiffies(busy_timeout); do { memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; @@ -2321,23 +2343,41 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card, unsigned int arg) { struct mmc_host *host = card->host; - unsigned int max_discard, x, y, qty = 0, max_qty, timeout; + unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout; unsigned int last_timeout = 0; - if (card->erase_shift) + if (card->erase_shift) { max_qty = UINT_MAX >> card->erase_shift; - else if (mmc_card_sd(card)) + min_qty = card->pref_erase >> card->erase_shift; + } else if (mmc_card_sd(card)) { max_qty = UINT_MAX; - else + min_qty = card->pref_erase; + } else { max_qty = UINT_MAX / card->erase_size; + min_qty = card->pref_erase / card->erase_size; + } - /* Find the largest qty with an OK timeout */ + /* + * We should not only use 'host->max_busy_timeout' as the limitation + * when deciding the max discard sectors. We should set a balance value + * to improve the erase speed, and it can not get too long timeout at + * the same time. + * + * Here we set 'card->pref_erase' as the minimal discard sectors no + * matter what size of 'host->max_busy_timeout', but if the + * 'host->max_busy_timeout' is large enough for more discard sectors, + * then we can continue to increase the max discard sectors until we + * get a balance value. + */ do { y = 0; for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) { timeout = mmc_erase_timeout(card, arg, qty + x); - if (timeout > host->max_busy_timeout) + + if (qty + x > min_qty && + timeout > host->max_busy_timeout) break; + if (timeout < last_timeout) break; last_timeout = timeout;