diff options
author | U. Artie Eoff <ullysses.a.eoff@intel.com> | 2014-09-29 15:49:32 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-11-14 10:10:31 -0800 |
commit | 8989ebbfd33e144015b1a4a22bac998a3b144251 (patch) | |
tree | 1d3556caa64c56549965188e24b7897f315ca338 /drivers/gpu | |
parent | 2a0a68a350d188451611a23c34e79cc8b52a16bb (diff) | |
download | lwn-8989ebbfd33e144015b1a4a22bac998a3b144251.tar.gz lwn-8989ebbfd33e144015b1a4a22bac998a3b144251.zip |
drm/i915: intel_backlight scale() math WA
commit 673e7bbdb3920b62cfc6c710bea626b0a9b0f43a upstream.
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>
Reviewed-By: Joe Konno <joe.konno@intel.com>
[danvet: Add backporting note.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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 8e374449c6b5..cbe8a8de85de 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) } } +#define DIV_ROUND_CLOSEST_ULL(ll, d) \ +({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) + /** * scale - scale values from one range to another * @@ -419,9 +422,8 @@ static uint32_t scale(uint32_t source_val, source_val = clamp(source_val, source_min, source_max); /* avoid overflows */ - target_val = (uint64_t)(source_val - source_min) * - (target_max - target_min); - do_div(target_val, source_max - source_min); + target_val = DIV_ROUND_CLOSEST_ULL((uint64_t)(source_val - source_min) * + (target_max - target_min), source_max - source_min); target_val += target_min; return target_val; |