Stop job_done thread when going to suspend. Use kthread_park() instead
of kthread_stop() to avoid memory allocation and potential failure
on resume.

Use separate function as thread wake up condition. Use spin lock to assure
rx_msg_list is properly protected against concurrent access.

Reviewed-by: Karol Wachowski <[email protected]>
Signed-off-by: Stanislaw Gruszka <[email protected]>
---
 drivers/accel/ivpu/ivpu_drv.c |  2 ++
 drivers/accel/ivpu/ivpu_ipc.c | 17 +++++++++++++++--
 drivers/accel/ivpu/ivpu_job.c | 20 ++++++++++++++++----
 drivers/accel/ivpu/ivpu_job.h |  2 ++
 4 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c
index 064cabef41bb..60277ff6af69 100644
--- a/drivers/accel/ivpu/ivpu_drv.c
+++ b/drivers/accel/ivpu/ivpu_drv.c
@@ -378,6 +378,7 @@ int ivpu_boot(struct ivpu_device *vdev)
        enable_irq(vdev->irq);
        ivpu_hw_irq_enable(vdev);
        ivpu_ipc_enable(vdev);
+       ivpu_job_done_thread_enable(vdev);
        return 0;
 }
 
@@ -389,6 +390,7 @@ int ivpu_shutdown(struct ivpu_device *vdev)
        disable_irq(vdev->irq);
        ivpu_ipc_disable(vdev);
        ivpu_mmu_disable(vdev);
+       ivpu_job_done_thread_disable(vdev);
 
        ret = ivpu_hw_power_down(vdev);
        if (ret)
diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c
index d069d1e1f91d..270caef789bf 100644
--- a/drivers/accel/ivpu/ivpu_ipc.c
+++ b/drivers/accel/ivpu/ivpu_ipc.c
@@ -202,6 +202,20 @@ ivpu_ipc_send(struct ivpu_device *vdev, struct 
ivpu_ipc_consumer *cons, struct v
        return ret;
 }
 
+static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons)
+{
+       int ret = 0;
+
+       if (IS_KTHREAD())
+               ret |= (kthread_should_stop() || kthread_should_park());
+
+       spin_lock_irq(&cons->rx_msg_lock);
+       ret |= !list_empty(&cons->rx_msg_list);
+       spin_unlock_irq(&cons->rx_msg_lock);
+
+       return ret;
+}
+
 int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
                     struct ivpu_ipc_hdr *ipc_buf,
                     struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms)
@@ -211,8 +225,7 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct 
ivpu_ipc_consumer *cons,
        int wait_ret, ret = 0;
 
        wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq,
-                                                   (IS_KTHREAD() && 
kthread_should_stop()) ||
-                                                   
!list_empty(&cons->rx_msg_list),
+                                                   
ivpu_ipc_rx_need_wakeup(cons),
                                                    
msecs_to_jiffies(timeout_ms));
 
        if (IS_KTHREAD() && kthread_should_stop())
diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c
index 6e96c921547d..a245b2d44db7 100644
--- a/drivers/accel/ivpu/ivpu_job.c
+++ b/drivers/accel/ivpu/ivpu_job.c
@@ -590,6 +590,11 @@ static int ivpu_job_done_thread(void *arg)
                                ivpu_pm_schedule_recovery(vdev);
                        }
                }
+               if (kthread_should_park()) {
+                       ivpu_dbg(vdev, JOB, "Parked %s\n", __func__);
+                       kthread_parkme();
+                       ivpu_dbg(vdev, JOB, "Unparked %s\n", __func__);
+               }
        }
 
        ivpu_ipc_consumer_del(vdev, &cons);
@@ -610,9 +615,6 @@ int ivpu_job_done_thread_init(struct ivpu_device *vdev)
                return -EIO;
        }
 
-       get_task_struct(thread);
-       wake_up_process(thread);
-
        vdev->job_done_thread = thread;
 
        return 0;
@@ -620,6 +622,16 @@ int ivpu_job_done_thread_init(struct ivpu_device *vdev)
 
 void ivpu_job_done_thread_fini(struct ivpu_device *vdev)
 {
+       kthread_unpark(vdev->job_done_thread);
        kthread_stop(vdev->job_done_thread);
-       put_task_struct(vdev->job_done_thread);
+}
+
+void ivpu_job_done_thread_disable(struct ivpu_device *vdev)
+{
+       kthread_park(vdev->job_done_thread);
+}
+
+void ivpu_job_done_thread_enable(struct ivpu_device *vdev)
+{
+       kthread_unpark(vdev->job_done_thread);
 }
diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h
index aa1f0b9479b0..a8e914e5affc 100644
--- a/drivers/accel/ivpu/ivpu_job.h
+++ b/drivers/accel/ivpu/ivpu_job.h
@@ -61,6 +61,8 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev);
 
 int ivpu_job_done_thread_init(struct ivpu_device *vdev);
 void ivpu_job_done_thread_fini(struct ivpu_device *vdev);
+void ivpu_job_done_thread_disable(struct ivpu_device *vdev);
+void ivpu_job_done_thread_enable(struct ivpu_device *vdev);
 
 void ivpu_jobs_abort_all(struct ivpu_device *vdev);
 
-- 
2.25.1

Reply via email to