Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: designware: use casting of u64 in clock multiplication to avoid overflow

In functions i2c_dw_scl_lcnt() and i2c_dw_scl_hcnt() may have overflow
by depending on the values of the given parameters including the ic_clk.
For example in our use case where ic_clk is larger than one million,
multiplication of ic_clk * 4700 will result in 32 bit overflow.

Add cast of u64 to the calculation to avoid multiplication overflow, and
use the corresponding define for divide.

Fixes: 2373f6b9744d ("i2c-designware: split of i2c-designware.c into core and bus specific parts")
Signed-off-by: Lareine Khawaly <lareine@amazon.com>
Signed-off-by: Hanna Hawa <hhhawa@amazon.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@kernel.org>

authored by

Lareine Khawaly and committed by
Wolfram Sang
c8c37bc5 b7bfaa76

+6 -3
+6 -3
drivers/i2c/busses/i2c-designware-common.c
··· 351 351 * 352 352 * If your hardware is free from tHD;STA issue, try this one. 353 353 */ 354 - return DIV_ROUND_CLOSEST(ic_clk * tSYMBOL, MICRO) - 8 + offset; 354 + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tSYMBOL, MICRO) - 355 + 8 + offset; 355 356 else 356 357 /* 357 358 * Conditional expression: ··· 368 367 * The reason why we need to take into account "tf" here, 369 368 * is the same as described in i2c_dw_scl_lcnt(). 370 369 */ 371 - return DIV_ROUND_CLOSEST(ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset; 370 + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - 371 + 3 + offset; 372 372 } 373 373 374 374 u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) ··· 385 383 * account the fall time of SCL signal (tf). Default tf value 386 384 * should be 0.3 us, for safety. 387 385 */ 388 - return DIV_ROUND_CLOSEST(ic_clk * (tLOW + tf), MICRO) - 1 + offset; 386 + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - 387 + 1 + offset; 389 388 } 390 389 391 390 int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)