From: minyard@acm.org To: Guenter Roeck <linux@roeck-us.net>, Wim Van Sebroeck <wim@linux-watchdog.org> Cc: linux-watchdog@vger.kernel.org, Gabriele Paoloni <gabriele.paoloni@intel.com>, Corey Minyard <cminyard@mvista.com> Subject: [PATCH 5/6] watchdog:i6300: Convert to a millisecond watchdog device Date: Sat, 20 Jun 2020 12:33:50 -0500 Message-ID: <20200620173351.18752-6-minyard@acm.org> (raw) In-Reply-To: <20200620173351.18752-1-minyard@acm.org> From: Corey Minyard <cminyard@mvista.com> The i6300 clock runs at 1Khz, so it's an easy conversion to make it a millisecond timer. Signed-off-by: Corey Minyard <cminyard@mvista.com> --- drivers/watchdog/i6300esb.c | 66 +++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c index a30835f547b3..9f5afe6ee622 100644 --- a/drivers/watchdog/i6300esb.c +++ b/drivers/watchdog/i6300esb.c @@ -69,12 +69,40 @@ #define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ #define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */ -/* module parameters */ -/* 30 sec default heartbeat (1 < heartbeat < 2*1023) */ +/* + * Timer clock is driven by a 30ns clock divided by 32768, giving a + * 983.04usec clock. Not really close enough to say it's 1Khz. But + * if we multiply by 101725261 / 100000000, that would give us a + * 1000.0000057 usec per increment of time, which is very close and + * slightly slow, which is preferred to slightly fast. If there is a + * remainder from that calculation, then round up. So if 1 comes in + * for the time, we will have (1 * 101725261) / 100000000 = 1, and + * (1 * 101725261) % 100000000 = 1725261, so we round up the 1 to a 2, which + * will result in 1.96608msecs. Remember, better too long than too short. + * All the arithmetic has to be 64 bit to avoid overflow. + * + * The error gets better as the numbers increase to more reasonable + * values. For 30 seconds, for instance, we get a count of 30518, + * which is 30.0004 seconds. Close enough :). + * + * The 2061582 max time comes in because we have 2 20 bit registers + * that count down. This means that the maximum timeout value we can + * put in the registers is 0x1ffffe. Run that through the calculation + * backwards and we get 0x1ffffe * 100000000 / 101725261 = 2061582. If we + * put that into our calculation, we get 2061582 * 101725261 / 100000000 = + * 0x1ffffd which will round up to 0x1ffffe. + * + * These numbers should never result in an error more than 1ms, so + * there is no need to be more accurate. This is been tested + * exhaustively. + */ #define ESB_HEARTBEAT_MIN 1 -#define ESB_HEARTBEAT_MAX 2046 -#define ESB_HEARTBEAT_DEFAULT 30 -#define ESB_HEARTBEAT_RANGE __MODULE_STRING(ESB_HEARTBEAT_MIN) \ +#define ESB_HEARTBEAT_MAX 2061582 +/* 30 sec default heartbeat */ +#define ESB_HEARTBEAT_DEFAULT 30000 + +/* module parameters */ +#define ESB_HEARTBEAT_RANGE __MODULE_STRING(ESB_HEARTBEAT_MIN) \ "<heartbeat<" __MODULE_STRING(ESB_HEARTBEAT_MAX) static int heartbeat; /* in seconds */ module_param(heartbeat, int, 0); @@ -158,17 +186,34 @@ static int esb_timer_set_heartbeat(struct watchdog_device *wdd, { struct esb_dev *edev = to_esb_dev(wdd); u32 val; + u64 ttime, ctime; + + /* See comments above ESB_HEARTBEAT_xxx for details on this. */ + ttime = (u64) time * 101725261ULL; + ctime = div_u64(ttime, 100000000); + /* + * You might think that a "if (ttime % 100000000ULL)" would be + * required here so we don't round up if the time is exact, + * but with these numbers, there is never a time value that + * will come in that will result in a zero remainder. So no + * need to check. We round up, as it's better to be a little + * long than a little short. + */ + ctime += 1; - /* We shift by 9, so if we are passed a value of 1 sec, - * val will be 1 << 9 = 512, then write that to two - * timers => 2 * 512 = 1024 (which is decremented at 1KHz) + /* + * We have two registers that have to count down, so each gets + * loaded with half the time. */ - val = time << 9; + val = ctime / 2; /* Write timer 1 */ esb_unlock_registers(edev); writel(val, ESB_TIMER1_REG(edev)); + /* If the time was odd, add the extra tick to the second register. */ + val += ctime % 2; + /* Write timer 2 */ esb_unlock_registers(edev); writel(val, ESB_TIMER2_REG(edev)); @@ -190,7 +235,8 @@ static int esb_timer_set_heartbeat(struct watchdog_device *wdd, static struct watchdog_info esb_info = { .identity = ESB_MODULE_NAME, - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, + .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | + WDIOF_MSECTIMER), }; static const struct watchdog_ops esb_ops = { -- 2.17.1
next prev parent reply index Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-06-20 17:33 [PATCH 0/6] watchdog: Add millisecond-level capabilities minyard 2020-06-20 17:33 ` [PATCH 1/6] watchdog: Allow a driver to use milliseconds instead of seconds minyard 2020-06-26 23:10 ` Guenter Roeck 2020-06-27 2:18 ` Corey Minyard 2020-06-27 4:08 ` Guenter Roeck 2020-06-28 14:54 ` Guenter Roeck 2020-06-28 17:56 ` Corey Minyard 2020-12-01 22:54 ` Corey Minyard 2020-12-01 23:43 ` Guenter Roeck 2020-06-20 17:33 ` [PATCH 2/6] watchdog: Add ioctls for millisecond timeout handling minyard 2020-06-20 17:33 ` [PATCH 3/6] watchdog: Add millisecond precision device attributes minyard 2020-06-20 17:33 ` [PATCH 4/6] watchdog: Add documentation for millisecond interfaces minyard 2020-06-20 17:33 ` minyard [this message] 2020-06-20 17:33 ` [PATCH 6/6] watchdog:softdog: Convert to a millisecond watchdog minyard
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20200620173351.18752-6-minyard@acm.org \ --to=minyard@acm.org \ --cc=cminyard@mvista.com \ --cc=gabriele.paoloni@intel.com \ --cc=linux-watchdog@vger.kernel.org \ --cc=linux@roeck-us.net \ --cc=wim@linux-watchdog.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Linux-Watchdog Archive on lore.kernel.org Archives are clonable: git clone --mirror https://lore.kernel.org/linux-watchdog/0 linux-watchdog/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 linux-watchdog linux-watchdog/ https://lore.kernel.org/linux-watchdog \ linux-watchdog@vger.kernel.org public-inbox-index linux-watchdog Example config snippet for mirrors Newsgroup available over NNTP: nntp://nntp.lore.kernel.org/org.kernel.vger.linux-watchdog AGPL code for this site: git clone https://public-inbox.org/public-inbox.git