退役したMacBook 12インチ(MacBook10,1、2017年モデル)にUbuntu 26.04を入れたところ、フタを閉じて開くと画面に「認証エラー」と表示され、キーボード入力も受け付けなくなった。電源ボタン長押し以外に復帰する手段がない。
結論から言うと、原因はApple製NVMe SSDとそのPCIeルートポートをD3coldに落とすことだった。suspendのnoirqフェーズでハングし、そのまま復帰しない。udevルールでd3cold_allowed=0にすれば直る。
「認証エラー」もキーボードが効かないのも症状であって原因ではなかった。最初はキーボードドライバを疑って時間を溶かしたので、切り分けの過程も含めて残しておく。
環境
| 項目 | 内容 |
|---|---|
| 機種 | MacBook10,1(12インチ, 2017) |
| OS | Ubuntu 26.04 LTS |
| カーネル | 7.0.0-28-generic |
| SSD | APPLE SSD AP0512J(Apple S3X NVMe Controller, 106b:2003) |
| デスクトップ | GNOME / Wayland |
症状
フタを閉じるとサスペンドし、開くと画面は復帰する。しかしそこに「認証エラー」と表示され、パスワードを入力しようにもキーボードが反応しない。トラックパッドも同様。電源ボタン長押しで強制終了するしかなかった。
最初の見立ては外れた
MacBook 12インチのキーボードとトラックパッドはUSBではなくSPI接続で、applespiというドライバが使われている。
lsmod | grep -E 'applespi|spi_pxa'applespi 57344 0spi_pxa2xx_platform 12288 0spi_pxa2xx_core 32768 1 spi_pxa2xx_platform「復帰後にapplespiのキーボードが死ぬ」という報告は検索するといくらでも出てくる。定番の回避策はサスペンド前後でモジュールを載せ替えるというものだ。/usr/lib/systemd/system-sleep/にフックを置けば、サスペンド前にpre、復帰後にpostという引数で呼ばれる。
#!/bin/shcase "$1" in pre) modprobe -r applespi ;; post) modprobe applespi ;;esacこれは効かなかった。SPIコントローラ本体(spi_pxa2xx_platform、spi_pxa2xx_core)まで含めて外しても同じ。後から分かるのだが、applespiはそもそも無関係だった。
ログが1行も残らない
まともに調べようとして、最初にぶつかったのがこれだった。journalctlで過去のブートを見ると、どのブートも例外なく同じ行で途切れている。
journalctl -b -1 --no-pager -n 37月 27 17:47:20 systemd-sleep[6306]: Performing sleep operation 'suspend'...7月 27 17:47:20 kernel: PM: suspend entry (deep)復帰後のログが1行も無い。5回分のブートを見て全部これだった。
つまり復帰後にディスクへの書き込みが一切通っていない。画面は出ているのにログが残らないという状況で、この時点で「キーボードの問題」という見立てはかなり怪しくなる。
ハングする系の問題を調べるときは、ログを書くたびにsyncする必要がある。ページキャッシュに残ったまま電源を切れば消えてしまうからだ。以降のスクリプトはすべてこうしている。
say() { echo "$(date '+%F %T') $*" >> "$LOG"; sync; }pm_testで段階を切り分ける
カーネルにCONFIG_PM_DEBUG=yが入っていれば/sys/power/pm_testが使える。これは実際には眠らずに、サスペンド処理を途中まで実行して5秒後に戻ってくるという機能で、まさにこういう時のためにある。
cat /sys/power/pm_test[none] core processors platform devices freezer浅い段階から順に試す。
for stage in freezer devices platform processors core; do echo "$stage" | sudo tee /sys/power/pm_test echo freeze | sudo tee /sys/power/statedone結果はこうなった。
<<< stage=freezer 成功<<< stage=devices 成功>>> stage=platform 開始 ← ここから戻ってこない2回繰り返して同じ結果。これで一気に絞れた。
各段階の意味は次の通り。
| 段階 | 内容 |
|---|---|
freezer | プロセスを凍結するだけ |
devices | + 各ドライバの通常フェーズのsuspend/resume |
platform | + late/noirqフェーズとプラットフォーム(ACPI)処理 |
processors | + 起動CPU以外を停止 |
core | + カーネルコアのsuspend |
devicesが通ったということは、applespiもNVMeも無線もi915も、通常フェーズのsuspend/resumeは全部正常ということだ。キーボードドライバ説はここで完全に否定された。
そしてplatformに含まれるのはlate/noirqフェーズ。ここはPCIデバイスを低電力状態(D3)に落とす処理が走る場所である。
ちなみに、この段階ではコンソールも既に落ちているため、no_console_suspendを付けて画面を見張っても何も出ない。ここでだいぶ回り道をした。
D3coldを疑う
noirqフェーズでの電源遷移が怪しいので、PCIデバイスを完全に電源断(D3cold)にする処理を止めて試す。sysfsにd3cold_allowedというノブがある。
for d in /sys/bus/pci/devices/*/d3cold_allowed; do echo 0 | sudo tee "$d"; doneこの状態でplatform段階を実行すると——通った。
2026-07-28 10:43:08 === d3cold_allowed=0 を 19 個のデバイスに設定2026-07-28 10:43:09 >>> platform 段階を実行 (条件: no-d3cold)2026-07-28 10:43:17 <<< ★通過★ 条件: no-d3cold原因はnoirqフェーズでのPCIe D3cold遷移で確定。
犯人を特定する
全デバイスで禁止すれば動くが、消費電力の面では無駄が多い。どのデバイスかを特定する。PCIツリーはこうなっている。
lspci -t -v-[0000:00]-+-02.0 Intel Kaby Lake-Y GT2 [HD Graphics 615] +-1c.0-[01]----00.0 Apple Inc. S3X NVMe Controller +-1d.0-[02]----00.0 Broadcom BCM4350 802.11ac Wireless +-1d.1-[03]----00.0 Broadcom 720p FaceTime HD Camera ...ここで効率のいいやり方がある。「1グループだけD3coldを許可して残りは全部禁止」を順に試すのだ。無実のグループは通過するのでマシンは生きたまま次に進める。固まった時点のグループが犯人になる。
hunt_group() { label="$1"; shift for d in /sys/bus/pci/devices/*/d3cold_allowed; do echo 0 > "$d"; done for a in "$@"; do echo 1 > "/sys/bus/pci/devices/$a/d3cold_allowed"; done say ">>>>>> グループ [$label] のみ D3cold 許可" echo platform > /sys/power/pm_test sync echo freeze > /sys/power/state && say "<<< 通過"}
hunt_group "NVMe" 0000:00:1c.0 0000:01:00.0hunt_group "無線" 0000:00:1d.0 0000:02:00.0hunt_group "カメラ" 0000:00:1d.1 0000:03:00.0最初のグループで止まった。
2026-07-28 10:51:02 >>>>>> グループ [NVMe] のみ D3cold 許可 (0000:00:1c.0 0000:01:00.0)2026-07-28 10:51:02 >>> platform 段階を実行 (条件: only:NVMe)(以降なし)犯人はApple S3X NVMe(01:00.0)とそのPCIeルートポート(00:1c.0)。強制終了して再起動し、残り3グループも確認したが、無線・カメラ・その他はすべて通過した。
<<< ★通過★ 条件: only:無線<<< ★通過★ 条件: only:カメラ<<< ★通過★ 条件: only:その他なぜ「認証エラー」だったのか
これで最初の症状の説明がつく。
- 復帰時にNVMeが戻らない
- ディスクI/Oが全滅する
- PAMが
/etc/shadowを読めず、ロック画面が「認証エラー」を出す - journaldも書けないので、ログが
PM: suspend entryで途切れる - ロック画面が固まっているので、キーボードが効かないように見える
画面(GNOME Shell)はメモリ上にあるので描画はされる。だから「画面は出るのに何もできない」という、いかにも入力デバイスの問題に見える症状になっていた。
対策
3つ入れた。
サスペンド方式をs2idleにする
Apple のEFIはmacOS向けに作られていて、S3(deep)からの復帰パスがLinuxでは動かないという報告が多い。ファームウェアを経由しないs2idleに変更する。
[Sleep]MemorySleepMode=s2idleなお、これは切り分けの初期に入れたもので、D3coldを直した後にdeepでも動くかは確認していない。s2idleで問題なく動いているのでそのままにしてある。
NVMe経路のD3coldを禁止する
これが本命。udevルールで起動時に設定する。
ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:00:1c.0", ATTR{d3cold_allowed}="0"ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:01:00.0", ATTR{d3cold_allowed}="0"反映はsudo udevadm control --reloadと再起動。
保険とログ
udevが取りこぼした場合に備えて、サスペンド直前に再適用するフックも置いた。ついでに復帰の記録も残す。
#!/bin/shLOG=/var/log/macbook-sleep.logNVME_PATH="0000:00:1c.0 0000:01:00.0"case "$1" in pre) echo s2idle > /sys/power/mem_sleep 2>/dev/null for a in $NVME_PATH; do echo 0 > "/sys/bus/pci/devices/$a/d3cold_allowed" 2>/dev/null done echo "$(date '+%F %T') pre op=$2" >> "$LOG"; sync ;; post) echo "$(date '+%F %T') post op=$2 復帰成功" >> "$LOG"; sync ;;esacchmod +xを忘れずに。
結果
フタの開閉で問題なく復帰するようになった。
2026-07-28 11:04:48 pre op=suspend2026-07-28 11:05:50 post op=suspend 復帰成功2026-07-28 11:09:46 pre op=suspend2026-07-28 11:09:47 post op=suspend 復帰成功復帰後のジャーナルも当然ながら残るようになり、カーネル側の復帰は0.5秒で完了していることが確認できる。
11:05:50.071 kernel: Freezing user space processes11:05:50.077 kernel: nvme nvme0: 1/0/0 default/read/poll queues11:05:50.486 kernel: PM: suspend exit11:05:50.675 systemd[1]: Finished grub2-common.service代償は、サスペンド中の消費電力がわずかに増えること。D3coldはPCIeデバイスの電源を完全に落とす状態で、それをD3hot止まりにしているためである。
役に立たなかったもの
pm_trace
CONFIG_PM_TRACE=yがあれば/sys/power/pm_traceが使える。suspend/resume中の各デバイスコールバックのハッシュをRTC(ハードウェア時計)に書き込み、電源を切っても消えないので次回起動時に「どのデバイスで止まったか」を教えてくれる、という仕組みだ。
期待して試したが、結果はこれだった。
PM: Magic number: 8:1:0PM: hash matches drivers/base/power/main.c:1988memory memory48: hash matchesmemory memory48はハッシュ衝突による偽陽性の典型で、/sys/power/pm_trace_dev_matchを見てもinputとmemoryにしか一致しない。ハッシュ空間が狭いので、こうなると使い物にならない。
副作用としてハードウェア時計が壊れる(上のログの通り、RTCが2024-01-01などに書き潰される)ので、使うなら覚悟がいる。Ubuntu 26.04にはhwclockが標準で入っていないので、時計はNTP同期後にtimedatectlで直すことになる。
no_console_suspend
quiet splashを外してno_console_suspend ignore_loglevelを付ければ、ハングした瞬間の最後の行が画面に残るはず——と考えたが、今回止まっていたnoirqフェーズではコンソールも既に落ちているため何も出なかった。
なおignore_loglevelを付けたままにすると、全カーネルメッセージをフレームバッファに描画するので復帰が体感でわかるほど遅くなる。デバッグが終わったら必ず外すこと。
残っている問題
復帰後、パネルが点灯するまでにまだ時間がかかる。ただしこれは別問題で、
- カーネルの復帰は0.5秒で完了しており、ジャーナルに待ち時間の空白が無い
- つまりシステムは裏で動いていて、画面だけが暗い
という状況。バックライトデバイスがacpi_video0しか無く、起動ログに次の行が出ている。
i915 0000:00:02.0: [drm] Skipping intel_backlight registration輝度制御をACPI(LNXVIDEO:00)が握っていて、i915のネイティブ制御が無効になっている。復帰のたびにacpi LNXVIDEO:00: Restoring backlight stateが出ているのも符合する。
定石通りacpi_backlight=nativeを試したが改善しなかったので、これは未解決のまま。とりあえず復帰はするので良しとしている。進展があれば追記する。
まとめ
- 復帰しない系の調査では、まず
/sys/power/pm_testでfreezer→devices→platformと段階を切ること。これだけで犯人の範囲が劇的に狭まる - ログは書くたびに
syncする。しないと消える platformで止まるならnoirqフェーズ、つまりPCIの電源遷移を疑う。d3cold_allowedは再起動なしで試せる- 「1グループだけ許可」方式なら、無実のグループは通過するので再起動の回数を最小化できる
- 症状(認証エラー、キーボードが効かない)から原因を推測しても当たらない