Only one watchdog could be used by this driver. Create driver private data structure and move there all variables for one instance. Signed-off-by: Michal Simek --- drivers/watchdog/of_xilinx_wdt.c | 97 +++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index 1f7ad91..d28bd3f 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c @@ -47,30 +47,27 @@ struct xwdt_device { void __iomem *base; u32 wdt_interval; + spinlock_t spinlock; + struct watchdog_device xilinx_wdt_wdd; }; -static struct xwdt_device xdev; - -static u32 timeout; - -static DEFINE_SPINLOCK(spinlock); - static int xilinx_wdt_start(struct watchdog_device *wdd) { u32 control_status_reg; + struct xwdt_device *xdev = watchdog_get_drvdata(wdd); - spin_lock(&spinlock); + spin_lock(&xdev->spinlock); /* Clean previous status and enable the watchdog timer */ - control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); + control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK), - xdev.base + XWT_TWCSR0_OFFSET); + xdev->base + XWT_TWCSR0_OFFSET); - iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET); + iowrite32(XWT_CSRX_EWDT2_MASK, xdev->base + XWT_TWCSR1_OFFSET); - spin_unlock(&spinlock); + spin_unlock(&xdev->spinlock); return 0; } @@ -78,17 +75,18 @@ static int xilinx_wdt_start(struct watchdog_device *wdd) static int xilinx_wdt_stop(struct watchdog_device *wdd) { u32 control_status_reg; + struct xwdt_device *xdev = watchdog_get_drvdata(wdd); - spin_lock(&spinlock); + spin_lock(&xdev->spinlock); - control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); + control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK), - xdev.base + XWT_TWCSR0_OFFSET); + xdev->base + XWT_TWCSR0_OFFSET); - iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET); + iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET); - spin_unlock(&spinlock); + spin_unlock(&xdev->spinlock); pr_info("Stopped!\n"); return 0; @@ -97,14 +95,15 @@ static int xilinx_wdt_stop(struct watchdog_device *wdd) static int xilinx_wdt_keepalive(struct watchdog_device *wdd) { u32 control_status_reg; + struct xwdt_device *xdev = watchdog_get_drvdata(wdd); - spin_lock(&spinlock); + spin_lock(&xdev->spinlock); - control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); + control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); - iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET); + iowrite32(control_status_reg, xdev->base + XWT_TWCSR0_OFFSET); - spin_unlock(&spinlock); + spin_unlock(&xdev->spinlock); return 0; } @@ -123,29 +122,24 @@ static const struct watchdog_ops xilinx_wdt_ops = { .ping = xilinx_wdt_keepalive, }; -static struct watchdog_device xilinx_wdt_wdd = { - .info = &xilinx_wdt_ident, - .ops = &xilinx_wdt_ops, -}; - -static u32 xwdt_selftest(void) +static u32 xwdt_selftest(struct xwdt_device *xdev) { int i; u32 timer_value1; u32 timer_value2; - spin_lock(&spinlock); + spin_lock(&xdev->spinlock); - timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET); - timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET); + timer_value1 = ioread32(xdev->base + XWT_TBR_OFFSET); + timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET); for (i = 0; ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) && (timer_value2 == timer_value1)); i++) { - timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET); + timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET); } - spin_unlock(&spinlock); + spin_unlock(&xdev->spinlock); if (timer_value2 != timer_value1) return ~XWT_TIMER_FAILED; @@ -159,12 +153,23 @@ static int xwdt_probe(struct platform_device *pdev) u32 *tmptr; u32 *pfreq; struct resource *res; + struct xwdt_device *xdev; bool no_timeout = false; + struct watchdog_device *xilinx_wdt_wdd; + + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); + if (!xdev) + return -ENOMEM; + + xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd; + xilinx_wdt_wdd->info = &xilinx_wdt_ident; + xilinx_wdt_wdd->ops = &xilinx_wdt_ops; + xilinx_wdt_wdd->parent = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - xdev.base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(xdev.base)) - return PTR_ERR(xdev.base); + xdev->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xdev->base)) + return PTR_ERR(xdev->base); pfreq = (u32 *)of_get_property(pdev->dev.of_node, "clock-frequency", NULL); @@ -180,14 +185,14 @@ static int xwdt_probe(struct platform_device *pdev) pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n"); no_timeout = true; } else { - xdev.wdt_interval = *tmptr; + xdev->wdt_interval = *tmptr; } tmptr = (u32 *)of_get_property(pdev->dev.of_node, "xlnx,wdt-enable-once", NULL); if (tmptr == NULL) { pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n"); - watchdog_set_nowayout(&xilinx_wdt_wdd, true); + watchdog_set_nowayout(xilinx_wdt_wdd, true); } /* @@ -195,29 +200,37 @@ static int xwdt_probe(struct platform_device *pdev) * ignored (interrupt), reset is only generated at second wdt overflow */ if (!no_timeout) - timeout = 2 * ((1<timeout = 2 * ((1 << xdev->wdt_interval) / + *pfreq); + + spin_lock_init(&xdev->spinlock); + watchdog_set_drvdata(xilinx_wdt_wdd, xdev); - rc = xwdt_selftest(); + rc = xwdt_selftest(xdev); if (rc == XWT_TIMER_FAILED) { pr_err("SelfTest routine error!\n"); return rc; } - rc = watchdog_register_device(&xilinx_wdt_wdd); + rc = watchdog_register_device(xilinx_wdt_wdd); if (rc) { pr_err("cannot register watchdog (err=%d)\n", rc); return rc; } dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", - xdev.base, timeout); + xdev->base, xilinx_wdt_wdd->timeout); + + platform_set_drvdata(pdev, xdev); return 0; } -static int xwdt_remove(struct platform_device *dev) +static int xwdt_remove(struct platform_device *pdev) { - watchdog_unregister_device(&xilinx_wdt_wdd); + struct xwdt_device *xdev = platform_get_drvdata(pdev); + + watchdog_unregister_device(&xdev->xilinx_wdt_wdd); return 0; } -- 1.8.2.3