Skip to content

Commit 51dd905

Browse files
Stanley Chumartinkpetersen
authored andcommitted
scsi: ufs: Fix WriteBooster flush during runtime suspend
Currently UFS host driver promises VCC supply if UFS device needs to do WriteBooster flush during runtime suspend. However the UFS specification mentions: "While the flushing operation is in progress, the device is in Active power mode." Therefore UFS host driver needs to promise more: Keep UFS device as "Active power mode", otherwise UFS device shall not do any flush if device enters Sleep or PowerDown power mode. Similarly, the same promises shall be applied if device needs urgent BKOP during runtime suspend. Fix this by not changing device power mode if WriteBooster flush or urgent BKOP is required in ufshcd_suspend(). Now, if device finishes its job but is not resumed for a very long time, system will have unnecessary power drain because VCC is still supplied. A method to re-check the threshold of keeping VCC supply is required to fix the power drain. However, the threshold re-check needs to re-activate the link first because the decision depends on the latest device status. Also introduce a delayed work to force runtime resume after a certain delay during runtime suspend. This makes threshold re-check happen natually in the entry of the next runtime-suspend. The device can continue its WriteBooster flush or urgent BKOP jobs soon after resumed if device has no upcoming requests and link enters hibern8 state either by Auto-Hibern8 or hibern8 during clk-gating scheme. This solution not only prevents power drain but also makes as much use of time as possible for device's background jobs. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Asutosh Das <[email protected]> Signed-off-by: Stanley Chu <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent e31011a commit 51dd905

File tree

3 files changed

+59
-23
lines changed

3 files changed

+59
-23
lines changed

drivers/scsi/ufs/ufs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ struct ufs_dev_info {
574574
u32 d_ext_ufs_feature_sup;
575575
u8 b_wb_buffer_type;
576576
u32 d_wb_alloc_units;
577-
bool keep_vcc_on;
577+
bool b_rpm_dev_flush_capable;
578578
u8 b_presrv_uspc_en;
579579
};
580580

drivers/scsi/ufs/ufshcd.c

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@
9494
/* default delay of autosuspend: 2000 ms */
9595
#define RPM_AUTOSUSPEND_DELAY_MS 2000
9696

97+
/* Default delay of RPM device flush delayed work */
98+
#define RPM_DEV_FLUSH_RECHECK_WORK_DELAY_MS 5000
99+
97100
/* Default value of wait time before gating device ref clock */
98101
#define UFSHCD_REF_CLK_GATING_WAIT_US 0xFF /* microsecs */
99102

@@ -5314,7 +5317,7 @@ static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba,
53145317
return false;
53155318
}
53165319

5317-
static bool ufshcd_wb_keep_vcc_on(struct ufs_hba *hba)
5320+
static bool ufshcd_wb_need_flush(struct ufs_hba *hba)
53185321
{
53195322
int ret;
53205323
u32 avail_buf;
@@ -5352,6 +5355,21 @@ static bool ufshcd_wb_keep_vcc_on(struct ufs_hba *hba)
53525355
return ufshcd_wb_presrv_usrspc_keep_vcc_on(hba, avail_buf);
53535356
}
53545357

