Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: host: Add facility to support re-tuning

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 7 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 */
unsigned int retune_now:1; /* do re-tuning at next req */
int need_retune; /* re-tuning is needed */
int hold_retune; /* hold off re-tuning */
unsigned int retune_period; /* re-tuning period in secs */
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 <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Adrian Hunter and committed by
Ulf Hansson
dfa13ebb 59d22309

+97
+68
drivers/mmc/core/host.c
··· 301 301 302 302 #endif 303 303 304 + void mmc_retune_enable(struct mmc_host *host) 305 + { 306 + host->can_retune = 1; 307 + if (host->retune_period) 308 + mod_timer(&host->retune_timer, 309 + jiffies + host->retune_period * HZ); 310 + } 311 + 312 + void mmc_retune_disable(struct mmc_host *host) 313 + { 314 + host->can_retune = 0; 315 + del_timer_sync(&host->retune_timer); 316 + host->retune_now = 0; 317 + host->need_retune = 0; 318 + } 319 + 320 + void mmc_retune_timer_stop(struct mmc_host *host) 321 + { 322 + del_timer_sync(&host->retune_timer); 323 + } 324 + EXPORT_SYMBOL(mmc_retune_timer_stop); 325 + 326 + void mmc_retune_hold(struct mmc_host *host) 327 + { 328 + if (!host->hold_retune) 329 + host->retune_now = 1; 330 + host->hold_retune += 1; 331 + } 332 + 333 + void mmc_retune_release(struct mmc_host *host) 334 + { 335 + if (host->hold_retune) 336 + host->hold_retune -= 1; 337 + else 338 + WARN_ON(1); 339 + } 340 + 341 + int mmc_retune(struct mmc_host *host) 342 + { 343 + int err; 344 + 345 + if (host->retune_now) 346 + host->retune_now = 0; 347 + else 348 + return 0; 349 + 350 + if (!host->need_retune || host->doing_retune || !host->card) 351 + return 0; 352 + 353 + host->need_retune = 0; 354 + 355 + host->doing_retune = 1; 356 + 357 + err = mmc_execute_tuning(host->card); 358 + 359 + host->doing_retune = 0; 360 + 361 + return err; 362 + } 363 + 364 + static void mmc_retune_timer(unsigned long data) 365 + { 366 + struct mmc_host *host = (struct mmc_host *)data; 367 + 368 + mmc_retune_needed(host); 369 + } 370 + 304 371 /** 305 372 * mmc_of_parse() - parse host's device-tree node 306 373 * @host: host whose node should be parsed. ··· 571 504 #ifdef CONFIG_PM 572 505 host->pm_notify.notifier_call = mmc_pm_notify; 573 506 #endif 507 + setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host); 574 508 575 509 /* 576 510 * By default, hosts do not support SGIO or large requests.
+6
drivers/mmc/core/host.h
··· 15 15 int mmc_register_host_class(void); 16 16 void mmc_unregister_host_class(void); 17 17 18 + void mmc_retune_enable(struct mmc_host *host); 19 + void mmc_retune_disable(struct mmc_host *host); 20 + void mmc_retune_hold(struct mmc_host *host); 21 + void mmc_retune_release(struct mmc_host *host); 22 + int mmc_retune(struct mmc_host *host); 23 + 18 24 #endif 19 25
+23
include/linux/mmc/host.h
··· 12 12 13 13 #include <linux/leds.h> 14 14 #include <linux/mutex.h> 15 + #include <linux/timer.h> 15 16 #include <linux/sched.h> 16 17 #include <linux/device.h> 17 18 #include <linux/fault-inject.h> ··· 322 321 #ifdef CONFIG_MMC_DEBUG 323 322 unsigned int removed:1; /* host is being removed */ 324 323 #endif 324 + unsigned int can_retune:1; /* re-tuning can be used */ 325 + unsigned int doing_retune:1; /* re-tuning in progress */ 326 + unsigned int retune_now:1; /* do re-tuning at next req */ 325 327 326 328 int rescan_disable; /* disable card detection */ 327 329 int rescan_entered; /* used with nonremovable devices */ 330 + 331 + int need_retune; /* re-tuning is needed */ 332 + int hold_retune; /* hold off re-tuning */ 333 + unsigned int retune_period; /* re-tuning period in secs */ 334 + struct timer_list retune_timer; /* for periodic re-tuning */ 328 335 329 336 bool trigger_card_event; /* card_event necessary */ 330 337 ··· 520 511 static inline bool mmc_card_hs400(struct mmc_card *card) 521 512 { 522 513 return card->host->ios.timing == MMC_TIMING_MMC_HS400; 514 + } 515 + 516 + void mmc_retune_timer_stop(struct mmc_host *host); 517 + 518 + static inline void mmc_retune_needed(struct mmc_host *host) 519 + { 520 + if (host->can_retune) 521 + host->need_retune = 1; 522 + } 523 + 524 + static inline void mmc_retune_recheck(struct mmc_host *host) 525 + { 526 + if (host->hold_retune <= 1) 527 + host->retune_now = 1; 523 528 } 524 529 525 530 #endif /* LINUX_MMC_HOST_H */