[PATCH 04/12] watchdog: fix division-by-zero when clock rate == 0

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Instead of storing the clk into the driver's device-specific private
data, just store the rate and make sure it's != 0 on probe.

This aligns us with what Linux does for the STM32 IWDG and DW WDT.

Reported-by: clang-analyzer-10
Cc: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx>
---
 drivers/watchdog/ar9344_wdt.c | 21 ++++++++++++++-------
 drivers/watchdog/dw_wdt.c     | 19 ++++++++++++-------
 drivers/watchdog/stm32_iwdg.c |  2 ++
 3 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/watchdog/ar9344_wdt.c b/drivers/watchdog/ar9344_wdt.c
index 4615288631d6..c7cd552dc711 100644
--- a/drivers/watchdog/ar9344_wdt.c
+++ b/drivers/watchdog/ar9344_wdt.c
@@ -34,8 +34,8 @@
 struct ar9344_wd {
 	struct watchdog		wd;
 	void __iomem		*base;
-	struct clk		*clk;
 	struct device_d		*dev;
+	unsigned int		rate;
 };
 
 static int ar9344_watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
@@ -45,7 +45,7 @@ static int ar9344_watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
 
 	if (timeout) {
 		ctrl = AR9344_WD_CTRL_ACTION_FCR;
-		val = timeout * clk_get_rate(priv->clk);
+		val = timeout * priv->rate;
 	} else {
 		ctrl = AR9344_WD_CTRL_ACTION_NONE;
 		val = U32_MAX;
@@ -74,6 +74,7 @@ static int ar9344_wdt_probe(struct device_d *dev)
 {
 	struct resource *iores;
 	struct ar9344_wd *priv;
+	struct clk *clk;
 	int ret;
 
 	priv = xzalloc(sizeof(struct ar9344_wd));
@@ -93,16 +94,22 @@ static int ar9344_wdt_probe(struct device_d *dev)
 
 	ar9344_watchdog_detect_reset_source(priv);
 
-	priv->clk = clk_get(dev, NULL);
-	if (IS_ERR(priv->clk)) {
+	clk = clk_get(dev, NULL);
+	if (IS_ERR(clk)) {
 		dev_err(dev, "could not get clk\n");
-		ret = PTR_ERR(priv->clk);
+		ret = PTR_ERR(clk);
 		goto on_error;
 	}
 
-	clk_enable(priv->clk);
+	clk_enable(clk);
 
-	priv->wd.timeout_max = U32_MAX / clk_get_rate(priv->clk);
+	priv->rate = clk_get_rate(clk);
+	if (priv->rate == 0) {
+		ret = -EINVAL;
+		goto on_error;
+	}
+
+	priv->wd.timeout_max = U32_MAX / priv->rate;
 
 	ret = watchdog_register(&priv->wd);
 	if (ret)
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index cb0d17e3610b..17771c712644 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -41,10 +41,10 @@
 
 struct dw_wdt {
 	void __iomem		*regs;
-	struct clk		*clk;
 	struct restart_handler	restart;
 	struct watchdog		wdd;
 	struct reset_control	*rst;
+	unsigned int		rate;
 };
 
 #define to_dw_wdt(wdd)	container_of(wdd, struct dw_wdt, wdd)
@@ -55,7 +55,7 @@ static inline int dw_wdt_top_in_seconds(struct dw_wdt *dw_wdt, 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.
 	 */
-	return (1U << (16 + top)) / clk_get_rate(dw_wdt->clk);
+	return (1U << (16 + top)) / dw_wdt->rate;
 }
 
 static int dw_wdt_start(struct watchdog *wdd)
@@ -134,6 +134,7 @@ static int dw_wdt_drv_probe(struct device_d *dev)
 	struct watchdog *wdd;
 	struct dw_wdt *dw_wdt;
 	struct resource *mem;
+	struct clk *clk;
 	int ret;
 
 	dw_wdt = xzalloc(sizeof(*dw_wdt));
@@ -143,11 +144,11 @@ static int dw_wdt_drv_probe(struct device_d *dev)
 	if (IS_ERR(dw_wdt->regs))
 		return PTR_ERR(dw_wdt->regs);
 
-	dw_wdt->clk = clk_get(dev, NULL);
-	if (IS_ERR(dw_wdt->clk))
-		return PTR_ERR(dw_wdt->clk);
+	clk = clk_get(dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
 
-	ret = clk_enable(dw_wdt->clk);
+	ret = clk_enable(clk);
 	if (ret)
 		return ret;
 
@@ -160,6 +161,10 @@ static int dw_wdt_drv_probe(struct device_d *dev)
 	wdd->hwdev = dev;
 	wdd->set_timeout = dw_wdt_set_timeout;
 
+	dw_wdt->rate = clk_get_rate(clk);
+	if (dw_wdt->rate == 0)
+		return -EINVAL;
+
 	ret = watchdog_register(wdd);
 	if (ret)
 		goto out_disable_clk;
@@ -179,7 +184,7 @@ static int dw_wdt_drv_probe(struct device_d *dev)
 	return 0;
 
 out_disable_clk:
-	clk_disable(dw_wdt->clk);
+	clk_disable(clk);
 	return ret;
 }
 
diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c
index 9e38f1a669f2..4d7a263b7e62 100644
--- a/drivers/watchdog/stm32_iwdg.c
+++ b/drivers/watchdog/stm32_iwdg.c
@@ -157,6 +157,8 @@ static int stm32_iwdg_probe(struct device_d *dev)
 		return ret;
 
 	wd->rate = clk_get_rate(clk);
+	if (wd->rate == 0)
+		return -EINVAL;
 
 	if (data->has_pclk) {
 		clk = clk_get(dev, "pclk");
-- 
2.28.0


_______________________________________________
barebox mailing list
barebox@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/barebox



[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux