当前位置:首页 » 操作系统 » suspendlinux

suspendlinux

发布时间: 2022-06-09 08:47:31

linux触摸屏驱动中什么时候会调用suspend这个函数

android系统摁下电源键后会让系统进入休眠以达到节电的目的。内核驱动中和休眠相关的就是suspend和resume函数。

suspend函数用于休眠,resume函数用于唤醒。下面分析驱动中的这两个函数是如何被调用到的。

驱动部分:

首先需要分析驱动的注册过程,较新的内核都是采用DTS方式来取代在内核中直接定义platform_device数据结构的注册方式,本文是基于DTS机制的内核来分析。

proct对应的dts文件在编译时被编译为dtb文件,uboot在启动时候会将其地址传给内核,内核在启动过程中会去解析,具体解析是在start_kernel()->setup_arch() --> unflatten_device_tree()中具体分析可以参考网上,解析的最终结果会存放在allnodes地址处,这个allnodes随后在machine的init函数
中被使用,init函数中会根据allnodes中的节点数据组合成platform_device数据结构,然后将其注册到platform总线上,下面简要分析一下并重点关注这些初始化过程中和
pm相关的初始化。

我参与的项目中machine的init函数就是via_init_machine函数,在这个函数中就是调用了of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)这个函数来解析allnodes的。of_platform_populate是系统提供的接口。下面分析这个接口的实现:

[html] view plain
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
struct device_node *child;
int rc = 0;

root = root ? of_node_get(root) : of_find_node_by_path("/");
if (!root)
return -EINVAL;

for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}

of_node_put(root);
return rc;
}
root最后就是取到的根节点,然后其作为参数传递给of_platform_bus_create,of_platform_device_create_pdata的实现如下:

[html] view plain
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;

/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, "compatible", NULL))) {
pr_debug("%s() - skipping %s, no compatible prop\n",
__func__, bus->full_name);
return 0;
}

auxdata = of_dev_lookup(lookup, bus);
if (auxdata) {
bus_id = auxdata->name;
platform_data = auxdata->platform_data;
}

if (of_device_is_compatible(bus, "arm,primecell")) {
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
}

dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return 0;

for_each_child_of_node(bus, child) {
pr_debug(" create child: %s\n", child->full_name);
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
if (rc) {
of_node_put(child);
break;
}
}
return rc;
}
根据传入参数,我们这里直接分析of_platform_device_create_padate函数,如下:

[html] view plain
struct platform_device *of_platform_device_create_pdata(
struct device_node *np,
const char *bus_id,
void *platform_data,
struct device *parent)
{
struct platform_device *dev;

if (!of_device_is_available(np))
return NULL;

dev = of_device_alloc(np, bus_id, parent);
if (!dev)
return NULL;

#if defined(CONFIG_MICROBLAZE)
dev->archdata.dma_mask = 0xffffffffUL;
#endif
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;

/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
* to do such, possibly using a device notifier
*/

if (of_device_add(dev) != 0) {
platform_device_put(dev);
return NULL;
}

return dev;
}

of_platform_device_create_padate->of_device_alloc->platform_device_alloc

便在platform_device_alloc函数中进行进行alloc和初始化了,实现如下:

[html] view plain
struct platform_device *platform_device_alloc(const char *name, int id)
{
struct platform_object *pa;

pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
if (pa) {
strcpy(pa->name, name);
pa->pdev.name = pa->name;
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
arch_setup_pdev_archdata(&pa->pdev);
}

return pa ? &pa->pdev : NULL;
}
可以看到有个device_initialize,这里面对pdev.dev做一些列的初始化,其中有一个函数就是device_pm_init,这个函数就是我们一直关心的device相关的pm函数,具体实现如下:

[html] view plain
void device_pm_init(struct device *dev)
{
dev->power.is_prepared = false;
dev->power.is_suspended = false;
init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
dev->power.wakeup = NULL;
spin_lock_init(&dev->power.lock);
pm_runtime_init(dev);
INIT_LIST_HEAD(&dev->power.entry);
dev->power.power_state = PMSG_INVALID;
}

