DF-3654 / harness.c
/* * DF-3654 harness — lock-pairing decision table for handle_hpd_rx_irq() * (sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1195-1255). * * amdgpu_dm.c:1209-1210 if (dc_link->type != dc_connection_mst_branch) * mutex_lock(&aconnector->hpd_lock); [ENTRY] * amdgpu_dm.c:1232 dc_link_detect(dc_link, DETECT_REASON_HPDRX); * ^ can flip link->type: * single -> mst_branch (dc_link.c:528) * mst_branch -> single (dc_link.c:569, * dm_helpers_dp_mst_start_top_mgr failure) * amdgpu_dm.c:1251-1254 if (dc_link->type != dc_connection_mst_branch) { * drm_dp_cec_irq(...); * mutex_unlock(&aconnector->hpd_lock); [EXIT] * } * * The lock/unlock decisions are made against DIFFERENT reads of the mutable * link->type. This harness enumerates the entry x exit matrix exactly as the * kernel computes it and reports which combinations strand the lock (permanent * hang of HPD work, dm_suspend/dm_resume, amdgpu_dm_irq_fini's flush_work) * or drop a lock that was never taken (lockmgr LK_RELEASE corruption/panic). */ #include <stdio.h> enum link_type { TYPE_SINGLE = 0, TYPE_MST }; static const char *tname[] = { "single", "mst_branch" }; int main(void) { int entry, exit_type, bad = 0; printf("handle_hpd_rx_irq() hpd_lock pairing matrix " "(amdgpu_dm.c:1209 x 1251):\n"); for (entry = 0; entry <= 1; entry++) { for (exit_type = 0; exit_type <= 1; exit_type++) { int locked = (entry != TYPE_MST); /* amdgpu_dm.c:1209 */ int unlocked = (exit_type != TYPE_MST); /* amdgpu_dm.c:1251 */ printf(" entry=%-11s exit=%-11s lock=%d unlock=%d : ", tname[entry], tname[exit_type], locked, unlocked); if (locked && !unlocked) { printf("STRANDED LOCK\n"); bad++; } else if (!locked && unlocked) { printf("UNLOCK WITHOUT HOLD\n"); bad++; } else { printf("balanced\n"); } } } printf("\n%d unbalanced combinations; both flips occur INSIDE the handler:\n", bad); printf(" single -> mst_branch : dc_link.c:528 (dc_link_detect discovers branch)\n"); printf(" mst_branch-> single : dc_link.c:569 (start_top_mgr fails, sink-controlled)\n"); printf("\nConsequences of a stranded hpd_lock (entry=single, exit=mst_branch):\n"); printf(" - handle_hpd_irq() (amdgpu_dm.c:1083) blocks forever in its work item\n"); printf(" - dm_resume()/dm_suspend() block forever (amdgpu_dm.c:864,878)\n"); printf(" - amdgpu_dm_irq_fini() flush_work() hangs (amdgpu_dm_irq.c:334)\n"); return bad == 0; } |