Re: [PATCH] drm/amd/display: fix usage of DC_FPU_{BEGIN,END} with PREEMPT_RT
Bert Karwatzki <[email protected]> Wed, 29 Jul 2026 14:35:34 +0200
| Newsgroups | org.freedesktop.lists.amd-gfx,dev.linux.lists.linux-rt-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-next,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
Am Dienstag, dem 28.07.2026 um 05:51 +0500 schrieb [email protected]: > On Mon, 2026-07-27 at 12:50 +0200, Bert Karwatzki wrote: > > On PREEMPT_RT kernels kvzalloc_obj() can sleep because spin_lock is > > converted to rt_mutex. dc_create_plane_state() can be called while > > inside an FPU-guarded region, resuling in "scheduling while atomic" > > errors on PREEMPT_RT kernels. > > Fix this by calling kvzalloc_obj() with > > DC_RUN_WITH_PREEMPTION_ENABLED(). > > Also fix the error path in dc_create_stream_for_sink(). > > > > Fixes: 3539437f354b ("drm/amd/display: Move FPU Guards From DML To DC > > - Part 1") > > Link: > > https://lore.kernel.org/lkml/[email protected]/ > > > > Signed-off-by: Bert Karwatzki <[email protected]> > > --- > > drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 5 +++-- > > drivers/gpu/drm/amd/display/dc/core/dc_surface.c | 4 ++-- > > 2 files changed, 5 insertions(+), 4 deletions(-) > > > > diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c > > b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c > > index dbc12640b01c..4ac835777b58 100644 > > --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c > > +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c > > @@ -233,8 +233,9 @@ struct dc_stream_state > > *dc_create_stream_for_sink( > > > > fail: > > if (stream) { > > - kfree(stream->update_scratch); > > - kfree(stream); > > + if (stream->update_scratch) > > + DC_RUN_WITH_PREEMPTION_ENABLED(kfree(stream- > > > update_scratch)); > > + DC_RUN_WITH_PREEMPTION_ENABLED(kfree(stream)); > > } > > > > return NULL; > > diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c > > b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c > > index 88e825a6582c..d5c6427796b6 100644 > > --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c > > +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c > > @@ -85,8 +85,8 @@ uint8_t dc_plane_get_pipe_mask(struct dc_state > > *dc_state, const struct dc_plane > > > > ********************************************************************* > > *********/ > > struct dc_plane_state *dc_create_plane_state(const struct dc *dc) > > { > > - struct dc_plane_state *plane_state = > > kvzalloc_obj(*plane_state, > > - > > GFP_ATOMIC); > > + struct dc_plane_state *plane_state; > > + DC_RUN_WITH_PREEMPTION_ENABLED(plane_state = > > kvzalloc_obj(*plane_state, GFP_ATOMIC)); > > > > if (NULL == plane_state) > > return NULL; > > Hi Bert, > > You may not be aware that the same allocation is already wrapped once, > at the dcn32 call site: > > 183182235f6d ("drm/amd/display: Wrap DCN32 phantom-plane allocation > in DC_RUN_WITH_PREEMPTION_ENABLED") > > That one only covers the dcn32 DML1 path, while your trace goes through > dcn401_validate_bandwidth() and dml21 - so wrapping the call site could > never have caught your case. Which is a good argument for guarding the > allocation in the callee, as you do: dc_create_plane_state() is reached > from every DCN and both DML generations. I did try a different approach, using DC_RUN_WITH_PREEMPTION_ENABLED further upward in the calltrace (This would have the slight benefit of more code running with preemption enabled). This does not work because dml21_utils.c is compiled as a _LINUX_FPU_COMPILATION_UNIT, so DC_RUN_WITH_PREEMPTION_ENABLED does nothing. (see drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c index 835fece1d46a..8c92deded8cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c @@ -286,7 +286,8 @@ static struct dc_plane_state *dml21_add_phantom_plane(struct dml2_context *dml_c (void)plane_programming; struct dc_plane_state *phantom_plane; - phantom_plane = dml_ctx->config.svp_pstate.callbacks.create_phantom_plane(dc, context, main_plane); + DC_RUN_WITH_PREEMPTION_ENABLED(phantom_plane + = dml_ctx->config.svp_pstate.callbacks.create_phantom_plane(dc, context, main_plane)); if (!phantom_plane) return NULL; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_mall_phantom.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_mall_phantom.c index 4543a60a0683..464bab9fc13b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_mall_phantom.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_mall_phantom.c @@ -769,10 +769,11 @@ static void enable_phantom_plane(struct dml2_context *ctx, if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state) { phantom_plane = prev_phantom_plane; } else { - phantom_plane = ctx->config.svp_pstate.callbacks.create_phantom_plane( + DC_RUN_WITH_PREEMPTION_ENABLED(phantom_plane = + ctx->config.svp_pstate.callbacks.create_phantom_plane( ctx->config.svp_pstate.callbacks.dc, state, - curr_pipe->plane_state); + curr_pipe->plane_state)); if (!phantom_plane) return; } Bert Karwatzki