Skip to content

Commit c210b75

Browse files
Aurabindo Pillaialexdeucher
authored andcommitted
drm/amd/display: fix dmub access race condition
Accessing DC from amdgpu_dm is usually preceded by acquisition of dc_lock mutex. Most of the DC API that DM calls are under a DC lock. However, there are a few that are not. Some DC API called from interrupt context end up sending DMUB commands via a DC API, while other threads were using DMUB. This was apparent from a race between calls for setting idle optimization enable/disable and the DC API to set vmin/vmax. Offload the call to dc_stream_adjust_vmin_vmax() to a thread instead of directly calling them from the interrupt handler such that it waits for dc_lock. Reviewed-by: Nicholas Kazlauskas <[email protected]> Signed-off-by: Aurabindo Pillai <[email protected]> Signed-off-by: Roman Li <[email protected]> Tested-by: Daniel Wheeler <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent fd20627 commit c210b75

File tree

2 files changed

+63
-6
lines changed

2 files changed

+63
-6
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,50 @@ static void dm_pflip_high_irq(void *interrupt_params)
530530
amdgpu_crtc->crtc_id, amdgpu_crtc, vrr_active, (int)!e);
531531
}
532532

533+
static void dm_handle_vmin_vmax_update(struct work_struct *offload_work)
534+
{
535+
struct vupdate_offload_work *work = container_of(offload_work, struct vupdate_offload_work, work);
536+
struct amdgpu_device *adev = work->adev;
537+
struct dc_stream_state *stream = work->stream;
538+
struct dc_crtc_timing_adjust *adjust = work->adjust;
539+
540+
mutex_lock(&adev->dm.dc_lock);
541+
dc_stream_adjust_vmin_vmax(adev->dm.dc, stream, adjust);
542+
mutex_unlock(&adev->dm.dc_lock);
543+
544+
dc_stream_release(stream);
545+
kfree(work->adjust);
546+
kfree(work);
547+
}
548+
549+
static void schedule_dc_vmin_vmax(struct amdgpu_device *adev,
550+
struct dc_stream_state *stream,
551+
struct dc_crtc_timing_adjust *adjust)
552+
{
553+
struct vupdate_offload_work *offload_work = kzalloc(sizeof(*offload_work), GFP_KERNEL);
554+
if (!offload_work) {
555+
drm_dbg_driver(adev_to_drm(adev), "Failed to allocate vupdate_offload_work\n");
556+
return;
557+
}
558+
559+
struct dc_crtc_timing_adjust *adjust_copy = kzalloc(sizeof(*adjust_copy), GFP_KERNEL);
560+
if (!adjust_copy) {
561+
drm_dbg_driver(adev_to_drm(adev), "Failed to allocate adjust_copy\n");
562+
kfree(offload_work);
563+
return;
564+
}
565+
566+
dc_stream_retain(stream);
567+
memcpy(adjust_copy, adjust, sizeof(*adjust_copy));
568+
569+
INIT_WORK(&offload_work->work, dm_handle_vmin_vmax_update);
570+
offload_work->adev = adev;
571+
offload_work->stream = stream;
572+
offload_work->adjust = adjust_copy;
573+
574+
queue_work(system_wq, &offload_work->work);
575+
}
576+
533577
static void dm_vupdate_high_irq(void *interrupt_params)
534578
{
535579
struct common_irq_params *irq_params = interrupt_params;
@@ -579,10 +623,9 @@ static void dm_vupdate_high_irq(void *interrupt_params)
579623
acrtc->dm_irq_params.stream,
580624
&acrtc->dm_irq_params.vrr_params);
581625

582-
dc_stream_adjust_vmin_vmax(
583-
adev->dm.dc,
584-
acrtc->dm_irq_params.stream,
585-
&acrtc->dm_irq_params.vrr_params.adjust);
626+
schedule_dc_vmin_vmax(adev,
627+
acrtc->dm_irq_params.stream,
628+
&acrtc->dm_irq_params.vrr_params.adjust);
586629
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
587630
}
588631
}
@@ -672,8 +715,8 @@ static void dm_crtc_high_irq(void *interrupt_params)
672715
acrtc->dm_irq_params.stream,
673716
&acrtc->dm_irq_params.vrr_params);
674717

675-
dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc->dm_irq_params.stream,
676-
&acrtc->dm_irq_params.vrr_params.adjust);
718+
schedule_dc_vmin_vmax(adev, acrtc->dm_irq_params.stream,
719+
&acrtc->dm_irq_params.vrr_params.adjust);
677720
}
678721

679722
/*

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,20 @@ struct idle_workqueue {
153153
bool running;
154154
};
155155

156+
/**
157+
* struct dm_vupdate_work - Work data for periodic action in idle
158+
* @work: Kernel work data for the work event
159+
* @adev: amdgpu_device back pointer
160+
* @stream: DC stream associated with the crtc
161+
* @adjust: DC CRTC timing adjust to be applied to the crtc
162+
*/
163+
struct vupdate_offload_work {
164+
struct work_struct work;
165+
struct amdgpu_device *adev;
166+
struct dc_stream_state *stream;
167+
struct dc_crtc_timing_adjust *adjust;
168+
};
169+
156170
#define MAX_LUMINANCE_DATA_POINTS 99
157171

158172
/**

0 commit comments

Comments
 (0)