summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2016-08-09 22:35:58 -0700
committerTao Huang <huangtao@rock-chips.com>2019-03-12 16:09:22 +0800
commitde56d92b60f66f938ee8cd0a02ff7cbe60bf16d7 (patch)
tree132d85e4b5d6bb17601b0ddba852e967156badd4
parentda72a45cf789251335775337921e47d0dbde6004 (diff)
BACKPORT: watchdog: dw_wdt: Read clock rate only once and validate it
Coverity reports: divide_by_zero: In expression readl(dw_wdt->regs + 8) / clk_get_rate(dw_wdt->clk), division by expression clk_get_rate(dw_wdt->clk) which may be zero has undefined behavior. The clock used for the watchdog timer won't change its rate, so read it only once during probe. Also validate it and abort the probe function with an error if it is 0. Cc: Douglas Anderson <dianders@chromium.org> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be> (cherry picked from commit c97344f73fdc35b27c7315c5e7c5decd4ce10467) Conflicts: drivers/watchdog/dw_wdt.c [due to missing: f29a72c24ad49 "watchdog: dw_wdt: Convert to use watchdog infrastructure" and local version of: 3024e0d13b0f3 "watchdog: dw_wdt: fix signedness bug in dw_wdt_top_in_seconds()"] Change-Id: Iea745e27224532bf4da560e5952b372289d1c6ae Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
-rw-r--r--drivers/watchdog/dw_wdt.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 7b1984d18448..cbe58aac5d8c 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -63,6 +63,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
static struct {
void __iomem *regs;
struct clk *clk;
+ unsigned long rate;
unsigned long in_use;
unsigned long next_heartbeat;
struct timer_list timer;
@@ -85,9 +86,7 @@ static inline int dw_wdt_top_in_seconds(unsigned top)
* There are 16 possible timeout values in 0..15 where the number of
* cycles is 2 ^ (16 + i) and the watchdog counts down.
*/
- unsigned int cycles = 1 << (16 + top);
-
- return cycles / clk_get_rate(dw_wdt.clk);
+ return (1U << (16 + top)) / dw_wdt.rate;
}
static int dw_wdt_get_top(void)
@@ -236,7 +235,7 @@ static ssize_t dw_wdt_write(struct file *filp, const char __user *buf,
static u32 dw_wdt_time_left(void)
{
return readl(dw_wdt.regs + WDOG_CURRENT_COUNT_REG_OFFSET) /
- clk_get_rate(dw_wdt.clk);
+ dw_wdt.rate;
}
static const struct watchdog_info dw_wdt_ident = {
@@ -362,6 +361,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
if (ret)
return ret;
+ dw_wdt.rate = clk_get_rate(dw_wdt.clk);
+ if (dw_wdt.rate == 0) {
+ ret = -EINVAL;
+ goto out_disable_clk;
+ }
+
ret = misc_register(&dw_wdt_miscdev);
if (ret)
goto out_disable_clk;