Skip to content

kernel: Retain the tethered warm boot state across kexec - #107

Draft
brkosebay wants to merge 29 commits into
OrchardLinux:mainfrom
brkosebay:j71t/warm-kernel
Draft

brkosebay wants to merge 29 commits into
OrchardLinux:mainfrom
brkosebay:j71t/warm-kernel

Conversation

@brkosebay

@brkosebay brkosebay commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Part 8 of 23 of the iPad 5 (J71t) series in this repository; merge after #110.

Problem

A warm restart through kexec needs the next kernel to see the pristine device tree from boot, the pstore region, the display state and the power domains that must not be cut while the next kernel starts.

Change

DT, OF, DRM, pmdomain and pstore patches retain the board-selected warm handoff state, so probe and shutdown keep what the next kernel needs: the pristine boot device tree, the pstore region, the display state and the Apple pmgr warm hold. The Orchard service file learns the retained state.

Testing

  • Hardware: iPad 5 Wi-Fi (J71t). Hands-on testing on 2026-11-11 with an integrated build of this series, made before the final failure-path fixes, covered warm restart.
  • 2026-11-12: 20+ warm restarts (kexec), several right after a glmark2 run, completed without a freeze; in the 9 warm restarts logged on the console that morning, the GPU came up warm every time.
  • Host: the Linux test suite passes at this branch's head, and the kernel and m1n1 patch series apply on apple-16k and apple-4k. At the top of the series the applied kernel tree is identical to the one in the built release image.
  • Other boards that share these drivers or compatibles have not been tested.

Dependencies

Depends on #110.

This branch is stacked on the PRs it depends on and carries their commits; the change of this PR is its last commit, "kernel: Retain the tethered warm boot state across kexec".

This update keeps the branch's earlier history: it merges the current base into the branch and adds the reworked change as a new commit on top.

🤖 Generated with Claude Code

kernel/configs/apple-16k/config:
CONFIG_DRM_APPLE_G5P=y
These options provide g5p and its Kconfig dependencies on both page sizes.

Assisted-by: LLM
kernel/configs/apple-16k/config:
CONFIG_APPLE_AOP_GYRO=m
CONFIG_APPLE_AOP_PRESSURE=m
These options provide aop and its Kconfig dependencies on both page sizes.

Assisted-by: LLM
kernel/configs/apple-16k/config:
# CONFIG_NVME_APPLE_ANS_EARLY_USB is not set
These options provide warm-storage and its Kconfig dependencies on both page sizes.

kernel/configs/apple-4k/config:
# CONFIG_NVME_APPLE_ANS_EARLY_USB is not set
These options provide warm-storage and its Kconfig dependencies on both page sizes.

Assisted-by: LLM
kernel/configs/apple-16k/config:
CONFIG_APPLE_AOP_GYRO=m
CONFIG_APPLE_AOP_PRESSURE=m
These options provide aop and its Kconfig dependencies on both page sizes.

Assisted-by: LLM
kernel/configs/apple-16k/config:
# CONFIG_NVME_APPLE_ANS_EARLY_USB is not set
These options provide warm-storage and its Kconfig dependencies on both page sizes.

kernel/configs/apple-4k/config:
# CONFIG_NVME_APPLE_ANS_EARLY_USB is not set
These options provide warm-storage and its Kconfig dependencies on both page sizes.

Assisted-by: LLM
Bring this branch onto current main. The merge keeps the other side's
tree; the next commit carries the reworked version of this branch's
change.
A7-A9 have no EL2 and boot without any PSCI firmware, so Linux on an
iPad 5 could not bring secondary CPUs down and up again, and a kexec had
nowhere to park them. CPU hotplug, kexec and a clean poweroff all need a
PSCI implementation that stays resident after m1n1 hands over.

Carry m1n1 patches that keep a small EL3 PSCI implementation resident:
CPU_ON/CPU_OFF with a firmware rendezvous (EL1 WFI/WFE trap to EL3),
SYSTEM_OFF, and a guarded SYSTEM_RESET that boots the default entry
again. The loader marks retained hardware in the device tree after a
PSCI re-entry. The resident PSCI is on by default on these SoCs; the
shipped boot framing keeps psci_reset=0, so SYSTEM_RESET stays off
unless a loader enables it. Adds boot/m1n1/psci-loader and its tests.

Assisted-by: LLM
Bring this branch onto current main and the series it depends on. The
merge keeps the other side's tree; the next commit carries the reworked
version of this branch's change.
The A9 AOP hosts the accelerometer, gyroscope, pressure and
ambient-light sensors. Its firmware needs boot arguments and per-device
calibration that m1n1 did not pass on S8003, and a reloaded AOP (after
kexec or sleep) lost its sensor firmware state, so the sensors did not
come back.

