aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/base.h
diff options
context:
space:
mode:
authorGrygorii Strashko <grygorii.strashko@ti.com>2015-07-27 20:43:01 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-05 17:07:19 -0700
commit52cdbdd49853dfa856082edb0f4c4c0249d9df07 (patch)
tree856c80406c901913e59241da9886cae27f10b1e2 /drivers/base/base.h
parentdriver core: fix docbook for device_private.device (diff)
downloadlinux-dev-52cdbdd49853dfa856082edb0f4c4c0249d9df07.tar.xz
linux-dev-52cdbdd49853dfa856082edb0f4c4c0249d9df07.zip
driver core: correct device's shutdown order
Now device's shutdown sequence is performed in reverse order of their registration in devices_kset list and this sequence corresponds to the reverse device's creation order. So, devices_kset data tracks "parent<-child" device's dependencies only. Unfortunately, that's not enough and causes problems in case of implementing board's specific shutdown procedures. For example [1]: "DRA7XX_evm uses PCF8575 and one of the PCF output lines feeds to MMC/SD and this line should be driven high in order for the MMC/SD to be detected. This line is modelled as regulator and the hsmmc driver takes care of enabling and disabling it. In the case of 'reboot', during shutdown path as part of it's cleanup process the hsmmc driver disables this regulator. This makes MMC boot not functional." To handle this issue the .shutdown() callback could be implemented for PCF8575 device where corresponding GPIO pins will be configured to states, required for correct warm/cold reset. This can be achieved only when all .shutdown() callbacks have been called already for all PCF8575's consumers. But devices_kset is not filled correctly now: devices_kset: Device61 4e000000.dmm devices_kset: Device62 48070000.i2c devices_kset: Device63 48072000.i2c devices_kset: Device64 48060000.i2c devices_kset: Device65 4809c000.mmc ... devices_kset: Device102 fixedregulator-sd ... devices_kset: Device181 0-0020 // PCF8575 devices_kset: Device182 gpiochip496 devices_kset: Device183 0-0021 // PCF8575 devices_kset: Device184 gpiochip480 As can be seen from above .shutdown() callback for PCF8575 will be called before its consumers, which, in turn means, that any changes of PCF8575 GPIO's pins will be or unsafe or overwritten later by GPIO's consumers. The problem can be solved if devices_kset list will be filled not only according device creation order, but also according device's probing order to track "supplier<-consumer" dependencies also. Hence, as a fix, lets add devices_kset_move_last(), devices_kset_move_before(), devices_kset_move_after() and call them from device_move() and also add call of devices_kset_move_last() in really_probe(). After this change all entries in devices_kset will be sorted according to device's creation ("parent<-child") and probing ("supplier<-consumer") order. devices_kset after: devices_kset: Device121 48070000.i2c devices_kset: Device122 i2c-0 ... devices_kset: Device147 regulator.24 devices_kset: Device148 0-0020 devices_kset: Device149 gpiochip496 devices_kset: Device150 0-0021 devices_kset: Device151 gpiochip480 devices_kset: Device152 0-0019 ... devices_kset: Device372 fixedregulator-sd devices_kset: Device373 regulator.29 devices_kset: Device374 4809c000.mmc devices_kset: Device375 mmc0 [1] http://www.spinics.net/lists/linux-mmc/msg29825.html Cc: Sekhar Nori <nsekhar@ti.com> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/base.h')
-rw-r--r--drivers/base/base.h1
1 files changed, 1 insertions, 0 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 29c985eb9f4c..1782f3aa386e 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -134,6 +134,7 @@ extern int devres_release_all(struct device *dev);
/* /sys/devices directory */
extern struct kset *devices_kset;
+extern void devices_kset_move_last(struct device *dev);
#if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS)
extern void module_add_driver(struct module *mod, struct device_driver *drv);