mmc: support BKOPS feature for eMMC
PATCH v8 1/1 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. After all I/O requests are finished, run BKOPS if required. Should read/write operations be requested during BKOPS, first issue HPI to interrupt the ongoing BKOPS and then service the request.
If BKOPS-STATUS is upper than LEVEL2, need to check until clear the BKOPS-STATUS vaule.
If you want to enable this feature, set MMC_CAP2_BKOPS. And if you want to set the BKOPS_EN bit in ext_csd register, use the MMC_CAP2_INIT_BKOPS.
When BKOPS_STATUS is Level-3, if we're waiting for done, it spent 60~80sec. So Added timeout value. if timeout value is set to 0, send hpi command.
---
Changelog V8:
- Remove host->lock spin lock reviewed by Adrian
- Support periodic start bkops
- when bkops_status is level-3, if timeout is set to 0, send hpi.
- Move the start-bkops point
Changelog V7:
- Use HPI command when issued URGENT_BKOPS
- Recheck until clearing the bkops-status bit.
Changelog V6:
- Add the flag of check-bkops-status.
(For fixing async_req problem)
- Add the capability for MMC_CAP2_INIT_BKOPS.
(When unset the bkops_en bit in ext_csd register)
- modify the wrong condition.
Changelog V5:
- Rebase based on the latest mmc-next.
- modify codes based-on Chris's comment
Changelog V4:
- Add mmc_read_bkops_status
- When URGENT_BKOPS(level2-3), didn't use HPI command.
- In mmc_switch(), use R1B/R1 according to level.
Changelog V3:
- move the bkops setting's location in mmc_blk_issue_rw_rq
- modify condition checking
- bkops_en is assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"
- remove the unused code
- change pr_debug instead of pr_warn in mmc_send_hpi_cmd
- Add the Future consideration suggested by Per
Changelog V2:
- Use EXCEPTION_STATUS instead of URGENT_BKOPS
- Add function to check Exception_status(for eMMC4.5)
--- drivers/mmc/card/queue.c | 2 + drivers/mmc/core/core.c | 170 +++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/core/host.c | 1 + drivers/mmc/core/mmc.c | 18 +++++ drivers/mmc/core/mmc_ops.c | 4 + include/linux/mmc/card.h | 16 ++++ include/linux/mmc/core.h | 5 ++ include/linux/mmc/host.h | 4 + include/linux/mmc/mmc.h | 20 +++++ 9 files changed, 238 insertions(+), 2 deletions(-)
drivers/mmc/card/queue.c +2 -0
@@ -66,6 +66,8 @@ static int mmc_queue_thread(void *d)spin_unlock_irq (q->queue_lock);if (req || mq->mqrq_prev->req) { +if (mmc_card_doing_bkops (mq->card)) +mmc_stop_bkops (mq->card);set_current_state (TASK_RUNNING ); mq->issue_fn (mq, req); }else {
drivers/mmc/core/core.c +168 -2
208 lines not on this page · raw message
drivers/mmc/core/host.c +1 -0
@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)spin_lock_init (&host->lock);init_waitqueue_head (&host->wq);INIT_DELAYED_WORK (&host->detect, mmc_rescan); +INIT_DELAYED_WORK (&host->start_bkops, mmc_start_periodic_bkops);#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify;#endif
drivers/mmc/core/mmc.c +18 -0
@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) }if (card->ext_csd.rev >=5 ) { +/* check whether the eMMC card support BKOPS */ +if (ext_csd[EXT_CSD_BKOPS_SUPPORT ] &0x1 ) { + card->ext_csd.bkops =1 ; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN ]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS ]; +if (!card->ext_csd.bkops_en && + card->host->caps2 &MMC_CAP2_INIT_BKOPS ) { + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_EN ,1 ,0 ); +if (err) +pr_warning ("%s: Enabling BKOPS failed\n" , +mmc_hostname (card->host)); +else + card->ext_csd.bkops_en =1 ; + } + } +/* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES ] &0x1 ) { card->ext_csd.hpi =1 ;
drivers/mmc/core/mmc_ops.c +4 -0
@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,if (err)return err; +/* No need to check card status in case of BKOPS switch*/ +if (index ==EXT_CSD_BKOPS_START ) +return 0 ; +/* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status);
include/linux/mmc/card.h +16 -0
@@ -76,6 +76,9 @@ struct mmc_ext_csd {bool hpi_en;/* HPI enablebit */ bool hpi;/* HPI support bit */ unsigned int hpi_cmd;/* cmd used as HPI */ +bool bkops;/* background support bit */ +bool bkops_en;/* background enable bit */ +u8 raw_exception_status;/* 53 */ unsigned int data_sector_size;/* 512 bytes or 4KB */ unsigned int data_tag_unit_size;/* DATA TAG UNIT size */ unsigned int boot_ro_lock;/* ro lock support */
@@ -93,6 +96,7 @@ struct mmc_ext_csd {u8 raw_sec_erase_mult;/* 230 */ u8 raw_sec_feature_support;/* 231 */ u8 raw_trim_mult;/* 232 */ +u8 raw_bkops_status;/* 246 */ u8 raw_sectors[4 ];/* 212 - 4 bytes */ unsigned int feature_support;
@@ -225,6 +229,9 @@ struct mmc_card {#define MMC_CARD_REMOVED (1<<7)/* card has been removed */ #define MMC_STATE_HIGHSPEED_200 (1<<8)/* card is in HS200 mode */ #define MMC_STATE_SLEEP (1<<9)/* card is in sleep state */ +#define MMC_STATE_NEED_BKOPS (1<<10)/* card need to do BKOPS */ +#define MMC_STATE_DOING_BKOPS (1<<11)/* card is doing BKOPS */ +#define MMC_STATE_CHECK_BKOPS (1<<12)/* card need to check BKOPS */ unsigned int quirks;/* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0)/* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)/* use func->cur_blksize */
@@ -391,6 +398,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_ext_capacity (c) ((c)->state & MMC_CARD_SDXC)#define mmc_card_removed (c) ((c) && ((c)->state & MMC_CARD_REMOVED))#define mmc_card_is_sleep (c) ((c)->state & MMC_STATE_SLEEP) +#define mmc_card_need_bkops (c) ((c)->state & MMC_STATE_NEED_BKOPS) +#define mmc_card_doing_bkops (c) ((c)->state & MMC_STATE_DOING_BKOPS) +#define mmc_card_check_bkops (c) ((c)->state & MMC_STATE_CHECK_BKOPS)#define mmc_card_set_present (c) ((c)->state |= MMC_STATE_PRESENT)#define mmc_card_set_readonly (c) ((c)->state |= MMC_STATE_READONLY)
@@ -403,7 +413,13 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_set_ext_capacity (c) ((c)->state |= MMC_CARD_SDXC)#define mmc_card_set_removed (c) ((c)->state |= MMC_CARD_REMOVED)#define mmc_card_set_sleep (c) ((c)->state |= MMC_STATE_SLEEP) +#define mmc_card_set_need_bkops (c) ((c)->state |= MMC_STATE_NEED_BKOPS) +#define mmc_card_set_doing_bkops (c) ((c)->state |= MMC_STATE_DOING_BKOPS) +#define mmc_card_set_check_bkops (c) ((c)->state |= MMC_STATE_CHECK_BKOPS) +#define mmc_card_clr_need_bkops (c) ((c)->state &= ~MMC_STATE_NEED_BKOPS) +#define mmc_card_clr_doing_bkops (c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) +#define mmc_card_clr_check_bkops (c) ((c)->state &= ~MMC_STATE_CHECK_BKOPS)#define mmc_card_clr_sleep (c) ((c)->state &= ~MMC_STATE_SLEEP)/* * Quirk add/remove for MMC products.
include/linux/mmc/core.h +5 -0
@@ -134,6 +134,9 @@ struct mmc_host;struct mmc_card ;struct mmc_async_req ; +extern int mmc_stop_bkops (struct mmc_card *); +extern int mmc_read_bkops_status (struct mmc_card *); +extern int mmc_is_exception_event (struct mmc_card *,unsigned int );extern struct mmc_async_req *mmc_start_req (struct mmc_host *,struct mmc_async_req *,int *);extern int mmc_interrupt_hpi (struct mmc_card *);
@@ -163,6 +166,8 @@ extern int mmc_can_sanitize(struct mmc_card *card);extern int mmc_can_secure_erase_trim (struct mmc_card *card);extern int mmc_erase_group_aligned (struct mmc_card *card,unsigned int from,unsigned int nr); +extern void mmc_start_periodic_bkops (struct work_struct *work); +extern void mmc_start_bkops (struct mmc_card *card);extern unsigned int mmc_calc_max_discard (struct mmc_card *card);extern int mmc_set_blocklen (struct mmc_card *card,unsigned int blocklen);
include/linux/mmc/host.h +4 -0
@@ -238,6 +238,8 @@ struct mmc_host {#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7)/* Use the broken voltage */ #define MMC_CAP2_DETECT_ON_ERR (1 << 8)/* On I/O err check card removal */ #define MMC_CAP2_HC_ERASE_SZ (1 << 9)/* High-capacity erase size */ +#define MMC_CAP2_INIT_BKOPS (1 << 10)/* To enable BKOPS */ +#define MMC_CAP2_BKOPS (1 << 11)/* BKOPS supported */ mmc_pm_flag_t pm_caps;/* supported pm features */ unsigned int power_notify_type;
@@ -320,6 +322,8 @@ struct mmc_host {unsigned int actual_clock;/* Actual HC clock rate */ +struct delayed_work start_bkops;/* Periodic bkops start */ +unsigned long private[0 ]____cacheline_aligned ; };
include/linux/mmc/mmc.h +20 -0
@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode)#define R1_CURRENT_STATE (x) ((x & 0x00001E00) >> 9)/* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8)/* sx, a */ #define R1_SWITCH_ERROR (1 << 7)/* sx, c */ +#define R1_EXCEPTION_EVENT (1 << 6)/* sx, a */ #define R1_APP_CMD (1 << 5)/* sr, c */ #define R1_STATE_IDLE 0
@@ -274,12 +275,15 @@ struct _mmc_csd {#define EXT_CSD_FLUSH_CACHE 32/* W */ #define EXT_CSD_CACHE_CTRL 33/* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34/* R/W */ +#define EXT_CSD_EXCEPTION_STATUS 54/* RO */ #define EXT_CSD_DATA_SECTOR_SIZE 61/* R */ #define EXT_CSD_GP_SIZE_MULT 143/* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156/* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160/* RO */ #define EXT_CSD_HPI_MGMT 161/* R/W */ #define EXT_CSD_RST_N_FUNCTION 162/* R/W */ +#define EXT_CSD_BKOPS_EN 163/* R/W */ +#define EXT_CSD_BKOPS_START 164/* W */ #define EXT_CSD_SANITIZE_START 165/* W */ #define EXT_CSD_WR_REL_PARAM 166/* RO */ #define EXT_CSD_BOOT_WP 173/* R/W */
@@ -313,11 +317,13 @@ struct _mmc_csd {#define EXT_CSD_PWR_CL_200_360 237/* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238/* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239/* RO */ +#define EXT_CSD_BKOPS_STATUS 246/* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247/* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248/* RO */ #define EXT_CSD_CACHE_SIZE 249/* RO, 4 bytes */ #define EXT_CSD_TAG_UNIT_SIZE 498/* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499/* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502/* RO */ #define EXT_CSD_HPI_FEATURES 503/* RO */ /*
@@ -386,4 +392,18 @@ struct _mmc_csd {#define MMC_SWITCH_MODE_CLEAR_BITS 0x02/* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03/* Set target to value */ +/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +#define EXT_CSD_BKOPS_LEVEL_3 0x3 + +/* +* EXCEPTION_EVENT_STATUS field (eMMC4.5) +*/ +#define EXT_CSD_URGENT_BKOPS BIT(0) +#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) +#define EXT_CSD_PACKED_FAILURE BIT(3) +#endif /* LINUX_MMC_MMC_H */
Hi Jaehoon,
I see 2 issues with new patch:
1. New code starts BKOPS always with waiting for BUSY. (see comment below in the code)
2. Runtime suspend (mmc_suspend_host) do not checks that BKOPS is in progress,
this means, that CMD5 (slee) will fail.
Quoted 350 lines
Enable eMMC background operations (BKOPS) feature.
If
URGENT_BKOPSis set after a response, note that BKOPS are required. After all I/O requests are finished, run BKOPS if required. Should read/write operations be requested during BKOPS, first issue HPI to interrupt the ongoing BKOPS and then service the request.
If BKOPS-STATUS is upper than LEVEL2, need to check until clear the BKOPS-STATUS vaule.If you want to enable this feature, set
MMC_CAP2_BKOPS. And if you want to set theBKOPS_ENbit inext_csdregister, use theMMC_CAP2_INIT_BKOPS.When
BKOPS_STATUSis Level-3, if we're waiting for done, it spent 60~80sec.
So Added timeout value. if timeout value is set to 0, send hpi command.Signed-off-by Jaehoon Chung <[email protected]>Signed-off-by Kyungmin Park <[email protected]>---
Changelog V8:
- Removehost->lockspin lock reviewed by Adrian
- Support periodic start bkops
- whenbkops_statusis level-3, if timeout is set to 0, send hpi.
- Move the start-bkops point
Changelog V7:
- Use HPI command when issuedURGENT_BKOPS
- Recheck until clearing the bkops-status bit.
Changelog V6:
- Add the flag of check-bkops-status.
(For fixingasync_reqproblem)
- Add the capability forMMC_CAP2_INIT_BKOPS.
(When unset thebkops_enbit inext_csdregister)
- modify the wrong condition.
Changelog V5:
- Rebase based on the latest mmc-next.
- modify codes based-on Chris's comment
Changelog V4:
- Addmmc_read_bkops_status
- WhenURGENT_BKOPS(level2-3), didn't use HPI command.
- Inmmc_switch(), use R1B/R1 according to level.
Changelog V3:
- move the bkops setting's location inmmc_blk_issue_rw_rq
- modify condition checking
-bkops_enis assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"
- remove the unused code
- changepr_debuginstead ofpr_warninmmc_send_hpi_cmd
- Add the Future consideration suggested by Per
Changelog V2:
- UseEXCEPTION_STATUSinstead ofURGENT_BKOPS
- Add function to checkException_status(for eMMC4.5)--- drivers/mmc/card/queue.c | 2 + drivers/mmc/core/core.c | 170 +++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/core/host.c | 1 + drivers/mmc/core/mmc.c | 18 +++++ drivers/mmc/core/mmc_ops.c | 4 + include/linux/mmc/card.h | 16 ++++ include/linux/mmc/core.h | 5 ++ include/linux/mmc/host.h | 4 + include/linux/mmc/mmc.h | 20 +++++ 9 files changed, 238 insertions(+), 2 deletions(-)drivers/mmc/card/queue.c +2
-0@@ -66,6 +66,8 @@ static int mmc_queue_thread(void *d)spin_unlock_irq (q->queue_lock);if (req || mq->mqrq_prev->req) { +if (mmc_card_doing_bkops (mq->card)) +mmc_stop_bkops (mq->card);set_current_state (TASK_RUNNING ); mq->issue_fn (mq, req); }else {drivers/mmc/core/core.c +7
-0@@ -175,6 +175,13 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)if (mrq->done) mrq->done (mrq); +/* +* Check BKOPS urgency from each R1 response +*/ +if (host->card &&mmc_card_mmc (host->card) && + (cmd->resp[0 ] &R1_EXCEPTION_EVENT )) +mmc_card_set_check_bkops (host->card); +mmc_host_clk_release (host); }}
drivers/mmc/core/core.c +70
-0@@ -245,6 +252,76 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) host->ops->request(host, mrq); } +static void mmc_send_bkops_cmd (struct mmc_card *card) +{ +int err; + +BUG_ON (!card); + + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_START ,1 ,0 ); +if (err) { +pr_warning ("%s: error %d starting bkops\n" , +mmc_hostname (card->host), err); +mmc_card_clr_need_bkops (card); +return ; + } + +mmc_card_clr_need_bkops (card); +mmc_card_set_doing_bkops (card); + +} + +void mmc_start_periodic_bkops (struct work_struct *work) +{ + struct mmc_host *host = container_of(work, struct mmc_host, + start_bkops.work); + +mmc_card_set_check_bkops (host->card); + +mmc_claim_host (host); +mmc_start_bkops (host->card); +mmc_release_host (host); +} +EXPORT_SYMBOL (mmc_start_periodic_bkops); + +/** +* mmc_start_bkops - start BKOPS for supported cards +* @card: MMC card to start BKOPS +* +* Start background operations whenever requested. +* when the urgent BKOPS bit is set in a R1 command response +* then background operations should be started immediately. +*/ +void mmc_start_bkops (struct mmc_card *card) +{ +BUG_ON (!card); +if (!card->ext_csd.bkops_en || !(card->host->caps2 &MMC_CAP2_BKOPS )) +return ; + +if (mmc_card_check_bkops (card)) { +mmc_card_clr_check_bkops (card); +if (mmc_is_exception_event (card,EXT_CSD_URGENT_BKOPS )) { +if (card->ext_csd.raw_bkops_status) +mmc_card_set_need_bkops (card); + }else +mmc_card_clr_need_bkops (card); + } + +/* +* If card_need_bkops_flag didn't set, then do nothing just +* return +*/ +if (mmc_card_doing_bkops (card) || !mmc_card_need_bkops (card)) + goto check_bkops; + +mmc_send_bkops_cmd (card); + +check_bkops: +queue_delayed_work (system_nrt_wq, &card->host->start_bkops,5 *HZ ); +} +EXPORT_SYMBOL (mmc_start_bkops); +static void mmc_wait_done (struct mmc_request *mrq) {drivers/mmc/core/core.c +3
-1complete (&mrq->completion);@@ -348,8 +425,10 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, struct mmc_async_req *data = host->areq;/* Prepare a new request */ -if (areq) +if (areq) { +cancel_delayed_work_sync (&host->start_bkops);mmc_pre_req (host, areq->mrq, !host->areq); + }if (host->areq) {drivers/mmc/core/core.c +4
-1mmc_wait_for_req_done (host, host->areq->mrq);@@ -359,8 +438,11 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, if (!err && areq) start_err = __mmc_start_req(host, areq->mrq); -if (host->areq) +if (host->areq) {mmc_post_req (host, host->areq->mrq,0 ); +if (!areq && host->areq &&mmc_card_mmc (host->card)) +mmc_start_bkops (host->card); + }/* Cancel a prepared request if it was not started. */ drivers/mmc/core/core.c +0
-0if ((err || start_err) && areq)@@ -480,6 +562,84 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct
mmc_command*cmd, int retries
EXPORT_SYMBOL(mmc_wait_for_cmd);/**
+ *mmc_stop_bkops- stop ongoing BKOPS
+ * @card: MMC card to check BKOPS
+ *
+ * Send HPI command to interrupt ongoing background operations,
+ * to allow rapid servicing of foreground operations,e.g. read/
+ * writes. Wait until the card comes out of the programming state
+ * to avoid errors in servicing read/write requests.
+ */drivers/mmc/core/core.c +76
-0+int mmc_stop_bkops (struct mmc_card *card) +{ +int err =0 ; +unsigned int timeout =0x10000 ; +u32 status; + +BUG_ON (!card); +cancel_delayed_work_sync (&card->host->start_bkops); + +if (card->ext_csd.raw_bkops_status ==EXT_CSD_BKOPS_LEVEL_3 ) { +do { +if (timeout ==0 ) +break ; +mmc_claim_host (card->host); +mmc_send_status (card, &status); +mmc_release_host (card->host); + + timeout--; + }while (R1_CURRENT_STATE (status) ==R1_STATE_PRG ); +if (timeout !=0 ) + goto done; + } + + err =mmc_interrupt_hpi (card); + +done: +mmc_card_clr_doing_bkops (card); + +return err; +} +EXPORT_SYMBOL (mmc_stop_bkops); + +int mmc_read_bkops_status (struct mmc_card *card) +{ +int err; +u8 ext_csd[512 ]; + +mmc_claim_host (card->host); + err =mmc_send_ext_csd (card, ext_csd); +mmc_release_host (card->host); +if (err) +return err; + + card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS ]; + card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXCEPTION_STATUS ]; + +return 0 ; +} +EXPORT_SYMBOL (mmc_read_bkops_status); + +int mmc_is_exception_event (struct mmc_card *card,unsigned int value) +{ +int err; + + err =mmc_read_bkops_status (card); +if (err) { +pr_err ("%s: Didn't read bkops status : %d\n" , +mmc_hostname (card->host), err); +return 0 ; + } + +/* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */ +if (card->ext_csd.rev ==5 ) +return 1 ; + +return (card->ext_csd.raw_exception_status & value) ?1 :0 ; +} +EXPORT_SYMBOL (mmc_is_exception_event); + +/** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer @@ -2382,6 +2542,12 @@ int mmc_pm_notify(struct notifier_block *notify_block, switch (mode) {case PM_HIBERNATION_PREPARE :case PM_SUSPEND_PREPARE : +if (host->card &&mmc_card_mmc (host->card) && +mmc_card_doing_bkops (host->card)) { +mmc_interrupt_hpi (host->card); +mmc_card_clr_doing_bkops (host->card); + } +cancel_delayed_work_sync (&host->start_bkops);spin_lock_irqsave (&host->lock, flags);drivers/mmc/core/core.c +0
-0host->rescan_disable =1 ;drivers/mmc/core/host.c +1
-0@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock);init_waitqueue_head (&host->wq);INIT_DELAYED_WORK (&host->detect, mmc_rescan); +INIT_DELAYED_WORK (&host->start_bkops, mmc_start_periodic_bkops);#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify;#endif
drivers/mmc/core/mmc.c +18
-0@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) }if (card->ext_csd.rev >=5 ) { +/* check whether the eMMC card support BKOPS */ +if (ext_csd[EXT_CSD_BKOPS_SUPPORT ] &0x1 ) { + card->ext_csd.bkops =1 ; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN ]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS ]; +if (!card->ext_csd.bkops_en && + card->host->caps2 &MMC_CAP2_INIT_BKOPS ) { + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_EN ,1 ,0 ); +if (err) +pr_warning ("%s: Enabling BKOPS failed\n" , +mmc_hostname (card->host)); +else + card->ext_csd.bkops_en =1 ; + } + } +/* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES ] &0x1 ) {drivers/mmc/core/mmc.c +0
-0card->ext_csd.hpi =1 ;drivers/mmc/core/mmc_ops.c +0
-0
drivers/mmc/core/mmc_ops.c int mmc_switch(struct mmc_card *card, u8 set, u8 · line 402
Quoted 4 lines
drivers/mmc/core/mmc_ops.c +0
-0@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (err)return err;
In your previous patch (v7) was code:
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags = MMC_CMD_AC;
+ if (index == EXT_CSD_BKOPS_START &&
+ card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2)
+ cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
+ else
+ cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
When level of raw_bkops_status is not critical, the host controller flags used
without waiting for BUSY line release. This means, that mmc queue thread will continue
to fetch requests while BKOPS still running on the card. Without this code, BKOPS will always be blocking till BKOPS done and using HPI for interrupt BKOPS on
new request is not need.
Why you removed this code?
Hi Konstantin.
Quoted 7 lines · On 05/10/2012 11:46 PM, [email protected] wrote:
Hi Jaehoon,
I see 2 issues with new patch:
1. New code starts BKOPS always with waiting for BUSY. (see comment below in the code)
2. Runtime suspend (mmc_suspend_host) do not checks that BKOPS is in progress,
this means, that CMD5 (slee) will fail.
You're right. it needs to check in progress.
I will add them.
Quoted 12 lines
In your previous patch (v7) was code:
(quoted diff) +6
-1- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; + cmd.flags = MMC_CMD_AC; + if (index == EXT_CSD_BKOPS_START && + card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2) + cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1; + else + cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
Quoted 9 lines
When level of
raw_bkops_statusis not critical, the host controller flags used
without waiting for BUSY line release. This means, that mmc queue thread will continue
to fetch requests while BKOPS still running on the card. Without this code, BKOPS will always be blocking till BKOPS done and using HPI for interrupt BKOPS on
new request is not need.
Why you removed this code?
You're right. it's my mistake. Actually i modified to use with __mmc_switch(). As I remember, maybe you mentioned this point. right?
So i tried to use based on your review. it's missing in this patch.
Thank you for your comment. any other comments?
If you have others, let me know, plz.
Best Regards,
Jaehoon Chung
Quoted 7 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 13 lines
Hi Konstantin.
Quoted 8 lines · On 05/10/2012 11:46 PM, [email protected] wrote:
Hi Jaehoon,
I see 2 issues with new patch:
1. New code starts BKOPS always with waiting for BUSY. (see comment below
in the code)
2. Runtime suspend (mmc_suspend_host) do not checks that BKOPS is in progress,
this means, that CMD5 (slee) will fail.
Quoted 2 lines
You're right. it needs to check in progress. I will add them.
OK, I will send you patch for runtime suspend flow (it is good to do righ before calling ops->suspend callback in mmc_suspend_host() function.
Quoted 13 lines
Quoted 13 lines
In your previous patch (v7) was code:
(quoted diff) +6
-1- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; + cmd.flags = MMC_CMD_AC; + if (index == EXT_CSD_BKOPS_START && + card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2) + cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1; + else + cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
Quoted 17 lines
Quoted 11 lines
When level of
raw_bkops_statusis not critical, the host controller flags
used
without waiting for BUSY line release. This means, that mmc queue thread will continue
to fetch requests while BKOPS still running on the card. Without this code, BKOPS will always be blocking till BKOPS done and using
HPI for interrupt BKOPS on
new request is not need.
Why you removed this code?You're right. it's my mistake. Actually i modified to use with
__mmc_switch().
As I remember, maybe you mentioned this point. right?
So i tried to use based on your review. it's missing in this patch.
yes
Quoted 2 lines
Thank you for your comment. any other comments? If you have others, let me know, plz.
I will check the patch and update you about it.
Thanks,
Kostya
Quoted 109 lines · Jaehoon Chung
Enable eMMC background operations (BKOPS) feature.
If
URGENT_BKOPSis set after a response, note that BKOPS are required. After all I/O requests are finished, run BKOPS if required. Should read/write operations be requested during BKOPS, first issue HPI to interrupt the ongoing BKOPS and then service the request.
If BKOPS-STATUS is upper than LEVEL2, need to check until clear the BKOPS-STATUS vaule.If you want to enable this feature, set
MMC_CAP2_BKOPS. And if you want to set theBKOPS_ENbit inext_csdregister, use theMMC_CAP2_INIT_BKOPS.When
BKOPS_STATUSis Level-3, if we're waiting for done, it spent 60~80sec. So Added timeout value. if timeout value is set to 0, send hpi command.Signed-off-by Jaehoon Chung <[email protected]>Signed-off-by Kyungmin Park <[email protected]>---
Changelog V8:
- Removehost->lockspin lock reviewed by Adrian
- Support periodic start bkops
- whenbkops_statusis level-3, if timeout is set to 0, send hpi.
- Move the start-bkops point
Changelog V7:
- Use HPI command when issuedURGENT_BKOPS
- Recheck until clearing the bkops-status bit. Changelog V6:
- Add the flag of check-bkops-status.
(For fixingasync_reqproblem)
- Add the capability forMMC_CAP2_INIT_BKOPS.
(When unset thebkops_enbit inext_csdregister)
- modify the wrong condition.
Changelog V5:
- Rebase based on the latest mmc-next.
- modify codes based-on Chris's comment
Changelog V4:
- Addmmc_read_bkops_status
- WhenURGENT_BKOPS(level2-3), didn't use HPI command.
- Inmmc_switch(), use R1B/R1 according to level. Changelog V3:
- move the bkops setting's location inmmc_blk_issue_rw_rq
- modify condition checking
-bkops_enis assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"
- remove the unused code
- changepr_debuginstead ofpr_warninmmc_send_hpi_cmd
- Add the Future consideration suggested by Per Changelog V2:
- UseEXCEPTION_STATUSinstead ofURGENT_BKOPS
- Add function to checkException_status(for eMMC4.5)
---
drivers/mmc/card/queue.c | 2 +drivers/mmc/core/core.c | 170 +++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/core/host.c | 1 + drivers/mmc/core/mmc.c | 18 +++++ drivers/mmc/core/mmc_ops.c | 4 + include/linux/mmc/card.h | 16 ++++ include/linux/mmc/core.h | 5 ++ include/linux/mmc/host.h | 4 + include/linux/mmc/mmc.h | 20 +++++ 9 files changed, 238 insertions(+), 2 deletions(-)drivers/mmc/card/queue.c +2
-0@@ -66,6 +66,8 @@ static int mmc_queue_thread(void *d) spin_unlock_irq(q->queue_lock); if (req || mq->mqrq_prev->req) { + if (mmc_card_doing_bkops(mq->card)) + mmc_stop_bkops(mq->card); set_current_state(TASK_RUNNING); mq->issue_fn(mq, req); } else {drivers/mmc/core/core.c +18
-0@@ -175,6 +175,13 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) if (mrq->done) mrq->done(mrq); + /* + * Check BKOPS urgency from each R1 response + */ + if (host->card && mmc_card_mmc(host->card) && + (cmd->resp[0] & R1_EXCEPTION_EVENT)) + mmc_card_set_check_bkops(host->card); + mmc_host_clk_release(host); } }@@ -245,6 +252,76 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) host->ops->request(host, mrq); } +static void mmc_send_bkops_cmd (struct mmc_card *card) +{ + int err; + + BUG_ON(!card); + + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BKOPS_START, 1, 0); + if (err) { + pr_warning("%s: error %d starting bkops\n", + mmc_hostname(card->host), err);
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 275
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+ mmc_card_clr_need_bkops(card); + return; + } + + mmc_card_clr_need_bkops(card); + mmc_card_set_doing_bkops(card); + +} + +void mmc_start_periodic_bkops (struct work_struct *work)
There's nothing periodic about this function, by looking at the contents. Maybe this one should be called mmc_start_bkops ..
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 280
Quoted 5 lines
drivers/mmc/core/core.c +5
-0+{ + struct mmc_host *host = container_of(work, struct mmc_host, + start_bkops.work); + + mmc_card_set_check_bkops(host->card);
Why is this being set here. The condition should be in the caller context.
Quoted 6 lines
drivers/mmc/core/core.c +6
-0+ + mmc_claim_host(host); + mmc_start_bkops(host->card); + mmc_release_host(host); +} +EXPORT_SYMBOL (mmc_start_periodic_bkops);
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 296
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+ +/** +* mmc_start_bkops - start BKOPS for supported cards +* @card: MMC card to start BKOPS +* +* Start background operations whenever requested. +* when the urgent BKOPS bit is set in a R1 command response +* then background operations should be started immediately. +*/ +void mmc_start_bkops (struct mmc_card *card)
.. and this one should be called __mmc_start_bkops() ?
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 306
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+{ + BUG_ON(!card); + if (!card->ext_csd.bkops_en || !(card->host->caps2 & MMC_CAP2_BKOPS)) + return; + + if (mmc_card_check_bkops(card)) { + mmc_card_clr_check_bkops(card); + if (mmc_is_exception_event(card, EXT_CSD_URGENT_BKOPS)) { + if (card->ext_csd.raw_bkops_status) + mmc_card_set_need_bkops(card);
This breaks abstraction. Why check ext_csd even after URGENT_BKOPS is set ?
Quoted 5 lines
drivers/mmc/core/core.c +5
-0+ } else + mmc_card_clr_need_bkops(card); + } + + /*
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 321
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+* If card_need_bkops_flag didn't set, then do nothing just +* return +*/ + if (mmc_card_doing_bkops(card) || !mmc_card_need_bkops(card)) + goto check_bkops; + + mmc_send_bkops_cmd(card); + +check_bkops: + queue_delayed_work(system_nrt_wq, &card->host->start_bkops, 5 * HZ);
IIUC, queue_delayed_work->start_bkops = mmc_start_periodic_bkops -> mmc_start_bkops -> queue_delayed_work
.. ad infinitum ?
Quoted 55 lines
drivers/mmc/core/core.c +30
-2+} +EXPORT_SYMBOL (mmc_start_bkops); + static void mmc_wait_done(struct mmc_request *mrq) { complete(&mrq->completion);@@ -348,8 +425,10 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, struct mmc_async_req *data = host->areq; /* Prepare a new request */ - if (areq) + if (areq) { + cancel_delayed_work_sync(&host->start_bkops); mmc_pre_req(host, areq->mrq, !host->areq); + } if (host->areq) { mmc_wait_for_req_done(host, host->areq->mrq);@@ -359,8 +438,11 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, if (!err && areq) start_err = __mmc_start_req(host, areq->mrq); - if (host->areq) + if (host->areq) { mmc_post_req(host, host->areq->mrq, 0); + if (!areq && host->areq && mmc_card_mmc(host->card)) + mmc_start_bkops(host->card); + } /* Cancel a prepared request if it was not started. */ if ((err || start_err) && areq)@@ -480,6 +562,84 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries EXPORT_SYMBOL(mmc_wait_for_cmd); /** +* mmc_stop_bkops - stop ongoing BKOPS +* @card: MMC card to check BKOPS +* +* Send HPI command to interrupt ongoing background operations, +* to allow rapid servicing of foreground operations,e.g. read/ +* writes. Wait until the card comes out of the programming state +* to avoid errors in servicing read/write requests. +*/ +int mmc_stop_bkops (struct mmc_card *card) +{ + int err = 0; + unsigned int timeout = 0x10000; + u32 status; + + BUG_ON(!card); + cancel_delayed_work_sync(&card->host->start_bkops); + + if (card->ext_csd.raw_bkops_status == EXT_CSD_BKOPS_LEVEL_3) { + do { + if (timeout == 0)
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 594
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+ break; + mmc_claim_host(card->host); + mmc_send_status(card, &status); + mmc_release_host(card->host); + + timeout--; + } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); + if (timeout != 0) + goto done; + }
This won't necessarily work all the time. Once BKOPS_START is issued, the card might finish GC and move to transfer state even before HPI can be sent. So just exit if the card is in transfer state already.
In this context, kdorfman's comments on "mmc:fix HPI execution sequence" makes sense.
Quoted 32 lines
drivers/mmc/core/core.c +32
-0+ + err = mmc_interrupt_hpi(card); + +done: + mmc_card_clr_doing_bkops(card); + + return err; +} +EXPORT_SYMBOL (mmc_stop_bkops); + +int mmc_read_bkops_status (struct mmc_card *card) +{ + int err; + u8 ext_csd[512]; + + mmc_claim_host(card->host); + err = mmc_send_ext_csd(card, ext_csd); + mmc_release_host(card->host); + if (err) + return err; + + card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; + card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXCEPTION_STATUS]; + + return 0; +} +EXPORT_SYMBOL (mmc_read_bkops_status); + +int mmc_is_exception_event (struct mmc_card *card,unsigned int value) +{ + int err; +
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 636
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+ err = mmc_read_bkops_status(card); + if (err) { + pr_err("%s: Didn't read bkops status : %d\n", + mmc_hostname(card->host), err); + return 0; + } + + /* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */ + if (card->ext_csd.rev == 5) + return 1;
Please swap the order in which you are doing this.
For eMMC4.41, we can save the mmc_read_bkops_status atleast for 4.41 card for _every_ request, which is not used.
Quoted 42 lines
drivers/mmc/core/core.c +6
-0+ + return (card->ext_csd.raw_exception_status & value) ? 1 : 0; +} +EXPORT_SYMBOL (mmc_is_exception_event); + +/** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer @@ -2382,6 +2542,12 @@ int mmc_pm_notify(struct notifier_block *notify_block, switch (mode) {case
PM_HIBERNATION_PREPARE:
casePM_SUSPEND_PREPARE:
+ if (host->card&&mmc_card_mmc(host->card)&&
+mmc_card_doing_bkops(host->card)) {
+mmc_interrupt_hpi(host->card);
+mmc_card_clr_doing_bkops(host->card);
+ }
+cancel_delayed_work_sync(&host->start_bkops);spin_lock_irqsave(&host->lock, flags);
host->rescan_disable= 1;drivers/mmc/core/host.c +1
-0@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); + INIT_DELAYED_WORK(&host->start_bkops, mmc_start_periodic_bkops); #ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify; #endifdrivers/mmc/core/mmc.c +0
-0@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } if (card->ext_csd.rev >= 5) {
drivers/mmc/core/mmc.c static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) · line 475
Quoted 10 lines
drivers/mmc/core/mmc.c +10
-0+ /* check whether the eMMC card support BKOPS */ + if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { + card->ext_csd.bkops = 1; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS]; + if (!card->ext_csd.bkops_en && + card->host->caps2 & MMC_CAP2_INIT_BKOPS) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BKOPS_EN, 1, 0);
I am not too comfortable tying a OTP register setting to a host controller capability.
What if I had multiple instances of MMC and reuse the same HC, and each needs a different
setting ? Or the same HC used in multiple SoCs ?
A sysfs entry would be better - program the INIT when a user explicitly sets "enable_bkops" for the device
that is being used.
Quoted 178 lines
drivers/mmc/core/mmc.c +8
-0+ if (err) + pr_warning("%s: Enabling BKOPS failed\n", + mmc_hostname(card->host)); + else + card->ext_csd.bkops_en = 1; + } + } + /* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { card->ext_csd.hpi = 1;drivers/mmc/core/mmc_ops.c +4
-0@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (err) return err; + /* No need to check card status in case of BKOPS switch*/ + if (index == EXT_CSD_BKOPS_START) + return 0; + /* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status);include/linux/mmc/card.h +0
-0@@ -76,6 +76,9 @@ struct mmc_ext_csd {bool hpi_en; /* HPI enablebit */ bool hpi; /* HPI support bit */ unsigned int hpi_cmd; /* cmd used as HPI */
+ bool bkops; /* background support bit */
+ bool bkops_en; /* background enable bit */
+ u8 raw_exception_status; /* 53 */ unsigned int data_sector_size; /* 512 bytes or 4KB */ unsigned int data_tag_unit_size; /* DATA TAG UNIT size */ unsigned int boot_ro_lock; /* ro lock support */include/linux/mmc/card.h +0
-0@@ -93,6 +96,7 @@ struct mmc_ext_csd {u8 raw_sec_erase_mult; /* 230 */ u8 raw_sec_feature_support;/* 231 */ u8 raw_trim_mult; /* 232 */
+ u8 raw_bkops_status; /* 246 */ u8 raw_sectors[4]; /* 212 - 4 bytes */unsigned int feature_support;
include/linux/mmc/card.h +3
-0@@ -225,6 +229,9 @@ struct mmc_card { #define MMC_CARD_REMOVED (1<<7) /* card has been removed */ #define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ #define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */ +#define MMC_STATE_NEED_BKOPS (1<<10)/* card need to do BKOPS */ +#define MMC_STATE_DOING_BKOPS (1<<11)/* card is doing BKOPS */ +#define MMC_STATE_CHECK_BKOPS (1<<12)/* card need to check BKOPS */ unsigned int quirks; /* card quirks */
#defineMMC_QUIRK_LENIENT_FN0(1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ #defineMMC_QUIRK_BLKSZ_FOR_BYTE_MODE(1<<1) /* usefunc->cur_blksize*/include/linux/mmc/card.h +9
-0@@ -391,6 +398,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) #define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP) +#define mmc_card_need_bkops (c) ((c)->state & MMC_STATE_NEED_BKOPS) +#define mmc_card_doing_bkops (c) ((c)->state & MMC_STATE_DOING_BKOPS) +#define mmc_card_check_bkops (c) ((c)->state & MMC_STATE_CHECK_BKOPS) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)@@ -403,7 +413,13 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) #define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP) +#define mmc_card_set_need_bkops (c) ((c)->state |= MMC_STATE_NEED_BKOPS) +#define mmc_card_set_doing_bkops (c) ((c)->state |= MMC_STATE_DOING_BKOPS) +#define mmc_card_set_check_bkops (c) ((c)->state |= MMC_STATE_CHECK_BKOPS) +#define mmc_card_clr_need_bkops (c) ((c)->state &= ~MMC_STATE_NEED_BKOPS) +#define mmc_card_clr_doing_bkops (c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) +#define mmc_card_clr_check_bkops (c) ((c)->state &= ~MMC_STATE_CHECK_BKOPS) #define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP) /** Quirk add/remove for MMC products. include/linux/mmc/core.h +5
-0@@ -134,6 +134,9 @@ struct mmc_host; struct mmc_card; struct mmc_async_req; +extern int mmc_stop_bkops (struct mmc_card *); +extern int mmc_read_bkops_status (struct mmc_card *); +extern int mmc_is_exception_event (struct mmc_card *,unsigned int ); extern struct mmc_async_req *mmc_start_req(struct mmc_host *, struct mmc_async_req *, int *); extern int mmc_interrupt_hpi(struct mmc_card *);@@ -163,6 +166,8 @@ extern int mmc_can_sanitize(struct mmc_card *card); extern int mmc_can_secure_erase_trim(struct mmc_card *card); extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, unsigned int nr); +extern void mmc_start_periodic_bkops (struct work_struct *work); +extern void mmc_start_bkops (struct mmc_card *card); extern unsigned int mmc_calc_max_discard(struct mmc_card *card); extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);include/linux/mmc/host.h +2
-0@@ -238,6 +238,8 @@ struct mmc_host { #define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */ #define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */ #define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */ +#define MMC_CAP2_INIT_BKOPS (1 << 10)/* To enable BKOPS */ +#define MMC_CAP2_BKOPS (1 << 11)/* BKOPS supported */ mmc_pm_flag_t
pm_caps; /* supported pm features */ unsigned int power_notify_type;include/linux/mmc/host.h +0
-0@@ -320,6 +322,8 @@ struct mmc_host {unsigned int actual_clock; /* Actual HC clock rate */
+ struct
delayed_workstart_bkops; /* Periodic bkops start */ +
unsigned long private[0]____cacheline_aligned; };include/linux/mmc/mmc.h +11
-0@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode) #define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ +#define R1_EXCEPTION_EVENT (1 << 6)/* sx, a */ #define R1_APP_CMD (1 << 5) /* sr, c */ #define R1_STATE_IDLE 0@@ -274,12 +275,15 @@ struct _mmc_csd { #define EXT_CSD_FLUSH_CACHE 32 /* W */ #define EXT_CSD_CACHE_CTRL 33 /* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ +#define EXT_CSD_EXCEPTION_STATUS 54/* RO */ #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ #define EXT_CSD_HPI_MGMT 161 /* R/W */ #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ +#define EXT_CSD_BKOPS_EN 163/* R/W */ +#define EXT_CSD_BKOPS_START 164/* W */ #define EXT_CSD_SANITIZE_START 165 /* W */ #define EXT_CSD_WR_REL_PARAM 166 /* RO */ #define EXT_CSD_BOOT_WP 173 /* R/W */@@ -313,11 +317,13 @@ struct _mmc_csd { #define EXT_CSD_PWR_CL_200_360 237 /* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ +#define EXT_CSD_BKOPS_STATUS 246/* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502/* RO */ #define EXT_CSD_HPI_FEATURES 503 /* RO */ /*@@ -386,4 +392,18 @@ struct _mmc_csd { #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ +/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +#define EXT_CSD_BKOPS_LEVEL_3 0x3
include/linux/mmc/mmc.h struct _mmc_csd { · line 409
Quoted 10 lines
include/linux/mmc/mmc.h +9
-0+ +/* +* EXCEPTION_EVENT_STATUS field (eMMC4.5) +*/ +#define EXT_CSD_URGENT_BKOPS BIT(0) +#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) +#define EXT_CSD_PACKED_FAILURE BIT(3) + #endif /* LINUX_MMC_MMC_H */
Overall, my significant concern is about performance.
IIUC, There is a ext_csd query during the execution of _every_ request
- this is far too obsessive and could kill throughput.
A more pragmatic approach would be to trigger on a threshold of number of writes or discards (ex: After 1M sector writes)
This means that a predominantly read only disk, which wouldn't need any BKOPS, wouldn't have any overhead.
Let me know if my assumption is incorrect.
~Venkat.
Quoted 115 lines · Venkatraman
Quoted 114 lines · Jaehoon Chung
Enable eMMC background operations (BKOPS) feature.
If
URGENT_BKOPSis set after a response, note that BKOPS are required. After all I/O requests are finished, run BKOPS if required. Should read/write operations be requested during BKOPS, first issue HPI to interrupt the ongoing BKOPS and then service the request.
If BKOPS-STATUS is upper than LEVEL2, need to check until clear the BKOPS-STATUS vaule.If you want to enable this feature, set
MMC_CAP2_BKOPS. And if you want to set theBKOPS_ENbit inext_csdregister, use theMMC_CAP2_INIT_BKOPS.When
BKOPS_STATUSis Level-3, if we're waiting for done, it spent 60~80sec. So Added timeout value. if timeout value is set to 0, send hpi command.Signed-off-by Jaehoon Chung <[email protected]>Signed-off-by Kyungmin Park <[email protected]>---
Changelog V8:
- Removehost->lockspin lock reviewed by Adrian
- Support periodic start bkops
- whenbkops_statusis level-3, if timeout is set to 0, send hpi.
- Move the start-bkops point
Changelog V7:
- Use HPI command when issuedURGENT_BKOPS
- Recheck until clearing the bkops-status bit.
Changelog V6:
- Add the flag of check-bkops-status.
(For fixingasync_reqproblem)
- Add the capability forMMC_CAP2_INIT_BKOPS.
(When unset thebkops_enbit inext_csdregister)
- modify the wrong condition.
Changelog V5:
- Rebase based on the latest mmc-next.
- modify codes based-on Chris's comment
Changelog V4:
- Addmmc_read_bkops_status
- WhenURGENT_BKOPS(level2-3), didn't use HPI command.
- Inmmc_switch(), use R1B/R1 according to level.
Changelog V3:
- move the bkops setting's location inmmc_blk_issue_rw_rq
- modify condition checking
-bkops_enis assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"
- remove the unused code
- changepr_debuginstead ofpr_warninmmc_send_hpi_cmd
- Add the Future consideration suggested by Per
Changelog V2:
- UseEXCEPTION_STATUSinstead ofURGENT_BKOPS
- Add function to checkException_status(for eMMC4.5)--- drivers/mmc/card/queue.c | 2 + drivers/mmc/core/core.c | 170 +++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/core/host.c | 1 + drivers/mmc/core/mmc.c | 18 +++++ drivers/mmc/core/mmc_ops.c | 4 + include/linux/mmc/card.h | 16 ++++ include/linux/mmc/core.h | 5 ++ include/linux/mmc/host.h | 4 + include/linux/mmc/mmc.h | 20 +++++ 9 files changed, 238 insertions(+), 2 deletions(-)drivers/mmc/card/queue.c +2
-0@@ -66,6 +66,8 @@ static int mmc_queue_thread(void *d)spin_unlock_irq (q->queue_lock);if (req || mq->mqrq_prev->req) { +if (mmc_card_doing_bkops (mq->card)) +mmc_stop_bkops (mq->card);set_current_state (TASK_RUNNING ); mq->issue_fn (mq, req); }else {drivers/mmc/core/core.c +23
-0@@ -175,6 +175,13 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)if (mrq->done) mrq->done (mrq); +/* +* Check BKOPS urgency from each R1 response +*/ +if (host->card &&mmc_card_mmc (host->card) && + (cmd->resp[0 ] &R1_EXCEPTION_EVENT )) +mmc_card_set_check_bkops (host->card); +mmc_host_clk_release (host); } }@@ -245,6 +252,76 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) host->ops->request (host, mrq); } +static void mmc_send_bkops_cmd (struct mmc_card *card) +{ +int err; + +BUG_ON (!card); + + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_START ,1 ,0 ); +if (err) { +pr_warning ("%s: error %d starting bkops\n" , +mmc_hostname (card->host), err); +mmc_card_clr_need_bkops (card); +return ; + } + +mmc_card_clr_need_bkops (card);
Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 275
Quoted 5 lines
drivers/mmc/core/core.c +5
-0+mmc_card_set_doing_bkops (card); + +} + +void mmc_start_periodic_bkops (struct work_struct *work)There's nothing periodic about this function, by looking at the contents. Maybe this one should be called
mmc_start_bkops..
Well...i will checked this point..i tested with eMMC4.5 card...In my case, working this function. But in your case, didn't work nothing..i will rework to this point after debugging.
Quoted 18 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 280
Quoted 6 lines
drivers/mmc/core/core.c +5
-0+{ + struct mmc_host *host = container_of(work, struct mmc_host, + start_bkops.work); + +mmc_card_set_check_bkops (host->card);Why is this being set here. The condition should be in the caller context.
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+ +mmc_claim_host (host); +mmc_start_bkops (host->card); +mmc_release_host (host); +} +EXPORT_SYMBOL (mmc_start_periodic_bkops); + +/** +* mmc_start_bkops - start BKOPS for supported cards +* @card: MMC card to start BKOPS
Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 296
Quoted 6 lines
drivers/mmc/core/core.c +6
-0+* +* Start background operations whenever requested. +* when the urgent BKOPS bit is set in a R1 command response +* then background operations should be started immediately. +*/ +void mmc_start_bkops (struct mmc_card *card).. and this one should be called
__mmc_start_bkops()?
Sure..i will change that.
Quoted 13 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 306
Quoted 11 lines
drivers/mmc/core/core.c +10
-0+{ +BUG_ON (!card); +if (!card->ext_csd.bkops_en || !(card->host->caps2 &MMC_CAP2_BKOPS )) +return ; + +if (mmc_card_check_bkops (card)) { +mmc_card_clr_check_bkops (card); +if (mmc_is_exception_event (card,EXT_CSD_URGENT_BKOPS )) { +if (card->ext_csd.raw_bkops_status) +mmc_card_set_need_bkops (card);This breaks abstraction. Why check
ext_csdeven afterURGENT_BKOPSis set ?
You means that need not to check ext_csd?
Well I didn't think so, we need to check bkops-status register
Quoted 12 lines
Quoted 12 lines
drivers/mmc/core/core.c +11
-0+ }else +mmc_card_clr_need_bkops (card); + } + +/* +* If card_need_bkops_flag didn't set, then do nothing just +* return +*/ +if (mmc_card_doing_bkops (card) || !mmc_card_need_bkops (card)) + goto check_bkops; +
Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 321
Quoted 4 lines
drivers/mmc/core/core.c +4
-0+mmc_send_bkops_cmd (card); + +check_bkops: +queue_delayed_work (system_nrt_wq, &card->host->start_bkops,5 *HZ );IIUC,
queue_delayed_work->start_bkops=mmc_start_periodic_bkops->mmc_start_bkops->queue_delayed_work
.. ad infinitum ?
Actually, i want to get review for this point..How did you think about?
Quoted 62 lines
Quoted 62 lines
drivers/mmc/core/core.c +36
-2+} +EXPORT_SYMBOL (mmc_start_bkops); +static void mmc_wait_done (struct mmc_request *mrq) {complete (&mrq->completion);@@ -348,8 +425,10 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,struct mmc_async_req *data = host->areq;/* Prepare a new request */ -if (areq) +if (areq) { +cancel_delayed_work_sync (&host->start_bkops);mmc_pre_req (host, areq->mrq, !host->areq); + }if (host->areq) {mmc_wait_for_req_done (host, host->areq->mrq);@@ -359,8 +438,11 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,if (!err && areq) start_err =__mmc_start_req (host, areq->mrq); -if (host->areq) +if (host->areq) {mmc_post_req (host, host->areq->mrq,0 ); +if (!areq && host->areq &&mmc_card_mmc (host->card)) +mmc_start_bkops (host->card); + }/* Cancel a prepared request if it was not started. */ if ((err || start_err) && areq)@@ -480,6 +562,84 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retriesEXPORT_SYMBOL (mmc_wait_for_cmd);/** +* mmc_stop_bkops - stop ongoing BKOPS +* @card: MMC card to check BKOPS +* +* Send HPI command to interrupt ongoing background operations, +* to allow rapid servicing of foreground operations,e.g. read/ +* writes. Wait until the card comes out of the programming state +* to avoid errors in servicing read/write requests. +*/ +int mmc_stop_bkops (struct mmc_card *card) +{ +int err =0 ; +unsigned int timeout =0x10000 ; +u32 status; + +BUG_ON (!card); +cancel_delayed_work_sync (&card->host->start_bkops); + +if (card->ext_csd.raw_bkops_status ==EXT_CSD_BKOPS_LEVEL_3 ) { + do { + if (timeout == 0) + break; + mmc_claim_host(card->host); + mmc_send_status(card, &status); + mmc_release_host(card->host); + + timeout--;
Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 594
Quoted 4 lines
drivers/mmc/core/core.c +4
-0+ }while (R1_CURRENT_STATE (status) ==R1_STATE_PRG ); +if (timeout !=0 ) + goto done; + }This won't necessarily work all the time. Once
BKOPS_STARTis issued, the card might finish GC and move to transfer state even before HPI can be sent. So just exit if the card is in transfer state already.
Right..But if didn't wait for prog-done, we can issue the HPI. (If didn't use Busy waiting flag)
Quoted 42 lines
In this context, kdorfman's comments on "mmc:fix HPI execution sequence" makes sense.
Quoted 38 lines
drivers/mmc/core/core.c +38
-0+ + err =mmc_interrupt_hpi (card); + +done: +mmc_card_clr_doing_bkops (card); + +return err; +} +EXPORT_SYMBOL (mmc_stop_bkops); + +int mmc_read_bkops_status (struct mmc_card *card) +{ +int err; +u8 ext_csd[512 ]; + +mmc_claim_host (card->host); + err =mmc_send_ext_csd (card, ext_csd); +mmc_release_host (card->host); +if (err) +return err; + + card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS ]; + card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXCEPTION_STATUS ]; + +return 0 ; +} +EXPORT_SYMBOL (mmc_read_bkops_status); + +int mmc_is_exception_event (struct mmc_card *card,unsigned int value) +{ +int err; + + err =mmc_read_bkops_status (card); +if (err) { +pr_err ("%s: Didn't read bkops status : %d\n" , +mmc_hostname (card->host), err); +return 0 ; + }
Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 636
Quoted 4 lines
drivers/mmc/core/core.c +4
-0+ +/* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */ +if (card->ext_csd.rev ==5 ) +return 1 ;Please swap the order in which you are doing this.
For eMMC4.41, we can save themmc_read_bkops_statusatleast for 4.41 card for _every_ request, which is not used.
If card is eMMC4.41, how did you check bkops-status? In eMCM4.41, also check the bkops-status level.
Quoted 54 lines
Quoted 43 lines
drivers/mmc/core/core.c +12
-0+ +return (card->ext_csd.raw_exception_status & value) ?1 :0 ; +} +EXPORT_SYMBOL (mmc_is_exception_event); + +/** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer @@ -2382,6 +2542,12 @@ int mmc_pm_notify(struct notifier_block *notify_block,switch (mode) {case PM_HIBERNATION_PREPARE :case PM_SUSPEND_PREPARE : +if (host->card &&mmc_card_mmc (host->card) && +mmc_card_doing_bkops (host->card)) { +mmc_interrupt_hpi (host->card); +mmc_card_clr_doing_bkops (host->card); + } +cancel_delayed_work_sync (&host->start_bkops);spin_lock_irqsave (&host->lock, flags); host->rescan_disable =1 ;drivers/mmc/core/host.c +1
-0@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)spin_lock_init (&host->lock);init_waitqueue_head (&host->wq);INIT_DELAYED_WORK (&host->detect, mmc_rescan); +INIT_DELAYED_WORK (&host->start_bkops, mmc_start_periodic_bkops);#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify;#endif drivers/mmc/core/mmc.c +0
-0@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) }if (card->ext_csd.rev >=5 ) {drivers/mmc/core/mmc.c static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) · line 475
Quoted 10 lines
drivers/mmc/core/mmc.c +10
-0+/* check whether the eMMC card support BKOPS */ +if (ext_csd[EXT_CSD_BKOPS_SUPPORT ] &0x1 ) { + card->ext_csd.bkops =1 ; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN ]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS ]; +if (!card->ext_csd.bkops_en && + card->host->caps2 &MMC_CAP2_INIT_BKOPS ) { + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_EN ,1 ,0 );
Quoted 8 lines
I am not too comfortable tying a OTP register setting to a host controller capability.
What if I had multiple instances of MMC and reuse the same HC, and each needs a different
setting ? Or the same HC used in multiple SoCs ?
A sysfs entry would be better - program the INIT when a user explicitly sets "enable_bkops" for the device
that is being used.
Actually, at first time i didn't consider whether bkops is enabled or not. Some card can be disabled for bkops enable bit.
If INIT_BKOPS is set, user didn't consider whether bkops is enabled or not. because that's set to enable.
Right, this is used sysfs..but I think it's problem what is prefrence..
Quoted 186 lines
Quoted 186 lines
drivers/mmc/core/mmc.c +8
-0+if (err) +pr_warning ("%s: Enabling BKOPS failed\n" , +mmc_hostname (card->host)); +else + card->ext_csd.bkops_en =1 ; + } + } +/* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES ] &0x1 ) { card->ext_csd.hpi =1 ;drivers/mmc/core/mmc_ops.c +4
-0@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,if (err)return err; +/* No need to check card status in case of BKOPS switch*/ +if (index ==EXT_CSD_BKOPS_START ) +return 0 ; +/* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status);include/linux/mmc/card.h +16
-0@@ -76,6 +76,9 @@ struct mmc_ext_csd {bool hpi_en;/* HPI enablebit */ bool hpi;/* HPI support bit */ unsigned int hpi_cmd;/* cmd used as HPI */ +bool bkops;/* background support bit */ +bool bkops_en;/* background enable bit */ +u8 raw_exception_status;/* 53 */ unsigned int data_sector_size;/* 512 bytes or 4KB */ unsigned int data_tag_unit_size;/* DATA TAG UNIT size */ unsigned int boot_ro_lock;/* ro lock support */ @@ -93,6 +96,7 @@ struct mmc_ext_csd {u8 raw_sec_erase_mult;/* 230 */ u8 raw_sec_feature_support;/* 231 */ u8 raw_trim_mult;/* 232 */ +u8 raw_bkops_status;/* 246 */ u8 raw_sectors[4 ];/* 212 - 4 bytes */ unsigned int feature_support;@@ -225,6 +229,9 @@ struct mmc_card {#define MMC_CARD_REMOVED (1<<7)/* card has been removed */ #define MMC_STATE_HIGHSPEED_200 (1<<8)/* card is in HS200 mode */ #define MMC_STATE_SLEEP (1<<9)/* card is in sleep state */ +#define MMC_STATE_NEED_BKOPS (1<<10)/* card need to do BKOPS */ +#define MMC_STATE_DOING_BKOPS (1<<11)/* card is doing BKOPS */ +#define MMC_STATE_CHECK_BKOPS (1<<12)/* card need to check BKOPS */ unsigned int quirks;/* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0)/* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)/* use func->cur_blksize */ @@ -391,6 +398,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_ext_capacity (c) ((c)->state & MMC_CARD_SDXC)#define mmc_card_removed (c) ((c) && ((c)->state & MMC_CARD_REMOVED))#define mmc_card_is_sleep (c) ((c)->state & MMC_STATE_SLEEP) +#define mmc_card_need_bkops (c) ((c)->state & MMC_STATE_NEED_BKOPS) +#define mmc_card_doing_bkops (c) ((c)->state & MMC_STATE_DOING_BKOPS) +#define mmc_card_check_bkops (c) ((c)->state & MMC_STATE_CHECK_BKOPS)#define mmc_card_set_present (c) ((c)->state |= MMC_STATE_PRESENT)#define mmc_card_set_readonly (c) ((c)->state |= MMC_STATE_READONLY)@@ -403,7 +413,13 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_set_ext_capacity (c) ((c)->state |= MMC_CARD_SDXC)#define mmc_card_set_removed (c) ((c)->state |= MMC_CARD_REMOVED)#define mmc_card_set_sleep (c) ((c)->state |= MMC_STATE_SLEEP) +#define mmc_card_set_need_bkops (c) ((c)->state |= MMC_STATE_NEED_BKOPS) +#define mmc_card_set_doing_bkops (c) ((c)->state |= MMC_STATE_DOING_BKOPS) +#define mmc_card_set_check_bkops (c) ((c)->state |= MMC_STATE_CHECK_BKOPS) +#define mmc_card_clr_need_bkops (c) ((c)->state &= ~MMC_STATE_NEED_BKOPS) +#define mmc_card_clr_doing_bkops (c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) +#define mmc_card_clr_check_bkops (c) ((c)->state &= ~MMC_STATE_CHECK_BKOPS)#define mmc_card_clr_sleep (c) ((c)->state &= ~MMC_STATE_SLEEP)/* * Quirk add/remove for MMC products. include/linux/mmc/core.h +5
-0@@ -134,6 +134,9 @@ struct mmc_host;struct mmc_card ;struct mmc_async_req ; +extern int mmc_stop_bkops (struct mmc_card *); +extern int mmc_read_bkops_status (struct mmc_card *); +extern int mmc_is_exception_event (struct mmc_card *,unsigned int );extern struct mmc_async_req *mmc_start_req (struct mmc_host *,struct mmc_async_req *,int *);extern int mmc_interrupt_hpi (struct mmc_card *);@@ -163,6 +166,8 @@ extern int mmc_can_sanitize(struct mmc_card *card);extern int mmc_can_secure_erase_trim (struct mmc_card *card);extern int mmc_erase_group_aligned (struct mmc_card *card,unsigned int from,unsigned int nr); +extern void mmc_start_periodic_bkops (struct work_struct *work); +extern void mmc_start_bkops (struct mmc_card *card);extern unsigned int mmc_calc_max_discard (struct mmc_card *card);extern int mmc_set_blocklen (struct mmc_card *card,unsigned int blocklen);include/linux/mmc/host.h +4
-0@@ -238,6 +238,8 @@ struct mmc_host {#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7)/* Use the broken voltage */ #define MMC_CAP2_DETECT_ON_ERR (1 << 8)/* On I/O err check card removal */ #define MMC_CAP2_HC_ERASE_SZ (1 << 9)/* High-capacity erase size */ +#define MMC_CAP2_INIT_BKOPS (1 << 10)/* To enable BKOPS */ +#define MMC_CAP2_BKOPS (1 << 11)/* BKOPS supported */ mmc_pm_flag_t pm_caps;/* supported pm features */ unsigned int power_notify_type;@@ -320,6 +322,8 @@ struct mmc_host {unsigned int actual_clock;/* Actual HC clock rate */ +struct delayed_work start_bkops;/* Periodic bkops start */ +unsigned long private[0 ]____cacheline_aligned ; };include/linux/mmc/mmc.h +18
-0@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode)#define R1_CURRENT_STATE (x) ((x & 0x00001E00) >> 9)/* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8)/* sx, a */ #define R1_SWITCH_ERROR (1 << 7)/* sx, c */ +#define R1_EXCEPTION_EVENT (1 << 6)/* sx, a */ #define R1_APP_CMD (1 << 5)/* sr, c */ #define R1_STATE_IDLE 0@@ -274,12 +275,15 @@ struct _mmc_csd {#define EXT_CSD_FLUSH_CACHE 32/* W */ #define EXT_CSD_CACHE_CTRL 33/* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34/* R/W */ +#define EXT_CSD_EXCEPTION_STATUS 54/* RO */ #define EXT_CSD_DATA_SECTOR_SIZE 61/* R */ #define EXT_CSD_GP_SIZE_MULT 143/* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156/* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160/* RO */ #define EXT_CSD_HPI_MGMT 161/* R/W */ #define EXT_CSD_RST_N_FUNCTION 162/* R/W */ +#define EXT_CSD_BKOPS_EN 163/* R/W */ +#define EXT_CSD_BKOPS_START 164/* W */ #define EXT_CSD_SANITIZE_START 165/* W */ #define EXT_CSD_WR_REL_PARAM 166/* RO */ #define EXT_CSD_BOOT_WP 173/* R/W */ @@ -313,11 +317,13 @@ struct _mmc_csd {#define EXT_CSD_PWR_CL_200_360 237/* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238/* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239/* RO */ +#define EXT_CSD_BKOPS_STATUS 246/* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247/* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248/* RO */ #define EXT_CSD_CACHE_SIZE 249/* RO, 4 bytes */ #define EXT_CSD_TAG_UNIT_SIZE 498/* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499/* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502/* RO */ #define EXT_CSD_HPI_FEATURES 503/* RO */ /* @@ -386,4 +392,18 @@ struct _mmc_csd {#define MMC_SWITCH_MODE_CLEAR_BITS 0x02/* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03/* Set target to value */ +/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +#define EXT_CSD_BKOPS_LEVEL_3 0x3 + +/* +* EXCEPTION_EVENT_STATUS field (eMMC4.5) +*/ +#define EXT_CSD_URGENT_BKOPS BIT(0) +#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
Quoted 8 lines
include/linux/mmc/mmc.h struct _mmc_csd { · line 409
Quoted 3 lines
include/linux/mmc/mmc.h +2
-0+#define EXT_CSD_PACKED_FAILURE BIT(3) +#endif /* LINUX_MMC_MMC_H */ Overall, my significant concern is about performance.
IIUC, There is aext_csdquery during the execution of _every_ request
- this is far too obsessive and could kill throughput.
I didn't find the performance issue. didn't _every_ request..only check to set bkops_need_check.
Quoted 2 lines
A more pragmatic approach would be to trigger on a threshold of number of writes or discards (ex: After 1M sector writes)
I will try to this approach.
Quoted 4 lines
This means that a predominantly read only disk, which wouldn't need any BKOPS, wouldn't have any overhead.
Let me know if my assumption is incorrect.
Thanks for reviwe.
Best Regards,
Jaehoon Chung
Quoted 7 lines
~Venkat.
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Venkat,
Quoted 26 lines
Quoted 17 lines
Quoted 17 lines
drivers/mmc/core/core.c +16
-0+static void mmc_send_bkops_cmd (struct mmc_card *card) +{ +int err; + +BUG_ON (!card); + + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_START ,1 ,0 ); +if (err) { +pr_warning ("%s: error %d starting bkops\n" , +mmc_hostname (card->host), err); +mmc_card_clr_need_bkops (card); +return ; + } + +mmc_card_clr_need_bkops (card);Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 275
Quoted 5 lines
drivers/mmc/core/core.c +5
-0+mmc_card_set_doing_bkops (card); + +} + +void mmc_start_periodic_bkops (struct work_struct *work)There's nothing periodic about this function, by looking at the contents. Maybe this one should be called
mmc_start_bkops..
Quoted 2 lines
Well...i will checked this point..i tested with eMMC4.5 card...In my case, working this function. But in your case, didn't work nothing..i will rework to this point after debugging.
Could you explain more detail? In my case, it's working at every 5sec.
Quoted 8 lines
Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 280
Quoted 7 lines
drivers/mmc/core/core.c +5
-0+{ + struct mmc_host *host = container_of(work, struct mmc_host, + start_bkops.work); + +mmc_card_set_check_bkops (host->card);Why is this being set here. The condition should be in the caller context.
We need to read bkops-status register. so card is set to check-bkops.
Quoted 36 lines
Quoted 11 lines
Quoted 11 lines
drivers/mmc/core/core.c +10
-0+ +mmc_claim_host (host); +mmc_start_bkops (host->card); +mmc_release_host (host); +} +EXPORT_SYMBOL (mmc_start_periodic_bkops); + +/** +* mmc_start_bkops - start BKOPS for supported cards +* @card: MMC card to start BKOPS Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 296
Quoted 6 lines
+ *
+ * Start background operations whenever requested. + * when the urgent BKOPS bit is set in a R1 command response + * then background operations should be started immediately.drivers/mmc/core/core.c +2
-0+*/ +void mmc_start_bkops (struct mmc_card *card).. and this one should be called
__mmc_start_bkops()?Sure..i will change that.
Quoted 13 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 306
Quoted 11 lines
drivers/mmc/core/core.c +10
-0+{ +BUG_ON (!card); +if (!card->ext_csd.bkops_en || !(card->host->caps2 &MMC_CAP2_BKOPS )) +return ; + +if (mmc_card_check_bkops (card)) { +mmc_card_clr_check_bkops (card); +if (mmc_is_exception_event (card,EXT_CSD_URGENT_BKOPS )) { +if (card->ext_csd.raw_bkops_status) +mmc_card_set_need_bkops (card);This breaks abstraction. Why check
ext_csdeven afterURGENT_BKOPSis set ?
Quoted 2 lines
You means that need not to check
ext_csd?
Well I didn't think so, we need to check bkops-status register
When URGENT_BKOPS is triggered, we didn't know which level.
It's just guessing Level-3 or Level-2.
In my case, status should be level-1 or level-0.
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
drivers/mmc/core/core.c +11
-0+ }else +mmc_card_clr_need_bkops (card); + } + +/* +* If card_need_bkops_flag didn't set, then do nothing just +* return +*/ +if (mmc_card_doing_bkops (card) || !mmc_card_need_bkops (card)) + goto check_bkops; +
Quoted 8 lines
Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 321
Quoted 4 lines
drivers/mmc/core/core.c +4
-0+mmc_send_bkops_cmd (card); + +check_bkops: +queue_delayed_work (system_nrt_wq, &card->host->start_bkops,5 *HZ );IIUC,
queue_delayed_work->start_bkops=mmc_start_periodic_bkops->mmc_start_bkops->queue_delayed_work
.. ad infinitum ?
If required the request, then it should be stopped.
Quoted 395 lines
Actually, i want to get review for this point..How did you think about?
Quoted 62 lines
Quoted 62 lines
drivers/mmc/core/core.c +36
-2+} +EXPORT_SYMBOL (mmc_start_bkops); +static void mmc_wait_done (struct mmc_request *mrq) {complete (&mrq->completion);@@ -348,8 +425,10 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,struct mmc_async_req *data = host->areq;/* Prepare a new request */ -if (areq) +if (areq) { +cancel_delayed_work_sync (&host->start_bkops);mmc_pre_req (host, areq->mrq, !host->areq); + }if (host->areq) {mmc_wait_for_req_done (host, host->areq->mrq);@@ -359,8 +438,11 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,if (!err && areq) start_err =__mmc_start_req (host, areq->mrq); -if (host->areq) +if (host->areq) {mmc_post_req (host, host->areq->mrq,0 ); +if (!areq && host->areq &&mmc_card_mmc (host->card)) +mmc_start_bkops (host->card); + }/* Cancel a prepared request if it was not started. */ if ((err || start_err) && areq)@@ -480,6 +562,84 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retriesEXPORT_SYMBOL (mmc_wait_for_cmd);/** +* mmc_stop_bkops - stop ongoing BKOPS +* @card: MMC card to check BKOPS +* +* Send HPI command to interrupt ongoing background operations, +* to allow rapid servicing of foreground operations,e.g. read/ +* writes. Wait until the card comes out of the programming state +* to avoid errors in servicing read/write requests. +*/ +int mmc_stop_bkops (struct mmc_card *card) +{ +int err =0 ; +unsigned int timeout =0x10000 ; +u32 status; + +BUG_ON (!card); +cancel_delayed_work_sync (&card->host->start_bkops); + +if (card->ext_csd.raw_bkops_status ==EXT_CSD_BKOPS_LEVEL_3 ) { + do { + if (timeout == 0) + break; + mmc_claim_host(card->host); + mmc_send_status(card, &status); + mmc_release_host(card->host); + + timeout--;Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 594
Quoted 4 lines
drivers/mmc/core/core.c +4
-0+ }while (R1_CURRENT_STATE (status) ==R1_STATE_PRG ); +if (timeout !=0 ) + goto done; + }This won't necessarily work all the time. Once
BKOPS_STARTis issued, the card might finish GC and move to transfer state even before HPI can be sent. So just exit if the card is in transfer state already.Right..But if didn't wait for prog-done, we can issue the HPI. (If didn't use Busy waiting flag)
Quoted 42 lines
In this context, kdorfman's comments on "mmc:fix HPI execution sequence" makes sense.
Quoted 38 lines
drivers/mmc/core/core.c +38
-0+ + err =mmc_interrupt_hpi (card); + +done: +mmc_card_clr_doing_bkops (card); + +return err; +} +EXPORT_SYMBOL (mmc_stop_bkops); + +int mmc_read_bkops_status (struct mmc_card *card) +{ +int err; +u8 ext_csd[512 ]; + +mmc_claim_host (card->host); + err =mmc_send_ext_csd (card, ext_csd); +mmc_release_host (card->host); +if (err) +return err; + + card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS ]; + card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXCEPTION_STATUS ]; + +return 0 ; +} +EXPORT_SYMBOL (mmc_read_bkops_status); + +int mmc_is_exception_event (struct mmc_card *card,unsigned int value) +{ +int err; + + err =mmc_read_bkops_status (card); +if (err) { +pr_err ("%s: Didn't read bkops status : %d\n" , +mmc_hostname (card->host), err); +return 0 ; + }Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 636
Quoted 4 lines
drivers/mmc/core/core.c +4
-0+ +/* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */ +if (card->ext_csd.rev ==5 ) +return 1 ;Please swap the order in which you are doing this.
For eMMC4.41, we can save themmc_read_bkops_statusatleast for 4.41 card for _every_ request, which is not used.If card is eMMC4.41, how did you check bkops-status? In eMCM4.41, also check the bkops-status level.
Quoted 54 lines
Quoted 43 lines
drivers/mmc/core/core.c +12
-0+ +return (card->ext_csd.raw_exception_status & value) ?1 :0 ; +} +EXPORT_SYMBOL (mmc_is_exception_event); + +/** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer @@ -2382,6 +2542,12 @@ int mmc_pm_notify(struct notifier_block *notify_block,switch (mode) {case PM_HIBERNATION_PREPARE :case PM_SUSPEND_PREPARE : +if (host->card &&mmc_card_mmc (host->card) && +mmc_card_doing_bkops (host->card)) { +mmc_interrupt_hpi (host->card); +mmc_card_clr_doing_bkops (host->card); + } +cancel_delayed_work_sync (&host->start_bkops);spin_lock_irqsave (&host->lock, flags); host->rescan_disable =1 ;drivers/mmc/core/host.c +1
-0@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)spin_lock_init (&host->lock);init_waitqueue_head (&host->wq);INIT_DELAYED_WORK (&host->detect, mmc_rescan); +INIT_DELAYED_WORK (&host->start_bkops, mmc_start_periodic_bkops);#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify;#endif drivers/mmc/core/mmc.c +0
-0@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) }if (card->ext_csd.rev >=5 ) {drivers/mmc/core/mmc.c static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) · line 475
Quoted 10 lines
drivers/mmc/core/mmc.c +10
-0+/* check whether the eMMC card support BKOPS */ +if (ext_csd[EXT_CSD_BKOPS_SUPPORT ] &0x1 ) { + card->ext_csd.bkops =1 ; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN ]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS ]; +if (!card->ext_csd.bkops_en && + card->host->caps2 &MMC_CAP2_INIT_BKOPS ) { + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_EN ,1 ,0 );Quoted 8 lines
I am not too comfortable tying a OTP register setting to a host controller capability.
What if I had multiple instances of MMC and reuse the same HC, and each needs a different
setting ? Or the same HC used in multiple SoCs ?
A sysfs entry would be better - program the INIT when a user explicitly sets "enable_bkops" for the device
that is being used.Actually, at first time i didn't consider whether bkops is enabled or not. Some card can be disabled for bkops enable bit.
IfINIT_BKOPSis set, user didn't consider whether bkops is enabled or not. because that's set to enable.
Right, this is used sysfs..but I think it's problem what is prefrence..Quoted 186 lines
Quoted 186 lines
drivers/mmc/core/mmc.c +8
-0+if (err) +pr_warning ("%s: Enabling BKOPS failed\n" , +mmc_hostname (card->host)); +else + card->ext_csd.bkops_en =1 ; + } + } +/* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES ] &0x1 ) { card->ext_csd.hpi =1 ;drivers/mmc/core/mmc_ops.c +4
-0@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,if (err)return err; +/* No need to check card status in case of BKOPS switch*/ +if (index ==EXT_CSD_BKOPS_START ) +return 0 ; +/* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status);include/linux/mmc/card.h +16
-0@@ -76,6 +76,9 @@ struct mmc_ext_csd {bool hpi_en;/* HPI enablebit */ bool hpi;/* HPI support bit */ unsigned int hpi_cmd;/* cmd used as HPI */ +bool bkops;/* background support bit */ +bool bkops_en;/* background enable bit */ +u8 raw_exception_status;/* 53 */ unsigned int data_sector_size;/* 512 bytes or 4KB */ unsigned int data_tag_unit_size;/* DATA TAG UNIT size */ unsigned int boot_ro_lock;/* ro lock support */ @@ -93,6 +96,7 @@ struct mmc_ext_csd {u8 raw_sec_erase_mult;/* 230 */ u8 raw_sec_feature_support;/* 231 */ u8 raw_trim_mult;/* 232 */ +u8 raw_bkops_status;/* 246 */ u8 raw_sectors[4 ];/* 212 - 4 bytes */ unsigned int feature_support;@@ -225,6 +229,9 @@ struct mmc_card {#define MMC_CARD_REMOVED (1<<7)/* card has been removed */ #define MMC_STATE_HIGHSPEED_200 (1<<8)/* card is in HS200 mode */ #define MMC_STATE_SLEEP (1<<9)/* card is in sleep state */ +#define MMC_STATE_NEED_BKOPS (1<<10)/* card need to do BKOPS */ +#define MMC_STATE_DOING_BKOPS (1<<11)/* card is doing BKOPS */ +#define MMC_STATE_CHECK_BKOPS (1<<12)/* card need to check BKOPS */ unsigned int quirks;/* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0)/* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)/* use func->cur_blksize */ @@ -391,6 +398,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_ext_capacity (c) ((c)->state & MMC_CARD_SDXC)#define mmc_card_removed (c) ((c) && ((c)->state & MMC_CARD_REMOVED))#define mmc_card_is_sleep (c) ((c)->state & MMC_STATE_SLEEP) +#define mmc_card_need_bkops (c) ((c)->state & MMC_STATE_NEED_BKOPS) +#define mmc_card_doing_bkops (c) ((c)->state & MMC_STATE_DOING_BKOPS) +#define mmc_card_check_bkops (c) ((c)->state & MMC_STATE_CHECK_BKOPS)#define mmc_card_set_present (c) ((c)->state |= MMC_STATE_PRESENT)#define mmc_card_set_readonly (c) ((c)->state |= MMC_STATE_READONLY)@@ -403,7 +413,13 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_set_ext_capacity (c) ((c)->state |= MMC_CARD_SDXC)#define mmc_card_set_removed (c) ((c)->state |= MMC_CARD_REMOVED)#define mmc_card_set_sleep (c) ((c)->state |= MMC_STATE_SLEEP) +#define mmc_card_set_need_bkops (c) ((c)->state |= MMC_STATE_NEED_BKOPS) +#define mmc_card_set_doing_bkops (c) ((c)->state |= MMC_STATE_DOING_BKOPS) +#define mmc_card_set_check_bkops (c) ((c)->state |= MMC_STATE_CHECK_BKOPS) +#define mmc_card_clr_need_bkops (c) ((c)->state &= ~MMC_STATE_NEED_BKOPS) +#define mmc_card_clr_doing_bkops (c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) +#define mmc_card_clr_check_bkops (c) ((c)->state &= ~MMC_STATE_CHECK_BKOPS)#define mmc_card_clr_sleep (c) ((c)->state &= ~MMC_STATE_SLEEP)/* * Quirk add/remove for MMC products. include/linux/mmc/core.h +5
-0@@ -134,6 +134,9 @@ struct mmc_host;struct mmc_card ;struct mmc_async_req ; +extern int mmc_stop_bkops (struct mmc_card *); +extern int mmc_read_bkops_status (struct mmc_card *); +extern int mmc_is_exception_event (struct mmc_card *,unsigned int );extern struct mmc_async_req *mmc_start_req (struct mmc_host *,struct mmc_async_req *,int *);extern int mmc_interrupt_hpi (struct mmc_card *);@@ -163,6 +166,8 @@ extern int mmc_can_sanitize(struct mmc_card *card);extern int mmc_can_secure_erase_trim (struct mmc_card *card);extern int mmc_erase_group_aligned (struct mmc_card *card,unsigned int from,unsigned int nr); +extern void mmc_start_periodic_bkops (struct work_struct *work); +extern void mmc_start_bkops (struct mmc_card *card);extern unsigned int mmc_calc_max_discard (struct mmc_card *card);extern int mmc_set_blocklen (struct mmc_card *card,unsigned int blocklen);include/linux/mmc/host.h +4
-0@@ -238,6 +238,8 @@ struct mmc_host {#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7)/* Use the broken voltage */ #define MMC_CAP2_DETECT_ON_ERR (1 << 8)/* On I/O err check card removal */ #define MMC_CAP2_HC_ERASE_SZ (1 << 9)/* High-capacity erase size */ +#define MMC_CAP2_INIT_BKOPS (1 << 10)/* To enable BKOPS */ +#define MMC_CAP2_BKOPS (1 << 11)/* BKOPS supported */ mmc_pm_flag_t pm_caps;/* supported pm features */ unsigned int power_notify_type;@@ -320,6 +322,8 @@ struct mmc_host {unsigned int actual_clock;/* Actual HC clock rate */ +struct delayed_work start_bkops;/* Periodic bkops start */ +unsigned long private[0 ]____cacheline_aligned ; };include/linux/mmc/mmc.h +18
-0@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode)#define R1_CURRENT_STATE (x) ((x & 0x00001E00) >> 9)/* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8)/* sx, a */ #define R1_SWITCH_ERROR (1 << 7)/* sx, c */ +#define R1_EXCEPTION_EVENT (1 << 6)/* sx, a */ #define R1_APP_CMD (1 << 5)/* sr, c */ #define R1_STATE_IDLE 0@@ -274,12 +275,15 @@ struct _mmc_csd {#define EXT_CSD_FLUSH_CACHE 32/* W */ #define EXT_CSD_CACHE_CTRL 33/* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34/* R/W */ +#define EXT_CSD_EXCEPTION_STATUS 54/* RO */ #define EXT_CSD_DATA_SECTOR_SIZE 61/* R */ #define EXT_CSD_GP_SIZE_MULT 143/* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156/* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160/* RO */ #define EXT_CSD_HPI_MGMT 161/* R/W */ #define EXT_CSD_RST_N_FUNCTION 162/* R/W */ +#define EXT_CSD_BKOPS_EN 163/* R/W */ +#define EXT_CSD_BKOPS_START 164/* W */ #define EXT_CSD_SANITIZE_START 165/* W */ #define EXT_CSD_WR_REL_PARAM 166/* RO */ #define EXT_CSD_BOOT_WP 173/* R/W */ @@ -313,11 +317,13 @@ struct _mmc_csd {#define EXT_CSD_PWR_CL_200_360 237/* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238/* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239/* RO */ +#define EXT_CSD_BKOPS_STATUS 246/* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247/* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248/* RO */ #define EXT_CSD_CACHE_SIZE 249/* RO, 4 bytes */ #define EXT_CSD_TAG_UNIT_SIZE 498/* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499/* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502/* RO */ #define EXT_CSD_HPI_FEATURES 503/* RO */ /* @@ -386,4 +392,18 @@ struct _mmc_csd {#define MMC_SWITCH_MODE_CLEAR_BITS 0x02/* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03/* Set target to value */ +/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +#define EXT_CSD_BKOPS_LEVEL_3 0x3 + +/* +* EXCEPTION_EVENT_STATUS field (eMMC4.5) +*/ +#define EXT_CSD_URGENT_BKOPS BIT(0) +#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)Quoted 8 lines
include/linux/mmc/mmc.h struct _mmc_csd { · line 409
Quoted 3 lines
include/linux/mmc/mmc.h +2
-0+#define EXT_CSD_PACKED_FAILURE BIT(3) +#endif /* LINUX_MMC_MMC_H */ Overall, my significant concern is about performance.
IIUC, There is aext_csdquery during the execution of _every_ request
- this is far too obsessive and could kill throughput.
Quoted 4 lines
I didn't find the performance issue. didn't _every_ request..only check to set
bkops_need_check.Quoted 2 lines
A more pragmatic approach would be to trigger on a threshold of number of writes or discards (ex: After 1M sector writes)
In this case, we need to use bkops feature, I think that just using discard. How think about? if you have other opinion, let me know, plz. Then i will apply to next-patch.
Best Regards,
Jaehoon Chung
Quoted 27 lines
I will try to this approach.
Quoted 4 lines
This means that a predominantly read only disk, which wouldn't need any BKOPS, wouldn't have any overhead.
Let me know if my assumption is incorrect.
Thanks for reviwe.
Best Regards,
Jaehoon ChungQuoted 7 lines
~Venkat.
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Jaehoon,
Please find comments inline below.
Quoted 68 lines · Jaehoon Chung
Enable eMMC background operations (BKOPS) feature.
If
URGENT_BKOPSis set after a response, note that BKOPS are required. After all I/O requests are finished, run BKOPS if required. Should read/write operations be requested during BKOPS, first issue HPI to interrupt the ongoing BKOPS and then service the request.
If BKOPS-STATUS is upper than LEVEL2, need to check until clear the BKOPS-STATUS vaule.If you want to enable this feature, set
MMC_CAP2_BKOPS. And if you want to set theBKOPS_ENbit inext_csdregister, use theMMC_CAP2_INIT_BKOPS.When
BKOPS_STATUSis Level-3, if we're waiting for done, it spent 60~80sec. So Added timeout value. if timeout value is set to 0, send hpi command.Signed-off-by Jaehoon Chung<[email protected]>Signed-off-by Kyungmin Park<[email protected]>---
Changelog V8:
- Removehost->lockspin lock reviewed by Adrian
- Support periodic start bkops
- whenbkops_statusis level-3, if timeout is set to 0, send hpi.
- Move the start-bkops point
Changelog V7:
- Use HPI command when issuedURGENT_BKOPS
- Recheck until clearing the bkops-status bit.
Changelog V6:
- Add the flag of check-bkops-status.
(For fixingasync_reqproblem)
- Add the capability forMMC_CAP2_INIT_BKOPS.
(When unset thebkops_enbit inext_csdregister)
- modify the wrong condition.
Changelog V5:
- Rebase based on the latest mmc-next.
- modify codes based-on Chris's comment
Changelog V4:
- Addmmc_read_bkops_status
- WhenURGENT_BKOPS(level2-3), didn't use HPI command.
- Inmmc_switch(), use R1B/R1 according to level.
Changelog V3:
- move the bkops setting's location inmmc_blk_issue_rw_rq
- modify condition checking
-bkops_enis assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"
- remove the unused code
- changepr_debuginstead ofpr_warninmmc_send_hpi_cmd
- Add the Future consideration suggested by Per
Changelog V2:
- UseEXCEPTION_STATUSinstead ofURGENT_BKOPS
- Add function to checkException_status(for eMMC4.5)--- drivers/mmc/card/queue.c | 2 + drivers/mmc/core/core.c | 170 +++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/core/host.c | 1 + drivers/mmc/core/mmc.c | 18 +++++ drivers/mmc/core/mmc_ops.c | 4 + include/linux/mmc/card.h | 16 ++++ include/linux/mmc/core.h | 5 ++ include/linux/mmc/host.h | 4 + include/linux/mmc/mmc.h | 20 +++++ 9 files changed, 238 insertions(+), 2 deletions(-)drivers/mmc/card/queue.c +0
-0
drivers/mmc/card/queue.c static int mmc_queue_thread(void *d) · line 70
Quoted 5 lines
drivers/mmc/card/queue.c +2
-0@@ -66,6 +66,8 @@ static int mmc_queue_thread(void *d)spin_unlock_irq (q->queue_lock);if (req || mq->mqrq_prev->req) { +if (mmc_card_doing_bkops (mq->card)) +mmc_stop_bkops (mq->card);
mmc_stop_bkops() may fail and can return an error but we are ignoring it here. What if this function has returned error which means BKOPS may still be running in card and if you go ahead and issue another read/write request?
Quoted 8 lines
drivers/mmc/card/queue.c +0
-0set_current_state (TASK_RUNNING ); mq->issue_fn (mq, req); }else {drivers/mmc/core/core.c +0
-0
drivers/mmc/core/core.c void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) · line 182
Quoted 8 lines
drivers/mmc/core/core.c +5
-0@@ -175,6 +175,13 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)if (mrq->done) mrq->done (mrq); +/* +* Check BKOPS urgency from each R1 response +*/ +if (host->card&&mmc_card_mmc (host->card)&& + (cmd->resp[0 ]&R1_EXCEPTION_EVENT ))
Shouldn't you make sure that response expected for this commands is R1/R1b? Only in that case cmd->resp[0] will have the device status.
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 255
Quoted 10 lines
drivers/mmc/core/core.c +3
-0+mmc_card_set_check_bkops (host->card); +mmc_host_clk_release (host); } }@@ -245,6 +252,76 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) host->ops->request (host, mrq); } +static void mmc_send_bkops_cmd (struct mmc_card *card)
I guess name should be mmc_send_bkops_start_cmd().
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 266
Quoted 11 lines
drivers/mmc/core/core.c +11
-0+{ +int err; + +BUG_ON (!card); + + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_START ,1 ,0 ); +if (err) { +pr_warning ("%s: error %d starting bkops\n" , +mmc_hostname (card->host), err); +mmc_card_clr_need_bkops (card);
In case of failure, why are we clearing the NEED_BKOPS flag? You still need the BKOPS, correct?
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 272
Quoted 6 lines
drivers/mmc/core/core.c +6
-0+return ; + } + +mmc_card_clr_need_bkops (card); +mmc_card_set_doing_bkops (card); +
You can remove this extra line here.
Quoted 39 lines
drivers/mmc/core/core.c +39
-0+} + +void mmc_start_periodic_bkops (struct work_struct *work) +{ + struct mmc_host *host = container_of(work, struct mmc_host, + start_bkops.work); + +mmc_card_set_check_bkops (host->card); + +mmc_claim_host (host); +mmc_start_bkops (host->card); +mmc_release_host (host); +} +EXPORT_SYMBOL (mmc_start_periodic_bkops); + +/** +* mmc_start_bkops - start BKOPS for supported cards +* @card: MMC card to start BKOPS +* +* Start background operations whenever requested. +* when the urgent BKOPS bit is set in a R1 command response +* then background operations should be started immediately. +*/ +void mmc_start_bkops (struct mmc_card *card) +{ +BUG_ON (!card); +if (!card->ext_csd.bkops_en || !(card->host->caps2&MMC_CAP2_BKOPS )) +return ; + +if (mmc_card_check_bkops (card)) { +mmc_card_clr_check_bkops (card); +if (mmc_is_exception_event (card,EXT_CSD_URGENT_BKOPS )) { +if (card->ext_csd.raw_bkops_status) +mmc_card_set_need_bkops (card); + }else +mmc_card_clr_need_bkops (card); + } + +/*
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+* If card_need_bkops_flag didn't set, then do nothing just +* return +*/ +if (mmc_card_doing_bkops (card) || !mmc_card_need_bkops (card)) + goto check_bkops; + +mmc_send_bkops_cmd (card); + +check_bkops: +queue_delayed_work (system_nrt_wq,&card->host->start_bkops,5 *HZ );
Can we use the deferrable timer for this delayed work? If it's not deferrable and if CPU is some low power state, it has to wakeup and serve this timer on it's expiration. Better make it deferrable so it won't wakeup the system when timer expires.
Also, just wondering, how came to this 5 sec timeout?
Quoted 37 lines
drivers/mmc/core/core.c +12
-2+} +EXPORT_SYMBOL (mmc_start_bkops); +static void mmc_wait_done (struct mmc_request *mrq) {complete (&mrq->completion);@@ -348,8 +425,10 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,struct mmc_async_req *data = host->areq;/* Prepare a new request */ -if (areq) +if (areq) { +cancel_delayed_work_sync (&host->start_bkops);mmc_pre_req (host, areq->mrq, !host->areq); + }if (host->areq) {mmc_wait_for_req_done (host, host->areq->mrq);@@ -359,8 +438,11 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,if (!err&& areq) start_err =__mmc_start_req (host, areq->mrq); -if (host->areq) +if (host->areq) {mmc_post_req (host, host->areq->mrq,0 ); +if (!areq&& host->areq&&mmc_card_mmc (host->card)) +mmc_start_bkops (host->card); + }/* Cancel a prepared request if it was not started. */ if ((err || start_err)&& areq)@@ -480,6 +562,84 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retriesEXPORT_SYMBOL (mmc_wait_for_cmd);/** +* mmc_stop_bkops - stop ongoing BKOPS +* @card: MMC card to check BKOPS
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 576
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+* +* Send HPI command to interrupt ongoing background operations, +* to allow rapid servicing of foreground operations,e.g. read/ +* writes. Wait until the card comes out of the programming state +* to avoid errors in servicing read/write requests. +*/ +int mmc_stop_bkops (struct mmc_card *card) +{ +int err =0 ; +unsigned int timeout =0x10000 ;
How this 0x10000 value is calculated? Is there any defined timeout value for card to come out of programming after starting the BKOPS? if not, then let's wait indefinitely for it to come out of the programming state? Don't we wait indefinitely for write request?
Quoted 13 lines
drivers/mmc/core/core.c +13
-0+u32 status; + +BUG_ON (!card); +cancel_delayed_work_sync (&card->host->start_bkops); + +if (card->ext_csd.raw_bkops_status ==EXT_CSD_BKOPS_LEVEL_3 ) { + do { + if (timeout == 0) + break; + mmc_claim_host(card->host); + mmc_send_status(card,&status); + mmc_release_host(card->host); +
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 599
Quoted 10 lines
drivers/mmc/core/core.c +10
-0+ timeout--; + }while (R1_CURRENT_STATE (status) ==R1_STATE_PRG ); +if (timeout !=0 ) + goto done; + } + + err =mmc_interrupt_hpi (card); + +done: +mmc_card_clr_doing_bkops (card);
Here even if mmc_interrupt_hpi() fails, you are clearing the DOING_BKOPS flag which is not correct. Which should clear this flag if HPI issued successfully.
Quoted 281 lines
drivers/mmc/core/core.c +49
-0+ +return err; +} +EXPORT_SYMBOL (mmc_stop_bkops); + +int mmc_read_bkops_status (struct mmc_card *card) +{ +int err; +u8 ext_csd[512 ]; + +mmc_claim_host (card->host); + err =mmc_send_ext_csd (card, ext_csd); +mmc_release_host (card->host); +if (err) +return err; + + card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS ]; + card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXCEPTION_STATUS ]; + +return 0 ; +} +EXPORT_SYMBOL (mmc_read_bkops_status); + +int mmc_is_exception_event (struct mmc_card *card,unsigned int value) +{ +int err; + + err =mmc_read_bkops_status (card); +if (err) { +pr_err ("%s: Didn't read bkops status : %d\n" , +mmc_hostname (card->host), err); +return 0 ; + } + +/* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */ +if (card->ext_csd.rev ==5 ) +return 1 ; + +return (card->ext_csd.raw_exception_status& value) ?1 :0 ; +} +EXPORT_SYMBOL (mmc_is_exception_event); + +/** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer @@ -2382,6 +2542,12 @@ int mmc_pm_notify(struct notifier_block *notify_block,switch (mode) {case PM_HIBERNATION_PREPARE :case PM_SUSPEND_PREPARE : +if (host->card&&mmc_card_mmc (host->card)&& +mmc_card_doing_bkops (host->card)) { +mmc_interrupt_hpi (host->card); +mmc_card_clr_doing_bkops (host->card); + } +cancel_delayed_work_sync (&host->start_bkops);spin_lock_irqsave (&host->lock, flags); host->rescan_disable =1 ;drivers/mmc/core/host.c +1
-0@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)spin_lock_init (&host->lock);init_waitqueue_head (&host->wq);INIT_DELAYED_WORK (&host->detect, mmc_rescan); +INIT_DELAYED_WORK (&host->start_bkops, mmc_start_periodic_bkops);#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify;#endif drivers/mmc/core/mmc.c +18
-0@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) }if (card->ext_csd.rev>=5 ) { +/* check whether the eMMC card support BKOPS */ +if (ext_csd[EXT_CSD_BKOPS_SUPPORT ]&0x1 ) { + card->ext_csd.bkops =1 ; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN ]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS ]; +if (!card->ext_csd.bkops_en&& + card->host->caps2&MMC_CAP2_INIT_BKOPS ) { + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_EN ,1 ,0 ); +if (err) +pr_warning ("%s: Enabling BKOPS failed\n" , +mmc_hostname (card->host)); +else + card->ext_csd.bkops_en =1 ; + } + } +/* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES ]&0x1 ) { card->ext_csd.hpi =1 ;drivers/mmc/core/mmc_ops.c +4
-0@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,if (err)return err; +/* No need to check card status in case of BKOPS switch*/ +if (index ==EXT_CSD_BKOPS_START ) +return 0 ; +/* Must check status to be sure of no errors */ do { err = mmc_send_status(card,&status);include/linux/mmc/card.h +16
-0@@ -76,6 +76,9 @@ struct mmc_ext_csd {bool hpi_en;/* HPI enablebit */ bool hpi;/* HPI support bit */ unsigned int hpi_cmd;/* cmd used as HPI */ +bool bkops;/* background support bit */ +bool bkops_en;/* background enable bit */ +u8 raw_exception_status;/* 53 */ unsigned int data_sector_size;/* 512 bytes or 4KB */ unsigned int data_tag_unit_size;/* DATA TAG UNIT size */ unsigned int boot_ro_lock;/* ro lock support */ @@ -93,6 +96,7 @@ struct mmc_ext_csd {u8 raw_sec_erase_mult;/* 230 */ u8 raw_sec_feature_support;/* 231 */ u8 raw_trim_mult;/* 232 */ +u8 raw_bkops_status;/* 246 */ u8 raw_sectors[4 ];/* 212 - 4 bytes */ unsigned int feature_support;@@ -225,6 +229,9 @@ struct mmc_card {#define MMC_CARD_REMOVED (1<<7)/* card has been removed */ #define MMC_STATE_HIGHSPEED_200 (1<<8)/* card is in HS200 mode */ #define MMC_STATE_SLEEP (1<<9)/* card is in sleep state */ +#define MMC_STATE_NEED_BKOPS (1<<10)/* card need to do BKOPS */ +#define MMC_STATE_DOING_BKOPS (1<<11)/* card is doing BKOPS */ +#define MMC_STATE_CHECK_BKOPS (1<<12)/* card need to check BKOPS */ unsigned int quirks;/* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0)/* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)/* use func->cur_blksize */ @@ -391,6 +398,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_ext_capacity (c) ((c)->state& MMC_CARD_SDXC)#define mmc_card_removed (c) ((c)&& ((c)->state& MMC_CARD_REMOVED))#define mmc_card_is_sleep (c) ((c)->state& MMC_STATE_SLEEP) +#define mmc_card_need_bkops (c) ((c)->state& MMC_STATE_NEED_BKOPS) +#define mmc_card_doing_bkops (c) ((c)->state& MMC_STATE_DOING_BKOPS) +#define mmc_card_check_bkops (c) ((c)->state& MMC_STATE_CHECK_BKOPS)#define mmc_card_set_present (c) ((c)->state |= MMC_STATE_PRESENT)#define mmc_card_set_readonly (c) ((c)->state |= MMC_STATE_READONLY)@@ -403,7 +413,13 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_set_ext_capacity (c) ((c)->state |= MMC_CARD_SDXC)#define mmc_card_set_removed (c) ((c)->state |= MMC_CARD_REMOVED)#define mmc_card_set_sleep (c) ((c)->state |= MMC_STATE_SLEEP) +#define mmc_card_set_need_bkops (c) ((c)->state |= MMC_STATE_NEED_BKOPS) +#define mmc_card_set_doing_bkops (c) ((c)->state |= MMC_STATE_DOING_BKOPS) +#define mmc_card_set_check_bkops (c) ((c)->state |= MMC_STATE_CHECK_BKOPS) +#define mmc_card_clr_need_bkops (c) ((c)->state&= ~MMC_STATE_NEED_BKOPS) +#define mmc_card_clr_doing_bkops (c) ((c)->state&= ~MMC_STATE_DOING_BKOPS) +#define mmc_card_clr_check_bkops (c) ((c)->state&= ~MMC_STATE_CHECK_BKOPS)#define mmc_card_clr_sleep (c) ((c)->state&= ~MMC_STATE_SLEEP)/* * Quirk add/remove for MMC products. include/linux/mmc/core.h +5
-0@@ -134,6 +134,9 @@ struct mmc_host;struct mmc_card ;struct mmc_async_req ; +extern int mmc_stop_bkops (struct mmc_card *); +extern int mmc_read_bkops_status (struct mmc_card *); +extern int mmc_is_exception_event (struct mmc_card *,unsigned int );extern struct mmc_async_req *mmc_start_req (struct mmc_host *,struct mmc_async_req *,int *);extern int mmc_interrupt_hpi (struct mmc_card *);@@ -163,6 +166,8 @@ extern int mmc_can_sanitize(struct mmc_card *card);extern int mmc_can_secure_erase_trim (struct mmc_card *card);extern int mmc_erase_group_aligned (struct mmc_card *card,unsigned int from,unsigned int nr); +extern void mmc_start_periodic_bkops (struct work_struct *work); +extern void mmc_start_bkops (struct mmc_card *card);extern unsigned int mmc_calc_max_discard (struct mmc_card *card);extern int mmc_set_blocklen (struct mmc_card *card,unsigned int blocklen);include/linux/mmc/host.h +4
-0@@ -238,6 +238,8 @@ struct mmc_host {#define MMC_CAP2_BROKEN_VOLTAGE (1<< 7)/* Use the broken voltage */ #define MMC_CAP2_DETECT_ON_ERR (1<< 8)/* On I/O err check card removal */ #define MMC_CAP2_HC_ERASE_SZ (1<< 9)/* High-capacity erase size */ +#define MMC_CAP2_INIT_BKOPS (1<< 10)/* To enable BKOPS */ +#define MMC_CAP2_BKOPS (1<< 11)/* BKOPS supported */ mmc_pm_flag_t pm_caps;/* supported pm features */ unsigned int power_notify_type;@@ -320,6 +322,8 @@ struct mmc_host {unsigned int actual_clock;/* Actual HC clock rate */ +struct delayed_work start_bkops;/* Periodic bkops start */ +unsigned long private[0 ]____cacheline_aligned ; };include/linux/mmc/mmc.h +20
-1@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode)#define R1_CURRENT_STATE (x) ((x& 0x00001E00)>> 9)/* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1<< 8)/* sx, a */ #define R1_SWITCH_ERROR (1<< 7)/* sx, c */ +#define R1_EXCEPTION_EVENT (1<< 6)/* sx, a */ #define R1_APP_CMD (1<< 5)/* sr, c */ #define R1_STATE_IDLE 0@@ -274,12 +275,15 @@ struct _mmc_csd {#define EXT_CSD_FLUSH_CACHE 32/* W */ #define EXT_CSD_CACHE_CTRL 33/* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34/* R/W */ +#define EXT_CSD_EXCEPTION_STATUS 54/* RO */ #define EXT_CSD_DATA_SECTOR_SIZE 61/* R */ #define EXT_CSD_GP_SIZE_MULT 143/* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156/* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160/* RO */ #define EXT_CSD_HPI_MGMT 161/* R/W */ #define EXT_CSD_RST_N_FUNCTION 162/* R/W */ +#define EXT_CSD_BKOPS_EN 163/* R/W */ +#define EXT_CSD_BKOPS_START 164/* W */ #define EXT_CSD_SANITIZE_START 165/* W */ #define EXT_CSD_WR_REL_PARAM 166/* RO */ #define EXT_CSD_BOOT_WP 173/* R/W */ @@ -313,11 +317,13 @@ struct _mmc_csd {#define EXT_CSD_PWR_CL_200_360 237/* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238/* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239/* RO */ +#define EXT_CSD_BKOPS_STATUS 246/* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247/* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248/* RO */ #define EXT_CSD_CACHE_SIZE 249/* RO, 4 bytes */ #define EXT_CSD_TAG_UNIT_SIZE 498/* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499/* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502/* RO */ #define EXT_CSD_HPI_FEATURES 503/* RO */ /* @@ -386,4 +392,18 @@ struct _mmc_csd {#define MMC_SWITCH_MODE_CLEAR_BITS 0x02/* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03/* Set target to value */ +/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +#define EXT_CSD_BKOPS_LEVEL_3 0x3 + +/* +* EXCEPTION_EVENT_STATUS field (eMMC4.5) +*/ +#define EXT_CSD_URGENT_BKOPS BIT(0) +#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) +#define EXT_CSD_PACKED_FAILURE BIT(3) +#endif /* LINUX_MMC_MMC_H */ --To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 75 lines · Subhash Jadavani
Hi Jaehoon,
Please find comments inline below.
Quoted 70 lines · Jaehoon Chung
Enable eMMC background operations (BKOPS) feature.
If
URGENT_BKOPSis set after a response, note that BKOPS are required. After all I/O requests are finished, run BKOPS if required. Should read/write operations be requested during BKOPS, first issue HPI to interrupt the ongoing BKOPS and then service the request.
If BKOPS-STATUS is upper than LEVEL2, need to check until clear the BKOPS-STATUS vaule.If you want to enable this feature, set
MMC_CAP2_BKOPS. And if you want to set theBKOPS_ENbit inext_csdregister, use theMMC_CAP2_INIT_BKOPS.When
BKOPS_STATUSis Level-3, if we're waiting for done, it spent 60~80sec. So Added timeout value. if timeout value is set to 0, send hpi command.Signed-off-by Jaehoon Chung<[email protected]>Signed-off-by Kyungmin Park<[email protected]>---
Changelog V8:
- Removehost->lockspin lock reviewed by Adrian
- Support periodic start bkops
- whenbkops_statusis level-3, if timeout is set to 0, send hpi.
- Move the start-bkops point
Changelog V7:
- Use HPI command when issuedURGENT_BKOPS
- Recheck until clearing the bkops-status bit.
Changelog V6:
- Add the flag of check-bkops-status.
(For fixingasync_reqproblem)
- Add the capability forMMC_CAP2_INIT_BKOPS.
(When unset thebkops_enbit inext_csdregister)
- modify the wrong condition.
Changelog V5:
- Rebase based on the latest mmc-next.
- modify codes based-on Chris's comment
Changelog V4:
- Addmmc_read_bkops_status
- WhenURGENT_BKOPS(level2-3), didn't use HPI command.
- Inmmc_switch(), use R1B/R1 according to level.
Changelog V3:
- move the bkops setting's location inmmc_blk_issue_rw_rq
- modify condition checking
-bkops_enis assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"
- remove the unused code
- changepr_debuginstead ofpr_warninmmc_send_hpi_cmd
- Add the Future consideration suggested by Per
Changelog V2:
- UseEXCEPTION_STATUSinstead ofURGENT_BKOPS
- Add function to checkException_status(for eMMC4.5)--- drivers/mmc/card/queue.c | 2 + drivers/mmc/core/core.c | 170 +++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/core/host.c | 1 + drivers/mmc/core/mmc.c | 18 +++++ drivers/mmc/core/mmc_ops.c | 4 + include/linux/mmc/card.h | 16 ++++ include/linux/mmc/core.h | 5 ++ include/linux/mmc/host.h | 4 + include/linux/mmc/mmc.h | 20 +++++ 9 files changed, 238 insertions(+), 2 deletions(-)drivers/mmc/card/queue.c +0
-0@@ -66,6 +66,8 @@ static int mmc_queue_thread(void *d)spin_unlock_irq (q->queue_lock);
Quoted 4 lines
drivers/mmc/card/queue.c static int mmc_queue_thread(void *d) · line 70
Quoted 3 lines
drivers/mmc/card/queue.c +2
-0if (req || mq->mqrq_prev->req) { +if (mmc_card_doing_bkops (mq->card)) +mmc_stop_bkops (mq->card);
mmc_stop_bkops()may fail and can return an error but we are ignoring it here. What if this function has returned error which means BKOPS may still be running in card and if you go ahead and issue another read/write request?
Great..i didn't think that..I will consider this point. Thanks.
Quoted 11 lines
Quoted 11 lines
drivers/mmc/card/queue.c +0
-0set_current_state (TASK_RUNNING ); mq->issue_fn (mq, req); }else {drivers/mmc/core/core.c +0
-0@@ -175,6 +175,13 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)if (mrq->done) mrq->done (mrq);
Quoted 6 lines
drivers/mmc/core/core.c void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
Quoted 5 lines
drivers/mmc/core/core.c +5
-0+/* +* Check BKOPS urgency from each R1 response +*/ +if (host->card&&mmc_card_mmc (host->card)&& + (cmd->resp[0 ]&R1_EXCEPTION_EVENT ))Shouldn't you make sure that response expected for this commands is R1/R1b? Only in that case cmd->resp[0] will have the device status.
Right..this point will be also modified..
Quoted 11 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 255
Quoted 10 lines
drivers/mmc/core/core.c +3
-0+mmc_card_set_check_bkops (host->card); +mmc_host_clk_release (host); } }@@ -245,6 +252,76 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) host->ops->request (host, mrq); } +static void mmc_send_bkops_cmd (struct mmc_card *card)I guess name should be
mmc_send_bkops_start_cmd().
Quoted 12 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 266
Quoted 11 lines
drivers/mmc/core/core.c +11
-0+{ +int err; + +BUG_ON (!card); + + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_START ,1 ,0 ); +if (err) { +pr_warning ("%s: error %d starting bkops\n" , +mmc_hostname (card->host), err); +mmc_card_clr_need_bkops (card);In case of failure, why are we clearing the
NEED_BKOPSflag? You still need the BKOPS, correct?
Right it's need the BKOPS. if card need the bkops, at next time card should be informed to host.
Quoted 7 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 272
Quoted 6 lines
drivers/mmc/core/core.c +6
-0+return ; + } + +mmc_card_clr_need_bkops (card); +mmc_card_set_doing_bkops (card); +You can remove this extra line here.
I will remove..
Quoted 42 lines
Quoted 42 lines
drivers/mmc/core/core.c +42
-0+} + +void mmc_start_periodic_bkops (struct work_struct *work) +{ + struct mmc_host *host = container_of(work, struct mmc_host, + start_bkops.work); + +mmc_card_set_check_bkops (host->card); + +mmc_claim_host (host); +mmc_start_bkops (host->card); +mmc_release_host (host); +} +EXPORT_SYMBOL (mmc_start_periodic_bkops); + +/** +* mmc_start_bkops - start BKOPS for supported cards +* @card: MMC card to start BKOPS +* +* Start background operations whenever requested. +* when the urgent BKOPS bit is set in a R1 command response +* then background operations should be started immediately. +*/ +void mmc_start_bkops (struct mmc_card *card) +{ +BUG_ON (!card); +if (!card->ext_csd.bkops_en || !(card->host->caps2&MMC_CAP2_BKOPS )) +return ; + +if (mmc_card_check_bkops (card)) { +mmc_card_clr_check_bkops (card); +if (mmc_is_exception_event (card,EXT_CSD_URGENT_BKOPS )) { +if (card->ext_csd.raw_bkops_status) +mmc_card_set_need_bkops (card); + }else +mmc_card_clr_need_bkops (card); + } + +/* +* If card_need_bkops_flag didn't set, then do nothing just +* return +*/
Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
Quoted 7 lines
drivers/mmc/core/core.c +7
-0+if (mmc_card_doing_bkops (card) || !mmc_card_need_bkops (card)) + goto check_bkops; + +mmc_send_bkops_cmd (card); + +check_bkops: +queue_delayed_work (system_nrt_wq,&card->host->start_bkops,5 *HZ );Can we use the deferrable timer for this delayed work? If it's not deferrable and if CPU is some low power state, it has to wakeup and serve this timer on it's expiration. Better make it deferrable so it won't wakeup the system when timer expires.
i will check this point..if you have other approach for periodic checking, let me know..it's helpful to me.
Quoted 2 lines
Also, just wondering, how came to this 5 sec timeout?
Nothing..it's just setting for testing. We need the discussion to set how long time..
Quoted 34 lines
Quoted 34 lines
drivers/mmc/core/core.c +10
-2+} +EXPORT_SYMBOL (mmc_start_bkops); +static void mmc_wait_done (struct mmc_request *mrq) {complete (&mrq->completion);@@ -348,8 +425,10 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,struct mmc_async_req *data = host->areq;/* Prepare a new request */ -if (areq) +if (areq) { +cancel_delayed_work_sync (&host->start_bkops);mmc_pre_req (host, areq->mrq, !host->areq); + }if (host->areq) {mmc_wait_for_req_done (host, host->areq->mrq);@@ -359,8 +438,11 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,if (!err&& areq) start_err =__mmc_start_req (host, areq->mrq); -if (host->areq) +if (host->areq) {mmc_post_req (host, host->areq->mrq,0 ); +if (!areq&& host->areq&&mmc_card_mmc (host->card)) +mmc_start_bkops (host->card); + }/* Cancel a prepared request if it was not started. */ if ((err || start_err)&& areq)@@ -480,6 +562,84 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retriesEXPORT_SYMBOL (mmc_wait_for_cmd);
Quoted 14 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 576
Quoted 13 lines
drivers/mmc/core/core.c +12
-0/** +* mmc_stop_bkops - stop ongoing BKOPS +* @card: MMC card to check BKOPS +* +* Send HPI command to interrupt ongoing background operations, +* to allow rapid servicing of foreground operations,e.g. read/ +* writes. Wait until the card comes out of the programming state +* to avoid errors in servicing read/write requests. +*/ +int mmc_stop_bkops (struct mmc_card *card) +{ +int err =0 ; +unsigned int timeout =0x10000 ;How this
0x10000value is calculated? Is there any defined timeout value for card to come out of programming after starting the BKOPS? if not, then let's wait indefinitely for it to come out of the programming state? Don't we wait indefinitely for write request?
This timeout value also is just setting. in my case, when i set to 0x10000, performance is impacted lower than other value.
Quoted 16 lines
Quoted 16 lines
drivers/mmc/core/core.c +16
-0+u32 status; + +BUG_ON (!card); +cancel_delayed_work_sync (&card->host->start_bkops); + +if (card->ext_csd.raw_bkops_status ==EXT_CSD_BKOPS_LEVEL_3 ) { +do { +if (timeout ==0 ) +break ; +mmc_claim_host (card->host); +mmc_send_status (card,&status); +mmc_release_host (card->host); + + timeout--; + }while (R1_CURRENT_STATE (status) ==R1_STATE_PRG ); +if (timeout !=0 )
Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 599
Quoted 7 lines
drivers/mmc/core/core.c +7
-0+ goto done; + } + + err =mmc_interrupt_hpi (card); + +done: +mmc_card_clr_doing_bkops (card);Here even if
mmc_interrupt_hpi()fails, you are clearing theDOING_BKOPSflag which is not correct. Which should clear this flag if HPI issued successfully.
i will modify this point..
Thanks for review...i will modify with your comment at next-version. if you have other comment or approach..let me know plz..
Best Regards,
Jaehoon Chung
Quoted 287 lines
Quoted 281 lines
drivers/mmc/core/core.c +49
-0+ +return err; +} +EXPORT_SYMBOL (mmc_stop_bkops); + +int mmc_read_bkops_status (struct mmc_card *card) +{ +int err; +u8 ext_csd[512 ]; + +mmc_claim_host (card->host); + err =mmc_send_ext_csd (card, ext_csd); +mmc_release_host (card->host); +if (err) +return err; + + card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS ]; + card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXCEPTION_STATUS ]; + +return 0 ; +} +EXPORT_SYMBOL (mmc_read_bkops_status); + +int mmc_is_exception_event (struct mmc_card *card,unsigned int value) +{ +int err; + + err =mmc_read_bkops_status (card); +if (err) { +pr_err ("%s: Didn't read bkops status : %d\n" , +mmc_hostname (card->host), err); +return 0 ; + } + +/* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */ +if (card->ext_csd.rev ==5 ) +return 1 ; + +return (card->ext_csd.raw_exception_status& value) ?1 :0 ; +} +EXPORT_SYMBOL (mmc_is_exception_event); + +/** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer @@ -2382,6 +2542,12 @@ int mmc_pm_notify(struct notifier_block *notify_block,switch (mode) {case PM_HIBERNATION_PREPARE :case PM_SUSPEND_PREPARE : +if (host->card&&mmc_card_mmc (host->card)&& +mmc_card_doing_bkops (host->card)) { +mmc_interrupt_hpi (host->card); +mmc_card_clr_doing_bkops (host->card); + } +cancel_delayed_work_sync (&host->start_bkops);spin_lock_irqsave (&host->lock, flags); host->rescan_disable =1 ;drivers/mmc/core/host.c +1
-0@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)spin_lock_init (&host->lock);init_waitqueue_head (&host->wq);INIT_DELAYED_WORK (&host->detect, mmc_rescan); +INIT_DELAYED_WORK (&host->start_bkops, mmc_start_periodic_bkops);#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify;#endif drivers/mmc/core/mmc.c +18
-0@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) }if (card->ext_csd.rev>=5 ) { +/* check whether the eMMC card support BKOPS */ +if (ext_csd[EXT_CSD_BKOPS_SUPPORT ]&0x1 ) { + card->ext_csd.bkops =1 ; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN ]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS ]; +if (!card->ext_csd.bkops_en&& + card->host->caps2&MMC_CAP2_INIT_BKOPS ) { + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_EN ,1 ,0 ); +if (err) +pr_warning ("%s: Enabling BKOPS failed\n" , +mmc_hostname (card->host)); +else + card->ext_csd.bkops_en =1 ; + } + } +/* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES ]&0x1 ) { card->ext_csd.hpi =1 ;drivers/mmc/core/mmc_ops.c +4
-0@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,if (err)return err; +/* No need to check card status in case of BKOPS switch*/ +if (index ==EXT_CSD_BKOPS_START ) +return 0 ; +/* Must check status to be sure of no errors */ do { err = mmc_send_status(card,&status);include/linux/mmc/card.h +16
-0@@ -76,6 +76,9 @@ struct mmc_ext_csd {bool hpi_en;/* HPI enablebit */ bool hpi;/* HPI support bit */ unsigned int hpi_cmd;/* cmd used as HPI */ +bool bkops;/* background support bit */ +bool bkops_en;/* background enable bit */ +u8 raw_exception_status;/* 53 */ unsigned int data_sector_size;/* 512 bytes or 4KB */ unsigned int data_tag_unit_size;/* DATA TAG UNIT size */ unsigned int boot_ro_lock;/* ro lock support */ @@ -93,6 +96,7 @@ struct mmc_ext_csd {u8 raw_sec_erase_mult;/* 230 */ u8 raw_sec_feature_support;/* 231 */ u8 raw_trim_mult;/* 232 */ +u8 raw_bkops_status;/* 246 */ u8 raw_sectors[4 ];/* 212 - 4 bytes */ unsigned int feature_support;@@ -225,6 +229,9 @@ struct mmc_card {#define MMC_CARD_REMOVED (1<<7)/* card has been removed */ #define MMC_STATE_HIGHSPEED_200 (1<<8)/* card is in HS200 mode */ #define MMC_STATE_SLEEP (1<<9)/* card is in sleep state */ +#define MMC_STATE_NEED_BKOPS (1<<10)/* card need to do BKOPS */ +#define MMC_STATE_DOING_BKOPS (1<<11)/* card is doing BKOPS */ +#define MMC_STATE_CHECK_BKOPS (1<<12)/* card need to check BKOPS */ unsigned int quirks;/* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0)/* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)/* use func->cur_blksize */ @@ -391,6 +398,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_ext_capacity (c) ((c)->state& MMC_CARD_SDXC)#define mmc_card_removed (c) ((c)&& ((c)->state& MMC_CARD_REMOVED))#define mmc_card_is_sleep (c) ((c)->state& MMC_STATE_SLEEP) +#define mmc_card_need_bkops (c) ((c)->state& MMC_STATE_NEED_BKOPS) +#define mmc_card_doing_bkops (c) ((c)->state& MMC_STATE_DOING_BKOPS) +#define mmc_card_check_bkops (c) ((c)->state& MMC_STATE_CHECK_BKOPS)#define mmc_card_set_present (c) ((c)->state |= MMC_STATE_PRESENT)#define mmc_card_set_readonly (c) ((c)->state |= MMC_STATE_READONLY)@@ -403,7 +413,13 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)#define mmc_card_set_ext_capacity (c) ((c)->state |= MMC_CARD_SDXC)#define mmc_card_set_removed (c) ((c)->state |= MMC_CARD_REMOVED)#define mmc_card_set_sleep (c) ((c)->state |= MMC_STATE_SLEEP) +#define mmc_card_set_need_bkops (c) ((c)->state |= MMC_STATE_NEED_BKOPS) +#define mmc_card_set_doing_bkops (c) ((c)->state |= MMC_STATE_DOING_BKOPS) +#define mmc_card_set_check_bkops (c) ((c)->state |= MMC_STATE_CHECK_BKOPS) +#define mmc_card_clr_need_bkops (c) ((c)->state&= ~MMC_STATE_NEED_BKOPS) +#define mmc_card_clr_doing_bkops (c) ((c)->state&= ~MMC_STATE_DOING_BKOPS) +#define mmc_card_clr_check_bkops (c) ((c)->state&= ~MMC_STATE_CHECK_BKOPS)#define mmc_card_clr_sleep (c) ((c)->state&= ~MMC_STATE_SLEEP)/* * Quirk add/remove for MMC products. include/linux/mmc/core.h +5
-0@@ -134,6 +134,9 @@ struct mmc_host;struct mmc_card ;struct mmc_async_req ; +extern int mmc_stop_bkops (struct mmc_card *); +extern int mmc_read_bkops_status (struct mmc_card *); +extern int mmc_is_exception_event (struct mmc_card *,unsigned int );extern struct mmc_async_req *mmc_start_req (struct mmc_host *,struct mmc_async_req *,int *);extern int mmc_interrupt_hpi (struct mmc_card *);@@ -163,6 +166,8 @@ extern int mmc_can_sanitize(struct mmc_card *card);extern int mmc_can_secure_erase_trim (struct mmc_card *card);extern int mmc_erase_group_aligned (struct mmc_card *card,unsigned int from,unsigned int nr); +extern void mmc_start_periodic_bkops (struct work_struct *work); +extern void mmc_start_bkops (struct mmc_card *card);extern unsigned int mmc_calc_max_discard (struct mmc_card *card);extern int mmc_set_blocklen (struct mmc_card *card,unsigned int blocklen);include/linux/mmc/host.h +4
-0@@ -238,6 +238,8 @@ struct mmc_host {#define MMC_CAP2_BROKEN_VOLTAGE (1<< 7)/* Use the broken voltage */ #define MMC_CAP2_DETECT_ON_ERR (1<< 8)/* On I/O err check card removal */ #define MMC_CAP2_HC_ERASE_SZ (1<< 9)/* High-capacity erase size */ +#define MMC_CAP2_INIT_BKOPS (1<< 10)/* To enable BKOPS */ +#define MMC_CAP2_BKOPS (1<< 11)/* BKOPS supported */ mmc_pm_flag_t pm_caps;/* supported pm features */ unsigned int power_notify_type;@@ -320,6 +322,8 @@ struct mmc_host {unsigned int actual_clock;/* Actual HC clock rate */ +struct delayed_work start_bkops;/* Periodic bkops start */ +unsigned long private[0 ]____cacheline_aligned ; };include/linux/mmc/mmc.h +20
-0@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode)#define R1_CURRENT_STATE (x) ((x& 0x00001E00)>> 9)/* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1<< 8)/* sx, a */ #define R1_SWITCH_ERROR (1<< 7)/* sx, c */ +#define R1_EXCEPTION_EVENT (1<< 6)/* sx, a */ #define R1_APP_CMD (1<< 5)/* sr, c */ #define R1_STATE_IDLE 0@@ -274,12 +275,15 @@ struct _mmc_csd {#define EXT_CSD_FLUSH_CACHE 32/* W */ #define EXT_CSD_CACHE_CTRL 33/* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34/* R/W */ +#define EXT_CSD_EXCEPTION_STATUS 54/* RO */ #define EXT_CSD_DATA_SECTOR_SIZE 61/* R */ #define EXT_CSD_GP_SIZE_MULT 143/* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156/* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160/* RO */ #define EXT_CSD_HPI_MGMT 161/* R/W */ #define EXT_CSD_RST_N_FUNCTION 162/* R/W */ +#define EXT_CSD_BKOPS_EN 163/* R/W */ +#define EXT_CSD_BKOPS_START 164/* W */ #define EXT_CSD_SANITIZE_START 165/* W */ #define EXT_CSD_WR_REL_PARAM 166/* RO */ #define EXT_CSD_BOOT_WP 173/* R/W */ @@ -313,11 +317,13 @@ struct _mmc_csd {#define EXT_CSD_PWR_CL_200_360 237/* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238/* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239/* RO */ +#define EXT_CSD_BKOPS_STATUS 246/* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247/* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248/* RO */ #define EXT_CSD_CACHE_SIZE 249/* RO, 4 bytes */ #define EXT_CSD_TAG_UNIT_SIZE 498/* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499/* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502/* RO */ #define EXT_CSD_HPI_FEATURES 503/* RO */ /* @@ -386,4 +392,18 @@ struct _mmc_csd {#define MMC_SWITCH_MODE_CLEAR_BITS 0x02/* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03/* Set target to value */ +/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +#define EXT_CSD_BKOPS_LEVEL_3 0x3 + +/* +* EXCEPTION_EVENT_STATUS field (eMMC4.5) +*/ +#define EXT_CSD_URGENT_BKOPS BIT(0) +#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) +#define EXT_CSD_PACKED_FAILURE BIT(3) +#endif /* LINUX_MMC_MMC_H */ Signature · 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.htmlSignature · 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 88 lines
-----Original Message-----
From: [email protected] [mailto:linux-mmc- [email protected]] On Behalf Of Jaehoon Chung
Sent: Monday, May 14, 2012 8:29 AM
To: Subhash Jadavani
Cc: Jaehoon Chung; linux-mmc; Chris Ball; Kyungmin Park; Hanumath Prasad; Per FORLIN; Sebastian Rasmussen; Dong, Chuanxiao; [email protected]; Saugata Das; Konstantin Dorfman; Adrian Hunter
Subject: Re: [PATCH v8] mmc: support BKOPS feature for eMMCQuoted 19 lines · Subhash Jadavani
Hi Jaehoon,
Please find comments inline below.
Quoted 14 lines · Jaehoon Chung
Enable eMMC background operations (BKOPS) feature.
If
URGENT_BKOPSis set after a response, note that BKOPS are required. After all I/O requests are finished, run BKOPS if required. Should read/write operations be requested during BKOPS, first issue HPI to interrupt the ongoing BKOPS and then service the request. If BKOPS-STATUS is upper than LEVEL2, need to check until clear the BKOPS-STATUS vaule.If you want to enable this feature, set
MMC_CAP2_BKOPS. And if you want to set theBKOPS_ENbit inext_csdregister, use theMMC_CAP2_INIT_BKOPS.When
BKOPS_STATUSis Level-3, if we're waiting for done, it spent60~80sec.
Quoted 29 lines
Quoted 29 lines
So Added timeout value. if timeout value is set to 0, send hpi command.
Signed-off-by Jaehoon Chung<[email protected]>Signed-off-by Kyungmin Park<[email protected]>---
Changelog V8:
- Removehost->lockspin lock reviewed by Adrian
- Support periodic start bkops
- whenbkops_statusis level-3, if timeout is set to 0, send hpi.
- Move the start-bkops point
Changelog V7:
- Use HPI command when issuedURGENT_BKOPS
- Recheck until clearing the bkops-status bit.
Changelog V6:
- Add the flag of check-bkops-status.
(For fixingasync_reqproblem)
- Add the capability forMMC_CAP2_INIT_BKOPS.
(When unset thebkops_enbit inext_csdregister)
- modify the wrong condition.
Changelog V5:
- Rebase based on the latest mmc-next.
- modify codes based-on Chris's comment Changelog V4:
- Addmmc_read_bkops_status
- WhenURGENT_BKOPS(level2-3), didn't use HPI command.
- Inmmc_switch(), use R1B/R1 according to level.
Changelog V3:
- move the bkops setting's location inmmc_blk_issue_rw_rq
- modify condition checking
-bkops_enis assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"Quoted 8 lines
Quoted 8 lines
- remove the unused code
- changepr_debuginstead ofpr_warninmmc_send_hpi_cmd
- Add the Future consideration suggested by Per Changelog V2:
- UseEXCEPTION_STATUSinstead ofURGENT_BKOPS
- Add function to checkException_status(for eMMC4.5)--- drivers/mmc/card/queue.c | 2 + drivers/mmc/core/core.c | 170+++++++++++++++++++++++++++++++++++++++++++-
Quoted 16 lines
Quoted 16 lines
drivers/mmc/core/host.c | 1 + drivers/mmc/core/mmc.c | 18 +++++ drivers/mmc/core/mmc_ops.c | 4 + include/linux/mmc/card.h | 16 ++++ include/linux/mmc/core.h | 5 ++ include/linux/mmc/host.h | 4 + include/linux/mmc/mmc.h | 20 +++++ 9 files changed, 238 insertions(+), 2 deletions(-)drivers/mmc/card/queue.c +0
-0@@ -66,6 +66,8 @@ static int mmc_queue_thread(void *d)spin_unlock_irq (q->queue_lock);
Quoted 6 lines
Quoted 4 lines
drivers/mmc/card/queue.c static int mmc_queue_thread(void *d) · line 70
Quoted 3 lines
drivers/mmc/card/queue.c +2
-0if (req || mq->mqrq_prev->req) { +if (mmc_card_doing_bkops (mq->card)) +mmc_stop_bkops (mq->card);
mmc_stop_bkops()may fail and can return an error but we are ignoring ithere. What if this function has returned error which means BKOPS may still be running in card and if you go ahead and issue another read/write
request?
Quoted 25 lines
Great..i didn't think that..I will consider this point. Thanks.
Quoted 8 lines
drivers/mmc/core/core.c void mmc_request_done(struct mmc_host
Quoted 8 lines
drivers/mmc/card/queue.c +0
-0set_current_state (TASK_RUNNING ); mq->issue_fn (mq, req); }else {drivers/mmc/core/core.c index renamed from drivers/mmc/core/core.c +0
-00b6141d..91a03d5 100644
drivers/mmc/core/core.c +0
-0@@ -175,6 +175,13 @@ void mmc_request_done(struct mmc_host*host, struct
mmc_request*mrq)Quoted 9 lines
drivers/mmc/core/core.c void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
Quoted 8 lines
drivers/mmc/core/core.c +5
-0if (mrq->done) mrq->done (mrq); +/* +* Check BKOPS urgency from each R1 response +*/ +if (host->card&&mmc_card_mmc (host->card)&& + (cmd->resp[0 ]&R1_EXCEPTION_EVENT ))Shouldn't you make sure that response expected for this commands is
R1/R1b? Only in that case cmd->resp[0] will have the device status.
Right..this point will be also modified..
Quoted 24 lines
Quoted 6 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host,
Quoted 6 lines
drivers/mmc/core/core.c +2
-0+mmc_card_set_check_bkops (host->card); +mmc_host_clk_release (host); } }@@ -245,6 +252,76 @@ mmc_start_request(struct mmc_host *host,struct
mmc_request*mrq)Quoted 17 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 255
Quoted 4 lines
drivers/mmc/core/core.c +1
-0host->ops->request (host, mrq); } +static void mmc_send_bkops_cmd (struct mmc_card *card)I guess name should be
mmc_send_bkops_start_cmd().drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 266
Quoted 11 lines
drivers/mmc/core/core.c +11
-0+{ +int err; + +BUG_ON (!card); + + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_START ,1 ,0 ); +if (err) { +pr_warning ("%s: error %d starting bkops\n" , +mmc_hostname (card->host), err); +mmc_card_clr_need_bkops (card);In case of failure, why are we clearing the
NEED_BKOPSflag? You still
need
Quoted 3 lines
the BKOPS, correct?
Right it's need the BKOPS. if card need the bkops, at next time card
should be
Quoted 62 lines
informed to host.
Quoted 7 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 272
Quoted 6 lines
drivers/mmc/core/core.c +6
-0+return ; + } + +mmc_card_clr_need_bkops (card); +mmc_card_set_doing_bkops (card); +You can remove this extra line here.
I will remove..
Quoted 17 lines
Quoted 17 lines
drivers/mmc/core/core.c +17
-0+} + +void mmc_start_periodic_bkops (struct work_struct *work) { + struct mmc_host *host = container_of(work, struct mmc_host, + start_bkops.work); + +mmc_card_set_check_bkops (host->card); + +mmc_claim_host (host); +mmc_start_bkops (host->card); +mmc_release_host (host); +} +EXPORT_SYMBOL (mmc_start_periodic_bkops); + +/** +* mmc_start_bkops - start BKOPS for supported cards +* @card: MMC card to start BKOPS Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
Quoted 8 lines
drivers/mmc/core/core.c +8
-0+* +* Start background operations whenever requested. +* when the urgent BKOPS bit is set in a R1 command response +* then background operations should be started immediately. +*/ +void mmc_start_bkops (struct mmc_card *card) { +BUG_ON (!card); + if (!card->ext_csd.bkops_en || !(card->host->caps2&
MMC_CAP2_BKOPS))Quoted 16 lines
Quoted 16 lines
drivers/mmc/core/core.c +16
-0+return ; + +if (mmc_card_check_bkops (card)) { +mmc_card_clr_check_bkops (card); +if (mmc_is_exception_event (card,EXT_CSD_URGENT_BKOPS )) { +if (card->ext_csd.raw_bkops_status) +mmc_card_set_need_bkops (card); + }else +mmc_card_clr_need_bkops (card); + } + +/* +* If card_need_bkops_flag didn't set, then do nothing just +* return +*/ +if (mmc_card_doing_bkops (card) || !mmc_card_need_bkops (card))Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
Quoted 7 lines
drivers/mmc/core/core.c +7
-0+ goto check_bkops; + +mmc_send_bkops_cmd (card); + +check_bkops: +queue_delayed_work (system_nrt_wq,&card->host->start_bkops,5 * +HZ );Can we use the deferrable timer for this delayed work? If it's not
Quoted 2 lines
deferrable and if CPU is some low power state, it has to wakeup and serve this timer on it's expiration. Better make it deferrable so it won't
wakeup the
Quoted 3 lines
system when timer expires.
i will check this point..if you have other approach for periodic checking,
let
Quoted 1 line
me know..it's helpful to me.
You can use the "system_nrt_freezable_wq" to queue the work instead of "system_nrt_wq". Check out this patch for reference:
https://lkml.org/lkml/2012/3/16/593 which had added this new type of workqueue.
Regards,
Subhash
Quoted 5 lines
Quoted 3 lines
Also, just wondering, how came to this 5 sec timeout?
Nothing..it's just setting for testing. We need the discussion to set how
long
Quoted 33 lines
time..
Quoted 7 lines
drivers/mmc/core/core.c struct mmc_async_req *mmc_start_req(struct
Quoted 7 lines
drivers/mmc/core/core.c +3
-0+} +EXPORT_SYMBOL (mmc_start_bkops); +static void mmc_wait_done (struct mmc_request *mrq) {complete (&mrq->completion);@@ -348,8 +425,10 @@ struct mmc_async_req *mmc_start_req(struct
mmc_host*host,Quoted 9 lines
Quoted 9 lines
drivers/mmc/core/core.c +3
-1struct mmc_async_req *data = host->areq;/* Prepare a new request */ -if (areq) +if (areq) { +cancel_delayed_work_sync (&host->start_bkops);mmc_pre_req (host, areq->mrq, !host->areq); + }Quoted 3 lines
drivers/mmc/core/core.c struct mmc_async_req *mmc_start_req(struct
Quoted 3 lines
drivers/mmc/core/core.c +1
-0if (host->areq) { mmc_wait_for_req_done(host, host->areq->mrq); @@ -359,8 +438,11 @@ struct mmc_async_req *mmc_start_req(struct mmc_host*host,
Quoted 10 lines
Quoted 10 lines
if (!err&& areq) start_err = __mmc_start_req(host, areq->mrq);drivers/mmc/core/core.c +4
-1-if (host->areq) +if (host->areq) {mmc_post_req (host, host->areq->mrq,0 ); +if (!areq&& host->areq&&mmc_card_mmc (host->card)) +mmc_start_bkops (host->card); + }
Quoted 19 lines
Quoted 3 lines
Quoted 3 lines
/* Cancel a prepared request if it was not started. */ if ((err || start_err)&& areq) @@ -480,6 +562,84 @@ intmmc_wait_for_cmd(struct
mmc_host*host, structmmc_command*cmd, int retries
Quoted 15 lines
Quoted 11 lines
EXPORT_SYMBOL(mmc_wait_for_cmd);/**
+ *mmc_stop_bkops- stop ongoing BKOPS
+ * @card: MMC card to check BKOPS
+ *+ * Send HPI command to interrupt ongoing background operations, + * to allow rapid servicing of foreground operations,e.g. read/ + * writes. Wait until the card comes out of the programming state + * to avoid errors in servicing read/write requests.+ */
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 576
Quoted 3 lines
drivers/mmc/core/core.c +3
-0+int mmc_stop_bkops (struct mmc_card *card) { +int err =0 ; +unsigned int timeout =0x10000 ;How this
0x10000value is calculated? Is there any defined timeout value
for
Quoted 1 line
card to come out of programming after starting the BKOPS? if not, then
let's
Quoted 1 line
wait indefinitely for it to come out of the programming state? Don't we
wait
Quoted 3 lines
indefinitely for write request?
This timeout value also is just setting. in my case, when i set to
0x10000,
Quoted 26 lines
performance is impacted lower than other value.
Quoted 16 lines
Quoted 16 lines
drivers/mmc/core/core.c +16
-0+u32 status; + +BUG_ON (!card); +cancel_delayed_work_sync (&card->host->start_bkops); + +if (card->ext_csd.raw_bkops_status ==EXT_CSD_BKOPS_LEVEL_3 ) { +do { +if (timeout ==0 ) +break ; +mmc_claim_host (card->host); +mmc_send_status (card,&status); +mmc_release_host (card->host); + + timeout--; + }while (R1_CURRENT_STATE (status) ==R1_STATE_PRG ); +if (timeout !=0 )Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 599
Quoted 7 lines
drivers/mmc/core/core.c +7
-0+ goto done; + } + + err =mmc_interrupt_hpi (card); + +done: +mmc_card_clr_doing_bkops (card);Here even if
mmc_interrupt_hpi()fails, you are clearing theDOING_BKOPS
Quoted 1 line
flag which is not correct. Which should clear this flag if HPI issued
successfully.
Quoted 134 lines
i will modify this point..
Thanks for review...i will modify with your comment at next-version. if you have other comment or approach..let me know plz..
Best Regards,
Jaehoon ChungQuoted 8 lines
Quoted 8 lines
drivers/mmc/core/core.c +8
-0+ +return err; +} +EXPORT_SYMBOL (mmc_stop_bkops); + +int mmc_read_bkops_status (struct mmc_card *card) { +int err; +u8 ext_csd[512 ];Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
Quoted 8 lines
drivers/mmc/core/core.c +8
-0+ +mmc_claim_host (card->host); + err =mmc_send_ext_csd (card, ext_csd); +mmc_release_host (card->host); +if (err) +return err; + + card->ext_csd.raw_bkops_status =ext_csd[EXT_CSD_BKOPS_STATUS];
Quoted 22 lines
Quoted 22 lines
drivers/mmc/core/core.c +22
-0+ card->ext_csd.raw_exception_status = + ext_csd[EXT_CSD_EXCEPTION_STATUS ]; + +return 0 ; +} +EXPORT_SYMBOL (mmc_read_bkops_status); + +int mmc_is_exception_event (struct mmc_card *card,unsigned int +value) { +int err; + + err =mmc_read_bkops_status (card); +if (err) { +pr_err ("%s: Didn't read bkops status : %d\n" , +mmc_hostname (card->host), err); +return 0 ; + } + +/* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */ +if (card->ext_csd.rev ==5 ) +return 1 ; +Quoted 8 lines
drivers/mmc/core/core.c int mmc_pm_notify(struct notifier_block
Quoted 8 lines
drivers/mmc/core/core.c +4
-0+return (card->ext_csd.raw_exception_status& value) ?1 :0 ; } +EXPORT_SYMBOL (mmc_is_exception_event); + +/** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer @@ -2382,6 +2542,12 @@ int mmc_pm_notify(struct notifier_block
*notify_block,Quoted 10 lines
Quoted 10 lines
drivers/mmc/core/core.c +6
-0switch (mode) {case PM_HIBERNATION_PREPARE :case PM_SUSPEND_PREPARE : +if (host->card&&mmc_card_mmc (host->card)&& +mmc_card_doing_bkops (host->card)) { +mmc_interrupt_hpi (host->card); +mmc_card_clr_doing_bkops (host->card); + } +cancel_delayed_work_sync (&host->start_bkops);Quoted 7 lines
drivers/mmc/core/host.c struct mmc_host *mmc_alloc_host(int extra,
Quoted 7 lines
drivers/mmc/core/core.c +0
-0spin_lock_irqsave (&host->lock, flags); host->rescan_disable =1 ;drivers/mmc/core/host.c index renamed from drivers/mmc/core/host.c +0
-091c84c7..3b6a8e4 100644
drivers/mmc/core/host.c +0
-0@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra,struct device *dev)
Quoted 4 lines
drivers/mmc/core/host.c struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
Quoted 4 lines
drivers/mmc/core/host.c +1
-0spin_lock_init (&host->lock);init_waitqueue_head (&host->wq);INIT_DELAYED_WORK (&host->detect, mmc_rescan); + INIT_DELAYED_WORK(&host->start_bkops,
mmc_start_periodic_bkops);Quoted 8 lines
drivers/mmc/core/mmc.c static int mmc_read_ext_csd(struct mmc_card
Quoted 8 lines
drivers/mmc/core/host.c +0
-0#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify;#endif drivers/mmc/core/mmc.c index renamed from drivers/mmc/core/mmc.c +0
-02f0e11c..275555a 100644
drivers/mmc/core/mmc.c +0
-0@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card*card, u8
*ext_csd)Quoted 17 lines
Quoted 17 lines
drivers/mmc/core/mmc.c +14
-0}if (card->ext_csd.rev>=5 ) { +/* check whether the eMMC card support BKOPS */ +if (ext_csd[EXT_CSD_BKOPS_SUPPORT ]&0x1 ) { + card->ext_csd.bkops =1 ; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN ]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS ]; +if (!card->ext_csd.bkops_en&& + card->host->caps2&MMC_CAP2_INIT_BKOPS ) { + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_EN ,1 ,0 ); +if (err) +pr_warning ("%s: Enabling BKOPS failed\n" , +mmc_hostname (card->host)); +else Quoted 8 lines
Review
Quoted 8 lines
drivers/mmc/core/mmc.c +4
-0+ card->ext_csd.bkops_en =1 ; + } + } +/* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES ]&0x1 ) { card->ext_csd.hpi =1 ;(quoted diff) +0
-0
b/drivers/mmc/core/mmc_ops.cQuoted 4 lines
drivers/mmc/core/mmc_ops.c int mmc_switch(struct mmc_card *card, u8 set,
Quoted 4 lines
index 69370f4..bc8da17 100644
drivers/mmc/core/mmc_ops.c +0
-0@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set,u8 index, u8 value,
Quoted 14 lines
Quoted 14 lines
drivers/mmc/core/mmc_ops.c +4
-0if (err)return err; +/* No need to check card status in case of BKOPS switch*/ +if (index ==EXT_CSD_BKOPS_START ) +return 0 ; +/* Must check status to be sure of no errors */ do { err = mmc_send_status(card,&status); diff --git
a/include/linux/mmc/card.hb/include/linux/mmc/card.hindex d76513b..52b507d 100644include/linux/mmc/card.h +0
-0
Quoted 8 lines
Quoted 8 lines
include/linux/mmc/card.h struct mmc_ext_csd { · line 82
Quoted 8 lines
include/linux/mmc/card.h +3
-0@@ -76,6 +76,9 @@ struct mmc_ext_csd {bool hpi_en;/* HPI enablebit */ bool hpi;/* HPI support bit */ unsigned int hpi_cmd;/* cmd used as HPI */ +bool bkops;/* background support bit */ +bool bkops_en;/* background enable bit */ +u8 raw_exception_status;/* 53 */ unsigned int data_sector_size;/* 512 bytes or
4KB */
Quoted 1 line
Quoted 1 line
include/linux/mmc/card.h struct mmc_ext_csd { · line 83
Quoted 1 line
include/linux/mmc/card.h +0
-0unsigned int data_tag_unit_size;/* DATA TAG UNIT
size */
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
include/linux/mmc/card.h +1
-0unsigned int boot_ro_lock;/* ro lock support */ @@ -93,6 +96,7 @@ struct mmc_ext_csd {u8 raw_sec_erase_mult;/* 230 */ u8 raw_sec_feature_support;/* 231 */ u8 raw_trim_mult;/* 232 */ +u8 raw_bkops_status;/* 246 */ u8 raw_sectors[4 ];/* 212 - 4 bytes */
Quoted 7 lines
Quoted 3 lines
include/linux/mmc/card.h struct mmc_card { · line 229
Quoted 3 lines
include/linux/mmc/card.h +0
-0unsigned int feature_support;@@ -225,6 +229,9 @@ struct mmc_card {#define MMC_CARD_REMOVED (1<<7)/* card has been removed */
Quoted 1 line
include/linux/mmc/card.h struct mmc_card { · line 230
Quoted 1 line
include/linux/mmc/card.h +0
-0#define MMC_STATE_HIGHSPEED_200 (1<<8)/* card is in HS200 mode */
Quoted 1 line
Quoted 1 line
include/linux/mmc/card.h +0
-0#define MMC_STATE_SLEEP (1<<9)/* card is in sleep
state */
Quoted 172 lines
Quoted 1 line
include/linux/mmc/card.h struct mmc_card { · line 232
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define MMC_STATE_NEED_BKOPS (1<<10)/* card need to do BKOPS */
Quoted 1 line
include/linux/mmc/card.h struct mmc_card { · line 233
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define MMC_STATE_DOING_BKOPS (1<<11)/* card is doing BKOPS */
Quoted 1 line
include/linux/mmc/card.h struct mmc_card { · line 234
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define MMC_STATE_CHECK_BKOPS (1<<12)/* card need to check BKOPS */
Quoted 2 lines
include/linux/mmc/card.h struct mmc_card { · line 236
Quoted 2 lines
include/linux/mmc/card.h +0
-0unsigned int quirks;/* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0)/* allow SDIO FN0 writes outside of the VS CCCR range */
Quoted 3 lines
include/linux/mmc/card.h struct mmc_card { · line 237
Quoted 1 line
include/linux/mmc/card.h +0
-0#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)/* use func-
cur_blksize*/include/linux/mmc/card.h static inline void __maybe_unused
Quoted 1 line
include/linux/mmc/card.h +0
-0@@ -391,6 +398,9 @@ static inline void __maybe_unused
remove_quirk(struct mmc_card *card, int data)Quoted 2 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 399
Quoted 2 lines
include/linux/mmc/card.h +0
-0#define mmc_card_ext_capacity (c) ((c)->state& MMC_CARD_SDXC)#define mmc_card_removed (c) ((c)&& ((c)->state&
MMC_CARD_REMOVED))Quoted 2 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 401
Quoted 2 lines
include/linux/mmc/card.h +1
-0#define mmc_card_is_sleep (c) ((c)->state& MMC_STATE_SLEEP) +#define mmc_card_need_bkops (c) ((c)->state&
MMC_STATE_NEED_BKOPS)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 402
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define mmc_card_doing_bkops (c) ((c)->state&
MMC_STATE_DOING_BKOPS)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 403
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define mmc_card_check_bkops (c) ((c)->state&
MMC_STATE_CHECK_BKOPS)Quoted 2 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 404
Quoted 2 lines
include/linux/mmc/card.h +0
-0#define mmc_card_set_present (c) ((c)->state |=
MMC_STATE_PRESENT)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 405
Quoted 1 line
include/linux/mmc/card.h +0
-0#define mmc_card_set_readonly (c) ((c)->state |=
MMC_STATE_READONLY)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused
Quoted 1 line
include/linux/mmc/card.h +0
-0@@ -403,7 +413,13 @@ static inline void __maybe_unused
remove_quirk(struct mmc_card *card, int data)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 413
Quoted 1 line
include/linux/mmc/card.h +0
-0#define mmc_card_set_ext_capacity (c) ((c)->state |=
MMC_CARD_SDXC)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 414
Quoted 1 line
include/linux/mmc/card.h +0
-0#define mmc_card_set_removed (c) ((c)->state |=
MMC_CARD_REMOVED)Quoted 2 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 416
Quoted 2 lines
include/linux/mmc/card.h +1
-0#define mmc_card_set_sleep (c) ((c)->state |= MMC_STATE_SLEEP) +#define mmc_card_set_need_bkops (c) ((c)->state |=
MMC_STATE_NEED_BKOPS)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 417
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define mmc_card_set_doing_bkops (c) ((c)->state |=
MMC_STATE_DOING_BKOPS)Quoted 4 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 421
Quoted 4 lines
include/linux/mmc/card.h +3
-0+#define mmc_card_set_check_bkops (c) ((c)->state |= +MMC_STATE_CHECK_BKOPS) +#define mmc_card_clr_need_bkops (c) ((c)->state&=~MMC_STATE_NEED_BKOPS)
Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 422
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define mmc_card_clr_doing_bkops (c) ((c)->state&=~MMC_STATE_DOING_BKOPS)
Quoted 13 lines
Quoted 13 lines
include/linux/mmc/card.h +2
-0+#define mmc_card_clr_check_bkops (c) ((c)->state&= +~MMC_STATE_CHECK_BKOPS)#define mmc_card_clr_sleep (c) ((c)->state&= ~MMC_STATE_SLEEP)/* * Quirk add/remove for MMC products. include/linux/mmc/core.h +0
-0@@ -134,6 +134,9 @@ struct mmc_host;struct mmc_card ;struct mmc_async_req ;Quoted 9 lines
Quoted 9 lines
include/linux/mmc/core.h +3
-0+extern int mmc_stop_bkops (struct mmc_card *);extern int +mmc_read_bkops_status (struct mmc_card *);extern int +mmc_is_exception_event (struct mmc_card *,unsigned int );extern struct mmc_async_req *mmc_start_req (struct mmc_host *,struct mmc_async_req *,int *); extern int mmc_interrupt_hpi(struct mmc_card *); @@ -163,6 +166,8@@ extern int
mmc_can_sanitize(struct mmc_card *card);
extern intmmc_can_secure_erase_trim(struct mmc_card *card); extern int mmc_erase_group_aligned(structmmc_card*card, unsignedint from,
Quoted 5 lines
Quoted 5 lines
unsigned int nr);include/linux/mmc/core.h +2
-0+extern void mmc_start_periodic_bkops (struct work_struct *work); +extern void mmc_start_bkops (struct mmc_card *card);extern unsigned int mmc_calc_max_discard (struct mmc_card *card);Quoted 7 lines
include/linux/mmc/host.h struct mmc_host { · line 238
Quoted 7 lines
extern int mmc_set_blocklen(struct
mmc_card*card, unsigned int
blocklen); diff --gita/include/linux/mmc/host.hb/include/linux/mmc/host.hindex 0707d22..186d146 100644include/linux/mmc/host.h +0
-0@@ -238,6 +238,8 @@ struct mmc_host {#define MMC_CAP2_BROKEN_VOLTAGE (1<< 7)/* Use the broken voltage */
Quoted 1 line
include/linux/mmc/host.h struct mmc_host { · line 239
Quoted 1 line
include/linux/mmc/host.h +0
-0#define MMC_CAP2_DETECT_ON_ERR (1<< 8)/* On I/O err check card removal */
Quoted 1 line
include/linux/mmc/host.h struct mmc_host { · line 240
Quoted 1 line
include/linux/mmc/host.h +0
-0#define MMC_CAP2_HC_ERASE_SZ (1<< 9)/* High-capacity erase size */
Quoted 14 lines
Quoted 14 lines
include/linux/mmc/host.h +4
-0+#define MMC_CAP2_INIT_BKOPS (1<< 10)/* To enable BKOPS */ +#define MMC_CAP2_BKOPS (1<< 11)/* BKOPS supported */ mmc_pm_flag_t pm_caps;/* supported pm features */ unsigned int power_notify_type;@@ -320,6 +322,8 @@ struct mmc_host {unsigned int actual_clock;/* Actual HC clock rate */ +struct delayed_work start_bkops;/* Periodic bkops start */ +unsigned long private[0 ]____cacheline_aligned ; };Quoted 6 lines
include/linux/mmc/mmc.h static inline bool mmc_op_multi(u32 opcode) · line 139
Quoted 6 lines
include/linux/mmc/mmc.h index renamed from include/linux/mmc/mmc.h +0
-0d425cab..06afeb4 100644
include/linux/mmc/mmc.h +0
-0@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode)#define R1_CURRENT_STATE (x) ((x& 0x00001E00)>> 9)/* sx, b (4 bits) */
Quoted 35 lines
Quoted 35 lines
include/linux/mmc/mmc.h +6
-0#define R1_READY_FOR_DATA (1<< 8)/* sx, a */ #define R1_SWITCH_ERROR (1<< 7)/* sx, c */ +#define R1_EXCEPTION_EVENT (1<< 6)/* sx, a */ #define R1_APP_CMD (1<< 5)/* sr, c */ #define R1_STATE_IDLE 0@@ -274,12 +275,15 @@ struct _mmc_csd {#define EXT_CSD_FLUSH_CACHE 32/* W */ #define EXT_CSD_CACHE_CTRL 33/* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34/* R/W */ +#define EXT_CSD_EXCEPTION_STATUS 54/* RO */ #define EXT_CSD_DATA_SECTOR_SIZE 61/* R */ #define EXT_CSD_GP_SIZE_MULT 143/* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156/* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160/* RO */ #define EXT_CSD_HPI_MGMT 161/* R/W */ #define EXT_CSD_RST_N_FUNCTION 162/* R/W */ +#define EXT_CSD_BKOPS_EN 163/* R/W */ +#define EXT_CSD_BKOPS_START 164/* W */ #define EXT_CSD_SANITIZE_START 165/* W */ #define EXT_CSD_WR_REL_PARAM 166/* RO */ #define EXT_CSD_BOOT_WP 173/* R/W */ @@ -313,11 +317,13 @@ struct _mmc_csd {#define EXT_CSD_PWR_CL_200_360 237/* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238/* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239/* RO */ +#define EXT_CSD_BKOPS_STATUS 246/* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247/* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248/* RO */ #define EXT_CSD_CACHE_SIZE 249/* RO, 4 bytes */ #define EXT_CSD_TAG_UNIT_SIZE 498/* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499/* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502/* RO */ #define EXT_CSD_HPI_FEATURES 503/* RO */ Quoted 3 lines
include/linux/mmc/mmc.h struct _mmc_csd { · line 392
Quoted 3 lines
include/linux/mmc/mmc.h +0
-0/* @@ -386,4 +392,18 @@ struct _mmc_csd {#define MMC_SWITCH_MODE_CLEAR_BITS 0x02/* Clear bits which are 1 in value */
Quoted 1 line
include/linux/mmc/mmc.h struct _mmc_csd { · line 393
Quoted 1 line
include/linux/mmc/mmc.h +0
-0#define MMC_SWITCH_MODE_WRITE_BYTE 0x03/* Set target to value */
Quoted 10 lines
Quoted 10 lines
include/linux/mmc/mmc.h +9
-0+/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +#define EXT_CSD_BKOPS_LEVEL_3 0x3 + +/* +* EXCEPTION_EVENT_STATUS field (eMMC4.5) */ +#define EXT_CSD_URGENT_BKOPS BIT(0)Quoted 8 lines
Quoted 8 lines
include/linux/mmc/mmc.h +4
-1+#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) +#define EXT_CSD_PACKED_FAILURE BIT(3) +#endif /* LINUX_MMC_MMC_H */ --To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected] More
majordomo
Quoted 5 lines
Quoted 1 line
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected] More
Quoted 7 lines
majordomo
Quoted 2 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the
Quoted 2 lines
body of a message to [email protected] More majordomo info at
http://vger.kernel.org/majordomo-info.html
Hi Subhash,
Thank you, Subhash.
I will refer to them. ASAP, i will send the patch-v9.
Best Regards,
Jaehoon Chung
Quoted 672 lines · Subhash Jadavani
Quoted 88 lines
-----Original Message-----
From: [email protected] [mailto:linux-mmc- [email protected]] On Behalf Of Jaehoon Chung
Sent: Monday, May 14, 2012 8:29 AM
To: Subhash Jadavani
Cc: Jaehoon Chung; linux-mmc; Chris Ball; Kyungmin Park; Hanumath Prasad; Per FORLIN; Sebastian Rasmussen; Dong, Chuanxiao; [email protected]; Saugata Das; Konstantin Dorfman; Adrian Hunter
Subject: Re: [PATCH v8] mmc: support BKOPS feature for eMMCQuoted 19 lines · Subhash Jadavani
Hi Jaehoon,
Please find comments inline below.
Quoted 14 lines · Jaehoon Chung
Enable eMMC background operations (BKOPS) feature.
If
URGENT_BKOPSis set after a response, note that BKOPS are required. After all I/O requests are finished, run BKOPS if required. Should read/write operations be requested during BKOPS, first issue HPI to interrupt the ongoing BKOPS and then service the request. If BKOPS-STATUS is upper than LEVEL2, need to check until clear the BKOPS-STATUS vaule.If you want to enable this feature, set
MMC_CAP2_BKOPS. And if you want to set theBKOPS_ENbit inext_csdregister, use theMMC_CAP2_INIT_BKOPS.When
BKOPS_STATUSis Level-3, if we're waiting for done, it spent60~80sec.
Quoted 29 lines
Quoted 29 lines
So Added timeout value. if timeout value is set to 0, send hpi command.
Signed-off-by Jaehoon Chung<[email protected]>Signed-off-by Kyungmin Park<[email protected]>---
Changelog V8:
- Removehost->lockspin lock reviewed by Adrian
- Support periodic start bkops
- whenbkops_statusis level-3, if timeout is set to 0, send hpi.
- Move the start-bkops point
Changelog V7:
- Use HPI command when issuedURGENT_BKOPS
- Recheck until clearing the bkops-status bit.
Changelog V6:
- Add the flag of check-bkops-status.
(For fixingasync_reqproblem)
- Add the capability forMMC_CAP2_INIT_BKOPS.
(When unset thebkops_enbit inext_csdregister)
- modify the wrong condition.
Changelog V5:
- Rebase based on the latest mmc-next.
- modify codes based-on Chris's comment Changelog V4:
- Addmmc_read_bkops_status
- WhenURGENT_BKOPS(level2-3), didn't use HPI command.
- Inmmc_switch(), use R1B/R1 according to level.
Changelog V3:
- move the bkops setting's location inmmc_blk_issue_rw_rq
- modify condition checking
-bkops_enis assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"Quoted 8 lines
Quoted 8 lines
- remove the unused code
- changepr_debuginstead ofpr_warninmmc_send_hpi_cmd
- Add the Future consideration suggested by Per Changelog V2:
- UseEXCEPTION_STATUSinstead ofURGENT_BKOPS
- Add function to checkException_status(for eMMC4.5)--- drivers/mmc/card/queue.c | 2 + drivers/mmc/core/core.c | 170+++++++++++++++++++++++++++++++++++++++++++-
Quoted 16 lines
Quoted 16 lines
drivers/mmc/core/host.c | 1 + drivers/mmc/core/mmc.c | 18 +++++ drivers/mmc/core/mmc_ops.c | 4 + include/linux/mmc/card.h | 16 ++++ include/linux/mmc/core.h | 5 ++ include/linux/mmc/host.h | 4 + include/linux/mmc/mmc.h | 20 +++++ 9 files changed, 238 insertions(+), 2 deletions(-)drivers/mmc/card/queue.c +0
-0@@ -66,6 +66,8 @@ static int mmc_queue_thread(void *d)spin_unlock_irq (q->queue_lock);Quoted 6 lines
Quoted 4 lines
drivers/mmc/card/queue.c static int mmc_queue_thread(void *d) · line 70
Quoted 3 lines
drivers/mmc/card/queue.c +2
-0if (req || mq->mqrq_prev->req) { +if (mmc_card_doing_bkops (mq->card)) +mmc_stop_bkops (mq->card);
mmc_stop_bkops()may fail and can return an error but we are ignoring ithere. What if this function has returned error which means BKOPS may still be running in card and if you go ahead and issue another read/write
request?
Quoted 25 lines
Great..i didn't think that..I will consider this point. Thanks.
Quoted 8 lines
drivers/mmc/core/core.c void mmc_request_done(struct mmc_host
Quoted 8 lines
drivers/mmc/card/queue.c +0
-0set_current_state (TASK_RUNNING ); mq->issue_fn (mq, req); }else {drivers/mmc/core/core.c index renamed from drivers/mmc/core/core.c +0
-00b6141d..91a03d5 100644
drivers/mmc/core/core.c +0
-0@@ -175,6 +175,13 @@ void mmc_request_done(struct mmc_host*host, struct
mmc_request*mrq)Quoted 9 lines
drivers/mmc/core/core.c void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
Quoted 8 lines
drivers/mmc/core/core.c +5
-0if (mrq->done) mrq->done (mrq); +/* +* Check BKOPS urgency from each R1 response +*/ +if (host->card&&mmc_card_mmc (host->card)&& + (cmd->resp[0 ]&R1_EXCEPTION_EVENT ))Shouldn't you make sure that response expected for this commands is
R1/R1b? Only in that case cmd->resp[0] will have the device status.
Right..this point will be also modified..
Quoted 24 lines
Quoted 6 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host,
Quoted 6 lines
drivers/mmc/core/core.c +2
-0+mmc_card_set_check_bkops (host->card); +mmc_host_clk_release (host); } }@@ -245,6 +252,76 @@ mmc_start_request(struct mmc_host *host,struct
mmc_request*mrq)Quoted 17 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 255
Quoted 4 lines
drivers/mmc/core/core.c +1
-0host->ops->request (host, mrq); } +static void mmc_send_bkops_cmd (struct mmc_card *card)I guess name should be
mmc_send_bkops_start_cmd().drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 266
Quoted 11 lines
drivers/mmc/core/core.c +11
-0+{ +int err; + +BUG_ON (!card); + + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_START ,1 ,0 ); +if (err) { +pr_warning ("%s: error %d starting bkops\n" , +mmc_hostname (card->host), err); +mmc_card_clr_need_bkops (card);In case of failure, why are we clearing the
NEED_BKOPSflag? You stillneed
Quoted 3 lines
the BKOPS, correct?
Right it's need the BKOPS. if card need the bkops, at next time card
should be
Quoted 62 lines
informed to host.
Quoted 7 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) · line 272
Quoted 6 lines
drivers/mmc/core/core.c +6
-0+return ; + } + +mmc_card_clr_need_bkops (card); +mmc_card_set_doing_bkops (card); +You can remove this extra line here.
I will remove..
Quoted 17 lines
Quoted 17 lines
drivers/mmc/core/core.c +17
-0+} + +void mmc_start_periodic_bkops (struct work_struct *work) { + struct mmc_host *host = container_of(work, struct mmc_host, + start_bkops.work); + +mmc_card_set_check_bkops (host->card); + +mmc_claim_host (host); +mmc_start_bkops (host->card); +mmc_release_host (host); +} +EXPORT_SYMBOL (mmc_start_periodic_bkops); + +/** +* mmc_start_bkops - start BKOPS for supported cards +* @card: MMC card to start BKOPS Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
Quoted 8 lines
drivers/mmc/core/core.c +8
-0+* +* Start background operations whenever requested. +* when the urgent BKOPS bit is set in a R1 command response +* then background operations should be started immediately. +*/ +void mmc_start_bkops (struct mmc_card *card) { +BUG_ON (!card); + if (!card->ext_csd.bkops_en || !(card->host->caps2&
MMC_CAP2_BKOPS))Quoted 16 lines
Quoted 16 lines
drivers/mmc/core/core.c +16
-0+return ; + +if (mmc_card_check_bkops (card)) { +mmc_card_clr_check_bkops (card); +if (mmc_is_exception_event (card,EXT_CSD_URGENT_BKOPS )) { +if (card->ext_csd.raw_bkops_status) +mmc_card_set_need_bkops (card); + }else +mmc_card_clr_need_bkops (card); + } + +/* +* If card_need_bkops_flag didn't set, then do nothing just +* return +*/ +if (mmc_card_doing_bkops (card) || !mmc_card_need_bkops (card))Quoted 8 lines
drivers/mmc/core/core.c mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
Quoted 7 lines
drivers/mmc/core/core.c +7
-0+ goto check_bkops; + +mmc_send_bkops_cmd (card); + +check_bkops: +queue_delayed_work (system_nrt_wq,&card->host->start_bkops,5 * +HZ );Can we use the deferrable timer for this delayed work? If it's not
Quoted 2 lines
deferrable and if CPU is some low power state, it has to wakeup and serve this timer on it's expiration. Better make it deferrable so it won't
wakeup the
Quoted 3 lines
system when timer expires.
i will check this point..if you have other approach for periodic checking,
let
Quoted 1 line
me know..it's helpful to me.
You can use the "
system_nrt_freezable_wq" to queue the work instead of "system_nrt_wq". Check out this patch for reference:
https://lkml.org/lkml/2012/3/16/593 which had added this new type of workqueue.Regards,
SubhashQuoted 5 lines
Quoted 3 lines
Also, just wondering, how came to this 5 sec timeout?
Nothing..it's just setting for testing. We need the discussion to set how
long
Quoted 33 lines
time..
Quoted 7 lines
drivers/mmc/core/core.c struct mmc_async_req *mmc_start_req(struct
Quoted 7 lines
drivers/mmc/core/core.c +3
-0+} +EXPORT_SYMBOL (mmc_start_bkops); +static void mmc_wait_done (struct mmc_request *mrq) {complete (&mrq->completion);@@ -348,8 +425,10 @@ struct mmc_async_req *mmc_start_req(struct
mmc_host*host,Quoted 9 lines
Quoted 9 lines
drivers/mmc/core/core.c +3
-1struct mmc_async_req *data = host->areq;/* Prepare a new request */ -if (areq) +if (areq) { +cancel_delayed_work_sync (&host->start_bkops);mmc_pre_req (host, areq->mrq, !host->areq); + }Quoted 3 lines
drivers/mmc/core/core.c struct mmc_async_req *mmc_start_req(struct
Quoted 3 lines
drivers/mmc/core/core.c +1
-0if (host->areq) { mmc_wait_for_req_done(host, host->areq->mrq); @@ -359,8 +438,11 @@ struct mmc_async_req *mmc_start_req(struct mmc_host*host,
Quoted 10 lines
Quoted 10 lines
if (!err&& areq) start_err = __mmc_start_req(host, areq->mrq);drivers/mmc/core/core.c +4
-1-if (host->areq) +if (host->areq) {mmc_post_req (host, host->areq->mrq,0 ); +if (!areq&& host->areq&&mmc_card_mmc (host->card)) +mmc_start_bkops (host->card); + }Quoted 19 lines
Quoted 3 lines
Quoted 3 lines
/* Cancel a prepared request if it was not started. */ if ((err || start_err)&& areq) @@ -480,6 +562,84 @@ intmmc_wait_for_cmd(struct
mmc_host*host, structmmc_command*cmd, int retries
Quoted 15 lines
Quoted 11 lines
EXPORT_SYMBOL(mmc_wait_for_cmd);/**
+ *mmc_stop_bkops- stop ongoing BKOPS
+ * @card: MMC card to check BKOPS
+ *+ * Send HPI command to interrupt ongoing background operations, + * to allow rapid servicing of foreground operations,e.g. read/ + * writes. Wait until the card comes out of the programming state + * to avoid errors in servicing read/write requests.+ */
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 576
Quoted 3 lines
drivers/mmc/core/core.c +3
-0+int mmc_stop_bkops (struct mmc_card *card) { +int err =0 ; +unsigned int timeout =0x10000 ;How this
0x10000value is calculated? Is there any defined timeout valuefor
Quoted 1 line
card to come out of programming after starting the BKOPS? if not, then
let's
Quoted 1 line
wait indefinitely for it to come out of the programming state? Don't we
wait
Quoted 3 lines
indefinitely for write request?
This timeout value also is just setting. in my case, when i set to
0x10000,Quoted 26 lines
performance is impacted lower than other value.
Quoted 16 lines
Quoted 16 lines
drivers/mmc/core/core.c +16
-0+u32 status; + +BUG_ON (!card); +cancel_delayed_work_sync (&card->host->start_bkops); + +if (card->ext_csd.raw_bkops_status ==EXT_CSD_BKOPS_LEVEL_3 ) { +do { +if (timeout ==0 ) +break ; +mmc_claim_host (card->host); +mmc_send_status (card,&status); +mmc_release_host (card->host); + + timeout--; + }while (R1_CURRENT_STATE (status) ==R1_STATE_PRG ); +if (timeout !=0 )Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries · line 599
Quoted 7 lines
drivers/mmc/core/core.c +7
-0+ goto done; + } + + err =mmc_interrupt_hpi (card); + +done: +mmc_card_clr_doing_bkops (card);Here even if
mmc_interrupt_hpi()fails, you are clearing theDOING_BKOPSQuoted 1 line
flag which is not correct. Which should clear this flag if HPI issued
successfully.
Quoted 134 lines
i will modify this point..
Thanks for review...i will modify with your comment at next-version. if you have other comment or approach..let me know plz..
Best Regards,
Jaehoon ChungQuoted 8 lines
Quoted 8 lines
drivers/mmc/core/core.c +8
-0+ +return err; +} +EXPORT_SYMBOL (mmc_stop_bkops); + +int mmc_read_bkops_status (struct mmc_card *card) { +int err; +u8 ext_csd[512 ];Quoted 8 lines
drivers/mmc/core/core.c int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
Quoted 8 lines
drivers/mmc/core/core.c +8
-0+ +mmc_claim_host (card->host); + err =mmc_send_ext_csd (card, ext_csd); +mmc_release_host (card->host); +if (err) +return err; + + card->ext_csd.raw_bkops_status =ext_csd[EXT_CSD_BKOPS_STATUS];
Quoted 22 lines
Quoted 22 lines
drivers/mmc/core/core.c +22
-0+ card->ext_csd.raw_exception_status = + ext_csd[EXT_CSD_EXCEPTION_STATUS ]; + +return 0 ; +} +EXPORT_SYMBOL (mmc_read_bkops_status); + +int mmc_is_exception_event (struct mmc_card *card,unsigned int +value) { +int err; + + err =mmc_read_bkops_status (card); +if (err) { +pr_err ("%s: Didn't read bkops status : %d\n" , +mmc_hostname (card->host), err); +return 0 ; + } + +/* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */ +if (card->ext_csd.rev ==5 ) +return 1 ; +Quoted 8 lines
drivers/mmc/core/core.c int mmc_pm_notify(struct notifier_block
Quoted 8 lines
drivers/mmc/core/core.c +4
-0+return (card->ext_csd.raw_exception_status& value) ?1 :0 ; } +EXPORT_SYMBOL (mmc_is_exception_event); + +/** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer @@ -2382,6 +2542,12 @@ int mmc_pm_notify(struct notifier_block
*notify_block,Quoted 10 lines
Quoted 10 lines
drivers/mmc/core/core.c +6
-0switch (mode) {case PM_HIBERNATION_PREPARE :case PM_SUSPEND_PREPARE : +if (host->card&&mmc_card_mmc (host->card)&& +mmc_card_doing_bkops (host->card)) { +mmc_interrupt_hpi (host->card); +mmc_card_clr_doing_bkops (host->card); + } +cancel_delayed_work_sync (&host->start_bkops);Quoted 7 lines
drivers/mmc/core/host.c struct mmc_host *mmc_alloc_host(int extra,
Quoted 7 lines
drivers/mmc/core/core.c +0
-0spin_lock_irqsave (&host->lock, flags); host->rescan_disable =1 ;drivers/mmc/core/host.c index renamed from drivers/mmc/core/host.c +0
-091c84c7..3b6a8e4 100644
drivers/mmc/core/host.c +0
-0@@ -330,6 +330,7 @@ struct mmc_host *mmc_alloc_host(int extra,struct device *dev)
Quoted 4 lines
drivers/mmc/core/host.c struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
Quoted 4 lines
drivers/mmc/core/host.c +1
-0spin_lock_init (&host->lock);init_waitqueue_head (&host->wq);INIT_DELAYED_WORK (&host->detect, mmc_rescan); + INIT_DELAYED_WORK(&host->start_bkops,
mmc_start_periodic_bkops);Quoted 8 lines
drivers/mmc/core/mmc.c static int mmc_read_ext_csd(struct mmc_card
Quoted 8 lines
drivers/mmc/core/host.c +0
-0#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify;#endif drivers/mmc/core/mmc.c index renamed from drivers/mmc/core/mmc.c +0
-02f0e11c..275555a 100644
drivers/mmc/core/mmc.c +0
-0@@ -463,6 +463,24 @@ static int mmc_read_ext_csd(struct mmc_card*card, u8
*ext_csd)Quoted 17 lines
Quoted 17 lines
drivers/mmc/core/mmc.c +14
-0}if (card->ext_csd.rev>=5 ) { +/* check whether the eMMC card support BKOPS */ +if (ext_csd[EXT_CSD_BKOPS_SUPPORT ]&0x1 ) { + card->ext_csd.bkops =1 ; + card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN ]; + card->ext_csd.raw_bkops_status = + ext_csd[EXT_CSD_BKOPS_STATUS ]; +if (!card->ext_csd.bkops_en&& + card->host->caps2&MMC_CAP2_INIT_BKOPS ) { + err =mmc_switch (card,EXT_CSD_CMD_SET_NORMAL , +EXT_CSD_BKOPS_EN ,1 ,0 ); +if (err) +pr_warning ("%s: Enabling BKOPS failed\n" , +mmc_hostname (card->host)); +else Quoted 8 lines
Review
Quoted 8 lines
drivers/mmc/core/mmc.c +4
-0+ card->ext_csd.bkops_en =1 ; + } + } +/* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES ]&0x1 ) { card->ext_csd.hpi =1 ;(quoted diff) +0
-0
b/drivers/mmc/core/mmc_ops.cQuoted 4 lines
drivers/mmc/core/mmc_ops.c int mmc_switch(struct mmc_card *card, u8 set,
Quoted 4 lines
index 69370f4..bc8da17 100644
drivers/mmc/core/mmc_ops.c +0
-0@@ -399,6 +399,10 @@ int mmc_switch(struct mmc_card *card, u8 set,u8 index, u8 value,
Quoted 14 lines
Quoted 14 lines
drivers/mmc/core/mmc_ops.c +4
-0if (err)return err; +/* No need to check card status in case of BKOPS switch*/ +if (index ==EXT_CSD_BKOPS_START ) +return 0 ; +/* Must check status to be sure of no errors */ do { err = mmc_send_status(card,&status); diff --git
a/include/linux/mmc/card.hb/include/linux/mmc/card.hindex d76513b..52b507d 100644include/linux/mmc/card.h +0
-0Quoted 8 lines
Quoted 8 lines
include/linux/mmc/card.h struct mmc_ext_csd { · line 82
Quoted 8 lines
include/linux/mmc/card.h +3
-0@@ -76,6 +76,9 @@ struct mmc_ext_csd {bool hpi_en;/* HPI enablebit */ bool hpi;/* HPI support bit */ unsigned int hpi_cmd;/* cmd used as HPI */ +bool bkops;/* background support bit */ +bool bkops_en;/* background enable bit */ +u8 raw_exception_status;/* 53 */ unsigned int data_sector_size;/* 512 bytes or 4KB */
Quoted 1 line
Quoted 1 line
include/linux/mmc/card.h struct mmc_ext_csd { · line 83
Quoted 1 line
include/linux/mmc/card.h +0
-0unsigned int data_tag_unit_size;/* DATA TAG UNIT size */
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
include/linux/mmc/card.h +1
-0unsigned int boot_ro_lock;/* ro lock support */ @@ -93,6 +96,7 @@ struct mmc_ext_csd {u8 raw_sec_erase_mult;/* 230 */ u8 raw_sec_feature_support;/* 231 */ u8 raw_trim_mult;/* 232 */ +u8 raw_bkops_status;/* 246 */ u8 raw_sectors[4 ];/* 212 - 4 bytes */ Quoted 7 lines
Quoted 3 lines
include/linux/mmc/card.h struct mmc_card { · line 229
Quoted 3 lines
include/linux/mmc/card.h +0
-0unsigned int feature_support;@@ -225,6 +229,9 @@ struct mmc_card {#define MMC_CARD_REMOVED (1<<7)/* card has been removed */
Quoted 1 line
include/linux/mmc/card.h struct mmc_card { · line 230
Quoted 1 line
include/linux/mmc/card.h +0
-0#define MMC_STATE_HIGHSPEED_200 (1<<8)/* card is in HS200 mode */
Quoted 1 line
Quoted 1 line
include/linux/mmc/card.h +0
-0#define MMC_STATE_SLEEP (1<<9)/* card is in sleep state */
Quoted 172 lines
Quoted 1 line
include/linux/mmc/card.h struct mmc_card { · line 232
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define MMC_STATE_NEED_BKOPS (1<<10)/* card need to do BKOPS */
Quoted 1 line
include/linux/mmc/card.h struct mmc_card { · line 233
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define MMC_STATE_DOING_BKOPS (1<<11)/* card is doing BKOPS */
Quoted 1 line
include/linux/mmc/card.h struct mmc_card { · line 234
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define MMC_STATE_CHECK_BKOPS (1<<12)/* card need to check BKOPS */
Quoted 2 lines
include/linux/mmc/card.h struct mmc_card { · line 236
Quoted 2 lines
include/linux/mmc/card.h +0
-0unsigned int quirks;/* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0)/* allow SDIO FN0 writes outside of the VS CCCR range */
Quoted 3 lines
include/linux/mmc/card.h struct mmc_card { · line 237
Quoted 1 line
include/linux/mmc/card.h +0
-0#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)/* use func-
cur_blksize*/include/linux/mmc/card.h static inline void __maybe_unused
Quoted 1 line
include/linux/mmc/card.h +0
-0@@ -391,6 +398,9 @@ static inline void __maybe_unused
remove_quirk(struct mmc_card *card, int data)Quoted 2 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 399
Quoted 2 lines
include/linux/mmc/card.h +0
-0#define mmc_card_ext_capacity (c) ((c)->state& MMC_CARD_SDXC)#define mmc_card_removed (c) ((c)&& ((c)->state&
MMC_CARD_REMOVED))Quoted 2 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 401
Quoted 2 lines
include/linux/mmc/card.h +1
-0#define mmc_card_is_sleep (c) ((c)->state& MMC_STATE_SLEEP) +#define mmc_card_need_bkops (c) ((c)->state&
MMC_STATE_NEED_BKOPS)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 402
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define mmc_card_doing_bkops (c) ((c)->state&
MMC_STATE_DOING_BKOPS)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 403
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define mmc_card_check_bkops (c) ((c)->state&
MMC_STATE_CHECK_BKOPS)Quoted 2 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 404
Quoted 2 lines
include/linux/mmc/card.h +0
-0#define mmc_card_set_present (c) ((c)->state |=
MMC_STATE_PRESENT)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 405
Quoted 1 line
include/linux/mmc/card.h +0
-0#define mmc_card_set_readonly (c) ((c)->state |=
MMC_STATE_READONLY)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused
Quoted 1 line
include/linux/mmc/card.h +0
-0@@ -403,7 +413,13 @@ static inline void __maybe_unused
remove_quirk(struct mmc_card *card, int data)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 413
Quoted 1 line
include/linux/mmc/card.h +0
-0#define mmc_card_set_ext_capacity (c) ((c)->state |=
MMC_CARD_SDXC)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 414
Quoted 1 line
include/linux/mmc/card.h +0
-0#define mmc_card_set_removed (c) ((c)->state |=
MMC_CARD_REMOVED)Quoted 2 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 416
Quoted 2 lines
include/linux/mmc/card.h +1
-0#define mmc_card_set_sleep (c) ((c)->state |= MMC_STATE_SLEEP) +#define mmc_card_set_need_bkops (c) ((c)->state |=
MMC_STATE_NEED_BKOPS)Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 417
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define mmc_card_set_doing_bkops (c) ((c)->state |=
MMC_STATE_DOING_BKOPS)Quoted 4 lines
include/linux/mmc/card.h static inline void __maybe_unused · line 421
Quoted 4 lines
include/linux/mmc/card.h +3
-0+#define mmc_card_set_check_bkops (c) ((c)->state |= +MMC_STATE_CHECK_BKOPS) +#define mmc_card_clr_need_bkops (c) ((c)->state&=~MMC_STATE_NEED_BKOPS)
Quoted 1 line
include/linux/mmc/card.h static inline void __maybe_unused · line 422
Quoted 1 line
include/linux/mmc/card.h +1
-0+#define mmc_card_clr_doing_bkops (c) ((c)->state&=~MMC_STATE_DOING_BKOPS)
Quoted 13 lines
Quoted 13 lines
include/linux/mmc/card.h +2
-0+#define mmc_card_clr_check_bkops (c) ((c)->state&= +~MMC_STATE_CHECK_BKOPS)#define mmc_card_clr_sleep (c) ((c)->state&= ~MMC_STATE_SLEEP)/* * Quirk add/remove for MMC products. include/linux/mmc/core.h +0
-0@@ -134,6 +134,9 @@ struct mmc_host;struct mmc_card ;struct mmc_async_req ;Quoted 9 lines
Quoted 9 lines
include/linux/mmc/core.h +3
-0+extern int mmc_stop_bkops (struct mmc_card *);extern int +mmc_read_bkops_status (struct mmc_card *);extern int +mmc_is_exception_event (struct mmc_card *,unsigned int );extern struct mmc_async_req *mmc_start_req (struct mmc_host *,struct mmc_async_req *,int *); extern int mmc_interrupt_hpi(struct mmc_card *); @@ -163,6 +166,8@@ extern int
mmc_can_sanitize(struct mmc_card *card);
extern intmmc_can_secure_erase_trim(struct mmc_card *card); extern int mmc_erase_group_aligned(structmmc_card*card, unsignedint from,
Quoted 5 lines
Quoted 5 lines
unsigned int nr);include/linux/mmc/core.h +2
-0+extern void mmc_start_periodic_bkops (struct work_struct *work); +extern void mmc_start_bkops (struct mmc_card *card);extern unsigned int mmc_calc_max_discard (struct mmc_card *card);Quoted 7 lines
include/linux/mmc/host.h struct mmc_host { · line 238
Quoted 7 lines
extern int mmc_set_blocklen(struct
mmc_card*card, unsigned int
blocklen); diff --gita/include/linux/mmc/host.hb/include/linux/mmc/host.hindex 0707d22..186d146 100644include/linux/mmc/host.h +0
-0@@ -238,6 +238,8 @@ struct mmc_host {#define MMC_CAP2_BROKEN_VOLTAGE (1<< 7)/* Use the broken voltage */
Quoted 1 line
include/linux/mmc/host.h struct mmc_host { · line 239
Quoted 1 line
include/linux/mmc/host.h +0
-0#define MMC_CAP2_DETECT_ON_ERR (1<< 8)/* On I/O err check card removal */
Quoted 1 line
include/linux/mmc/host.h struct mmc_host { · line 240
Quoted 1 line
include/linux/mmc/host.h +0
-0#define MMC_CAP2_HC_ERASE_SZ (1<< 9)/* High-capacity erase size */
Quoted 14 lines
Quoted 14 lines
include/linux/mmc/host.h +4
-0+#define MMC_CAP2_INIT_BKOPS (1<< 10)/* To enable BKOPS */ +#define MMC_CAP2_BKOPS (1<< 11)/* BKOPS supported */ mmc_pm_flag_t pm_caps;/* supported pm features */ unsigned int power_notify_type;@@ -320,6 +322,8 @@ struct mmc_host {unsigned int actual_clock;/* Actual HC clock rate */ +struct delayed_work start_bkops;/* Periodic bkops start */ +unsigned long private[0 ]____cacheline_aligned ; };Quoted 6 lines
include/linux/mmc/mmc.h static inline bool mmc_op_multi(u32 opcode) · line 139
Quoted 6 lines
include/linux/mmc/mmc.h index renamed from include/linux/mmc/mmc.h +0
-0d425cab..06afeb4 100644
include/linux/mmc/mmc.h +0
-0@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode)#define R1_CURRENT_STATE (x) ((x& 0x00001E00)>> 9)/* sx, b (4 bits) */
Quoted 35 lines
Quoted 35 lines
include/linux/mmc/mmc.h +6
-0#define R1_READY_FOR_DATA (1<< 8)/* sx, a */ #define R1_SWITCH_ERROR (1<< 7)/* sx, c */ +#define R1_EXCEPTION_EVENT (1<< 6)/* sx, a */ #define R1_APP_CMD (1<< 5)/* sr, c */ #define R1_STATE_IDLE 0@@ -274,12 +275,15 @@ struct _mmc_csd {#define EXT_CSD_FLUSH_CACHE 32/* W */ #define EXT_CSD_CACHE_CTRL 33/* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34/* R/W */ +#define EXT_CSD_EXCEPTION_STATUS 54/* RO */ #define EXT_CSD_DATA_SECTOR_SIZE 61/* R */ #define EXT_CSD_GP_SIZE_MULT 143/* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156/* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160/* RO */ #define EXT_CSD_HPI_MGMT 161/* R/W */ #define EXT_CSD_RST_N_FUNCTION 162/* R/W */ +#define EXT_CSD_BKOPS_EN 163/* R/W */ +#define EXT_CSD_BKOPS_START 164/* W */ #define EXT_CSD_SANITIZE_START 165/* W */ #define EXT_CSD_WR_REL_PARAM 166/* RO */ #define EXT_CSD_BOOT_WP 173/* R/W */ @@ -313,11 +317,13 @@ struct _mmc_csd {#define EXT_CSD_PWR_CL_200_360 237/* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238/* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239/* RO */ +#define EXT_CSD_BKOPS_STATUS 246/* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247/* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248/* RO */ #define EXT_CSD_CACHE_SIZE 249/* RO, 4 bytes */ #define EXT_CSD_TAG_UNIT_SIZE 498/* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499/* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502/* RO */ #define EXT_CSD_HPI_FEATURES 503/* RO */ Quoted 3 lines
include/linux/mmc/mmc.h struct _mmc_csd { · line 392
Quoted 3 lines
include/linux/mmc/mmc.h +0
-0/* @@ -386,4 +392,18 @@ struct _mmc_csd {#define MMC_SWITCH_MODE_CLEAR_BITS 0x02/* Clear bits which are 1 in value */
Quoted 1 line
include/linux/mmc/mmc.h struct _mmc_csd { · line 393
Quoted 1 line
include/linux/mmc/mmc.h +0
-0#define MMC_SWITCH_MODE_WRITE_BYTE 0x03/* Set target to value */
Quoted 10 lines
Quoted 10 lines
include/linux/mmc/mmc.h +9
-0+/* +* BKOPS status level +*/ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +#define EXT_CSD_BKOPS_LEVEL_3 0x3 + +/* +* EXCEPTION_EVENT_STATUS field (eMMC4.5) */ +#define EXT_CSD_URGENT_BKOPS BIT(0)Quoted 8 lines
Quoted 8 lines
include/linux/mmc/mmc.h +4
-1+#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) +#define EXT_CSD_PACKED_FAILURE BIT(3) +#endif /* LINUX_MMC_MMC_H */ --To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected] More
majordomo
Quoted 5 lines
Quoted 1 line
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected] MoreQuoted 7 lines
majordomo
Quoted 2 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" inthe
Quoted 2 lines
body of a message to [email protected] More majordomo info at
http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html