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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/702777.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux-CentOS-7忘记密码-修改登录密码图文详解

Linux-CentOS-7忘记密码-修改登录密码图文详解 1.重启系统&#xff1a; 在登录界面&#xff0c;选择要登录的用户并点击"Power"按钮&#xff0c;然后选择"Restart"或"Reboot"重新启动系统。 在系统启动时持续按下 “e” 键进入编辑模式。 2…

抖店曝光率高,转化低,不知道怎么提升转化率?试试这四个方法

大家好&#xff0c;我是醒醒团队电商花花。 我们现在做抖音小店的商家或多或少都会遇到不出单&#xff0c;转化低的各种问题。 明明店铺的曝光不低&#xff0c;访客也不少&#xff0c;就是没转化。 下面我根据我们做店的经验&#xff0c;给大家分享一些问题所在&#xff0c;…

总结 UDP 的报文结构和注意事项

UDP协议端格式 UDP报文主体分为两个部分:UDP报头(占8个字节)UDP数据/UDP载荷UPD报头:源端口号目的端口号包长度校验和 1.源端口号&#xff1a;一般是客户端程序程序请求时&#xff0c;由系统自动指定&#xff0c;端口号范围是0~65535&#xff0c; 0 ~ 1023为知名端口号——占16…

数据分析(二)——导入外部数据,导入Excel数据,CSV文件,txt文件,HTML网页,数据抽取,DataFrame对象的loc属性与iloc属性

一.导入外部数据 1.导入.xIs或.xIsx文件 pd.read_ excel(io,sheet_ name,header) 1.1常用参数说明 ●io:表示.xIs或.xIsx文件路径或类文件对象 ●sheet name:表示工作表&#xff0c;取值如下表所示 ●header:默认值为0&#xff0c;取第一行的值为列名&#xff0c;数据为除列…

【保姆级】生成式网络模型基础知识(图像合成/语音合成/GPT)

生成式模型基础知识 初步接触生成任务 生成任务&#xff0c;顾名思义就是要去生成一个东西&#xff0c;比如生成图片/音频/文字等等。 大家接触最多比如chatGPT、stable diffusion、还有一些语音合成相关的东西。 那么问题来了&#xff0c;具体生成步骤是什么样的&#xff…

MIT 6.5840(6.824) Lab1:MapReduce 设计实现

1 介绍 本次实验是实现一个简易版本的MapReduce&#xff0c;你需要实现一个工作程序&#xff08;worker process&#xff09;和一个调度程序&#xff08;coordinator process&#xff09;。工作程序用来调用Map和Reduce函数&#xff0c;并处理文件的读取和写入。调度程序用来协…

【制作100个unity游戏之26】unity2d横版卷轴动作类游戏5(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言三段攻击攻击设置只对敌人造成伤害限制可以移动攻击问题 角色连续按四下攻击&#xff0c;最后会多a一下问题&#xff1a;站在原地连续攻击野猪&#xff0c;只有第一下攻击野猪才掉血&#xff0c;后面的攻击野猪不掉血源码完结 …

Keli5烧写程序成功后再次烧写程序却不能识别芯片。解决方法

1问题&#xff08;已排除硬件问题和Debug配置问题&#xff09; 再次烧写不能识别下如图&#xff08;提示为不能识别到芯片&#xff09; 硬件识别正常 Debug配置正常 就是不能识别到芯片 2为什么会出现这个问题 在STM32Cude设置中没有设置SYS&#xff08;默认是No Debug&…

[Cesium for Supermap]加载iserver发布的wms服务

1&#xff0c;wms服务 2&#xff0c;加载代码 let provider new Cesium.WebMapServiceImageryProvider({url: "http://support.supermap.com.cn:8090/iserver/services/map-china400/wms111/China_4326",enablePickFeatures:true,rectangle: Cesium.Rectangle.fromD…

必背!!2024年软考中级——网络工程师考前冲刺几页纸

距离软考考试的时间越来越近了&#xff0c;趁着这两周赶紧准备起来 今天给大家整理了——软考网络工程师考前冲刺几页纸&#xff0c;都是核心重点&#xff0c;有PDF版&#xff0c;可打印下来&#xff0c;每天背一点。 计算机总线分类 ①总线的分类&#xff1a;数据总线、地址总…

618值得入手的数码有哪些?数码好物清单推荐|款款实用闭眼冲

每年的618购物节都是消费者们翘首以盼的盛宴&#xff0c;这一天&#xff0c;各大品牌和电商平台都会推出极具吸引力的优惠活动&#xff0c;让消费者们能够以更优惠的价格购买到心仪的数码好物&#xff0c;为了帮助大家在这个购物狂欢节中挑选到真正实用、性价比高的数码产品&am…