Skip to content

Commit ccd4923

Browse files
committed
ARM: at91: pm: fix imbalanced reference counter for ethernet devices
The of_find_device_by_node() function is returning a struct platform_device object with the embedded struct device member's reference counter incremented. This needs to be dropped when done with the platform device returned by of_find_device_by_node(). at91_pm_eth_quirk_is_valid() calls of_find_device_by_node() on suspend and resume path. On suspend it calls of_find_device_by_node() and on resume and failure paths it drops the counter of struct platform_device::dev. In case ethernet device may not wakeup there is a put_device() on at91_pm_eth_quirk_is_valid() which is wrong as it colides with put_device() on resume path leading to the reference counter of struct device embedded in struct platform_device to be messed, stack trace to be displayed (after 5 consecutive suspend/resume cycles) and execution to hang. Along with this the error path of at91_pm_config_quirks() had been also adapted to decrement propertly the reference counter of struct device embedded in struct platform_device. Fixes: b7fc72c ("ARM: at91: pm: add quirks for pm") Signed-off-by: Claudiu Beznea <[email protected]> Acked-by: Nicolas Ferre <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent ac9a786 commit ccd4923

File tree

1 file changed

+9
-11
lines changed
  • arch/arm/mach-at91

1 file changed

+9
-11
lines changed

arch/arm/mach-at91/pm.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -334,16 +334,14 @@ static bool at91_pm_eth_quirk_is_valid(struct at91_pm_quirk_eth *eth)
334334
pdev = of_find_device_by_node(eth->np);
335335
if (!pdev)
336336
return false;
337+
/* put_device(eth->dev) is called at the end of suspend. */
337338
eth->dev = &pdev->dev;
338339
}
339340

340341
/* No quirks if device isn't a wakeup source. */
341-
if (!device_may_wakeup(eth->dev)) {
342-
put_device(eth->dev);
342+
if (!device_may_wakeup(eth->dev))
343343
return false;
344-
}
345344

346-
/* put_device(eth->dev) is called at the end of suspend. */
347345
return true;
348346
}
349347

@@ -439,14 +437,14 @@ static int at91_pm_config_quirks(bool suspend)
439437
pr_err("AT91: PM: failed to enable %s clocks\n",
440438
j == AT91_PM_G_ETH ? "geth" : "eth");
441439
}
442-
} else {
443-
/*
444-
* Release the reference to eth->dev taken in
445-
* at91_pm_eth_quirk_is_valid().
446-
*/
447-
put_device(eth->dev);
448-
eth->dev = NULL;
449440
}
441+
442+
/*
443+
* Release the reference to eth->dev taken in
444+
* at91_pm_eth_quirk_is_valid().
445+
*/
446+
put_device(eth->dev);
447+
eth->dev = NULL;
450448
}
451449

452450
return ret;

0 commit comments

Comments
 (0)