summaryrefslogtreecommitdiff
path: root/drivers/of
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2020-08-06 17:36:50 +0200
committerRob Herring <robh@kernel.org>2020-08-17 20:19:35 -0600
commit70a29209f67cf7dfa7c04975b3261e127694a4e7 (patch)
treebb5946727c7493004a1e67889506f41f40c922f4 /drivers/of
parent1c5711876b32470ba5983f9aa9b2a25dd5bc9639 (diff)
of: platform: Destroy child devices symmetrically
Iterate over child devices in reverse when unpopulating a platform device to make this step symmetrical with the population step. This fixes an issue in the Tegra DRM driver where upon module unload the DPAUX controller tries to unregister an I2C controller but will end up waiting indefinitely because one of the SOR devices is keeping a reference to it. Since the SOR devices are instantiated after the DPAUX devices, they would only be removed (and hence release their reference to the I2C controller) after the DPAUX devices have been removed. While destroying the child devices in reverse order helps in this situation, it isn't fully safe to do so either. An even better way would be for the child devices to be reordered to match the probe order, which would work irrespective of the instantiation order. However, reordering by probe order would be fairly complicated and doesn't fix any known issues, so we'll go with the simpler fix for now. Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://lore.kernel.org/r/20200806153650.3883530-1-thierry.reding@gmail.com Signed-off-by: Rob Herring <robh@kernel.org>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/platform.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 071f04da32c8..b557a0fcd4ba 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -590,7 +590,7 @@ EXPORT_SYMBOL_GPL(of_platform_device_destroy);
void of_platform_depopulate(struct device *parent)
{
if (parent->of_node && of_node_check_flag(parent->of_node, OF_POPULATED_BUS)) {
- device_for_each_child(parent, NULL, of_platform_device_destroy);
+ device_for_each_child_reverse(parent, NULL, of_platform_device_destroy);
of_node_clear_flag(parent->of_node, OF_POPULATED_BUS);
}
}