1. UFS Power Management 管理UFS Power相关资源,
在收到访问请求的时候唤醒UFS工作,切换为工作模式,在完成请求后让UFS进行睡眠,切换为睡眠模式,能够节省功耗,提高续航。
主要是分为UFS Runtime Power Management和UFS System Power Management。
2. UFS Runtime Power Management:
UFS模块运行时睡眠唤醒机制,只需要UFS模块空闲,即可进入睡眠状态,不受其他模块的睡眠唤醒状态影响,通俗点讲就是个人自扫门前雪。

3. UFS System Power Management:
UFS系统睡眠唤醒机制,和系统的睡眠唤醒状态有关,需要系统所有的模块都睡眠下去,UFS 模块才会睡眠下去,当只有存在系统一个模块是唤醒状态/或者系统存在唤醒源导致睡眠部下去,UFS模块也是不能成功睡眠下去,通俗点讲就是有福同享,有难同当,不放弃任何一个民众。

1. UFS Runtime Power Management :

(1) UFS Runtime Power Management是在Linux Kernel RPM Framework下进行管理的,在没有访问请求/UFS空闲的时候,将UFS置为睡眠状态,当UFS有访问请求/不是空闲状态时,将UFS置为唤醒状态。
(2) UFS Driver RPM Power Management 主要是管理UFS Device Power Mode State和MPHY Link State。
UFS PM Level State划分为六个等级,默认rpm_lvl 是3,也就是UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE。
UFS_SLEEP_PWR_MODE:指的是UFS Device PowerMode为Sleep Mode, 需要发送SSU命令切换UFS Power Mode。
UIC_LINK_ACTIVE_STATE:指的是将UFS MPHY Link设置为Hibernate状态,需要发送DME_HIBERNATE_ENTER命令切换Link Status.
- struct ufs_pm_lvl_states ufs_pm_lvl_states[] = {
- {UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE},
- {UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE},
- {UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE},
- {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE},
- {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE},
- {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE},
- };
(3) UFS RPM 相关Sysfs节点:
-
- UFS RPM Sysfs节点目录: /sys/device/platform/soc/1d84.ufshci/power
-
- UFS RPM 相关节点:
-
- 1. control: Report/change current runtime PM setting of the device
- *
- * Runtime power management of a device can be blocked with the help of
- * this attribute. All devices have one of the following two values for
- * the power/control file:
- * + "auto\n" to allow the device to be power managed at run time;
- * + "on\n" to prevent the device from being power managed at run time;
-
- 2. autosuspend_delay_ms - Report/change a device's autosuspend_delay value
- *
- * Some drivers don't want to carry out a runtime suspend as soon as a
- * device becomes idle; they want it always to remain idle for some period
- * of time before suspending it. This period is the autosuspend_delay
- * value (expressed in milliseconds) and it can be controlled by the user.
- * If the value is negative then the device will never be runtime
- * suspended.
-
- 3. runtime_active_time: report runtime active status totol time.
-
- 4. runtime_suspended_time: report runtime suspended status totol time.
-
- 5. runtime_status: report runtime status.
(4) UFS 设备Runtime Power Management状态:
-
- /*
- * Device run-time power management status.
- *
- * These status labels are used internally by the PM core to indicate the
- * current status of a device with respect to the PM core operations. They do
- * not reflect the actual power state of the device or its status as seen by the
- * driver.
- *
- * RPM_ACTIVE Device is fully operational. Indicates that the device
- * bus type's ->runtime_resume() callback has completed
- * successfully.
- *
- * RPM_SUSPENDED Device bus type's ->runtime_suspend() callback has
- * completed successfully. The device is regarded as
- * suspended.
- *
- * RPM_RESUMING Device bus type's ->runtime_resume() callback is being
- * executed.
- *
- * RPM_SUSPENDING Device bus type's ->runtime_suspend() callback is being
- * executed.
- */
-
- enum rpm_status {
- RPM_ACTIVE = 0,
- RPM_RESUMING,
- RPM_SUSPENDED,
- RPM_SUSPENDING,
- };
(5) UFS 驱动常用Runtime PM使用接口和使用场景
在访问UFS 设备之前,为了防止UFS 进入Suspend , 我们需要调用以下两个接口增加设备使用计数,然后唤醒UFS 设备(Resume)为Active状态,这里UFS设备指的是UFS Host Controller,
Note:不管是UFS驱动还是USB驱动还是其他驱动,在访问设备之前都应该遵循以上流程,唤醒设备为Active状态,保证设备正常工作,否则如果设备进入了Suspend状态去访问会出现未知的错误。
pm_runtime_get_sync
pm_runtime_get
访问UFS设备之后,就可以让UFS 设备进入Suspend, 我们需要调用以下两个接口减少设备使用技术,然后使得UFS设备进入睡眠状态(Suspended), 这里UFS设备指的是UFS Host Controller.
pm_runtime_put
pm_runtime_put_sync
下面是一个具体的使用场景:
在对UFS Host Controller做访问之前,调用pm,_runtime_get_sync增加设备引用计数,唤醒设备,然后对设备进行访问操作,访问完成后调用pm_runtimr_put_sync减少设备引用计数,让设备睡眠。
- int ufshcd_clk_scaling_enable(struct ufs_hba *hba, int value)
- {
- int err;
-
- value = !!value;
- mutex_lock(&ufshcd_clkscale_lock);
- if (value == hba->clk_scaling.is_allowed)
- goto out;
-
- // 获取UFS PM Runtime 资源,增加PM Usage Count, 让UFS Host处于Active Status
- pm_runtime_get_sync(hba->dev);
- ufshcd_hold(hba, false);
-
- cancel_work_sync(&hba->clk_scaling.suspend_work);
- cancel_work_sync(&hba->clk_scaling.resume_work);
-
- hba->clk_scaling.is_allowed = value;
-
- if (value) {
- ufshcd_resume_clkscaling(hba);
- } else {
- ufshcd_suspend_clkscaling(hba);
- err = ufshcd_devfreq_scale(hba, true);
- if (err)
- dev_err(hba->dev, "%s: failed to scale clocks up %d\n",
- __func__, err);
- }
-
- ufshcd_release(hba, false);
- // 释放UFS PM Runtime资源,减少PM Usage Count, 让UFS Host处于Suspend Status
-
- pm_runtime_put_sync(hba->dev);
- out:
- mutex_unlock(&ufshcd_clkscale_lock);
- return 0;
- }
阻塞UFS设备在Linux RPM Power Management 管理运行时进入Suspend.
增加设备引用计数和清除设备power.runtime_auto标志
除非调用pm_runtime_allow,否则UFS设备不会在运行的时候进入Suspend状态
pm_runtime_forbid
UFS设备在Linux RPM Power Management 管理运行时允许挂起(进入Suspended)
减少设备引用计数和设置设备power.runtime_auto标志
pm_runtime_allow
下面是一个具体的使用场景:
static const char ctrl_auto[] = "auto";
static const char ctrl_on[] = "on";static ssize_t control_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n",
dev->power.runtime_auto ? ctrl_auto : ctrl_on);
}static ssize_t control_store(struct device * dev, struct device_attribute *attr,
const char * buf, size_t n)
{
device_lock(dev);
if (sysfs_streq(buf, ctrl_auto))
pm_runtime_allow(dev);
else if (sysfs_streq(buf, ctrl_on))
pm_runtime_forbid(dev);
else
n = -EINVAL;
device_unlock(dev);
return n;
}
2. UFS System Power Management:

