Alright, now that I’m in front of a computer.
A little backstory.
The first three iterations of the Framework Laptop use a Microchip MEC-series embedded controller. The MEC has a communication protocol that requires a low- or no-contention bus. To talk to the EC, ACPI (which contains code to check the battery charge levels, report that the OS has finished waking from sleep, etc.) and the kernel need to:
- write an address to an EC register
- read or write data from a different EC register
- repeat [2] until complete
Since ACPI and the kernel could both be competing for access to the EC, they can corrupt eachother’s in-flight requests (by the kernel writing to the address register while ACPI is reading the data registers, etc.)
I originally lit up support for Linux to talk to the Framework EC (back in kernel 5.18 or so.) I was unaware of this bus contention issue when I did.
It happens a lot during wake from sleep, where ACPI is reporting to the EC that it’s back in the OS. The kernel is trying to read EC console logs or something at the same time. The EC never learns that the OS is running, and never re-enables the high-level keyboard functions.
Anyway. There’s an ACPI mutex that the kernel can grab to say “hey stop talking to the EC for a sec”.
One of the community members here submitted this patch series to make it do that. Now they can coexist.
I believe this only rolled out with kernel 6.11 and above. I am not aware that it has been backported to any of the LTS/stable branches, nor am I sure that Ubuntu has or has not backported it themselves.
This isn’t an issue on AMD 7040-series boards and newer because they moved to a Nuvoton EC with a different (and simpler) communication protocol that is not subject to races like this.
Anyway: if you need a quick fix and don’t need to talk to the EC from userspace, put the cros_ec_lpcs module on your module disallow list. You can also try a more targeted fix, disallowing cros_ec_debugfs (which accounts for a great many of the early-wake reads originated by the kernel.)