Repository navigation
Experiment: withdraw pmp-dispext0's PMP request in sleep (module, under the driver's lock) - #3
Conversation
…leep aurora #274 cut M3 Pro s2idle from ~2.6 W to 1.35 W mostly by withdrawing external display PMP requests in suspend_noirq. On T600x, pmp-disp0 and pmp-dispext0 are apple,always-on, and a read of the PMP report (target = actual = 0x7000) shows both asserted with nothing attached. - pmp-request.c: read, withdraw or assert one request on T600x through /dev/mem, with the pmp-report driver's register sequence (aligned 64-bit ldr/str only) and a refusal unless the live device tree is this block. - sleep-drain-log: with /etc/sleep-drain/pmp-release (sleep-drain-pmp), the listed requests are withdrawn as the last pre step and asserted again as the first post step; only ones this hook withdrew go back. Logged as pmp_release= and pmp_back=. - Snapshots log charge_counter (mA·s on this machine, not µAh) and voltage; the post line and report gain avg_mw_cc, accurate for short sleeps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A request left withdrawn after resume would starve that display processor, so the post step retries for up to a second. "Already asserted" on the first try means something re-asserted it during the sleep (logged <id>:early); after an unacknowledged write it is that write landing (ok). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The userspace PMP mask update is not serialized with the kernel driver's updates; resolve whether the writes can overlap before enabling this experiment.
Reviewed changes This review covers the PMP request helper and sleep-hook release/restore flow, coulomb-counter power measurement and reporting, plus installer and research-documentation updates.
- PMP request experiment Adds a device-tree-guarded
/dev/memhelper and optional pre-suspend withdrawal/post-resume restoration of configured request bits. - Power measurement Adds coulomb-counter and voltage snapshots,
avg_mw_cccalculations, and the corresponding report column. - Installation and documentation Adds the PMP toggle command and updates install, uninstall, and research instructions.
Important
This run used your free trial credits ($9.78 of $10 left) on GPT Luna, a fast, lightweight model. Connect a provider → to run the model you choose.
gpt-6-luna (free trial credits) | 𝕏
…W window Review on #3: the kernel driver updates the same target mask under a spinlock userspace can't take, so an overlapping update could be lost. - Refuse to write while target != actual (exit 4): the driver may be mid-update. The hook logs <id>:busy and records nothing; the restore retries. - Read actual, read target and write the new mask back to back, at SCHED_FIFO priority, so no normal task preempts the window. - After the acknowledgement, re-read the mask; if it changed elsewhere, exit 5 (logged <id>:raced) so a collision is visible. The residual window is a few instructions; the real fix is patch 6 in the driver, under its lock. Also: the report's no-post and pending rows gain the mW(cc) placeholder so they stay aligned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The updated PMP collision check can still silently overwrite a concurrent kernel request and let its power-domain transition time out.
Reviewed changes This review covers d5399ef, which added settling-state checks, a higher-priority read-modify-write window, post-acknowledgement mask verification, and aligned the pending/no-post report rows.
- Narrowed the PMP write window Refused writes while target and actual masks differ, raised the helper to
SCHED_FIFOaround the read-modify-write, and added a post-write mask check. - Aligned exceptional report rows Added the missing
mW(cc)placeholder to pending and no-post rows.
Important
This run used your free trial credits ($9.73 of $10 left) on GPT Luna, a fast, lightweight model. Connect a provider → to run the model you choose.
gpt-6-luna (free trial credits) | 𝕏
Review on #3: a userspace read-modify-write of the PMP target mask can overwrite a concurrent pmp-report update undetectably (the driver's write can land between our read and our write), and userspace can't take the driver's spinlock. So the write moves into the kernel: - pmp-sleep-release/: an out-of-tree module that withdraws the requests in its ids in suspend_noirq (only if acknowledged) and asserts them again in resume_noirq, with the driver's register sequence under rep->lock, which is what aurora #274's patch 6 does. pmp-report is built in, so the module reaches the report through its device's drvdata. The leading struct members come from the running kernel's BTF, and load refuses unless rep->dev, the T600x offsets and every id (an enabled entry in the live DT) check out. Read-only parameters report what each sleep withdrew and any unacknowledged writes. - sleep-drain-pmp loads and unloads the module (nothing loads it at boot); install.sh builds it for the running kernel, non-fatally. - The hook no longer writes: it logs the module's ids before the sleep and pmp_released/pmp_failures after. - pmp-request is read-only: no write path or MMIO store left. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes This review covers 14fc957, which replaces userspace PMP writes with a kernel module that withdraws configured requests under the report driver's lock during system sleep and restores them on resume.
- Moved PMP writes into noirq callbacks Added
pmp_sleep_release, validated the live report device, register offsets, and enabled DT request IDs, and reducedpmp-requestto read-only access. - Updated experiment control and logging Added explicit module load/unload controls, logged the configured IDs and module outcome through the sleep hook, and updated installation, uninstall, and research documentation. The PR description reports that the module has not yet been loaded or tested during sleep.
Important
This run used your free trial credits ($9.71 of $10 left) on GPT Luna, a fast, lightweight model. Connect a provider → to run the model you choose.
gpt-6-luna (free trial credits) | 𝕏

Why
omacom/linux-aurora #274 cut M3 Pro s2idle from ~2.6 W to 1.35 W, mostly by withdrawing the external display processors' PMP report requests during sleep (patch 6, for entries marked
apple,release-for-sleep). This M1 Pro has the same PMP report block, and its device tree markspmp-disp0andpmp-dispext0apple,always-on. A read-only check (target = actual =0x7000) shows both asserted and acknowledged with nothing attached, so they stay up all night.This is a pre-screen before building a whole kernel: does withdrawing
pmp-dispext0's request during sleep save real power here?What
pmp-sleep-release/: an out-of-tree module that does what patch 6 does.suspend_noirq, after every device's suspend callback, and asserts it again inresume_noirq, before any device resumes.rep->lock.rep->dev, the T600x offsets and every id (an enabled entry in the live device tree) check out. vermagic pins it to this kernel.sleep-drain-pmp release 0xd/keeploads or unloads it. Nothing loads it at boot, so a reboot always ends the experiment.install.shbuilds it for the running kernel (non-fatal if the headers are missing).sleep-drain-logwrites nothing new. It logs the module'sidsbefore the sleep andpmp_released/pmp_failuresafter.cc=(the SMC coulomb counter, which counts mA·s here, not µAh) anduv=. The post line andsleep-drain-reportgainavg_mw_cc, which is accurate for 10-minute sleeps whereenergy_nowisn't.pmp-request.c: a read-only view of the PMP report masks (no write path).An earlier revision wrote the mask from userspace in the sleep hook. Review showed a concurrent driver update could be silently overwritten, which userspace can't prevent, so the write moved into the kernel.
Tested so far
linux-aurora-headers7.2.11-9 with clang (LLVM=1). The kernel itself was built with clang 18; this is clang 23, the usual warning.pmp-requestread-only as root:status=0x1 target=0x7000 actual=0x7000. The binary contains no MMIO store.avg_mw_ccon a real 61 s awake sample: 12,292 mW vsenergy_now's 12,110. Lines withoutccprint-.bash -non every script.Not run yet: loading the module, or a sleep with it. That happens after review and merge.
After merging
pkexec bash install.sh, thensleep-drain-pmp release 0xdfor the "on" runs andsleep-drain-pmp keepfor the "off" runs.🤖 Generated with Claude Code