diff options
author | Sultan Alsawaf <sultan@kerneltoast.com> | 2023-10-15 21:48:24 -0700 |
---|---|---|
committer | Will McVicker <willmcvicker@google.com> | 2024-04-16 11:58:49 -0700 |
commit | 3e28b92d793d889f2b95feafcf7fc5e32adefd8e (patch) | |
tree | ff99da9533b7e283213ea167679e2fcd8df34191 | |
parent | f91a72bd297105ad9a18c7e291d0f50b17be8294 (diff) | |
download | raviole-device-3e28b92d793d889f2b95feafcf7fc5e32adefd8e.tar.gz |
eh: Make the compression thread freezable to fix suspend death
Since kthreads aren't freezable by default, it's possible for the
compression thread to run after the system is frozen and thus after EH has
been suspended. This is a fatal error, because EH hardware can neither
finish its work nor be interacted with after it is put to sleep.
Symptoms of the compression thread running after EH is suspended range from
complete system hangs due to the compression thread waiting for EH to
finish a compression that got lost during suspend, to kernel panics and
non-secure watchdog bites when the compression thread attempts to read EH
registers after EH is powered off.
As such, the compression thread must not run after EH is suspended. Fix
this by making the compression thread freezable, so that it must enter the
refrigerator before EH can suspend. Participating in system-wide freezing
also guarantees the compression thread won't be unfrozen until after EH is
resumed.
Bug: 312269139
Change-Id: I27658e8885d4e0e03c4e59d1b5d1cb020355094c
Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
Signed-off-by: Minchan Kim <minchan@google.com>
Signed-off-by: Will McVicker <willmcvicker@google.com>
-rw-r--r-- | drivers/soc/google/eh/eh_main.c | 37 |
1 files changed, 20 insertions, 17 deletions
diff --git a/drivers/soc/google/eh/eh_main.c b/drivers/soc/google/eh/eh_main.c index a1e423a7b..f853a551a 100644 --- a/drivers/soc/google/eh/eh_main.c +++ b/drivers/soc/google/eh/eh_main.c @@ -668,11 +668,18 @@ static void eh_abort_incomplete_descriptors(struct eh_device *eh_dev) } } +static bool ready_to_run(struct eh_device *eh_dev, bool *slept) +{ + if (atomic_read(&eh_dev->nr_request) || !sw_fifo_empty(&eh_dev->sw_fifo)) + return true; + + *slept = true; + return false; +} + static int eh_comp_thread(void *data) { struct eh_device *eh_dev = data; - DEFINE_WAIT(wait); - int nr_processed = 0; struct sched_attr attr = { .sched_policy = SCHED_NORMAL, .sched_nice = -10, @@ -680,24 +687,20 @@ static int eh_comp_thread(void *data) WARN_ON_ONCE(sched_setattr_nocheck(current, &attr) != 0); current->flags |= PF_MEMALLOC; + set_freezable(); while (!kthread_should_stop()) { int ret; + bool slept = false; - prepare_to_wait(&eh_dev->comp_wq, &wait, TASK_IDLE); - if (atomic_read(&eh_dev->nr_request) == 0 && - sw_fifo_empty(&eh_dev->sw_fifo)) { - eh_dev->nr_compressed += nr_processed; - schedule(); - nr_processed = 0; - /* - * The condition check above is racy so the schedule - * couldn't schedule out the process but it should be - * rare and the stat doesn't need to be precise. - */ + wait_event_freezable(eh_dev->comp_wq, ready_to_run(eh_dev, &slept)); + /* + * The condition check above is racy so the schedule + * couldn't schedule out the process but it should be + * rare and the stat doesn't need to be precise. + */ + if (slept) eh_dev->nr_run++; - } - finish_wait(&eh_dev->comp_wq, &wait); ret = eh_process_compress(eh_dev); if (unlikely(ret < 0)) { @@ -725,11 +728,11 @@ static int eh_comp_thread(void *data) */ if (ret == 0) usleep_range(5, 10); + else + eh_dev->nr_compressed += ret; if (!fifo_full(eh_dev)) flush_sw_fifo(eh_dev); - - nr_processed += ret; } return 0; |