Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: Fix LFC multiplier changing erratically

[Why]
1. There is a calculation that is using frame_time_in_us instead of
last_render_time_in_us to calculate whether choosing an LFC multiplier
would cause the inserted frame duration to be outside of range.

2. We do not handle unsigned integer subtraction correctly and it underflows
to a really large value, which causes some logic errors.

[How]
1. Fix logic to calculate 'within range' using last_render_time_in_us
2. Split out delta_from_mid_point_delta_in_us calculation to ensure
we don't underflow and wrap around

Signed-off-by: Anthony Koo <Anthony.Koo@amd.com>
Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Anthony Koo and committed by
Alex Deucher
e4ed4dbb a49f6727

+31 -9
+31 -9
drivers/gpu/drm/amd/display/modules/freesync/freesync.c
··· 324 324 325 325 /* Choose number of frames to insert based on how close it 326 326 * can get to the mid point of the variable range. 327 + * - Delta for CEIL: delta_from_mid_point_in_us_1 328 + * - Delta for FLOOR: delta_from_mid_point_in_us_2 327 329 */ 328 - if ((frame_time_in_us / mid_point_frames_ceil) > in_out_vrr->min_duration_in_us && 329 - (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2 || 330 - mid_point_frames_floor < 2)) { 331 - frames_to_insert = mid_point_frames_ceil; 332 - delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 - 333 - delta_from_mid_point_in_us_1; 334 - } else { 330 + if ((last_render_time_in_us / mid_point_frames_ceil) < in_out_vrr->min_duration_in_us) { 331 + /* Check for out of range. 332 + * If using CEIL produces a value that is out of range, 333 + * then we are forced to use FLOOR. 334 + */ 335 335 frames_to_insert = mid_point_frames_floor; 336 - delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 - 337 - delta_from_mid_point_in_us_2; 336 + } else if (mid_point_frames_floor < 2) { 337 + /* Check if FLOOR would result in non-LFC. In this case 338 + * choose to use CEIL 339 + */ 340 + frames_to_insert = mid_point_frames_ceil; 341 + } else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) { 342 + /* If choosing CEIL results in a frame duration that is 343 + * closer to the mid point of the range. 344 + * Choose CEIL 345 + */ 346 + frames_to_insert = mid_point_frames_ceil; 347 + } else { 348 + /* If choosing FLOOR results in a frame duration that is 349 + * closer to the mid point of the range. 350 + * Choose FLOOR 351 + */ 352 + frames_to_insert = mid_point_frames_floor; 338 353 } 339 354 340 355 /* Prefer current frame multiplier when BTR is enabled unless it drifts 341 356 * too far from the midpoint 342 357 */ 358 + if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) { 359 + delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 - 360 + delta_from_mid_point_in_us_1; 361 + } else { 362 + delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 - 363 + delta_from_mid_point_in_us_2; 364 + } 343 365 if (in_out_vrr->btr.frames_to_insert != 0 && 344 366 delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) { 345 367 if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <