drm/msm: Fix devfreq NULL pointer dereference on a3xx
authorStephan Gerhold <stephan@gerhold.net>
Mon, 13 Sep 2021 16:45:56 +0000 (18:45 +0200)
committerRob Clark <robdclark@chromium.org>
Tue, 12 Oct 2021 00:30:53 +0000 (17:30 -0700)
There is no devfreq on a3xx at the moment since gpu_busy is not
implemented. This means that msm_devfreq_init() will return early
and the entire devfreq setup is skipped.

However, msm_devfreq_active() and msm_devfreq_idle() are still called
unconditionally later, causing a NULL pointer dereference:

  Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010
  Internal error: Oops: 96000004 [#1] PREEMPT SMP
  CPU: 0 PID: 133 Comm: ring0 Not tainted 5.15.0-rc1 #4
  Hardware name: Longcheer L8150 (DT)
  pc : mutex_lock_io+0x2bc/0x2f0
  lr : msm_devfreq_active+0x3c/0xe0 [msm]
  Call trace:
   mutex_lock_io+0x2bc/0x2f0
   msm_gpu_submit+0x164/0x180 [msm]
   msm_job_run+0x54/0xe0 [msm]
   drm_sched_main+0x2b0/0x4a0 [gpu_sched]
   kthread+0x154/0x160
   ret_from_fork+0x10/0x20

Fix this by adding a check in msm_devfreq_active/idle() which ensures
that devfreq was actually initialized earlier.

Fixes: 9bc95570175a ("drm/msm: Devfreq tuning")
Reported-by: Nikita Travkin <nikita@trvn.ru>
Tested-by: Nikita Travkin <nikita@trvn.ru>
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Link: https://lore.kernel.org/r/20210913164556.16284-1-stephan@gerhold.net
Signed-off-by: Rob Clark <robdclark@chromium.org>
drivers/gpu/drm/msm/msm_gpu_devfreq.c

index 0a1ee20..84e98c0 100644 (file)
@@ -151,6 +151,9 @@ void msm_devfreq_active(struct msm_gpu *gpu)
        unsigned int idle_time;
        unsigned long target_freq = df->idle_freq;
 
+       if (!df->devfreq)
+               return;
+
        /*
         * Hold devfreq lock to synchronize with get_dev_status()/
         * target() callbacks
@@ -186,6 +189,9 @@ void msm_devfreq_idle(struct msm_gpu *gpu)
        struct msm_gpu_devfreq *df = &gpu->devfreq;
        unsigned long idle_freq, target_freq = 0;
 
+       if (!df->devfreq)
+               return;
+
        /*
         * Hold devfreq lock to synchronize with get_dev_status()/
         * target() callbacks