From patchwork Sat Nov 18 01:06:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 10064245 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 C5FFE6037E for ; Sat, 18 Nov 2017 01:06:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B837E2AEAF for ; Sat, 18 Nov 2017 01:06:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ACD242AEB2; Sat, 18 Nov 2017 01:06:50 +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.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, 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 C8CA62AEAF for ; Sat, 18 Nov 2017 01:06:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1162357AbdKRBGs (ORCPT ); Fri, 17 Nov 2017 20:06:48 -0500 Received: from mail-it0-f68.google.com ([209.85.214.68]:45769 "EHLO mail-it0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1162355AbdKRBGr (ORCPT ); Fri, 17 Nov 2017 20:06:47 -0500 Received: by mail-it0-f68.google.com with SMTP id l196so6135016itl.4 for ; Fri, 17 Nov 2017 17:06:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:from:to:cc:subject:date:message-id; bh=UkYyv0/6vh3CHIvTfJ94IsvBbhRXrQdlT5+wvMXUDOA=; b=BAlNb+4BD6ewVqHlMEHHOQKnBIdMyxsbrHa6hgCvcZi0Bqdnk5p+dI2kMT/RI4Dipk k/Hcxyg0amEQmJq2cL4Qqa/WvlPifZlxa4FaYVkacw5eI4GKjfiTvs0gOnsh4uKAuxQx u3W85YptuqOqFIm1ilpPcWfLdYAws5dTH0ENiqnihA+xmMbEjvAmc0KZHzw+r5vCtfsz AgWOCoOPHCW0d/mZgKpxPIhFM0QtiaMiD6vsl8S/w9qaF5uEBrQcxAScVXIygUvNTN11 buAvUgU6v2JMXSDG6r9N+LKOzZ+QepwFowU8phHevnCJDE5xTe2OxqMNgasFkaZ56YtE YNxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id; bh=UkYyv0/6vh3CHIvTfJ94IsvBbhRXrQdlT5+wvMXUDOA=; b=XM8JQwxW5CQoK8iuP1dE6LsqQjMgf+Qpz2Ok72CUhydCQL961eBTinkuPIEuHEPP/l YpmZhrgC3nE4oQ7WlgHPtpGXAD4cMAgbDTNOyqiS7364SiLb7TioDdbhCalp/gYsIe8x YIcP7Hzkf6I5i1yuzBozAEALGu0Za230lKUMmmKZk6cQj3pXP2n7hIRlgmJ6aEKgAOtg 8RcVwt9lepV8gPyztI45uz2a1vMgYahaR3LBIZx4Dj8KGDmleNrdtnbz1DXWwBOfo28L fVAtw7DOeJ0C+gF9CTpkNGR5SqQs9Nm9kdGjUCtqhOAlLApxQZCdYmO8sNwan3i2/QAf jOZA== X-Gm-Message-State: AJaThX6ZG08pjD6geSgEO32xsf/E8J7yZybba+6kN1VMRJNJlqjBm6wV 3mQLcnXM+Qyq9mPOCUkiVuCUIg== X-Google-Smtp-Source: AGs4zMbKas9SR9u/UdYapWm1d6Ud0dfpONGKH87SPchLL3nmihcYoqcdPeQmP2xX/I/oqr9sGfa0/A== X-Received: by 10.36.112.132 with SMTP id f126mr9533049itc.7.1510967205777; Fri, 17 Nov 2017 17:06:45 -0800 (PST) Received: from gwendal.mtv.corp.google.com ([172.22.113.171]) by smtp.gmail.com with ESMTPSA id u14sm2246666iou.1.2017.11.17.17.06.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 17 Nov 2017 17:06:44 -0800 (PST) From: Gwendal Grignou To: ulf.hansson@linaro.org Cc: linux-mmc@vger.kernel.org, Avi.Shchislowski@sandisk.com, cjb@laptop.org, Alex.Lemberg@sandisk.com, thierry.escande@collabora.com Subject: [PATCH] mmc: core: Send SLEEP_NOTIFICATION for eMMC 5.x device Date: Fri, 17 Nov 2017 17:06:34 -0800 Message-Id: <20171118010634.1111-1-gwendal@chromium.org> X-Mailer: git-send-email 2.15.0.448.gf294e3d99a-goog 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 eMMC 5.0 spec introduces a new power off notification, SLEEP_NOTIFICATION, the host may send before issuing the sleep commamd. Some eMMC expect the SLEEP_NOTIFICATION for optimal performance: It is recommended by Sandisk for its iNAND 7232 to empty the iNAND SmartTLC buffer, See "Emptying the iNAND SmartSLC buffer" of datasheet. Hynix eMMC also resume faster when SLEEP_NOTIFICATION is sent before going to sleep. SLEEP_NOTIFICATION PON can theoretically take a long time, iNAND sleep notification timeout is set to 83.88s. But it has to be sent just before CMD5, otherwise newer commands may make it moot. Signed-off-by: Gwendal Grignou --- There were several attempts to add SLEEP_NOTIFICATION, here is another try. For refrence: http://thread.gmane.org/gmane.linux.kernel.mmc/23471 [1/2034] http://www.spinics.net/lists/linux-mmc/msg31344.html [6/2015] https://patchwork.kernel.org/patch/9360633/ [10/2016] drivers/mmc/core/mmc.c | 46 +++++++++++++++++++++++++++++++++++++--------- include/linux/mmc/card.h | 3 ++- include/linux/mmc/mmc.h | 2 ++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 36217ad5e9b1..00ee7dd5ba07 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -633,6 +633,13 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]; card->ext_csd.device_life_time_est_typ_b = ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]; + + if (ext_csd[EXT_CSD_SLEEP_NOTIFICATION_TIME] == 0 || + ext_csd[EXT_CSD_SLEEP_NOTIFICATION_TIME] >= 0x18) + card->ext_csd.sleep_notification_time = 0; + else + card->ext_csd.sleep_notification_time = + max((10 << ext_csd[EXT_CSD_SLEEP_NOTIFICATION_TIME]) / 1000, 1); } /* eMMC v5.1 or later */ @@ -652,6 +659,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.cmdq_depth); } } + out: return err; } @@ -1865,18 +1873,34 @@ static int mmc_can_poweroff_notify(const struct mmc_card *card) (card->ext_csd.power_off_notification == EXT_CSD_POWER_ON); } +static int mmc_can_sleep_notify(const struct mmc_card *card) +{ + return mmc_can_poweroff_notify(card) && + (card->ext_csd.sleep_notification_time > 0); +} + static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) { - unsigned int timeout = card->ext_csd.generic_cmd6_time; + unsigned int timeout; + bool use_busy_signal = true; int err; - /* Use EXT_CSD_POWER_OFF_SHORT as default notification type. */ - if (notify_type == EXT_CSD_POWER_OFF_LONG) + switch (notify_type) { + case EXT_CSD_POWER_OFF_LONG: timeout = card->ext_csd.power_off_longtime; + break; + case EXT_CSD_SLEEP_NOTIFICATION: + timeout = card->ext_csd.sleep_notification_time; + use_busy_signal = false; + break; + default: + /* Use EXT_CSD_POWER_OFF_SHORT as default notification type. */ + timeout = card->ext_csd.generic_cmd6_time; + } err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_OFF_NOTIFICATION, - notify_type, timeout, 0, true, false, false); + notify_type, timeout, 0, use_busy_signal, false, false); if (err) pr_err("%s: Power Off Notification timed out, %u\n", mmc_hostname(card->host), timeout); @@ -1952,13 +1976,17 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) goto out; if (mmc_can_poweroff_notify(host->card) && - ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend)) + ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend)) { err = mmc_poweroff_notify(host->card, notify_type); - else if (mmc_can_sleep(host->card)) - err = mmc_sleep(host); - else if (!mmc_host_is_spi(host)) + } else if (mmc_can_sleep(host->card)) { + if (mmc_can_sleep_notify(host->card)) + err = mmc_poweroff_notify(host->card, + EXT_CSD_SLEEP_NOTIFICATION); + if (!err) + err = mmc_sleep(host); + } else if (!mmc_host_is_spi(host)) { err = mmc_deselect_cards(host); - + } if (!err) { mmc_power_off(host); mmc_card_set_suspended(host->card); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 279b39008a33..5af3661bd98a 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -59,8 +59,9 @@ struct mmc_ext_csd { u8 packed_event_en; unsigned int part_time; /* Units: ms */ unsigned int sa_timeout; /* Units: 100ns */ - unsigned int generic_cmd6_time; /* Units: 10ms */ + unsigned int generic_cmd6_time; /* Units: ms */ unsigned int power_off_longtime; /* Units: ms */ + unsigned int sleep_notification_time; /* Units: ms */ u8 power_off_notification; /* state */ unsigned int hs_max_dtr; unsigned int hs200_max_dtr; diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 3ffc27aaeeaf..901e124dee72 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -277,6 +277,7 @@ static inline bool mmc_op_multi(u32 opcode) #define EXT_CSD_PWR_CL_52_360 202 /* RO */ #define EXT_CSD_PWR_CL_26_360 203 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_SLEEP_NOTIFICATION_TIME 216 /* RO */ #define EXT_CSD_S_A_TIMEOUT 217 /* RO */ #define EXT_CSD_REL_WR_SEC_C 222 /* RO */ #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ @@ -379,6 +380,7 @@ static inline bool mmc_op_multi(u32 opcode) #define EXT_CSD_POWER_ON 1 #define EXT_CSD_POWER_OFF_SHORT 2 #define EXT_CSD_POWER_OFF_LONG 3 +#define EXT_CSD_SLEEP_NOTIFICATION 4 #define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */ #define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */