watchdog: aspeed: Add pre-timeout interrupt support
cover watchdog: aspeed: Add pre-timeout interrupt support
Enable the pre-timeout interrupt if requested by device property, and document that property.
Eddie James (2):
watchdog: aspeed: Add pre-timeout interrupt support
dt-bindings: watchdog: aspeed: Document aspeed,pre-timeout-irq-us
.../bindings/watchdog/aspeed-wdt.txt | 7 ++- drivers/watchdog/aspeed_wdt.c | 53 ++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-)
Signature · 1 line
2.31.1
PATCH 1/2 watchdog: aspeed: Add pre-timeout interrupt support
Enable the pre-timeout interrupt if requested by device property.
--- drivers/watchdog/aspeed_wdt.c | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-)
drivers/watchdog/aspeed_wdt.c +51 -2
@@ -5,11 +5,14 @@* Joel Stanley <[email protected]> */ +#include <linux/bits.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/watchdog.h>
@@ -26,20 +29,32 @@ struct aspeed_wdt {struct aspeed_wdt_config {u32 ext_pulse_width_mask; +u32 irq_shift; +u32 irq_mask; };static const struct aspeed_wdt_config ast2400_config = { .ext_pulse_width_mask =0xff , + .irq_shift =0 , + .irq_mask =0 , };static const struct aspeed_wdt_config ast2500_config = { .ext_pulse_width_mask =0xfffff , + .irq_shift =12 , + .irq_mask =GENMASK (31 ,12 ), +}; + +static const struct aspeed_wdt_config ast2600_config = { + .ext_pulse_width_mask =0xfffff , + .irq_shift =0 , + .irq_mask =GENMASK (31 ,10 ), };static const struct of_device_id aspeed_wdt_of_table[] = { { .compatible ="aspeed,ast2400-wdt" , .data = &ast2400_config }, { .compatible ="aspeed,ast2500-wdt" , .data = &ast2500_config }, - { .compatible ="aspeed,ast2600-wdt" , .data = &ast2500_config }, + { .compatible ="aspeed,ast2600-wdt" , .data = &ast2600_config }, { }, };MODULE_DEVICE_TABLE (of, aspeed_wdt_of_table);
@@ -58,6 +73,7 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);#define WDT_CTRL_RESET_SYSTEM BIT(1)#define WDT_CTRL_ENABLE BIT(0)#define WDT_TIMEOUT_STATUS 0x10 +#define WDT_TIMEOUT_STATUS_IRQ BIT(2)#define WDT_TIMEOUT_STATUS_BOOT_SECONDARY BIT(1)#define WDT_CLEAR_TIMEOUT_STATUS 0x14#define WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION BIT(0)
@@ -243,6 +259,17 @@ static const struct watchdog_info aspeed_wdt_info = { .identity = KBUILD_MODNAME, }; +static irqreturn_t aspeed_wdt_irq (int irq,void *arg) +{ +struct aspeed_wdt *wdt = arg; +u32 status =readl (wdt->base +WDT_TIMEOUT_STATUS ); + +if (status &WDT_TIMEOUT_STATUS_IRQ ) +panic ("Watchdog pre-timeout IRQ" ); + +return IRQ_NONE ; +} +static int aspeed_wdt_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;
@@ -253,6 +280,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)const char *reset_type;u32 duration;u32 status; +u32 timeout =0 ;int ret; wdt =devm_kzalloc (dev,sizeof (*wdt),GFP_KERNEL );
@@ -291,6 +319,27 @@ static int aspeed_wdt_probe(struct platform_device *pdev)if (of_device_is_compatible (np,"aspeed,ast2400-wdt" )) wdt->ctrl =WDT_CTRL_1MHZ_CLK ; +if (config->irq_mask) { +if (!of_property_read_u32 (np,"aspeed,pre-timeout-irq-us" , &timeout) && timeout) { +int irq =platform_get_irq (pdev,0 ); + +if (irq <0 ) { +dev_warn (dev,"Couldn't find IRQ: %d\n" , irq); + timeout =0 ; + }else { + ret =devm_request_irq (dev, irq, aspeed_wdt_irq,IRQF_SHARED , +dev_name (dev), wdt); +if (ret) { +dev_warn (dev,"Couldn't request IRQ:%d\n" , ret); + timeout =0 ; + }else { + wdt->ctrl |= ((timeout << config->irq_shift) & + config->irq_mask) |WDT_CTRL_WDT_INTR ; + } + } + } + } +/* * Control reset on a per-device basis to ensure the * host is not affected by a BMC reboot
@@ -308,7 +357,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)else if (!strcmp (reset_type,"system" )) wdt->ctrl |=WDT_CTRL_RESET_MODE_FULL_CHIP |WDT_CTRL_RESET_SYSTEM ; -else if (strcmp (reset_type,"none" )) +else if (strcmp (reset_type,"none" ) && !timeout)return -EINVAL ; }if (of_property_read_bool (np,"aspeed,external-signal" ))
Signature · 1 line
2.31.1
Guenter Roeck
maintainerQuoted 2 lines · Eddie James
Enable the pre-timeout interrupt if requested by device property.
I am not inclined to accept this patch without detailed explanation. Why would it make sense and/or be desirable to completely bypass the watchdog core with this pretimeout support ?
Thanks,
Guenter
Quoted 132 lines
Signed-off-by Eddie James <[email protected]>--- drivers/watchdog/aspeed_wdt.c | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-)drivers/watchdog/aspeed_wdt.c +51
-2@@ -5,11 +5,14 @@* Joel Stanley <[email protected]> */ +#include <linux/bits.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/watchdog.h> @@ -26,20 +29,32 @@ struct aspeed_wdt {struct aspeed_wdt_config {u32 ext_pulse_width_mask; +u32 irq_shift; +u32 irq_mask; };static const struct aspeed_wdt_config ast2400_config = { .ext_pulse_width_mask =0xff , + .irq_shift =0 , + .irq_mask =0 , };static const struct aspeed_wdt_config ast2500_config = { .ext_pulse_width_mask =0xfffff , + .irq_shift =12 , + .irq_mask =GENMASK (31 ,12 ), +}; + +static const struct aspeed_wdt_config ast2600_config = { + .ext_pulse_width_mask =0xfffff , + .irq_shift =0 , + .irq_mask =GENMASK (31 ,10 ), };static const struct of_device_id aspeed_wdt_of_table[] = { { .compatible ="aspeed,ast2400-wdt" , .data = &ast2400_config }, { .compatible ="aspeed,ast2500-wdt" , .data = &ast2500_config }, - { .compatible ="aspeed,ast2600-wdt" , .data = &ast2500_config }, + { .compatible ="aspeed,ast2600-wdt" , .data = &ast2600_config }, { }, };MODULE_DEVICE_TABLE (of, aspeed_wdt_of_table);@@ -58,6 +73,7 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);#define WDT_CTRL_RESET_SYSTEM BIT(1)#define WDT_CTRL_ENABLE BIT(0)#define WDT_TIMEOUT_STATUS 0x10 +#define WDT_TIMEOUT_STATUS_IRQ BIT(2)#define WDT_TIMEOUT_STATUS_BOOT_SECONDARY BIT(1)#define WDT_CLEAR_TIMEOUT_STATUS 0x14#define WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION BIT(0)@@ -243,6 +259,17 @@ static const struct watchdog_info aspeed_wdt_info = { .identity = KBUILD_MODNAME, }; +static irqreturn_t aspeed_wdt_irq (int irq,void *arg) +{ +struct aspeed_wdt *wdt = arg; +u32 status =readl (wdt->base +WDT_TIMEOUT_STATUS ); + +if (status &WDT_TIMEOUT_STATUS_IRQ ) +panic ("Watchdog pre-timeout IRQ" ); + +return IRQ_NONE ; +} +static int aspeed_wdt_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;@@ -253,6 +280,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)const char *reset_type;u32 duration;u32 status; +u32 timeout =0 ;int ret; wdt =devm_kzalloc (dev,sizeof (*wdt),GFP_KERNEL );@@ -291,6 +319,27 @@ static int aspeed_wdt_probe(struct platform_device *pdev)if (of_device_is_compatible (np,"aspeed,ast2400-wdt" )) wdt->ctrl =WDT_CTRL_1MHZ_CLK ; +if (config->irq_mask) { +if (!of_property_read_u32 (np,"aspeed,pre-timeout-irq-us" , &timeout) && timeout) { +int irq =platform_get_irq (pdev,0 ); + +if (irq <0 ) { +dev_warn (dev,"Couldn't find IRQ: %d\n" , irq); + timeout =0 ; + }else { + ret =devm_request_irq (dev, irq, aspeed_wdt_irq,IRQF_SHARED , +dev_name (dev), wdt); +if (ret) { +dev_warn (dev,"Couldn't request IRQ:%d\n" , ret); + timeout =0 ; + }else { + wdt->ctrl |= ((timeout << config->irq_shift) & + config->irq_mask) |WDT_CTRL_WDT_INTR ; + } + } + } + } +/* * Control reset on a per-device basis to ensure the * host is not affected by a BMC reboot @@ -308,7 +357,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)else if (!strcmp (reset_type,"system" )) wdt->ctrl |=WDT_CTRL_RESET_MODE_FULL_CHIP |WDT_CTRL_RESET_SYSTEM ; -else if (strcmp (reset_type,"none" )) +else if (strcmp (reset_type,"none" ) && !timeout)return -EINVAL ; }if (of_property_read_bool (np,"aspeed,external-signal" ))Signature · 1 line
2.31.1
Quoted 6 lines · Guenter Roeck
Quoted 2 lines · Eddie James
Enable the pre-timeout interrupt if requested by device property.
I am not inclined to accept this patch without detailed explanation. Why would it make sense and/or be desirable to completely bypass the watchdog core with this pretimeout support ?
Sorry, I should add more detail.
It doesn't necessarily bypass the watchdog core. It can, if you specify reset-type="none". But if not, the watchdog will still fire at the appropriate time.
The purpose is to get a stack dump from a kernel panic rather than a hard reset from the watchdog. The interrupt will fire a certain number of microseconds (configurable by dts property) before the watchdog does. The interrupt handler then panics, and all the CPU stacks are dumped, so hopefully you can catch where another processor was stuck.
I can submit v2 with this information in the commit message and/or comments.
Thanks,
Eddie
Quoted 136 lines
Thanks,
GuenterQuoted 132 lines
Signed-off-by Eddie James <[email protected]>--- drivers/watchdog/aspeed_wdt.c | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-)drivers/watchdog/aspeed_wdt.c +51
-2@@ -5,11 +5,14 @@* Joel Stanley <[email protected]> */ +#include <linux/bits.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/watchdog.h> @@ -26,20 +29,32 @@ struct aspeed_wdt {struct aspeed_wdt_config {u32 ext_pulse_width_mask; +u32 irq_shift; +u32 irq_mask; };static const struct aspeed_wdt_config ast2400_config = { .ext_pulse_width_mask =0xff , + .irq_shift =0 , + .irq_mask =0 , };static const struct aspeed_wdt_config ast2500_config = { .ext_pulse_width_mask =0xfffff , + .irq_shift =12 , + .irq_mask =GENMASK (31 ,12 ), +}; + +static const struct aspeed_wdt_config ast2600_config = { + .ext_pulse_width_mask =0xfffff , + .irq_shift =0 , + .irq_mask =GENMASK (31 ,10 ), };static const struct of_device_id aspeed_wdt_of_table[] = { { .compatible ="aspeed,ast2400-wdt" , .data = &ast2400_config }, { .compatible ="aspeed,ast2500-wdt" , .data = &ast2500_config }, - { .compatible ="aspeed,ast2600-wdt" , .data = &ast2500_config }, + { .compatible ="aspeed,ast2600-wdt" , .data = &ast2600_config }, { }, };MODULE_DEVICE_TABLE (of, aspeed_wdt_of_table);@@ -58,6 +73,7 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);#define WDT_CTRL_RESET_SYSTEM BIT(1)#define WDT_CTRL_ENABLE BIT(0)#define WDT_TIMEOUT_STATUS 0x10 +#define WDT_TIMEOUT_STATUS_IRQ BIT(2)#define WDT_TIMEOUT_STATUS_BOOT_SECONDARY BIT(1)#define WDT_CLEAR_TIMEOUT_STATUS 0x14#define WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION BIT(0)@@ -243,6 +259,17 @@ static const struct watchdog_info aspeed_wdt_info = { .identity = KBUILD_MODNAME, }; +static irqreturn_t aspeed_wdt_irq (int irq,void *arg) +{ +struct aspeed_wdt *wdt = arg; +u32 status =readl (wdt->base +WDT_TIMEOUT_STATUS ); + +if (status &WDT_TIMEOUT_STATUS_IRQ ) +panic ("Watchdog pre-timeout IRQ" ); + +return IRQ_NONE ; +} +static int aspeed_wdt_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;@@ -253,6 +280,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)const char *reset_type;u32 duration;u32 status; +u32 timeout =0 ;int ret; wdt =devm_kzalloc (dev,sizeof (*wdt),GFP_KERNEL );@@ -291,6 +319,27 @@ static int aspeed_wdt_probe(struct platform_device *pdev)if (of_device_is_compatible (np,"aspeed,ast2400-wdt" )) wdt->ctrl =WDT_CTRL_1MHZ_CLK ; +if (config->irq_mask) { +if (!of_property_read_u32 (np,"aspeed,pre-timeout-irq-us" , &timeout) && timeout) { +int irq =platform_get_irq (pdev,0 ); + +if (irq <0 ) { +dev_warn (dev,"Couldn't find IRQ: %d\n" , irq); + timeout =0 ; + }else { + ret =devm_request_irq (dev, irq, aspeed_wdt_irq,IRQF_SHARED , +dev_name (dev), wdt); +if (ret) { +dev_warn (dev,"Couldn't request IRQ:%d\n" , ret); + timeout =0 ; + }else { + wdt->ctrl |= ((timeout << config->irq_shift) & + config->irq_mask) |WDT_CTRL_WDT_INTR ; + } + } + } + } +/* * Control reset on a per-device basis to ensure the * host is not affected by a BMC reboot @@ -308,7 +357,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)else if (!strcmp (reset_type,"system" )) wdt->ctrl |=WDT_CTRL_RESET_MODE_FULL_CHIP |WDT_CTRL_RESET_SYSTEM ; -else if (strcmp (reset_type,"none" )) +else if (strcmp (reset_type,"none" ) && !timeout)return -EINVAL ; }if (of_property_read_bool (np,"aspeed,external-signal" ))Signature · 1 line
2.31.1
Guenter Roeck
maintainerQuoted 10 lines · Eddie James
Quoted 6 lines · Guenter Roeck
Quoted 2 lines · Eddie James
Enable the pre-timeout interrupt if requested by device property.
I am not inclined to accept this patch without detailed explanation. Why would it make sense and/or be desirable to completely bypass the watchdog core with this pretimeout support ?
Quoted 9 lines
Sorry, I should add more detail.
It doesn't necessarily bypass the watchdog core. It can, if you specify reset-type="none". But if not, the watchdog will still fire at the appropriate time.
The purpose is to get a stack dump from a kernel panic rather than a hard reset from the watchdog. The interrupt will fire a certain number of microseconds (configurable by dts property) before the watchdog does. The interrupt handler then panics, and all the CPU stacks are dumped, so hopefully you can catch where another processor was stuck.
I can submit v2 with this information in the commit message and/or comments.
You did not answer the question why you do not use the pretimeout functionality supported by the watchdog core.
Guenter
Quoted 132 lines
Thanks,
Eddie
Quoted 127 lines
Thanks,
GuenterQuoted 123 lines
Signed-off-by Eddie James <[email protected]>---
?drivers/watchdog/aspeed_wdt.c| 53 +++++++++++++++++++++++++++++++++-- ? 1 file changed, 51 insertions(+), 2 deletions(-)drivers/watchdog/aspeed_wdt.c +0
-0@@ -5,11 +5,14 @@?? * Joel Stanley <[email protected]>
?? */
+#include <linux/bits.h>
? #include <linux/delay.h>
+#include <linux/interrupt.h>
? #include <linux/io.h>
? #include <linux/kernel.h>
? #include <linux/module.h>
? #include <linux/of.h>
+#include <linux/of_irq.h>
? #include <linux/platform_device.h>
? #include <linux/watchdog.h>drivers/watchdog/aspeed_wdt.c +13
-1@@ -26,20 +29,32 @@ struct aspeed_wdt { ? struct aspeed_wdt_config { ????? u32 ext_pulse_width_mask; +??? u32 irq_shift; +??? u32 irq_mask; ? }; ? static const struct aspeed_wdt_config ast2400_config = { ????? .ext_pulse_width_mask = 0xff, +??? .irq_shift = 0, +??? .irq_mask = 0, ? }; ? static const struct aspeed_wdt_config ast2500_config = { ????? .ext_pulse_width_mask = 0xfffff, +??? .irq_shift = 12, +??? .irq_mask = GENMASK(31, 12), +}; + +static const struct aspeed_wdt_config ast2600_config = { +??? .ext_pulse_width_mask = 0xfffff, +??? .irq_shift = 0, +??? .irq_mask = GENMASK(31, 10), ? }; ? static const struct of_device_id aspeed_wdt_of_table[] = { ????? { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_config }, ????? { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_config }, -??? { .compatible = "aspeed,ast2600-wdt", .data = &ast2500_config }, +??? { .compatible = "aspeed,ast2600-wdt", .data = &ast2600_config }, ????? { }, ? }; ? MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);@@ -58,6 +73,7 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); ? #define?? WDT_CTRL_RESET_SYSTEM??????? BIT(1) ? #define?? WDT_CTRL_ENABLE??????? BIT(0)? #define
WDT_TIMEOUT_STATUS???0x10
+#define??WDT_TIMEOUT_STATUS_IRQ??????? BIT(2)
? #define??WDT_TIMEOUT_STATUS_BOOT_SECONDARY??? BIT(1) ? #defineWDT_CLEAR_TIMEOUT_STATUS???0x14
? #define??WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION??? BIT(0)drivers/watchdog/aspeed_wdt.c +33
-0@@ -243,6 +259,17 @@ static const struct watchdog_info aspeed_wdt_info = { ????? .identity??? = KBUILD_MODNAME, ? }; +static irqreturn_t aspeed_wdt_irq (int irq,void *arg) +{ +??? struct aspeed_wdt *wdt = arg; +??? u32 status = readl(wdt->base + WDT_TIMEOUT_STATUS); + +??? if (status & WDT_TIMEOUT_STATUS_IRQ) +??????? panic("Watchdog pre-timeout IRQ"); + +??? return IRQ_NONE; +} + ? static int aspeed_wdt_probe(struct platform_device *pdev) ? { ????? struct device *dev = &pdev->dev;@@ -253,6 +280,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) ????? const char *reset_type; ????? u32 duration; ????? u32 status; +??? u32 timeout = 0; ????? int ret; ????? wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);@@ -291,6 +319,27 @@ static int aspeed_wdt_probe(struct platform_device *pdev) ????? if (of_device_is_compatible(np, "aspeed,ast2400-wdt")) ????????? wdt->ctrl = WDT_CTRL_1MHZ_CLK; +??? if (config->irq_mask) { +??????? if (!of_property_read_u32(np, "aspeed,pre-timeout-irq-us", &timeout) && timeout) { +??????????? int irq =? platform_get_irq(pdev, 0); + +??????????? if (irq < 0) { +??????????????? dev_warn(dev, "Couldn't find IRQ: %d\n", irq); +??????????????? timeout = 0; +??????????? } else { +??????????????? ret = devm_request_irq(dev, irq, aspeed_wdt_irq, IRQF_SHARED, +?????????????????????????????? dev_name(dev), wdt); +??????????????? if (ret) { +??????????????????? dev_warn(dev, "Couldn't request IRQ:%d\n", ret); +??????????????????? timeout = 0; +??????????????? } else { +??????????????????? wdt->ctrl |= ((timeout << config->irq_shift) & +????????????????????????????? config->irq_mask) | WDT_CTRL_WDT_INTR; +??????????????? } +??????????? } +??????? } +??? } +????? /*
?????? * Control reset on a per-device basis to ensure the ?????? * host is not affected by a BMC rebootdrivers/watchdog/aspeed_wdt.c +0
-0@@ -308,7 +357,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) ????????? else if (!strcmp(reset_type, "system"))?????????????
wdt->ctrl|=WDT_CTRL_RESET_MODE_FULL_CHIP| ??????????????????????WDT_CTRL_RESET_SYSTEM; -??????? else if (strcmp(reset_type, "none")) +??????? else if (strcmp(reset_type, "none")&& !timeout) ????????????? return-EINVAL;
????? }
????? if (of_property_read_bool(np, "aspeed,external-signal"))Signature · 1 line
2.31.1
Quoted 25 lines · Guenter Roeck
Quoted 24 lines · Eddie James
Quoted 6 lines · Guenter Roeck
Quoted 2 lines · Eddie James
Enable the pre-timeout interrupt if requested by device property.
I am not inclined to accept this patch without detailed explanation. Why would it make sense and/or be desirable to completely bypass the watchdog core with this pretimeout support ?
Sorry, I should add more detail.
It doesn't necessarily bypass the watchdog core. It can, if you specify reset-type="none". But if not, the watchdog will still fire at the appropriate time.
The purpose is to get a stack dump from a kernel panic rather than a hard reset from the watchdog. The interrupt will fire a certain number of microseconds (configurable by dts property) before the watchdog does. The interrupt handler then panics, and all the CPU stacks are dumped, so hopefully you can catch where another processor was stuck.
Quoted 7 lines
Quoted 3 lines
I can submit v2 with this information in the commit message and/or comments.
You did not answer the question why you do not use the pretimeout functionality
supported by the watchdog core.
I misunderstood your question and I wasn't actually aware of the pretimeout support in the core. I have sent v2 using the core pretimeout.
Thanks,
Eddie
Quoted 144 lines
Guenter
Quoted 140 lines
Thanks,
Eddie
Quoted 135 lines
Thanks,
GuenterQuoted 131 lines
Signed-off-by Eddie James <[email protected]>---
?drivers/watchdog/aspeed_wdt.c| 53
+++++++++++++++++++++++++++++++++--
? 1 file changed, 51 insertions(+), 2 deletions(-)drivers/watchdog/aspeed_wdt.c +0
-0@@ -5,11 +5,14 @@?? * Joel Stanley <[email protected]>
?? */
+#include <linux/bits.h>
? #include <linux/delay.h>
+#include <linux/interrupt.h>
? #include <linux/io.h>
? #include <linux/kernel.h>
? #include <linux/module.h>
? #include <linux/of.h>
+#include <linux/of_irq.h>
? #include <linux/platform_device.h>
? #include <linux/watchdog.h>drivers/watchdog/aspeed_wdt.c +13
-1@@ -26,20 +29,32 @@ struct aspeed_wdt { ? struct aspeed_wdt_config { ????? u32 ext_pulse_width_mask; +??? u32 irq_shift; +??? u32 irq_mask; ? }; ? static const struct aspeed_wdt_config ast2400_config = { ????? .ext_pulse_width_mask = 0xff, +??? .irq_shift = 0, +??? .irq_mask = 0, ? }; ? static const struct aspeed_wdt_config ast2500_config = { ????? .ext_pulse_width_mask = 0xfffff, +??? .irq_shift = 12, +??? .irq_mask = GENMASK(31, 12), +}; + +static const struct aspeed_wdt_config ast2600_config = { +??? .ext_pulse_width_mask = 0xfffff, +??? .irq_shift = 0, +??? .irq_mask = GENMASK(31, 10), ? }; ? static const struct of_device_id aspeed_wdt_of_table[] = { ????? { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_config }, ????? { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_config }, -??? { .compatible = "aspeed,ast2600-wdt", .data = &ast2500_config }, +??? { .compatible = "aspeed,ast2600-wdt", .data = &ast2600_config }, ????? { }, ? }; ? MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);@@ -58,6 +73,7 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); ? #define?? WDT_CTRL_RESET_SYSTEM??????? BIT(1) ? #define?? WDT_CTRL_ENABLE??????? BIT(0)? #define
WDT_TIMEOUT_STATUS???0x10
+#define??WDT_TIMEOUT_STATUS_IRQ??????? BIT(2)
? #define??WDT_TIMEOUT_STATUS_BOOT_SECONDARY??? BIT(1) ? #defineWDT_CLEAR_TIMEOUT_STATUS???0x14
? #define??WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTIONBIT(0)drivers/watchdog/aspeed_wdt.c +33
-0@@ -243,6 +259,17 @@ static const struct watchdog_info aspeed_wdt_info = { ????? .identity??? = KBUILD_MODNAME, ? }; +static irqreturn_t aspeed_wdt_irq (int irq,void *arg) +{ +??? struct aspeed_wdt *wdt = arg; +??? u32 status = readl(wdt->base + WDT_TIMEOUT_STATUS); + +??? if (status & WDT_TIMEOUT_STATUS_IRQ) +??????? panic("Watchdog pre-timeout IRQ"); + +??? return IRQ_NONE; +} + ? static int aspeed_wdt_probe(struct platform_device *pdev) ? { ????? struct device *dev = &pdev->dev;@@ -253,6 +280,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) ????? const char *reset_type; ????? u32 duration; ????? u32 status; +??? u32 timeout = 0; ????? int ret; ????? wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);@@ -291,6 +319,27 @@ static int aspeed_wdt_probe(struct platform_device *pdev) ????? if (of_device_is_compatible(np, "aspeed,ast2400-wdt")) ????????? wdt->ctrl = WDT_CTRL_1MHZ_CLK; +??? if (config->irq_mask) { +??????? if (!of_property_read_u32(np, "aspeed,pre-timeout-irq-us", &timeout) && timeout) { +??????????? int irq =? platform_get_irq(pdev, 0); + +??????????? if (irq < 0) { +??????????????? dev_warn(dev, "Couldn't find IRQ: %d\n", irq); +??????????????? timeout = 0; +??????????? } else { +??????????????? ret = devm_request_irq(dev, irq, aspeed_wdt_irq,IRQF_SHARED , +?????????????????????????????? dev_name(dev), wdt); +??????????????? if (ret) { +??????????????????? dev_warn(dev, "Couldn't request IRQ:%d\n", ret); +??????????????????? timeout = 0; +??????????????? } else { +??????????????????? wdt->ctrl |= ((timeout << config->irq_shift) & +????????????????????????????? config->irq_mask) | WDT_CTRL_WDT_INTR; +??????????????? } +??????????? } +??????? } +??? } +????? /*
?????? * Control reset on a per-device basis to ensure the ?????? * host is not affected by a BMC rebootdrivers/watchdog/aspeed_wdt.c +0
-0@@ -308,7 +357,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) ????????? else if (!strcmp(reset_type, "system"))?????????????
wdt->ctrl|=WDT_CTRL_RESET_MODE_FULL_CHIP| ??????????????????????WDT_CTRL_RESET_SYSTEM; -??????? else if (strcmp(reset_type, "none")) +??????? else if (strcmp(reset_type, "none")&& !timeout) ????????????? return-EINVAL;
????? }
????? if (of_property_read_bool(np, "aspeed,external-signal"))Signature · 1 line
2.31.1
PATCH 2/2 dt-bindings: watchdog: aspeed: Document aspeed,pre-timeout-irq-us
In reply to Eddie JamesDocument this new property for the pre-timeout interrupt.
--- Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt +6 -1
@@ -40,12 +40,17 @@ Optional properties: specified no external signal is sent. - aspeed,ext-pulse-duration: External signal pulse duration in microseconds -Optional properties for AST2500-compatible watchdogs: +Optional properties for AST2500 and AST2600 compatible watchdogs: - aspeed,ext-push-pull: If aspeed,external-signal is present, set the pin's drive type to push-pull. The default is open-drain. - aspeed,ext-active-high: If aspeed,external-signal is present and and the pin is configured as push-pull, then set the pulse polarity to active-high. The default is active-low. + - aspeed,pre-timeout-irq-us: If aspeed,pre-timeout-irq-us is non-zero, the + pre-timeout interrupt will be enabled for the + watchdog. The interrupt will fire the specified + number of microseconds before the watchdog expires + and trigger a kernel panic. Example:
Signature · 1 line
2.31.1
Re: [PATCH 2/2] dt-bindings: watchdog: aspeed: Document aspeed,pre-timeout-irq-us
Quoted 1 line · Eddie James
Document this new property for the pre-timeout interrupt.
Please convert bindings to DT schema first.
Best regards,
Krzysztof
Rob Herring
maintainerRe: [PATCH 2/2] dt-bindings: watchdog: aspeed: Document aspeed,pre-timeout-irq-us
In reply to Eddie JamesQuoted 17 lines · Eddie James
Document this new property for the pre-timeout interrupt.
Signed-off-by Eddie James <[email protected]>--- Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt +1
-1@@ -40,12 +40,17 @@ Optional properties: specified no external signal is sent. - aspeed,ext-pulse-duration: External signal pulse duration in microseconds -Optional properties for AST2500-compatible watchdogs: +Optional properties for AST2500 and AST2600 compatible watchdogs:
Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt Optional properties: · line 53
Quoted 10 lines
Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt +5
-0- aspeed,ext-push-pull: If aspeed,external-signal is present, set the pin's drive type to push-pull. The default is open-drain. - aspeed,ext-active-high: If aspeed,external-signal is present and and the pin is configured as push-pull, then set the pulse polarity to active-high. The default is active-low. + - aspeed,pre-timeout-irq-us: If aspeed,pre-timeout-irq-us is non-zero, the + pre-timeout interrupt will be enabled for the + watchdog. The interrupt will fire the specified + number of microseconds before the watchdog expires + and trigger a kernel panic.
A pre-timeout interrupt is fairly common. Come up with a common property please. You'll need to be clear if the time is from wdog restart or time before final timeout.
Rob
Guenter Roeck
maintainerRe: [PATCH 2/2] dt-bindings: watchdog: aspeed: Document aspeed,pre-timeout-irq-us
Quoted 16 lines · Rob Herring
Quoted 15 lines · Eddie James
Document this new property for the pre-timeout interrupt.
Signed-off-by Eddie James <[email protected]>--- Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt +0
-0@@ -40,12 +40,17 @@ Optional properties: specified no external signal is sent. - aspeed,ext-pulse-duration: External signal pulse duration in microseconds
Quoted 17 lines
Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt Optional properties: · line 53
Quoted 12 lines
Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt +6
-1-Optional properties for AST2500-compatible watchdogs: +Optional properties for AST2500 and AST2600 compatible watchdogs: - aspeed,ext-push-pull: If aspeed,external-signal is present, set the pin's drive type to push-pull. The default is open-drain. - aspeed,ext-active-high: If aspeed,external-signal is present and and the pin is configured as push-pull, then set the pulse polarity to active-high. The default is active-low. + - aspeed,pre-timeout-irq-us: If aspeed,pre-timeout-irq-us is non-zero, the + pre-timeout interrupt will be enabled for the + watchdog. The interrupt will fire the specified + number of microseconds before the watchdog expires + and trigger a kernel panic.A pre-timeout interrupt is fairly common. Come up with a common property please. You'll need to be clear if the time is from wdog restart or time before final timeout.
It would be nice if it would match the semantics of the existing pretimeout attribute in the watchdog core.
Guenter