linux下pm子系统
来源:互联网 发布:mac怎么玩dota2国服 编辑:程序博客网 时间:2024/06/16 00:34
工作中分配了低功耗相关方面的内容,查了相关资料,linux更是有一套pm相关的子系统。
首先需要说明的是既然是低功耗,那么SoC就要支持相关低功耗。
如果要进入低功耗模式,有一种方式可以在用户空间通知内核空间,echo “stanby" > /sys/power/state至于字符串的内容,需要在/kernel/power/suspend.c去查看或者修改。
linux中/sys/中是内核空间数据结构的体现,功能和/proc是相同的,/sys/下文件夹的创建,
sysfs_create_group(power_kobj, &attr_group); 后面的那个参数就是,是之前注册的回调函数。
#define power_attr(_name) \ static struct kobj_attribute _name##_attr = { \ .attr = { \ .name = __stringify(_name), \ .mode = 0644, \ }, \ .show = _name##_show, \ .store = _name##_store, \ }
最后还是会调用到state_store.
既然进入低功耗模式,控制台端口就需要关闭。调试的时候没有任何打印,当然就不知道现在的状态的,所以现在需要在.config中的CONFIG_CMDLINE后面加上no_console_suspend。这样就会有内核打印了。
各硬件外设在注册设备的时候如果有低功耗的功能的时候,会注册相应的suspend和resume的回调函数,但是仔细看一下,发现有好几个结构体的都有这两种回调函数,所以肯定会有调用的先后顺序,先把相应的结构体列举出来。
struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; };
struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ const struct of_device_id *of_match_table; int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };
struct dev_pm_ops { int (*prepare)(struct device *dev); void (*complete)(struct device *dev); int (*suspend)(struct device *dev); int (*resume)(struct device *dev); int (*freeze)(struct device *dev); int (*thaw)(struct device *dev); int (*poweroff)(struct device *dev); int (*restore)(struct device *dev); int (*suspend_noirq)(struct device *dev); int (*resume_noirq)(struct device *dev); int (*freeze_noirq)(struct device *dev); int (*thaw_noirq)(struct device *dev); int (*poweroff_noirq)(struct device *dev); int (*restore_noirq)(struct device *dev); int (*runtime_suspend)(struct device *dev); int (*runtime_resume)(struct device *dev); int (*runtime_idle)(struct device *dev); };第三个回调函数是后来细化了低功耗相关的动作。
真正去调用这些回调函数是在该函数中:
/** * dpm_suspend_start - Prepare devices for PM transition and suspend them. * @state: PM transition of the system being carried out. * * Prepare all non-sysdev devices for system PM transition and execute "suspend" * callbacks for them. */ int dpm_suspend_start(pm_message_t state) { int error; error = dpm_prepare(state); if (!error) error = dpm_suspend(state); return error; } EXPORT_SYMBOL_GPL(dpm_suspend_start);这两个分别去调用回调prepare和suspend回调函数,里面的优先级就有很明确的定义。
if (dev->pwr_domain) { pm_dev_dbg(dev, state, "power domain "); error = pm_op(dev, &dev->pwr_domain->ops, state); goto End; } if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "type "); error = pm_op(dev, dev->type->pm, state); goto End; } if (dev->class) { if (dev->class->pm) { pm_dev_dbg(dev, state, "class "); error = pm_op(dev, dev->class->pm, state); goto End; } else if (dev->class->suspend) { pm_dev_dbg(dev, state, "legacy class "); error = legacy_suspend(dev, state, dev->class->suspend); goto End; } } if (dev->bus) { if (dev->bus->pm) { pm_dev_dbg(dev, state, ""); error = pm_op(dev, dev->bus->pm, state); } else if (dev->bus->suspend) { pm_dev_dbg(dev, state, "legacy "); error = legacy_suspend(dev, state, dev->bus->suspend); } }可见顺序是从小到大的,device->class->bus。
硬件设备进入休眠状态之后,需要让CPU进入休眠状态。
int suspend_enter(suspend_state_t state)该函数的核心是
error = syscore_suspend(); if (!error) { if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { error = suspend_ops->enter(state); events_check_enabled = false; } syscore_resume(); }而suspend_ops的回调函数,是各SoC厂商在arch/cpuxxx/SoCxxx/pm.c中调用函数
static const struct platform_suspend_ops xxx_pm_ops = { .valid = xxx_valid, .enter = xxx_enter, }; static int __init xxx_pm_init(void) { suspend_set_ops(&xxx_pm_ops); return 0; }而在xxx_enter中主要是对SoC中power manager unit寄存器设置,包括设置中断唤醒源,是进入cpuoff模式还是plloff模式。
在完成该低功耗任务时,遇到的最大问题就是,板子上的wifi模块,每次suspend之后,被唤醒源唤醒之后,各个设备能够resume成功,但是唯独wifi模块6212,因为wifi模块是在sdio总线上的,在resume过程中,sdio出现了timeout的情况,跟了很久,发现是在wifi驱动在suspend的时候,注释了相关代码导致的,而实际上最后只需要在sd/mmc驱动中,增加一个mmc标志位就可以了,该情况充分证明了总线和挂载在总线上的紧密联系。
因为之前也弄了实时操作系统的低功耗,通过这两次,发现了,自己并没有对当时的现场保存下来,而我也不可能将全部的现场保存下来,我发现时,当我设置PMU单元进入低功耗模式之后,sdram的内容会被定格下来,也正是这个原因,所以不需要人工手动去保存现场,不然将又是一场浩大的工程。
- linux下pm子系统
- linux下中断子系统
- linux下时间子系统
- Linux下RTC子系统学习
- Linux下的Keyboard子系统
- Linux下的LED子系统
- Linux下的RTC子系统
- Linux下的LED子系统
- LINUX下input子系统分析
- LINUX下IIC子系统分析
- Linux下的LED子系统
- Linux下的Backlight子系统
- Linux下的RTC子系统
- Linux下的Keyboard子系统
- Linux下的LED子系统
- Linux下的RTC子系统
- win10下开启Linux子系统
- 浅析Linux下的子系统
- Unity 入门 物理系统中 添加力
- hdu 5500 Reorder the books 思维
- malloc,calloc,ralloc
- 有关搜索引擎的思考与实用技巧的总结(Google)
- 使用pull解析用xml方式存储的数据
- linux下pm子系统
- 图解 Session(会话)
- 一张纸折叠多少次,高度不小于珠穆朗玛峰的高度
- 客户端访问scan IP出现ora12545错误
- 第46课:Spark中的新解析引擎Catalyst源码初探
- Notification的用法
- android bluetooth stack-init
- 封装
- 微信接入探秘(一)——从零认识微信接口