diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index cd53c170171..b7402d7042a 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -457,6 +457,10 @@ mux-control-names = "mux0"; }; + multimatch-test { + compatible = "sandbox,multimatch-test"; + }; + phy_provider0: gen_phy@0 { compatible = "sandbox,phy"; #phy-cells = <1>; diff --git a/drivers/core/lists.c b/drivers/core/lists.c index c7be504b6fc..2545dc142f6 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -204,10 +204,8 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, const struct udevice_id *id; struct driver *entry; struct udevice *dev; - bool found = false; const char *name, *compat_list, *compat; int compat_length, i; - int result = 0; int ret = 0; if (devp) @@ -237,55 +235,56 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, log_debug(" - attempt to match compatible string '%s'\n", compat); - id = NULL; for (entry = driver; entry != driver + n_ents; entry++) { + /* Search for drivers with matching drv or existing of_match */ if (drv) { if (drv != entry) continue; - if (!entry->of_match) - break; + } else if (!entry->of_match) { + continue; } - ret = driver_check_compatible(entry->of_match, &id, - compat); - if (!ret) - break; - } - if (entry == driver + n_ents) - continue; - if (pre_reloc_only) { - if (!ofnode_pre_reloc(node) && - !(entry->flags & DM_FLAG_PRE_RELOC)) { - log_debug("Skipping device pre-relocation\n"); - return 0; + id = NULL; + if (entry->of_match) { + ret = driver_check_compatible(entry->of_match, &id, + compat); + if (ret) + continue; + log_debug(" - found match at driver '%s' for '%s'\n", + entry->name, id->compatible); + } + + if (pre_reloc_only) { + if (!ofnode_pre_reloc(node) && + !(entry->flags & DM_FLAG_PRE_RELOC)) { + log_debug("Skipping device pre-relocation\n"); + return 0; + } + } + + ret = device_bind_with_driver_data(parent, entry, name, + id ? id->data : 0, node, + &dev); + if (!drv && ret == -ENODEV) { + log_debug(" - Driver '%s' refuses to bind\n", entry->name); + continue; + } + if (ret) { + dm_warn("Error binding driver '%s': %d\n", entry->name, + ret); + return log_msg_ret("bind", ret); } - } - if (entry->of_match) - log_debug(" - found match at driver '%s' for '%s'\n", - entry->name, id->compatible); - ret = device_bind_with_driver_data(parent, entry, name, - id ? id->data : 0, node, - &dev); - if (ret == -ENODEV) { - log_debug("Driver '%s' refuses to bind\n", entry->name); - continue; - } - if (ret) { - dm_warn("Error binding driver '%s': %d\n", entry->name, - ret); - return log_msg_ret("bind", ret); - } else { - found = true; if (devp) *devp = dev; + + return 0; } - break; } - if (!found && !result && ret != -ENODEV) + if (ret != -ENODEV) log_debug("No match for node '%s'\n", name); - return result; + return 0; } #endif diff --git a/test/dm/core.c b/test/dm/core.c index 53693f4f7ed..78ee14af228 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -1410,3 +1410,18 @@ static int dm_test_try_first_device(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_try_first_device, 0); + +/* Test that all drivers are iterated when bind returns -ENODEV */ +static int dm_test_multimatch(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_find_device_by_name(UCLASS_TEST, "multimatch-test", + &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("test_multimatch_second", dev->driver->name); + ut_asserteq(2, dm_testdrv_op_count[DM_TEST_OP_BIND]); + + return 0; +} +DM_TEST(dm_test_multimatch, UTF_SCAN_FDT); diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c index 759de3a5f77..d628a6d766f 100644 --- a/test/dm/test-driver.c +++ b/test/dm/test-driver.c @@ -197,3 +197,29 @@ U_BOOT_DRIVER(test_act_dma_vital_clk_drv) = { .unbind = test_manual_unbind, .flags = DM_FLAG_VITAL | DM_FLAG_ACTIVE_DMA, }; + +static int test_multimatch_first_bind(struct udevice *dev) +{ + dm_testdrv_op_count[DM_TEST_OP_BIND]++; + + return -ENODEV; +} + +static const struct udevice_id test_multimatch_ids[] = { + { .compatible = "sandbox,multimatch-test" }, + { } +}; + +U_BOOT_DRIVER(test_multimatch_first) = { + .name = "test_multimatch_first", + .id = UCLASS_TEST, + .of_match = test_multimatch_ids, + .bind = test_multimatch_first_bind, +}; + +U_BOOT_DRIVER(test_multimatch_second) = { + .name = "test_multimatch_second", + .id = UCLASS_TEST, + .of_match = test_multimatch_ids, + .bind = test_manual_bind, +};