i2c-hid on a stack of its own; PSOGM powers off after three minutes
The touchpad driver crashed the ASUS TUF A15 at boot. Its thread runs the firmware's AML -- _DSM, _PS0, _CRS -- through uACPI at -O0, on an 8 KB kernel stack, and kernel stacks are one array: running off the end lands in the next thread's stack, and the machine dies a moment later in some other code. The thread now runs on a 64 KB stack of its own, through SCFF's call_on_stack(). And a crashed laptop sat with its fans up until somebody held the power button, since the other processors keep running. On an ordinary boot the PSOGM now says it will power off, and does, after three minutes: SLP_TYP from \_S5, read at boot, written straight to PM1 control with no AML, which could sleep or wait on a lock a dead processor holds. A verbose boot keeps the screen up for ever. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
c79b1d6d6d
commit
b15fb2fdaa
4 changed files with 85 additions and 3 deletions
|
|
@ -32,9 +32,14 @@
|
|||
#include <uacpi/resources.h>
|
||||
#include <uacpi/event.h>
|
||||
#include <uacpi/sleep.h>
|
||||
#include <uacpi/registers.h>
|
||||
|
||||
static int ready;
|
||||
|
||||
// \_S5's SLP_TYP values, read once at boot for acpi_poweroff_now(): -1 until
|
||||
// then, or if the firmware has none.
|
||||
static int s5_typ_a = -1, s5_typ_b = -1;
|
||||
|
||||
static uacpi_interrupt_ret power_button(uacpi_handle ctx);
|
||||
|
||||
void
|
||||
|
|
@ -74,6 +79,23 @@ acpi_aml_init(void)
|
|||
kinfo("acpi: no fixed power button: %s\n", uacpi_status_to_string(st));
|
||||
|
||||
uacpi_finalize_gpe_initialization();
|
||||
|
||||
{
|
||||
uacpi_object *o = 0;
|
||||
uacpi_object_array p;
|
||||
uacpi_u64 ta, tb;
|
||||
if (uacpi_eval_package(0, "\\_S5", 0, &o) == UACPI_STATUS_OK) {
|
||||
if (uacpi_object_get_package(o, &p) == UACPI_STATUS_OK && p.count >= 1 &&
|
||||
uacpi_object_get_integer(p.objects[0], &ta) == UACPI_STATUS_OK) {
|
||||
tb = ta;
|
||||
if (p.count >= 2)
|
||||
uacpi_object_get_integer(p.objects[1], &tb);
|
||||
s5_typ_a = ta & 7;
|
||||
s5_typ_b = tb & 7;
|
||||
}
|
||||
uacpi_object_unref(o);
|
||||
}
|
||||
}
|
||||
ready = 1;
|
||||
kinfo("acpi: namespace loaded\n");
|
||||
}
|
||||
|
|
@ -118,6 +140,28 @@ acpi_poweroff(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Power off from a dead kernel: the PSOGM, after it has been up long enough to
|
||||
// be read. acpi_poweroff() runs _PTS and other AML, which can sleep and take
|
||||
// locks that another processor died holding, so it is no use here. This is
|
||||
// only the last step of it -- SLP_TYP from \_S5, then SLP_EN, written straight
|
||||
// to the PM1 control registers. The firmware's preparations are skipped; a
|
||||
// crashed machine has nothing to save. Returns only if the machine is still on.
|
||||
void
|
||||
acpi_poweroff_now(void)
|
||||
{
|
||||
uacpi_u64 cnt = 0, a, b;
|
||||
|
||||
if (!ready || s5_typ_a < 0)
|
||||
return;
|
||||
uacpi_read_register(UACPI_REGISTER_PM1_CNT, &cnt);
|
||||
cnt &= ~(uacpi_u64)((7 << 10) | (1 << 13));
|
||||
a = cnt | ((uacpi_u64)s5_typ_a << 10);
|
||||
b = cnt | ((uacpi_u64)s5_typ_b << 10);
|
||||
uacpi_write_registers(UACPI_REGISTER_PM1_CNT, a, b);
|
||||
uacpi_write_registers(UACPI_REGISTER_PM1_CNT, a | (1 << 13), b | (1 << 13));
|
||||
microdelay(100000);
|
||||
}
|
||||
|
||||
int
|
||||
acpi_reboot(void)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue