diff options
author | Thierry Reding <treding@nvidia.com> | 2020-08-06 17:36:50 +0200 |
---|---|---|
committer | Rob Herring <robh@kernel.org> | 2020-08-17 20:19:35 -0600 |
commit | 70a29209f67cf7dfa7c04975b3261e127694a4e7 (patch) | |
tree | bb5946727c7493004a1e67889506f41f40c922f4 /drivers/of | |
parent | 1c5711876b32470ba5983f9aa9b2a25dd5bc9639 (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.c | 2 |
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); } } |