Progress Report: Linux 7.2 Previous
Previous
Linux 7.2 has been released! That was fast. Let’s dive in to yet another Asahi Linux progress report. We’ve got a lot of interesting developments for you today, so make yourself a cuppa and enjoy.
Think Different… again
The Apple Silicon platform’s power management infrastructure is complicated. Responsibilities are divided between multiple hardware blocks, including the SMC, PMGR, and PMP, all of which have featured before on this blog. While supporting these blocks is important for power use, one of the biggest obstacles to improving battery life has been the application cores themselves.
There are multiple ways to “sleep” a CPU core, and each one should be used in a specific context. The most basic way to sleep an ARM CPU core is to use a Wait For Interrupt (WFI) instruction. This tells the core to stop doing things until it is woken up by an interrupt from an interrupt source. While this does save power by virtue of stopping the core from executing any code, the core stays powered up and retains enough state for it to resume work extremely quickly. As such, WFI is typically only used for parking a core on a running system. Apple cores include a “deep” WFI mode, which shuts down more of the core at the expense of losing its state. Our downstream cpuidle driver operates by setting WFI up in this mode, saving the core’s state, then issuing a WFI loop.
Vendor-specific power management oddities like this are quite common. Thankfully for kernel maintainers, there is a standard way to deal with them: the Power State Coordination Interface. PSCI defines a standard iterface that allows an operating system to call into a defined set of CPU core power management functions implemented by system firmware, including to prepare them for sleep.
To avoid a proliferation of vendor-specific power management hacks inside the Linux kernel, the maintainers of the arm64 arch-specific code have mandated that all upstream hardware must use PSCI for power management. As such, we are not able to upstream our Apple-specific cpuidle driver. Why are we still using it then?
PSCI defines “conduits” through which calls to firmware are to be dispatched from the kernel. The two currently supported conduits in the kernel are the SMC (Secure Monitor Call) and HVC (Hypervisor Call) instructions, which are used to yield execution to a higher Exception Level. The Linux kernel expects to be running at EL2, which means that its PSCI calls must yield to firmware running in EL3. Except Apple’s cores do not implement EL3…
With the kernel already running in EL2 and no firmware running in EL3 to talk to, we are a bit stuck. Linux cannot issue an SMC or HVC instruction since there is no EL3 to yield execution to, which means we cannot make use of PSCI. Being able to properly power-manage the CPU cores is vital for battery life and efficiency, so the status quo simply will not do. One quick and dirty solution would be to have m1n1 load the kernel into EL1, and host a PSCI implementation in EL2. While this would theoretically work, it would also break a lot of architectural features, such as virtualisation. There must be something else we can do…
... continue reading