lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <03f65f72-4727-44c7-90cb-6d251f360c85@linaro.org>
Date: Fri, 28 Mar 2025 20:42:52 +0100
From: Daniel Lezcano <daniel.lezcano@...aro.org>
To: Guenter Roeck <linux@...ck-us.net>, wim@...ux-watchdog.org
Cc: linux-watchdog@...r.kernel.org, linux-kernel@...r.kernel.org,
 S32@....com, Ghennadi Procopciuc <ghennadi.procopciuc@....com>,
 Thomas Fossati <thomas.fossati@...aro.org>
Subject: Re: [PATCH 2/2] watchdog: Add the Software Watchdog Timer for the NXP
 S32 platform


Hi Guenter,

thanks for your review

On 28/03/2025 19:10, Guenter Roeck wrote:
> On 3/28/25 08:15, Daniel Lezcano wrote:
>> The S32 platform has several Software Watchdog Timer available and
> 
> Why "Software" ? This is a hardware watchdog, or am I missing something ?

I have no idea why it is called 'Software' because it is indeed a 
hardware watchdog. It is how NXP called it in their technical reference 
manual.

>> tied with a CPU. The SWT0 is the only one which directly asserts the
>> reset line, other SWT require an external setup to configure the reset
>> behavior which is not part of this change.
>>
>> The maximum watchdog value depends on the clock feeding the SWT
>> counter which is 32bits wide. On the s32g274-rb2, the clock has a rate
>> of 51MHz which lead to 83 seconds maximum timeout.
>>
>> The timeout can be specified via the device tree with the usual
>> existing bindings 'timeout-sec' or via the module param timeout.
>>
>> The watchdog can be loaded with the 'nowayout' option, preventing the
>> watchdog to be stopped.
>>
>> The watchdog can be started at boot time with the 'early-enable'
>> option, thus letting the watchdog framework to service the watchdog
>> counter.
>>
>> the watchdog support the magic character to stop when the userspace
>> releases the device.
>>
>> Cc: Ghennadi Procopciuc <ghennadi.procopciuc@....com>
>> Cc: Thomas Fossati <thomas.fossati@...aro.org>
>> Signed-off-by: Daniel Lezcano <daniel.lezcano@...aro.org>
>> ---

[ ... ]

>> --- /dev/null
>> +++ b/drivers/watchdog/s32g_wdt.c
>> @@ -0,0 +1,362 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Watchdog driver for S32G SoC
>> + *
>> + * Copyright (C) 2014 Freescale Semiconductor, Inc.
>> + * Copyright 2017-2019, 2021-2025 NXP.
> 
> Does this originate from out-of-tree code ?
> If so, a reference would be helpful.

Well, I kept the copyright but this implementation is mostly from scratch.

>> +#include <linux/debugfs.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/watchdog.h>
>> +#include <linux/clk.h>
>> +#include <linux/io.h>
>> +#include <linux/of.h>
> 
> Alphabetic include file order, please.
> 
>> +
>> +#define DRIVER_NAME "s32g-wdt"
>> +
>> +#define S32G_SWT_CR(__base)    (__base + 0x00)        /* Control 
>> Register offset    */
> 
> checkpatch:
>      CHECK: Macro argument '__base' may be better as '(__base)' to avoid 
> precedence issues

I'm not sure to get this one.

>> +#define S32G_SWT_CR_SM        BIT(9) | BIT(10)    /* -> Service 
>> Mode        */
> 
> checkpatch:
>      ERROR: Macros with complex values should be enclosed in parentheses
> 
> I am not going to comment on the other issues reported by checkpatch,
> but I expect them to be fixed in the next version. I would strongly suggest
> to run "checkpatch o--strict" on the patch and fix what it reports.

Sure, I will do that, thanks

[ ... ]

>> +static void s32g_wdt_debugfs_init(struct device *dev, struct 
>> s32g_wdt_device *wdev)
>> +{
>> +    struct debugfs_regset32 *regset;
>> +    static struct dentry *dentry = NULL;
>> +
>> +    if (!dentry)
>> +        dentry = debugfs_create_dir("watchdog", NULL);
> 
> That is a terribly generic debugfs directory name. That is unacceptable.
> Pick a name that is driver specific.

Why is it terrible ? We end up with:

watchdog/40100000.watchdog

There are 7 watchdogs on the platform, the directory is there to group 
them all. It seems to me it is self-explanatory, no ?

>> +
>> +    dentry = debugfs_create_dir(dev_name(dev), dentry);
>> +
> 
> Where is this removed if the driver is unloaded ?

Oh right, I missed it. Thanks for pointing this out.

> Also, if the driver is built into the kernel, it seems to me that a second
> instance will create a nested directory. That seems odd.

No, because there is the test above if (!dentry) which is a static variable.

[ ... ]

>> +static int s32g_wdt_set_timeout(struct watchdog_device *wdog, 
>> unsigned int timeout)
>> +{
>> +    struct s32g_wdt_device *wdev = wdd_to_s32g_wdt(wdog);
>> +
>> +    __raw_writel(wdog_sec_to_count(wdev, timeout), S32G_SWT_TO(wdev- 
>> >base));
>> +
>> +    /*
>> +     * Conforming to the documentation, the timeout counter is
>> +     * loaded when servicing is operated or when the counter is
>> +     * enabled. In case the watchdog is already started it must be
>> +     * stopped and started again to update the timeout
>> +     * register. Here we choose to service the watchdog for
>> +     * simpler code.
>> +     */
>> +    return s32g_wdt_ping(wdog);
> 
> Either check if the watchdog is running, or add a note explaining that a 
> ping
> on a stopped watchdog does not have adverse effect.

Ok, I think the comment is unclear. I'll provide a clarified version 
based on the documentation.

>> +}
>> +
>> +static unsigned int s32g_wdt_get_timeleft(struct watchdog_device *wdog)
>> +{
>> +    struct s32g_wdt_device *wdev = wdd_to_s32g_wdt(wdog);
>> +    unsigned long val, counter;
>> +
>> +    /*
>> +     * The counter output can be read only if the SWT is
>> +     * disabled. Given the latency between the internal counter
>> +     * and the counter output update, there can be very small
>> +     * difference. However, we can accept this matter of fact
>> +     * given the resolution is a second based unit for the output.
>> +     */
>> +    val = __raw_readl(S32G_SWT_CR(wdev->base));
>> +
>> +    if (test_bit(S32G_SWT_CR_WEN, &val))
>> +        s32g_wdt_stop(wdog);
> 
> The watchdog core provides wdt_is_running() which would avoid the
> extra i/o access.

Ok, thanks for the suggestion

>> +
>> +    counter = __raw_readl(S32G_SWT_CO(wdev->base));
>> +
>> +    if (test_bit(S32G_SWT_CR_WEN, &val))
>> +        s32g_wdt_start(wdog);
>> +
>> +    return counter / wdev->rate;
>> +}
>> +
>> +static const struct watchdog_ops s32g_wdt_ops = {
>> +    .owner        = THIS_MODULE,
>> +    .start        = s32g_wdt_start,
>> +    .stop        = s32g_wdt_stop,
>> +    .ping        = s32g_wdt_ping,
>> +    .set_timeout    = s32g_wdt_set_timeout,
>> +    .get_timeleft    = s32g_wdt_get_timeleft,
>> +};
>> +
>> +static void s32g_wdt_init(struct s32g_wdt_device *wdev)
>> +{
>> +    unsigned long val;
>> +
>> +    /* Set the watchdog's Time-Out value */
>> +    val = wdog_sec_to_count(wdev, wdev->wdog.timeout);
>> +
>> +    __raw_writel(val, S32G_SWT_TO(wdev->base));
>> +
>> +    /*
>> +     * Get the control register content. We are at init time, the
>> +     * watchdog should not be started.
>> +     */
>> +    val = __raw_readl(S32G_SWT_CR(wdev->base));
>> +
>> +    /*
>> +     * We want to allow the watchdog timer to be stopped when
>> +     * device enters debug mode.
>> +     */
>> +    val |= S32G_SWT_CR_FRZ;
>> +
>> +    /*
>> +     * However, when the CPU is in WFI or suspend mode, the
>> +     * watchdog must continue. The documentation refers it as the
>> +     * stopped mode.
>> +     */
>> +    val &= ~S32G_SWT_CR_STP;
>> +
>> +    /*
>> +     * Use Fixed Service Sequence to ping the watchdog which is
>> +     * 0x00 configuration value for the service mode. It should be
>> +     * already set because it is the default value but we reset it
>> +     * in case.
>> +     */
>> +    val &= ~S32G_SWT_CR_SM;
>> +
>> +    __raw_writel(val, S32G_SWT_CR(wdev->base));
>> +
>> +    /*
>> +     * The watchdog must be started when the module is loaded,
>> +     * leading to getting ride of the userspace control. The
> 
> ride ? And why does it _have_ to be started when the module is loaded ?

The comment is misleading. I meant when the 'early_enable' option is 
set, then the watchdog must be started.

>> +     * watchdog framework will handle the pings. It is especially
>> +     * handy for kernel development.
>> +     */
>> +    if (early_enable) {
>> +        s32g_wdt_start(&wdev->wdog);
>> +        set_bit(WDOG_HW_RUNNING, &wdev->wdog.status);
>> +    }
>> +}
>> +

[ ... ]

Thanks

   -- Daniel


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