From owner-svn-src-head@freebsd.org Wed Jul 15 19:34:22 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 81DF436DCD6; Wed, 15 Jul 2020 19:34:22 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4B6SHx1j9rz4sXs; Wed, 15 Jul 2020 19:34:20 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 182FA1C13B; Wed, 15 Jul 2020 19:34:20 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 06FJYJ69049664; Wed, 15 Jul 2020 19:34:19 GMT (envelope-from adrian@FreeBSD.org) Received: (from adrian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 06FJYJFg049663; Wed, 15 Jul 2020 19:34:19 GMT (envelope-from adrian@FreeBSD.org) Message-Id: <202007151934.06FJYJFg049663@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: adrian set sender to adrian@FreeBSD.org using -f From: Adrian Chadd Date: Wed, 15 Jul 2020 19:34:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r363236 - head/sys/mips/atheros X-SVN-Group: head X-SVN-Commit-Author: adrian X-SVN-Commit-Paths: head/sys/mips/atheros X-SVN-Commit-Revision: 363236 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Jul 2020 19:34:22 -0000 Author: adrian Date: Wed Jul 15 19:34:19 2020 New Revision: 363236 URL: https://svnweb.freebsd.org/changeset/base/363236 Log: [ar71xx] fix watchdog to work on subsequent SoCs The AR9341 AHB runs at 225MHz, much faster than the 33MHz of the AR71xx AHB. So not only is the math going to do weird things, it will also wrap rather than being clamped. So: * clamp! don't wrap! * tidy up some debugging * add an option to throw an NMI rather than reset! Tested: * AR9341 SoC (TP-Link TL-WDR4300), patting/not patting the watchdog! Modified: head/sys/mips/atheros/ar71xx_wdog.c Modified: head/sys/mips/atheros/ar71xx_wdog.c ============================================================================== --- head/sys/mips/atheros/ar71xx_wdog.c Wed Jul 15 18:49:00 2020 (r363235) +++ head/sys/mips/atheros/ar71xx_wdog.c Wed Jul 15 19:34:19 2020 (r363236) @@ -50,6 +50,7 @@ struct ar71xx_wdog_softc { device_t dev; int armed; int reboot_from_watchdog; + int watchdog_nmi; int debug; }; @@ -58,32 +59,54 @@ ar71xx_wdog_watchdog_fn(void *private, u_int cmd, int { struct ar71xx_wdog_softc *sc = private; uint64_t timer_val; + int action; + action = RST_WDOG_ACTION_RESET; + if (sc->watchdog_nmi != 0) + action = RST_WDOG_ACTION_NMI; + cmd &= WD_INTERVAL; if (sc->debug) - device_printf(sc->dev, "ar71xx_wdog_watchdog_fn: cmd: %x\n", cmd); + device_printf(sc->dev, "%s: : cmd: %x\n", __func__, cmd); if (cmd > 0) { timer_val = (uint64_t)(1ULL << cmd) * ar71xx_ahb_freq() / 1000000000; + + /* + * Clamp the timer value in case we overflow. + */ + if (timer_val > 0xffffffff) + timer_val = 0xffffffff; if (sc->debug) - device_printf(sc->dev, "ar71xx_wdog_watchdog_fn: programming timer: %jx\n", (uintmax_t) timer_val); + device_printf(sc->dev, "%s: programming timer: %jx\n", + __func__, (uintmax_t) timer_val); /* - * Load timer with large enough value to prevent spurious - * reset + * Make sure the watchdog is set to NOACTION and give it + * time to take. */ - ATH_WRITE_REG(AR71XX_RST_WDOG_TIMER, - ar71xx_ahb_freq() * 10); - ATH_WRITE_REG(AR71XX_RST_WDOG_CONTROL, - RST_WDOG_ACTION_RESET); - ATH_WRITE_REG(AR71XX_RST_WDOG_TIMER, - (timer_val & 0xffffffff)); + ATH_WRITE_REG(AR71XX_RST_WDOG_CONTROL, RST_WDOG_ACTION_NOACTION); + wmb(); + DELAY(100); + + /* + * Update the timer value. It's already clamped at this + * point so we don't have to wrap/clamp it here. + */ + ATH_WRITE_REG(AR71XX_RST_WDOG_TIMER, timer_val); + wmb(); + DELAY(100); + + /* + * And now, arm. + */ + ATH_WRITE_REG(AR71XX_RST_WDOG_CONTROL, action); sc->armed = 1; *error = 0; } else { if (sc->debug) - device_printf(sc->dev, "ar71xx_wdog_watchdog_fn: disarming\n"); + device_printf(sc->dev, "%s: disarming\n", __func__); if (sc->armed) { - ATH_WRITE_REG(AR71XX_RST_WDOG_CONTROL, + ATH_WRITE_REG(AR71XX_RST_WDOG_CONTROL, RST_WDOG_ACTION_NOACTION); sc->armed = 0; } @@ -109,6 +132,9 @@ ar71xx_wdog_sysctl(device_t dev) SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &sc->debug, 0, "enable watchdog debugging"); + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "nmi", CTLFLAG_RW, &sc->watchdog_nmi, 0, + "watchdog triggers NMI instead of reset"); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "armed", CTLFLAG_RD, &sc->armed, 0, "whether the watchdog is armed");