当前位置:网站首页>UFS Power Management 介绍

UFS Power Management 介绍

2022-07-08 00:56:00 果汁底线

一 . UFS Power Management Overview

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模块也是不能成功睡眠下去,通俗点讲就是有福同享,有难同当,不放弃任何一个民众。

二 . UFS Power Management Detail

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

原网站

版权声明
本文为[果汁底线]所创,转载请带上原文链接,感谢
https://blog.csdn.net/guozhidixian/article/details/125364022

随机推荐