From bea5b158ff0da9c7246ff391f754f5f38e34577a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 11 Aug 2016 10:20:58 -0500 Subject: [PATCH] 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 Cc: Greg Kroah-Hartman Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 10 ++++++++++ drivers/base/dd.c | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) 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 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 bool 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) { int ret = -EPROBE_DEFER; int local_trigger_count = atomic_read(&deferred_trigger_count); + bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE); if (defer_all_probes) { /* @@ -346,6 +347,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) drv->bus->name, __func__, drv->name, dev_name(dev)); WARN_ON(!list_empty(&dev->devres_head)); +re_probe: dev->driver = drv; /* If using pinctrl, bind pins now before probing */ @@ -383,6 +385,25 @@ static int really_probe(struct device *dev, struct device_driver *drv) 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); if (dev->pm_domain && dev->pm_domain->sync)