Re:Re: [PATCH V6 1/2] watchdog: mtk: support pre-timeout when the bark irq is available

王擎 wangqing at vivo.com
Thu Apr 22 04:46:18 BST 2021


>On 4/21/21 7:45 PM, Wang Qing wrote:
>> Use the bark interrupt as the pretimeout notifier if available.
>> 
>> When the watchdog timer expires in dual mode, an interrupt will be
>> triggered first, then the timing restarts. The reset signal will be
>> initiated when the timer expires again.
>> 
>> The pretimeout notification shall occur at timeout-sec/2.
>> 
>> 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.
>> 
>> V4:
>> - Remove pretimeout related processing. 
>> - Add dual mode control separately.
>> 
>> V5:
>> - Fix some formatting and printing problems.
>> 
>> V6:
>> - Realize pretimeout processing through dualmode.
>> 
>> Signed-off-by: Wang Qing <wangqing at vivo.com>
>> ---
>>  drivers/watchdog/mtk_wdt.c | 53 +++++++++++++++++++++++++++++++++++++++++-----
>>  1 file changed, 48 insertions(+), 5 deletions(-)
>> 
>> diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
>> index 97ca993..ebc648b
>> --- 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
>> @@ -184,15 +185,22 @@ static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
>>  {
>>  	struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
>>  	void __iomem *wdt_base = mtk_wdt->wdt_base;
>> +	unsigned int timeout_interval;
>>  	u32 reg;
>>  
>> -	wdt_dev->timeout = timeout;
>> +	timeout_interval = wdt_dev->timeout = timeout;
>> +	/*
>> +	 * In dual mode, irq will be triggered at timeout/2
>> +	 * the real timeout occurs at timeout
>> +	 */
>> +	if (wdt_dev->pretimeout)
>> +		timeout_interval = wdt_dev->pretimeout = timeout/2;
>
>Please run checkpatch --strict and fix what it reports.
>Also, there should be a set_pretimeout function to set the
>pretimeout. It is ok to update it here, but it should be set
>in its own function to make sure that the actual value
>is reported back to userspace.
>
>Thanks,
>Guenter

The reason why the set_pretimeout interface is not provided is 
because the pretimeout is fixed after the timeout is set,  we need
to modify timeout after setting pretimeout, which is puzzling.

I will point out this behavior in the doc and comments,
or implement the set_pretimeout interface only as a print prompt.
What do you think of it?

Thanks,
Qing
>
>>  
>>  	/*
>>  	 * One bit is the value of 512 ticks
>>  	 * The clock has 32 KHz
>>  	 */
>> -	reg = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY;
>> +	reg = WDT_LENGTH_TIMEOUT(timeout_interval << 6) | WDT_LENGTH_KEY;
>>  	iowrite32(reg, wdt_base + WDT_LENGTH);
>>  
>>  	mtk_wdt_ping(wdt_dev);
>> @@ -239,13 +247,25 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
>>  		return ret;
>>  
>>  	reg = ioread32(wdt_base + WDT_MODE);
>> -	reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
>> +	if (wdt_dev->pretimeout)
>> +		reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
>> +	else
>> +		reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
>>  	reg |= (WDT_MODE_EN | WDT_MODE_KEY);
>>  	iowrite32(reg, wdt_base + WDT_MODE);
>>  
>>  	return 0;
>>  }
>>  
>> +static irqreturn_t mtk_wdt_isr(int irq, void *arg)
>> +{
>> +	struct watchdog_device *wdd = arg;
>> +
>> +	watchdog_notify_pretimeout(wdd);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>>  static const struct watchdog_info mtk_wdt_info = {
>>  	.identity	= DRV_NAME,
>>  	.options	= WDIOF_SETTIMEOUT |
>> @@ -253,6 +273,14 @@ static const struct watchdog_info mtk_wdt_info = {
>>  			  WDIOF_MAGICCLOSE,
>>  };
>>  
>> +static const struct watchdog_info mtk_wdt_pt_info = {
>> +	.identity	= DRV_NAME,
>> +	.options	= WDIOF_SETTIMEOUT |
>> +			  WDIOF_PRETIMEOUT |
>> +			  WDIOF_KEEPALIVEPING |
>> +			  WDIOF_MAGICCLOSE,
>> +};
>> +
>>  static const struct watchdog_ops mtk_wdt_ops = {
>>  	.owner		= THIS_MODULE,
>>  	.start		= mtk_wdt_start,
>> @@ -267,7 +295,7 @@ static int mtk_wdt_probe(struct platform_device *pdev)
>>  	struct device *dev = &pdev->dev;
>>  	struct mtk_wdt_dev *mtk_wdt;
>>  	const struct mtk_wdt_data *wdt_data;
>> -	int err;
>> +	int err, irq;
>>  
>>  	mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);
>>  	if (!mtk_wdt)
>> @@ -279,7 +307,22 @@ static int mtk_wdt_probe(struct platform_device *pdev)
>>  	if (IS_ERR(mtk_wdt->wdt_base))
>>  		return PTR_ERR(mtk_wdt->wdt_base);
>>  
>> -	mtk_wdt->wdt_dev.info = &mtk_wdt_info;
>> +	irq = platform_get_irq(pdev, 0);
>> +	if (irq > 0) {
>> +		err = devm_request_irq(&pdev->dev, irq, mtk_wdt_isr, 0, "wdt_bark",
>> +							&mtk_wdt->wdt_dev);
>> +		if (err)
>> +			return err;
>> +
>> +		mtk_wdt->wdt_dev.info = &mtk_wdt_pt_info;
>> +		mtk_wdt->wdt_dev.pretimeout = WDT_MAX_TIMEOUT/2;
>> +	} else {
>> +		if (irq == -EPROBE_DEFER)
>> +			return -EPROBE_DEFER;
>> +
>> +		mtk_wdt->wdt_dev.info = &mtk_wdt_info;
>> +	}
>> +
>>  	mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;
>>  	mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
>>  	mtk_wdt->wdt_dev.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT * 1000;
>> 
>




More information about the linux-arm-kernel mailing list