On 9/30/22 03:35, Krzysztof Kozlowski wrote:
On 27/09/2022 13:02, Srinivas Neeli wrote:
+
+static void xwwdt_clk_disable_unprepare(void *data)
+{
+ clk_disable_unprepare(data);
If watchdog is stopped and then device unbound, don't you have double
disable? IOW, where is matching clk_enable?
After looking into the entire driver code, I see the problem:
clk_disable() is called in the stop function. That is wrong;
if the clock is disabled in the stop function, it needs to be
enabled in the start function (which is not currently the case).
In that situation, using the devm_ callback when unloading the
driver isn't possible (or, rather, would require checking if the
clock is enabled before disabling it).
Thanks,
Guenter
+}
+
+static const struct watchdog_info xilinx_wwdt_ident = {
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_SETTIMEOUT,
+ .firmware_version = 1,
+ .identity = "xlnx_window watchdog",
+};
+
+static const struct watchdog_ops xilinx_wwdt_ops = {
+ .owner = THIS_MODULE,
+ .start = xilinx_wwdt_start,
+ .stop = xilinx_wwdt_stop,
+ .set_timeout = xilinx_wwdt_set_timeout,
+ .ping = xilinx_wwdt_keepalive,
+};
+
+static int xwwdt_probe(struct platform_device *pdev)
+{
+ struct watchdog_device *xilinx_wwdt_wdd;
+ struct device *dev = &pdev->dev;
+ struct xwwdt_device *xdev;
+ int ret;
+
+ xdev = devm_kzalloc(dev, sizeof(*xdev), GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ xilinx_wwdt_wdd = &xdev->xilinx_wwdt_wdd;
+ xilinx_wwdt_wdd->info = &xilinx_wwdt_ident;
+ xilinx_wwdt_wdd->ops = &xilinx_wwdt_ops;
+ xilinx_wwdt_wdd->parent = dev;
+
+ xdev->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(xdev->base))
+ return PTR_ERR(xdev->base);
+
+ xdev->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(xdev->clk))
+ return PTR_ERR(xdev->clk);
+
+ xdev->freq = clk_get_rate(xdev->clk);
+ if (!xdev->freq)
+ return -EINVAL;
+
+ ret = clk_prepare_enable(xdev->clk);
+ if (ret) {
+ dev_err(dev, "unable to enable clock\n");
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(dev, xwwdt_clk_disable_unprepare,
+ xdev->clk);
+ if (ret)
+ return ret;
+
+ xilinx_wwdt_wdd->timeout = XWWDT_DEFAULT_TIMEOUT;
+ xilinx_wwdt_wdd->min_timeout = XWWDT_MIN_TIMEOUT;
+ xilinx_wwdt_wdd->max_timeout = XWWDT_MAX_TIMEOUT;
+
+ ret = watchdog_init_timeout(xilinx_wwdt_wdd,
+ xwwdt_timeout, &pdev->dev);
+ if (ret)
+ dev_info(&pdev->dev, "Configured default timeout value\n");
+
+ spin_lock_init(&xdev->spinlock);
+ watchdog_set_drvdata(xilinx_wwdt_wdd, xdev);
+
+ ret = devm_watchdog_register_device(dev, xilinx_wwdt_wdd);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "Xilinx window watchdog Timer with timeout %ds\n",
+ xilinx_wwdt_wdd->timeout);
+
+ return 0;
+}
+
+static const struct of_device_id xwwdt_of_match[] = {
+ { .compatible = "xlnx,versal-wwdt-1.0", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xwwdt_of_match);
+
+static struct platform_driver xwwdt_driver = {
+ .probe = xwwdt_probe,
+ .driver = {
+ .name = "Xilinx window watchdog",
Do you see spaces in other names of drivers?
Best regards,
Krzysztof