runtime pm的实例分析

2024-05-15 15:28
文章标签 分析 实例 runtime pm

本文主要是介绍runtime pm的实例分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概念

运行时的PM与前文描述的系统级挂起到RAM时候的PM不太一样,它是针对单个设备,指系统在非睡眠状态的情况下,某个设备在空闲时可以进入运行时挂起状态,而在不是空闲时执行运行时恢复使得设备进入正常工作状态,如此,这个设备在运行时会省电

struct dev_pm_ops {
...
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*runtime_idle)(struct device *dev);
...
};

基本框架简化如下,就是驱动通过runtime pm core提供的接口,再调用到驱动本身的实现

 

spi_pump_messages

通过之前的文章简述spi内核框架,我们可以知道,这个文件drivers/spi/spi.c里的spi_pump_messages就是一次传输行为,总线空闲就会调用unprepare_transfer_hardware,总线忙就会调用prepare_transfer_hardware;soc根据这两个行为就可以去实现pm操作来省电

static void spi_pump_messages(struct kthread_work *work)
{struct spi_master *master =container_of(work, struct spi_master, pump_messages);unsigned long flags;bool was_busy = false;int ret;/* Lock queue and check for queue work */spin_lock_irqsave(&master->queue_lock, flags);if (list_empty(&master->queue) || !master->running) {if (!master->busy) {spin_unlock_irqrestore(&master->queue_lock, flags);return;}master->busy = false;spin_unlock_irqrestore(&master->queue_lock, flags);if (master->unprepare_transfer_hardware &&master->unprepare_transfer_hardware(master))dev_err(&master->dev,"failed to unprepare transfer hardware\n");return;}/* Make sure we are not already running a message */if (master->cur_msg) {spin_unlock_irqrestore(&master->queue_lock, flags);return;}/* Extract head of queue */master->cur_msg =list_entry(master->queue.next, struct spi_message, queue);list_del_init(&master->cur_msg->queue);if (master->busy)was_busy = true;elsemaster->busy = true;spin_unlock_irqrestore(&master->queue_lock, flags);if (!was_busy && master->prepare_transfer_hardware) {ret = master->prepare_transfer_hardware(master);if (ret) {dev_err(&master->dev,"failed to prepare transfer hardware\n");return;}}ret = master->transfer_one_message(master, master->cur_msg);if (ret) {dev_err(&master->dev,"failed to transfer one message from queue\n");return;}
}

unprepare_transfer_hardware

比如在drivers/spi/spi_qsd.c中,unprepare_transfer_hardware接口会去通过pm_runtime_put_autosuspend,去调用pm_dev_ops的runtime_suspend成员

pm_runtime_put_autosuspend__pm_runtime_suspendrpm_suspendcallback = RPM_GET_CALLBACK(dev, runtime_suspend);
static int msm_spi_unprepare_transfer_hardware(struct spi_master *master)
{struct msm_spi  *dd = spi_master_get_devdata(master);pm_runtime_mark_last_busy(dd->dev);pm_runtime_put_autosuspend(dd->dev);return 0;
}

prepare_transfer_hardware

比如在drivers/spi/spi_qsd.c中,prepare_transfer_hardware接口会去通过pm_runtime_get_sync,去调用pm_dev_ops的runtime_resume成员

pm_runtime_get_sync__pm_runtime_resumerpm_resumecallback = RPM_GET_CALLBACK(dev, runtime_resume);rpm_callback(callback, dev);
static int msm_spi_prepare_transfer_hardware(struct spi_master *master)
{struct msm_spi  *dd = spi_master_get_devdata(master);int resume_state = 0;resume_state = pm_runtime_get_sync(dd->dev);if (resume_state < 0)return resume_state;/** Counter-part of system-suspend when runtime-pm is not enabled.* This way, resume can be left empty and device will be put in* active mode only if client requests anything on the bus*/if (!pm_runtime_enabled(dd->dev))resume_state = msm_spi_pm_resume_runtime(dd->dev);if (resume_state < 0)return resume_state;if (dd->suspended)return -EBUSY;return 0;
}

runtime_suspend

runtime_suspend成员的实现如下:主要是去关闭spi控制器的时钟,达到省电的目的