可以看见它对device和功耗相关的数据做了一些初始化,我们这里先重点关注下dev->power.entry,初始化一个链表头,所以他/它很有可能会在后面加到某个链表里面去,而那个链表应该是用来保存所有的device用的。系统中所有的platform_device都是通过这种方式注册到系统中的,那么应该所有的platform_device都会初始化一个dev->power.entry,如果到时候把所有的dev->power.entry都添加到某个链表上去,那么系统到时候查询的时候只要找到这个list head就可以找到所有的platform_device了。嗯,不过这是我们的猜测。我们接下去分析来验证下。

platform_device通过alloc之后已经初始化好了,那么接下去就可以添加到系统中了,所以我们再回头看of_platform_device_create_pdata的实现。
函数在of_device_alloc之后把dev->dev.bus赋值给了platform_bus_type,接着就调用了of_device_add函数,在of_device_add函数中最后通过device_add添加到了bus上,但是device_add中有个函数需要我们关系,就是device_pm_add(dev),实现如下:

[html] view plain
void device_pm_add(struct device *dev)
{
pr_debug("PM: Adding info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
mutex_lock(&dpm_list_mtx);
if (dev->parent && dev->parent->power.is_prepared)
dev_warn(dev, "parent %s should not be sleeping\n",
dev_name(dev->parent));
list_add_tail(&dev->power.entry, &dpm_list);
dev_pm_qos_constraints_init(dev);
mutex_unlock(&dpm_list_mtx);
}

可以看到这里list_add_tail(&dev->power.entry, &dpm_list);这就验证了我们之前的猜测。所有注册到系统中的设备,最终都是会添加到dpm_list这条链表上。

那么系统在休眠的时候是如何通过dmp_list这表链表来suspend设备的呢?接下去就是我们要分析的电源管理部分内容。

系统电源部分:
电源管理相关文件在kernel/power目录下,前面已经分析到。系统中注册的设备都是会添加到dmp_list这条链表上的。那么睡眠的时候系统应该是会查找dmp_list这条链表,
然后通过这条链表依次去查到对应的driver,然后调用driver中的suspend方法。下面我们来验证。

2.在suspend会轮询bus下的driver,然后一次调用到driver->pm->suspend方法,然后进入休眠。

3.state_store->pm_suspend->enter_state->suspend_devices_and_enter->dpm_suspend_start->dpm_suspend->device_suspend->__device_suspend->pm_op->(ops->suspend)

Ⅱ linux suspend resume可以使用互斥体吗

Suspend可以挂起一个线程,就是把这个线程暂停了,它占着资源,但不运行,用Resume是继续挂起的线程,让这个线程继续执行下去

Ⅲ linux 如何立刻suspend usb

suspend:

#disableexternalwake-up;dothisonlyonce
echodisabled>/sys/bus/usb/devices/usb1/power/wakeup

echosuspend>/sys/bus/usb/devices/usb1/power/level#turnoff

wake up:

echoon>/sys/bus/usb/devices/usb1/power/level#turnon

根据你的实际情况修改usb1为usb n

Ⅳ 在linux中,qsub投任务,我想问一下这两个状态:pending和suspend 有什么区别

通常情况下:
Pending是指任务在可以随时运行,但是因为已经有任务在运行,所以排队,这种状态的任务可随时进入运行态。
Suspend是被挂起的,在等待资源,等待的资源可以是输入、信号或者硬件设备,在得到想要的资源后会转成Pending状态(如果有任务在运行)。

Ⅳ 红帽linux ctrl+alt+delete第一个选项suspend和第二个选项hibemate是做什么的

suspend 休眠到内存。。。休眠过程中掉电的话开机工作丢失,但是不掉电的情况下恢复工作速度快
hibernate 休眠到硬盘,即使掉电后开机依然可以继续先前的工作,但是速度慢一些。。。因为要将硬盘上的状态拷到内存

Ⅵ 如何在Android 或Linux 下,做Suspend /Resume 的Debug

在Linux或Android下,做power management 的调适时,常遇到没有足够的information,可以做为debug时的依据和参考

我们整理了几个常用的参数或Command,可供设计者,得到足够的Informaiton 做Suspend / Resume的function Debug。

加boot 参数 no_console_suspend
基本上我们常常使用console做为suspend function的debug的Information source,但原始的source code在suspend过程中,会将console关掉。所以我们看到一定程度后就再也看不到message了。

但是我们并不知道在Suspend的过程中,系统到底发生了什么事,可能造成无法suspend。
为此,我们就会在kernel 启动参数中加上no_console_suspend这个参数。在AM/DM37x APM中是修改boot.scr档案参数
#!/bin/sh
cat <<EOF > boot.cmd
if fatload mmc 0 82000000 uImage
then
echo ***** Kernel: /dev/mmcblk0p1/uImage *****
fi
echo ***** RootFS: /dev/mmcblk0p2 *****
# Pantherboard DVI output
#setenv bootargs 'console=ttyO2,115200n8 androidboot.console=ttyO2 mem=512M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y omapdss.def_disp=dvi vram=32M omapfb.mode=dvi:1280x720MR-32 omapfb.vram=0:16M mpurate=1000'
# Pantherboard LCD output
setenv bootargs 'console=ttyO2,115200n8 androidboot.console=ttyO2 mem=512M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y omapdss.def_disp=lcd omapfb.mode=lcd:800x480MR-32 vram=8M omapfb.vram=0:8M mpurate=1000'

将no_console_suspend加上去到boot 参数后就好了

setenv bootargs 'console=ttyO2,115200n8 androidboot.console=ttyO2 mem=512M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y omapdss.def_disp=lcd omapfb.mode=lcd:800x480MR-32 vram=8M omapfb.vram=0:8M mpurate=1000 no_console_suspend'

如果是OMAP4 APM的话,请修改Kernel 参数的所在档案即可(在U-boot Source code中)

这个是基本的参数,所以在Android或Linux上都可以使用。 kernel把console suspend掉以后, 不管里面出了什么事情, 在Console上都看不到。 而使用这个参数后,大部分在suspend/resume时候的死机都可以通过Console看到kernel Panic的信息, 这样我们才会知道是哪里出了问题。 因为有的时候resume出错, 或者suspend到很后面出错的console不加这个参数都看不到。

但这个参数在TI OMAP3/OMAP4/AM37x/DM37x有可能造成有时Suspend 完当掉或是resume 失败的问题,假如已经抓到问题在那的时候,您就可以将这个参数Disable,不然很可能就会Debug不下去。

initcall_debug
这个同样kernel参数,使用的时机是,当我们不知道是那个driver在suspend/resume过程中出错的时候,可以使用这个参数来找出问题所在。在下完这个参数后,Kernel在suspend时,会将每个driver或task的状况report出来。我们可以借由这些information,Check 在suspend时,每个task和driver是否已经完成进suspend 的相关准备工作…

打开这个参数的方法有二种
一种是在console下Command,启动这个function…

echo 1 > /sys/mole/kernel/parameters/initcall_debug
echo 9 > /proc/sys/kernel/printk

其中上面的第一条命令是打开initcall_debug, 这个是所有的kernel都会有的。

而第二条命令是要提高kernel message 级别,因为initcall的这些信息都是KERN_DEBUG级别的, 所以需要提高printk的级别才可以看到, 要不然suspend/resume的时候挂了,你就没有机会看到这些信息了。

另一种启动方法是写在kernel的启动参数下,就可以了。

setenv bootargs 'console=ttyO2,115200n8 androidboot.console=ttyO2 mem=512M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y omapdss.def_disp=lcd omapfb.mode=lcd:800x480MR-32 vram=8M omapfb.vram=0:8M mpurate=1000 initcall_debug no_console_suspend'

同样的,这个参数也有可能造成AM37x/DM37x/OMAP4 APM发生进suspend当掉的问题。所以一旦知道问题所在,麻烦请将这个参数Disable掉。
suspend_test
这个方法可以用rtc这种软件的方式来做循环的suspend/resume, 尽管对于Android这样并不是很足够, (还要再模拟一个POWER_KEY上去才够), 但是对于测试Driver的稳定性, 还是有一定用处的。不要认为suspend了几次可以,那么就可以通过几千次的测试。这个suspend是5秒钟用RTC唤醒,然后回到Android后5秒钟又会自动睡下去,但是对于通用Linux,你可以写个script来让他起来一会再睡下去,或许这个工具比较有用rtcwakeup(google rtcwakeup)。

使用方法:
编译一个有这个功能的kernel, make menuconfig 以后选上

CONFIG_PM_DEBUG=y
CONFIG_PM_TEST_SUSPEND=y

这两个选项,烧写新的kernel,然后打开你需要测试的Device, 比如WIFI,3G

echo "core" > /sys/power/pm_test
echo "mem" > /sys/power/state

这样, 它就会循环休眠和唤醒了。

wakelock
Android和Linux在Power Management相关的最大的就是wakelock机制的有无。Android有时候会碰到suspend进不去,或者suspend到最后又莫名奇妙的wake up的问题。这些都有可能是wakelock引起的,或者说是wakelock的使用者引起的。怎么fine tune呢,使用Console在Android 系统下设定:
echo 15 > /sys/mole/wakelock/parameters/debug_mask
echo 15 > /sys/mole/userwakelock/parameters/debug_mask

15是代表16进制的F, 在wakelock里面就是把所有的debug信息打开, 起码现在是这样设定的。如果以后不够用了,可能就会改成255.
这样你能看到kernel和frameworks层对于wakelock的操作、申请及释放。这样看申请和释放成对否就可以了。
注意: wakelock有一种是timeout的,就是说多少毫秒以后,会自动释放,对于这些wakelock,申请和释放可能是不成对的。

power.0
有时看到系统suspend到了最后, 然后遇到power.0后suspend失败,然后整个系统又resume回来。这个是android专有的,因为power.0是android注册到suspend最后的一个行程, 它会在CPU进入suspend之前检查一下有没有wakelock存在, 如果这时候还有没有释放的wakelock, 那么它会return -EBUSY然后导致整个suspend失败。 Check这个问题的方法就是把上面wakelock的debug信息打开,然后看看是哪个去申请了wakelock,然后Release它。

这个错误的错误信息大概是这样的:

pm_noirq_op(): platform_pm_suspend_noirq+0x0/0x38 returns -11
PM: Device power.0 failed to suspend late: error -11

earlysuspend
在android里面中另外一个和Power Management有相关的机制叫earlysuspend, 同样可以打开debug message,用来做Android earlysuspend debug之用:
echo 15 > /sys/mole/earlysuspend/parameters/debug_mask

来把相关的debug信息印出来, 例如那个earlysuspend要被call之类的。
suspend/resume 时间 fine tune
有的时候你要调试suspend/resume的时间太慢的问题。 一种方法是用initcall_debug, 然后把printk的时间戳打上, 然后看那个process最慢,再来Check原因是什么
我有一个patch,专门用来调试这个问题的,但是upstream不接受, 说非要用这种折磨人的方法才行, 但是如果你想用可以下下来打上去用一下。
地址在这里:http://www.spinics.net/lists/linux-pm/msg24063.html
用法是, 打上这个PATCH以后, 在KERNEL里面选择上PM_DEBUG, SUSPEND_DEVICE_TIME_DEBUG 这两个选项。
然后
echo 微秒> /sys/power/device_suspend_time_threshold

比如
echo 50000 > /sys/power/device_suspend_time_threshold

注意这里是微秒哦。 。 。 它会把在suspend/resume的时候慢的那些driver打出来,然后你去干掉它。 。

热点内容
jrtplib编译 发布:2024-11-01 18:06:01 浏览:226
java代码中if 发布:2024-11-01 18:02:40 浏览:377
android定时刷新 发布:2024-11-01 17:59:43 浏览:999
炎黄解说我的世界服务器生存 发布:2024-11-01 17:59:42 浏览:542
如何清楚网页缓存 发布:2024-11-01 17:53:58 浏览:552
linux文件权限不够 发布:2024-11-01 17:53:19 浏览:917
c语言中10是什么意思 发布:2024-11-01 17:45:08 浏览:892
装棉衣压缩袋 发布:2024-11-01 17:37:18 浏览:297
android40ble蓝牙 发布:2024-11-01 17:36:58 浏览:712
数据库表对比 发布:2024-11-01 17:18:42 浏览:985