m1n1 passes the A9 AOP boot arguments and sensor calibration. The kernel
selects a certified AOP reload path through device-tree match data
(bindings, DT, mailbox, pmdomain, IIO and AOP driver patches), keeps the
AOP power domain and firmware state for that reload, and refuses a
suspend that would interrupt the firmware's boot. The J71t firmware
recipe gains the AOP pieces, the gyroscope and pressure drivers are
enabled, and J71t's accelerometer and gyroscope move from missing to
working, and its light sensor from untested to working.

Assisted-by: LLM
Bring this branch onto current main and the series it depends on. The
merge keeps the other side's tree; the next commit carries the reworked
version of this branch's change.
The TriStar charger subscribed to the PMU's RTC event 16 for source
identification. An acknowledgement there could take the RTC's wake
event, and the polled cover inputs had no driver enabled.

Give RTC event 16 to the RTC alone and keep the PMU and RTC event split
(DT, RTC and USB patches), so one consumer's acknowledgement cannot take
the other's wake event. Enable KEYBOARD_GPIO_POLLED for the polled cover
inputs.

Assisted-by: LLM
Bring this branch onto current main and the series it depends on. The
merge keeps the other side's tree; the next commit carries the reworked
version of this branch's change.
On J71t the NVMe controller (ANS) sits behind the H9P PCIe port, and
resetting that port loses the controller until a cold boot. A kexec
therefore has to hand over a stopped but powered ANS, with its DART
translations retained, or the next kernel loses its root filesystem. The
first version of this handoff panicked when a step failed, which with
panic=0 is an indefinite hang.

Keep the certified ANS kexec handoff: DT and bindings describe it, the
DART, H9P and NVMe drivers stop queues and translations in order and the
next kernel picks them up, and core/printk export what the modules need.
Every failure on the outgoing side now ends in a native cold reset
through apple_cold_reset() instead of a panic, with explicit returns
after it. The port is handed over powered, with PERST# asserted and the
link stopped, and the incoming kernel brings it up with the cold-boot
sequence (port power cycle, NVMe mode, port enable, then link training).
Retraining the powered port by PERST# alone, as iOS never does, left the
root port in Detect.Quiet and cost a timeout on every warm boot.

Assisted-by: LLM
Bring this branch onto current main and the series it depends on. The
merge keeps the other side's tree; the next commit carries the reworked
version of this branch's change.
After a kexec the next kernel found the S8000 GPIO controller with
interrupt modes armed by the previous kernel, the PIO SPI controller
with queued transfers and an asserted chip select, and the touch
controller still running. An orphaned GPIO interrupt fires forever and
touch did not come back.

Retire inherited GPIO interrupt modes before the chained parent
interrupts are enabled, drain and idle the S8000 PIO SPI controller on
shutdown and at probe, and stop the Apple Z2 touch controller before its
SPI parent shuts down.

Assisted-by: LLM
Bring this branch onto current main and the series it depends on. The
merge keeps the other side's tree; the next commit carries the reworked
version of this branch's change.
A Mac grants an iPad more than the standard USB current, but the charger
took the gadget's reported budget unchecked and the composite gadget
could draw the extra current while the bus was suspended.

Cap and log the USB host budget in the TriStar charger, draw no extra
Apple current while suspended, and let the initramfs and orchard USB
helpers opt J71t into the Mac current profile. Documented in
docs/bring-up/charging/j71t-mac-current.md, with tests.

Assisted-by: LLM
Bring this branch onto current main and the series it depends on. The
merge keeps the other side's tree; the next commit carries the reworked
version of this branch's change.
The USB serial number changed between installed boots and RAM sessions,
so the host saw a new device every boot and could not keep its SSH
known_hosts entry or serial console name.

Share one BOARD/hashed-ID serial format between installed boots and RAM
sessions (usb-identity), and get the per-boot SSH identity through the
existing ACM console. Documented in docs/device-protocol.md, with tests.

Assisted-by: LLM
Bring this branch onto current main and the series it depends on. The
merge keeps the other side's tree; the next commit carries the reworked
version of this branch's change.
A warm restart through kexec needs the next kernel to see the pristine
device tree from boot, the pstore region, the display state and the
power domains that must not be cut while the next kernel starts.

DT, OF, DRM, pmdomain and pstore patches retain the board-selected warm
handoff state, so probe and shutdown keep what the next kernel needs:
the pristine boot device tree, the pstore region, the display state and
the Apple pmgr warm hold. The Orchard service file learns the retained
state.

Assisted-by: LLM
@brkosebay brkosebay changed the title Warm Restart evidence, reset guard and pristine DT kernel: Retain the tethered warm boot state across kexec Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant