>On 4/14/21 4:48 AM, Wang Qing wrote:
>> Use the bark interrupt as the pretimeout notifier if available.
>> 
>> By default, the pretimeout notification shall occur one second earlier
>> than the timeout.
>> 
>> V2:
>> - panic() by default if WATCHDOG_PRETIMEOUT_GOV is not enabled.
>> 
>> V3:
>> - Modify the pretimeout behavior, manually reset after the pretimeout
>> - is processed and wait until timeout.
>> 
>> Signed-off-by: Wang Qing <wangq...@vivo.com>
>> ---
>>  drivers/watchdog/mtk_wdt.c | 62 
>> ++++++++++++++++++++++++++++++++++++++++++----
>>  1 file changed, 57 insertions(+), 5 deletions(-)
>> 
>> diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
>> index 97ca993..7bef1e3
>> --- a/drivers/watchdog/mtk_wdt.c
>> +++ b/drivers/watchdog/mtk_wdt.c
>> @@ -25,6 +25,7 @@
>>  #include <linux/reset-controller.h>
>>  #include <linux/types.h>
>>  #include <linux/watchdog.h>
>> +#include <linux/interrupt.h>
>>  
>>  #define WDT_MAX_TIMEOUT             31
>>  #define WDT_MIN_TIMEOUT             1
>> @@ -234,18 +235,46 @@ static int mtk_wdt_start(struct watchdog_device 
>> *wdt_dev)
>>      void __iomem *wdt_base = mtk_wdt->wdt_base;
>>      int ret;
>>  
>> -    ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
>> +    ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout - 
>> wdt_dev->pretimeout);
>>      if (ret < 0)
>>              return ret;
>>  
>>      reg = ioread32(wdt_base + WDT_MODE);
>> -    reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
>> +    reg &= ~WDT_MODE_IRQ_EN;
>> +    if (wdt_dev->pretimeout)
>> +            reg |= WDT_MODE_IRQ_EN;
>> +    else
>> +            reg &= ~WDT_MODE_IRQ_EN;
>>      reg |= (WDT_MODE_EN | WDT_MODE_KEY);
>>      iowrite32(reg, wdt_base + WDT_MODE);
>>  
>>      return 0;
>>  }
>>  
>> +static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd,
>> +                               unsigned int timeout)
>> +{
>> +    wdd->pretimeout = timeout;
>> +    return mtk_wdt_start(wdd);
>
>The watchdog is not necessarily active here.
>
>> +}
>> +
>> +static irqreturn_t mtk_wdt_isr(int irq, void *arg)
>> +{
>> +    struct watchdog_device *wdd = arg;
>> +    struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdd);
>> +    void __iomem *wdt_base = mtk_wdt->wdt_base;
>> +
>> +    watchdog_notify_pretimeout(wdd);
>> +    /*
>> +     * Guaranteed to be reset when the timeout
>> +     * expires under any situations
>> +     */
>> +    mdelay(1000*wdd->pretimeout);
>
>That is not how this is supposed to work. The idea with a pretimeout is that 
>the
>real watchdog reset will happen under all circumstances, and that executing
>the pretimeout (and changing some hardware registers) is not a prerequisite
>for the real timeout to happen. After all, the system could be stuck hard, with
>interrupts disabled.
>
>On top of that, just sleeping here while waiting for the real timeout and
>then resetting the system isn't the idea either. On a single core system this
>will just hang. On a multi-core system, who knows if userspace managed to ping
>the watchdog in the meantime.
>
>Unless there is a means to trigger the watchdog twice, without intervention,
>the first time generating an interrupt and the second time resetting the 
>system,
>there is no way for this to work. I don't see how this chip really supports
>pretimeout. It seems that it supports either a hard reset or generating an
>interrupt on watchdog timeout, and there is only a single timeout.
>
>If you have a use case for generating an interrupt and resetting the system via
>software (ie panic) _instead_ of having it generate a hard reset, please feel
>free to submit a patch along that line, together with a description of its use
>case.
>
>Thanks,
>Guenter
>

Yes, as mentioned before, the behavior of WDT_MODE_IRQ_EN is use irq instead of
reset, so we must use WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN if like you said
"the first time generating an interrupt and the second time resetting the 
system" . 

The Dual mode is mentioned in the MTK datasheet:
In this mode, the watchdog will be AUTO-RESTART after interrupt is triggered. 
AP need to clear WDT_STA after receiving interrupt from TOPRGU, or system reset
will be triggered after watchdog timer expires.
Instructions for use:
Set wdt_en = 1'b1.
Set dual_mode = 1'b1.
Set wdt_irq = 1'b1.

We can use Dual mode to achieve pretimeout behavior, only in this way can we
get more information during pretimeout processing, instead of directly 
resetting.

Thanks,
Qing

Reply via email to