Current implementation leaves wakeup enabled in the .remove() and the error path of .probe(), which results in a memory leak. Fix it by adding device_init_wakeup(&pdev->dev, 0) calls. This bug has been found by an experimental static analysis tool that we are developing. Fixes: 9fedc9f1b18f ("rtc-at91sam9 fixes") Signed-off-by: Joe Hattori <joe@xxxxxxxxxxxxxxxxxxxxx> --- drivers/rtc/rtc-at91sam9.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 15b21da2788f..539565c0c888 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -358,31 +358,36 @@ static int at91_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); rtc->rtt = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(rtc->rtt)) - return PTR_ERR(rtc->rtt); + if (IS_ERR(rtc->rtt)) { + ret = PTR_ERR(rtc->rtt); + goto err_disable_wakeup; + } ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, "atmel,rtt-rtc-time-reg", 1, 0, &args); if (ret) - return ret; + goto err_disable_wakeup; rtc->gpbr = syscon_node_to_regmap(args.np); of_node_put(args.np); rtc->gpbr_offset = args.args[0]; if (IS_ERR(rtc->gpbr)) { dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_disable_wakeup; } rtc->sclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(rtc->sclk)) - return PTR_ERR(rtc->sclk); + if (IS_ERR(rtc->sclk)) { + ret = PTR_ERR(rtc->sclk); + goto err_disable_wakeup; + } ret = clk_prepare_enable(rtc->sclk); if (ret) { dev_err(&pdev->dev, "Could not enable slow clock\n"); - return ret; + goto err_disable_wakeup; } sclk_rate = clk_get_rate(rtc->sclk); @@ -432,10 +437,15 @@ static int at91_rtc_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "%s: SET TIME!\n", dev_name(&rtc->rtcdev->dev)); - return devm_rtc_register_device(rtc->rtcdev); + ret = devm_rtc_register_device(rtc->rtcdev); + if (ret) + goto err_clk; + return 0; err_clk: clk_disable_unprepare(rtc->sclk); +err_disable_wakeup: + device_init_wakeup(&pdev->dev, 0); return ret; } @@ -452,6 +462,7 @@ static void at91_rtc_remove(struct platform_device *pdev) rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); clk_disable_unprepare(rtc->sclk); + device_init_wakeup(&pdev->dev, 0); } static void at91_rtc_shutdown(struct platform_device *pdev) -- 2.34.1