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 | |
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>
-rw-r--r-- | drivers/mmc/core/core.c | 160 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 11 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 26 | ||||
-rw-r--r-- | include/linux/mmc/card.h | 8 | ||||
-rw-r--r-- | include/linux/mmc/core.h | 4 | ||||
-rw-r--r-- | include/linux/mmc/mmc.h | 19 |
6 files changed, 220 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 | |||
44 | static struct workqueue_struct *workqueue; | 51 | static struct workqueue_struct *workqueue; |
45 | static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; | 52 | static 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 | */ | ||
265 | void 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); | ||
314 | out: | ||
315 | mmc_release_host(card->host); | ||
316 | } | ||
317 | EXPORT_SYMBOL(mmc_start_bkops); | ||
318 | |||
248 | static void mmc_wait_done(struct mmc_request *mrq) | 319 | static 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 | */ |
403 | int mmc_interrupt_hpi(struct mmc_card *card) | 482 | int 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 | |||
490 | EXPORT_SYMBOL(mmc_wait_for_cmd); | 569 | EXPORT_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 | */ | ||
580 | int 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 | } | ||
598 | EXPORT_SYMBOL(mmc_stop_bkops); | ||
599 | |||
600 | int 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]; | ||
623 | out: | ||
624 | kfree(ext_csd); | ||
625 | return err; | ||
626 | } | ||
627 | EXPORT_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 | */ |
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) |
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 4b27f9f503e4..78cc3be85391 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
@@ -76,10 +76,13 @@ struct mmc_ext_csd { | |||
76 | bool hpi_en; /* HPI enablebit */ | 76 | bool hpi_en; /* HPI enablebit */ |
77 | bool hpi; /* HPI support bit */ | 77 | bool hpi; /* HPI support bit */ |
78 | unsigned int hpi_cmd; /* cmd used as HPI */ | 78 | unsigned int hpi_cmd; /* cmd used as HPI */ |
79 | bool bkops; /* background support bit */ | ||
80 | bool bkops_en; /* background enable bit */ | ||
79 | unsigned int data_sector_size; /* 512 bytes or 4KB */ | 81 | unsigned int data_sector_size; /* 512 bytes or 4KB */ |
80 | unsigned int data_tag_unit_size; /* DATA TAG UNIT size */ | 82 | unsigned int data_tag_unit_size; /* DATA TAG UNIT size */ |
81 | unsigned int boot_ro_lock; /* ro lock support */ | 83 | unsigned int boot_ro_lock; /* ro lock support */ |
82 | bool boot_ro_lockable; | 84 | bool boot_ro_lockable; |
85 | u8 raw_exception_status; /* 53 */ | ||
83 | u8 raw_partition_support; /* 160 */ | 86 | u8 raw_partition_support; /* 160 */ |
84 | u8 raw_erased_mem_count; /* 181 */ | 87 | u8 raw_erased_mem_count; /* 181 */ |
85 | u8 raw_ext_csd_structure; /* 194 */ | 88 | u8 raw_ext_csd_structure; /* 194 */ |
@@ -93,6 +96,7 @@ struct mmc_ext_csd { | |||
93 | u8 raw_sec_erase_mult; /* 230 */ | 96 | u8 raw_sec_erase_mult; /* 230 */ |
94 | u8 raw_sec_feature_support;/* 231 */ | 97 | u8 raw_sec_feature_support;/* 231 */ |
95 | u8 raw_trim_mult; /* 232 */ | 98 | u8 raw_trim_mult; /* 232 */ |
99 | u8 raw_bkops_status; /* 246 */ | ||
96 | u8 raw_sectors[4]; /* 212 - 4 bytes */ | 100 | u8 raw_sectors[4]; /* 212 - 4 bytes */ |
97 | 101 | ||
98 | unsigned int feature_support; | 102 | unsigned int feature_support; |
@@ -226,6 +230,7 @@ struct mmc_card { | |||
226 | #define MMC_CARD_REMOVED (1<<7) /* card has been removed */ | 230 | #define MMC_CARD_REMOVED (1<<7) /* card has been removed */ |
227 | #define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ | 231 | #define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ |
228 | #define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */ | 232 | #define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */ |
233 | #define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */ | ||
229 | unsigned int quirks; /* card quirks */ | 234 | unsigned int quirks; /* card quirks */ |
230 | #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ | 235 | #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ |
231 | #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ | 236 | #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ |
@@ -393,6 +398,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) | |||
393 | #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) | 398 | #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) |
394 | #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) | 399 | #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) |
395 | #define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP) | 400 | #define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP) |
401 | #define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS) | ||
396 | 402 | ||
397 | #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) | 403 | #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) |
398 | #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) | 404 | #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) |
@@ -405,7 +411,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) | |||
405 | #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) | 411 | #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) |
406 | #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) | 412 | #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) |
407 | #define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP) | 413 | #define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP) |
414 | #define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS) | ||
408 | 415 | ||
416 | #define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) | ||
409 | #define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP) | 417 | #define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP) |
410 | /* | 418 | /* |
411 | * Quirk add/remove for MMC products. | 419 | * Quirk add/remove for MMC products. |
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 1b431c728b9a..9b9cdafc7737 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h | |||
@@ -134,6 +134,8 @@ struct mmc_host; | |||
134 | struct mmc_card; | 134 | struct mmc_card; |
135 | struct mmc_async_req; | 135 | struct mmc_async_req; |
136 | 136 | ||
137 | extern int mmc_stop_bkops(struct mmc_card *); | ||
138 | extern int mmc_read_bkops_status(struct mmc_card *); | ||
137 | extern struct mmc_async_req *mmc_start_req(struct mmc_host *, | 139 | extern struct mmc_async_req *mmc_start_req(struct mmc_host *, |
138 | struct mmc_async_req *, int *); | 140 | struct mmc_async_req *, int *); |
139 | extern int mmc_interrupt_hpi(struct mmc_card *); | 141 | extern int mmc_interrupt_hpi(struct mmc_card *); |
@@ -142,6 +144,8 @@ extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); | |||
142 | extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *); | 144 | extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *); |
143 | extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, | 145 | extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, |
144 | struct mmc_command *, int); | 146 | struct mmc_command *, int); |
147 | extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); | ||
148 | extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool); | ||
145 | extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); | 149 | extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); |
146 | 150 | ||
147 | #define MMC_ERASE_ARG 0x00000000 | 151 | #define MMC_ERASE_ARG 0x00000000 |
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index d425cab144d9..01e4b394029b 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h | |||
@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode) | |||
139 | #define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ | 139 | #define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ |
140 | #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ | 140 | #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ |
141 | #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ | 141 | #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ |
142 | #define R1_EXCEPTION_EVENT (1 << 6) /* sx, a */ | ||
142 | #define R1_APP_CMD (1 << 5) /* sr, c */ | 143 | #define R1_APP_CMD (1 << 5) /* sr, c */ |
143 | 144 | ||
144 | #define R1_STATE_IDLE 0 | 145 | #define R1_STATE_IDLE 0 |
@@ -274,12 +275,15 @@ struct _mmc_csd { | |||
274 | #define EXT_CSD_FLUSH_CACHE 32 /* W */ | 275 | #define EXT_CSD_FLUSH_CACHE 32 /* W */ |
275 | #define EXT_CSD_CACHE_CTRL 33 /* R/W */ | 276 | #define EXT_CSD_CACHE_CTRL 33 /* R/W */ |
276 | #define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ | 277 | #define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ |
278 | #define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO */ | ||
277 | #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ | 279 | #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ |
278 | #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ | 280 | #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ |
279 | #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ | 281 | #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ |
280 | #define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ | 282 | #define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ |
281 | #define EXT_CSD_HPI_MGMT 161 /* R/W */ | 283 | #define EXT_CSD_HPI_MGMT 161 /* R/W */ |
282 | #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ | 284 | #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ |
285 | #define EXT_CSD_BKOPS_EN 163 /* R/W */ | ||
286 | #define EXT_CSD_BKOPS_START 164 /* W */ | ||
283 | #define EXT_CSD_SANITIZE_START 165 /* W */ | 287 | #define EXT_CSD_SANITIZE_START 165 /* W */ |
284 | #define EXT_CSD_WR_REL_PARAM 166 /* RO */ | 288 | #define EXT_CSD_WR_REL_PARAM 166 /* RO */ |
285 | #define EXT_CSD_BOOT_WP 173 /* R/W */ | 289 | #define EXT_CSD_BOOT_WP 173 /* R/W */ |
@@ -313,11 +317,13 @@ struct _mmc_csd { | |||
313 | #define EXT_CSD_PWR_CL_200_360 237 /* RO */ | 317 | #define EXT_CSD_PWR_CL_200_360 237 /* RO */ |
314 | #define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ | 318 | #define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ |
315 | #define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ | 319 | #define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ |
320 | #define EXT_CSD_BKOPS_STATUS 246 /* RO */ | ||
316 | #define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ | 321 | #define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ |
317 | #define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ | 322 | #define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ |
318 | #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ | 323 | #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ |
319 | #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ | 324 | #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ |
320 | #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ | 325 | #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ |
326 | #define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ | ||
321 | #define EXT_CSD_HPI_FEATURES 503 /* RO */ | 327 | #define EXT_CSD_HPI_FEATURES 503 /* RO */ |
322 | 328 | ||
323 | /* | 329 | /* |
@@ -378,6 +384,19 @@ struct _mmc_csd { | |||
378 | #define EXT_CSD_PWR_CL_8BIT_SHIFT 4 | 384 | #define EXT_CSD_PWR_CL_8BIT_SHIFT 4 |
379 | #define EXT_CSD_PWR_CL_4BIT_SHIFT 0 | 385 | #define EXT_CSD_PWR_CL_4BIT_SHIFT 0 |
380 | /* | 386 | /* |
387 | * EXCEPTION_EVENT_STATUS field | ||
388 | */ | ||
389 | #define EXT_CSD_URGENT_BKOPS BIT(0) | ||
390 | #define EXT_CSD_DYNCAP_NEEDED BIT(1) | ||
391 | #define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) | ||
392 | #define EXT_CSD_PACKED_FAILURE BIT(3) | ||
393 | |||
394 | /* | ||
395 | * BKOPS status level | ||
396 | */ | ||
397 | #define EXT_CSD_BKOPS_LEVEL_2 0x2 | ||
398 | |||
399 | /* | ||
381 | * MMC_SWITCH access modes | 400 | * MMC_SWITCH access modes |
382 | */ | 401 | */ |
383 | 402 | ||