(1)UFS System Power Management是受整个内核系统影响的,需要内核系统所有模块都睡眠 了或者内核系统没有唤醒事件,UFS设备才会进入UFS System Suspend。
UFS手机功耗续航测试就是在整个系统进入System Suspend(包括UFS System Suspend)后进行 测试的,相关开发同事需要对整个系统的System Suspend/Resume 机制非常了解,才能清晰的 定位到某个模块影响了系统进入System Suspend,导致功耗问题。
(2) UFS Driver RPM Power Management 主要是管理UFS Device Power Mode State和 MPHY Link State 还有UFS Device的供电VCC。
UFS PM Level State划分为六个等级,默认spm_lvl 是3,也就是UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE。
UFS_SLEEP_PWR_MODE:指的是UFS Device PowerMode为Sleep Mode, 需要发送SSU命 令切换UFS Power Mode。
UIC_LINK_ACTIVE_STATE:指的是将UFS MPHY Link设置为Hibernate状态,需要发送 DME_HIBERNATE_ENTER命令切换Link Status.
VCC: UFS Device进入System Suspend的时候,会将VCC电压关闭节省耗电,减少功耗。
(3) UFS System Suspend相关Sysfs节点:
系统PM节点目录: /sys/power/*
wake_lock: 系统唤醒锁,如果有进程持有wake_lock, 整个系统就不会进入System Suspend, 当然UFS 设备也不能进入system suspend.
wake_unlock: 释放系统唤醒锁,让整个系统可以进入System Suspend, 当然UFS 设备也 能进入system suspend.
(4) UFS 设备相关System PM状态:
系统System PM 相关状态:
#define PM_SUSPEND_ON ((__force suspend_state_t) 0)
#define PM_SUSPEND_TO_IDLE ((__force suspend_state_t) 1)
#define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2)
#define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
#define PM_SUSPEND_MIN PM_SUSPEND_TO_IDLE
#define PM_SUSPEND_MAX ((__force suspend_state_t) 4)
kernel/power/main.c
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
suspend_state_t state;
int error;error = pm_autosleep_lock();
if (error)
return error;if (pm_autosleep_state() > PM_SUSPEND_ON) {
error = -EBUSY;
goto out;
}state = decode_state(buf, n);
if (state < PM_SUSPEND_MAX) {
if (state == PM_SUSPEND_MEM)
state = mem_sleep_current;error = pm_suspend(state);
} else if (state == PM_SUSPEND_MAX) {
error = hibernate();
} else {
error = -EINVAL;
}out:
pm_autosleep_unlock();
return error ? error : n;
}
UFS System PM相关状态:
/* Used to differentiate the power management options */
enum ufs_pm_op {
UFS_RUNTIME_PM,
UFS_SYSTEM_PM,
UFS_SHUTDOWN_PM,
};
/**
* ufshcd_system_suspend - system suspend routine
* @hba: per adapter instance
*
* Check the description of ufshcd_suspend() function for more details.
*
* Returns 0 for success and non-zero for failure
*/
int ufshcd_system_suspend(struct ufs_hba *hba)
{
int ret = 0;
ktime_t start = ktime_get();if (!hba || !hba->is_powered)
return 0;if ((ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl) ==
hba->curr_dev_pwr_mode) &&
(ufs_get_pm_lvl_to_link_pwr_state(hba->spm_lvl) ==
hba->uic_link_state))
goto out;if (pm_runtime_suspended(hba->dev)) {
/*
* UFS device and/or UFS link low power states during runtime
* suspend seems to be different than what is expected during
* system suspend. Hence runtime resume the devic & link and
* let the system suspend low power states to take effect.
* TODO: If resume takes longer time, we might have optimize
* it in future by not resuming everything if possible.
*/
ret = ufshcd_runtime_resume(hba);
if (ret)
goto out;
}ret = ufshcd_suspend(hba, UFS_SYSTEM_PM);
out:
trace_ufshcd_system_suspend(dev_name(hba->dev), ret,
ktime_to_us(ktime_sub(ktime_get(), start)),
hba->curr_dev_pwr_mode, hba->uic_link_state);
if (!ret)
hba->is_sys_suspended = true;
return ret;
}
EXPORT_SYMBOL(ufshcd_system_suspend);
(6)UFS 驱动常用System PM使用接口和使用场景:
系统开始进入System Suspend的时候,会循环遍历每个设备都进入System Suspend状态,包 括UFS设备,UFS驱动没有显性调用System PM的接口,主要是受系统Suspend机制管理,当系 统开始进入Suspend流程的时候,UFS设备也是空闲的状态的时候,此时UFS设备就会进入System Suspend的状态,UFS驱动发送SSU命令让UFS Device进入SLEEP Mode, 发送DME_HIBER_ENTER让MPHY Link 进入Hibernate状态,并且UFS Device的VCC供电也会关闭,节省功耗。
1. Kernel System Power Management Source Code
2 . Kernel Runtime Power Management Source Code
3. Kernel UFS Power Management Source Code