Skip to content

Commit

Permalink
RME: ath79: convert watchdog to panic instead of system reset
Browse files Browse the repository at this point in the history
This works around apparent errors in how the watchdog's "full chip
reset" works.  Whether it be bootloader failure, or watchdog failure,
using the default full chip reset will occasionally result in the device
hanging on boot.  (Repeatedly seen on our carambola2 based devices, but
based the openwrt bugs, this has been intermittently seen on _many_
ath79 devices)

Fixes: https://dev.openwrt.org/ticket/12121
Uses the same fix as: https://dev.archive.openwrt.org/ticket/17839 (ie,
use a known fixed restart)
Further discussion and original implementation for ar71xx at: openwrt#747

Signed-off-by: Karl Palsson <karlp@etactica.com>
  • Loading branch information
karlp committed Oct 26, 2021
1 parent e1137fc commit 2f6dba8
Showing 1 changed file with 60 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -29,6 +29,7 @@
#include <linux/watchdog.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/uaccess.h>
@@ -97,7 +98,11 @@ static inline void ath79_wdt_enable(void
*/
udelay(2);

- ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR);
+ /*
+ * Watchdog reset is unreliable, sometimes causing hangs.
+ * Use GPI to trigger panic instead, which is well handled
+ */
+ ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_GPI);
/* flush write */
ath79_wdt_rr(WDOG_REG_CTRL);
}
@@ -248,10 +253,17 @@ static struct miscdevice ath79_wdt_miscd
.fops = &ath79_wdt_fops,
};

+static irqreturn_t ath79_wdt_interrupt(int irq, void *dev_id)
+{
+ /* Let the kernel handle watchdog failure instead */
+ panic("watchdog timeout, deferring to panic");
+}
+
static int ath79_wdt_probe(struct platform_device *pdev)
{
u32 ctrl;
int err;
+ struct resource *irq_res;

if (wdt_base)
return -EBUSY;
@@ -282,6 +294,18 @@ static int ath79_wdt_probe(struct platfo
max_timeout, timeout);
}

+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq_res) {
+ dev_err(&pdev->dev, "no IRQ resource\n");
+ return -EINVAL;
+ }
+
+ err = request_irq(irq_res->start, ath79_wdt_interrupt, 0, DRIVER_NAME, NULL);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register wdt IRQ, err=%d\n", err);
+ goto err_clk_disable;
+ }
+
ctrl = ath79_wdt_rr(WDOG_REG_CTRL);
boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0;

0 comments on commit 2f6dba8

Please sign in to comment.