During probe every time driver gets resource it should usually check for error printk some message if it is not -EPROBE_DEFER and return the error. This pattern is simple but requires adding few lines after any resource acquisition code, as a result it is often omitted or implemented only partially. dev_err_probe helps to replace such code sequences with simple call, so code: if (err != -EPROBE_DEFER) dev_err(dev, ...); return err; becomes: return dev_err_probe(dev, err, ...);
Unified · Split
| @@ -4203,6 +4203,48 @@ define_dev_printk_level(_dev_info, KERN_INFO); · 4202 unmodified lines | ||
| 4203 | 4203 | |
| 4204 | 4204 | #endif |
| 4205 | 4205 | |
| 4206 | +/** | |
| 4207 | + * dev_err_probe - probe error check and log helper | |
| 4208 | + * @dev: the pointer to the struct device | |
| 4209 | + * @err: error value to test | |
| 4210 | + * @fmt: printf-style format string | |
| 4211 | + * @...: arguments as specified in the format string | |
| 4212 | + * | |
| 4213 | + * This helper implements common pattern present in probe functions for error | |
| 4214 | + * checking: print debug or error message depending if the error value is | |
| 4215 | + * -EPROBE_DEFER and propagate error upwards. | |
| 4216 | + * It replaces code sequence: | |
| 4217 | + * if (err != -EPROBE_DEFER) | |
| 4218 | + * dev_err(dev, ...); | |
| 4219 | + * else | |
| 4220 | + * dev_dbg(dev, ...); | |
| 4221 | + * return err; | |
| 4222 | + * with | |
| 4223 | + * return dev_err_probe(dev, err, ...); | |
| 4224 | + * | |
| 4225 | + * Returns @err. | |
| 4226 | + * | |
| 4227 | + */ | |
| 4228 | +int dev_err_probe(const struct device *dev, int err, const char *fmt, ...) | |
| 4229 | +{ | |
| 4230 | + struct va_format vaf; | |
| 4231 | + va_list args; | |
| 4232 | + | |
| 4233 | + va_start(args, fmt); | |
| 4234 | + vaf.fmt = fmt; | |
| 4235 | + vaf.va = &args; | |
| 4236 | + | |
| 4237 | + if (err != -EPROBE_DEFER) | |
| 4238 | + dev_err(dev, "error %d: %pV", err, &vaf); | |
| 4239 | + else | |
| 4240 | + dev_dbg(dev, "error %d: %pV", err, &vaf); | |
| 4241 | + | |
| 4242 | + va_end(args); | |
| 4243 | + | |
| 4244 | + return err; | |
| 4245 | +} | |
| 4246 | +EXPORT_SYMBOL_GPL(dev_err_probe); | |
| 4247 | + | |
| 4206 | 4248 | static inline bool fwnode_is_primary(struct fwnode_handle *fwnode) |
| 4207 | 4249 | { |
| 4208 | 4250 | return fwnode && !IS_ERR(fwnode->secondary); |
| @@ -962,6 +962,9 @@ void device_link_remove(void *consumer, struct device *supplier); · 961 unmodified lines | ||
| 962 | 962 | void device_links_supplier_sync_state_pause(void); |
| 963 | 963 | void device_links_supplier_sync_state_resume(void); |
| 964 | 964 | |
| 965 | +extern __printf(3, 4) | |
| 966 | +int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); | |
| 967 | + | |
| 965 | 968 | /* Create alias, so I can be autoloaded. */ |
| 966 | 969 | #define MODULE_ALIAS_CHARDEV(major,minor) \ |
| 967 | 970 | MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) |