pwm: samsung: Fix to use lowest div for large enough modulation bits
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Tue, 16 Aug 2016 14:22:01 +0000 (23:22 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 14 Dec 2016 04:54:36 +0000 (13:54 +0900)
From pwm_samsung_calc_tin(), there is routine to find the lowest divider
possible to generate lower frequency than requested one. But it is
always possible to generate requested frequency with large enough
modulation bits except on s3c24xx, so this patch fixes to use lowest div
for the case. This patch removes following UBSAN warning:

   UBSAN: Undefined behaviour in drivers/pwm/pwm-samsung.c:197:13
   shift exponent 32 is too large for 32-bit type 'long unsigned int'
   [...]
   [<c0670248>] (ubsan_epilogue) from [<c06707b4>] (__ubsan_handle_shift_out_of_bounds+0xd8/0x120)
   [<c06707b4>] (__ubsan_handle_shift_out_of_bounds) from [<c0694b28>] (pwm_samsung_config+0x508/0x6a4)
   [<c0694b28>] (pwm_samsung_config) from [<c069286c>] (pwm_apply_state+0x174/0x40c)
   [<c069286c>] (pwm_apply_state) from [<c0b2e070>] (pwm_fan_probe+0xc8/0x488)
   [<c0b2e070>] (pwm_fan_probe) from [<c07ba8b0>] (platform_drv_probe+0x70/0x150)
   [...]

Cc: Tomasz Figa <tomasz.figa@gmail.com>
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
[Backport from mainline to remove UBSAN warning]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Change-Id: Idf20ea7ccb2d20d0317e5c82498dd1e7fa3656cc

drivers/pwm/pwm-samsung.c

index ff201e1b92197e1d354cacc3239a045b7b88e77c..0ec05489d8edc69decd5d45fe9fde6f144e60036 100644 (file)
@@ -193,9 +193,18 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip,
         * divider settings and choose the lowest divisor that can generate
         * frequencies lower than requested.
         */
-       for (div = variant->div_base; div < 4; ++div)
-               if ((rate >> (variant->bits + div)) < freq)
-                       break;
+       if (variant->bits < 32) {
+               /* Only for s3c24xx */
+               for (div = variant->div_base; div < 4; ++div)
+                       if ((rate >> (variant->bits + div)) < freq)
+                               break;
+       } else {
+               /*
+                * Other variants have enough counter bits to generate any
+                * requested rate, so no need to check higher divisors.
+                */
+               div = variant->div_base;
+       }
 
        pwm_samsung_set_divisor(chip, chan, BIT(div));