diff options
author | U. Artie Eoff <ullysses.a.eoff@intel.com> | 2014-09-29 18:49:32 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-10-06 10:47:24 -0400 |
commit | 673e7bbdb3920b62cfc6c710bea626b0a9b0f43a (patch) | |
tree | 374688115b4c6f01df23a1a8c08841b0e8cdd3e9 /drivers/gpu | |
parent | ebb69c95175609990af708ec90c46530f5a2c819 (diff) |
drm/i915: intel_backlight scale() math WA
Improper truncated integer division in the scale() function causes
actual_brightness != brightness. This (partial) work-around should be
sufficient for a majority of use-cases, but it is by no means a complete
solution.
TODO: Determine how best to scale "user" values to "hw" values, and
vice-versa, when the ranges are of different sizes. That would be a
buggy scenario even with this work-around.
The issue was introduced in the following (v3.17-rc1) commit:
6dda730 drm/i915: respect the VBT minimum backlight brightness
Note that for easier backporting this commit adds a duplicated macro.
A follow-up cleanup patch rectifies this for 3.18+
v2: (thanks to Chris Wilson) clarify commit message, use rounded division
macro
v3: -DIV_ROUND_CLOSEST() fails to build with CONFIG_X86_32=y. (Jani)
-Use DIV_ROUND_CLOSEST_ULL() instead. (Damien)
-v1 and v2 originally authored by Joe Konno.
Signed-off-by: U. Artie Eoff <ullysses.a.eoff@intel.com>
Cc: stable@vger.kernel.org
Reviewed-By: Joe Konno <joe.konno@intel.com>
[danvet: Add backporting note.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 18784470a760..97ff71f40dd3 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
@@ -398,6 +398,9 @@ intel_panel_detect(struct drm_device *dev) | |||
398 | } | 398 | } |
399 | } | 399 | } |
400 | 400 | ||
401 | #define DIV_ROUND_CLOSEST_ULL(ll, d) \ | ||
402 | ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) | ||
403 | |||
401 | /** | 404 | /** |
402 | * scale - scale values from one range to another | 405 | * scale - scale values from one range to another |
403 | * | 406 | * |
@@ -419,9 +422,8 @@ static uint32_t scale(uint32_t source_val, | |||
419 | source_val = clamp(source_val, source_min, source_max); | 422 | source_val = clamp(source_val, source_min, source_max); |
420 | 423 | ||
421 | /* avoid overflows */ | 424 | /* avoid overflows */ |
422 | target_val = (uint64_t)(source_val - source_min) * | 425 | target_val = DIV_ROUND_CLOSEST_ULL((uint64_t)(source_val - source_min) * |
423 | (target_max - target_min); | 426 | (target_max - target_min), source_max - source_min); |
424 | do_div(target_val, source_max - source_min); | ||
425 | target_val += target_min; | 427 | target_val += target_min; |
426 | 428 | ||
427 | return target_val; | 429 | return target_val; |