diff options
author | Rob Herring <robh@kernel.org> | 2016-08-11 11:20:58 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-08-31 09:13:55 -0400 |
commit | bea5b158ff0da9c7246ff391f754f5f38e34577a (patch) | |
tree | 0e8ea972b4548c148751a5db6b7ca4f2608e3d77 /drivers/base | |
parent | cebf8fd16900fdfd58c0028617944f808f97fe50 (diff) |
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.html
Suggested-by: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Rob Herring <robh@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Kconfig | 10 | ||||
-rw-r--r-- | drivers/base/dd.c | 21 |
2 files changed, 31 insertions, 0 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 98504ec99c7d..fdf44cac08e6 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
@@ -212,6 +212,16 @@ config DEBUG_DEVRES | |||
212 | 212 | ||
213 | If you are unsure about this, Say N here. | 213 | If you are unsure about this, Say N here. |
214 | 214 | ||
215 | config DEBUG_TEST_DRIVER_REMOVE | ||
216 | bool "Test driver remove calls during probe" | ||
217 | depends on DEBUG_KERNEL | ||
218 | help | ||
219 | Say Y here if you want the Driver core to test driver remove functions | ||
220 | by calling probe, remove, probe. This tests the remove path without | ||
221 | having to unbind the driver or unload the driver module. | ||
222 | |||
223 | If you are unsure about this, say N here. | ||
224 | |||
215 | config SYS_HYPERVISOR | 225 | config SYS_HYPERVISOR |
216 | bool | 226 | bool |
217 | default n | 227 | default n |
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 16688f50729c..4910e6db2a34 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -329,6 +329,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) | |||
329 | { | 329 | { |
330 | int ret = -EPROBE_DEFER; | 330 | int ret = -EPROBE_DEFER; |
331 | int local_trigger_count = atomic_read(&deferred_trigger_count); | 331 | int local_trigger_count = atomic_read(&deferred_trigger_count); |
332 | bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE); | ||
332 | 333 | ||
333 | if (defer_all_probes) { | 334 | if (defer_all_probes) { |
334 | /* | 335 | /* |
@@ -346,6 +347,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) | |||
346 | drv->bus->name, __func__, drv->name, dev_name(dev)); | 347 | drv->bus->name, __func__, drv->name, dev_name(dev)); |
347 | WARN_ON(!list_empty(&dev->devres_head)); | 348 | WARN_ON(!list_empty(&dev->devres_head)); |
348 | 349 | ||
350 | re_probe: | ||
349 | dev->driver = drv; | 351 | dev->driver = drv; |
350 | 352 | ||
351 | /* If using pinctrl, bind pins now before probing */ | 353 | /* If using pinctrl, bind pins now before probing */ |
@@ -383,6 +385,25 @@ static int really_probe(struct device *dev, struct device_driver *drv) | |||
383 | goto probe_failed; | 385 | goto probe_failed; |
384 | } | 386 | } |
385 | 387 | ||
388 | if (test_remove) { | ||
389 | test_remove = false; | ||
390 | |||
391 | if (dev->bus && dev->bus->remove) | ||
392 | dev->bus->remove(dev); | ||
393 | else if (drv->remove) | ||
394 | drv->remove(dev); | ||
395 | |||
396 | devres_release_all(dev); | ||
397 | driver_sysfs_remove(dev); | ||
398 | dev->driver = NULL; | ||
399 | dev_set_drvdata(dev, NULL); | ||
400 | if (dev->pm_domain && dev->pm_domain->dismiss) | ||
401 | dev->pm_domain->dismiss(dev); | ||
402 | pm_runtime_reinit(dev); | ||
403 | |||
404 | goto re_probe; | ||
405 | } | ||
406 | |||
386 | pinctrl_init_done(dev); | 407 | pinctrl_init_done(dev); |
387 | 408 | ||
388 | if (dev->pm_domain && dev->pm_domain->sync) | 409 | if (dev->pm_domain && dev->pm_domain->sync) |