3.17-stable review patch.  If anyone has any objections, please let me know.

------------------

From: "U. Artie Eoff" <ullysses.a.e...@intel.com>

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.e...@intel.com>
Reviewed-By: Joe Konno <joe.ko...@intel.com>
[danvet: Add backporting note.]
Signed-off-by: Daniel Vetter <daniel.vet...@ffwll.ch>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/gpu/drm/i915/intel_panel.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

--- 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 *de
        }
 }
 
+#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_va
        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;


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to