From 04d68dea26b0a409d44e87ea573a131b6dc67e78 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Tue, 16 Aug 2016 23:22:01 +0900 Subject: [PATCH] pwm: samsung: Fix to use lowest div for large enough modulation bits 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' [...] [] (ubsan_epilogue) from [] (__ubsan_handle_shift_out_of_bounds+0xd8/0x120) [] (__ubsan_handle_shift_out_of_bounds) from [] (pwm_samsung_config+0x508/0x6a4) [] (pwm_samsung_config) from [] (pwm_apply_state+0x174/0x40c) [] (pwm_apply_state) from [] (pwm_fan_probe+0xc8/0x488) [] (pwm_fan_probe) from [] (platform_drv_probe+0x70/0x150) [...] Cc: Tomasz Figa Signed-off-by: Seung-Woo Kim Reviewed-by: Krzysztof Kozlowski Signed-off-by: Thierry Reding --- drivers/pwm/pwm-samsung.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index ada2d326dc3e..f113cda47032 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -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));