Merge patch series "Adjust how autoprobe is implemented"

Simon Glass <sjg@chromium.org> says:

This little series makes a minor change to how autoprobe is
implemented, as discussed on the list.

Link: https://lore.kernel.org/r/20240626235717.272219-1-marex@denx.de
Link: https://lore.kernel.org/r/20241120153642.861633-1-sjg@chromium.org
This commit is contained in:
Tom Rini
2025-01-14 11:43:01 -06:00
6 changed files with 69 additions and 14 deletions

View File

@@ -815,21 +815,26 @@ static int initf_bootstage(void)
static int initf_dm(void) static int initf_dm(void)
{ {
#if defined(CONFIG_DM) && CONFIG_IS_ENABLED(SYS_MALLOC_F)
int ret; int ret;
if (!CONFIG_IS_ENABLED(SYS_MALLOC_F))
return 0;
bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f"); bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f");
ret = dm_init_and_scan(true); ret = dm_init_and_scan(true);
bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F); bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F);
if (ret) if (ret)
return ret; return ret;
ret = dm_autoprobe();
if (ret)
return ret;
if (IS_ENABLED(CONFIG_TIMER_EARLY)) { if (IS_ENABLED(CONFIG_TIMER_EARLY)) {
ret = dm_timer_init(); ret = dm_timer_init();
if (ret) if (ret)
return ret; return ret;
} }
#endif
return 0; return 0;
} }

View File

@@ -250,7 +250,7 @@ static int initr_dm(void)
if (ret) if (ret)
return ret; return ret;
return 0; return dm_autoprobe();
} }
#endif #endif

View File

@@ -500,6 +500,10 @@ static int spl_common_init(bool setup_malloc)
debug("dm_init_and_scan() returned error %d\n", ret); debug("dm_init_and_scan() returned error %d\n", ret);
return ret; return ret;
} }
ret = dm_autoprobe();
if (ret)
return ret;
} }
return 0; return 0;

View File

@@ -842,6 +842,23 @@ steps (see device_probe()):
cause the uclass to do some housekeeping to record the device as cause the uclass to do some housekeeping to record the device as
activated and 'known' by the uclass. activated and 'known' by the uclass.
For some platforms, certain devices must be probed to get the platform into
a working state. To help with this, drivers marked with DM_FLAG_PROBE_AFTER_BIND
will be probed immediately after all devices are bound. For now, this happens in
SPL, before relocation and after relocation. See the call to ``dm_autoprobe()``
for where this is done.
The auto-probe feature is tricky because it bypasses the normal ordering of
probing. General, if device A (e.g. video) needs device B (e.g. clock), then
A's probe() method uses ``clk_get_by_index()`` and B is probed before A. But
A is only probed when it is used. Therefore care should be taken when using
auto-probe, limiting it to devices which truly are essential, such as power
domains or critical clocks.
See here for more discussion of this feature:
:Link: https://patchwork.ozlabs.org/project/uboot/patch/20240626235717.272219-1-marex@denx.de/
Running stage Running stage
^^^^^^^^^^^^^ ^^^^^^^^^^^^^

View File

@@ -288,26 +288,40 @@ void *dm_priv_to_rw(void *priv)
} }
#endif #endif
static int dm_probe_devices(struct udevice *dev, bool pre_reloc_only) /**
* dm_probe_devices() - Check whether to probe a device and all children
*
* Probes the device if DM_FLAG_PROBE_AFTER_BIND is enabled for it. Then scans
* all its children recursively to do the same.
*
* @dev: Device to (maybe) probe
* Return 0 if OK, -ve on error
*/
static int dm_probe_devices(struct udevice *dev)
{ {
ofnode node = dev_ofnode(dev);
struct udevice *child; struct udevice *child;
int ret;
if (pre_reloc_only &&
(!ofnode_valid(node) || !ofnode_pre_reloc(node)) &&
!(dev->driver->flags & DM_FLAG_PRE_RELOC))
goto probe_children;
if (dev_get_flags(dev) & DM_FLAG_PROBE_AFTER_BIND) { if (dev_get_flags(dev) & DM_FLAG_PROBE_AFTER_BIND) {
int ret;
ret = device_probe(dev); ret = device_probe(dev);
if (ret) if (ret)
return ret; return ret;
} }
probe_children:
list_for_each_entry(child, &dev->child_head, sibling_node) list_for_each_entry(child, &dev->child_head, sibling_node)
dm_probe_devices(child, pre_reloc_only); dm_probe_devices(child);
return 0;
}
int dm_autoprobe(void)
{
int ret;
ret = dm_probe_devices(gd->dm_root);
if (ret)
return log_msg_ret("pro", ret);
return 0; return 0;
} }
@@ -344,7 +358,7 @@ static int dm_scan(bool pre_reloc_only)
if (ret) if (ret)
return ret; return ret;
return dm_probe_devices(gd->dm_root, pre_reloc_only); return 0;
} }
int dm_init_and_scan(bool pre_reloc_only) int dm_init_and_scan(bool pre_reloc_only)

View File

@@ -136,6 +136,21 @@ int dm_scan_other(bool pre_reloc_only);
*/ */
int dm_init_and_scan(bool pre_reloc_only); int dm_init_and_scan(bool pre_reloc_only);
/**
* dm_autoprobe() - Probe devices which are marked for probe-after-bind
*
* This probes all devices with a DM_FLAG_PROBE_AFTER_BIND flag. It checks the
* entire tree, so parent nodes need not have the flag set.
*
* It recursively probes parent nodes, so they do not need to have the flag
* set themselves. Since parents are always probed before children, if a child
* has the flag set, then its parent (and any devices up the chain to the root
* device) will be probed too.
*
* Return: 0 if OK, -ve on error
*/
int dm_autoprobe(void);
/** /**
* dm_init() - Initialise Driver Model structures * dm_init() - Initialise Driver Model structures
* *