static int msm_spi_pm_suspend_runtime(struct device *device)
{struct platform_device *pdev = to_platform_device(device);struct spi_master *master = platform_get_drvdata(pdev);struct msm_spi    *dd;unsigned long      flags;dev_err(device, "pm_runtime: suspending...\n");if (!master)goto suspend_exit;dd = spi_master_get_devdata(master);if (!dd)goto suspend_exit;if (dd->suspended)return 0;/** Make sure nothing is added to the queue while we're* suspending*/spin_lock_irqsave(&dd->queue_lock, flags);dd->suspended = 1;spin_unlock_irqrestore(&dd->queue_lock, flags);/* Wait for transactions to end, or time out */wait_event_interruptible(dd->continue_suspend,!dd->transfer_pending);if (dd->pdata && !dd->pdata->active_only)msm_spi_clk_path_unvote(dd);suspend_exit:return 0;
}

runtime_resume

runtime_resume成员的实现如下,主要是去开启spi控制的时钟

static int msm_spi_pm_resume_runtime(struct device *device)
{struct platform_device *pdev = to_platform_device(device);struct spi_master *master = platform_get_drvdata(pdev);struct msm_spi    *dd;int               ret = 0;dev_err(device, "pm_runtime: resuming...\n");if (!master)goto resume_exit;dd = spi_master_get_devdata(master);if (!dd)goto resume_exit;if (!dd->suspended)return 0;if (!dd->is_init_complete) {ret = init_resources(pdev);if (ret != 0)return ret;elsedd->is_init_complete = true;}msm_spi_clk_path_init(dd);if (!dd->pdata->active_only)msm_spi_clk_path_vote(dd);dd->suspended = 0;resume_exit:return 0;
}

dev_pm_ops

将实现赋值给dev_pm_ops结构里的runtime_suspend和runtime_resume成员

static const struct dev_pm_ops msm_spi_dev_pm_ops = {SET_SYSTEM_SLEEP_PM_OPS(msm_spi_suspend, msm_spi_resume)SET_RUNTIME_PM_OPS(msm_spi_pm_suspend_runtime,msm_spi_pm_resume_runtime, NULL)
};static struct platform_driver msm_spi_driver = {.driver         = {.name   = SPI_DRV_NAME,.owner  = THIS_MODULE,.pm             = &msm_spi_dev_pm_ops,.of_match_table = msm_spi_dt_match,},.remove         = msm_spi_remove,.probe          = msm_spi_probe,
};

pm_runtime_get/put

在/drivers/base/power/runtime.c中,设备驱动调用的pm_runtime_get/put 会先原子操作usage,然后判断是否调用rpm_idle/rpm_suspend/rpm_resume;他们会来执行设备驱动实现的对应操作;suspend_timer用定时器来延时调用rpm_suspend

void pm_runtime_init(struct device *dev)
{dev->power.runtime_status = RPM_SUSPENDED;dev->power.last_status = RPM_INVALID;dev->power.idle_notification = false;dev->power.disable_depth = 1;atomic_set(&dev->power.usage_count, 0);dev->power.runtime_error = 0;atomic_set(&dev->power.child_count, 0);pm_suspend_ignore_children(dev, false);dev->power.runtime_auto = true;dev->power.request_pending = false;dev->power.request = RPM_REQ_NONE;dev->power.deferred_resume = false;dev->power.needs_force_resume = 0;INIT_WORK(&dev->power.work, pm_runtime_work);dev->power.timer_expires = 0;hrtimer_init(&dev->power.suspend_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);dev->power.suspend_timer.function = pm_suspend_timer_fn;init_waitqueue_head(&dev->power.wait_queue);
}static void pm_runtime_work(struct work_struct *work)
{struct device *dev = container_of(work, struct device, power.work);enum rpm_request req;spin_lock_irq(&dev->power.lock);if (!dev->power.request_pending)goto out;req = dev->power.request;dev->power.request = RPM_REQ_NONE;dev->power.request_pending = false;switch (req) {case RPM_REQ_NONE:break;case RPM_REQ_IDLE:rpm_idle(dev, RPM_NOWAIT);break;case RPM_REQ_SUSPEND:rpm_suspend(dev, RPM_NOWAIT);break;case RPM_REQ_AUTOSUSPEND:rpm_suspend(dev, RPM_NOWAIT | RPM_AUTO);break;case RPM_REQ_RESUME:rpm_resume(dev, RPM_NOWAIT);break;}out:spin_unlock_irq(&dev->power.lock);
}

这篇关于runtime pm的实例分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/992199

相关文章

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重

关于MyISAM和InnoDB对比分析

《关于MyISAM和InnoDB对比分析》:本文主要介绍关于MyISAM和InnoDB对比分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录开篇:从交通规则看存储引擎选择理解存储引擎的基本概念技术原理对比1. 事务支持:ACID的守护者2. 锁机制:并发控制的艺

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部