On 9/29/26 1:59 PM, Sean Anderson wrote:
Normally, all child devices are removed before their parent is removed. However, mdio muxes are not direct children of their parents, so they can stick around even when their parent has been removed. This can cause crashes when the mux tries to access the parent bus. Fix this by listening for device removals. When an MDIO bus is removed, we remove any child that has that bus as a parent. It's possible we may fail to remove a child if there are multiple children of a bus and the first child fails to remove. However, there are no such configurations in-tree so I went with a simpler approach. Fixes: 8880edba06d5 ("net: add MDIO_MUX DM class") Signed-off-by: Sean Anderson <[email protected]> --- drivers/net/Kconfig | 1 + net/mdio-mux-uclass.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c057504cf66..5124c4a644e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -30,6 +30,7 @@ config DM_MDIOconfig DM_MDIO_MUXbool "Enable Driver Model for MDIO MUX devices" + select DM_EVENT depends on DM_MDIO help Enable driver model for MDIO MUX devices diff --git a/net/mdio-mux-uclass.c b/net/mdio-mux-uclass.c index 14143ca0ab6..a45575f526c 100644 --- a/net/mdio-mux-uclass.c +++ b/net/mdio-mux-uclass.c @@ -7,6 +7,7 @@ #include <dm.h> #include <log.h> #include <miiphy.h> +#include <dm/device_compat.h> #include <dm/device-internal.h> #include <dm/uclass-internal.h> #include <dm/lists.h> @@ -231,3 +232,31 @@ UCLASS_DRIVER(mdio_mux) = { .per_device_auto = sizeof(struct mdio_mux_perdev_priv), .per_child_plat_auto = sizeof(struct mdio_mux_ch_data), }; + +static int dm_mdio_mux_parent_pre_remove(void *ctx, struct event *event) +{ + struct udevice *mdio_parent = event->data.dm.dev; + struct udevice *mux, *mux_next; + struct uclass *uc; + int ret; + + if (device_get_uclass_id(mdio_parent) != UCLASS_MDIO) + return 0; + + if (uclass_get(UCLASS_MDIO_MUX, &uc)) + return 0; + + uclass_foreach_dev_safe(mux, mux_next, uc) { + if (mmux_get_parent_mdio(mux) != mdio_parent)
This needs a check for device_active() which I will add in v2. --Sean
+ continue; + + dev_dbg(mdio_parent, "removing %s %s\n", mux->driver->name, + mux->name); + ret = device_remove(mux, DM_REMOVE_NORMAL); + if (ret) + return ret; + } + + return 0; +} +EVENT_SPY_FULL(EVT_DM_PRE_REMOVE, dm_mdio_mux_parent_pre_remove);
