+ -
当前位置:首页 → 问答吧 → acpid+pm-utils唤醒问题

acpid+pm-utils唤醒问题

时间:2009-12-27

来源:互联网

前天开始装系统,到昨天下午基本完成,虽然中间经历了不少波折但装好之后对ArchLinux还算比较满意。不过成功的喜悦是暂时的,为了减少co2排放今天决定搞定笔记本的电源管理。
参照wiki文档安装acpid+pm-utils,创建/etc/acpi/events/power定义Power按钮按下后调用pm-suspend挂起系统:
#cat /etc/acpi/events/power
event=button/power.*
action=/usr/sbin/pm-suspend

写好后启动acpid,报告acpid: can't open /proc/acpi/event: No such file or directory。想起acpid用的是已经过时的/proc/acpi/event事件接口,编译内核时被我去掉了。
没办法,谁让acpid的netlink事件接口还没搞定(08年作者就说他还在努力),只能先加上迁就一下acpid。
改好内核用kexec重启,进入系统后按下电源键测试acpi事件和待机是否正常。硬盘劈里啪啦响过一阵后扬声器发出欢快的滴滴声,证明笔记本已经安然入睡了。关键时刻终于到来,究竟系统能否正常唤醒?无奈午休时间已到,只好怀着忐忑心情边吃饭边看完了最近流行的2012,更加坚定了我为节能减排作贡献的决心。

作者: lifc   发布时间: 2009-12-27

其实对这个老机还是比较有信心,之前用2.6.27核心时就测试过可以正常休眠唤醒。时代在进步linux在发展,心里想着怎么也不至于到了今天的2.6.31反而一睡不醒吧?
然而现实终究是残酷的,再次按下电源键之后系统滴的一声点亮了LCD的背灯,但屏幕上始终灰蒙蒙一片没有任何字符出现……
时间一秒一秒的流逝,最初的期望和信心也一点点化做了失望在内心中流淌。就在快要失去信心拔掉电源时左上角终于跳出了闪烁的光标,vga寄存器中光标发生器部分成功恢复,说明内核其实还没死……
经过漫长的等待(起码有一分钟)终于看到熟悉的控制台。本以为我们的故事就要在这里终止,谁知道死而复生的系统居然不能上网了。ifconfig检查网卡状态,怎么少了eth0?赶紧ifconfig -a再看一次,原来它还在那儿,只是没睡醒罢了。

作者: lifc   发布时间: 2009-12-27

因为有昨天安装时的不愉快经验,这个时候心里马上开始嘀咕:arch到底还是小众系统,休眠唤醒之后竟不记得重新激活网卡……看我先把网卡激活,然后写个pm-utils的脚本把你搞定……
ifconfig eth0 up之后傻了眼,系统死了???过了大概一分钟终于再次死而复生,原来刚才休眠唤醒就是执行到ifconfig eth0 up挂起的。想起之前用archboot光盘远程安装时遇到过同样问题,立马dmesg看kernel怎么说,不出所料果然和安装时的错误一样:
e100 0000:00:12.0: firmware: requesting e100/d101s_ucode.bin
e100: eth0: e100_request_firmware: Failed to load firmware "e100/d101s_ucode.bin": -2
pci 0000:00:14.0: PME# disabled
do_drive_get_GTF: Run _GTF error: status = 0x5

作者: lifc   发布时间: 2009-12-27

这下彻底无语了,昨天网络安装时还为了这个问题差点将两台笔记本“杀机取卡”换网卡,最后靠一块96年的10M古董PC卡网卡解了围。安装时用10M不要紧,比internet接入速度快就好,但装好后总不能为了正常休眠唤醒天天用10M网卡啊!
pacman -Ql udev看了一下包结构,负责固件加载的firmware.sh放在/lib/udev下,二话不说进去修改这个文件,增加一些桩子方便调试。
重启系统保存正常加载固件信息,休眠再唤醒系统经过1分23秒等待进入系统,对比两次的加载过程:调用环境变量一样,只是唤醒后访问/sys/devices/pci0000:00/0000:00:12.0/firmware/0000:00:12.0/loading失败。
再改一次脚本,把前后两次的/sys/devices/pci0000:00/0000:00:12.0目录内容保存下来分析,原来唤醒后少了firmware这个目录,难怪firmware.sh没办法完成加载。

作者: lifc   发布时间: 2009-12-27

看来固件加载部分代码出了什么问题,上网搜索一下同病相怜的国际友人不在少数,估计问题不太好解决,先看看有没有什么简便方法回避这个bug。
初步分析方案有几个:
1、将网卡固件编译进入内核,不用动态加载。应该可行,用gentoo这样做没有问题。
2、休眠之前停止网络服务、撤掉内核模块,唤醒后重新加载驱动模块初、始化网络服务。有效性待验证。
3、研究一下内核请求固件的流程,找到根本原因。麻烦一点应该还可行,也最彻底。
4、换不用固件的8139 mini pci网卡。需要拆老婆电脑不容易批准。

