ARM: at91: pm: fix imbalanced reference counter for ethernet devices
[ Upstream commit ccd4923d18d5698a5910d516646ce125b9155d47 ]
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: b7fc72c633
("ARM: at91: pm: add quirks for pm")
Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Link: https://lore.kernel.org/r/20230518062511.2988500-1-claudiu.beznea@microchip.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
c97f30d215
commit
4b8ebe5393
@ -334,16 +334,14 @@ static bool at91_pm_eth_quirk_is_valid(struct at91_pm_quirk_eth *eth)
|
|||||||
pdev = of_find_device_by_node(eth->np);
|
pdev = of_find_device_by_node(eth->np);
|
||||||
if (!pdev)
|
if (!pdev)
|
||||||
return false;
|
return false;
|
||||||
|
/* put_device(eth->dev) is called at the end of suspend. */
|
||||||
eth->dev = &pdev->dev;
|
eth->dev = &pdev->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No quirks if device isn't a wakeup source. */
|
/* No quirks if device isn't a wakeup source. */
|
||||||
if (!device_may_wakeup(eth->dev)) {
|
if (!device_may_wakeup(eth->dev))
|
||||||
put_device(eth->dev);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
/* put_device(eth->dev) is called at the end of suspend. */
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,14 +437,14 @@ static int at91_pm_config_quirks(bool suspend)
|
|||||||
pr_err("AT91: PM: failed to enable %s clocks\n",
|
pr_err("AT91: PM: failed to enable %s clocks\n",
|
||||||
j == AT91_PM_G_ETH ? "geth" : "eth");
|
j == AT91_PM_G_ETH ? "geth" : "eth");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Release the reference to eth->dev taken in
|
|
||||||
* at91_pm_eth_quirk_is_valid().
|
|
||||||
*/
|
|
||||||
put_device(eth->dev);
|
|
||||||
eth->dev = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release the reference to eth->dev taken in
|
||||||
|
* at91_pm_eth_quirk_is_valid().
|
||||||
|
*/
|
||||||
|
put_device(eth->dev);
|
||||||
|
eth->dev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user