`
womendu
  • 浏览: 1513442 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

新版linux系统设备架构中关于电源管理方式的变更

阅读更多

新版linux系统设备架构中关于电源管理方式的变更
based on linux-2.6.32

一、设备模型各数据结构中电源管理的部分

linux的设备模型通过诸多结构体来联合描述,如struct device,struct device_type,struct class,
struct device_driver,struct bus_type等。

@kernel/include/linux/devices.h中有这几中结构体的定义,这里只列出和PM有关的项,其余查看源码:

struct device{
...
struct dev_pm_infopower;
...
}

struct device_type {
...
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
char *(*devnode)(struct device *dev, mode_t *mode);
void (*release)(struct device *dev);

const struct dev_pm_ops *pm;
};

struct class {
...
void (*class_release)(struct class *class);
void (*dev_release)(struct device *dev);

int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);

const struct dev_pm_ops *pm;
...
};

struct device_driver {
...
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 dev_pm_ops *pm;
...
};

struct bus_type {
...
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
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 dev_pm_ops *pm;
...
};

以上可以看出和电源管理相关的两个结构体是struct dev_pm_info和struct dev_pm_ops,他们定义于文件
@kernel/include/linux/pm.h

struct dev_pm_info {
pm_message_tpower_state;
unsigned intcan_wakeup:1;
unsigned intshould_wakeup:1;
enum dpm_statestatus;/* Owned by the PM core - 表示该设备当前的PM状态*/
#ifdef CONFIG_PM_SLEEP
struct list_headentry;/* 链接到dpm_list全局链表中的连接体 */
#endif
#ifdef CONFIG_PM_RUNTIME// undef
struct timer_listsuspend_timer;
unsigned longtimer_expires;
struct work_structwork;
wait_queue_head_twait_queue;
spinlock_tlock;
atomic_tusage_count;
atomic_tchild_count;
unsigned intdisable_depth:3;
unsigned intignore_children:1;
unsigned intidle_notification:1;
unsigned intrequest_pending:1;
unsigned intdeferred_resume:1;
enum rpm_requestrequest;
enum rpm_statusruntime_status;
intruntime_error;
#endif
};

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

二、device中的dev_pm_info结构体

device结构体中的power项用来将该设备纳入电源管理的范围,记录电源管理的一些信息。
在注册设备的时候调用函数device_add()来向sysfs系统添加power接口和注册进电源管理系统,代码片段如下:
...
error = dpm_sysfs_add(dev);@kernel/drivers/base/power/sysfs.c
if (error)
goto DPMError;
device_pm_add(dev);@kernel/drivers/base/power/main.c
...
其中dpm_sysfs_add()函数用来向sysfs文件系统中添加相应设备的power接口文件,如注册mt6516_tpd paltform device的时候,会在sysfs中出现如下目录和文件:
#pwd
/sys/devices/platform/mt6516-tpd
#cd mt6516-tpd
#ls -l
-rw-r--r-- root root 4096 2010-01-02 06:35 uevent
-r--r--r-- root root 4096 2010-01-02 06:39 modalias
lrwxrwxrwx root root 2010-01-02 06:39 subsystem -> ../../../bus/platform
drwxr-xr-x root root 2010-01-02 06:35 power
lrwxrwxrwx root root 2010-01-02 06:39 driver -> ../../../bus/platform/drivers/mt6516-tpd
#cd power
#ls -l
-rw-r--r-- root root 4096 2010-01-02 06:39 wakeup

源码片段:
static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);

static struct attribute * power_attrs[] = {
&dev_attr_wakeup.attr,
NULL,
};
static struct attribute_group pm_attr_group = {
.name= "power",// attribute_group结构体的name域不为NULL的话,都会已name建立一个属性目录的
.attrs= power_attrs,
};

int dpm_sysfs_add(struct device * dev)
{
return sysfs_create_group(&dev->kobj, &pm_attr_group);//在当前device的kobject结构体对应的目录下建立
}

其中的device_pm_add()函数会将该设备插入到电源管理的核心链表dpm_list中统一管理。
值得一提的是,在函数device_initialize()会调用函数device_pm_init()来初始化该device结构体的power域:
dev->power.status = DPM_ON;

void device_pm_add(struct device *dev)
{
...
mutex_lock(&dpm_list_mtx);
if (dev->parent) {
if (dev->parent->power.status >= DPM_SUSPENDING)
// 如果某设备处于DPM_SUSPENDING极其之后的状态,此时不允许以该设备为父设备注册子设备
dev_warn(dev, "parent %s should not be sleeping\n", dev_name(dev->parent));
} else if (transition_started) { // transition_started全局变量包含在PM transition期间不允许注册设备
/*
* We refuse to register parentless devices while a PM
* transition is in progress in order to avoid leaving them
* unhandled down the road
*/
dev_WARN(dev, "Parentless device registered during a PM transaction\n");
}

list_add_tail(&dev->power.entry, &dpm_list);// 将device结构体通过power.entry项链接进dpm_list
mutex_unlock(&dpm_list_mtx);
}

void device_pm_remove(struct device *dev)
{
...
mutex_lock(&dpm_list_mtx);
list_del_init(&dev->power.entry);
mutex_unlock(&dpm_list_mtx);
pm_runtime_remove(dev);
}

举例说明:

我们熟知的platform bus在系统中也是作为一种设备注册进了系统,在sysfs文件系统中的位置是:
/sys/devices/platform。使用函数device_register(&platform_bus)进行注册,调用device_add()函数,
注册ok之后,也会出现目录/sys/devices/platform/power。最后也会将其添加进dpm_list中。

i2c控制器外设代表的设备是注册在platform总线上的,也就是说它的父设备是platform。
最终在platform_device_add()中会调用函数device_add()函数来添加设备,最终也会在mt6516-i2c.0/
mt6516-i2c.1/mt6516-i2c.2中出现一个power目录,同时这3个platform设备会依靠
platform_device.dev.power.entry连接件链接到电源管理核心链表dpm_list中。
/sys/devices/platform/mt6516-i2c.2/power

每一个i2c控制器都会在系统中至少注册成一个适配器(adapter),该结构体将会间接提供给i2c设备的驱动来使用,以避免直接使用i2c控制器结构体。这个适配器没有对应的driver,在错综复杂的i2c架构中,相对于只起到了一个承上启下的作用,上接i2c控制器的结构体及driver,下接i2c设备的结构体i2c_client和特点的driver。adapter.dev.parent为i2c控制器对应的device,所以就会出现名为i2c-0/1/2的设备kobject,只是该设备的bus总线和device_type是:
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
然后调用函数device_register(&adap->dev);来注册这个device,所以在对应的i2c-0/1/2目录下也会出现power目录。
/sys/devices/platform/mt6516-i2c.2/i2c-2/power

i2c设备会通过自动检测或者事先静态描述的方式来注册进系统,不管什么方式,都会调用到函数:i2c_new_device()
struct i2c_client*client;
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr);
status = device_register(&client->dev);
可以看得出来名字是什么了,例如:2-00aa
#ls -l /sys/devices/platform/mt6516-i2c.2/i2c-2/2-00aa
-rw-r--r-- root root 4096 2010-01-02 06:35 uevent
-r--r--r-- root root 4096 2010-01-02 06:38 name
-r--r--r-- root root 4096 2010-01-02 06:38 modalias
lrwxrwxrwx root root 2010-01-02 06:38 subsystem -> ../../../../../bus/i2c
drwxr-xr-x root root 2010-01-02 06:35 power
lrwxrwxrwx root root 2010-01-02 06:38 driver -> ../../../../../bus/i2c/drivers/mt6516-tpd

三、bus_type、device_driver、device_type、class中的dev_pm_ops方法结构体
在新的linux内核中,已不再有subsystem数据结构了,他的功能被kset代替。

全局变量bus_kset初始化:kernel_init()-->do_basic_setup()-->driver_init()-->buses_init()
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);

1. 总线类型结构体:bus_type,以platform和i2c总线为例:
@kernel/drivers/base/platform.c
static const struct dev_pm_ops platform_dev_pm_ops = {
.prepare = platform_pm_prepare,//
.complete = platform_pm_complete,//
.suspend = platform_pm_suspend,//
.resume = platform_pm_resume,//
.freeze = platform_pm_freeze,
.thaw = platform_pm_thaw,
.poweroff = platform_pm_poweroff,//
.restore = platform_pm_restore,
.suspend_noirq = platform_pm_suspend_noirq,
.resume_noirq = platform_pm_resume_noirq,
.freeze_noirq = platform_pm_freeze_noirq,
.thaw_noirq = platform_pm_thaw_noirq,
.poweroff_noirq = platform_pm_poweroff_noirq,
.restore_noirq = platform_pm_restore_noirq,
.runtime_suspend = platform_pm_runtime_suspend,
.runtime_resume = platform_pm_runtime_resume,
.runtime_idle = platform_pm_runtime_idle,
};

struct bus_type platform_bus_type = {
.name= "platform",
.dev_attrs= platform_dev_attrs,
.match= platform_match,
.uevent= platform_uevent,
.pm= &platform_dev_pm_ops,
};
从上面的dev_pm_ops结构体中拿出最普遍使用的函数指针来说明一下,对于bus_type它的电源管理是如何实现的。
static int platform_pm_prepare(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;

if (drv && drv->pm && drv->pm->prepare)
ret = drv->pm->prepare(dev);

return ret;
}
static void platform_pm_complete(struct device *dev)
{
struct device_driver *drv = dev->driver;

if (drv && drv->pm && drv->pm->complete)
drv->pm->complete(dev);
}
可以看出这两个函数都最终是利用了device_driver结构体中的dev_pm_ops函数方法结构体中的对应函数指针。

////////////////////////////////////////////
static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
{
struct platform_driver *pdrv = to_platform_driver(dev->driver);
struct platform_device *pdev = to_platform_device(dev);
int ret = 0;

if (dev->driver && pdrv->suspend)
ret = pdrv->suspend(pdev, mesg);

return ret;
}

static int platform_legacy_resume(struct device *dev)
{
struct platform_driver *pdrv = to_platform_driver(dev->driver);
struct platform_device *pdev = to_platform_device(dev);
int ret = 0;

if (dev->driver && pdrv->resume)
ret = pdrv->resume(pdev);

return ret;
}
////////////////////////////////////////////
static int platform_pm_suspend(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;

if (!drv)
return 0;

if (drv->pm) {
if (drv->pm->suspend)
ret = drv->pm->suspend(dev);
} else {
ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
}

return ret;
}

static int platform_pm_resume(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;

if (!drv)
return 0;

if (drv->pm) {
if (drv->pm->resume)
ret = drv->pm->resume(dev);
} else {
ret = platform_legacy_resume(dev);
}

return ret;
}


这里suspend和resume函数也是最终都是调用了device_driver结构体的dev_pm_ops方法结构体中的对应函数指针(device_driver.pm项被初始化),否则使用老式的方法:platform_legacy_suspend(dev, PMSG_SUSPEND)和platform_legacy_resume(dev)。根据这两个函数的源码可以看出。一般地,在我们的platform device的platform driver定义中,都是实现了pdrv.suspend和pdrv.resume函数,而并没有实现pdrv.driver.suspend和pdrv.driver.resume函数,其余三个函数可以在platform_driver_register()函数中看出:
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;

return driver_register(&drv->driver);
}

i2c总线注册没有使用新式的电源管理方法:dev_pm_ops,仍然使用老式的方式:
@kernel/drivers/i2c/i2c-core.c
struct bus_type i2c_bus_type = {
.name= "i2c",
.match= i2c_device_match,
.probe= i2c_device_probe,
.remove= i2c_device_remove,
.shutdown= i2c_device_shutdown,
.suspend= i2c_device_suspend,
.resume= i2c_device_resume,
};

static int i2c_device_suspend(struct device *dev, pm_message_t mesg)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;

if (!client || !dev->driver)
return 0;
driver = to_i2c_driver(dev->driver);
if (!driver->suspend)
return 0;
return driver->suspend(client, mesg);
}

static int i2c_device_resume(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;

if (!client || !dev->driver)
return 0;
driver = to_i2c_driver(dev->driver);
if (!driver->resume)
return 0;
return driver->resume(client);
}
// 实际上都是调用的i2c_driver结构体的suspend和resume函数。

2. device_type结构体暂时还没有找到有哪一个模块使用了新式了dev_pm_ops电源管理方法,一般都是没有实现这部分。

3. class结构体也没有找到使用dev_pm_ops方法结构体的地方,先暂时放一放。

4. device_driver
struct device_driver {
const char*name;
struct bus_type*bus;
...
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 i2c_driver {
...
/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
...
struct device_driver driver;
const struct i2c_device_id *id_table;

/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);
const struct i2c_client_address_data *address_data;
struct list_head clients;
};
一般都是实现了platform driver和i2c_driver结构体的suspend和resume函数,并没有使用新式的电源管理方式。

分享到:
评论

相关推荐

    linux 电源管理架构

    随着计算设备向着更加节能高效的方向发展,Linux 作为主流操作系统之一,其内核的电源管理 (Power Management, PM) 架构也经历了多次迭代与优化。本文旨在综述 Linux 内核中的电源管理框架,包括其关键组成部分及其...

    Linux设备驱动开发

    书中还删除了过时的内容,并新增了大量内容,如Linux内核的编码风格、Linux内核的移植、Android驱动、USBUDC和gadget驱动、ALSASoC驱动、input驱动、SPI驱动、基于sysfs的设备驱动、Linux设备驱动的固件加载、Linux...

    linux驱动开发的好书,老外写的

    - **电源管理**:讨论了Linux中的电源管理系统,包括休眠模式和功耗控制等。 #### 五、字符设备驱动 - **字符设备基础**:讲解字符设备的特性及其实现方式。 - **CMOS访问**:介绍如何通过字符设备访问系统CMOS,...

    linux内核分析及各个版本kernel源码地址

    Linux内核是开源操作系统的核心部分,它负责管理系统的硬件资源,调度进程,提供系统调用接口,以及确保系统的稳定性和安全性。对Linux内核的深入分析对于理解操作系统的工作原理至关重要,尤其是在开发驱动程序、...

    Inter Video手持多媒体技术广泛应用于移软科技基于Linux智能手机系统设计中.pdf

    Inter Video手持多媒体技术...Inter Video手持多媒体技术可以广泛应用于移软科技基于Linux智能手机系统设计中,实现智能手机系统的设计和开发,同时也可以提供一个集中管理的知识库系统和开放式的PowerWise接口标准。

    君正Linux_开发指南.pdf

    - UDEV负责管理系统的设备节点。 - **创建INITRAMFS**: - INITRAMFS是一种用于临时存储根文件系统的压缩文件系统。 #### 6. 如何在只有SD卡的情况下构建一个完整的系统 - **SD卡作为主要存储介质**: - 介绍如何...

    LINUX服务介绍(清晰版).pdf

    5. **alsa** - 高级Linux声音架构,包含在内核中,提供音频输入输出功能。 - **知识点**: ALSA (Advanced Linux Sound Architecture) 是Linux内核的一部分,为用户提供了一种统一的方式来处理音频设备。 6. **...

    Linux kernel-3.18.8

    Linux内核是操作系统的核心部分,负责管理系统的硬件资源、提供系统调用接口以及调度进程等。3.18.8是Linux内核的一个版本,它在Linux内核的3.x系列中占据一席之地。这个版本的发布通常意味着对之前版本的错误修复、...

    Linux常用命令浅析.pdf

    有些用户会使用直接断掉电源的方式来关闭 Linux 系统,这是十分危险的。因为 Linux 与 Windows 不同,其后台运行着许多进程及用户,所以强制关机可能会导致进程的数据丢失,使系统处于不稳定的状态,甚至在有的系统...

    \MTK驱动架构分析\MTK驱动架构分析\MTK驱动架构分析

    MTK(MediaTek)驱动架构分析是嵌入式系统和移动设备开发中的关键部分,尤其在Android系统中,驱动程序是连接硬件与操作系统的核心。本文将深入探讨MTK驱动架构的各个方面,帮助读者理解其工作原理和设计思路。 MTK...

    一体化智能运维管理系统招标参数-0812 (2).pdf

    【一体化智能运维管理系统】是一种专为互联网行业设计的高级IT管理解决方案,旨在通过自动化和智能化技术,提升IT系统的监控、管理和控制效率。该系统通常包括以下几个核心知识点: 1. **架构要求**: - **软硬件...

    基于Linux的AT91SAM9G20微处理器节能研究.pdf

    然而,由于这些设备通常需要长时间运行且电源受限,因此研究如何在基于Linux的操作系统上优化其能源效率显得至关重要。 本文针对AT91SAM9G20微处理器的节能进行了深入研究,提出了一个基于Linux操作系统的节能方案...

    STM32MP135实现input驱动【支持STM32MP1系列单片机_Linux驱动】.zip

    Linux内核驱动模型是系统硬件接口的核心部分,它提供了一种结构化的方法来管理设备驱动程序。输入子系统是Linux内核中的一部分,用于处理各种输入设备,如键盘、鼠标、触摸屏等。输入驱动负责将硬件事件转换为内核...

    嵌入式系统设计师教程

    - 电源管理:考虑功耗和效率,特别是在电池驱动的设备中。 6. 软件开发流程 - 需求分析:明确系统功能和性能要求。 - 设计阶段:架构设计、硬件选型、软件架构设计。 - 编码实现:遵循编码规范,编写可读性高的...

    i.MX_Linux_User's_Guide.pdf

    - **功耗管理**:了解如何通过调整 CPU 频率、电源模式切换等方式来降低功耗。 - **多媒体处理**:掌握如何利用 i.MX 平台的多媒体加速器来提高音频、视频处理性能。 - **图形处理**:学习如何利用 GPU 加速来提升...

    深圳市商业银行信贷管理系统总体技术方案

    - **范围**:本方案涵盖了信贷管理系统的总体架构设计、关键技术实现方案、系统支撑环境等多个方面。 - **名词定义** - **信贷管理系统**:指为深圳市商业银行提供信贷业务管理、风险控制、统计分析等功能的信息...

    PCB行业智能工厂技术方案.pdf

    企业层级实现面向企业的经营管理,包括企业资源计划系统(ERP)、产品生命周期管理(PLM)、供应链管理系统(SCM)和客户关系管理系统(CRM)等;协同层级由产业链上不同企业通过互联网络共享信息实现协同研发、智能...

    imx6q开发板原理图

    这些信息点覆盖了从硬件架构、接口到电源管理和设计变更等多方面的详细知识,为使用和理解i.MX6Q开发板提供了扎实的理论基础。这些知识点对于嵌入式系统开发人员和硬件工程师来说至关重要,他们通常会根据原理图设计...

    clk-pfd.rar_V2

    在IT行业中,Linux内核是操作系统的核心部分,负责管理系统的硬件资源、进程调度以及提供系统调用等服务。本文将详细解析"clk-pfd.rar_V2"中的"IMX PFD clock for Linux v2.13.6"相关知识点。 首先,让我们了解...

Global site tag (gtag.js) - Google Analytics