From mboxrd@z Thu Jan 1 00:00:00 1970 From: Adrian Hunter Subject: [PATCH V2 01/15] mmc: host: Add facility to support re-tuning Date: Thu, 29 Jan 2015 11:00:16 +0200 Message-ID: <1422522030-17793-2-git-send-email-adrian.hunter@intel.com> References: <1422522030-17793-1-git-send-email-adrian.hunter@intel.com> Return-path: Received: from mga09.intel.com ([134.134.136.24]:57059 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753180AbbA2JC1 (ORCPT ); Thu, 29 Jan 2015 04:02:27 -0500 In-Reply-To: <1422522030-17793-1-git-send-email-adrian.hunter@intel.com> Sender: linux-mmc-owner@vger.kernel.org List-Id: linux-mmc@vger.kernel.org To: Ulf Hansson , Chris Ball Cc: linux-mmc , Aaron Lu , Philip Rakity , Girish K S , Al Cooper , Arend van Spriel Currently, there is core support for tuning during initialization. There can also be a need to re-tune periodically (e.g. sdhci) or to re-tune after the host controller is powered off (e.g. after PM runtime suspend / resume) or to re-tune in response to CRC errors. The main requirements for re-tuning are: - ability to enable /disable re-tuning - ability to flag that re-tuning is needed - ability to re-tune before any request - ability to hold off re-tuning if the card is busy - ability to hold off re-tuning if re-tuning is in progress - ability to run a re-tuning timer To support those requirements 5 members are added to struct mmc_host: unsigned int can_retune:1; /* re-tuning can be used */ unsigned int doing_retune:1; /* re-tuning in progress */ int need_retune; /* re-tuning is needed */ int hold_retune; /* hold off re-tuning */ struct timer_list retune_timer; /* for periodic re-tuning */ need_retune is an integer so it can be set without needing synchronization. hold_retune is a integer to allow nesting. Various simple functions are provided to set / clear those variables. Subsequent patches take those functions into use. Signed-off-by: Adrian Hunter --- drivers/mmc/core/host.c | 46 ++++++++++++++++++++++++++++++++++++++ include/linux/mmc/host.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 8be0df7..221d46d 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -301,6 +301,51 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) #endif +void mmc_retune_enable(struct mmc_host *host, unsigned int period) +{ + host->can_retune = 1; + if (period) + mod_timer(&host->retune_timer, jiffies + period * HZ); +} + +void mmc_retune_disable(struct mmc_host *host) +{ + host->can_retune = 0; + del_timer_sync(&host->retune_timer); + host->need_retune = 0; +} + +void mmc_retune_timer_stop(struct mmc_host *host) +{ + del_timer_sync(&host->retune_timer); +} + +int mmc_retune(struct mmc_host *host) +{ + int err; + + if (!host->need_retune || host->doing_retune || host->hold_retune || + !host->card) + return 0; + + host->need_retune = 0; + + host->doing_retune = 1; + + err = mmc_execute_tuning(host->card); + + host->doing_retune = 0; + + return err; +} + +static void mmc_retune_timer(unsigned long data) +{ + struct mmc_host *host = (struct mmc_host *)data; + + mmc_retune_needed(host); +} + /** * mmc_of_parse() - parse host's device-tree node * @host: host whose node should be parsed. @@ -504,6 +549,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) #ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify; #endif + setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host); /* * By default, hosts do not support SGIO or large requests. diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 0c8cbe5..e9a7470 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -327,10 +328,16 @@ struct mmc_host { #ifdef CONFIG_MMC_DEBUG unsigned int removed:1; /* host is being removed */ #endif + unsigned int can_retune:1; /* re-tuning can be used */ + unsigned int doing_retune:1; /* re-tuning in progress */ int rescan_disable; /* disable card detection */ int rescan_entered; /* used with nonremovable devices */ + int need_retune; /* re-tuning is needed */ + int hold_retune; /* hold off re-tuning */ + struct timer_list retune_timer; /* for periodic re-tuning */ + bool trigger_card_event; /* card_event necessary */ struct mmc_card *card; /* device attached to this host */ @@ -519,4 +526,55 @@ static inline bool mmc_card_hs400(struct mmc_card *card) return card->host->ios.timing == MMC_TIMING_MMC_HS400; } +void mmc_retune_enable(struct mmc_host *host, unsigned int period); +void mmc_retune_disable(struct mmc_host *host); +void mmc_retune_timer_stop(struct mmc_host *host); +int mmc_retune(struct mmc_host *host); + +static inline void mmc_retune_needed(struct mmc_host *host) +{ + if (host->can_retune) + host->need_retune = 1; +} + +static inline void mmc_retune_not_needed(struct mmc_host *host) +{ + host->need_retune = 0; +} + +static inline void mmc_retune_hold(struct mmc_host *host) +{ + host->hold_retune += 1; +} + +static inline void mmc_retune_release(struct mmc_host *host) +{ + if (host->hold_retune) + host->hold_retune -= 1; + else + WARN_ON(1); +} + +static inline int mmc_retune_and_hold(struct mmc_host *host) +{ + int err; + + err = mmc_retune(host); + if (!err) + mmc_retune_hold(host); + + return err; +} + +static inline int mmc_retune_recheck(struct mmc_host *host) +{ + int err; + + mmc_retune_release(host); + err = mmc_retune(host); + mmc_retune_hold(host); + + return err; +} + #endif /* LINUX_MMC_HOST_H */ -- 1.9.1