summaryrefslogtreecommitdiff
path: root/lib/utils
diff options
context:
space:
mode:
authorSamuel Holland <[email protected]>2025-02-19 12:42:51 -0800
committerAnup Patel <[email protected]>2025-03-24 16:37:06 +0530
commit0ffe265fd969f5ac689c820a4b40a99cd2f1e9a9 (patch)
tree404885df7a5483efcb734e3f75ad2eadc5b0782b /lib/utils
parentb2e8e6986d676005f23fc5e3b3845b027fc4330f (diff)
lib: utils/fdt: Respect compatible string fallback priority
When matching drivers to DT nodes, always match all drivers against the first compatible string before considering fallback compatible strings. This ensures the most specific match is always selected, regardless of the order of the drivers or match structures, as long as no compatible string appears in multiple match structures. Fixes: 1ccc52c427f3 ("lib: utils/fdt: Add helpers for generic driver initialization") Signed-off-by: Samuel Holland <[email protected]> Reviewed-by: Anup Patel <[email protected]>
Diffstat (limited to 'lib/utils')
-rw-r--r--lib/utils/fdt/fdt_driver.c46
1 files changed, 25 insertions, 21 deletions
diff --git a/lib/utils/fdt/fdt_driver.c b/lib/utils/fdt/fdt_driver.c
index f6707c0e..39385ce9 100644
--- a/lib/utils/fdt/fdt_driver.c
+++ b/lib/utils/fdt/fdt_driver.c
@@ -15,39 +15,43 @@ int fdt_driver_init_by_offset(const void *fdt, int nodeoff,
{
const struct fdt_driver *driver;
const struct fdt_match *match;
- const void *prop;
- int len, rc;
+ int compat_len, prop_len, rc;
+ const char *compat_str;
if (!fdt_node_is_enabled(fdt, nodeoff))
return SBI_ENODEV;
- prop = fdt_getprop(fdt, nodeoff, "compatible", &len);
- if (!prop)
+ compat_str = fdt_getprop(fdt, nodeoff, "compatible", &prop_len);
+ if (!compat_str)
return SBI_ENODEV;
- while ((driver = *drivers++)) {
- for (match = driver->match_table; match->compatible; match++) {
- if (!fdt_stringlist_contains(prop, len, match->compatible))
- continue;
+ while ((compat_len = strnlen(compat_str, prop_len) + 1) <= prop_len) {
+ for (int i = 0; (driver = drivers[i]); i++)
+ for (match = driver->match_table; match->compatible; match++)
+ if (!memcmp(match->compatible, compat_str, compat_len))
+ goto found;
- if (driver->experimental)
- sbi_printf("WARNING: %s driver is experimental and may change\n",
- match->compatible);
+ compat_str += compat_len;
+ prop_len -= compat_len;
+ }
- rc = driver->init(fdt, nodeoff, match);
- if (rc < 0) {
- const char *name;
+ return SBI_ENODEV;
- name = fdt_get_name(fdt, nodeoff, NULL);
- sbi_printf("%s: %s (%s) init failed: %d\n",
- __func__, name, match->compatible, rc);
- }
+found:
+ if (driver->experimental)
+ sbi_printf("WARNING: %s driver is experimental and may change\n",
+ match->compatible);
- return rc;
- }
+ rc = driver->init(fdt, nodeoff, match);
+ if (rc < 0) {
+ const char *name;
+
+ name = fdt_get_name(fdt, nodeoff, NULL);
+ sbi_printf("%s: %s (%s) init failed: %d\n",
+ __func__, name, match->compatible, rc);
}
- return SBI_ENODEV;
+ return rc;
}
static int fdt_driver_init_scan(const void *fdt,