Commit bea5b158 authored by Rob Herring's avatar Rob Herring Committed by Greg Kroah-Hartman

driver core: add test of driver remove calls during probe

In recent discussions on ksummit-discuss[1], it was suggested to do a
sequence of probe, remove, probe for testing driver remove paths. This
adds a kconfig option for said test.

[1] https://lists.linuxfoundation.org/pipermail/ksummit-discuss/2016-August/003459.htmlSuggested-by: default avatarArnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarRob Herring <robh@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent cebf8fd1
...@@ -212,6 +212,16 @@ config DEBUG_DEVRES ...@@ -212,6 +212,16 @@ config DEBUG_DEVRES
If you are unsure about this, Say N here. If you are unsure about this, Say N here.
config DEBUG_TEST_DRIVER_REMOVE
bool "Test driver remove calls during probe"
depends on DEBUG_KERNEL
help
Say Y here if you want the Driver core to test driver remove functions
by calling probe, remove, probe. This tests the remove path without
having to unbind the driver or unload the driver module.
If you are unsure about this, say N here.
config SYS_HYPERVISOR config SYS_HYPERVISOR
bool bool
default n default n
......
...@@ -329,6 +329,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -329,6 +329,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
{ {
int ret = -EPROBE_DEFER; int ret = -EPROBE_DEFER;
int local_trigger_count = atomic_read(&deferred_trigger_count); int local_trigger_count = atomic_read(&deferred_trigger_count);
bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE);
if (defer_all_probes) { if (defer_all_probes) {
/* /*
...@@ -346,6 +347,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -346,6 +347,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
drv->bus->name, __func__, drv->name, dev_name(dev)); drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head)); WARN_ON(!list_empty(&dev->devres_head));
re_probe:
dev->driver = drv; dev->driver = drv;
/* If using pinctrl, bind pins now before probing */ /* If using pinctrl, bind pins now before probing */
...@@ -383,6 +385,25 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -383,6 +385,25 @@ static int really_probe(struct device *dev, struct device_driver *drv)
goto probe_failed; goto probe_failed;
} }
if (test_remove) {
test_remove = false;
if (dev->bus && dev->bus->remove)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
if (dev->pm_domain && dev->pm_domain->dismiss)
dev->pm_domain->dismiss(dev);
pm_runtime_reinit(dev);
goto re_probe;
}
pinctrl_init_done(dev); pinctrl_init_done(dev);
if (dev->pm_domain && dev->pm_domain->sync) if (dev->pm_domain && dev->pm_domain->sync)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment