⬢ DragonFlyBSD Kernel Audit
DF-3654 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1200,13 +1200,20 @@
 	struct dc_link *dc_link = aconnector->dc_link;
 	bool is_mst_root_connector = aconnector->mst_mgr.mst_state;
 	enum dc_connection_type new_connection_type = dc_connection_none;
+	bool hpd_lock_taken;
 
 	/*
 	 * TODO:Temporary add mutex to protect hpd interrupt not have a gpio
 	 * conflict, after implement i2c helper, this mutex should be
 	 * retired.
+	 *
+	 * Cache the locking decision: dc_link_detect() below can change
+	 * dc_link->type while the handler runs, so re-evaluating the
+	 * condition at unlock time strands the lock (single -> mst_branch)
+	 * or releases a lock we never took (mst_branch -> single).
 	 */
-	if (dc_link->type != dc_connection_mst_branch)
+	hpd_lock_taken = (dc_link->type != dc_connection_mst_branch);
+	if (hpd_lock_taken)
 		mutex_lock(&aconnector->hpd_lock);
 
 	if (dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL) &&
@@ -1248,7 +1255,7 @@
 	    (dc_link->type == dc_connection_mst_branch))
 		dm_handle_hpd_rx_irq(aconnector);
 
-	if (dc_link->type != dc_connection_mst_branch) {
+	if (hpd_lock_taken) {
 		drm_dp_cec_irq(&aconnector->dm_dp_aux.aux);
 		mutex_unlock(&aconnector->hpd_lock);
 	}