On Fri, Jul 08, 2022 at 11:41:38AM +0200, Johannes Zink wrote: > This stores the probe deferral reason in the device structure. > If a probe is permanently deferred, the last reason is displayed. > > Example output on a permanently deferred probe: > ERROR: imx-pgc-domain0: probe permanently deferred (Failed to get domain's regulator) > > Other dev_err_probe outputs are displayed as before. > > Signed-off-by: Johannes Zink <j.zink@xxxxxxxxxxxxxx> > --- Applied, thanks Sascha > v1 -> v2: > - improved commit message > - improved function prototypes > - improved debug output, device name is displayed once only per > message > - reverted removal of MSG_DEBUG output on deferred probe > - replaced kfree by free > - removed unnecessary null checks before free > - fixed several typos > - fixed compiler warnings > - fixed coding style issues > v2 -> v3: > - dropped const from dev_err_probe > - use xasprintf instead of basprintf: guarantee memory allocation > - prevent newline within message on permanent deferral > - removed unnecessary helper functions > - fixed remaining typos and whitespace changes > - improved comments > - reverted removal of kernel doc comment > - added example in commit message > --- > drivers/base/driver.c | 44 +++++++++++++++++++++++++++++++++++------- > include/driver.h | 5 +++++ > include/linux/printk.h | 6 +++--- > 3 files changed, 45 insertions(+), 10 deletions(-) > > diff --git a/drivers/base/driver.c b/drivers/base/driver.c > index 303ca061c..4898e0114 100644 > --- a/drivers/base/driver.c > +++ b/drivers/base/driver.c > @@ -283,6 +283,7 @@ void free_device_res(struct device_d *dev) > dev->name = NULL; > free(dev->unique_name); > dev->unique_name = NULL; > + free(dev->deferred_probe_reason); > } > EXPORT_SYMBOL(free_device_res); > > @@ -333,9 +334,13 @@ static int device_probe_deferred(void) > } > } while (success); > > - list_for_each_entry(dev, &deferred, active) > - dev_err(dev, "probe permanently deferred\n"); > - > + list_for_each_entry(dev, &deferred, active) { > + if (dev->deferred_probe_reason) > + dev_err(dev, "probe permanently deferred (%s)\n", > + dev->deferred_probe_reason); > + else > + dev_err(dev, "probe permanently deferred\n"); > + } > return 0; > } > late_initcall(device_probe_deferred); > @@ -573,6 +578,24 @@ const void *device_get_match_data(struct device_d *dev) > return NULL; > } > > +static void device_set_deferred_probe_reason(struct device_d *dev, const struct va_format *vaf) > +{ > + char *reason; > + char *last_char; > + > + free(dev->deferred_probe_reason); > + > + reason = xasprintf("%pV", vaf); > + > + /* drop newline char at end of reason string */ > + last_char = reason + strlen(reason) - 1; > + > + if (*last_char == '\n') > + *last_char = '\0'; > + > + dev->deferred_probe_reason = reason; > +} > + > /** > * dev_err_probe - probe error check and log helper > * @loglevel: log level configured in source file > @@ -584,8 +607,12 @@ const void *device_get_match_data(struct device_d *dev) > * This helper implements common pattern present in probe functions for error > * checking: print debug or error message depending if the error value is > * -EPROBE_DEFER and propagate error upwards. > - * In case of -EPROBE_DEFER it sets also defer probe reason, which can be > - * checked later by reading devices_deferred debugfs attribute. > + * > + * In case of -EPROBE_DEFER it sets the device's deferred_probe_reason attribute, > + * but does not report an error. The error is recorded and displayed later, if > + * (and only if) the probe is permanently deferred. For all other error codes, > + * it just outputs the error along with the formatted message. > + * > * It replaces code sequence:: > * > * if (err != -EPROBE_DEFER) > @@ -601,8 +628,8 @@ const void *device_get_match_data(struct device_d *dev) > * Returns @err. > * > */ > -int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...); > -int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...) > +int dev_err_probe(struct device_d *dev, int err, const char *fmt, ...); > +int dev_err_probe(struct device_d *dev, int err, const char *fmt, ...) > { > struct va_format vaf; > va_list args; > @@ -611,6 +638,9 @@ int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...) > vaf.fmt = fmt; > vaf.va = &args; > > + if (err == -EPROBE_DEFER) > + device_set_deferred_probe_reason(dev, &vaf); > + > dev_printf(err == -EPROBE_DEFER ? MSG_DEBUG : MSG_ERR, > dev, "error %pe: %pV", ERR_PTR(err), &vaf); > > diff --git a/include/driver.h b/include/driver.h > index b35b5f397..a89ce7af9 100644 > --- a/include/driver.h > +++ b/include/driver.h > @@ -88,6 +88,11 @@ struct device_d { > * when the driver should actually detect client devices > */ > int (*detect) (struct device_d *); > + > + /* > + * if a driver probe is deferred, this stores the last error > + */ > + char *deferred_probe_reason; > }; > > /** @brief Describes a driver present in the system */ > diff --git a/include/linux/printk.h b/include/linux/printk.h > index 39523b057..e21e859bf 100644 > --- a/include/linux/printk.h > +++ b/include/linux/printk.h > @@ -76,12 +76,12 @@ static inline int pr_print(int level, const char *format, ...) > __dev_printf(8, (dev) , format , ## arg) > > #if LOGLEVEL >= MSG_ERR > -int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...) > +int dev_err_probe(struct device_d *dev, int err, const char *fmt, ...) > __attribute__ ((format(__printf__, 3, 4))); > #elif !defined(dev_err_probe) > -static int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...) > +static int dev_err_probe(struct device_d *dev, int err, const char *fmt, ...) > __attribute__ ((format(__printf__, 3, 4))); > -static inline int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...) > +static inline int dev_err_probe(struct device_d *dev, int err, const char *fmt, ...) > { > return err; > } > -- > 2.30.2 > > > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |