Patch "drm/msm/dp: stop event kernel thread when DP unbind" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    drm/msm/dp: stop event kernel thread when DP unbind

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     drm-msm-dp-stop-event-kernel-thread-when-dp-unbind.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 474e45398e8bd745bd12cc455aaafe14c30313cb
Author: Kuogee Hsieh <quic_khsieh@xxxxxxxxxxx>
Date:   Mon Apr 18 14:56:28 2022 -0700

    drm/msm/dp: stop event kernel thread when DP unbind
    
    [ Upstream commit 570d3e5d28db7a94557fa179167a9fb8642fb8a1 ]
    
    Current DP driver implementation, event thread is kept running
    after DP display is unbind. This patch fix this problem by disabling
    DP irq and stop event thread to exit gracefully at dp_display_unbind().
    
    Changes in v2:
    -- start event thread at dp_display_bind()
    
    Changes in v3:
    -- disable all HDP interrupts at unbind
    -- replace dp_hpd_event_setup() with dp_hpd_event_thread_start()
    -- replace dp_hpd_event_stop() with dp_hpd_event_thread_stop()
    -- move init_waitqueue_head(&dp->event_q) to probe()
    -- move spin_lock_init(&dp->event_lock) to probe()
    
    Changes in v4:
    -- relocate both dp_display_bind() and dp_display_unbind() to bottom of file
    
    Changes in v5:
    -- cancel relocation of both dp_display_bind() and dp_display_unbind()
    
    Changes in v6:
    -- move empty event q to dp_event_thread_start()
    
    Changes in v7:
    -- call ktheread_stop() directly instead of dp_hpd_event_thread_stop() function
    
    Changes in v8:
    -- return error immediately if audio registration failed.
    
    Changes in v9:
    -- return error immediately if event thread create failed.
    
    Changes in v10:
    -- delete extra  DRM_ERROR("failed to create DP event thread\n");
    
    Fixes: 8ede2ecc3e5e ("drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets")
    Signed-off-by: Kuogee Hsieh <quic_khsieh@xxxxxxxxxxx>
    Reported-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx>
    Reviewed-by: Stephen Boyd <swboyd@xxxxxxxxxxxx>
    Patchwork: https://patchwork.freedesktop.org/patch/482399/
    Link: https://lore.kernel.org/r/1650318988-17580-1-git-send-email-quic_khsieh@xxxxxxxxxxx
    [DB: fixed Fixes tag]
    Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index d5198b435638..5648c1eb5fa8 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -110,6 +110,7 @@ struct dp_display_private {
 	u32 hpd_state;
 	u32 event_pndx;
 	u32 event_gndx;
+	struct task_struct *ev_tsk;
 	struct dp_event event_list[DP_EVENT_Q_MAX];
 	spinlock_t event_lock;
 
@@ -193,6 +194,8 @@ void dp_display_signal_audio_complete(struct msm_dp *dp_display)
 	complete_all(&dp->audio_comp);
 }
 
+static int dp_hpd_event_thread_start(struct dp_display_private *dp_priv);
+
 static int dp_display_bind(struct device *dev, struct device *master,
 			   void *data)
 {
@@ -230,9 +233,18 @@ static int dp_display_bind(struct device *dev, struct device *master,
 	}
 
 	rc = dp_register_audio_driver(dev, dp->audio);
-	if (rc)
+	if (rc) {
 		DRM_ERROR("Audio registration Dp failed\n");
+		goto end;
+	}
 
+	rc = dp_hpd_event_thread_start(dp);
+	if (rc) {
+		DRM_ERROR("Event thread create failed\n");
+		goto end;
+	}
+
+	return 0;
 end:
 	return rc;
 }
@@ -247,6 +259,11 @@ static void dp_display_unbind(struct device *dev, struct device *master,
 	dp = container_of(g_dp_display,
 			struct dp_display_private, dp_display);
 
+	/* disable all HPD interrupts */
+	dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false);
+
+	kthread_stop(dp->ev_tsk);
+
 	dp_power_client_deinit(dp->power);
 	dp_aux_unregister(dp->aux);
 	priv->dp = NULL;
@@ -1052,7 +1069,7 @@ static int hpd_event_thread(void *data)
 
 	dp_priv = (struct dp_display_private *)data;
 
-	while (1) {
+	while (!kthread_should_stop()) {
 		if (timeout_mode) {
 			wait_event_timeout(dp_priv->event_q,
 				(dp_priv->event_pndx == dp_priv->event_gndx),
@@ -1130,12 +1147,17 @@ static int hpd_event_thread(void *data)
 	return 0;
 }
 
-static void dp_hpd_event_setup(struct dp_display_private *dp_priv)
+static int dp_hpd_event_thread_start(struct dp_display_private *dp_priv)
 {
-	init_waitqueue_head(&dp_priv->event_q);
-	spin_lock_init(&dp_priv->event_lock);
+	/* set event q to empty */
+	dp_priv->event_gndx = 0;
+	dp_priv->event_pndx = 0;
 
-	kthread_run(hpd_event_thread, dp_priv, "dp_hpd_handler");
+	dp_priv->ev_tsk = kthread_run(hpd_event_thread, dp_priv, "dp_hpd_handler");
+	if (IS_ERR(dp_priv->ev_tsk))
+		return PTR_ERR(dp_priv->ev_tsk);
+
+	return 0;
 }
 
 static irqreturn_t dp_display_irq_handler(int irq, void *dev_id)
@@ -1236,8 +1258,11 @@ static int dp_display_probe(struct platform_device *pdev)
 		return -EPROBE_DEFER;
 	}
 
+	/* setup event q */
 	mutex_init(&dp->event_mutex);
 	g_dp_display = &dp->dp_display;
+	init_waitqueue_head(&dp->event_q);
+	spin_lock_init(&dp->event_lock);
 
 	/* Store DP audio handle inside DP display */
 	g_dp_display->dp_audio = dp->audio;
@@ -1414,8 +1439,6 @@ void msm_dp_irq_postinstall(struct msm_dp *dp_display)
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
-	dp_hpd_event_setup(dp);
-
 	dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100);
 }
 



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux