From: Frieder Schrempf <[email protected]> blk_post_probe() binds a UCLASS_PARTITION child for each partition found on the device. Removing the block device removes these children, but does not unbind them. When the block device is probed again, a second set of partition devices is bound next to the first one.
This happens for example when the probe of a block device fails in the EVT_DM_POST_PROBE event and is retried later. The EFI disk code then iterates over all children and tries to install a second EFI handle with the same device path for the stale partition device, which fails with EFI_ALREADY_STARTED: Adding partition for [email protected]:1 failed switch to partitions #0, ERROR As every further probe adds another set of partition devices, the block device can't be used anymore until the next reset. This was seen on an i.MX93 board where a single failed read during the first probe of the SD card made it unusable for the rest of the boot. Unbind the partition devices in the pre_remove hook of the block uclass, so that they are bound and unbound together with the probe and remove of the block device. When only some devices are removed, like before booting an OS, the partition devices don't match the remove flags and are still active at this point, so remove them first. Fixes: bf76031d19fa ("dm: blk: add a device-probe hook for scanning disk partitions") Assisted-by: LLM Signed-off-by: Frieder Schrempf <[email protected]> --- drivers/block/blk-uclass.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 37d87be3a57..cf6357d3041 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -841,9 +841,31 @@ static int blk_post_probe(struct udevice *dev) return 0; } +static int blk_pre_remove(struct udevice *dev) +{ + struct driver *drv = DM_DRIVER_GET(blk_partition); + int ret; + + if (!CONFIG_IS_ENABLED(PARTITIONS) || !blk_enabled()) + return 0; + + /* + * The partition devices are bound in blk_post_probe(), so unbind them + * here. Otherwise the next probe adds a second set of them. They are + * still active if the remove flags don't match their driver, so + * remove them first. + */ + ret = device_chld_remove(dev, drv, DM_REMOVE_NORMAL); + if (ret) + return ret; + + return device_chld_unbind(dev, drv); +} + UCLASS_DRIVER(blk) = { .id = UCLASS_BLK, .name = "blk", .post_probe = blk_post_probe, + .pre_remove = blk_pre_remove, .per_device_plat_auto = sizeof(struct blk_desc), }; -- 2.55.0
