summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSultan Alsawaf <sultan@kerneltoast.com>2023-10-15 21:48:24 -0700
committerWill McVicker <willmcvicker@google.com>2024-04-16 11:58:49 -0700
commit3e28b92d793d889f2b95feafcf7fc5e32adefd8e (patch)
treeff99da9533b7e283213ea167679e2fcd8df34191
parentf91a72bd297105ad9a18c7e291d0f50b17be8294 (diff)
downloadraviole-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.c37
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;