]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/commitdiff
mmc: add timer to issue flush request periodically
authorR Raj Kumar <rrajk@nvidia.com>
Thu, 7 Jan 2016 15:17:54 +0000 (20:47 +0530)
committerR Raj Kumar <rrajk@nvidia.com>
Mon, 27 Jun 2016 06:21:45 +0000 (23:21 -0700)
-Added timer for issuing flush requests periodically
to reduce the cache flush overhead during read/write
data transfers on eMMC device.
-Flush timer will be deleted and resumed back during
device suspend/resume calls.

Bug 200165213

Change-Id: Iac6199922bc82cbc9394f0a6b3c6067283ed5240
Reviewed-on: http://git-master/r/930061

Signed-off-by: R Raj Kumar <rrajk@nvidia.com>
Change-Id: I42ccba5b7ebaa9495817406bbd66312a9a4fea9c
Reviewed-on: http://git-master/r/1171079
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>
drivers/mmc/card/block.c
drivers/mmc/core/mmc.c
include/linux/mmc/host.h

index be0db82f9778fcc782f6d60833365d49a09c4f14..eca63113f2f7797c236966bb44b117316e951c75 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright 2002 Hewlett-Packard Company
  * Copyright 2005-2008 Pierre Ossman
+ * Copyright (c) 2014-2016, NVIDIA CORPORATION.  All rights reserved.
  *
  * Use consistent with the GNU GPL is permitted,
  * provided that this copyright notice is
@@ -1575,8 +1576,15 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
        struct mmc_blk_data *md = mq->data;
        struct mmc_card *card = md->queue.card;
+       struct mmc_host *host = card->host;
        int ret = 0;
 
+       if (host->en_periodic_cflush && host->flush_timeout &&
+                       !host->cache_flush_needed) {
+               blk_end_request(req, 0, 0);
+               return 0;
+       }
+
        ret = mmc_flush_cache(card);
        if (ret)
                ret = -EIO;
@@ -1600,6 +1608,11 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 #endif
        blk_end_request_all(req, ret);
 
+       if (host->en_periodic_cflush && host->flush_timeout && !ret) {
+               host->cache_flush_needed = false;
+               mod_timer(&host->flush_timer, jiffies +
+                       msecs_to_jiffies(host->flush_timeout));
+       }
        return ret ? 0 : 1;
 }
 
@@ -2429,6 +2442,13 @@ int mmc_blk_cmdq_issue_flush_rq(struct mmc_queue *mq, struct request *req)
        BUG_ON(!card);
        host = card->host;
        BUG_ON(!host);
+
+       if (host->en_periodic_cflush && host->flush_timeout &&
+                       !host->cache_flush_needed) {
+               blk_end_request(req, 0, 0);
+               return 0;
+       }
+
        BUG_ON((req->tag < 0) || (req->tag > card->ext_csd.cmdq_depth));
        BUG_ON(test_and_set_bit(req->tag, &host->cmdq_ctx.active_reqs));
 
@@ -2453,6 +2473,11 @@ int mmc_blk_cmdq_issue_flush_rq(struct mmc_queue *mq, struct request *req)
                return err;
 
        err = mmc_blk_cmdq_start_req(card->host, cmdq_req);
+       if (host->en_periodic_cflush && host->flush_timeout && !err) {
+               host->cache_flush_needed = false;
+               mod_timer(&host->flush_timer, jiffies +
+                       msecs_to_jiffies(host->flush_timeout));
+       }
        return err;
 }
 EXPORT_SYMBOL(mmc_blk_cmdq_issue_flush_rq);
@@ -2935,6 +2960,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
             card->ext_csd.rel_sectors)) {
                md->flags |= MMC_BLK_REL_WR;
                blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
+               card->host->cache_flush_needed = true;
        }
 
        if (card->cmdq_init) {
index daa8ffc2413b476abcdf8816f780532b5613d3c6..37e986a2c948b78aad2202983dde52c02a88859f 100644 (file)
@@ -1392,6 +1392,13 @@ static int mmc_hs200_tuning(struct mmc_card *card)
        return mmc_execute_tuning(card);
 }
 
+static void cache_flush_handler(unsigned long data)
+{
+       struct mmc_host *host = (struct mmc_host *)data;
+
+       host->cache_flush_needed = true;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -1710,6 +1717,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
+       if (!oldcard && card->ext_csd.cache_ctrl &&
+                       (host->caps2 & MMC_CAP2_PERIODIC_CACHE_FLUSH)) {
+               host->cache_flush_needed = true;
+               host->en_periodic_cflush = true;
+               setup_timer(&host->flush_timer, cache_flush_handler,
+                               (unsigned long)host);
+               pr_info("%s: periodic cache flush enabled\n",
+                               mmc_hostname(host));
+       }
        return 0;
 
 free_card:
@@ -1881,6 +1897,9 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
        if (err)
                goto out;
 
+       if (host->card->ext_csd.cache_ctrl && host->en_periodic_cflush)
+               del_timer(&host->flush_timer);
+
        if (mmc_can_poweroff_notify(host->card) &&
                ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
                err = mmc_poweroff_notify(host->card, notify_type);
@@ -1947,6 +1966,9 @@ static int _mmc_resume(struct mmc_host *host)
                mmc_card_clr_suspended(host->card);
        }
 
+       if (host->card->ext_csd.cache_ctrl && host->en_periodic_cflush)
+               mod_timer(&host->flush_timer, host->flush_timeout);
+
 out:
        mmc_release_host(host);
        return err;
index 15f58cdf93f8f6dfdb737e45961e8e677bcbb724..12467d6af38695defa852b6094b6071c9bf49b6e 100644 (file)
@@ -362,6 +362,7 @@ struct mmc_host {
 #define MMC_CAP2_NO_SLEEP_CMD  (1 << 20)       /* cannot support sleep mode */
 #define MMC_CAP2_HW_CQ         (1 << 23)       /* support eMMC command queue */
 #define MMC_CAP2_CMDQ_QBR      (1 << 24)       /* CMDQ Queue barrier supported */
+#define MMC_CAP2_PERIODIC_CACHE_FLUSH  (1 << 26)
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -461,7 +462,10 @@ struct mmc_host {
                int                             num_funcs;
        } embedded_sdio_data;
 #endif
-
+       bool                    cache_flush_needed;
+       bool                    en_periodic_cflush;
+       unsigned int            flush_timeout;
+       struct timer_list       flush_timer;
        unsigned long           private[0] ____cacheline_aligned;
 };