ThinkPad T14 Gen3 + Xubuntu 22.10 をハイバネートできるようにしてみた

ハイバネート

Ubuntu 22.04でのハイバネーション - Journal InTime(2023-01-03) を見て、自分の ThinkPad T14 Gen3 はそんなでもないけどサスペンド時にまあまあバッテリーが減るので、自分もハイバネートしようかと思ってやってみた。

ハイバネートの設定手順は上のブログに書いてあるのそのまま:

# swapoff -a300
# grep -q swapfile/etc/fstab ||  echo "/swapfile  none  swap  sw  0  0" >> /etc/fstab
# fallocate -l 32G /swapfile
# chown 0 /swapfile
# chmod 0600 /swapfile
# mkswap /swapfile
# swapon /swapfile
# findmnt / -o UUID
UUID
90263320-8701-4639-b7b9-9705677d9c7a
# filefrag -v /swapfile |grep " 0:"| awk '{print $4}'
34816..

/etc/default/grub を編集:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash resume=UUID=90263320-8701-4639-b7b9-9705677d9c7a resume_offset=34816"
# update-grub

メモリ 24GB なのでスワップは 32GB にした。 ファイルシステム上にあるスワップファイルの物理位置を指定するのってなんか怖いんだけど大丈夫なのかな。 スワップ専用パーテイションを用意する方が安全なんじゃないかと思ってしまう。

ハイバネートのテスト:

# systemctl hibernate

ちゃんとハイバネートして、電源ボタンで復帰すればOK。

でも復帰時に画面が真っ暗のままで syslog に延々と [drm] *ERROR* Fault errors on pipe A: 0x00000080 が出力されてしまう。

その状態で Ctrl-Alt-F1 押して Alt-F7 を押すとログイン画面が表示されてログも止まるんだけど、ログがすごい勢いで溜まってディスクを圧迫するので止めたい。

どうやらカーネル 6.0.3 で直ってるらしいので、mainline から 6.0.19 を取ってきてインストールしたら直った。

6.1 を使ったほうがいいのかな、実は…。

蓋を閉じたときにハイバネート

Xubuntu は蓋を閉じたときの振る舞いとしてハイバネートを設定できない。 何かやればできるようになるのかもしれないけど、軽くググったくらいだと見つからなかったので自力でなんとかする。

LID イベントを拾えればいいので、入力デバイスを調べる:

% sudo evtest
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:  Sleep Button
/dev/input/event1:  Lid Switch
/dev/input/event10: sof-hda-dsp Mic
/dev/input/event11: sof-hda-dsp Headphone
/dev/input/event12: sof-hda-dsp HDMI/DP,pcm=3
/dev/input/event13: sof-hda-dsp HDMI/DP,pcm=4
/dev/input/event14: sof-hda-dsp HDMI/DP,pcm=5
/dev/input/event15: Integrated Camera: Integrated C
/dev/input/event16: rkremap
/dev/input/event2:  Power Button
/dev/input/event3:  AT Translated Set 2 keyboard
/dev/input/event4:  ThinkPad Extra Buttons
/dev/input/event5:  ELAN0676:00 04F3:3195 Mouse
/dev/input/event6:  TPPS/2 Elan TrackPoint
/dev/input/event7:  Video Bus
/dev/input/event8:  Intel HID events
/dev/input/event9:  ELAN0676:00 04F3:3195 Touchpad
Select the device event number [0-16]: ^C

/dev/input/event1 がそれっぽい。 自作 gem の rkremap をインストールした状態で、こんな感じにすると蓋を閉じたイベントを拾って systemctl hibernate を実行することができた。

% sudo ruby -rrkremap -e 'dev = Rkremap::Evdev.new("/dev/input/event1"); dev.grab; loop{e = dev.read_event; system("systemctl hibernate") if e.ev_type == 5 && e.value == 1 }'

grab してるので普通の電源設定の方のサスペンドとかが動いちゃうこともない。 もっと簡単な方法もあるような気がするけどまあいいや。

サスペンドしてしばらくしてからハイバネート

ハイバネートはサスペンドに比べると復帰までに時間が掛かるので、蓋を閉じるたびにハイバネートするのはいまいち。 サスペンドしてしばらくしてからハイバネートする suspend-then-hibernate というのがあったので、これを使ってみる。

% sudo ruby -rrkremap -e 'dev = Rkremap::Evdev.new("/dev/input/event1"); dev.grab; loop{e = dev.read_event; system("systemctl suspend-then-hibernate") if e.ev_type == 5 && e.value == 1 }'

サスペンドしてからハイバネートするまでの時間は /etc/systemd/sleep.conf の HibernateDelaySec で設定できる。デフォルトは 120min らしい。ちょっと長いので 30min にしてみた。

勝手にハイバネートが解除される

これで完成!…と思ったけど、蓋閉じてるのになぜか普通に電源が入ってバッテリを食い尽くしてサスペンドになっていたことがあった。

systemctl hibernate を何回か実行して試してみたら 4〜5回に1回くらいはハイバネート直後に復帰しちゃう。

復帰トリガー - ArchWiki を見て、次のように対処してみた。

S4(ハイバネート)の復帰トリガーとして有効なものをリスト:

% cat /proc/acpi/wakeup | grep 'S4.*enabled'
PEG0      S4    *enabled   pci:0000:00:06.0
TXHC      S4    *enabled   pci:0000:00:0d.0
TDM0      S4    *enabled   pci:0000:00:0d.2
TDM1      S4    *enabled   pci:0000:00:0d.3
TRP0      S4    *enabled   pci:0000:00:07.0
TRP2      S4    *enabled   pci:0000:00:07.2
AWAC      S4    *enabled   platform:ACPI000E:00
LID       S4    *enabled   platform:PNP0C0D:00

LID は蓋なので有効でもいい。それ以外はよくわからなかったけど echo XXX > /proc/acpi/wakeup で全部無効化した。

この状態で試してみたら勝手に復帰しちゃうことはなくなったっぽいので、この設定を永続化する。 udev をいじったりすると永続化設定できるみたいなんだけど、難しくてよくわからなかったので、起動スクリプトを作った。

/etc/init.d/disable-wakeup:

#!/bin/sh
### BEGIN INIT INFO
# Default-Start: 2 3 4 5
### END INIT INFO
cat /proc/acpi/wakeup | grep 'S4.*enabled' | awk '{print $1}' | grep -v LID | while read x; do
  echo "$x" > /proc/acpi/wakeup
done

というファイルを作って、 sudo update-rc.d disable-wakeup defaults で Linux 起動時に自動実行されるようにした。

しばらく使ってみてるけど大丈夫っぽい。 念の為、電源設定で、バッテリ駆動時に無操作状態が15分続くとサスペンドするように設定しておいてある。

この続きはcodocで購入