X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fbase%2Fplatform.c;fp=kernel%2Fdrivers%2Fbase%2Fplatform.c;h=176b59f5bc4717925e174ce18d794470cf58b91e;hb=e09b41010ba33a20a87472ee821fa407a5b8da36;hp=7403de94832c007d7187ffe0f6b65ca77ef4d8f1;hpb=f93b97fd65072de626c074dbe099a1fff05ce060;p=kvmfornfv.git diff --git a/kernel/drivers/base/platform.c b/kernel/drivers/base/platform.c index 7403de948..176b59f5b 100644 --- a/kernel/drivers/base/platform.c +++ b/kernel/drivers/base/platform.c @@ -514,9 +514,14 @@ static int platform_drv_probe(struct device *_dev) ret = dev_pm_domain_attach(_dev, true); if (ret != -EPROBE_DEFER) { - ret = drv->probe(dev); - if (ret) - dev_pm_domain_detach(_dev, true); + if (drv->probe) { + ret = drv->probe(dev); + if (ret) + dev_pm_domain_detach(_dev, true); + } else { + /* don't fail if just dev_pm_domain_attach failed */ + ret = 0; + } } if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { @@ -536,9 +541,10 @@ static int platform_drv_remove(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); - int ret; + int ret = 0; - ret = drv->remove(dev); + if (drv->remove) + ret = drv->remove(dev); dev_pm_domain_detach(_dev, true); return ret; @@ -549,7 +555,8 @@ static void platform_drv_shutdown(struct device *_dev) struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); - drv->shutdown(dev); + if (drv->shutdown) + drv->shutdown(dev); dev_pm_domain_detach(_dev, true); } @@ -563,12 +570,9 @@ int __platform_driver_register(struct platform_driver *drv, { drv->driver.owner = owner; drv->driver.bus = &platform_bus_type; - if (drv->probe) - drv->driver.probe = platform_drv_probe; - if (drv->remove) - drv->driver.remove = platform_drv_remove; - if (drv->shutdown) - drv->driver.shutdown = platform_drv_shutdown; + drv->driver.probe = platform_drv_probe; + drv->driver.remove = platform_drv_remove; + drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver); } @@ -609,6 +613,19 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv, { int retval, code; + if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) { + pr_err("%s: drivers registered with %s can not be probed asynchronously\n", + drv->driver.name, __func__); + return -EINVAL; + } + + /* + * We have to run our probes synchronously because we check if + * we find any devices to bind to and exit with error if there + * are any. + */ + drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS; + /* * Prevent driver from requesting probe deferral to avoid further * futile probe attempts. @@ -698,6 +715,67 @@ err_out: } EXPORT_SYMBOL_GPL(__platform_create_bundle); +/** + * __platform_register_drivers - register an array of platform drivers + * @drivers: an array of drivers to register + * @count: the number of drivers to register + * @owner: module owning the drivers + * + * Registers platform drivers specified by an array. On failure to register a + * driver, all previously registered drivers will be unregistered. Callers of + * this API should use platform_unregister_drivers() to unregister drivers in + * the reverse order. + * + * Returns: 0 on success or a negative error code on failure. + */ +int __platform_register_drivers(struct platform_driver * const *drivers, + unsigned int count, struct module *owner) +{ + unsigned int i; + int err; + + for (i = 0; i < count; i++) { + pr_debug("registering platform driver %ps\n", drivers[i]); + + err = __platform_driver_register(drivers[i], owner); + if (err < 0) { + pr_err("failed to register platform driver %ps: %d\n", + drivers[i], err); + goto error; + } + } + + return 0; + +error: + while (i--) { + pr_debug("unregistering platform driver %ps\n", drivers[i]); + platform_driver_unregister(drivers[i]); + } + + return err; +} +EXPORT_SYMBOL_GPL(__platform_register_drivers); + +/** + * platform_unregister_drivers - unregister an array of platform drivers + * @drivers: an array of drivers to unregister + * @count: the number of drivers to unregister + * + * Unegisters platform drivers specified by an array. This is typically used + * to complement an earlier call to platform_register_drivers(). Drivers are + * unregistered in the reverse order in which they were registered. + */ +void platform_unregister_drivers(struct platform_driver * const *drivers, + unsigned int count) +{ + while (count--) { + pr_debug("unregistering platform driver %ps\n", drivers[count]); + platform_driver_unregister(drivers[count]); + } +} +EXPORT_SYMBOL_GPL(platform_unregister_drivers); + /* modalias support enables more hands-off userspace setup: * (a) environment variable lets new-style hotplug events work once system is * fully running: "modprobe $MODALIAS"