Loading drivers/mmc/card/block.c +17 −3 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include <linux/mmc/ioctl.h> #include <linux/mmc/card.h> #include <linux/mmc/core.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> Loading Loading @@ -3311,7 +3312,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) unsigned long flags; unsigned int cmd_flags = req ? req->cmd_flags : 0; if (req && !mq->mqrq_prev->req) if (req && !mq->mqrq_prev->req) { /* claim host only for the first request */ mmc_get_card(card); Loading @@ -3319,6 +3320,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) if (mmc_bus_needs_resume(card->host)) mmc_resume_bus(card->host); #endif if (mmc_card_doing_bkops(host->card)) { ret = mmc_stop_bkops(host->card); if (ret) goto out; } } ret = mmc_blk_part_switch(card, md); if (ret) { Loading Loading @@ -3842,7 +3849,14 @@ static int mmc_blk_probe(struct mmc_card *card) goto out; } pm_runtime_set_autosuspend_delay(&card->dev, 3000); pm_runtime_set_autosuspend_delay(&card->dev, MMC_AUTOSUSPEND_DELAY_MS); /* * If there is a runtime_idle function, it should take care of * suspending the card */ if (card->host->bus_ops->runtime_idle) pm_runtime_dont_use_autosuspend(&card->dev); else pm_runtime_use_autosuspend(&card->dev); /* Loading drivers/mmc/core/bus.c +11 −1 Original line number Diff line number Diff line Loading @@ -205,10 +205,20 @@ static int mmc_runtime_resume(struct device *dev) return host->bus_ops->runtime_resume(host); } static int mmc_runtime_idle(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; return host->bus_ops->runtime_idle(host); } #endif /* !CONFIG_PM_RUNTIME */ static const struct dev_pm_ops mmc_bus_pm_ops = { SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, NULL) SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, mmc_runtime_idle) SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume) }; Loading drivers/mmc/core/core.c +114 −40 Original line number Diff line number Diff line Loading @@ -865,24 +865,71 @@ static void mmc_start_cmdq_request(struct mmc_host *host, } /** * mmc_start_bkops - start BKOPS for supported cards * mmc_set_auto_bkops - set auto BKOPS for supported cards * @card: MMC card to start BKOPS * @form_exception: A flag to indicate if this function was * called due to an exception raised by the card * @enable: enable/disable flag * * Start background operations whenever requested. * When the urgent BKOPS bit is set in a R1 command response * then background operations should be started immediately. * Configure the card to run automatic BKOPS. * * Should be called when host is claimed. */ void mmc_start_bkops(struct mmc_card *card, bool from_exception) int mmc_set_auto_bkops(struct mmc_card *card, bool enable) { int ret = 0; u8 bkops_en; BUG_ON(!card); enable = !!enable; if (unlikely(!mmc_card_support_auto_bkops(card))) { pr_err("%s: %s: card doesn't support auto bkops\n", mmc_hostname(card->host), __func__); return -EPERM; } if (enable) { if (mmc_card_doing_auto_bkops(card)) goto out; bkops_en = card->ext_csd.bkops_en | EXT_CSD_BKOPS_AUTO_EN; } else { if (!mmc_card_doing_auto_bkops(card)) goto out; bkops_en = card->ext_csd.bkops_en & ~EXT_CSD_BKOPS_AUTO_EN; } ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, bkops_en, 0); if (ret) { pr_err("%s: %s: error in setting auto bkops to %d (%d)\n", mmc_hostname(card->host), __func__, enable, ret); } else { if (enable) mmc_card_set_auto_bkops(card); else mmc_card_clr_auto_bkops(card); card->ext_csd.bkops_en = bkops_en; } out: return ret; } EXPORT_SYMBOL(mmc_set_auto_bkops); /** * mmc_check_bkops - check BKOPS for supported cards * @card: MMC card to check BKOPS * * Read the BKOPS status in order to determine whether the * card requires bkops to be started. */ void mmc_check_bkops(struct mmc_card *card) { int err; int timeout; bool use_busy_signal; BUG_ON(!card); if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card)) if (unlikely(!mmc_card_configured_manual_bkops(card))) return; if (mmc_card_doing_bkops(card) || mmc_card_doing_auto_bkops(card)) return; err = mmc_read_bkops_status(card); Loading @@ -892,42 +939,44 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) return; } if (!card->ext_csd.raw_bkops_status) if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2) return; card->bkops.needs_manual = true; } EXPORT_SYMBOL(mmc_check_bkops); /** * mmc_start_manual_bkops - start BKOPS for supported cards * @card: MMC card to start BKOPS * * Send START_BKOPS to the card. */ void mmc_start_manual_bkops(struct mmc_card *card) { int err; BUG_ON(!card); if (unlikely(!mmc_card_configured_manual_bkops(card))) return; if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 && from_exception) if (mmc_card_doing_bkops(card)) return; mmc_claim_host(card->host); if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) { timeout = MMC_BKOPS_MAX_TIMEOUT; use_busy_signal = true; } else { timeout = 0; use_busy_signal = false; } err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true, false); err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_START, 1, 0, false, true, false); if (err) { pr_warn("%s: Error %d starting bkops\n", pr_err("%s: Error %d starting manual bkops\n", mmc_hostname(card->host), err); goto out; } /* * For urgent bkops status (LEVEL_2 and more) * bkops executed synchronously, otherwise * the operation is in progress */ if (!use_busy_signal) } else { mmc_card_set_doing_bkops(card); out: card->bkops.needs_manual = false; } mmc_release_host(card->host); } EXPORT_SYMBOL(mmc_start_bkops); EXPORT_SYMBOL(mmc_start_manual_bkops); /* * mmc_wait_data_done() - done callback for data request Loading Loading @@ -1280,7 +1329,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) || (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) && (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) mmc_start_bkops(host->card, true); mmc_check_bkops(host->card); } if (!err && areq) { Loading Loading @@ -1437,6 +1486,11 @@ int mmc_stop_bkops(struct mmc_card *card) int err = 0; BUG_ON(!card); if (unlikely(!mmc_card_configured_manual_bkops(card))) goto out; if (!mmc_card_doing_bkops(card)) goto out; err = mmc_interrupt_hpi(card); /* Loading @@ -1447,7 +1501,7 @@ int mmc_stop_bkops(struct mmc_card *card) mmc_card_clr_doing_bkops(card); err = 0; } out: return err; } EXPORT_SYMBOL(mmc_stop_bkops); Loading Loading @@ -1705,6 +1759,19 @@ void mmc_get_card(struct mmc_card *card) } EXPORT_SYMBOL(mmc_get_card); /* * This is a helper function, which drops the runtime * pm reference for the card device. */ static void __mmc_put_card(struct mmc_card *card) { /* In case of runtime_idle, it will handle the suspend */ if (card->host->bus_ops->runtime_idle) pm_runtime_put(&card->dev); else pm_runtime_put_autosuspend(&card->dev); } /* * This is a helper function, which releases the host and drops the runtime * pm reference for the card device. Loading @@ -1713,7 +1780,7 @@ void mmc_put_card(struct mmc_card *card) { mmc_release_host(card->host); pm_runtime_mark_last_busy(&card->dev); pm_runtime_put_autosuspend(&card->dev); __mmc_put_card(card); } EXPORT_SYMBOL(mmc_put_card); Loading @@ -1725,6 +1792,13 @@ void mmc_set_ios(struct mmc_host *host) { struct mmc_ios *ios = &host->ios; if (unlikely(ios->power_mode == MMC_POWER_OFF && host->card && mmc_card_doing_auto_bkops(host->card))) { pr_err("%s: %s: illegal to disable power to card when running auto bkops\n", mmc_hostname(host), __func__); return; } pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " "width %u timing %u\n", mmc_hostname(host), ios->clock, ios->bus_mode, Loading drivers/mmc/core/core.h +0 −15 Original line number Diff line number Diff line Loading @@ -15,21 +15,6 @@ #define MMC_CMD_RETRIES 3 struct mmc_bus_ops { void (*remove)(struct mmc_host *); void (*detect)(struct mmc_host *); int (*pre_suspend)(struct mmc_host *); int (*suspend)(struct mmc_host *); int (*resume)(struct mmc_host *); int (*runtime_suspend)(struct mmc_host *); int (*runtime_resume)(struct mmc_host *); int (*power_save)(struct mmc_host *); int (*power_restore)(struct mmc_host *); int (*alive)(struct mmc_host *); int (*shutdown)(struct mmc_host *); int (*change_bus_speed)(struct mmc_host *, unsigned long *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); void mmc_detach_bus(struct mmc_host *host); Loading drivers/mmc/core/mmc.c +51 −3 Original line number Diff line number Diff line Loading @@ -570,6 +570,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) */ card->ext_csd.out_of_int_time = ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; pr_info("%s: Out-of-interrupt timeout is %d[ms]\n", mmc_hostname(card->host), card->ext_csd.out_of_int_time); } if (card->ext_csd.rev >= 5) { Loading @@ -584,9 +587,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) 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) pr_info("%s: BKOPS_EN bit is not set\n", mmc_hostname(card->host)); pr_info("%s: BKOPS_EN equals 0x%x\n", mmc_hostname(card->host), card->ext_csd.bkops_en); } card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; Loading Loading @@ -1959,6 +1963,23 @@ reinit: } } /* * Start auto bkops, if supported. * * Note: This leaves the possibility of having both manual and * auto bkops running in parallel. The runtime implementation * will allow this, but ignore bkops exceptions on the premises * that auto bkops will eventually kick in and the device will * handle bkops without START_BKOPS from the host. */ if (mmc_card_support_auto_bkops(card)) { /* * Ignore the return value of setting auto bkops. * If it failed, will run in backward compatible mode. */ (void)mmc_set_auto_bkops(card, true); } return 0; free_card: Loading Loading @@ -2157,6 +2178,12 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) goto out; } if (mmc_card_doing_auto_bkops(host->card)) { err = mmc_set_auto_bkops(host->card, false); if (err) goto out; } err = mmc_flush_cache(host->card); if (err) goto out; Loading Loading @@ -2351,6 +2378,26 @@ static int mmc_power_restore(struct mmc_host *host) return ret; } #define NO_AUTOSUSPEND (-1) static int mmc_runtime_idle(struct mmc_host *host) { BUG_ON(!host->card); if (host->card->bkops.needs_manual) mmc_start_manual_bkops(host->card); pm_runtime_mark_last_busy(&host->card->dev); /* * TODO: consider prolonging suspend when bkops * is running in order to allow a longer time for * bkops to complete * */ pm_schedule_suspend(&host->card->dev, MMC_AUTOSUSPEND_DELAY_MS); /* return negative value in order to avoid autosuspend */ return NO_AUTOSUSPEND; } static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, Loading @@ -2358,6 +2405,7 @@ static const struct mmc_bus_ops mmc_ops = { .resume = mmc_resume, .runtime_suspend = mmc_runtime_suspend, .runtime_resume = mmc_runtime_resume, .runtime_idle = mmc_runtime_idle, .power_restore = mmc_power_restore, .alive = mmc_alive, .shutdown = mmc_shutdown, Loading Loading
drivers/mmc/card/block.c +17 −3 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include <linux/mmc/ioctl.h> #include <linux/mmc/card.h> #include <linux/mmc/core.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> Loading Loading @@ -3311,7 +3312,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) unsigned long flags; unsigned int cmd_flags = req ? req->cmd_flags : 0; if (req && !mq->mqrq_prev->req) if (req && !mq->mqrq_prev->req) { /* claim host only for the first request */ mmc_get_card(card); Loading @@ -3319,6 +3320,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) if (mmc_bus_needs_resume(card->host)) mmc_resume_bus(card->host); #endif if (mmc_card_doing_bkops(host->card)) { ret = mmc_stop_bkops(host->card); if (ret) goto out; } } ret = mmc_blk_part_switch(card, md); if (ret) { Loading Loading @@ -3842,7 +3849,14 @@ static int mmc_blk_probe(struct mmc_card *card) goto out; } pm_runtime_set_autosuspend_delay(&card->dev, 3000); pm_runtime_set_autosuspend_delay(&card->dev, MMC_AUTOSUSPEND_DELAY_MS); /* * If there is a runtime_idle function, it should take care of * suspending the card */ if (card->host->bus_ops->runtime_idle) pm_runtime_dont_use_autosuspend(&card->dev); else pm_runtime_use_autosuspend(&card->dev); /* Loading
drivers/mmc/core/bus.c +11 −1 Original line number Diff line number Diff line Loading @@ -205,10 +205,20 @@ static int mmc_runtime_resume(struct device *dev) return host->bus_ops->runtime_resume(host); } static int mmc_runtime_idle(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; return host->bus_ops->runtime_idle(host); } #endif /* !CONFIG_PM_RUNTIME */ static const struct dev_pm_ops mmc_bus_pm_ops = { SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, NULL) SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, mmc_runtime_idle) SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume) }; Loading
drivers/mmc/core/core.c +114 −40 Original line number Diff line number Diff line Loading @@ -865,24 +865,71 @@ static void mmc_start_cmdq_request(struct mmc_host *host, } /** * mmc_start_bkops - start BKOPS for supported cards * mmc_set_auto_bkops - set auto BKOPS for supported cards * @card: MMC card to start BKOPS * @form_exception: A flag to indicate if this function was * called due to an exception raised by the card * @enable: enable/disable flag * * Start background operations whenever requested. * When the urgent BKOPS bit is set in a R1 command response * then background operations should be started immediately. * Configure the card to run automatic BKOPS. * * Should be called when host is claimed. */ void mmc_start_bkops(struct mmc_card *card, bool from_exception) int mmc_set_auto_bkops(struct mmc_card *card, bool enable) { int ret = 0; u8 bkops_en; BUG_ON(!card); enable = !!enable; if (unlikely(!mmc_card_support_auto_bkops(card))) { pr_err("%s: %s: card doesn't support auto bkops\n", mmc_hostname(card->host), __func__); return -EPERM; } if (enable) { if (mmc_card_doing_auto_bkops(card)) goto out; bkops_en = card->ext_csd.bkops_en | EXT_CSD_BKOPS_AUTO_EN; } else { if (!mmc_card_doing_auto_bkops(card)) goto out; bkops_en = card->ext_csd.bkops_en & ~EXT_CSD_BKOPS_AUTO_EN; } ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, bkops_en, 0); if (ret) { pr_err("%s: %s: error in setting auto bkops to %d (%d)\n", mmc_hostname(card->host), __func__, enable, ret); } else { if (enable) mmc_card_set_auto_bkops(card); else mmc_card_clr_auto_bkops(card); card->ext_csd.bkops_en = bkops_en; } out: return ret; } EXPORT_SYMBOL(mmc_set_auto_bkops); /** * mmc_check_bkops - check BKOPS for supported cards * @card: MMC card to check BKOPS * * Read the BKOPS status in order to determine whether the * card requires bkops to be started. */ void mmc_check_bkops(struct mmc_card *card) { int err; int timeout; bool use_busy_signal; BUG_ON(!card); if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card)) if (unlikely(!mmc_card_configured_manual_bkops(card))) return; if (mmc_card_doing_bkops(card) || mmc_card_doing_auto_bkops(card)) return; err = mmc_read_bkops_status(card); Loading @@ -892,42 +939,44 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) return; } if (!card->ext_csd.raw_bkops_status) if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2) return; card->bkops.needs_manual = true; } EXPORT_SYMBOL(mmc_check_bkops); /** * mmc_start_manual_bkops - start BKOPS for supported cards * @card: MMC card to start BKOPS * * Send START_BKOPS to the card. */ void mmc_start_manual_bkops(struct mmc_card *card) { int err; BUG_ON(!card); if (unlikely(!mmc_card_configured_manual_bkops(card))) return; if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 && from_exception) if (mmc_card_doing_bkops(card)) return; mmc_claim_host(card->host); if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) { timeout = MMC_BKOPS_MAX_TIMEOUT; use_busy_signal = true; } else { timeout = 0; use_busy_signal = false; } err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true, false); err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_START, 1, 0, false, true, false); if (err) { pr_warn("%s: Error %d starting bkops\n", pr_err("%s: Error %d starting manual bkops\n", mmc_hostname(card->host), err); goto out; } /* * For urgent bkops status (LEVEL_2 and more) * bkops executed synchronously, otherwise * the operation is in progress */ if (!use_busy_signal) } else { mmc_card_set_doing_bkops(card); out: card->bkops.needs_manual = false; } mmc_release_host(card->host); } EXPORT_SYMBOL(mmc_start_bkops); EXPORT_SYMBOL(mmc_start_manual_bkops); /* * mmc_wait_data_done() - done callback for data request Loading Loading @@ -1280,7 +1329,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) || (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) && (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) mmc_start_bkops(host->card, true); mmc_check_bkops(host->card); } if (!err && areq) { Loading Loading @@ -1437,6 +1486,11 @@ int mmc_stop_bkops(struct mmc_card *card) int err = 0; BUG_ON(!card); if (unlikely(!mmc_card_configured_manual_bkops(card))) goto out; if (!mmc_card_doing_bkops(card)) goto out; err = mmc_interrupt_hpi(card); /* Loading @@ -1447,7 +1501,7 @@ int mmc_stop_bkops(struct mmc_card *card) mmc_card_clr_doing_bkops(card); err = 0; } out: return err; } EXPORT_SYMBOL(mmc_stop_bkops); Loading Loading @@ -1705,6 +1759,19 @@ void mmc_get_card(struct mmc_card *card) } EXPORT_SYMBOL(mmc_get_card); /* * This is a helper function, which drops the runtime * pm reference for the card device. */ static void __mmc_put_card(struct mmc_card *card) { /* In case of runtime_idle, it will handle the suspend */ if (card->host->bus_ops->runtime_idle) pm_runtime_put(&card->dev); else pm_runtime_put_autosuspend(&card->dev); } /* * This is a helper function, which releases the host and drops the runtime * pm reference for the card device. Loading @@ -1713,7 +1780,7 @@ void mmc_put_card(struct mmc_card *card) { mmc_release_host(card->host); pm_runtime_mark_last_busy(&card->dev); pm_runtime_put_autosuspend(&card->dev); __mmc_put_card(card); } EXPORT_SYMBOL(mmc_put_card); Loading @@ -1725,6 +1792,13 @@ void mmc_set_ios(struct mmc_host *host) { struct mmc_ios *ios = &host->ios; if (unlikely(ios->power_mode == MMC_POWER_OFF && host->card && mmc_card_doing_auto_bkops(host->card))) { pr_err("%s: %s: illegal to disable power to card when running auto bkops\n", mmc_hostname(host), __func__); return; } pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " "width %u timing %u\n", mmc_hostname(host), ios->clock, ios->bus_mode, Loading
drivers/mmc/core/core.h +0 −15 Original line number Diff line number Diff line Loading @@ -15,21 +15,6 @@ #define MMC_CMD_RETRIES 3 struct mmc_bus_ops { void (*remove)(struct mmc_host *); void (*detect)(struct mmc_host *); int (*pre_suspend)(struct mmc_host *); int (*suspend)(struct mmc_host *); int (*resume)(struct mmc_host *); int (*runtime_suspend)(struct mmc_host *); int (*runtime_resume)(struct mmc_host *); int (*power_save)(struct mmc_host *); int (*power_restore)(struct mmc_host *); int (*alive)(struct mmc_host *); int (*shutdown)(struct mmc_host *); int (*change_bus_speed)(struct mmc_host *, unsigned long *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); void mmc_detach_bus(struct mmc_host *host); Loading
drivers/mmc/core/mmc.c +51 −3 Original line number Diff line number Diff line Loading @@ -570,6 +570,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) */ card->ext_csd.out_of_int_time = ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; pr_info("%s: Out-of-interrupt timeout is %d[ms]\n", mmc_hostname(card->host), card->ext_csd.out_of_int_time); } if (card->ext_csd.rev >= 5) { Loading @@ -584,9 +587,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) 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) pr_info("%s: BKOPS_EN bit is not set\n", mmc_hostname(card->host)); pr_info("%s: BKOPS_EN equals 0x%x\n", mmc_hostname(card->host), card->ext_csd.bkops_en); } card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; Loading Loading @@ -1959,6 +1963,23 @@ reinit: } } /* * Start auto bkops, if supported. * * Note: This leaves the possibility of having both manual and * auto bkops running in parallel. The runtime implementation * will allow this, but ignore bkops exceptions on the premises * that auto bkops will eventually kick in and the device will * handle bkops without START_BKOPS from the host. */ if (mmc_card_support_auto_bkops(card)) { /* * Ignore the return value of setting auto bkops. * If it failed, will run in backward compatible mode. */ (void)mmc_set_auto_bkops(card, true); } return 0; free_card: Loading Loading @@ -2157,6 +2178,12 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) goto out; } if (mmc_card_doing_auto_bkops(host->card)) { err = mmc_set_auto_bkops(host->card, false); if (err) goto out; } err = mmc_flush_cache(host->card); if (err) goto out; Loading Loading @@ -2351,6 +2378,26 @@ static int mmc_power_restore(struct mmc_host *host) return ret; } #define NO_AUTOSUSPEND (-1) static int mmc_runtime_idle(struct mmc_host *host) { BUG_ON(!host->card); if (host->card->bkops.needs_manual) mmc_start_manual_bkops(host->card); pm_runtime_mark_last_busy(&host->card->dev); /* * TODO: consider prolonging suspend when bkops * is running in order to allow a longer time for * bkops to complete * */ pm_schedule_suspend(&host->card->dev, MMC_AUTOSUSPEND_DELAY_MS); /* return negative value in order to avoid autosuspend */ return NO_AUTOSUSPEND; } static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, Loading @@ -2358,6 +2405,7 @@ static const struct mmc_bus_ops mmc_ops = { .resume = mmc_resume, .runtime_suspend = mmc_runtime_suspend, .runtime_resume = mmc_runtime_resume, .runtime_idle = mmc_runtime_idle, .power_restore = mmc_power_restore, .alive = mmc_alive, .shutdown = mmc_shutdown, Loading