5358+
static void ufshcd_rpm_dev_flush_recheck_work(struct work_struct *work)
5359+
{
5360+
struct ufs_hba *hba = container_of(to_delayed_work(work),
5361+
struct ufs_hba,
5362+
rpm_dev_flush_recheck_work);
5363+
/*
5364+
* To prevent unnecessary VCC power drain after device finishes
5365+
* WriteBooster buffer flush or Auto BKOPs, force runtime resume
5366+
* after a certain delay to recheck the threshold by next runtime
5367+
* suspend.
5368+
*/
5369+
pm_runtime_get_sync(hba->dev);
5370+
pm_runtime_put_sync(hba->dev);
5371+
}
5372+
53555373
/**
53565374
* ufshcd_exception_event_handler - handle exceptions raised by device
53575375
* @work: pointer to work data
@@ -8099,8 +8117,7 @@ static void ufshcd_vreg_set_lpm(struct ufs_hba *hba)
80998117
!hba->dev_info.is_lu_power_on_wp) {
81008118
ufshcd_setup_vreg(hba, false);
81018119
} else if (!ufshcd_is_ufs_dev_active(hba)) {
8102-
if (!hba->dev_info.keep_vcc_on)
8103-
ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
8120+
ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
81048121
if (!ufshcd_is_link_active(hba)) {
81058122
ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq);
81068123
ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2);
@@ -8225,27 +8242,30 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
82258242
ufshcd_disable_auto_bkops(hba);
82268243
}
82278244
/*
8228-
* With wb enabled, if the bkops is enabled or if the
8229-
* configured WB type is 70% full, keep vcc ON
8230-
* for the device to flush the wb buffer
8245+
* If device needs to do BKOP or WB buffer flush during
8246+
* Hibern8, keep device power mode as "active power mode"
8247+
* and VCC supply.
82318248
*/
8232-
if ((hba->auto_bkops_enabled && ufshcd_is_wb_allowed(hba)) ||
8233-
ufshcd_wb_keep_vcc_on(hba))
8234-
hba->dev_info.keep_vcc_on = true;
8235-
else
8236-
hba->dev_info.keep_vcc_on = false;
8237-
} else {
8238-
hba->dev_info.keep_vcc_on = false;
8239-
}
8249+
hba->dev_info.b_rpm_dev_flush_capable =
8250+
hba->auto_bkops_enabled ||
8251+
(((req_link_state == UIC_LINK_HIBERN8_STATE) ||
8252+
((req_link_state == UIC_LINK_ACTIVE_STATE) &&
8253+
ufshcd_is_auto_hibern8_enabled(hba))) &&
8254+
ufshcd_wb_need_flush(hba));
8255+
}
8256+
8257+
if (req_dev_pwr_mode != hba->curr_dev_pwr_mode) {
8258+
if ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
8259+
!ufshcd_is_runtime_pm(pm_op)) {
8260+
/* ensure that bkops is disabled */
8261+
ufshcd_disable_auto_bkops(hba);
8262+
}
82408263

8241-
if ((req_dev_pwr_mode != hba->curr_dev_pwr_mode) &&
8242-
((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
8243-
!ufshcd_is_runtime_pm(pm_op))) {
8244-
/* ensure that bkops is disabled */
8245-
ufshcd_disable_auto_bkops(hba);
8246-
ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
8247-
if (ret)
8248-
goto enable_gating;
8264+
if (!hba->dev_info.b_rpm_dev_flush_capable) {
8265+
ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
8266+
if (ret)
8267+
goto enable_gating;
8268+
}
82498269
}
82508270

82518271
flush_work(&hba->eeh_work);
@@ -8298,9 +8318,16 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
82988318
if (hba->clk_scaling.is_allowed)
82998319
ufshcd_resume_clkscaling(hba);
83008320
hba->clk_gating.is_suspended = false;
8321+
hba->dev_info.b_rpm_dev_flush_capable = false;
83018322
ufshcd_release(hba);
83028323
out:
8324+
if (hba->dev_info.b_rpm_dev_flush_capable) {
8325+
schedule_delayed_work(&hba->rpm_dev_flush_recheck_work,
8326+
msecs_to_jiffies(RPM_DEV_FLUSH_RECHECK_WORK_DELAY_MS));
8327+
}
8328+
83038329
hba->pm_op_in_progress = 0;
8330+
83048331
if (ret)
83058332
ufshcd_update_reg_hist(&hba->ufs_stats.suspend_err, (u32)ret);
83068333
return ret;
@@ -8389,6 +8416,11 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
83898416
/* Enable Auto-Hibernate if configured */
83908417
ufshcd_auto_hibern8_enable(hba);
83918418

8419+
if (hba->dev_info.b_rpm_dev_flush_capable) {
8420+
hba->dev_info.b_rpm_dev_flush_capable = false;
8421+
cancel_delayed_work(&hba->rpm_dev_flush_recheck_work);
8422+
}
8423+
83928424
/* Schedule clock gating in case of no access to UFS device yet */
83938425
ufshcd_release(hba);
83948426

@@ -8862,6 +8894,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
88628894
UFS_SLEEP_PWR_MODE,
88638895
UIC_LINK_HIBERN8_STATE);
88648896

8897+
INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work,
8898+
ufshcd_rpm_dev_flush_recheck_work);
8899+
88658900
/* Set the default auto-hiberate idle timer value to 150 ms */
88668901
if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) {
88678902
hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) |

drivers/scsi/ufs/ufshcd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@ struct ufs_hba {
745745
struct request_queue *bsg_queue;
746746
bool wb_buf_flush_enabled;
747747
bool wb_enabled;
748+
struct delayed_work rpm_dev_flush_recheck_work;
748749
};
749750

750751
/* Returns true if clocks can be gated. Otherwise false */

0 commit comments

Comments
 (0)