Hello Austin Zheng,
Commit 2fb66192d389 ("drm/amd/display: Move DML Wrapper into its own
Component") from Aug 6, 2026 (linux-next), leads to the following
Smatch static checker warning:
drivers/gpu/drm/amd/amdgpu/../display/dc/dml2_wrapper/dml2_mall_phantom.c:613
subvp_vblank_schedulable()
warn: unsigned subtraction: 'subvp_active_us - prefetch_us -
vblank_frame_us - max_vblank_mallregion' use '!='
drivers/gpu/drm/amd/amdgpu/../display/dc/dml2_wrapper/dml2_mall_phantom.c
533 static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct
dc_state *context)
534 {
535 struct pipe_ctx *pipe = NULL;
536 struct pipe_ctx *subvp_pipe = NULL;
537 bool found = false;
538 bool schedulable = false;
539 int i = 0;
540 uint8_t vblank_index = 0;
541 uint32_t prefetch_us = 0;
542 uint32_t mall_region_us = 0;
543 uint32_t vblank_frame_us = 0;
544 uint32_t subvp_active_us = 0;
545 uint32_t vblank_blank_us = 0;
546 uint32_t max_vblank_mallregion = 0;
547 struct dc_crtc_timing *main_timing = NULL;
548 struct dc_crtc_timing *phantom_timing = NULL;
549 struct dc_crtc_timing *vblank_timing = NULL;
550 struct dc_stream_state *phantom_stream;
551 enum mall_stream_type pipe_mall_type;
552
553 /* For SubVP + VBLANK/DRR cases, we assume there can only be
554 * a single VBLANK/DRR display. If DML outputs SubVP + VBLANK
555 * is supported, it is either a single VBLANK case or two VBLANK
556 * displays which are synchronized (in which case they have
identical
557 * timings).
558 */
559 for (i = 0; i < ctx->config.dcn_pipe_count && i < MAX_PIPES ;
i++) {
560 pipe = &context->res_ctx.pipe_ctx[i];
561 pipe_mall_type =
ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe);
562
563 // We check for master pipe, but it shouldn't matter
since we only need
564 // the pipe for timing info (stream should be same for
any pipe splits)
565 if (!pipe->stream || !pipe->plane_state ||
pipe->top_pipe || pipe->prev_odm_pipe)
566 continue;
567
568 if (!found && pipe_mall_type == SUBVP_NONE) {
569 // Found pipe which is not SubVP or Phantom
(i.e. the VBLANK pipe).
570 ASSERT(i <= 0xFF);
571 vblank_index = (uint8_t)i;
572 found = true;
573 }
574
575 if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN)
576 subvp_pipe = pipe;
577 }
578
579 if (subvp_pipe == NULL) {
580 // Defensive: should never happen, catch in debug
581 ASSERT(0);
582 return false;
583 }
584
585 // Use ignore_msa_timing_param flag to identify as DRR
586 if (found &&
context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) {
587 // SUBVP + DRR case
588 schedulable = dml2_svp_drr_schedulable(ctx, context,
&context->res_ctx.pipe_ctx[vblank_index].stream->timing);
589 } else if (found) {
590 phantom_stream =
ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context,
subvp_pipe->stream);
591 main_timing = &subvp_pipe->stream->timing;
592 phantom_timing = &phantom_stream->timing;
593 vblank_timing =
&context->res_ctx.pipe_ctx[vblank_index].stream->timing;
594 // Prefetch time is equal to VACTIVE + BP + VSYNC of
the phantom pipe
595 // Also include the prefetch end to mallstart delay time
596 prefetch_us = (uint32_t)((phantom_timing->v_total -
phantom_timing->v_front_porch) * phantom_timing->h_total /
597 (double)(phantom_timing->pix_clk_100hz
* 100) * 1000000 +
598
ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us);
599 // P-State allow width and FW delays already included
phantom_timing->v_addressable
600 mall_region_us =
(uint32_t)(phantom_timing->v_addressable * phantom_timing->h_total /
601 (double)(phantom_timing->pix_clk_100hz
* 100) * 1000000);
602 vblank_frame_us = (uint32_t)(vblank_timing->v_total *
vblank_timing->h_total /
603 (double)(vblank_timing->pix_clk_100hz *
100) * 1000000);
604 vblank_blank_us = (uint32_t)((vblank_timing->v_total -
vblank_timing->v_addressable) * vblank_timing->h_total /
605 (double)(vblank_timing->pix_clk_100hz *
100) * 1000000);
606 subvp_active_us = (uint32_t)(main_timing->v_addressable
* main_timing->h_total /
607 (double)(main_timing->pix_clk_100hz *
100) * 1000000);
608 max_vblank_mallregion = vblank_blank_us >
mall_region_us ? vblank_blank_us : mall_region_us;
609
610 // Schedulable if VACTIVE region of the SubVP pipe can
fit the MALL prefetch, VBLANK frame time,
611 // and the max of (VBLANK blanking time, MALL region)
612 // TODO: Possibly add some margin (i.e. the below
conditions should be [...] > X instead of [...] > 0)
--> 613 if (subvp_active_us - prefetch_us - vblank_frame_us -
max_vblank_mallregion > 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
These variables are unsigned so this is testing if != 0 instead of > 0.
Claude went a bit crazy and made a bunch of unrelated changes and no one
reviewed it. HashtagSadFace. There is similar math in
dml2_svp_drr_schedulable() where the math is signed. I asked ChatGPT's
cheapest model to review this and it said this was a bug. AI Fight!
614 schedulable = true;
615 }
616 return schedulable;
617 }
This email is a free service from the Smatch-CI project [smatch.sf.net].
regards,
dan carpenter