diff options
author | Jaehoon Chung <jh80.chung@samsung.com> | 2012-09-17 04:42:02 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-10-03 10:05:12 -0400 |
commit | 950d56acce5d401f477b91d0177605b543d63d07 (patch) | |
tree | 205505f3976d02c6ef2fa9d6c911407f0e0f6c80 /drivers/mmc/core/mmc_ops.c | |
parent | bec9d4e5939987053169a9bb48fc58b6a2d3e237 (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/core/mmc_ops.c')
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 26 |
1 files changed, 22 insertions, 4 deletions
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 | */ |
406 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, | 407 | int __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 | } |
463 | EXPORT_SYMBOL_GPL(__mmc_switch); | ||
464 | |||
465 | int 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 | } | ||
452 | EXPORT_SYMBOL_GPL(mmc_switch); | 470 | EXPORT_SYMBOL_GPL(mmc_switch); |
453 | 471 | ||
454 | int mmc_send_status(struct mmc_card *card, u32 *status) | 472 | int mmc_send_status(struct mmc_card *card, u32 *status) |