Certain Altera FPGAs have an ARM-based Hard Processor System (HPS) that includes two DesignWare Watchdog Timer peripherals. Problems occur if both are enabled in the device tree as the "dw_wdt" driver only supports a single device, using a static variable (`dw_wdt`) to hold its state. Typically, the timer queue gets corrupted, leading to a kernel Oops. Use bit 1 of `dw_wdt.state` to indicate that a device has already been probed, and reject attempts to probe extra devices. Signed-off-by: Ian Abbott <abbotti@xxxxxxxxx> --- drivers/watchdog/dw_wdt.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 249ef09..cece633 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c @@ -61,6 +61,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " /* dw_wdt.state bit numbers */ #define DW_WDT_IN_USE 0 +#define DW_WDT_PROBED 1 static struct { void __iomem *regs; @@ -335,17 +336,26 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) int ret; struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (test_and_set_bit(DW_WDT_PROBED, &dw_wdt.state)) { + pr_err("This driver only supports one device\n"); + return -ENODEV; + } + dw_wdt.regs = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(dw_wdt.regs)) - return PTR_ERR(dw_wdt.regs); + if (IS_ERR(dw_wdt.regs)) { + ret = PTR_ERR(dw_wdt.regs); + goto out_unmark_probed; + } dw_wdt.clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dw_wdt.clk)) - return PTR_ERR(dw_wdt.clk); + if (IS_ERR(dw_wdt.clk)) { + ret = PTR_ERR(dw_wdt.clk); + goto out_unmark_probed; + } ret = clk_prepare_enable(dw_wdt.clk); if (ret) - return ret; + goto out_unmark_probed; ret = misc_register(&dw_wdt_miscdev); if (ret) @@ -366,6 +376,9 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) out_disable_clk: clk_disable_unprepare(dw_wdt.clk); +out_unmark_probed: + clear_bit(DW_WDT_PROBED, &dw_wdt.state); + return ret; } @@ -377,6 +390,8 @@ static int dw_wdt_drv_remove(struct platform_device *pdev) clk_disable_unprepare(dw_wdt.clk); + clear_bit(DW_WDT_PROBED, &dw_wdt.state); + return 0; } -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html