作者: lifc   发布时间: 2009-12-27

分析一下难度,4>3>2>1,但第一种方法不适合不想自己编译核心的同学,简单说一下方法然后从第二种方法开始入手。
内核配置中设置FIRMWARE_IN_KERNEL=y打开核心包含固件功能,然后设置EXTRA_FIRMWARE="e100/d101s_ucode.bin"告知内核编译脚本将e100/d101s_ucode.bin编入核心,再设置 EXTRA_FIRMWARE_DIR="/lib/firmware"标明二进制固件存放位置,前提是已经执行过make modules_install或者安装过firmware包,/lib/firmware目录存在上述固件。

作者: lifc   发布时间: 2009-12-27

嗯,我的intel 82559网卡在2.6.31下遇到过这个问题,最后还是把2.6.29的驱动源码放到2.6.31的源码树下,修改后重编内核搞好的。
这个问题是因为kernel是GPL的,因此不应该在里面放私有版权的固件,所以现在陆续分离出来了,不过一些程序员在驱动代码修改分离时,出了些bug,就这样了。只要有用户反馈,相信新的kernel就都解决了。

作者: 没本   发布时间: 2009-12-27

对目前linux内核包括大多数(几乎全部)硬件驱动的做法不是特别认同,毕竟社区的条件和资源是有限的,不太可能针对每种驱动、每种硬件型号、修订版、外围IC(桥、codec、eeprom、flash)的全部功能排列组合做完全测试,有能力的人没硬件,有硬件的人没能力,二者都具备的又未必有时间。希望将来能在内核与驱动之间形成一套相对固定(比如核心版本修改0.1接口变化一次)的API,如此厂商才有可能提供功能相对完善稳定的驱动(不愿开源的也可以二进制形式提供),降低linux系统使用者的入门难度。

作者: lifc   发布时间: 2009-12-27

接着刚才的话题说。第一种方法自己测试了一下没有问题,幸运的是对于e100这种网卡(至少手头这块)第二种方法(2、休眠之前停止网络服务、撤掉内核模块,唤醒后重新加载驱动模块初、始化网络服务)也是可行的。我的方法是在/etc/pm/sleep.d下创建一个50network脚本,具体内容如下:
#!/bin/bash

. /usr/lib/pm-utils/functions

case "$1" in
hibernate|suspend)
/etc/rc.d/network stop
rmmod e100
;;
thaw|resume)
modprobe e100
/etc/rc.d/network start
;;
*)
;;
esac

exit 0

这样每次休眠之前停止全部网络服务并卸载模块,唤醒之后再加载模块(和固件)并重新启用网络服务。这里要说一下,pm-utils本来已经提供了两个与之相关的脚本pm-utils /usr/lib/pm-utils/sleep.d/{11netcfg,55NetworkManager},但前者需要依赖11netcfg后者通过dbus发送通告消息给总线监听者,我这里都没有安装所以就不提了。另外pm-utils可以通过设置SUSPEND_MODULES="e100"这种方法来自动卸载模块,只是因为需要同时关闭、激活网络服务所以就直接写到上面的脚本:rmmod e100/modprobe e100。

作者: lifc   发布时间: 2009-12-27

引用:
作者: lifc
接着刚才的话题说。第一种方法自己测试了一下没有问题,幸运的是对于e100这种网卡(至少手头这块)第二种方法(2、休眠之前停止网络服务、撤掉内核模块,唤醒后重新加载驱动模块初、始化网络服务)也是可行的。我的方法是在/etc/pm/sleep.d下创建一个50network脚本,具体内容如下:
#!/bin/bash

. /usr/lib/pm-utils/functions

case "$1" in
hibernate|suspend)
/etc/rc.d/network stop
rmmod e100
;;
thaw|resume)
modprobe e100
/etc/rc.d/network start
;;
*)
;;
esac

exit 0

这样每次休眠之前停止全部网络服务并卸载模块,唤醒之后再加载模块(和固件)并重新启用网络服务。这里要说一下,pm-utils本来已经提供了两个与之相关的脚本pm-utils /usr/lib/pm-utils/sleep.d/{11netcfg,55NetworkManager},但前者需要依赖11netcfg后者通过dbus发送通告消息给总线监听者,我这里都没有安装所以就不提了。另外pm-utils可以通过设置SUSPEND_MODULES="e100"这种方法来自动卸载模块,只是因为需要同时关闭、激活网络服务所以就直接写到上面的脚本:rmmod e100/modprobe e100。
貌似以前ehci_hcd,uhci_hcd模块也会导致无法休眠。我觉得pm-utils用这个方法就足够了,没必要去改内核。改得乱七八糟到最后自己都不记得动了哪边。

作者: Alerander   发布时间: 2009-12-28

嗯,如果是不能进入休眠看一下/var/log/pm-suspend.log的内容,会标明哪个脚本或设备导致无法进入休眠,在休眠之前想办法把他们卸载掉说不定就可以了。

作者: lifc   发布时间: 2009-12-28