aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorJaehoon Chung <jh80.chung@samsung.com>2012-09-17 04:42:02 -0400
committerChris Ball <cjb@laptop.org>2012-10-03 10:05:12 -0400
commit950d56acce5d401f477b91d0177605b543d63d07 (patch)
tree205505f3976d02c6ef2fa9d6c911407f0e0f6c80 /drivers/mmc
parentbec9d4e5939987053169a9bb48fc58b6a2d3e237 (diff)
mmc: support BKOPS feature for eMMC
Enable eMMC background operations (BKOPS) feature. If URGENT_BKOPS is set after a response, note that BKOPS are required. Immediately run BKOPS if required. Read/write operations should be requested during BKOPS(LEVEL-1), then issue HPI to interrupt the ongoing BKOPS and service the foreground operation. (This patch only controls the LEVEL2/3.) When repeating the writing 1GB data, at a certain time, performance is decreased. At that time, card triggers the Level-3 or Level-2. After running bkops, performance is recovered. Future considerations: * Check BKOPS_LEVEL=1 and start BKOPS in a preventive manner. * Interrupt ongoing BKOPS before powering off the card. * How do we get BKOPS_STATUS value (periodically send ext_csd command)? * If using periodic bkops, also consider runtime_pm control. Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Konstantin Dorfman <kdorfman@codeaurora.org> Reviewed-by: Maya Erez <merez@codeaurora.org> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c160
-rw-r--r--drivers/mmc/core/mmc.c11
-rw-r--r--drivers/mmc/core/mmc_ops.c26
3 files changed, 189 insertions, 8 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index af2c4d2fd69e..044cd016320e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -26,6 +26,7 @@
26#include <linux/suspend.h> 26#include <linux/suspend.h>
27#include <linux/fault-inject.h> 27#include <linux/fault-inject.h>
28#include <linux/random.h> 28#include <linux/random.h>
29#include <linux/slab.h>
29 30
30#include <linux/mmc/card.h> 31#include <linux/mmc/card.h>
31#include <linux/mmc/host.h> 32#include <linux/mmc/host.h>
@@ -41,6 +42,12 @@
41#include "sd_ops.h" 42#include "sd_ops.h"
42#include "sdio_ops.h" 43#include "sdio_ops.h"
43 44
45/*
46 * Background operations can take a long time, depending on the housekeeping
47 * operations the card has to perform.
48 */
49#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
50
44static struct workqueue_struct *workqueue; 51static struct workqueue_struct *workqueue;
45static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; 52static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
46 53
@@ -245,6 +252,70 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
245 host->ops->request(host, mrq); 252 host->ops->request(host, mrq);
246} 253}
247 254
255/**
256 * mmc_start_bkops - start BKOPS for supported cards
257 * @card: MMC card to start BKOPS
258 * @form_exception: A flag to indicate if this function was
259 * called due to an exception raised by the card
260 *
261 * Start background operations whenever requested.
262 * When the urgent BKOPS bit is set in a R1 command response
263 * then background operations should be started immediately.
264*/
265void mmc_start_bkops(struct mmc_card *card, bool from_exception)
266{
267 int err;
268 int timeout;
269 bool use_busy_signal;
270
271 BUG_ON(!card);
272
273 if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
274 return;
275
276 err = mmc_read_bkops_status(card);
277 if (err) {
278 pr_err("%s: Failed to read bkops status: %d\n",
279 mmc_hostname(card->host), err);
280 return;
281 }
282
283 if (!card->ext_csd.raw_bkops_status)
284 return;
285
286 if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
287 from_exception)
288 return;
289
290 mmc_claim_host(card->host);
291 if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
292 timeout = MMC_BKOPS_MAX_TIMEOUT;
293 use_busy_signal = true;
294 } else {
295 timeout = 0;
296 use_busy_signal = false;
297 }
298
299 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
300 EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
301 if (err) {
302 pr_warn("%s: Error %d starting bkops\n",
303 mmc_hostname(card->host), err);
304 goto out;
305 }
306
307 /*
308 * For urgent bkops status (LEVEL_2 and more)
309 * bkops executed synchronously, otherwise
310 * the operation is in progress
311 */
312 if (!use_busy_signal)
313 mmc_card_set_doing_bkops(card);
314out:
315 mmc_release_host(card->host);
316}
317EXPORT_SYMBOL(mmc_start_bkops);
318
248static void mmc_wait_done(struct mmc_request *mrq) 319static void mmc_wait_done(struct mmc_request *mrq)
249{ 320{
250 complete(&mrq->completion); 321 complete(&mrq->completion);
@@ -354,6 +425,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
354 if (host->areq) { 425 if (host->areq) {
355 mmc_wait_for_req_done(host, host->areq->mrq); 426 mmc_wait_for_req_done(host, host->areq->mrq);
356 err = host->areq->err_check(host->card, host->areq); 427 err = host->areq->err_check(host->card, host->areq);
428 /*
429 * Check BKOPS urgency for each R1 response
430 */
431 if (host->card && mmc_card_mmc(host->card) &&
432 ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
433 (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
434 (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
435 mmc_start_bkops(host->card, true);
357 } 436 }
358 437
359 if (!err && areq) 438 if (!err && areq)
@@ -398,7 +477,7 @@ EXPORT_SYMBOL(mmc_wait_for_req);
398 * @card: the MMC card associated with the HPI transfer 477 * @card: the MMC card associated with the HPI transfer
399 * 478 *
400 * Issued High Priority Interrupt, and check for card status 479 * Issued High Priority Interrupt, and check for card status
401 * util out-of prg-state. 480 * until out-of prg-state.
402 */ 481 */
403int mmc_interrupt_hpi(struct mmc_card *card) 482int mmc_interrupt_hpi(struct mmc_card *card)
404{ 483{
@@ -490,6 +569,64 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
490EXPORT_SYMBOL(mmc_wait_for_cmd); 569EXPORT_SYMBOL(mmc_wait_for_cmd);
491 570
492/** 571/**
572 * mmc_stop_bkops - stop ongoing BKOPS
573 * @card: MMC card to check BKOPS
574 *
575 * Send HPI command to stop ongoing background operations to
576 * allow rapid servicing of foreground operations, e.g. read/
577 * writes. Wait until the card comes out of the programming state
578 * to avoid errors in servicing read/write requests.
579 */
580int mmc_stop_bkops(struct mmc_card *card)
581{
582 int err = 0;
583
584 BUG_ON(!card);
585 err = mmc_interrupt_hpi(card);
586
587 /*
588 * If err is EINVAL, we can't issue an HPI.
589 * It should complete the BKOPS.
590 */
591 if (!err || (err == -EINVAL)) {
592 mmc_card_clr_doing_bkops(card);
593 err = 0;
594 }
595
596 return err;
597}
598EXPORT_SYMBOL(mmc_stop_bkops);
599
600int mmc_read_bkops_status(struct mmc_card *card)
601{
602 int err;
603 u8 *ext_csd;
604
605 /*
606 * In future work, we should consider storing the entire ext_csd.
607 */
608 ext_csd = kmalloc(512, GFP_KERNEL);
609 if (!ext_csd) {
610 pr_err("%s: could not allocate buffer to receive the ext_csd.\n",
611 mmc_hostname(card->host));
612 return -ENOMEM;
613 }
614
615 mmc_claim_host(card->host);
616 err = mmc_send_ext_csd(card, ext_csd);
617 mmc_release_host(card->host);
618 if (err)
619 goto out;
620
621 card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
622 card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
623out:
624 kfree(ext_csd);
625 return err;
626}
627EXPORT_SYMBOL(mmc_read_bkops_status);
628
629/**
493 * mmc_set_data_timeout - set the timeout for a data command 630 * mmc_set_data_timeout - set the timeout for a data command
494 * @data: data phase for command 631 * @data: data phase for command
495 * @card: the MMC card associated with the data transfer 632 * @card: the MMC card associated with the data transfer
@@ -2333,9 +2470,14 @@ int mmc_suspend_host(struct mmc_host *host)
2333 2470
2334 mmc_bus_get(host); 2471 mmc_bus_get(host);
2335 if (host->bus_ops && !host->bus_dead) { 2472 if (host->bus_ops && !host->bus_dead) {
2336 2473 if (host->bus_ops->suspend) {
2337 if (host->bus_ops->suspend) 2474 if (mmc_card_doing_bkops(host->card)) {
2475 err = mmc_stop_bkops(host->card);
2476 if (err)
2477 goto out;
2478 }
2338 err = host->bus_ops->suspend(host); 2479 err = host->bus_ops->suspend(host);
2480 }
2339 2481
2340 if (err == -ENOSYS || !host->bus_ops->resume) { 2482 if (err == -ENOSYS || !host->bus_ops->resume) {
2341 /* 2483 /*
@@ -2417,11 +2559,21 @@ int mmc_pm_notify(struct notifier_block *notify_block,
2417 struct mmc_host *host = container_of( 2559 struct mmc_host *host = container_of(
2418 notify_block, struct mmc_host, pm_notify); 2560 notify_block, struct mmc_host, pm_notify);
2419 unsigned long flags; 2561 unsigned long flags;
2420 2562 int err = 0;
2421 2563
2422 switch (mode) { 2564 switch (mode) {
2423 case PM_HIBERNATION_PREPARE: 2565 case PM_HIBERNATION_PREPARE:
2424 case PM_SUSPEND_PREPARE: 2566 case PM_SUSPEND_PREPARE:
2567 if (host->card && mmc_card_mmc(host->card) &&
2568 mmc_card_doing_bkops(host->card)) {
2569 err = mmc_stop_bkops(host->card);
2570 if (err) {
2571 pr_err("%s: didn't stop bkops\n",
2572 mmc_hostname(host));
2573 return err;
2574 }
2575 mmc_card_clr_doing_bkops(host->card);
2576 }
2425 2577
2426 spin_lock_irqsave(&host->lock, flags); 2578 spin_lock_irqsave(&host->lock, flags);
2427 host->rescan_disable = 1; 2579 host->rescan_disable = 1;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 396b25891bb9..7509de14aa78 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -463,6 +463,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
463 } 463 }
464 464
465 if (card->ext_csd.rev >= 5) { 465 if (card->ext_csd.rev >= 5) {
466 /* check whether the eMMC card supports BKOPS */
467 if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
468 card->ext_csd.bkops = 1;
469 card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
470 card->ext_csd.raw_bkops_status =
471 ext_csd[EXT_CSD_BKOPS_STATUS];
472 if (!card->ext_csd.bkops_en)
473 pr_info("%s: BKOPS_EN bit is not set\n",
474 mmc_hostname(card->host));
475 }
476
466 /* check whether the eMMC card supports HPI */ 477 /* check whether the eMMC card supports HPI */
467 if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { 478 if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
468 card->ext_csd.hpi = 1; 479 card->ext_csd.hpi = 1;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 225371a28861..a0e172042e65 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -393,18 +393,19 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
393} 393}
394 394
395/** 395/**
396 * mmc_switch - modify EXT_CSD register 396 * __mmc_switch - modify EXT_CSD register
397 * @card: the MMC card associated with the data transfer 397 * @card: the MMC card associated with the data transfer
398 * @set: cmd set values 398 * @set: cmd set values
399 * @index: EXT_CSD register index 399 * @index: EXT_CSD register index
400 * @value: value to program into EXT_CSD register 400 * @value: value to program into EXT_CSD register
401 * @timeout_ms: timeout (ms) for operation performed by register write, 401 * @timeout_ms: timeout (ms) for operation performed by register write,
402 * timeout of zero implies maximum possible timeout 402 * timeout of zero implies maximum possible timeout
403 * @use_busy_signal: use the busy signal as response type
403 * 404 *
404 * Modifies the EXT_CSD register for selected card. 405 * Modifies the EXT_CSD register for selected card.
405 */ 406 */
406int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, 407int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
407 unsigned int timeout_ms) 408 unsigned int timeout_ms, bool use_busy_signal)
408{ 409{
409 int err; 410 int err;
410 struct mmc_command cmd = {0}; 411 struct mmc_command cmd = {0};
@@ -418,13 +419,23 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
418 (index << 16) | 419 (index << 16) |
419 (value << 8) | 420 (value << 8) |
420 set; 421 set;
421 cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; 422 cmd.flags = MMC_CMD_AC;
423 if (use_busy_signal)
424 cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
425 else
426 cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
427
428
422 cmd.cmd_timeout_ms = timeout_ms; 429 cmd.cmd_timeout_ms = timeout_ms;
423 430
424 err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); 431 err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
425 if (err) 432 if (err)
426 return err; 433 return err;
427 434
435 /* No need to check card status in case of unblocking command */
436 if (!use_busy_signal)
437 return 0;
438
428 /* Must check status to be sure of no errors */ 439 /* Must check status to be sure of no errors */
429 do { 440 do {
430 err = mmc_send_status(card, &status); 441 err = mmc_send_status(card, &status);
@@ -449,6 +460,13 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
449 460
450 return 0; 461 return 0;
451} 462}
463EXPORT_SYMBOL_GPL(__mmc_switch);
464
465int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
466 unsigned int timeout_ms)
467{
468 return __mmc_switch(card, set, index, value, timeout_ms, true);
469}
452EXPORT_SYMBOL_GPL(mmc_switch); 470EXPORT_SYMBOL_GPL(mmc_switch);
453 471
454int mmc_send_status(struct mmc_card *card, u32 *status) 472int mmc_send_status(struct mmc_card *card, u32 *status)