aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/core.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-01-12 14:40:46 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-01-24 23:40:04 -0500
commit775b64d2b6ca37697de925f70799c710aab5849a (patch)
tree09e91c89228c8d3c6928a1b2ef56711190c69836 /drivers/base/core.c
parent7a83d456a86d559a6347115d206d23774bc152d9 (diff)
PM: Acquire device locks on suspend
This patch reorganizes the way suspend and resume notifications are sent to drivers. The major changes are that now the PM core acquires every device semaphore before calling the methods, and calls to device_add() during suspends will fail, while calls to device_del() during suspends will block. It also provides a way to safely remove a suspended device with the help of the PM core, by using the device_pm_schedule_removal() callback introduced specifically for this purpose, and updates two drivers (msr and cpuid) that need to use it. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r--drivers/base/core.c65
1 files changed, 57 insertions, 8 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2683eac30c68..ce6b64c489ad 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -726,11 +726,20 @@ int device_add(struct device *dev)
726{ 726{
727 struct device *parent = NULL; 727 struct device *parent = NULL;
728 struct class_interface *class_intf; 728 struct class_interface *class_intf;
729 int error = -EINVAL; 729 int error;
730
731 error = pm_sleep_lock();
732 if (error) {
733 dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__);
734 dump_stack();
735 return error;
736 }
730 737
731 dev = get_device(dev); 738 dev = get_device(dev);
732 if (!dev || !strlen(dev->bus_id)) 739 if (!dev || !strlen(dev->bus_id)) {
740 error = -EINVAL;
733 goto Error; 741 goto Error;
742 }
734 743
735 pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); 744 pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
736 745
@@ -795,6 +804,7 @@ int device_add(struct device *dev)
795 } 804 }
796 Done: 805 Done:
797 put_device(dev); 806 put_device(dev);
807 pm_sleep_unlock();
798 return error; 808 return error;
799 BusError: 809 BusError:
800 device_pm_remove(dev); 810 device_pm_remove(dev);
@@ -905,6 +915,7 @@ void device_del(struct device * dev)
905 struct device * parent = dev->parent; 915 struct device * parent = dev->parent;
906 struct class_interface *class_intf; 916 struct class_interface *class_intf;
907 917
918 device_pm_remove(dev);
908 if (parent) 919 if (parent)
909 klist_del(&dev->knode_parent); 920 klist_del(&dev->knode_parent);
910 if (MAJOR(dev->devt)) 921 if (MAJOR(dev->devt))
@@ -981,7 +992,6 @@ void device_del(struct device * dev)
981 if (dev->bus) 992 if (dev->bus)
982 blocking_notifier_call_chain(&dev->bus->bus_notifier, 993 blocking_notifier_call_chain(&dev->bus->bus_notifier,
983 BUS_NOTIFY_DEL_DEVICE, dev); 994 BUS_NOTIFY_DEL_DEVICE, dev);
984 device_pm_remove(dev);
985 kobject_uevent(&dev->kobj, KOBJ_REMOVE); 995 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
986 kobject_del(&dev->kobj); 996 kobject_del(&dev->kobj);
987 if (parent) 997 if (parent)
@@ -1156,14 +1166,11 @@ error:
1156EXPORT_SYMBOL_GPL(device_create); 1166EXPORT_SYMBOL_GPL(device_create);
1157 1167
1158/** 1168/**
1159 * device_destroy - removes a device that was created with device_create() 1169 * find_device - finds a device that was created with device_create()
1160 * @class: pointer to the struct class that this device was registered with 1170 * @class: pointer to the struct class that this device was registered with
1161 * @devt: the dev_t of the device that was previously registered 1171 * @devt: the dev_t of the device that was previously registered
1162 *
1163 * This call unregisters and cleans up a device that was created with a
1164 * call to device_create().
1165 */ 1172 */
1166void device_destroy(struct class *class, dev_t devt) 1173static struct device *find_device(struct class *class, dev_t devt)
1167{ 1174{
1168 struct device *dev = NULL; 1175 struct device *dev = NULL;
1169 struct device *dev_tmp; 1176 struct device *dev_tmp;
@@ -1176,12 +1183,54 @@ void device_destroy(struct class *class, dev_t devt)
1176 } 1183 }
1177 } 1184 }
1178 up(&class->sem); 1185 up(&class->sem);
1186 return dev;
1187}
1179 1188
1189/**
1190 * device_destroy - removes a device that was created with device_create()
1191 * @class: pointer to the struct class that this device was registered with
1192 * @devt: the dev_t of the device that was previously registered
1193 *
1194 * This call unregisters and cleans up a device that was created with a
1195 * call to device_create().
1196 */
1197void device_destroy(struct class *class, dev_t devt)
1198{
1199 struct device *dev;
1200
1201 dev = find_device(class, devt);
1180 if (dev) 1202 if (dev)
1181 device_unregister(dev); 1203 device_unregister(dev);
1182} 1204}
1183EXPORT_SYMBOL_GPL(device_destroy); 1205EXPORT_SYMBOL_GPL(device_destroy);
1184 1206
1207#ifdef CONFIG_PM_SLEEP
1208/**
1209 * destroy_suspended_device - asks the PM core to remove a suspended device
1210 * @class: pointer to the struct class that this device was registered with
1211 * @devt: the dev_t of the device that was previously registered
1212 *
1213 * This call notifies the PM core of the necessity to unregister a suspended
1214 * device created with a call to device_create() (devices cannot be
1215 * unregistered directly while suspended, since the PM core holds their
1216 * semaphores at that time).
1217 *
1218 * It can only be called within the scope of a system sleep transition. In
1219 * practice this means it has to be directly or indirectly invoked either by
1220 * a suspend or resume method, or by the PM core (e.g. via
1221 * disable_nonboot_cpus() or enable_nonboot_cpus()).
1222 */
1223void destroy_suspended_device(struct class *class, dev_t devt)
1224{
1225 struct device *dev;
1226
1227 dev = find_device(class, devt);
1228 if (dev)
1229 device_pm_schedule_removal(dev);
1230}
1231EXPORT_SYMBOL_GPL(destroy_suspended_device);
1232#endif /* CONFIG_PM_SLEEP */
1233
1185/** 1234/**
1186 * device_rename - renames a device 1235 * device_rename - renames a device
1187 * @dev: the pointer to the struct device to be renamed 1236 * @dev: the pointer to the struct device to be renamed