diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Makefile | 4 | ||||
-rw-r--r-- | drivers/base/base.h | 12 | ||||
-rw-r--r-- | drivers/base/bus.c | 293 | ||||
-rw-r--r-- | drivers/base/class.c | 14 | ||||
-rw-r--r-- | drivers/base/core.c | 89 | ||||
-rw-r--r-- | drivers/base/cpu.c | 153 | ||||
-rw-r--r-- | drivers/base/devres.c | 2 | ||||
-rw-r--r-- | drivers/base/devtmpfs.c | 11 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 18 | ||||
-rw-r--r-- | drivers/base/init.c | 1 | ||||
-rw-r--r-- | drivers/base/memory.c | 160 | ||||
-rw-r--r-- | drivers/base/node.c | 154 | ||||
-rw-r--r-- | drivers/base/platform.c | 117 | ||||
-rw-r--r-- | drivers/base/power/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 539 | ||||
-rw-r--r-- | drivers/base/power/domain_governor.c | 156 | ||||
-rw-r--r-- | drivers/base/power/generic_ops.c | 91 | ||||
-rw-r--r-- | drivers/base/power/main.c | 375 | ||||
-rw-r--r-- | drivers/base/power/qos.c | 49 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 157 | ||||
-rw-r--r-- | drivers/base/sys.c | 10 | ||||
-rw-r--r-- | drivers/base/topology.c | 51 |
22 files changed, 1542 insertions, 916 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 99a375ad2cc9..1334d893b560 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -3,7 +3,8 @@ | |||
3 | obj-y := core.o sys.o bus.o dd.o syscore.o \ | 3 | obj-y := core.o sys.o bus.o dd.o syscore.o \ |
4 | driver.o class.o platform.o \ | 4 | driver.o class.o platform.o \ |
5 | cpu.o firmware.o init.o map.o devres.o \ | 5 | cpu.o firmware.o init.o map.o devres.o \ |
6 | attribute_container.o transport_class.o | 6 | attribute_container.o transport_class.o \ |
7 | topology.o | ||
7 | obj-$(CONFIG_DEVTMPFS) += devtmpfs.o | 8 | obj-$(CONFIG_DEVTMPFS) += devtmpfs.o |
8 | obj-y += power/ | 9 | obj-y += power/ |
9 | obj-$(CONFIG_HAS_DMA) += dma-mapping.o | 10 | obj-$(CONFIG_HAS_DMA) += dma-mapping.o |
@@ -12,7 +13,6 @@ obj-$(CONFIG_ISA) += isa.o | |||
12 | obj-$(CONFIG_FW_LOADER) += firmware_class.o | 13 | obj-$(CONFIG_FW_LOADER) += firmware_class.o |
13 | obj-$(CONFIG_NUMA) += node.o | 14 | obj-$(CONFIG_NUMA) += node.o |
14 | obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o | 15 | obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o |
15 | obj-$(CONFIG_SMP) += topology.o | ||
16 | ifeq ($(CONFIG_SYSFS),y) | 16 | ifeq ($(CONFIG_SYSFS),y) |
17 | obj-$(CONFIG_MODULES) += module.o | 17 | obj-$(CONFIG_MODULES) += module.o |
18 | endif | 18 | endif |
diff --git a/drivers/base/base.h b/drivers/base/base.h index 21c1b96c34c6..7a6ae4228761 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h | |||
@@ -4,7 +4,9 @@ | |||
4 | * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. | 4 | * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. |
5 | * | 5 | * |
6 | * @subsys - the struct kset that defines this subsystem | 6 | * @subsys - the struct kset that defines this subsystem |
7 | * @devices_kset - the list of devices associated | 7 | * @devices_kset - the subsystem's 'devices' directory |
8 | * @interfaces - list of subsystem interfaces associated | ||
9 | * @mutex - protect the devices, and interfaces lists. | ||
8 | * | 10 | * |
9 | * @drivers_kset - the list of drivers associated | 11 | * @drivers_kset - the list of drivers associated |
10 | * @klist_devices - the klist to iterate over the @devices_kset | 12 | * @klist_devices - the klist to iterate over the @devices_kset |
@@ -14,10 +16,8 @@ | |||
14 | * @bus - pointer back to the struct bus_type that this structure is associated | 16 | * @bus - pointer back to the struct bus_type that this structure is associated |
15 | * with. | 17 | * with. |
16 | * | 18 | * |
17 | * @class_interfaces - list of class_interfaces associated | ||
18 | * @glue_dirs - "glue" directory to put in-between the parent device to | 19 | * @glue_dirs - "glue" directory to put in-between the parent device to |
19 | * avoid namespace conflicts | 20 | * avoid namespace conflicts |
20 | * @class_mutex - mutex to protect the children, devices, and interfaces lists. | ||
21 | * @class - pointer back to the struct class that this structure is associated | 21 | * @class - pointer back to the struct class that this structure is associated |
22 | * with. | 22 | * with. |
23 | * | 23 | * |
@@ -28,6 +28,8 @@ | |||
28 | struct subsys_private { | 28 | struct subsys_private { |
29 | struct kset subsys; | 29 | struct kset subsys; |
30 | struct kset *devices_kset; | 30 | struct kset *devices_kset; |
31 | struct list_head interfaces; | ||
32 | struct mutex mutex; | ||
31 | 33 | ||
32 | struct kset *drivers_kset; | 34 | struct kset *drivers_kset; |
33 | struct klist klist_devices; | 35 | struct klist klist_devices; |
@@ -36,9 +38,7 @@ struct subsys_private { | |||
36 | unsigned int drivers_autoprobe:1; | 38 | unsigned int drivers_autoprobe:1; |
37 | struct bus_type *bus; | 39 | struct bus_type *bus; |
38 | 40 | ||
39 | struct list_head class_interfaces; | ||
40 | struct kset glue_dirs; | 41 | struct kset glue_dirs; |
41 | struct mutex class_mutex; | ||
42 | struct class *class; | 42 | struct class *class; |
43 | }; | 43 | }; |
44 | #define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj) | 44 | #define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj) |
@@ -94,7 +94,6 @@ extern int hypervisor_init(void); | |||
94 | static inline int hypervisor_init(void) { return 0; } | 94 | static inline int hypervisor_init(void) { return 0; } |
95 | #endif | 95 | #endif |
96 | extern int platform_bus_init(void); | 96 | extern int platform_bus_init(void); |
97 | extern int system_bus_init(void); | ||
98 | extern int cpu_dev_init(void); | 97 | extern int cpu_dev_init(void); |
99 | 98 | ||
100 | extern int bus_add_device(struct device *dev); | 99 | extern int bus_add_device(struct device *dev); |
@@ -116,6 +115,7 @@ extern char *make_class_name(const char *name, struct kobject *kobj); | |||
116 | 115 | ||
117 | extern int devres_release_all(struct device *dev); | 116 | extern int devres_release_all(struct device *dev); |
118 | 117 | ||
118 | /* /sys/devices directory */ | ||
119 | extern struct kset *devices_kset; | 119 | extern struct kset *devices_kset; |
120 | 120 | ||
121 | #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) | 121 | #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) |
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 000e7b2006f8..99dc5921e1dd 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -16,9 +16,14 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
19 | #include <linux/mutex.h> | ||
19 | #include "base.h" | 20 | #include "base.h" |
20 | #include "power/power.h" | 21 | #include "power/power.h" |
21 | 22 | ||
23 | /* /sys/devices/system */ | ||
24 | /* FIXME: make static after drivers/base/sys.c is deleted */ | ||
25 | struct kset *system_kset; | ||
26 | |||
22 | #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) | 27 | #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) |
23 | 28 | ||
24 | /* | 29 | /* |
@@ -360,6 +365,47 @@ struct device *bus_find_device_by_name(struct bus_type *bus, | |||
360 | } | 365 | } |
361 | EXPORT_SYMBOL_GPL(bus_find_device_by_name); | 366 | EXPORT_SYMBOL_GPL(bus_find_device_by_name); |
362 | 367 | ||
368 | /** | ||
369 | * subsys_find_device_by_id - find a device with a specific enumeration number | ||
370 | * @subsys: subsystem | ||
371 | * @id: index 'id' in struct device | ||
372 | * @hint: device to check first | ||
373 | * | ||
374 | * Check the hint's next object and if it is a match return it directly, | ||
375 | * otherwise, fall back to a full list search. Either way a reference for | ||
376 | * the returned object is taken. | ||
377 | */ | ||
378 | struct device *subsys_find_device_by_id(struct bus_type *subsys, unsigned int id, | ||
379 | struct device *hint) | ||
380 | { | ||
381 | struct klist_iter i; | ||
382 | struct device *dev; | ||
383 | |||
384 | if (!subsys) | ||
385 | return NULL; | ||
386 | |||
387 | if (hint) { | ||
388 | klist_iter_init_node(&subsys->p->klist_devices, &i, &hint->p->knode_bus); | ||
389 | dev = next_device(&i); | ||
390 | if (dev && dev->id == id && get_device(dev)) { | ||
391 | klist_iter_exit(&i); | ||
392 | return dev; | ||
393 | } | ||
394 | klist_iter_exit(&i); | ||
395 | } | ||
396 | |||
397 | klist_iter_init_node(&subsys->p->klist_devices, &i, NULL); | ||
398 | while ((dev = next_device(&i))) { | ||
399 | if (dev->id == id && get_device(dev)) { | ||
400 | klist_iter_exit(&i); | ||
401 | return dev; | ||
402 | } | ||
403 | } | ||
404 | klist_iter_exit(&i); | ||
405 | return NULL; | ||
406 | } | ||
407 | EXPORT_SYMBOL_GPL(subsys_find_device_by_id); | ||
408 | |||
363 | static struct device_driver *next_driver(struct klist_iter *i) | 409 | static struct device_driver *next_driver(struct klist_iter *i) |
364 | { | 410 | { |
365 | struct klist_node *n = klist_next(i); | 411 | struct klist_node *n = klist_next(i); |
@@ -487,38 +533,59 @@ out_put: | |||
487 | void bus_probe_device(struct device *dev) | 533 | void bus_probe_device(struct device *dev) |
488 | { | 534 | { |
489 | struct bus_type *bus = dev->bus; | 535 | struct bus_type *bus = dev->bus; |
536 | struct subsys_interface *sif; | ||
490 | int ret; | 537 | int ret; |
491 | 538 | ||
492 | if (bus && bus->p->drivers_autoprobe) { | 539 | if (!bus) |
540 | return; | ||
541 | |||
542 | if (bus->p->drivers_autoprobe) { | ||
493 | ret = device_attach(dev); | 543 | ret = device_attach(dev); |
494 | WARN_ON(ret < 0); | 544 | WARN_ON(ret < 0); |
495 | } | 545 | } |
546 | |||
547 | mutex_lock(&bus->p->mutex); | ||
548 | list_for_each_entry(sif, &bus->p->interfaces, node) | ||
549 | if (sif->add_dev) | ||
550 | sif->add_dev(dev, sif); | ||
551 | mutex_unlock(&bus->p->mutex); | ||
496 | } | 552 | } |
497 | 553 | ||
498 | /** | 554 | /** |
499 | * bus_remove_device - remove device from bus | 555 | * bus_remove_device - remove device from bus |
500 | * @dev: device to be removed | 556 | * @dev: device to be removed |
501 | * | 557 | * |
502 | * - Remove symlink from bus's directory. | 558 | * - Remove device from all interfaces. |
559 | * - Remove symlink from bus' directory. | ||
503 | * - Delete device from bus's list. | 560 | * - Delete device from bus's list. |
504 | * - Detach from its driver. | 561 | * - Detach from its driver. |
505 | * - Drop reference taken in bus_add_device(). | 562 | * - Drop reference taken in bus_add_device(). |
506 | */ | 563 | */ |
507 | void bus_remove_device(struct device *dev) | 564 | void bus_remove_device(struct device *dev) |
508 | { | 565 | { |
509 | if (dev->bus) { | 566 | struct bus_type *bus = dev->bus; |
510 | sysfs_remove_link(&dev->kobj, "subsystem"); | 567 | struct subsys_interface *sif; |
511 | sysfs_remove_link(&dev->bus->p->devices_kset->kobj, | 568 | |
512 | dev_name(dev)); | 569 | if (!bus) |
513 | device_remove_attrs(dev->bus, dev); | 570 | return; |
514 | if (klist_node_attached(&dev->p->knode_bus)) | 571 | |
515 | klist_del(&dev->p->knode_bus); | 572 | mutex_lock(&bus->p->mutex); |
516 | 573 | list_for_each_entry(sif, &bus->p->interfaces, node) | |
517 | pr_debug("bus: '%s': remove device %s\n", | 574 | if (sif->remove_dev) |
518 | dev->bus->name, dev_name(dev)); | 575 | sif->remove_dev(dev, sif); |
519 | device_release_driver(dev); | 576 | mutex_unlock(&bus->p->mutex); |
520 | bus_put(dev->bus); | 577 | |
521 | } | 578 | sysfs_remove_link(&dev->kobj, "subsystem"); |
579 | sysfs_remove_link(&dev->bus->p->devices_kset->kobj, | ||
580 | dev_name(dev)); | ||
581 | device_remove_attrs(dev->bus, dev); | ||
582 | if (klist_node_attached(&dev->p->knode_bus)) | ||
583 | klist_del(&dev->p->knode_bus); | ||
584 | |||
585 | pr_debug("bus: '%s': remove device %s\n", | ||
586 | dev->bus->name, dev_name(dev)); | ||
587 | device_release_driver(dev); | ||
588 | bus_put(dev->bus); | ||
522 | } | 589 | } |
523 | 590 | ||
524 | static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv) | 591 | static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv) |
@@ -847,14 +914,14 @@ static ssize_t bus_uevent_store(struct bus_type *bus, | |||
847 | static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); | 914 | static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); |
848 | 915 | ||
849 | /** | 916 | /** |
850 | * bus_register - register a bus with the system. | 917 | * __bus_register - register a driver-core subsystem |
851 | * @bus: bus. | 918 | * @bus: bus. |
852 | * | 919 | * |
853 | * Once we have that, we registered the bus with the kobject | 920 | * Once we have that, we registered the bus with the kobject |
854 | * infrastructure, then register the children subsystems it has: | 921 | * infrastructure, then register the children subsystems it has: |
855 | * the devices and drivers that belong to the bus. | 922 | * the devices and drivers that belong to the subsystem. |
856 | */ | 923 | */ |
857 | int bus_register(struct bus_type *bus) | 924 | int __bus_register(struct bus_type *bus, struct lock_class_key *key) |
858 | { | 925 | { |
859 | int retval; | 926 | int retval; |
860 | struct subsys_private *priv; | 927 | struct subsys_private *priv; |
@@ -898,6 +965,8 @@ int bus_register(struct bus_type *bus) | |||
898 | goto bus_drivers_fail; | 965 | goto bus_drivers_fail; |
899 | } | 966 | } |
900 | 967 | ||
968 | INIT_LIST_HEAD(&priv->interfaces); | ||
969 | __mutex_init(&priv->mutex, "subsys mutex", key); | ||
901 | klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); | 970 | klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); |
902 | klist_init(&priv->klist_drivers, NULL, NULL); | 971 | klist_init(&priv->klist_drivers, NULL, NULL); |
903 | 972 | ||
@@ -927,7 +996,7 @@ out: | |||
927 | bus->p = NULL; | 996 | bus->p = NULL; |
928 | return retval; | 997 | return retval; |
929 | } | 998 | } |
930 | EXPORT_SYMBOL_GPL(bus_register); | 999 | EXPORT_SYMBOL_GPL(__bus_register); |
931 | 1000 | ||
932 | /** | 1001 | /** |
933 | * bus_unregister - remove a bus from the system | 1002 | * bus_unregister - remove a bus from the system |
@@ -939,6 +1008,8 @@ EXPORT_SYMBOL_GPL(bus_register); | |||
939 | void bus_unregister(struct bus_type *bus) | 1008 | void bus_unregister(struct bus_type *bus) |
940 | { | 1009 | { |
941 | pr_debug("bus: '%s': unregistering\n", bus->name); | 1010 | pr_debug("bus: '%s': unregistering\n", bus->name); |
1011 | if (bus->dev_root) | ||
1012 | device_unregister(bus->dev_root); | ||
942 | bus_remove_attrs(bus); | 1013 | bus_remove_attrs(bus); |
943 | remove_probe_files(bus); | 1014 | remove_probe_files(bus); |
944 | kset_unregister(bus->p->drivers_kset); | 1015 | kset_unregister(bus->p->drivers_kset); |
@@ -1028,10 +1099,194 @@ void bus_sort_breadthfirst(struct bus_type *bus, | |||
1028 | } | 1099 | } |
1029 | EXPORT_SYMBOL_GPL(bus_sort_breadthfirst); | 1100 | EXPORT_SYMBOL_GPL(bus_sort_breadthfirst); |
1030 | 1101 | ||
1102 | /** | ||
1103 | * subsys_dev_iter_init - initialize subsys device iterator | ||
1104 | * @iter: subsys iterator to initialize | ||
1105 | * @subsys: the subsys we wanna iterate over | ||
1106 | * @start: the device to start iterating from, if any | ||
1107 | * @type: device_type of the devices to iterate over, NULL for all | ||
1108 | * | ||
1109 | * Initialize subsys iterator @iter such that it iterates over devices | ||
1110 | * of @subsys. If @start is set, the list iteration will start there, | ||
1111 | * otherwise if it is NULL, the iteration starts at the beginning of | ||
1112 | * the list. | ||
1113 | */ | ||
1114 | void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys, | ||
1115 | struct device *start, const struct device_type *type) | ||
1116 | { | ||
1117 | struct klist_node *start_knode = NULL; | ||
1118 | |||
1119 | if (start) | ||
1120 | start_knode = &start->p->knode_bus; | ||
1121 | klist_iter_init_node(&subsys->p->klist_devices, &iter->ki, start_knode); | ||
1122 | iter->type = type; | ||
1123 | } | ||
1124 | EXPORT_SYMBOL_GPL(subsys_dev_iter_init); | ||
1125 | |||
1126 | /** | ||
1127 | * subsys_dev_iter_next - iterate to the next device | ||
1128 | * @iter: subsys iterator to proceed | ||
1129 | * | ||
1130 | * Proceed @iter to the next device and return it. Returns NULL if | ||
1131 | * iteration is complete. | ||
1132 | * | ||
1133 | * The returned device is referenced and won't be released till | ||
1134 | * iterator is proceed to the next device or exited. The caller is | ||
1135 | * free to do whatever it wants to do with the device including | ||
1136 | * calling back into subsys code. | ||
1137 | */ | ||
1138 | struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter) | ||
1139 | { | ||
1140 | struct klist_node *knode; | ||
1141 | struct device *dev; | ||
1142 | |||
1143 | for (;;) { | ||
1144 | knode = klist_next(&iter->ki); | ||
1145 | if (!knode) | ||
1146 | return NULL; | ||
1147 | dev = container_of(knode, struct device_private, knode_bus)->device; | ||
1148 | if (!iter->type || iter->type == dev->type) | ||
1149 | return dev; | ||
1150 | } | ||
1151 | } | ||
1152 | EXPORT_SYMBOL_GPL(subsys_dev_iter_next); | ||
1153 | |||
1154 | /** | ||
1155 | * subsys_dev_iter_exit - finish iteration | ||
1156 | * @iter: subsys iterator to finish | ||
1157 | * | ||
1158 | * Finish an iteration. Always call this function after iteration is | ||
1159 | * complete whether the iteration ran till the end or not. | ||
1160 | */ | ||
1161 | void subsys_dev_iter_exit(struct subsys_dev_iter *iter) | ||
1162 | { | ||
1163 | klist_iter_exit(&iter->ki); | ||
1164 | } | ||
1165 | EXPORT_SYMBOL_GPL(subsys_dev_iter_exit); | ||
1166 | |||
1167 | int subsys_interface_register(struct subsys_interface *sif) | ||
1168 | { | ||
1169 | struct bus_type *subsys; | ||
1170 | struct subsys_dev_iter iter; | ||
1171 | struct device *dev; | ||
1172 | |||
1173 | if (!sif || !sif->subsys) | ||
1174 | return -ENODEV; | ||
1175 | |||
1176 | subsys = bus_get(sif->subsys); | ||
1177 | if (!subsys) | ||
1178 | return -EINVAL; | ||
1179 | |||
1180 | mutex_lock(&subsys->p->mutex); | ||
1181 | list_add_tail(&sif->node, &subsys->p->interfaces); | ||
1182 | if (sif->add_dev) { | ||
1183 | subsys_dev_iter_init(&iter, subsys, NULL, NULL); | ||
1184 | while ((dev = subsys_dev_iter_next(&iter))) | ||
1185 | sif->add_dev(dev, sif); | ||
1186 | subsys_dev_iter_exit(&iter); | ||
1187 | } | ||
1188 | mutex_unlock(&subsys->p->mutex); | ||
1189 | |||
1190 | return 0; | ||
1191 | } | ||
1192 | EXPORT_SYMBOL_GPL(subsys_interface_register); | ||
1193 | |||
1194 | void subsys_interface_unregister(struct subsys_interface *sif) | ||
1195 | { | ||
1196 | struct bus_type *subsys = sif->subsys; | ||
1197 | struct subsys_dev_iter iter; | ||
1198 | struct device *dev; | ||
1199 | |||
1200 | if (!sif) | ||
1201 | return; | ||
1202 | |||
1203 | mutex_lock(&subsys->p->mutex); | ||
1204 | list_del_init(&sif->node); | ||
1205 | if (sif->remove_dev) { | ||
1206 | subsys_dev_iter_init(&iter, subsys, NULL, NULL); | ||
1207 | while ((dev = subsys_dev_iter_next(&iter))) | ||
1208 | sif->remove_dev(dev, sif); | ||
1209 | subsys_dev_iter_exit(&iter); | ||
1210 | } | ||
1211 | mutex_unlock(&subsys->p->mutex); | ||
1212 | |||
1213 | bus_put(subsys); | ||
1214 | } | ||
1215 | EXPORT_SYMBOL_GPL(subsys_interface_unregister); | ||
1216 | |||
1217 | static void system_root_device_release(struct device *dev) | ||
1218 | { | ||
1219 | kfree(dev); | ||
1220 | } | ||
1221 | /** | ||
1222 | * subsys_system_register - register a subsystem at /sys/devices/system/ | ||
1223 | * @subsys - system subsystem | ||
1224 | * @groups - default attributes for the root device | ||
1225 | * | ||
1226 | * All 'system' subsystems have a /sys/devices/system/<name> root device | ||
1227 | * with the name of the subsystem. The root device can carry subsystem- | ||
1228 | * wide attributes. All registered devices are below this single root | ||
1229 | * device and are named after the subsystem with a simple enumeration | ||
1230 | * number appended. The registered devices are not explicitely named; | ||
1231 | * only 'id' in the device needs to be set. | ||
1232 | * | ||
1233 | * Do not use this interface for anything new, it exists for compatibility | ||
1234 | * with bad ideas only. New subsystems should use plain subsystems; and | ||
1235 | * add the subsystem-wide attributes should be added to the subsystem | ||
1236 | * directory itself and not some create fake root-device placed in | ||
1237 | * /sys/devices/system/<name>. | ||
1238 | */ | ||
1239 | int subsys_system_register(struct bus_type *subsys, | ||
1240 | const struct attribute_group **groups) | ||
1241 | { | ||
1242 | struct device *dev; | ||
1243 | int err; | ||
1244 | |||
1245 | err = bus_register(subsys); | ||
1246 | if (err < 0) | ||
1247 | return err; | ||
1248 | |||
1249 | dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
1250 | if (!dev) { | ||
1251 | err = -ENOMEM; | ||
1252 | goto err_dev; | ||
1253 | } | ||
1254 | |||
1255 | err = dev_set_name(dev, "%s", subsys->name); | ||
1256 | if (err < 0) | ||
1257 | goto err_name; | ||
1258 | |||
1259 | dev->kobj.parent = &system_kset->kobj; | ||
1260 | dev->groups = groups; | ||
1261 | dev->release = system_root_device_release; | ||
1262 | |||
1263 | err = device_register(dev); | ||
1264 | if (err < 0) | ||
1265 | goto err_dev_reg; | ||
1266 | |||
1267 | subsys->dev_root = dev; | ||
1268 | return 0; | ||
1269 | |||
1270 | err_dev_reg: | ||
1271 | put_device(dev); | ||
1272 | dev = NULL; | ||
1273 | err_name: | ||
1274 | kfree(dev); | ||
1275 | err_dev: | ||
1276 | bus_unregister(subsys); | ||
1277 | return err; | ||
1278 | } | ||
1279 | EXPORT_SYMBOL_GPL(subsys_system_register); | ||
1280 | |||
1031 | int __init buses_init(void) | 1281 | int __init buses_init(void) |
1032 | { | 1282 | { |
1033 | bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); | 1283 | bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); |
1034 | if (!bus_kset) | 1284 | if (!bus_kset) |
1035 | return -ENOMEM; | 1285 | return -ENOMEM; |
1286 | |||
1287 | system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); | ||
1288 | if (!system_kset) | ||
1289 | return -ENOMEM; | ||
1290 | |||
1036 | return 0; | 1291 | return 0; |
1037 | } | 1292 | } |
diff --git a/drivers/base/class.c b/drivers/base/class.c index b80d91cc8c3a..03243d4002fd 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -184,9 +184,9 @@ int __class_register(struct class *cls, struct lock_class_key *key) | |||
184 | if (!cp) | 184 | if (!cp) |
185 | return -ENOMEM; | 185 | return -ENOMEM; |
186 | klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); | 186 | klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); |
187 | INIT_LIST_HEAD(&cp->class_interfaces); | 187 | INIT_LIST_HEAD(&cp->interfaces); |
188 | kset_init(&cp->glue_dirs); | 188 | kset_init(&cp->glue_dirs); |
189 | __mutex_init(&cp->class_mutex, "struct class mutex", key); | 189 | __mutex_init(&cp->mutex, "subsys mutex", key); |
190 | error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); | 190 | error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); |
191 | if (error) { | 191 | if (error) { |
192 | kfree(cp); | 192 | kfree(cp); |
@@ -460,15 +460,15 @@ int class_interface_register(struct class_interface *class_intf) | |||
460 | if (!parent) | 460 | if (!parent) |
461 | return -EINVAL; | 461 | return -EINVAL; |
462 | 462 | ||
463 | mutex_lock(&parent->p->class_mutex); | 463 | mutex_lock(&parent->p->mutex); |
464 | list_add_tail(&class_intf->node, &parent->p->class_interfaces); | 464 | list_add_tail(&class_intf->node, &parent->p->interfaces); |
465 | if (class_intf->add_dev) { | 465 | if (class_intf->add_dev) { |
466 | class_dev_iter_init(&iter, parent, NULL, NULL); | 466 | class_dev_iter_init(&iter, parent, NULL, NULL); |
467 | while ((dev = class_dev_iter_next(&iter))) | 467 | while ((dev = class_dev_iter_next(&iter))) |
468 | class_intf->add_dev(dev, class_intf); | 468 | class_intf->add_dev(dev, class_intf); |
469 | class_dev_iter_exit(&iter); | 469 | class_dev_iter_exit(&iter); |
470 | } | 470 | } |
471 | mutex_unlock(&parent->p->class_mutex); | 471 | mutex_unlock(&parent->p->mutex); |
472 | 472 | ||
473 | return 0; | 473 | return 0; |
474 | } | 474 | } |
@@ -482,7 +482,7 @@ void class_interface_unregister(struct class_interface *class_intf) | |||
482 | if (!parent) | 482 | if (!parent) |
483 | return; | 483 | return; |
484 | 484 | ||
485 | mutex_lock(&parent->p->class_mutex); | 485 | mutex_lock(&parent->p->mutex); |
486 | list_del_init(&class_intf->node); | 486 | list_del_init(&class_intf->node); |
487 | if (class_intf->remove_dev) { | 487 | if (class_intf->remove_dev) { |
488 | class_dev_iter_init(&iter, parent, NULL, NULL); | 488 | class_dev_iter_init(&iter, parent, NULL, NULL); |
@@ -490,7 +490,7 @@ void class_interface_unregister(struct class_interface *class_intf) | |||
490 | class_intf->remove_dev(dev, class_intf); | 490 | class_intf->remove_dev(dev, class_intf); |
491 | class_dev_iter_exit(&iter); | 491 | class_dev_iter_exit(&iter); |
492 | } | 492 | } |
493 | mutex_unlock(&parent->p->class_mutex); | 493 | mutex_unlock(&parent->p->mutex); |
494 | 494 | ||
495 | class_put(parent); | 495 | class_put(parent); |
496 | } | 496 | } |
diff --git a/drivers/base/core.c b/drivers/base/core.c index 919daa7cd5b1..4a67cc0c8b37 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -118,6 +118,56 @@ static const struct sysfs_ops dev_sysfs_ops = { | |||
118 | .store = dev_attr_store, | 118 | .store = dev_attr_store, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | #define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr) | ||
122 | |||
123 | ssize_t device_store_ulong(struct device *dev, | ||
124 | struct device_attribute *attr, | ||
125 | const char *buf, size_t size) | ||
126 | { | ||
127 | struct dev_ext_attribute *ea = to_ext_attr(attr); | ||
128 | char *end; | ||
129 | unsigned long new = simple_strtoul(buf, &end, 0); | ||
130 | if (end == buf) | ||
131 | return -EINVAL; | ||
132 | *(unsigned long *)(ea->var) = new; | ||
133 | /* Always return full write size even if we didn't consume all */ | ||
134 | return size; | ||
135 | } | ||
136 | EXPORT_SYMBOL_GPL(device_store_ulong); | ||
137 | |||
138 | ssize_t device_show_ulong(struct device *dev, | ||
139 | struct device_attribute *attr, | ||
140 | char *buf) | ||
141 | { | ||
142 | struct dev_ext_attribute *ea = to_ext_attr(attr); | ||
143 | return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var)); | ||
144 | } | ||
145 | EXPORT_SYMBOL_GPL(device_show_ulong); | ||
146 | |||
147 | ssize_t device_store_int(struct device *dev, | ||
148 | struct device_attribute *attr, | ||
149 | const char *buf, size_t size) | ||
150 | { | ||
151 | struct dev_ext_attribute *ea = to_ext_attr(attr); | ||
152 | char *end; | ||
153 | long new = simple_strtol(buf, &end, 0); | ||
154 | if (end == buf || new > INT_MAX || new < INT_MIN) | ||
155 | return -EINVAL; | ||
156 | *(int *)(ea->var) = new; | ||
157 | /* Always return full write size even if we didn't consume all */ | ||
158 | return size; | ||
159 | } | ||
160 | EXPORT_SYMBOL_GPL(device_store_int); | ||
161 | |||
162 | ssize_t device_show_int(struct device *dev, | ||
163 | struct device_attribute *attr, | ||
164 | char *buf) | ||
165 | { | ||
166 | struct dev_ext_attribute *ea = to_ext_attr(attr); | ||
167 | |||
168 | return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var)); | ||
169 | } | ||
170 | EXPORT_SYMBOL_GPL(device_show_int); | ||
121 | 171 | ||
122 | /** | 172 | /** |
123 | * device_release - free device structure. | 173 | * device_release - free device structure. |
@@ -198,7 +248,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, | |||
198 | if (MAJOR(dev->devt)) { | 248 | if (MAJOR(dev->devt)) { |
199 | const char *tmp; | 249 | const char *tmp; |
200 | const char *name; | 250 | const char *name; |
201 | mode_t mode = 0; | 251 | umode_t mode = 0; |
202 | 252 | ||
203 | add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); | 253 | add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); |
204 | add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); | 254 | add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); |
@@ -464,7 +514,7 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr, | |||
464 | static struct device_attribute devt_attr = | 514 | static struct device_attribute devt_attr = |
465 | __ATTR(dev, S_IRUGO, show_dev, NULL); | 515 | __ATTR(dev, S_IRUGO, show_dev, NULL); |
466 | 516 | ||
467 | /* kset to create /sys/devices/ */ | 517 | /* /sys/devices/ */ |
468 | struct kset *devices_kset; | 518 | struct kset *devices_kset; |
469 | 519 | ||
470 | /** | 520 | /** |
@@ -711,6 +761,10 @@ static struct kobject *get_device_parent(struct device *dev, | |||
711 | return k; | 761 | return k; |
712 | } | 762 | } |
713 | 763 | ||
764 | /* subsystems can specify a default root directory for their devices */ | ||
765 | if (!parent && dev->bus && dev->bus->dev_root) | ||
766 | return &dev->bus->dev_root->kobj; | ||
767 | |||
714 | if (parent) | 768 | if (parent) |
715 | return &parent->kobj; | 769 | return &parent->kobj; |
716 | return NULL; | 770 | return NULL; |
@@ -731,14 +785,6 @@ static void cleanup_device_parent(struct device *dev) | |||
731 | cleanup_glue_dir(dev, dev->kobj.parent); | 785 | cleanup_glue_dir(dev, dev->kobj.parent); |
732 | } | 786 | } |
733 | 787 | ||
734 | static void setup_parent(struct device *dev, struct device *parent) | ||
735 | { | ||
736 | struct kobject *kobj; | ||
737 | kobj = get_device_parent(dev, parent); | ||
738 | if (kobj) | ||
739 | dev->kobj.parent = kobj; | ||
740 | } | ||
741 | |||
742 | static int device_add_class_symlinks(struct device *dev) | 788 | static int device_add_class_symlinks(struct device *dev) |
743 | { | 789 | { |
744 | int error; | 790 | int error; |
@@ -891,6 +937,7 @@ int device_private_init(struct device *dev) | |||
891 | int device_add(struct device *dev) | 937 | int device_add(struct device *dev) |
892 | { | 938 | { |
893 | struct device *parent = NULL; | 939 | struct device *parent = NULL; |
940 | struct kobject *kobj; | ||
894 | struct class_interface *class_intf; | 941 | struct class_interface *class_intf; |
895 | int error = -EINVAL; | 942 | int error = -EINVAL; |
896 | 943 | ||
@@ -914,6 +961,10 @@ int device_add(struct device *dev) | |||
914 | dev->init_name = NULL; | 961 | dev->init_name = NULL; |
915 | } | 962 | } |
916 | 963 | ||
964 | /* subsystems can specify simple device enumeration */ | ||
965 | if (!dev_name(dev) && dev->bus && dev->bus->dev_name) | ||
966 | dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); | ||
967 | |||
917 | if (!dev_name(dev)) { | 968 | if (!dev_name(dev)) { |
918 | error = -EINVAL; | 969 | error = -EINVAL; |
919 | goto name_error; | 970 | goto name_error; |
@@ -922,7 +973,9 @@ int device_add(struct device *dev) | |||
922 | pr_debug("device: '%s': %s\n", dev_name(dev), __func__); | 973 | pr_debug("device: '%s': %s\n", dev_name(dev), __func__); |
923 | 974 | ||
924 | parent = get_device(dev->parent); | 975 | parent = get_device(dev->parent); |
925 | setup_parent(dev, parent); | 976 | kobj = get_device_parent(dev, parent); |
977 | if (kobj) | ||
978 | dev->kobj.parent = kobj; | ||
926 | 979 | ||
927 | /* use parent numa_node */ | 980 | /* use parent numa_node */ |
928 | if (parent) | 981 | if (parent) |
@@ -982,17 +1035,17 @@ int device_add(struct device *dev) | |||
982 | &parent->p->klist_children); | 1035 | &parent->p->klist_children); |
983 | 1036 | ||
984 | if (dev->class) { | 1037 | if (dev->class) { |
985 | mutex_lock(&dev->class->p->class_mutex); | 1038 | mutex_lock(&dev->class->p->mutex); |
986 | /* tie the class to the device */ | 1039 | /* tie the class to the device */ |
987 | klist_add_tail(&dev->knode_class, | 1040 | klist_add_tail(&dev->knode_class, |
988 | &dev->class->p->klist_devices); | 1041 | &dev->class->p->klist_devices); |
989 | 1042 | ||
990 | /* notify any interfaces that the device is here */ | 1043 | /* notify any interfaces that the device is here */ |
991 | list_for_each_entry(class_intf, | 1044 | list_for_each_entry(class_intf, |
992 | &dev->class->p->class_interfaces, node) | 1045 | &dev->class->p->interfaces, node) |
993 | if (class_intf->add_dev) | 1046 | if (class_intf->add_dev) |
994 | class_intf->add_dev(dev, class_intf); | 1047 | class_intf->add_dev(dev, class_intf); |
995 | mutex_unlock(&dev->class->p->class_mutex); | 1048 | mutex_unlock(&dev->class->p->mutex); |
996 | } | 1049 | } |
997 | done: | 1050 | done: |
998 | put_device(dev); | 1051 | put_device(dev); |
@@ -1107,15 +1160,15 @@ void device_del(struct device *dev) | |||
1107 | if (dev->class) { | 1160 | if (dev->class) { |
1108 | device_remove_class_symlinks(dev); | 1161 | device_remove_class_symlinks(dev); |
1109 | 1162 | ||
1110 | mutex_lock(&dev->class->p->class_mutex); | 1163 | mutex_lock(&dev->class->p->mutex); |
1111 | /* notify any interfaces that the device is now gone */ | 1164 | /* notify any interfaces that the device is now gone */ |
1112 | list_for_each_entry(class_intf, | 1165 | list_for_each_entry(class_intf, |
1113 | &dev->class->p->class_interfaces, node) | 1166 | &dev->class->p->interfaces, node) |
1114 | if (class_intf->remove_dev) | 1167 | if (class_intf->remove_dev) |
1115 | class_intf->remove_dev(dev, class_intf); | 1168 | class_intf->remove_dev(dev, class_intf); |
1116 | /* remove the device from the class list */ | 1169 | /* remove the device from the class list */ |
1117 | klist_del(&dev->knode_class); | 1170 | klist_del(&dev->knode_class); |
1118 | mutex_unlock(&dev->class->p->class_mutex); | 1171 | mutex_unlock(&dev->class->p->mutex); |
1119 | } | 1172 | } |
1120 | device_remove_file(dev, &uevent_attr); | 1173 | device_remove_file(dev, &uevent_attr); |
1121 | device_remove_attrs(dev); | 1174 | device_remove_attrs(dev); |
@@ -1182,7 +1235,7 @@ static struct device *next_device(struct klist_iter *i) | |||
1182 | * freed by the caller. | 1235 | * freed by the caller. |
1183 | */ | 1236 | */ |
1184 | const char *device_get_devnode(struct device *dev, | 1237 | const char *device_get_devnode(struct device *dev, |
1185 | mode_t *mode, const char **tmp) | 1238 | umode_t *mode, const char **tmp) |
1186 | { | 1239 | { |
1187 | char *s; | 1240 | char *s; |
1188 | 1241 | ||
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 251acea3d359..9a5578efbc93 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c | |||
@@ -1,8 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/base/cpu.c - basic CPU class support | 2 | * CPU subsystem support |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/sysdev.h> | ||
6 | #include <linux/module.h> | 5 | #include <linux/module.h> |
7 | #include <linux/init.h> | 6 | #include <linux/init.h> |
8 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
@@ -14,40 +13,40 @@ | |||
14 | 13 | ||
15 | #include "base.h" | 14 | #include "base.h" |
16 | 15 | ||
17 | static struct sysdev_class_attribute *cpu_sysdev_class_attrs[]; | 16 | struct bus_type cpu_subsys = { |
18 | |||
19 | struct sysdev_class cpu_sysdev_class = { | ||
20 | .name = "cpu", | 17 | .name = "cpu", |
21 | .attrs = cpu_sysdev_class_attrs, | 18 | .dev_name = "cpu", |
22 | }; | 19 | }; |
23 | EXPORT_SYMBOL(cpu_sysdev_class); | 20 | EXPORT_SYMBOL_GPL(cpu_subsys); |
24 | 21 | ||
25 | static DEFINE_PER_CPU(struct sys_device *, cpu_sys_devices); | 22 | static DEFINE_PER_CPU(struct device *, cpu_sys_devices); |
26 | 23 | ||
27 | #ifdef CONFIG_HOTPLUG_CPU | 24 | #ifdef CONFIG_HOTPLUG_CPU |
28 | static ssize_t show_online(struct sys_device *dev, struct sysdev_attribute *attr, | 25 | static ssize_t show_online(struct device *dev, |
26 | struct device_attribute *attr, | ||
29 | char *buf) | 27 | char *buf) |
30 | { | 28 | { |
31 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | 29 | struct cpu *cpu = container_of(dev, struct cpu, dev); |
32 | 30 | ||
33 | return sprintf(buf, "%u\n", !!cpu_online(cpu->sysdev.id)); | 31 | return sprintf(buf, "%u\n", !!cpu_online(cpu->dev.id)); |
34 | } | 32 | } |
35 | 33 | ||
36 | static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribute *attr, | 34 | static ssize_t __ref store_online(struct device *dev, |
37 | const char *buf, size_t count) | 35 | struct device_attribute *attr, |
36 | const char *buf, size_t count) | ||
38 | { | 37 | { |
39 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | 38 | struct cpu *cpu = container_of(dev, struct cpu, dev); |
40 | ssize_t ret; | 39 | ssize_t ret; |
41 | 40 | ||
42 | cpu_hotplug_driver_lock(); | 41 | cpu_hotplug_driver_lock(); |
43 | switch (buf[0]) { | 42 | switch (buf[0]) { |
44 | case '0': | 43 | case '0': |
45 | ret = cpu_down(cpu->sysdev.id); | 44 | ret = cpu_down(cpu->dev.id); |
46 | if (!ret) | 45 | if (!ret) |
47 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); | 46 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); |
48 | break; | 47 | break; |
49 | case '1': | 48 | case '1': |
50 | ret = cpu_up(cpu->sysdev.id); | 49 | ret = cpu_up(cpu->dev.id); |
51 | if (!ret) | 50 | if (!ret) |
52 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); | 51 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); |
53 | break; | 52 | break; |
@@ -60,44 +59,44 @@ static ssize_t __ref store_online(struct sys_device *dev, struct sysdev_attribut | |||
60 | ret = count; | 59 | ret = count; |
61 | return ret; | 60 | return ret; |
62 | } | 61 | } |
63 | static SYSDEV_ATTR(online, 0644, show_online, store_online); | 62 | static DEVICE_ATTR(online, 0644, show_online, store_online); |
64 | 63 | ||
65 | static void __cpuinit register_cpu_control(struct cpu *cpu) | 64 | static void __cpuinit register_cpu_control(struct cpu *cpu) |
66 | { | 65 | { |
67 | sysdev_create_file(&cpu->sysdev, &attr_online); | 66 | device_create_file(&cpu->dev, &dev_attr_online); |
68 | } | 67 | } |
69 | void unregister_cpu(struct cpu *cpu) | 68 | void unregister_cpu(struct cpu *cpu) |
70 | { | 69 | { |
71 | int logical_cpu = cpu->sysdev.id; | 70 | int logical_cpu = cpu->dev.id; |
72 | 71 | ||
73 | unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); | 72 | unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); |
74 | 73 | ||
75 | sysdev_remove_file(&cpu->sysdev, &attr_online); | 74 | device_remove_file(&cpu->dev, &dev_attr_online); |
76 | 75 | ||
77 | sysdev_unregister(&cpu->sysdev); | 76 | device_unregister(&cpu->dev); |
78 | per_cpu(cpu_sys_devices, logical_cpu) = NULL; | 77 | per_cpu(cpu_sys_devices, logical_cpu) = NULL; |
79 | return; | 78 | return; |
80 | } | 79 | } |
81 | 80 | ||
82 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE | 81 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE |
83 | static ssize_t cpu_probe_store(struct sysdev_class *class, | 82 | static ssize_t cpu_probe_store(struct device *dev, |
84 | struct sysdev_class_attribute *attr, | 83 | struct device_attribute *attr, |
85 | const char *buf, | 84 | const char *buf, |
86 | size_t count) | 85 | size_t count) |
87 | { | 86 | { |
88 | return arch_cpu_probe(buf, count); | 87 | return arch_cpu_probe(buf, count); |
89 | } | 88 | } |
90 | 89 | ||
91 | static ssize_t cpu_release_store(struct sysdev_class *class, | 90 | static ssize_t cpu_release_store(struct device *dev, |
92 | struct sysdev_class_attribute *attr, | 91 | struct device_attribute *attr, |
93 | const char *buf, | 92 | const char *buf, |
94 | size_t count) | 93 | size_t count) |
95 | { | 94 | { |
96 | return arch_cpu_release(buf, count); | 95 | return arch_cpu_release(buf, count); |
97 | } | 96 | } |
98 | 97 | ||
99 | static SYSDEV_CLASS_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); | 98 | static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); |
100 | static SYSDEV_CLASS_ATTR(release, S_IWUSR, NULL, cpu_release_store); | 99 | static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); |
101 | #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ | 100 | #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ |
102 | 101 | ||
103 | #else /* ... !CONFIG_HOTPLUG_CPU */ | 102 | #else /* ... !CONFIG_HOTPLUG_CPU */ |
@@ -109,15 +108,15 @@ static inline void register_cpu_control(struct cpu *cpu) | |||
109 | #ifdef CONFIG_KEXEC | 108 | #ifdef CONFIG_KEXEC |
110 | #include <linux/kexec.h> | 109 | #include <linux/kexec.h> |
111 | 110 | ||
112 | static ssize_t show_crash_notes(struct sys_device *dev, struct sysdev_attribute *attr, | 111 | static ssize_t show_crash_notes(struct device *dev, struct device_attribute *attr, |
113 | char *buf) | 112 | char *buf) |
114 | { | 113 | { |
115 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | 114 | struct cpu *cpu = container_of(dev, struct cpu, dev); |
116 | ssize_t rc; | 115 | ssize_t rc; |
117 | unsigned long long addr; | 116 | unsigned long long addr; |
118 | int cpunum; | 117 | int cpunum; |
119 | 118 | ||
120 | cpunum = cpu->sysdev.id; | 119 | cpunum = cpu->dev.id; |
121 | 120 | ||
122 | /* | 121 | /* |
123 | * Might be reading other cpu's data based on which cpu read thread | 122 | * Might be reading other cpu's data based on which cpu read thread |
@@ -129,7 +128,7 @@ static ssize_t show_crash_notes(struct sys_device *dev, struct sysdev_attribute | |||
129 | rc = sprintf(buf, "%Lx\n", addr); | 128 | rc = sprintf(buf, "%Lx\n", addr); |
130 | return rc; | 129 | return rc; |
131 | } | 130 | } |
132 | static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); | 131 | static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL); |
133 | #endif | 132 | #endif |
134 | 133 | ||
135 | /* | 134 | /* |
@@ -137,12 +136,12 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); | |||
137 | */ | 136 | */ |
138 | 137 | ||
139 | struct cpu_attr { | 138 | struct cpu_attr { |
140 | struct sysdev_class_attribute attr; | 139 | struct device_attribute attr; |
141 | const struct cpumask *const * const map; | 140 | const struct cpumask *const * const map; |
142 | }; | 141 | }; |
143 | 142 | ||
144 | static ssize_t show_cpus_attr(struct sysdev_class *class, | 143 | static ssize_t show_cpus_attr(struct device *dev, |
145 | struct sysdev_class_attribute *attr, | 144 | struct device_attribute *attr, |
146 | char *buf) | 145 | char *buf) |
147 | { | 146 | { |
148 | struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); | 147 | struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); |
@@ -153,10 +152,10 @@ static ssize_t show_cpus_attr(struct sysdev_class *class, | |||
153 | return n; | 152 | return n; |
154 | } | 153 | } |
155 | 154 | ||
156 | #define _CPU_ATTR(name, map) \ | 155 | #define _CPU_ATTR(name, map) \ |
157 | { _SYSDEV_CLASS_ATTR(name, 0444, show_cpus_attr, NULL), map } | 156 | { __ATTR(name, 0444, show_cpus_attr, NULL), map } |
158 | 157 | ||
159 | /* Keep in sync with cpu_sysdev_class_attrs */ | 158 | /* Keep in sync with cpu_subsys_attrs */ |
160 | static struct cpu_attr cpu_attrs[] = { | 159 | static struct cpu_attr cpu_attrs[] = { |
161 | _CPU_ATTR(online, &cpu_online_mask), | 160 | _CPU_ATTR(online, &cpu_online_mask), |
162 | _CPU_ATTR(possible, &cpu_possible_mask), | 161 | _CPU_ATTR(possible, &cpu_possible_mask), |
@@ -166,19 +165,19 @@ static struct cpu_attr cpu_attrs[] = { | |||
166 | /* | 165 | /* |
167 | * Print values for NR_CPUS and offlined cpus | 166 | * Print values for NR_CPUS and offlined cpus |
168 | */ | 167 | */ |
169 | static ssize_t print_cpus_kernel_max(struct sysdev_class *class, | 168 | static ssize_t print_cpus_kernel_max(struct device *dev, |
170 | struct sysdev_class_attribute *attr, char *buf) | 169 | struct device_attribute *attr, char *buf) |
171 | { | 170 | { |
172 | int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); | 171 | int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); |
173 | return n; | 172 | return n; |
174 | } | 173 | } |
175 | static SYSDEV_CLASS_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); | 174 | static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); |
176 | 175 | ||
177 | /* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ | 176 | /* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ |
178 | unsigned int total_cpus; | 177 | unsigned int total_cpus; |
179 | 178 | ||
180 | static ssize_t print_cpus_offline(struct sysdev_class *class, | 179 | static ssize_t print_cpus_offline(struct device *dev, |
181 | struct sysdev_class_attribute *attr, char *buf) | 180 | struct device_attribute *attr, char *buf) |
182 | { | 181 | { |
183 | int n = 0, len = PAGE_SIZE-2; | 182 | int n = 0, len = PAGE_SIZE-2; |
184 | cpumask_var_t offline; | 183 | cpumask_var_t offline; |
@@ -205,7 +204,7 @@ static ssize_t print_cpus_offline(struct sysdev_class *class, | |||
205 | n += snprintf(&buf[n], len - n, "\n"); | 204 | n += snprintf(&buf[n], len - n, "\n"); |
206 | return n; | 205 | return n; |
207 | } | 206 | } |
208 | static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL); | 207 | static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); |
209 | 208 | ||
210 | /* | 209 | /* |
211 | * register_cpu - Setup a sysfs device for a CPU. | 210 | * register_cpu - Setup a sysfs device for a CPU. |
@@ -218,57 +217,73 @@ static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL); | |||
218 | int __cpuinit register_cpu(struct cpu *cpu, int num) | 217 | int __cpuinit register_cpu(struct cpu *cpu, int num) |
219 | { | 218 | { |
220 | int error; | 219 | int error; |
221 | cpu->node_id = cpu_to_node(num); | ||
222 | cpu->sysdev.id = num; | ||
223 | cpu->sysdev.cls = &cpu_sysdev_class; | ||
224 | |||
225 | error = sysdev_register(&cpu->sysdev); | ||
226 | 220 | ||
221 | cpu->node_id = cpu_to_node(num); | ||
222 | cpu->dev.id = num; | ||
223 | cpu->dev.bus = &cpu_subsys; | ||
224 | error = device_register(&cpu->dev); | ||
227 | if (!error && cpu->hotpluggable) | 225 | if (!error && cpu->hotpluggable) |
228 | register_cpu_control(cpu); | 226 | register_cpu_control(cpu); |
229 | if (!error) | 227 | if (!error) |
230 | per_cpu(cpu_sys_devices, num) = &cpu->sysdev; | 228 | per_cpu(cpu_sys_devices, num) = &cpu->dev; |
231 | if (!error) | 229 | if (!error) |
232 | register_cpu_under_node(num, cpu_to_node(num)); | 230 | register_cpu_under_node(num, cpu_to_node(num)); |
233 | 231 | ||
234 | #ifdef CONFIG_KEXEC | 232 | #ifdef CONFIG_KEXEC |
235 | if (!error) | 233 | if (!error) |
236 | error = sysdev_create_file(&cpu->sysdev, &attr_crash_notes); | 234 | error = device_create_file(&cpu->dev, &dev_attr_crash_notes); |
237 | #endif | 235 | #endif |
238 | return error; | 236 | return error; |
239 | } | 237 | } |
240 | 238 | ||
241 | struct sys_device *get_cpu_sysdev(unsigned cpu) | 239 | struct device *get_cpu_device(unsigned cpu) |
242 | { | 240 | { |
243 | if (cpu < nr_cpu_ids && cpu_possible(cpu)) | 241 | if (cpu < nr_cpu_ids && cpu_possible(cpu)) |
244 | return per_cpu(cpu_sys_devices, cpu); | 242 | return per_cpu(cpu_sys_devices, cpu); |
245 | else | 243 | else |
246 | return NULL; | 244 | return NULL; |
247 | } | 245 | } |
248 | EXPORT_SYMBOL_GPL(get_cpu_sysdev); | 246 | EXPORT_SYMBOL_GPL(get_cpu_device); |
247 | |||
248 | static struct attribute *cpu_root_attrs[] = { | ||
249 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE | ||
250 | &dev_attr_probe.attr, | ||
251 | &dev_attr_release.attr, | ||
252 | #endif | ||
253 | &cpu_attrs[0].attr.attr, | ||
254 | &cpu_attrs[1].attr.attr, | ||
255 | &cpu_attrs[2].attr.attr, | ||
256 | &dev_attr_kernel_max.attr, | ||
257 | &dev_attr_offline.attr, | ||
258 | NULL | ||
259 | }; | ||
260 | |||
261 | static struct attribute_group cpu_root_attr_group = { | ||
262 | .attrs = cpu_root_attrs, | ||
263 | }; | ||
264 | |||
265 | static const struct attribute_group *cpu_root_attr_groups[] = { | ||
266 | &cpu_root_attr_group, | ||
267 | NULL, | ||
268 | }; | ||
269 | |||
270 | bool cpu_is_hotpluggable(unsigned cpu) | ||
271 | { | ||
272 | struct device *dev = get_cpu_device(cpu); | ||
273 | return dev && container_of(dev, struct cpu, dev)->hotpluggable; | ||
274 | } | ||
275 | EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); | ||
249 | 276 | ||
250 | int __init cpu_dev_init(void) | 277 | int __init cpu_dev_init(void) |
251 | { | 278 | { |
252 | int err; | 279 | int err; |
253 | 280 | ||
254 | err = sysdev_class_register(&cpu_sysdev_class); | 281 | err = subsys_system_register(&cpu_subsys, cpu_root_attr_groups); |
282 | if (err) | ||
283 | return err; | ||
284 | |||
255 | #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) | 285 | #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) |
256 | if (!err) | 286 | err = sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root); |
257 | err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class); | ||
258 | #endif | 287 | #endif |
259 | |||
260 | return err; | 288 | return err; |
261 | } | 289 | } |
262 | |||
263 | static struct sysdev_class_attribute *cpu_sysdev_class_attrs[] = { | ||
264 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE | ||
265 | &attr_probe, | ||
266 | &attr_release, | ||
267 | #endif | ||
268 | &cpu_attrs[0].attr, | ||
269 | &cpu_attrs[1].attr, | ||
270 | &cpu_attrs[2].attr, | ||
271 | &attr_kernel_max, | ||
272 | &attr_offline, | ||
273 | NULL | ||
274 | }; | ||
diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 65cd74832450..524bf96c289f 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c | |||
@@ -639,7 +639,7 @@ EXPORT_SYMBOL_GPL(devm_kzalloc); | |||
639 | * @dev: Device this memory belongs to | 639 | * @dev: Device this memory belongs to |
640 | * @p: Memory to free | 640 | * @p: Memory to free |
641 | * | 641 | * |
642 | * Free memory allocated with dev_kzalloc(). | 642 | * Free memory allocated with devm_kzalloc(). |
643 | */ | 643 | */ |
644 | void devm_kfree(struct device *dev, void *p) | 644 | void devm_kfree(struct device *dev, void *p) |
645 | { | 645 | { |
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index a4760e095ff5..8493536ea55b 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c | |||
@@ -40,7 +40,7 @@ static struct req { | |||
40 | struct completion done; | 40 | struct completion done; |
41 | int err; | 41 | int err; |
42 | const char *name; | 42 | const char *name; |
43 | mode_t mode; /* 0 => delete */ | 43 | umode_t mode; /* 0 => delete */ |
44 | struct device *dev; | 44 | struct device *dev; |
45 | } *requests; | 45 | } *requests; |
46 | 46 | ||
@@ -142,7 +142,7 @@ int devtmpfs_delete_node(struct device *dev) | |||
142 | return req.err; | 142 | return req.err; |
143 | } | 143 | } |
144 | 144 | ||
145 | static int dev_mkdir(const char *name, mode_t mode) | 145 | static int dev_mkdir(const char *name, umode_t mode) |
146 | { | 146 | { |
147 | struct dentry *dentry; | 147 | struct dentry *dentry; |
148 | struct path path; | 148 | struct path path; |
@@ -189,7 +189,7 @@ static int create_path(const char *nodepath) | |||
189 | return err; | 189 | return err; |
190 | } | 190 | } |
191 | 191 | ||
192 | static int handle_create(const char *nodename, mode_t mode, struct device *dev) | 192 | static int handle_create(const char *nodename, umode_t mode, struct device *dev) |
193 | { | 193 | { |
194 | struct dentry *dentry; | 194 | struct dentry *dentry; |
195 | struct path path; | 195 | struct path path; |
@@ -378,7 +378,7 @@ int devtmpfs_mount(const char *mntdir) | |||
378 | 378 | ||
379 | static DECLARE_COMPLETION(setup_done); | 379 | static DECLARE_COMPLETION(setup_done); |
380 | 380 | ||
381 | static int handle(const char *name, mode_t mode, struct device *dev) | 381 | static int handle(const char *name, umode_t mode, struct device *dev) |
382 | { | 382 | { |
383 | if (mode) | 383 | if (mode) |
384 | return handle_create(name, mode, dev); | 384 | return handle_create(name, mode, dev); |
@@ -413,10 +413,9 @@ static int devtmpfsd(void *p) | |||
413 | } | 413 | } |
414 | spin_lock(&req_lock); | 414 | spin_lock(&req_lock); |
415 | } | 415 | } |
416 | set_current_state(TASK_INTERRUPTIBLE); | 416 | __set_current_state(TASK_INTERRUPTIBLE); |
417 | spin_unlock(&req_lock); | 417 | spin_unlock(&req_lock); |
418 | schedule(); | 418 | schedule(); |
419 | __set_current_state(TASK_RUNNING); | ||
420 | } | 419 | } |
421 | return 0; | 420 | return 0; |
422 | out: | 421 | out: |
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 06ed6b4e7df5..26ab358dac62 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -226,13 +226,13 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
226 | int loading = simple_strtol(buf, NULL, 10); | 226 | int loading = simple_strtol(buf, NULL, 10); |
227 | int i; | 227 | int i; |
228 | 228 | ||
229 | mutex_lock(&fw_lock); | ||
230 | |||
231 | if (!fw_priv->fw) | ||
232 | goto out; | ||
233 | |||
229 | switch (loading) { | 234 | switch (loading) { |
230 | case 1: | 235 | case 1: |
231 | mutex_lock(&fw_lock); | ||
232 | if (!fw_priv->fw) { | ||
233 | mutex_unlock(&fw_lock); | ||
234 | break; | ||
235 | } | ||
236 | firmware_free_data(fw_priv->fw); | 236 | firmware_free_data(fw_priv->fw); |
237 | memset(fw_priv->fw, 0, sizeof(struct firmware)); | 237 | memset(fw_priv->fw, 0, sizeof(struct firmware)); |
238 | /* If the pages are not owned by 'struct firmware' */ | 238 | /* If the pages are not owned by 'struct firmware' */ |
@@ -243,7 +243,6 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
243 | fw_priv->page_array_size = 0; | 243 | fw_priv->page_array_size = 0; |
244 | fw_priv->nr_pages = 0; | 244 | fw_priv->nr_pages = 0; |
245 | set_bit(FW_STATUS_LOADING, &fw_priv->status); | 245 | set_bit(FW_STATUS_LOADING, &fw_priv->status); |
246 | mutex_unlock(&fw_lock); | ||
247 | break; | 246 | break; |
248 | case 0: | 247 | case 0: |
249 | if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { | 248 | if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { |
@@ -274,7 +273,8 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
274 | fw_load_abort(fw_priv); | 273 | fw_load_abort(fw_priv); |
275 | break; | 274 | break; |
276 | } | 275 | } |
277 | 276 | out: | |
277 | mutex_unlock(&fw_lock); | ||
278 | return count; | 278 | return count; |
279 | } | 279 | } |
280 | 280 | ||
@@ -534,6 +534,8 @@ static int _request_firmware(const struct firmware **firmware_p, | |||
534 | return 0; | 534 | return 0; |
535 | } | 535 | } |
536 | 536 | ||
537 | read_lock_usermodehelper(); | ||
538 | |||
537 | if (WARN_ON(usermodehelper_is_disabled())) { | 539 | if (WARN_ON(usermodehelper_is_disabled())) { |
538 | dev_err(device, "firmware: %s will not be loaded\n", name); | 540 | dev_err(device, "firmware: %s will not be loaded\n", name); |
539 | retval = -EBUSY; | 541 | retval = -EBUSY; |
@@ -572,6 +574,8 @@ static int _request_firmware(const struct firmware **firmware_p, | |||
572 | fw_destroy_instance(fw_priv); | 574 | fw_destroy_instance(fw_priv); |
573 | 575 | ||
574 | out: | 576 | out: |
577 | read_unlock_usermodehelper(); | ||
578 | |||
575 | if (retval) { | 579 | if (retval) { |
576 | release_firmware(firmware); | 580 | release_firmware(firmware); |
577 | *firmware_p = NULL; | 581 | *firmware_p = NULL; |
diff --git a/drivers/base/init.c b/drivers/base/init.c index c8a934e79421..c16f0b808a17 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c | |||
@@ -31,7 +31,6 @@ void __init driver_init(void) | |||
31 | * core core pieces. | 31 | * core core pieces. |
32 | */ | 32 | */ |
33 | platform_bus_init(); | 33 | platform_bus_init(); |
34 | system_bus_init(); | ||
35 | cpu_dev_init(); | 34 | cpu_dev_init(); |
36 | memory_dev_init(); | 35 | memory_dev_init(); |
37 | } | 36 | } |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 8272d92d22c0..f17e3ea041c0 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/base/memory.c - basic Memory class support | 2 | * Memory subsystem support |
3 | * | 3 | * |
4 | * Written by Matt Tolentino <matthew.e.tolentino@intel.com> | 4 | * Written by Matt Tolentino <matthew.e.tolentino@intel.com> |
5 | * Dave Hansen <haveblue@us.ibm.com> | 5 | * Dave Hansen <haveblue@us.ibm.com> |
@@ -10,7 +10,6 @@ | |||
10 | * SPARSEMEM should be contained here, or in mm/memory_hotplug.c. | 10 | * SPARSEMEM should be contained here, or in mm/memory_hotplug.c. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/sysdev.h> | ||
14 | #include <linux/module.h> | 13 | #include <linux/module.h> |
15 | #include <linux/init.h> | 14 | #include <linux/init.h> |
16 | #include <linux/topology.h> | 15 | #include <linux/topology.h> |
@@ -38,26 +37,9 @@ static inline int base_memory_block_id(int section_nr) | |||
38 | return section_nr / sections_per_block; | 37 | return section_nr / sections_per_block; |
39 | } | 38 | } |
40 | 39 | ||
41 | static struct sysdev_class memory_sysdev_class = { | 40 | static struct bus_type memory_subsys = { |
42 | .name = MEMORY_CLASS_NAME, | 41 | .name = MEMORY_CLASS_NAME, |
43 | }; | 42 | .dev_name = MEMORY_CLASS_NAME, |
44 | |||
45 | static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) | ||
46 | { | ||
47 | return MEMORY_CLASS_NAME; | ||
48 | } | ||
49 | |||
50 | static int memory_uevent(struct kset *kset, struct kobject *obj, | ||
51 | struct kobj_uevent_env *env) | ||
52 | { | ||
53 | int retval = 0; | ||
54 | |||
55 | return retval; | ||
56 | } | ||
57 | |||
58 | static const struct kset_uevent_ops memory_uevent_ops = { | ||
59 | .name = memory_uevent_name, | ||
60 | .uevent = memory_uevent, | ||
61 | }; | 43 | }; |
62 | 44 | ||
63 | static BLOCKING_NOTIFIER_HEAD(memory_chain); | 45 | static BLOCKING_NOTIFIER_HEAD(memory_chain); |
@@ -96,21 +78,21 @@ int register_memory(struct memory_block *memory) | |||
96 | { | 78 | { |
97 | int error; | 79 | int error; |
98 | 80 | ||
99 | memory->sysdev.cls = &memory_sysdev_class; | 81 | memory->dev.bus = &memory_subsys; |
100 | memory->sysdev.id = memory->start_section_nr / sections_per_block; | 82 | memory->dev.id = memory->start_section_nr / sections_per_block; |
101 | 83 | ||
102 | error = sysdev_register(&memory->sysdev); | 84 | error = device_register(&memory->dev); |
103 | return error; | 85 | return error; |
104 | } | 86 | } |
105 | 87 | ||
106 | static void | 88 | static void |
107 | unregister_memory(struct memory_block *memory) | 89 | unregister_memory(struct memory_block *memory) |
108 | { | 90 | { |
109 | BUG_ON(memory->sysdev.cls != &memory_sysdev_class); | 91 | BUG_ON(memory->dev.bus != &memory_subsys); |
110 | 92 | ||
111 | /* drop the ref. we got in remove_memory_block() */ | 93 | /* drop the ref. we got in remove_memory_block() */ |
112 | kobject_put(&memory->sysdev.kobj); | 94 | kobject_put(&memory->dev.kobj); |
113 | sysdev_unregister(&memory->sysdev); | 95 | device_unregister(&memory->dev); |
114 | } | 96 | } |
115 | 97 | ||
116 | unsigned long __weak memory_block_size_bytes(void) | 98 | unsigned long __weak memory_block_size_bytes(void) |
@@ -138,22 +120,22 @@ static unsigned long get_memory_block_size(void) | |||
138 | * uses. | 120 | * uses. |
139 | */ | 121 | */ |
140 | 122 | ||
141 | static ssize_t show_mem_start_phys_index(struct sys_device *dev, | 123 | static ssize_t show_mem_start_phys_index(struct device *dev, |
142 | struct sysdev_attribute *attr, char *buf) | 124 | struct device_attribute *attr, char *buf) |
143 | { | 125 | { |
144 | struct memory_block *mem = | 126 | struct memory_block *mem = |
145 | container_of(dev, struct memory_block, sysdev); | 127 | container_of(dev, struct memory_block, dev); |
146 | unsigned long phys_index; | 128 | unsigned long phys_index; |
147 | 129 | ||
148 | phys_index = mem->start_section_nr / sections_per_block; | 130 | phys_index = mem->start_section_nr / sections_per_block; |
149 | return sprintf(buf, "%08lx\n", phys_index); | 131 | return sprintf(buf, "%08lx\n", phys_index); |
150 | } | 132 | } |
151 | 133 | ||
152 | static ssize_t show_mem_end_phys_index(struct sys_device *dev, | 134 | static ssize_t show_mem_end_phys_index(struct device *dev, |
153 | struct sysdev_attribute *attr, char *buf) | 135 | struct device_attribute *attr, char *buf) |
154 | { | 136 | { |
155 | struct memory_block *mem = | 137 | struct memory_block *mem = |
156 | container_of(dev, struct memory_block, sysdev); | 138 | container_of(dev, struct memory_block, dev); |
157 | unsigned long phys_index; | 139 | unsigned long phys_index; |
158 | 140 | ||
159 | phys_index = mem->end_section_nr / sections_per_block; | 141 | phys_index = mem->end_section_nr / sections_per_block; |
@@ -163,13 +145,13 @@ static ssize_t show_mem_end_phys_index(struct sys_device *dev, | |||
163 | /* | 145 | /* |
164 | * Show whether the section of memory is likely to be hot-removable | 146 | * Show whether the section of memory is likely to be hot-removable |
165 | */ | 147 | */ |
166 | static ssize_t show_mem_removable(struct sys_device *dev, | 148 | static ssize_t show_mem_removable(struct device *dev, |
167 | struct sysdev_attribute *attr, char *buf) | 149 | struct device_attribute *attr, char *buf) |
168 | { | 150 | { |
169 | unsigned long i, pfn; | 151 | unsigned long i, pfn; |
170 | int ret = 1; | 152 | int ret = 1; |
171 | struct memory_block *mem = | 153 | struct memory_block *mem = |
172 | container_of(dev, struct memory_block, sysdev); | 154 | container_of(dev, struct memory_block, dev); |
173 | 155 | ||
174 | for (i = 0; i < sections_per_block; i++) { | 156 | for (i = 0; i < sections_per_block; i++) { |
175 | pfn = section_nr_to_pfn(mem->start_section_nr + i); | 157 | pfn = section_nr_to_pfn(mem->start_section_nr + i); |
@@ -182,11 +164,11 @@ static ssize_t show_mem_removable(struct sys_device *dev, | |||
182 | /* | 164 | /* |
183 | * online, offline, going offline, etc. | 165 | * online, offline, going offline, etc. |
184 | */ | 166 | */ |
185 | static ssize_t show_mem_state(struct sys_device *dev, | 167 | static ssize_t show_mem_state(struct device *dev, |
186 | struct sysdev_attribute *attr, char *buf) | 168 | struct device_attribute *attr, char *buf) |
187 | { | 169 | { |
188 | struct memory_block *mem = | 170 | struct memory_block *mem = |
189 | container_of(dev, struct memory_block, sysdev); | 171 | container_of(dev, struct memory_block, dev); |
190 | ssize_t len = 0; | 172 | ssize_t len = 0; |
191 | 173 | ||
192 | /* | 174 | /* |
@@ -324,13 +306,13 @@ out: | |||
324 | } | 306 | } |
325 | 307 | ||
326 | static ssize_t | 308 | static ssize_t |
327 | store_mem_state(struct sys_device *dev, | 309 | store_mem_state(struct device *dev, |
328 | struct sysdev_attribute *attr, const char *buf, size_t count) | 310 | struct device_attribute *attr, const char *buf, size_t count) |
329 | { | 311 | { |
330 | struct memory_block *mem; | 312 | struct memory_block *mem; |
331 | int ret = -EINVAL; | 313 | int ret = -EINVAL; |
332 | 314 | ||
333 | mem = container_of(dev, struct memory_block, sysdev); | 315 | mem = container_of(dev, struct memory_block, dev); |
334 | 316 | ||
335 | if (!strncmp(buf, "online", min((int)count, 6))) | 317 | if (!strncmp(buf, "online", min((int)count, 6))) |
336 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); | 318 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); |
@@ -351,41 +333,41 @@ store_mem_state(struct sys_device *dev, | |||
351 | * s.t. if I offline all of these sections I can then | 333 | * s.t. if I offline all of these sections I can then |
352 | * remove the physical device? | 334 | * remove the physical device? |
353 | */ | 335 | */ |
354 | static ssize_t show_phys_device(struct sys_device *dev, | 336 | static ssize_t show_phys_device(struct device *dev, |
355 | struct sysdev_attribute *attr, char *buf) | 337 | struct device_attribute *attr, char *buf) |
356 | { | 338 | { |
357 | struct memory_block *mem = | 339 | struct memory_block *mem = |
358 | container_of(dev, struct memory_block, sysdev); | 340 | container_of(dev, struct memory_block, dev); |
359 | return sprintf(buf, "%d\n", mem->phys_device); | 341 | return sprintf(buf, "%d\n", mem->phys_device); |
360 | } | 342 | } |
361 | 343 | ||
362 | static SYSDEV_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); | 344 | static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); |
363 | static SYSDEV_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL); | 345 | static DEVICE_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL); |
364 | static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state); | 346 | static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state); |
365 | static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL); | 347 | static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL); |
366 | static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL); | 348 | static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL); |
367 | 349 | ||
368 | #define mem_create_simple_file(mem, attr_name) \ | 350 | #define mem_create_simple_file(mem, attr_name) \ |
369 | sysdev_create_file(&mem->sysdev, &attr_##attr_name) | 351 | device_create_file(&mem->dev, &dev_attr_##attr_name) |
370 | #define mem_remove_simple_file(mem, attr_name) \ | 352 | #define mem_remove_simple_file(mem, attr_name) \ |
371 | sysdev_remove_file(&mem->sysdev, &attr_##attr_name) | 353 | device_remove_file(&mem->dev, &dev_attr_##attr_name) |
372 | 354 | ||
373 | /* | 355 | /* |
374 | * Block size attribute stuff | 356 | * Block size attribute stuff |
375 | */ | 357 | */ |
376 | static ssize_t | 358 | static ssize_t |
377 | print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr, | 359 | print_block_size(struct device *dev, struct device_attribute *attr, |
378 | char *buf) | 360 | char *buf) |
379 | { | 361 | { |
380 | return sprintf(buf, "%lx\n", get_memory_block_size()); | 362 | return sprintf(buf, "%lx\n", get_memory_block_size()); |
381 | } | 363 | } |
382 | 364 | ||
383 | static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); | 365 | static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL); |
384 | 366 | ||
385 | static int block_size_init(void) | 367 | static int block_size_init(void) |
386 | { | 368 | { |
387 | return sysfs_create_file(&memory_sysdev_class.kset.kobj, | 369 | return device_create_file(memory_subsys.dev_root, |
388 | &attr_block_size_bytes.attr); | 370 | &dev_attr_block_size_bytes); |
389 | } | 371 | } |
390 | 372 | ||
391 | /* | 373 | /* |
@@ -396,7 +378,7 @@ static int block_size_init(void) | |||
396 | */ | 378 | */ |
397 | #ifdef CONFIG_ARCH_MEMORY_PROBE | 379 | #ifdef CONFIG_ARCH_MEMORY_PROBE |
398 | static ssize_t | 380 | static ssize_t |
399 | memory_probe_store(struct class *class, struct class_attribute *attr, | 381 | memory_probe_store(struct device *dev, struct device_attribute *attr, |
400 | const char *buf, size_t count) | 382 | const char *buf, size_t count) |
401 | { | 383 | { |
402 | u64 phys_addr; | 384 | u64 phys_addr; |
@@ -423,12 +405,11 @@ memory_probe_store(struct class *class, struct class_attribute *attr, | |||
423 | out: | 405 | out: |
424 | return ret; | 406 | return ret; |
425 | } | 407 | } |
426 | static CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store); | 408 | static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store); |
427 | 409 | ||
428 | static int memory_probe_init(void) | 410 | static int memory_probe_init(void) |
429 | { | 411 | { |
430 | return sysfs_create_file(&memory_sysdev_class.kset.kobj, | 412 | return device_create_file(memory_subsys.dev_root, &dev_attr_probe); |
431 | &class_attr_probe.attr); | ||
432 | } | 413 | } |
433 | #else | 414 | #else |
434 | static inline int memory_probe_init(void) | 415 | static inline int memory_probe_init(void) |
@@ -444,8 +425,8 @@ static inline int memory_probe_init(void) | |||
444 | 425 | ||
445 | /* Soft offline a page */ | 426 | /* Soft offline a page */ |
446 | static ssize_t | 427 | static ssize_t |
447 | store_soft_offline_page(struct class *class, | 428 | store_soft_offline_page(struct device *dev, |
448 | struct class_attribute *attr, | 429 | struct device_attribute *attr, |
449 | const char *buf, size_t count) | 430 | const char *buf, size_t count) |
450 | { | 431 | { |
451 | int ret; | 432 | int ret; |
@@ -463,8 +444,8 @@ store_soft_offline_page(struct class *class, | |||
463 | 444 | ||
464 | /* Forcibly offline a page, including killing processes. */ | 445 | /* Forcibly offline a page, including killing processes. */ |
465 | static ssize_t | 446 | static ssize_t |
466 | store_hard_offline_page(struct class *class, | 447 | store_hard_offline_page(struct device *dev, |
467 | struct class_attribute *attr, | 448 | struct device_attribute *attr, |
468 | const char *buf, size_t count) | 449 | const char *buf, size_t count) |
469 | { | 450 | { |
470 | int ret; | 451 | int ret; |
@@ -478,18 +459,18 @@ store_hard_offline_page(struct class *class, | |||
478 | return ret ? ret : count; | 459 | return ret ? ret : count; |
479 | } | 460 | } |
480 | 461 | ||
481 | static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); | 462 | static DEVICE_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); |
482 | static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); | 463 | static DEVICE_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); |
483 | 464 | ||
484 | static __init int memory_fail_init(void) | 465 | static __init int memory_fail_init(void) |
485 | { | 466 | { |
486 | int err; | 467 | int err; |
487 | 468 | ||
488 | err = sysfs_create_file(&memory_sysdev_class.kset.kobj, | 469 | err = device_create_file(memory_subsys.dev_root, |
489 | &class_attr_soft_offline_page.attr); | 470 | &dev_attr_soft_offline_page); |
490 | if (!err) | 471 | if (!err) |
491 | err = sysfs_create_file(&memory_sysdev_class.kset.kobj, | 472 | err = device_create_file(memory_subsys.dev_root, |
492 | &class_attr_hard_offline_page.attr); | 473 | &dev_attr_hard_offline_page); |
493 | return err; | 474 | return err; |
494 | } | 475 | } |
495 | #else | 476 | #else |
@@ -509,31 +490,23 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn) | |||
509 | return 0; | 490 | return 0; |
510 | } | 491 | } |
511 | 492 | ||
493 | /* | ||
494 | * A reference for the returned object is held and the reference for the | ||
495 | * hinted object is released. | ||
496 | */ | ||
512 | struct memory_block *find_memory_block_hinted(struct mem_section *section, | 497 | struct memory_block *find_memory_block_hinted(struct mem_section *section, |
513 | struct memory_block *hint) | 498 | struct memory_block *hint) |
514 | { | 499 | { |
515 | struct kobject *kobj; | ||
516 | struct sys_device *sysdev; | ||
517 | struct memory_block *mem; | ||
518 | char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; | ||
519 | int block_id = base_memory_block_id(__section_nr(section)); | 500 | int block_id = base_memory_block_id(__section_nr(section)); |
501 | struct device *hintdev = hint ? &hint->dev : NULL; | ||
502 | struct device *dev; | ||
520 | 503 | ||
521 | kobj = hint ? &hint->sysdev.kobj : NULL; | 504 | dev = subsys_find_device_by_id(&memory_subsys, block_id, hintdev); |
522 | 505 | if (hint) | |
523 | /* | 506 | put_device(&hint->dev); |
524 | * This only works because we know that section == sysdev->id | 507 | if (!dev) |
525 | * slightly redundant with sysdev_register() | ||
526 | */ | ||
527 | sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, block_id); | ||
528 | |||
529 | kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); | ||
530 | if (!kobj) | ||
531 | return NULL; | 508 | return NULL; |
532 | 509 | return container_of(dev, struct memory_block, dev); | |
533 | sysdev = container_of(kobj, struct sys_device, kobj); | ||
534 | mem = container_of(sysdev, struct memory_block, sysdev); | ||
535 | |||
536 | return mem; | ||
537 | } | 510 | } |
538 | 511 | ||
539 | /* | 512 | /* |
@@ -542,7 +515,7 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section, | |||
542 | * this gets to be a real problem, we can always use a radix | 515 | * this gets to be a real problem, we can always use a radix |
543 | * tree or something here. | 516 | * tree or something here. |
544 | * | 517 | * |
545 | * This could be made generic for all sysdev classes. | 518 | * This could be made generic for all device subsystems. |
546 | */ | 519 | */ |
547 | struct memory_block *find_memory_block(struct mem_section *section) | 520 | struct memory_block *find_memory_block(struct mem_section *section) |
548 | { | 521 | { |
@@ -598,7 +571,7 @@ static int add_memory_section(int nid, struct mem_section *section, | |||
598 | mem = find_memory_block(section); | 571 | mem = find_memory_block(section); |
599 | if (mem) { | 572 | if (mem) { |
600 | mem->section_count++; | 573 | mem->section_count++; |
601 | kobject_put(&mem->sysdev.kobj); | 574 | kobject_put(&mem->dev.kobj); |
602 | } else | 575 | } else |
603 | ret = init_memory_block(&mem, section, state); | 576 | ret = init_memory_block(&mem, section, state); |
604 | 577 | ||
@@ -631,7 +604,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, | |||
631 | unregister_memory(mem); | 604 | unregister_memory(mem); |
632 | kfree(mem); | 605 | kfree(mem); |
633 | } else | 606 | } else |
634 | kobject_put(&mem->sysdev.kobj); | 607 | kobject_put(&mem->dev.kobj); |
635 | 608 | ||
636 | mutex_unlock(&mem_sysfs_mutex); | 609 | mutex_unlock(&mem_sysfs_mutex); |
637 | return 0; | 610 | return 0; |
@@ -664,8 +637,7 @@ int __init memory_dev_init(void) | |||
664 | int err; | 637 | int err; |
665 | unsigned long block_sz; | 638 | unsigned long block_sz; |
666 | 639 | ||
667 | memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops; | 640 | ret = subsys_system_register(&memory_subsys, NULL); |
668 | ret = sysdev_class_register(&memory_sysdev_class); | ||
669 | if (ret) | 641 | if (ret) |
670 | goto out; | 642 | goto out; |
671 | 643 | ||
diff --git a/drivers/base/node.c b/drivers/base/node.c index 5693ecee9a40..44f427a66117 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
@@ -1,8 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/base/node.c - basic Node class support | 2 | * Basic Node interface support |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/sysdev.h> | ||
6 | #include <linux/module.h> | 5 | #include <linux/module.h> |
7 | #include <linux/init.h> | 6 | #include <linux/init.h> |
8 | #include <linux/mm.h> | 7 | #include <linux/mm.h> |
@@ -19,18 +18,16 @@ | |||
19 | #include <linux/swap.h> | 18 | #include <linux/swap.h> |
20 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
21 | 20 | ||
22 | static struct sysdev_class_attribute *node_state_attrs[]; | 21 | static struct bus_type node_subsys = { |
23 | |||
24 | static struct sysdev_class node_class = { | ||
25 | .name = "node", | 22 | .name = "node", |
26 | .attrs = node_state_attrs, | 23 | .dev_name = "node", |
27 | }; | 24 | }; |
28 | 25 | ||
29 | 26 | ||
30 | static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf) | 27 | static ssize_t node_read_cpumap(struct device *dev, int type, char *buf) |
31 | { | 28 | { |
32 | struct node *node_dev = to_node(dev); | 29 | struct node *node_dev = to_node(dev); |
33 | const struct cpumask *mask = cpumask_of_node(node_dev->sysdev.id); | 30 | const struct cpumask *mask = cpumask_of_node(node_dev->dev.id); |
34 | int len; | 31 | int len; |
35 | 32 | ||
36 | /* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */ | 33 | /* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */ |
@@ -44,23 +41,23 @@ static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf) | |||
44 | return len; | 41 | return len; |
45 | } | 42 | } |
46 | 43 | ||
47 | static inline ssize_t node_read_cpumask(struct sys_device *dev, | 44 | static inline ssize_t node_read_cpumask(struct device *dev, |
48 | struct sysdev_attribute *attr, char *buf) | 45 | struct device_attribute *attr, char *buf) |
49 | { | 46 | { |
50 | return node_read_cpumap(dev, 0, buf); | 47 | return node_read_cpumap(dev, 0, buf); |
51 | } | 48 | } |
52 | static inline ssize_t node_read_cpulist(struct sys_device *dev, | 49 | static inline ssize_t node_read_cpulist(struct device *dev, |
53 | struct sysdev_attribute *attr, char *buf) | 50 | struct device_attribute *attr, char *buf) |
54 | { | 51 | { |
55 | return node_read_cpumap(dev, 1, buf); | 52 | return node_read_cpumap(dev, 1, buf); |
56 | } | 53 | } |
57 | 54 | ||
58 | static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL); | 55 | static DEVICE_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL); |
59 | static SYSDEV_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); | 56 | static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); |
60 | 57 | ||
61 | #define K(x) ((x) << (PAGE_SHIFT - 10)) | 58 | #define K(x) ((x) << (PAGE_SHIFT - 10)) |
62 | static ssize_t node_read_meminfo(struct sys_device * dev, | 59 | static ssize_t node_read_meminfo(struct device *dev, |
63 | struct sysdev_attribute *attr, char * buf) | 60 | struct device_attribute *attr, char *buf) |
64 | { | 61 | { |
65 | int n; | 62 | int n; |
66 | int nid = dev->id; | 63 | int nid = dev->id; |
@@ -157,10 +154,10 @@ static ssize_t node_read_meminfo(struct sys_device * dev, | |||
157 | } | 154 | } |
158 | 155 | ||
159 | #undef K | 156 | #undef K |
160 | static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); | 157 | static DEVICE_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); |
161 | 158 | ||
162 | static ssize_t node_read_numastat(struct sys_device * dev, | 159 | static ssize_t node_read_numastat(struct device *dev, |
163 | struct sysdev_attribute *attr, char * buf) | 160 | struct device_attribute *attr, char *buf) |
164 | { | 161 | { |
165 | return sprintf(buf, | 162 | return sprintf(buf, |
166 | "numa_hit %lu\n" | 163 | "numa_hit %lu\n" |
@@ -176,10 +173,10 @@ static ssize_t node_read_numastat(struct sys_device * dev, | |||
176 | node_page_state(dev->id, NUMA_LOCAL), | 173 | node_page_state(dev->id, NUMA_LOCAL), |
177 | node_page_state(dev->id, NUMA_OTHER)); | 174 | node_page_state(dev->id, NUMA_OTHER)); |
178 | } | 175 | } |
179 | static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); | 176 | static DEVICE_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); |
180 | 177 | ||
181 | static ssize_t node_read_vmstat(struct sys_device *dev, | 178 | static ssize_t node_read_vmstat(struct device *dev, |
182 | struct sysdev_attribute *attr, char *buf) | 179 | struct device_attribute *attr, char *buf) |
183 | { | 180 | { |
184 | int nid = dev->id; | 181 | int nid = dev->id; |
185 | int i; | 182 | int i; |
@@ -191,10 +188,10 @@ static ssize_t node_read_vmstat(struct sys_device *dev, | |||
191 | 188 | ||
192 | return n; | 189 | return n; |
193 | } | 190 | } |
194 | static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL); | 191 | static DEVICE_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL); |
195 | 192 | ||
196 | static ssize_t node_read_distance(struct sys_device * dev, | 193 | static ssize_t node_read_distance(struct device *dev, |
197 | struct sysdev_attribute *attr, char * buf) | 194 | struct device_attribute *attr, char * buf) |
198 | { | 195 | { |
199 | int nid = dev->id; | 196 | int nid = dev->id; |
200 | int len = 0; | 197 | int len = 0; |
@@ -212,7 +209,7 @@ static ssize_t node_read_distance(struct sys_device * dev, | |||
212 | len += sprintf(buf + len, "\n"); | 209 | len += sprintf(buf + len, "\n"); |
213 | return len; | 210 | return len; |
214 | } | 211 | } |
215 | static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); | 212 | static DEVICE_ATTR(distance, S_IRUGO, node_read_distance, NULL); |
216 | 213 | ||
217 | #ifdef CONFIG_HUGETLBFS | 214 | #ifdef CONFIG_HUGETLBFS |
218 | /* | 215 | /* |
@@ -230,7 +227,7 @@ static node_registration_func_t __hugetlb_unregister_node; | |||
230 | static inline bool hugetlb_register_node(struct node *node) | 227 | static inline bool hugetlb_register_node(struct node *node) |
231 | { | 228 | { |
232 | if (__hugetlb_register_node && | 229 | if (__hugetlb_register_node && |
233 | node_state(node->sysdev.id, N_HIGH_MEMORY)) { | 230 | node_state(node->dev.id, N_HIGH_MEMORY)) { |
234 | __hugetlb_register_node(node); | 231 | __hugetlb_register_node(node); |
235 | return true; | 232 | return true; |
236 | } | 233 | } |
@@ -266,17 +263,17 @@ int register_node(struct node *node, int num, struct node *parent) | |||
266 | { | 263 | { |
267 | int error; | 264 | int error; |
268 | 265 | ||
269 | node->sysdev.id = num; | 266 | node->dev.id = num; |
270 | node->sysdev.cls = &node_class; | 267 | node->dev.bus = &node_subsys; |
271 | error = sysdev_register(&node->sysdev); | 268 | error = device_register(&node->dev); |
272 | 269 | ||
273 | if (!error){ | 270 | if (!error){ |
274 | sysdev_create_file(&node->sysdev, &attr_cpumap); | 271 | device_create_file(&node->dev, &dev_attr_cpumap); |
275 | sysdev_create_file(&node->sysdev, &attr_cpulist); | 272 | device_create_file(&node->dev, &dev_attr_cpulist); |
276 | sysdev_create_file(&node->sysdev, &attr_meminfo); | 273 | device_create_file(&node->dev, &dev_attr_meminfo); |
277 | sysdev_create_file(&node->sysdev, &attr_numastat); | 274 | device_create_file(&node->dev, &dev_attr_numastat); |
278 | sysdev_create_file(&node->sysdev, &attr_distance); | 275 | device_create_file(&node->dev, &dev_attr_distance); |
279 | sysdev_create_file(&node->sysdev, &attr_vmstat); | 276 | device_create_file(&node->dev, &dev_attr_vmstat); |
280 | 277 | ||
281 | scan_unevictable_register_node(node); | 278 | scan_unevictable_register_node(node); |
282 | 279 | ||
@@ -296,17 +293,17 @@ int register_node(struct node *node, int num, struct node *parent) | |||
296 | */ | 293 | */ |
297 | void unregister_node(struct node *node) | 294 | void unregister_node(struct node *node) |
298 | { | 295 | { |
299 | sysdev_remove_file(&node->sysdev, &attr_cpumap); | 296 | device_remove_file(&node->dev, &dev_attr_cpumap); |
300 | sysdev_remove_file(&node->sysdev, &attr_cpulist); | 297 | device_remove_file(&node->dev, &dev_attr_cpulist); |
301 | sysdev_remove_file(&node->sysdev, &attr_meminfo); | 298 | device_remove_file(&node->dev, &dev_attr_meminfo); |
302 | sysdev_remove_file(&node->sysdev, &attr_numastat); | 299 | device_remove_file(&node->dev, &dev_attr_numastat); |
303 | sysdev_remove_file(&node->sysdev, &attr_distance); | 300 | device_remove_file(&node->dev, &dev_attr_distance); |
304 | sysdev_remove_file(&node->sysdev, &attr_vmstat); | 301 | device_remove_file(&node->dev, &dev_attr_vmstat); |
305 | 302 | ||
306 | scan_unevictable_unregister_node(node); | 303 | scan_unevictable_unregister_node(node); |
307 | hugetlb_unregister_node(node); /* no-op, if memoryless node */ | 304 | hugetlb_unregister_node(node); /* no-op, if memoryless node */ |
308 | 305 | ||
309 | sysdev_unregister(&node->sysdev); | 306 | device_unregister(&node->dev); |
310 | } | 307 | } |
311 | 308 | ||
312 | struct node node_devices[MAX_NUMNODES]; | 309 | struct node node_devices[MAX_NUMNODES]; |
@@ -317,41 +314,41 @@ struct node node_devices[MAX_NUMNODES]; | |||
317 | int register_cpu_under_node(unsigned int cpu, unsigned int nid) | 314 | int register_cpu_under_node(unsigned int cpu, unsigned int nid) |
318 | { | 315 | { |
319 | int ret; | 316 | int ret; |
320 | struct sys_device *obj; | 317 | struct device *obj; |
321 | 318 | ||
322 | if (!node_online(nid)) | 319 | if (!node_online(nid)) |
323 | return 0; | 320 | return 0; |
324 | 321 | ||
325 | obj = get_cpu_sysdev(cpu); | 322 | obj = get_cpu_device(cpu); |
326 | if (!obj) | 323 | if (!obj) |
327 | return 0; | 324 | return 0; |
328 | 325 | ||
329 | ret = sysfs_create_link(&node_devices[nid].sysdev.kobj, | 326 | ret = sysfs_create_link(&node_devices[nid].dev.kobj, |
330 | &obj->kobj, | 327 | &obj->kobj, |
331 | kobject_name(&obj->kobj)); | 328 | kobject_name(&obj->kobj)); |
332 | if (ret) | 329 | if (ret) |
333 | return ret; | 330 | return ret; |
334 | 331 | ||
335 | return sysfs_create_link(&obj->kobj, | 332 | return sysfs_create_link(&obj->kobj, |
336 | &node_devices[nid].sysdev.kobj, | 333 | &node_devices[nid].dev.kobj, |
337 | kobject_name(&node_devices[nid].sysdev.kobj)); | 334 | kobject_name(&node_devices[nid].dev.kobj)); |
338 | } | 335 | } |
339 | 336 | ||
340 | int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) | 337 | int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) |
341 | { | 338 | { |
342 | struct sys_device *obj; | 339 | struct device *obj; |
343 | 340 | ||
344 | if (!node_online(nid)) | 341 | if (!node_online(nid)) |
345 | return 0; | 342 | return 0; |
346 | 343 | ||
347 | obj = get_cpu_sysdev(cpu); | 344 | obj = get_cpu_device(cpu); |
348 | if (!obj) | 345 | if (!obj) |
349 | return 0; | 346 | return 0; |
350 | 347 | ||
351 | sysfs_remove_link(&node_devices[nid].sysdev.kobj, | 348 | sysfs_remove_link(&node_devices[nid].dev.kobj, |
352 | kobject_name(&obj->kobj)); | 349 | kobject_name(&obj->kobj)); |
353 | sysfs_remove_link(&obj->kobj, | 350 | sysfs_remove_link(&obj->kobj, |
354 | kobject_name(&node_devices[nid].sysdev.kobj)); | 351 | kobject_name(&node_devices[nid].dev.kobj)); |
355 | 352 | ||
356 | return 0; | 353 | return 0; |
357 | } | 354 | } |
@@ -393,15 +390,15 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) | |||
393 | continue; | 390 | continue; |
394 | if (page_nid != nid) | 391 | if (page_nid != nid) |
395 | continue; | 392 | continue; |
396 | ret = sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj, | 393 | ret = sysfs_create_link_nowarn(&node_devices[nid].dev.kobj, |
397 | &mem_blk->sysdev.kobj, | 394 | &mem_blk->dev.kobj, |
398 | kobject_name(&mem_blk->sysdev.kobj)); | 395 | kobject_name(&mem_blk->dev.kobj)); |
399 | if (ret) | 396 | if (ret) |
400 | return ret; | 397 | return ret; |
401 | 398 | ||
402 | return sysfs_create_link_nowarn(&mem_blk->sysdev.kobj, | 399 | return sysfs_create_link_nowarn(&mem_blk->dev.kobj, |
403 | &node_devices[nid].sysdev.kobj, | 400 | &node_devices[nid].dev.kobj, |
404 | kobject_name(&node_devices[nid].sysdev.kobj)); | 401 | kobject_name(&node_devices[nid].dev.kobj)); |
405 | } | 402 | } |
406 | /* mem section does not span the specified node */ | 403 | /* mem section does not span the specified node */ |
407 | return 0; | 404 | return 0; |
@@ -434,10 +431,10 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, | |||
434 | continue; | 431 | continue; |
435 | if (node_test_and_set(nid, *unlinked_nodes)) | 432 | if (node_test_and_set(nid, *unlinked_nodes)) |
436 | continue; | 433 | continue; |
437 | sysfs_remove_link(&node_devices[nid].sysdev.kobj, | 434 | sysfs_remove_link(&node_devices[nid].dev.kobj, |
438 | kobject_name(&mem_blk->sysdev.kobj)); | 435 | kobject_name(&mem_blk->dev.kobj)); |
439 | sysfs_remove_link(&mem_blk->sysdev.kobj, | 436 | sysfs_remove_link(&mem_blk->dev.kobj, |
440 | kobject_name(&node_devices[nid].sysdev.kobj)); | 437 | kobject_name(&node_devices[nid].dev.kobj)); |
441 | } | 438 | } |
442 | NODEMASK_FREE(unlinked_nodes); | 439 | NODEMASK_FREE(unlinked_nodes); |
443 | return 0; | 440 | return 0; |
@@ -468,7 +465,7 @@ static int link_mem_sections(int nid) | |||
468 | } | 465 | } |
469 | 466 | ||
470 | if (mem_blk) | 467 | if (mem_blk) |
471 | kobject_put(&mem_blk->sysdev.kobj); | 468 | kobject_put(&mem_blk->dev.kobj); |
472 | return err; | 469 | return err; |
473 | } | 470 | } |
474 | 471 | ||
@@ -596,19 +593,19 @@ static ssize_t print_nodes_state(enum node_states state, char *buf) | |||
596 | } | 593 | } |
597 | 594 | ||
598 | struct node_attr { | 595 | struct node_attr { |
599 | struct sysdev_class_attribute attr; | 596 | struct device_attribute attr; |
600 | enum node_states state; | 597 | enum node_states state; |
601 | }; | 598 | }; |
602 | 599 | ||
603 | static ssize_t show_node_state(struct sysdev_class *class, | 600 | static ssize_t show_node_state(struct device *dev, |
604 | struct sysdev_class_attribute *attr, char *buf) | 601 | struct device_attribute *attr, char *buf) |
605 | { | 602 | { |
606 | struct node_attr *na = container_of(attr, struct node_attr, attr); | 603 | struct node_attr *na = container_of(attr, struct node_attr, attr); |
607 | return print_nodes_state(na->state, buf); | 604 | return print_nodes_state(na->state, buf); |
608 | } | 605 | } |
609 | 606 | ||
610 | #define _NODE_ATTR(name, state) \ | 607 | #define _NODE_ATTR(name, state) \ |
611 | { _SYSDEV_CLASS_ATTR(name, 0444, show_node_state, NULL), state } | 608 | { __ATTR(name, 0444, show_node_state, NULL), state } |
612 | 609 | ||
613 | static struct node_attr node_state_attr[] = { | 610 | static struct node_attr node_state_attr[] = { |
614 | _NODE_ATTR(possible, N_POSSIBLE), | 611 | _NODE_ATTR(possible, N_POSSIBLE), |
@@ -620,17 +617,26 @@ static struct node_attr node_state_attr[] = { | |||
620 | #endif | 617 | #endif |
621 | }; | 618 | }; |
622 | 619 | ||
623 | static struct sysdev_class_attribute *node_state_attrs[] = { | 620 | static struct attribute *node_state_attrs[] = { |
624 | &node_state_attr[0].attr, | 621 | &node_state_attr[0].attr.attr, |
625 | &node_state_attr[1].attr, | 622 | &node_state_attr[1].attr.attr, |
626 | &node_state_attr[2].attr, | 623 | &node_state_attr[2].attr.attr, |
627 | &node_state_attr[3].attr, | 624 | &node_state_attr[3].attr.attr, |
628 | #ifdef CONFIG_HIGHMEM | 625 | #ifdef CONFIG_HIGHMEM |
629 | &node_state_attr[4].attr, | 626 | &node_state_attr[4].attr.attr, |
630 | #endif | 627 | #endif |
631 | NULL | 628 | NULL |
632 | }; | 629 | }; |
633 | 630 | ||
631 | static struct attribute_group memory_root_attr_group = { | ||
632 | .attrs = node_state_attrs, | ||
633 | }; | ||
634 | |||
635 | static const struct attribute_group *cpu_root_attr_groups[] = { | ||
636 | &memory_root_attr_group, | ||
637 | NULL, | ||
638 | }; | ||
639 | |||
634 | #define NODE_CALLBACK_PRI 2 /* lower than SLAB */ | 640 | #define NODE_CALLBACK_PRI 2 /* lower than SLAB */ |
635 | static int __init register_node_type(void) | 641 | static int __init register_node_type(void) |
636 | { | 642 | { |
@@ -639,7 +645,7 @@ static int __init register_node_type(void) | |||
639 | BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES); | 645 | BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES); |
640 | BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES); | 646 | BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES); |
641 | 647 | ||
642 | ret = sysdev_class_register(&node_class); | 648 | ret = subsys_system_register(&node_subsys, cpu_root_attr_groups); |
643 | if (!ret) { | 649 | if (!ret) { |
644 | hotplug_memory_notifier(node_memory_callback, | 650 | hotplug_memory_notifier(node_memory_callback, |
645 | NODE_CALLBACK_PRI); | 651 | NODE_CALLBACK_PRI); |
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 7a24895543e7..f0c605e99ade 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -383,7 +383,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); | |||
383 | * Returns &struct platform_device pointer on success, or ERR_PTR() on error. | 383 | * Returns &struct platform_device pointer on success, or ERR_PTR() on error. |
384 | */ | 384 | */ |
385 | struct platform_device *platform_device_register_full( | 385 | struct platform_device *platform_device_register_full( |
386 | struct platform_device_info *pdevinfo) | 386 | const struct platform_device_info *pdevinfo) |
387 | { | 387 | { |
388 | int ret = -ENOMEM; | 388 | int ret = -ENOMEM; |
389 | struct platform_device *pdev; | 389 | struct platform_device *pdev; |
@@ -700,25 +700,6 @@ static int platform_legacy_resume(struct device *dev) | |||
700 | return ret; | 700 | return ret; |
701 | } | 701 | } |
702 | 702 | ||
703 | int platform_pm_prepare(struct device *dev) | ||
704 | { | ||
705 | struct device_driver *drv = dev->driver; | ||
706 | int ret = 0; | ||
707 | |||
708 | if (drv && drv->pm && drv->pm->prepare) | ||
709 | ret = drv->pm->prepare(dev); | ||
710 | |||
711 | return ret; | ||
712 | } | ||
713 | |||
714 | void platform_pm_complete(struct device *dev) | ||
715 | { | ||
716 | struct device_driver *drv = dev->driver; | ||
717 | |||
718 | if (drv && drv->pm && drv->pm->complete) | ||
719 | drv->pm->complete(dev); | ||
720 | } | ||
721 | |||
722 | #endif /* CONFIG_PM_SLEEP */ | 703 | #endif /* CONFIG_PM_SLEEP */ |
723 | 704 | ||
724 | #ifdef CONFIG_SUSPEND | 705 | #ifdef CONFIG_SUSPEND |
@@ -741,22 +722,6 @@ int platform_pm_suspend(struct device *dev) | |||
741 | return ret; | 722 | return ret; |
742 | } | 723 | } |
743 | 724 | ||
744 | int platform_pm_suspend_noirq(struct device *dev) | ||
745 | { | ||
746 | struct device_driver *drv = dev->driver; | ||
747 | int ret = 0; | ||
748 | |||
749 | if (!drv) | ||
750 | return 0; | ||
751 | |||
752 | if (drv->pm) { | ||
753 | if (drv->pm->suspend_noirq) | ||
754 | ret = drv->pm->suspend_noirq(dev); | ||
755 | } | ||
756 | |||
757 | return ret; | ||
758 | } | ||
759 | |||
760 | int platform_pm_resume(struct device *dev) | 725 | int platform_pm_resume(struct device *dev) |
761 | { | 726 | { |
762 | struct device_driver *drv = dev->driver; | 727 | struct device_driver *drv = dev->driver; |
@@ -775,22 +740,6 @@ int platform_pm_resume(struct device *dev) | |||
775 | return ret; | 740 | return ret; |
776 | } | 741 | } |
777 | 742 | ||
778 | int platform_pm_resume_noirq(struct device *dev) | ||
779 | { | ||
780 | struct device_driver *drv = dev->driver; | ||
781 | int ret = 0; | ||
782 | |||
783 | if (!drv) | ||
784 | return 0; | ||
785 | |||
786 | if (drv->pm) { | ||
787 | if (drv->pm->resume_noirq) | ||
788 | ret = drv->pm->resume_noirq(dev); | ||
789 | } | ||
790 | |||
791 | return ret; | ||
792 | } | ||
793 | |||
794 | #endif /* CONFIG_SUSPEND */ | 743 | #endif /* CONFIG_SUSPEND */ |
795 | 744 | ||
796 | #ifdef CONFIG_HIBERNATE_CALLBACKS | 745 | #ifdef CONFIG_HIBERNATE_CALLBACKS |
@@ -813,22 +762,6 @@ int platform_pm_freeze(struct device *dev) | |||
813 | return ret; | 762 | return ret; |
814 | } | 763 | } |
815 | 764 | ||
816 | int platform_pm_freeze_noirq(struct device *dev) | ||
817 | { | ||
818 | struct device_driver *drv = dev->driver; | ||
819 | int ret = 0; | ||
820 | |||
821 | if (!drv) | ||
822 | return 0; | ||
823 | |||
824 | if (drv->pm) { | ||
825 | if (drv->pm->freeze_noirq) | ||
826 | ret = drv->pm->freeze_noirq(dev); | ||
827 | } | ||
828 | |||
829 | return ret; | ||
830 | } | ||
831 | |||
832 | int platform_pm_thaw(struct device *dev) | 765 | int platform_pm_thaw(struct device *dev) |
833 | { | 766 | { |
834 | struct device_driver *drv = dev->driver; | 767 | struct device_driver *drv = dev->driver; |
@@ -847,22 +780,6 @@ int platform_pm_thaw(struct device *dev) | |||
847 | return ret; | 780 | return ret; |
848 | } | 781 | } |
849 | 782 | ||
850 | int platform_pm_thaw_noirq(struct device *dev) | ||
851 | { | ||
852 | struct device_driver *drv = dev->driver; | ||
853 | int ret = 0; | ||
854 | |||
855 | if (!drv) | ||
856 | return 0; | ||
857 | |||
858 | if (drv->pm) { | ||
859 | if (drv->pm->thaw_noirq) | ||
860 | ret = drv->pm->thaw_noirq(dev); | ||
861 | } | ||
862 | |||
863 | return ret; | ||
864 | } | ||
865 | |||
866 | int platform_pm_poweroff(struct device *dev) | 783 | int platform_pm_poweroff(struct device *dev) |
867 | { | 784 | { |
868 | struct device_driver *drv = dev->driver; | 785 | struct device_driver *drv = dev->driver; |
@@ -881,22 +798,6 @@ int platform_pm_poweroff(struct device *dev) | |||
881 | return ret; | 798 | return ret; |
882 | } | 799 | } |
883 | 800 | ||
884 | int platform_pm_poweroff_noirq(struct device *dev) | ||
885 | { | ||
886 | struct device_driver *drv = dev->driver; | ||
887 | int ret = 0; | ||
888 | |||
889 | if (!drv) | ||
890 | return 0; | ||
891 | |||
892 | if (drv->pm) { | ||
893 | if (drv->pm->poweroff_noirq) | ||
894 | ret = drv->pm->poweroff_noirq(dev); | ||
895 | } | ||
896 | |||
897 | return ret; | ||
898 | } | ||
899 | |||
900 | int platform_pm_restore(struct device *dev) | 801 | int platform_pm_restore(struct device *dev) |
901 | { | 802 | { |
902 | struct device_driver *drv = dev->driver; | 803 | struct device_driver *drv = dev->driver; |
@@ -915,22 +816,6 @@ int platform_pm_restore(struct device *dev) | |||
915 | return ret; | 816 | return ret; |
916 | } | 817 | } |
917 | 818 | ||
918 | int platform_pm_restore_noirq(struct device *dev) | ||
919 | { | ||
920 | struct device_driver *drv = dev->driver; | ||
921 | int ret = 0; | ||
922 | |||
923 | if (!drv) | ||
924 | return 0; | ||
925 | |||
926 | if (drv->pm) { | ||
927 | if (drv->pm->restore_noirq) | ||
928 | ret = drv->pm->restore_noirq(dev); | ||
929 | } | ||
930 | |||
931 | return ret; | ||
932 | } | ||
933 | |||
934 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ | 819 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ |
935 | 820 | ||
936 | static const struct dev_pm_ops platform_dev_pm_ops = { | 821 | static const struct dev_pm_ops platform_dev_pm_ops = { |
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 81676dd17900..2e58ebb1f6c0 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
@@ -3,7 +3,7 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o | |||
3 | obj-$(CONFIG_PM_RUNTIME) += runtime.o | 3 | obj-$(CONFIG_PM_RUNTIME) += runtime.o |
4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o | 4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o |
5 | obj-$(CONFIG_PM_OPP) += opp.o | 5 | obj-$(CONFIG_PM_OPP) += opp.o |
6 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o | 6 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o |
7 | obj-$(CONFIG_HAVE_CLK) += clock_ops.o | 7 | obj-$(CONFIG_HAVE_CLK) += clock_ops.o |
8 | 8 | ||
9 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG | 9 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG |
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 6790cf7eba5a..92e6a9048065 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -15,13 +15,44 @@ | |||
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/suspend.h> | 17 | #include <linux/suspend.h> |
18 | #include <linux/export.h> | ||
19 | |||
20 | #define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \ | ||
21 | ({ \ | ||
22 | type (*__routine)(struct device *__d); \ | ||
23 | type __ret = (type)0; \ | ||
24 | \ | ||
25 | __routine = genpd->dev_ops.callback; \ | ||
26 | if (__routine) { \ | ||
27 | __ret = __routine(dev); \ | ||
28 | } else { \ | ||
29 | __routine = dev_gpd_data(dev)->ops.callback; \ | ||
30 | if (__routine) \ | ||
31 | __ret = __routine(dev); \ | ||
32 | } \ | ||
33 | __ret; \ | ||
34 | }) | ||
35 | |||
36 | #define GENPD_DEV_TIMED_CALLBACK(genpd, type, callback, dev, field, name) \ | ||
37 | ({ \ | ||
38 | ktime_t __start = ktime_get(); \ | ||
39 | type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \ | ||
40 | s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \ | ||
41 | struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev); \ | ||
42 | if (__elapsed > __gpd_data->td.field) { \ | ||
43 | __gpd_data->td.field = __elapsed; \ | ||
44 | dev_warn(dev, name " latency exceeded, new value %lld ns\n", \ | ||
45 | __elapsed); \ | ||
46 | } \ | ||
47 | __retval; \ | ||
48 | }) | ||
18 | 49 | ||
19 | static LIST_HEAD(gpd_list); | 50 | static LIST_HEAD(gpd_list); |
20 | static DEFINE_MUTEX(gpd_list_lock); | 51 | static DEFINE_MUTEX(gpd_list_lock); |
21 | 52 | ||
22 | #ifdef CONFIG_PM | 53 | #ifdef CONFIG_PM |
23 | 54 | ||
24 | static struct generic_pm_domain *dev_to_genpd(struct device *dev) | 55 | struct generic_pm_domain *dev_to_genpd(struct device *dev) |
25 | { | 56 | { |
26 | if (IS_ERR_OR_NULL(dev->pm_domain)) | 57 | if (IS_ERR_OR_NULL(dev->pm_domain)) |
27 | return ERR_PTR(-EINVAL); | 58 | return ERR_PTR(-EINVAL); |
@@ -29,6 +60,31 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev) | |||
29 | return pd_to_genpd(dev->pm_domain); | 60 | return pd_to_genpd(dev->pm_domain); |
30 | } | 61 | } |
31 | 62 | ||
63 | static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
64 | { | ||
65 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, stop, dev, | ||
66 | stop_latency_ns, "stop"); | ||
67 | } | ||
68 | |||
69 | static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
70 | { | ||
71 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev, | ||
72 | start_latency_ns, "start"); | ||
73 | } | ||
74 | |||
75 | static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
76 | { | ||
77 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev, | ||
78 | save_state_latency_ns, "state save"); | ||
79 | } | ||
80 | |||
81 | static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
82 | { | ||
83 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev, | ||
84 | restore_state_latency_ns, | ||
85 | "state restore"); | ||
86 | } | ||
87 | |||
32 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) | 88 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) |
33 | { | 89 | { |
34 | bool ret = false; | 90 | bool ret = false; |
@@ -145,9 +201,21 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd) | |||
145 | } | 201 | } |
146 | 202 | ||
147 | if (genpd->power_on) { | 203 | if (genpd->power_on) { |
204 | ktime_t time_start = ktime_get(); | ||
205 | s64 elapsed_ns; | ||
206 | |||
148 | ret = genpd->power_on(genpd); | 207 | ret = genpd->power_on(genpd); |
149 | if (ret) | 208 | if (ret) |
150 | goto err; | 209 | goto err; |
210 | |||
211 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
212 | if (elapsed_ns > genpd->power_on_latency_ns) { | ||
213 | genpd->power_on_latency_ns = elapsed_ns; | ||
214 | if (genpd->name) | ||
215 | pr_warning("%s: Power-on latency exceeded, " | ||
216 | "new value %lld ns\n", genpd->name, | ||
217 | elapsed_ns); | ||
218 | } | ||
151 | } | 219 | } |
152 | 220 | ||
153 | genpd_set_active(genpd); | 221 | genpd_set_active(genpd); |
@@ -190,7 +258,6 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd, | |||
190 | { | 258 | { |
191 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | 259 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); |
192 | struct device *dev = pdd->dev; | 260 | struct device *dev = pdd->dev; |
193 | struct device_driver *drv = dev->driver; | ||
194 | int ret = 0; | 261 | int ret = 0; |
195 | 262 | ||
196 | if (gpd_data->need_restore) | 263 | if (gpd_data->need_restore) |
@@ -198,15 +265,9 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd, | |||
198 | 265 | ||
199 | mutex_unlock(&genpd->lock); | 266 | mutex_unlock(&genpd->lock); |
200 | 267 | ||
201 | if (drv && drv->pm && drv->pm->runtime_suspend) { | 268 | genpd_start_dev(genpd, dev); |
202 | if (genpd->start_device) | 269 | ret = genpd_save_dev(genpd, dev); |
203 | genpd->start_device(dev); | 270 | genpd_stop_dev(genpd, dev); |
204 | |||
205 | ret = drv->pm->runtime_suspend(dev); | ||
206 | |||
207 | if (genpd->stop_device) | ||
208 | genpd->stop_device(dev); | ||
209 | } | ||
210 | 271 | ||
211 | mutex_lock(&genpd->lock); | 272 | mutex_lock(&genpd->lock); |
212 | 273 | ||
@@ -227,22 +288,15 @@ static void __pm_genpd_restore_device(struct pm_domain_data *pdd, | |||
227 | { | 288 | { |
228 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | 289 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); |
229 | struct device *dev = pdd->dev; | 290 | struct device *dev = pdd->dev; |
230 | struct device_driver *drv = dev->driver; | ||
231 | 291 | ||
232 | if (!gpd_data->need_restore) | 292 | if (!gpd_data->need_restore) |
233 | return; | 293 | return; |
234 | 294 | ||
235 | mutex_unlock(&genpd->lock); | 295 | mutex_unlock(&genpd->lock); |
236 | 296 | ||
237 | if (drv && drv->pm && drv->pm->runtime_resume) { | 297 | genpd_start_dev(genpd, dev); |
238 | if (genpd->start_device) | 298 | genpd_restore_dev(genpd, dev); |
239 | genpd->start_device(dev); | 299 | genpd_stop_dev(genpd, dev); |
240 | |||
241 | drv->pm->runtime_resume(dev); | ||
242 | |||
243 | if (genpd->stop_device) | ||
244 | genpd->stop_device(dev); | ||
245 | } | ||
246 | 300 | ||
247 | mutex_lock(&genpd->lock); | 301 | mutex_lock(&genpd->lock); |
248 | 302 | ||
@@ -354,11 +408,16 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
354 | } | 408 | } |
355 | 409 | ||
356 | if (genpd->power_off) { | 410 | if (genpd->power_off) { |
411 | ktime_t time_start; | ||
412 | s64 elapsed_ns; | ||
413 | |||
357 | if (atomic_read(&genpd->sd_count) > 0) { | 414 | if (atomic_read(&genpd->sd_count) > 0) { |
358 | ret = -EBUSY; | 415 | ret = -EBUSY; |
359 | goto out; | 416 | goto out; |
360 | } | 417 | } |
361 | 418 | ||
419 | time_start = ktime_get(); | ||
420 | |||
362 | /* | 421 | /* |
363 | * If sd_count > 0 at this point, one of the subdomains hasn't | 422 | * If sd_count > 0 at this point, one of the subdomains hasn't |
364 | * managed to call pm_genpd_poweron() for the master yet after | 423 | * managed to call pm_genpd_poweron() for the master yet after |
@@ -372,9 +431,29 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
372 | genpd_set_active(genpd); | 431 | genpd_set_active(genpd); |
373 | goto out; | 432 | goto out; |
374 | } | 433 | } |
434 | |||
435 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
436 | if (elapsed_ns > genpd->power_off_latency_ns) { | ||
437 | genpd->power_off_latency_ns = elapsed_ns; | ||
438 | if (genpd->name) | ||
439 | pr_warning("%s: Power-off latency exceeded, " | ||
440 | "new value %lld ns\n", genpd->name, | ||
441 | elapsed_ns); | ||
442 | } | ||
375 | } | 443 | } |
376 | 444 | ||
377 | genpd->status = GPD_STATE_POWER_OFF; | 445 | genpd->status = GPD_STATE_POWER_OFF; |
446 | genpd->power_off_time = ktime_get(); | ||
447 | |||
448 | /* Update PM QoS information for devices in the domain. */ | ||
449 | list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) { | ||
450 | struct gpd_timing_data *td = &to_gpd_data(pdd)->td; | ||
451 | |||
452 | pm_runtime_update_max_time_suspended(pdd->dev, | ||
453 | td->start_latency_ns + | ||
454 | td->restore_state_latency_ns + | ||
455 | genpd->power_on_latency_ns); | ||
456 | } | ||
378 | 457 | ||
379 | list_for_each_entry(link, &genpd->slave_links, slave_node) { | 458 | list_for_each_entry(link, &genpd->slave_links, slave_node) { |
380 | genpd_sd_counter_dec(link->master); | 459 | genpd_sd_counter_dec(link->master); |
@@ -413,6 +492,8 @@ static void genpd_power_off_work_fn(struct work_struct *work) | |||
413 | static int pm_genpd_runtime_suspend(struct device *dev) | 492 | static int pm_genpd_runtime_suspend(struct device *dev) |
414 | { | 493 | { |
415 | struct generic_pm_domain *genpd; | 494 | struct generic_pm_domain *genpd; |
495 | bool (*stop_ok)(struct device *__dev); | ||
496 | int ret; | ||
416 | 497 | ||
417 | dev_dbg(dev, "%s()\n", __func__); | 498 | dev_dbg(dev, "%s()\n", __func__); |
418 | 499 | ||
@@ -422,11 +503,16 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
422 | 503 | ||
423 | might_sleep_if(!genpd->dev_irq_safe); | 504 | might_sleep_if(!genpd->dev_irq_safe); |
424 | 505 | ||
425 | if (genpd->stop_device) { | 506 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; |
426 | int ret = genpd->stop_device(dev); | 507 | if (stop_ok && !stop_ok(dev)) |
427 | if (ret) | 508 | return -EBUSY; |
428 | return ret; | 509 | |
429 | } | 510 | ret = genpd_stop_dev(genpd, dev); |
511 | if (ret) | ||
512 | return ret; | ||
513 | |||
514 | pm_runtime_update_max_time_suspended(dev, | ||
515 | dev_gpd_data(dev)->td.start_latency_ns); | ||
430 | 516 | ||
431 | /* | 517 | /* |
432 | * If power.irq_safe is set, this routine will be run with interrupts | 518 | * If power.irq_safe is set, this routine will be run with interrupts |
@@ -502,8 +588,7 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
502 | mutex_unlock(&genpd->lock); | 588 | mutex_unlock(&genpd->lock); |
503 | 589 | ||
504 | out: | 590 | out: |
505 | if (genpd->start_device) | 591 | genpd_start_dev(genpd, dev); |
506 | genpd->start_device(dev); | ||
507 | 592 | ||
508 | return 0; | 593 | return 0; |
509 | } | 594 | } |
@@ -534,6 +619,52 @@ static inline void genpd_power_off_work_fn(struct work_struct *work) {} | |||
534 | 619 | ||
535 | #ifdef CONFIG_PM_SLEEP | 620 | #ifdef CONFIG_PM_SLEEP |
536 | 621 | ||
622 | static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, | ||
623 | struct device *dev) | ||
624 | { | ||
625 | return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev); | ||
626 | } | ||
627 | |||
628 | static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
629 | { | ||
630 | return GENPD_DEV_CALLBACK(genpd, int, suspend, dev); | ||
631 | } | ||
632 | |||
633 | static int genpd_suspend_late(struct generic_pm_domain *genpd, struct device *dev) | ||
634 | { | ||
635 | return GENPD_DEV_CALLBACK(genpd, int, suspend_late, dev); | ||
636 | } | ||
637 | |||
638 | static int genpd_resume_early(struct generic_pm_domain *genpd, struct device *dev) | ||
639 | { | ||
640 | return GENPD_DEV_CALLBACK(genpd, int, resume_early, dev); | ||
641 | } | ||
642 | |||
643 | static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
644 | { | ||
645 | return GENPD_DEV_CALLBACK(genpd, int, resume, dev); | ||
646 | } | ||
647 | |||
648 | static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
649 | { | ||
650 | return GENPD_DEV_CALLBACK(genpd, int, freeze, dev); | ||
651 | } | ||
652 | |||
653 | static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev) | ||
654 | { | ||
655 | return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev); | ||
656 | } | ||
657 | |||
658 | static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev) | ||
659 | { | ||
660 | return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev); | ||
661 | } | ||
662 | |||
663 | static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
664 | { | ||
665 | return GENPD_DEV_CALLBACK(genpd, int, thaw, dev); | ||
666 | } | ||
667 | |||
537 | /** | 668 | /** |
538 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. | 669 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. |
539 | * @genpd: PM domain to power off, if possible. | 670 | * @genpd: PM domain to power off, if possible. |
@@ -590,7 +721,7 @@ static bool resume_needed(struct device *dev, struct generic_pm_domain *genpd) | |||
590 | if (!device_can_wakeup(dev)) | 721 | if (!device_can_wakeup(dev)) |
591 | return false; | 722 | return false; |
592 | 723 | ||
593 | active_wakeup = genpd->active_wakeup && genpd->active_wakeup(dev); | 724 | active_wakeup = genpd_dev_active_wakeup(genpd, dev); |
594 | return device_may_wakeup(dev) ? active_wakeup : !active_wakeup; | 725 | return device_may_wakeup(dev) ? active_wakeup : !active_wakeup; |
595 | } | 726 | } |
596 | 727 | ||
@@ -646,7 +777,7 @@ static int pm_genpd_prepare(struct device *dev) | |||
646 | /* | 777 | /* |
647 | * The PM domain must be in the GPD_STATE_ACTIVE state at this point, | 778 | * The PM domain must be in the GPD_STATE_ACTIVE state at this point, |
648 | * so pm_genpd_poweron() will return immediately, but if the device | 779 | * so pm_genpd_poweron() will return immediately, but if the device |
649 | * is suspended (e.g. it's been stopped by .stop_device()), we need | 780 | * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need |
650 | * to make it operational. | 781 | * to make it operational. |
651 | */ | 782 | */ |
652 | pm_runtime_resume(dev); | 783 | pm_runtime_resume(dev); |
@@ -685,7 +816,7 @@ static int pm_genpd_suspend(struct device *dev) | |||
685 | if (IS_ERR(genpd)) | 816 | if (IS_ERR(genpd)) |
686 | return -EINVAL; | 817 | return -EINVAL; |
687 | 818 | ||
688 | return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev); | 819 | return genpd->suspend_power_off ? 0 : genpd_suspend_dev(genpd, dev); |
689 | } | 820 | } |
690 | 821 | ||
691 | /** | 822 | /** |
@@ -710,16 +841,14 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
710 | if (genpd->suspend_power_off) | 841 | if (genpd->suspend_power_off) |
711 | return 0; | 842 | return 0; |
712 | 843 | ||
713 | ret = pm_generic_suspend_noirq(dev); | 844 | ret = genpd_suspend_late(genpd, dev); |
714 | if (ret) | 845 | if (ret) |
715 | return ret; | 846 | return ret; |
716 | 847 | ||
717 | if (dev->power.wakeup_path | 848 | if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) |
718 | && genpd->active_wakeup && genpd->active_wakeup(dev)) | ||
719 | return 0; | 849 | return 0; |
720 | 850 | ||
721 | if (genpd->stop_device) | 851 | genpd_stop_dev(genpd, dev); |
722 | genpd->stop_device(dev); | ||
723 | 852 | ||
724 | /* | 853 | /* |
725 | * Since all of the "noirq" callbacks are executed sequentially, it is | 854 | * Since all of the "noirq" callbacks are executed sequentially, it is |
@@ -761,10 +890,9 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
761 | */ | 890 | */ |
762 | pm_genpd_poweron(genpd); | 891 | pm_genpd_poweron(genpd); |
763 | genpd->suspended_count--; | 892 | genpd->suspended_count--; |
764 | if (genpd->start_device) | 893 | genpd_start_dev(genpd, dev); |
765 | genpd->start_device(dev); | ||
766 | 894 | ||
767 | return pm_generic_resume_noirq(dev); | 895 | return genpd_resume_early(genpd, dev); |
768 | } | 896 | } |
769 | 897 | ||
770 | /** | 898 | /** |
@@ -785,7 +913,7 @@ static int pm_genpd_resume(struct device *dev) | |||
785 | if (IS_ERR(genpd)) | 913 | if (IS_ERR(genpd)) |
786 | return -EINVAL; | 914 | return -EINVAL; |
787 | 915 | ||
788 | return genpd->suspend_power_off ? 0 : pm_generic_resume(dev); | 916 | return genpd->suspend_power_off ? 0 : genpd_resume_dev(genpd, dev); |
789 | } | 917 | } |
790 | 918 | ||
791 | /** | 919 | /** |
@@ -806,7 +934,7 @@ static int pm_genpd_freeze(struct device *dev) | |||
806 | if (IS_ERR(genpd)) | 934 | if (IS_ERR(genpd)) |
807 | return -EINVAL; | 935 | return -EINVAL; |
808 | 936 | ||
809 | return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev); | 937 | return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev); |
810 | } | 938 | } |
811 | 939 | ||
812 | /** | 940 | /** |
@@ -832,12 +960,11 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
832 | if (genpd->suspend_power_off) | 960 | if (genpd->suspend_power_off) |
833 | return 0; | 961 | return 0; |
834 | 962 | ||
835 | ret = pm_generic_freeze_noirq(dev); | 963 | ret = genpd_freeze_late(genpd, dev); |
836 | if (ret) | 964 | if (ret) |
837 | return ret; | 965 | return ret; |
838 | 966 | ||
839 | if (genpd->stop_device) | 967 | genpd_stop_dev(genpd, dev); |
840 | genpd->stop_device(dev); | ||
841 | 968 | ||
842 | return 0; | 969 | return 0; |
843 | } | 970 | } |
@@ -864,10 +991,9 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
864 | if (genpd->suspend_power_off) | 991 | if (genpd->suspend_power_off) |
865 | return 0; | 992 | return 0; |
866 | 993 | ||
867 | if (genpd->start_device) | 994 | genpd_start_dev(genpd, dev); |
868 | genpd->start_device(dev); | ||
869 | 995 | ||
870 | return pm_generic_thaw_noirq(dev); | 996 | return genpd_thaw_early(genpd, dev); |
871 | } | 997 | } |
872 | 998 | ||
873 | /** | 999 | /** |
@@ -888,72 +1014,7 @@ static int pm_genpd_thaw(struct device *dev) | |||
888 | if (IS_ERR(genpd)) | 1014 | if (IS_ERR(genpd)) |
889 | return -EINVAL; | 1015 | return -EINVAL; |
890 | 1016 | ||
891 | return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev); | 1017 | return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev); |
892 | } | ||
893 | |||
894 | /** | ||
895 | * pm_genpd_dev_poweroff - Power off a device belonging to an I/O PM domain. | ||
896 | * @dev: Device to suspend. | ||
897 | * | ||
898 | * Power off a device under the assumption that its pm_domain field points to | ||
899 | * the domain member of an object of type struct generic_pm_domain representing | ||
900 | * a PM domain consisting of I/O devices. | ||
901 | */ | ||
902 | static int pm_genpd_dev_poweroff(struct device *dev) | ||
903 | { | ||
904 | struct generic_pm_domain *genpd; | ||
905 | |||
906 | dev_dbg(dev, "%s()\n", __func__); | ||
907 | |||
908 | genpd = dev_to_genpd(dev); | ||
909 | if (IS_ERR(genpd)) | ||
910 | return -EINVAL; | ||
911 | |||
912 | return genpd->suspend_power_off ? 0 : pm_generic_poweroff(dev); | ||
913 | } | ||
914 | |||
915 | /** | ||
916 | * pm_genpd_dev_poweroff_noirq - Late power off of a device from a PM domain. | ||
917 | * @dev: Device to suspend. | ||
918 | * | ||
919 | * Carry out a late powering off of a device under the assumption that its | ||
920 | * pm_domain field points to the domain member of an object of type | ||
921 | * struct generic_pm_domain representing a PM domain consisting of I/O devices. | ||
922 | */ | ||
923 | static int pm_genpd_dev_poweroff_noirq(struct device *dev) | ||
924 | { | ||
925 | struct generic_pm_domain *genpd; | ||
926 | int ret; | ||
927 | |||
928 | dev_dbg(dev, "%s()\n", __func__); | ||
929 | |||
930 | genpd = dev_to_genpd(dev); | ||
931 | if (IS_ERR(genpd)) | ||
932 | return -EINVAL; | ||
933 | |||
934 | if (genpd->suspend_power_off) | ||
935 | return 0; | ||
936 | |||
937 | ret = pm_generic_poweroff_noirq(dev); | ||
938 | if (ret) | ||
939 | return ret; | ||
940 | |||
941 | if (dev->power.wakeup_path | ||
942 | && genpd->active_wakeup && genpd->active_wakeup(dev)) | ||
943 | return 0; | ||
944 | |||
945 | if (genpd->stop_device) | ||
946 | genpd->stop_device(dev); | ||
947 | |||
948 | /* | ||
949 | * Since all of the "noirq" callbacks are executed sequentially, it is | ||
950 | * guaranteed that this function will never run twice in parallel for | ||
951 | * the same PM domain, so it is not necessary to use locking here. | ||
952 | */ | ||
953 | genpd->suspended_count++; | ||
954 | pm_genpd_sync_poweroff(genpd); | ||
955 | |||
956 | return 0; | ||
957 | } | 1018 | } |
958 | 1019 | ||
959 | /** | 1020 | /** |
@@ -993,31 +1054,9 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
993 | 1054 | ||
994 | pm_genpd_poweron(genpd); | 1055 | pm_genpd_poweron(genpd); |
995 | genpd->suspended_count--; | 1056 | genpd->suspended_count--; |
996 | if (genpd->start_device) | 1057 | genpd_start_dev(genpd, dev); |
997 | genpd->start_device(dev); | ||
998 | |||
999 | return pm_generic_restore_noirq(dev); | ||
1000 | } | ||
1001 | |||
1002 | /** | ||
1003 | * pm_genpd_restore - Restore a device belonging to an I/O power domain. | ||
1004 | * @dev: Device to resume. | ||
1005 | * | ||
1006 | * Restore a device under the assumption that its pm_domain field points to the | ||
1007 | * domain member of an object of type struct generic_pm_domain representing | ||
1008 | * a power domain consisting of I/O devices. | ||
1009 | */ | ||
1010 | static int pm_genpd_restore(struct device *dev) | ||
1011 | { | ||
1012 | struct generic_pm_domain *genpd; | ||
1013 | |||
1014 | dev_dbg(dev, "%s()\n", __func__); | ||
1015 | |||
1016 | genpd = dev_to_genpd(dev); | ||
1017 | if (IS_ERR(genpd)) | ||
1018 | return -EINVAL; | ||
1019 | 1058 | ||
1020 | return genpd->suspend_power_off ? 0 : pm_generic_restore(dev); | 1059 | return genpd_resume_early(genpd, dev); |
1021 | } | 1060 | } |
1022 | 1061 | ||
1023 | /** | 1062 | /** |
@@ -1067,20 +1106,19 @@ static void pm_genpd_complete(struct device *dev) | |||
1067 | #define pm_genpd_freeze_noirq NULL | 1106 | #define pm_genpd_freeze_noirq NULL |
1068 | #define pm_genpd_thaw_noirq NULL | 1107 | #define pm_genpd_thaw_noirq NULL |
1069 | #define pm_genpd_thaw NULL | 1108 | #define pm_genpd_thaw NULL |
1070 | #define pm_genpd_dev_poweroff_noirq NULL | ||
1071 | #define pm_genpd_dev_poweroff NULL | ||
1072 | #define pm_genpd_restore_noirq NULL | 1109 | #define pm_genpd_restore_noirq NULL |
1073 | #define pm_genpd_restore NULL | ||
1074 | #define pm_genpd_complete NULL | 1110 | #define pm_genpd_complete NULL |
1075 | 1111 | ||
1076 | #endif /* CONFIG_PM_SLEEP */ | 1112 | #endif /* CONFIG_PM_SLEEP */ |
1077 | 1113 | ||
1078 | /** | 1114 | /** |
1079 | * pm_genpd_add_device - Add a device to an I/O PM domain. | 1115 | * __pm_genpd_add_device - Add a device to an I/O PM domain. |
1080 | * @genpd: PM domain to add the device to. | 1116 | * @genpd: PM domain to add the device to. |
1081 | * @dev: Device to be added. | 1117 | * @dev: Device to be added. |
1118 | * @td: Set of PM QoS timing parameters to attach to the device. | ||
1082 | */ | 1119 | */ |
1083 | int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | 1120 | int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, |
1121 | struct gpd_timing_data *td) | ||
1084 | { | 1122 | { |
1085 | struct generic_pm_domain_data *gpd_data; | 1123 | struct generic_pm_domain_data *gpd_data; |
1086 | struct pm_domain_data *pdd; | 1124 | struct pm_domain_data *pdd; |
@@ -1123,6 +1161,8 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | |||
1123 | gpd_data->base.dev = dev; | 1161 | gpd_data->base.dev = dev; |
1124 | gpd_data->need_restore = false; | 1162 | gpd_data->need_restore = false; |
1125 | list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); | 1163 | list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); |
1164 | if (td) | ||
1165 | gpd_data->td = *td; | ||
1126 | 1166 | ||
1127 | out: | 1167 | out: |
1128 | genpd_release_lock(genpd); | 1168 | genpd_release_lock(genpd); |
@@ -1280,6 +1320,204 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | |||
1280 | } | 1320 | } |
1281 | 1321 | ||
1282 | /** | 1322 | /** |
1323 | * pm_genpd_add_callbacks - Add PM domain callbacks to a given device. | ||
1324 | * @dev: Device to add the callbacks to. | ||
1325 | * @ops: Set of callbacks to add. | ||
1326 | * @td: Timing data to add to the device along with the callbacks (optional). | ||
1327 | */ | ||
1328 | int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops, | ||
1329 | struct gpd_timing_data *td) | ||
1330 | { | ||
1331 | struct pm_domain_data *pdd; | ||
1332 | int ret = 0; | ||
1333 | |||
1334 | if (!(dev && dev->power.subsys_data && ops)) | ||
1335 | return -EINVAL; | ||
1336 | |||
1337 | pm_runtime_disable(dev); | ||
1338 | device_pm_lock(); | ||
1339 | |||
1340 | pdd = dev->power.subsys_data->domain_data; | ||
1341 | if (pdd) { | ||
1342 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | ||
1343 | |||
1344 | gpd_data->ops = *ops; | ||
1345 | if (td) | ||
1346 | gpd_data->td = *td; | ||
1347 | } else { | ||
1348 | ret = -EINVAL; | ||
1349 | } | ||
1350 | |||
1351 | device_pm_unlock(); | ||
1352 | pm_runtime_enable(dev); | ||
1353 | |||
1354 | return ret; | ||
1355 | } | ||
1356 | EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks); | ||
1357 | |||
1358 | /** | ||
1359 | * __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device. | ||
1360 | * @dev: Device to remove the callbacks from. | ||
1361 | * @clear_td: If set, clear the device's timing data too. | ||
1362 | */ | ||
1363 | int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td) | ||
1364 | { | ||
1365 | struct pm_domain_data *pdd; | ||
1366 | int ret = 0; | ||
1367 | |||
1368 | if (!(dev && dev->power.subsys_data)) | ||
1369 | return -EINVAL; | ||
1370 | |||
1371 | pm_runtime_disable(dev); | ||
1372 | device_pm_lock(); | ||
1373 | |||
1374 | pdd = dev->power.subsys_data->domain_data; | ||
1375 | if (pdd) { | ||
1376 | struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); | ||
1377 | |||
1378 | gpd_data->ops = (struct gpd_dev_ops){ 0 }; | ||
1379 | if (clear_td) | ||
1380 | gpd_data->td = (struct gpd_timing_data){ 0 }; | ||
1381 | } else { | ||
1382 | ret = -EINVAL; | ||
1383 | } | ||
1384 | |||
1385 | device_pm_unlock(); | ||
1386 | pm_runtime_enable(dev); | ||
1387 | |||
1388 | return ret; | ||
1389 | } | ||
1390 | EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks); | ||
1391 | |||
1392 | /* Default device callbacks for generic PM domains. */ | ||
1393 | |||
1394 | /** | ||
1395 | * pm_genpd_default_save_state - Default "save device state" for PM domians. | ||
1396 | * @dev: Device to handle. | ||
1397 | */ | ||
1398 | static int pm_genpd_default_save_state(struct device *dev) | ||
1399 | { | ||
1400 | int (*cb)(struct device *__dev); | ||
1401 | struct device_driver *drv = dev->driver; | ||
1402 | |||
1403 | cb = dev_gpd_data(dev)->ops.save_state; | ||
1404 | if (cb) | ||
1405 | return cb(dev); | ||
1406 | |||
1407 | if (drv && drv->pm && drv->pm->runtime_suspend) | ||
1408 | return drv->pm->runtime_suspend(dev); | ||
1409 | |||
1410 | return 0; | ||
1411 | } | ||
1412 | |||
1413 | /** | ||
1414 | * pm_genpd_default_restore_state - Default PM domians "restore device state". | ||
1415 | * @dev: Device to handle. | ||
1416 | */ | ||
1417 | static int pm_genpd_default_restore_state(struct device *dev) | ||
1418 | { | ||
1419 | int (*cb)(struct device *__dev); | ||
1420 | struct device_driver *drv = dev->driver; | ||
1421 | |||
1422 | cb = dev_gpd_data(dev)->ops.restore_state; | ||
1423 | if (cb) | ||
1424 | return cb(dev); | ||
1425 | |||
1426 | if (drv && drv->pm && drv->pm->runtime_resume) | ||
1427 | return drv->pm->runtime_resume(dev); | ||
1428 | |||
1429 | return 0; | ||
1430 | } | ||
1431 | |||
1432 | /** | ||
1433 | * pm_genpd_default_suspend - Default "device suspend" for PM domians. | ||
1434 | * @dev: Device to handle. | ||
1435 | */ | ||
1436 | static int pm_genpd_default_suspend(struct device *dev) | ||
1437 | { | ||
1438 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend; | ||
1439 | |||
1440 | return cb ? cb(dev) : pm_generic_suspend(dev); | ||
1441 | } | ||
1442 | |||
1443 | /** | ||
1444 | * pm_genpd_default_suspend_late - Default "late device suspend" for PM domians. | ||
1445 | * @dev: Device to handle. | ||
1446 | */ | ||
1447 | static int pm_genpd_default_suspend_late(struct device *dev) | ||
1448 | { | ||
1449 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; | ||
1450 | |||
1451 | return cb ? cb(dev) : pm_generic_suspend_noirq(dev); | ||
1452 | } | ||
1453 | |||
1454 | /** | ||
1455 | * pm_genpd_default_resume_early - Default "early device resume" for PM domians. | ||
1456 | * @dev: Device to handle. | ||
1457 | */ | ||
1458 | static int pm_genpd_default_resume_early(struct device *dev) | ||
1459 | { | ||
1460 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; | ||
1461 | |||
1462 | return cb ? cb(dev) : pm_generic_resume_noirq(dev); | ||
1463 | } | ||
1464 | |||
1465 | /** | ||
1466 | * pm_genpd_default_resume - Default "device resume" for PM domians. | ||
1467 | * @dev: Device to handle. | ||
1468 | */ | ||
1469 | static int pm_genpd_default_resume(struct device *dev) | ||
1470 | { | ||
1471 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume; | ||
1472 | |||
1473 | return cb ? cb(dev) : pm_generic_resume(dev); | ||
1474 | } | ||
1475 | |||
1476 | /** | ||
1477 | * pm_genpd_default_freeze - Default "device freeze" for PM domians. | ||
1478 | * @dev: Device to handle. | ||
1479 | */ | ||
1480 | static int pm_genpd_default_freeze(struct device *dev) | ||
1481 | { | ||
1482 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze; | ||
1483 | |||
1484 | return cb ? cb(dev) : pm_generic_freeze(dev); | ||
1485 | } | ||
1486 | |||
1487 | /** | ||
1488 | * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians. | ||
1489 | * @dev: Device to handle. | ||
1490 | */ | ||
1491 | static int pm_genpd_default_freeze_late(struct device *dev) | ||
1492 | { | ||
1493 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; | ||
1494 | |||
1495 | return cb ? cb(dev) : pm_generic_freeze_noirq(dev); | ||
1496 | } | ||
1497 | |||
1498 | /** | ||
1499 | * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians. | ||
1500 | * @dev: Device to handle. | ||
1501 | */ | ||
1502 | static int pm_genpd_default_thaw_early(struct device *dev) | ||
1503 | { | ||
1504 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; | ||
1505 | |||
1506 | return cb ? cb(dev) : pm_generic_thaw_noirq(dev); | ||
1507 | } | ||
1508 | |||
1509 | /** | ||
1510 | * pm_genpd_default_thaw - Default "device thaw" for PM domians. | ||
1511 | * @dev: Device to handle. | ||
1512 | */ | ||
1513 | static int pm_genpd_default_thaw(struct device *dev) | ||
1514 | { | ||
1515 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw; | ||
1516 | |||
1517 | return cb ? cb(dev) : pm_generic_thaw(dev); | ||
1518 | } | ||
1519 | |||
1520 | /** | ||
1283 | * pm_genpd_init - Initialize a generic I/O PM domain object. | 1521 | * pm_genpd_init - Initialize a generic I/O PM domain object. |
1284 | * @genpd: PM domain object to initialize. | 1522 | * @genpd: PM domain object to initialize. |
1285 | * @gov: PM domain governor to associate with the domain (may be NULL). | 1523 | * @gov: PM domain governor to associate with the domain (may be NULL). |
@@ -1305,6 +1543,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1305 | genpd->resume_count = 0; | 1543 | genpd->resume_count = 0; |
1306 | genpd->device_count = 0; | 1544 | genpd->device_count = 0; |
1307 | genpd->suspended_count = 0; | 1545 | genpd->suspended_count = 0; |
1546 | genpd->max_off_time_ns = -1; | ||
1308 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; | 1547 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; |
1309 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; | 1548 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; |
1310 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; | 1549 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; |
@@ -1317,11 +1556,21 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1317 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; | 1556 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; |
1318 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; | 1557 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; |
1319 | genpd->domain.ops.thaw = pm_genpd_thaw; | 1558 | genpd->domain.ops.thaw = pm_genpd_thaw; |
1320 | genpd->domain.ops.poweroff = pm_genpd_dev_poweroff; | 1559 | genpd->domain.ops.poweroff = pm_genpd_suspend; |
1321 | genpd->domain.ops.poweroff_noirq = pm_genpd_dev_poweroff_noirq; | 1560 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; |
1322 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; | 1561 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; |
1323 | genpd->domain.ops.restore = pm_genpd_restore; | 1562 | genpd->domain.ops.restore = pm_genpd_resume; |
1324 | genpd->domain.ops.complete = pm_genpd_complete; | 1563 | genpd->domain.ops.complete = pm_genpd_complete; |
1564 | genpd->dev_ops.save_state = pm_genpd_default_save_state; | ||
1565 | genpd->dev_ops.restore_state = pm_genpd_default_restore_state; | ||
1566 | genpd->dev_ops.suspend = pm_genpd_default_suspend; | ||
1567 | genpd->dev_ops.suspend_late = pm_genpd_default_suspend_late; | ||
1568 | genpd->dev_ops.resume_early = pm_genpd_default_resume_early; | ||
1569 | genpd->dev_ops.resume = pm_genpd_default_resume; | ||
1570 | genpd->dev_ops.freeze = pm_genpd_default_freeze; | ||
1571 | genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late; | ||
1572 | genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early; | ||
1573 | genpd->dev_ops.thaw = pm_genpd_default_thaw; | ||
1325 | mutex_lock(&gpd_list_lock); | 1574 | mutex_lock(&gpd_list_lock); |
1326 | list_add(&genpd->gpd_list_node, &gpd_list); | 1575 | list_add(&genpd->gpd_list_node, &gpd_list); |
1327 | mutex_unlock(&gpd_list_lock); | 1576 | mutex_unlock(&gpd_list_lock); |
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c new file mode 100644 index 000000000000..51527ee92d10 --- /dev/null +++ b/drivers/base/power/domain_governor.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * drivers/base/power/domain_governor.c - Governors for device PM domains. | ||
3 | * | ||
4 | * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp. | ||
5 | * | ||
6 | * This file is released under the GPLv2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/pm_domain.h> | ||
12 | #include <linux/pm_qos.h> | ||
13 | #include <linux/hrtimer.h> | ||
14 | |||
15 | /** | ||
16 | * default_stop_ok - Default PM domain governor routine for stopping devices. | ||
17 | * @dev: Device to check. | ||
18 | */ | ||
19 | bool default_stop_ok(struct device *dev) | ||
20 | { | ||
21 | struct gpd_timing_data *td = &dev_gpd_data(dev)->td; | ||
22 | |||
23 | dev_dbg(dev, "%s()\n", __func__); | ||
24 | |||
25 | if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0) | ||
26 | return true; | ||
27 | |||
28 | return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns | ||
29 | && td->break_even_ns < dev->power.max_time_suspended_ns; | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * default_power_down_ok - Default generic PM domain power off governor routine. | ||
34 | * @pd: PM domain to check. | ||
35 | * | ||
36 | * This routine must be executed under the PM domain's lock. | ||
37 | */ | ||
38 | static bool default_power_down_ok(struct dev_pm_domain *pd) | ||
39 | { | ||
40 | struct generic_pm_domain *genpd = pd_to_genpd(pd); | ||
41 | struct gpd_link *link; | ||
42 | struct pm_domain_data *pdd; | ||
43 | s64 min_dev_off_time_ns; | ||
44 | s64 off_on_time_ns; | ||
45 | ktime_t time_now = ktime_get(); | ||
46 | |||
47 | off_on_time_ns = genpd->power_off_latency_ns + | ||
48 | genpd->power_on_latency_ns; | ||
49 | /* | ||
50 | * It doesn't make sense to remove power from the domain if saving | ||
51 | * the state of all devices in it and the power off/power on operations | ||
52 | * take too much time. | ||
53 | * | ||
54 | * All devices in this domain have been stopped already at this point. | ||
55 | */ | ||
56 | list_for_each_entry(pdd, &genpd->dev_list, list_node) { | ||
57 | if (pdd->dev->driver) | ||
58 | off_on_time_ns += | ||
59 | to_gpd_data(pdd)->td.save_state_latency_ns; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Check if subdomains can be off for enough time. | ||
64 | * | ||
65 | * All subdomains have been powered off already at this point. | ||
66 | */ | ||
67 | list_for_each_entry(link, &genpd->master_links, master_node) { | ||
68 | struct generic_pm_domain *sd = link->slave; | ||
69 | s64 sd_max_off_ns = sd->max_off_time_ns; | ||
70 | |||
71 | if (sd_max_off_ns < 0) | ||
72 | continue; | ||
73 | |||
74 | sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now, | ||
75 | sd->power_off_time)); | ||
76 | /* | ||
77 | * Check if the subdomain is allowed to be off long enough for | ||
78 | * the current domain to turn off and on (that's how much time | ||
79 | * it will have to wait worst case). | ||
80 | */ | ||
81 | if (sd_max_off_ns <= off_on_time_ns) | ||
82 | return false; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Check if the devices in the domain can be off enough time. | ||
87 | */ | ||
88 | min_dev_off_time_ns = -1; | ||
89 | list_for_each_entry(pdd, &genpd->dev_list, list_node) { | ||
90 | struct gpd_timing_data *td; | ||
91 | struct device *dev = pdd->dev; | ||
92 | s64 dev_off_time_ns; | ||
93 | |||
94 | if (!dev->driver || dev->power.max_time_suspended_ns < 0) | ||
95 | continue; | ||
96 | |||
97 | td = &to_gpd_data(pdd)->td; | ||
98 | dev_off_time_ns = dev->power.max_time_suspended_ns - | ||
99 | (td->start_latency_ns + td->restore_state_latency_ns + | ||
100 | ktime_to_ns(ktime_sub(time_now, | ||
101 | dev->power.suspend_time))); | ||
102 | if (dev_off_time_ns <= off_on_time_ns) | ||
103 | return false; | ||
104 | |||
105 | if (min_dev_off_time_ns > dev_off_time_ns | ||
106 | || min_dev_off_time_ns < 0) | ||
107 | min_dev_off_time_ns = dev_off_time_ns; | ||
108 | } | ||
109 | |||
110 | if (min_dev_off_time_ns < 0) { | ||
111 | /* | ||
112 | * There are no latency constraints, so the domain can spend | ||
113 | * arbitrary time in the "off" state. | ||
114 | */ | ||
115 | genpd->max_off_time_ns = -1; | ||
116 | return true; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * The difference between the computed minimum delta and the time needed | ||
121 | * to turn the domain on is the maximum theoretical time this domain can | ||
122 | * spend in the "off" state. | ||
123 | */ | ||
124 | min_dev_off_time_ns -= genpd->power_on_latency_ns; | ||
125 | |||
126 | /* | ||
127 | * If the difference between the computed minimum delta and the time | ||
128 | * needed to turn the domain off and back on on is smaller than the | ||
129 | * domain's power break even time, removing power from the domain is not | ||
130 | * worth it. | ||
131 | */ | ||
132 | if (genpd->break_even_ns > | ||
133 | min_dev_off_time_ns - genpd->power_off_latency_ns) | ||
134 | return false; | ||
135 | |||
136 | genpd->max_off_time_ns = min_dev_off_time_ns; | ||
137 | return true; | ||
138 | } | ||
139 | |||
140 | struct dev_power_governor simple_qos_governor = { | ||
141 | .stop_ok = default_stop_ok, | ||
142 | .power_down_ok = default_power_down_ok, | ||
143 | }; | ||
144 | |||
145 | static bool always_on_power_down_ok(struct dev_pm_domain *domain) | ||
146 | { | ||
147 | return false; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * pm_genpd_gov_always_on - A governor implementing an always-on policy | ||
152 | */ | ||
153 | struct dev_power_governor pm_domain_always_on_gov = { | ||
154 | .power_down_ok = always_on_power_down_ok, | ||
155 | .stop_ok = default_stop_ok, | ||
156 | }; | ||
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 265a0ee3b49e..10bdd793f0bd 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c | |||
@@ -97,16 +97,16 @@ int pm_generic_prepare(struct device *dev) | |||
97 | * @event: PM transition of the system under way. | 97 | * @event: PM transition of the system under way. |
98 | * @bool: Whether or not this is the "noirq" stage. | 98 | * @bool: Whether or not this is the "noirq" stage. |
99 | * | 99 | * |
100 | * If the device has not been suspended at run time, execute the | 100 | * Execute the PM callback corresponding to @event provided by the driver of |
101 | * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and | 101 | * @dev, if defined, and return its error code. Return 0 if the callback is |
102 | * return its error code. Otherwise, return zero. | 102 | * not present. |
103 | */ | 103 | */ |
104 | static int __pm_generic_call(struct device *dev, int event, bool noirq) | 104 | static int __pm_generic_call(struct device *dev, int event, bool noirq) |
105 | { | 105 | { |
106 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | 106 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
107 | int (*callback)(struct device *); | 107 | int (*callback)(struct device *); |
108 | 108 | ||
109 | if (!pm || pm_runtime_suspended(dev)) | 109 | if (!pm) |
110 | return 0; | 110 | return 0; |
111 | 111 | ||
112 | switch (event) { | 112 | switch (event) { |
@@ -119,9 +119,15 @@ static int __pm_generic_call(struct device *dev, int event, bool noirq) | |||
119 | case PM_EVENT_HIBERNATE: | 119 | case PM_EVENT_HIBERNATE: |
120 | callback = noirq ? pm->poweroff_noirq : pm->poweroff; | 120 | callback = noirq ? pm->poweroff_noirq : pm->poweroff; |
121 | break; | 121 | break; |
122 | case PM_EVENT_RESUME: | ||
123 | callback = noirq ? pm->resume_noirq : pm->resume; | ||
124 | break; | ||
122 | case PM_EVENT_THAW: | 125 | case PM_EVENT_THAW: |
123 | callback = noirq ? pm->thaw_noirq : pm->thaw; | 126 | callback = noirq ? pm->thaw_noirq : pm->thaw; |
124 | break; | 127 | break; |
128 | case PM_EVENT_RESTORE: | ||
129 | callback = noirq ? pm->restore_noirq : pm->restore; | ||
130 | break; | ||
125 | default: | 131 | default: |
126 | callback = NULL; | 132 | callback = NULL; |
127 | break; | 133 | break; |
@@ -211,56 +217,12 @@ int pm_generic_thaw(struct device *dev) | |||
211 | EXPORT_SYMBOL_GPL(pm_generic_thaw); | 217 | EXPORT_SYMBOL_GPL(pm_generic_thaw); |
212 | 218 | ||
213 | /** | 219 | /** |
214 | * __pm_generic_resume - Generic resume/restore callback for subsystems. | ||
215 | * @dev: Device to handle. | ||
216 | * @event: PM transition of the system under way. | ||
217 | * @bool: Whether or not this is the "noirq" stage. | ||
218 | * | ||
219 | * Execute the resume/resotre callback provided by the @dev's driver, if | ||
220 | * defined. If it returns 0, change the device's runtime PM status to 'active'. | ||
221 | * Return the callback's error code. | ||
222 | */ | ||
223 | static int __pm_generic_resume(struct device *dev, int event, bool noirq) | ||
224 | { | ||
225 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
226 | int (*callback)(struct device *); | ||
227 | int ret; | ||
228 | |||
229 | if (!pm) | ||
230 | return 0; | ||
231 | |||
232 | switch (event) { | ||
233 | case PM_EVENT_RESUME: | ||
234 | callback = noirq ? pm->resume_noirq : pm->resume; | ||
235 | break; | ||
236 | case PM_EVENT_RESTORE: | ||
237 | callback = noirq ? pm->restore_noirq : pm->restore; | ||
238 | break; | ||
239 | default: | ||
240 | callback = NULL; | ||
241 | break; | ||
242 | } | ||
243 | |||
244 | if (!callback) | ||
245 | return 0; | ||
246 | |||
247 | ret = callback(dev); | ||
248 | if (!ret && !noirq && pm_runtime_enabled(dev)) { | ||
249 | pm_runtime_disable(dev); | ||
250 | pm_runtime_set_active(dev); | ||
251 | pm_runtime_enable(dev); | ||
252 | } | ||
253 | |||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * pm_generic_resume_noirq - Generic resume_noirq callback for subsystems. | 220 | * pm_generic_resume_noirq - Generic resume_noirq callback for subsystems. |
259 | * @dev: Device to resume. | 221 | * @dev: Device to resume. |
260 | */ | 222 | */ |
261 | int pm_generic_resume_noirq(struct device *dev) | 223 | int pm_generic_resume_noirq(struct device *dev) |
262 | { | 224 | { |
263 | return __pm_generic_resume(dev, PM_EVENT_RESUME, true); | 225 | return __pm_generic_call(dev, PM_EVENT_RESUME, true); |
264 | } | 226 | } |
265 | EXPORT_SYMBOL_GPL(pm_generic_resume_noirq); | 227 | EXPORT_SYMBOL_GPL(pm_generic_resume_noirq); |
266 | 228 | ||
@@ -270,7 +232,7 @@ EXPORT_SYMBOL_GPL(pm_generic_resume_noirq); | |||
270 | */ | 232 | */ |
271 | int pm_generic_resume(struct device *dev) | 233 | int pm_generic_resume(struct device *dev) |
272 | { | 234 | { |
273 | return __pm_generic_resume(dev, PM_EVENT_RESUME, false); | 235 | return __pm_generic_call(dev, PM_EVENT_RESUME, false); |
274 | } | 236 | } |
275 | EXPORT_SYMBOL_GPL(pm_generic_resume); | 237 | EXPORT_SYMBOL_GPL(pm_generic_resume); |
276 | 238 | ||
@@ -280,7 +242,7 @@ EXPORT_SYMBOL_GPL(pm_generic_resume); | |||
280 | */ | 242 | */ |
281 | int pm_generic_restore_noirq(struct device *dev) | 243 | int pm_generic_restore_noirq(struct device *dev) |
282 | { | 244 | { |
283 | return __pm_generic_resume(dev, PM_EVENT_RESTORE, true); | 245 | return __pm_generic_call(dev, PM_EVENT_RESTORE, true); |
284 | } | 246 | } |
285 | EXPORT_SYMBOL_GPL(pm_generic_restore_noirq); | 247 | EXPORT_SYMBOL_GPL(pm_generic_restore_noirq); |
286 | 248 | ||
@@ -290,7 +252,7 @@ EXPORT_SYMBOL_GPL(pm_generic_restore_noirq); | |||
290 | */ | 252 | */ |
291 | int pm_generic_restore(struct device *dev) | 253 | int pm_generic_restore(struct device *dev) |
292 | { | 254 | { |
293 | return __pm_generic_resume(dev, PM_EVENT_RESTORE, false); | 255 | return __pm_generic_call(dev, PM_EVENT_RESTORE, false); |
294 | } | 256 | } |
295 | EXPORT_SYMBOL_GPL(pm_generic_restore); | 257 | EXPORT_SYMBOL_GPL(pm_generic_restore); |
296 | 258 | ||
@@ -314,28 +276,3 @@ void pm_generic_complete(struct device *dev) | |||
314 | pm_runtime_idle(dev); | 276 | pm_runtime_idle(dev); |
315 | } | 277 | } |
316 | #endif /* CONFIG_PM_SLEEP */ | 278 | #endif /* CONFIG_PM_SLEEP */ |
317 | |||
318 | struct dev_pm_ops generic_subsys_pm_ops = { | ||
319 | #ifdef CONFIG_PM_SLEEP | ||
320 | .prepare = pm_generic_prepare, | ||
321 | .suspend = pm_generic_suspend, | ||
322 | .suspend_noirq = pm_generic_suspend_noirq, | ||
323 | .resume = pm_generic_resume, | ||
324 | .resume_noirq = pm_generic_resume_noirq, | ||
325 | .freeze = pm_generic_freeze, | ||
326 | .freeze_noirq = pm_generic_freeze_noirq, | ||
327 | .thaw = pm_generic_thaw, | ||
328 | .thaw_noirq = pm_generic_thaw_noirq, | ||
329 | .poweroff = pm_generic_poweroff, | ||
330 | .poweroff_noirq = pm_generic_poweroff_noirq, | ||
331 | .restore = pm_generic_restore, | ||
332 | .restore_noirq = pm_generic_restore_noirq, | ||
333 | .complete = pm_generic_complete, | ||
334 | #endif | ||
335 | #ifdef CONFIG_PM_RUNTIME | ||
336 | .runtime_suspend = pm_generic_runtime_suspend, | ||
337 | .runtime_resume = pm_generic_runtime_resume, | ||
338 | .runtime_idle = pm_generic_runtime_idle, | ||
339 | #endif | ||
340 | }; | ||
341 | EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); | ||
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index c3d2dfcf438d..e2cc3d2e0ecc 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include "../base.h" | 32 | #include "../base.h" |
33 | #include "power.h" | 33 | #include "power.h" |
34 | 34 | ||
35 | typedef int (*pm_callback_t)(struct device *); | ||
36 | |||
35 | /* | 37 | /* |
36 | * The entries in the dpm_list list are in a depth first order, simply | 38 | * The entries in the dpm_list list are in a depth first order, simply |
37 | * because children are guaranteed to be discovered after parents, and | 39 | * because children are guaranteed to be discovered after parents, and |
@@ -164,8 +166,9 @@ static ktime_t initcall_debug_start(struct device *dev) | |||
164 | ktime_t calltime = ktime_set(0, 0); | 166 | ktime_t calltime = ktime_set(0, 0); |
165 | 167 | ||
166 | if (initcall_debug) { | 168 | if (initcall_debug) { |
167 | pr_info("calling %s+ @ %i\n", | 169 | pr_info("calling %s+ @ %i, parent: %s\n", |
168 | dev_name(dev), task_pid_nr(current)); | 170 | dev_name(dev), task_pid_nr(current), |
171 | dev->parent ? dev_name(dev->parent) : "none"); | ||
169 | calltime = ktime_get(); | 172 | calltime = ktime_get(); |
170 | } | 173 | } |
171 | 174 | ||
@@ -211,151 +214,69 @@ static void dpm_wait_for_children(struct device *dev, bool async) | |||
211 | } | 214 | } |
212 | 215 | ||
213 | /** | 216 | /** |
214 | * pm_op - Execute the PM operation appropriate for given PM event. | 217 | * pm_op - Return the PM operation appropriate for given PM event. |
215 | * @dev: Device to handle. | ||
216 | * @ops: PM operations to choose from. | 218 | * @ops: PM operations to choose from. |
217 | * @state: PM transition of the system being carried out. | 219 | * @state: PM transition of the system being carried out. |
218 | */ | 220 | */ |
219 | static int pm_op(struct device *dev, | 221 | static pm_callback_t pm_op(const struct dev_pm_ops *ops, pm_message_t state) |
220 | const struct dev_pm_ops *ops, | ||
221 | pm_message_t state) | ||
222 | { | 222 | { |
223 | int error = 0; | ||
224 | ktime_t calltime; | ||
225 | |||
226 | calltime = initcall_debug_start(dev); | ||
227 | |||
228 | switch (state.event) { | 223 | switch (state.event) { |
229 | #ifdef CONFIG_SUSPEND | 224 | #ifdef CONFIG_SUSPEND |
230 | case PM_EVENT_SUSPEND: | 225 | case PM_EVENT_SUSPEND: |
231 | if (ops->suspend) { | 226 | return ops->suspend; |
232 | error = ops->suspend(dev); | ||
233 | suspend_report_result(ops->suspend, error); | ||
234 | } | ||
235 | break; | ||
236 | case PM_EVENT_RESUME: | 227 | case PM_EVENT_RESUME: |
237 | if (ops->resume) { | 228 | return ops->resume; |
238 | error = ops->resume(dev); | ||
239 | suspend_report_result(ops->resume, error); | ||
240 | } | ||
241 | break; | ||
242 | #endif /* CONFIG_SUSPEND */ | 229 | #endif /* CONFIG_SUSPEND */ |
243 | #ifdef CONFIG_HIBERNATE_CALLBACKS | 230 | #ifdef CONFIG_HIBERNATE_CALLBACKS |
244 | case PM_EVENT_FREEZE: | 231 | case PM_EVENT_FREEZE: |
245 | case PM_EVENT_QUIESCE: | 232 | case PM_EVENT_QUIESCE: |
246 | if (ops->freeze) { | 233 | return ops->freeze; |
247 | error = ops->freeze(dev); | ||
248 | suspend_report_result(ops->freeze, error); | ||
249 | } | ||
250 | break; | ||
251 | case PM_EVENT_HIBERNATE: | 234 | case PM_EVENT_HIBERNATE: |
252 | if (ops->poweroff) { | 235 | return ops->poweroff; |
253 | error = ops->poweroff(dev); | ||
254 | suspend_report_result(ops->poweroff, error); | ||
255 | } | ||
256 | break; | ||
257 | case PM_EVENT_THAW: | 236 | case PM_EVENT_THAW: |
258 | case PM_EVENT_RECOVER: | 237 | case PM_EVENT_RECOVER: |
259 | if (ops->thaw) { | 238 | return ops->thaw; |
260 | error = ops->thaw(dev); | ||
261 | suspend_report_result(ops->thaw, error); | ||
262 | } | ||
263 | break; | 239 | break; |
264 | case PM_EVENT_RESTORE: | 240 | case PM_EVENT_RESTORE: |
265 | if (ops->restore) { | 241 | return ops->restore; |
266 | error = ops->restore(dev); | ||
267 | suspend_report_result(ops->restore, error); | ||
268 | } | ||
269 | break; | ||
270 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ | 242 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ |
271 | default: | ||
272 | error = -EINVAL; | ||
273 | } | 243 | } |
274 | 244 | ||
275 | initcall_debug_report(dev, calltime, error); | 245 | return NULL; |
276 | |||
277 | return error; | ||
278 | } | 246 | } |
279 | 247 | ||
280 | /** | 248 | /** |
281 | * pm_noirq_op - Execute the PM operation appropriate for given PM event. | 249 | * pm_noirq_op - Return the PM operation appropriate for given PM event. |
282 | * @dev: Device to handle. | ||
283 | * @ops: PM operations to choose from. | 250 | * @ops: PM operations to choose from. |
284 | * @state: PM transition of the system being carried out. | 251 | * @state: PM transition of the system being carried out. |
285 | * | 252 | * |
286 | * The driver of @dev will not receive interrupts while this function is being | 253 | * The driver of @dev will not receive interrupts while this function is being |
287 | * executed. | 254 | * executed. |
288 | */ | 255 | */ |
289 | static int pm_noirq_op(struct device *dev, | 256 | static pm_callback_t pm_noirq_op(const struct dev_pm_ops *ops, pm_message_t state) |
290 | const struct dev_pm_ops *ops, | ||
291 | pm_message_t state) | ||
292 | { | 257 | { |
293 | int error = 0; | ||
294 | ktime_t calltime = ktime_set(0, 0), delta, rettime; | ||
295 | |||
296 | if (initcall_debug) { | ||
297 | pr_info("calling %s+ @ %i, parent: %s\n", | ||
298 | dev_name(dev), task_pid_nr(current), | ||
299 | dev->parent ? dev_name(dev->parent) : "none"); | ||
300 | calltime = ktime_get(); | ||
301 | } | ||
302 | |||
303 | switch (state.event) { | 258 | switch (state.event) { |
304 | #ifdef CONFIG_SUSPEND | 259 | #ifdef CONFIG_SUSPEND |
305 | case PM_EVENT_SUSPEND: | 260 | case PM_EVENT_SUSPEND: |
306 | if (ops->suspend_noirq) { | 261 | return ops->suspend_noirq; |
307 | error = ops->suspend_noirq(dev); | ||
308 | suspend_report_result(ops->suspend_noirq, error); | ||
309 | } | ||
310 | break; | ||
311 | case PM_EVENT_RESUME: | 262 | case PM_EVENT_RESUME: |
312 | if (ops->resume_noirq) { | 263 | return ops->resume_noirq; |
313 | error = ops->resume_noirq(dev); | ||
314 | suspend_report_result(ops->resume_noirq, error); | ||
315 | } | ||
316 | break; | ||
317 | #endif /* CONFIG_SUSPEND */ | 264 | #endif /* CONFIG_SUSPEND */ |
318 | #ifdef CONFIG_HIBERNATE_CALLBACKS | 265 | #ifdef CONFIG_HIBERNATE_CALLBACKS |
319 | case PM_EVENT_FREEZE: | 266 | case PM_EVENT_FREEZE: |
320 | case PM_EVENT_QUIESCE: | 267 | case PM_EVENT_QUIESCE: |
321 | if (ops->freeze_noirq) { | 268 | return ops->freeze_noirq; |
322 | error = ops->freeze_noirq(dev); | ||
323 | suspend_report_result(ops->freeze_noirq, error); | ||
324 | } | ||
325 | break; | ||
326 | case PM_EVENT_HIBERNATE: | 269 | case PM_EVENT_HIBERNATE: |
327 | if (ops->poweroff_noirq) { | 270 | return ops->poweroff_noirq; |
328 | error = ops->poweroff_noirq(dev); | ||
329 | suspend_report_result(ops->poweroff_noirq, error); | ||
330 | } | ||
331 | break; | ||
332 | case PM_EVENT_THAW: | 271 | case PM_EVENT_THAW: |
333 | case PM_EVENT_RECOVER: | 272 | case PM_EVENT_RECOVER: |
334 | if (ops->thaw_noirq) { | 273 | return ops->thaw_noirq; |
335 | error = ops->thaw_noirq(dev); | ||
336 | suspend_report_result(ops->thaw_noirq, error); | ||
337 | } | ||
338 | break; | ||
339 | case PM_EVENT_RESTORE: | 274 | case PM_EVENT_RESTORE: |
340 | if (ops->restore_noirq) { | 275 | return ops->restore_noirq; |
341 | error = ops->restore_noirq(dev); | ||
342 | suspend_report_result(ops->restore_noirq, error); | ||
343 | } | ||
344 | break; | ||
345 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ | 276 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ |
346 | default: | ||
347 | error = -EINVAL; | ||
348 | } | ||
349 | |||
350 | if (initcall_debug) { | ||
351 | rettime = ktime_get(); | ||
352 | delta = ktime_sub(rettime, calltime); | ||
353 | printk("initcall %s_i+ returned %d after %Ld usecs\n", | ||
354 | dev_name(dev), error, | ||
355 | (unsigned long long)ktime_to_ns(delta) >> 10); | ||
356 | } | 277 | } |
357 | 278 | ||
358 | return error; | 279 | return NULL; |
359 | } | 280 | } |
360 | 281 | ||
361 | static char *pm_verb(int event) | 282 | static char *pm_verb(int event) |
@@ -413,6 +334,26 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) | |||
413 | usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); | 334 | usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); |
414 | } | 335 | } |
415 | 336 | ||
337 | static int dpm_run_callback(pm_callback_t cb, struct device *dev, | ||
338 | pm_message_t state, char *info) | ||
339 | { | ||
340 | ktime_t calltime; | ||
341 | int error; | ||
342 | |||
343 | if (!cb) | ||
344 | return 0; | ||
345 | |||
346 | calltime = initcall_debug_start(dev); | ||
347 | |||
348 | pm_dev_dbg(dev, state, info); | ||
349 | error = cb(dev); | ||
350 | suspend_report_result(cb, error); | ||
351 | |||
352 | initcall_debug_report(dev, calltime, error); | ||
353 | |||
354 | return error; | ||
355 | } | ||
356 | |||
416 | /*------------------------- Resume routines -------------------------*/ | 357 | /*------------------------- Resume routines -------------------------*/ |
417 | 358 | ||
418 | /** | 359 | /** |
@@ -425,25 +366,34 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) | |||
425 | */ | 366 | */ |
426 | static int device_resume_noirq(struct device *dev, pm_message_t state) | 367 | static int device_resume_noirq(struct device *dev, pm_message_t state) |
427 | { | 368 | { |
369 | pm_callback_t callback = NULL; | ||
370 | char *info = NULL; | ||
428 | int error = 0; | 371 | int error = 0; |
429 | 372 | ||
430 | TRACE_DEVICE(dev); | 373 | TRACE_DEVICE(dev); |
431 | TRACE_RESUME(0); | 374 | TRACE_RESUME(0); |
432 | 375 | ||
433 | if (dev->pm_domain) { | 376 | if (dev->pm_domain) { |
434 | pm_dev_dbg(dev, state, "EARLY power domain "); | 377 | info = "EARLY power domain "; |
435 | error = pm_noirq_op(dev, &dev->pm_domain->ops, state); | 378 | callback = pm_noirq_op(&dev->pm_domain->ops, state); |
436 | } else if (dev->type && dev->type->pm) { | 379 | } else if (dev->type && dev->type->pm) { |
437 | pm_dev_dbg(dev, state, "EARLY type "); | 380 | info = "EARLY type "; |
438 | error = pm_noirq_op(dev, dev->type->pm, state); | 381 | callback = pm_noirq_op(dev->type->pm, state); |
439 | } else if (dev->class && dev->class->pm) { | 382 | } else if (dev->class && dev->class->pm) { |
440 | pm_dev_dbg(dev, state, "EARLY class "); | 383 | info = "EARLY class "; |
441 | error = pm_noirq_op(dev, dev->class->pm, state); | 384 | callback = pm_noirq_op(dev->class->pm, state); |
442 | } else if (dev->bus && dev->bus->pm) { | 385 | } else if (dev->bus && dev->bus->pm) { |
443 | pm_dev_dbg(dev, state, "EARLY "); | 386 | info = "EARLY bus "; |
444 | error = pm_noirq_op(dev, dev->bus->pm, state); | 387 | callback = pm_noirq_op(dev->bus->pm, state); |
445 | } | 388 | } |
446 | 389 | ||
390 | if (!callback && dev->driver && dev->driver->pm) { | ||
391 | info = "EARLY driver "; | ||
392 | callback = pm_noirq_op(dev->driver->pm, state); | ||
393 | } | ||
394 | |||
395 | error = dpm_run_callback(callback, dev, state, info); | ||
396 | |||
447 | TRACE_RESUME(error); | 397 | TRACE_RESUME(error); |
448 | return error; | 398 | return error; |
449 | } | 399 | } |
@@ -486,26 +436,6 @@ void dpm_resume_noirq(pm_message_t state) | |||
486 | EXPORT_SYMBOL_GPL(dpm_resume_noirq); | 436 | EXPORT_SYMBOL_GPL(dpm_resume_noirq); |
487 | 437 | ||
488 | /** | 438 | /** |
489 | * legacy_resume - Execute a legacy (bus or class) resume callback for device. | ||
490 | * @dev: Device to resume. | ||
491 | * @cb: Resume callback to execute. | ||
492 | */ | ||
493 | static int legacy_resume(struct device *dev, int (*cb)(struct device *dev)) | ||
494 | { | ||
495 | int error; | ||
496 | ktime_t calltime; | ||
497 | |||
498 | calltime = initcall_debug_start(dev); | ||
499 | |||
500 | error = cb(dev); | ||
501 | suspend_report_result(cb, error); | ||
502 | |||
503 | initcall_debug_report(dev, calltime, error); | ||
504 | |||
505 | return error; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * device_resume - Execute "resume" callbacks for given device. | 439 | * device_resume - Execute "resume" callbacks for given device. |
510 | * @dev: Device to handle. | 440 | * @dev: Device to handle. |
511 | * @state: PM transition of the system being carried out. | 441 | * @state: PM transition of the system being carried out. |
@@ -513,6 +443,8 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev)) | |||
513 | */ | 443 | */ |
514 | static int device_resume(struct device *dev, pm_message_t state, bool async) | 444 | static int device_resume(struct device *dev, pm_message_t state, bool async) |
515 | { | 445 | { |
446 | pm_callback_t callback = NULL; | ||
447 | char *info = NULL; | ||
516 | int error = 0; | 448 | int error = 0; |
517 | bool put = false; | 449 | bool put = false; |
518 | 450 | ||
@@ -535,40 +467,48 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
535 | put = true; | 467 | put = true; |
536 | 468 | ||
537 | if (dev->pm_domain) { | 469 | if (dev->pm_domain) { |
538 | pm_dev_dbg(dev, state, "power domain "); | 470 | info = "power domain "; |
539 | error = pm_op(dev, &dev->pm_domain->ops, state); | 471 | callback = pm_op(&dev->pm_domain->ops, state); |
540 | goto End; | 472 | goto Driver; |
541 | } | 473 | } |
542 | 474 | ||
543 | if (dev->type && dev->type->pm) { | 475 | if (dev->type && dev->type->pm) { |
544 | pm_dev_dbg(dev, state, "type "); | 476 | info = "type "; |
545 | error = pm_op(dev, dev->type->pm, state); | 477 | callback = pm_op(dev->type->pm, state); |
546 | goto End; | 478 | goto Driver; |
547 | } | 479 | } |
548 | 480 | ||
549 | if (dev->class) { | 481 | if (dev->class) { |
550 | if (dev->class->pm) { | 482 | if (dev->class->pm) { |
551 | pm_dev_dbg(dev, state, "class "); | 483 | info = "class "; |
552 | error = pm_op(dev, dev->class->pm, state); | 484 | callback = pm_op(dev->class->pm, state); |
553 | goto End; | 485 | goto Driver; |
554 | } else if (dev->class->resume) { | 486 | } else if (dev->class->resume) { |
555 | pm_dev_dbg(dev, state, "legacy class "); | 487 | info = "legacy class "; |
556 | error = legacy_resume(dev, dev->class->resume); | 488 | callback = dev->class->resume; |
557 | goto End; | 489 | goto End; |
558 | } | 490 | } |
559 | } | 491 | } |
560 | 492 | ||
561 | if (dev->bus) { | 493 | if (dev->bus) { |
562 | if (dev->bus->pm) { | 494 | if (dev->bus->pm) { |
563 | pm_dev_dbg(dev, state, ""); | 495 | info = "bus "; |
564 | error = pm_op(dev, dev->bus->pm, state); | 496 | callback = pm_op(dev->bus->pm, state); |
565 | } else if (dev->bus->resume) { | 497 | } else if (dev->bus->resume) { |
566 | pm_dev_dbg(dev, state, "legacy "); | 498 | info = "legacy bus "; |
567 | error = legacy_resume(dev, dev->bus->resume); | 499 | callback = dev->bus->resume; |
500 | goto End; | ||
568 | } | 501 | } |
569 | } | 502 | } |
570 | 503 | ||
504 | Driver: | ||
505 | if (!callback && dev->driver && dev->driver->pm) { | ||
506 | info = "driver "; | ||
507 | callback = pm_op(dev->driver->pm, state); | ||
508 | } | ||
509 | |||
571 | End: | 510 | End: |
511 | error = dpm_run_callback(callback, dev, state, info); | ||
572 | dev->power.is_suspended = false; | 512 | dev->power.is_suspended = false; |
573 | 513 | ||
574 | Unlock: | 514 | Unlock: |
@@ -660,24 +600,33 @@ void dpm_resume(pm_message_t state) | |||
660 | */ | 600 | */ |
661 | static void device_complete(struct device *dev, pm_message_t state) | 601 | static void device_complete(struct device *dev, pm_message_t state) |
662 | { | 602 | { |
603 | void (*callback)(struct device *) = NULL; | ||
604 | char *info = NULL; | ||
605 | |||
663 | device_lock(dev); | 606 | device_lock(dev); |
664 | 607 | ||
665 | if (dev->pm_domain) { | 608 | if (dev->pm_domain) { |
666 | pm_dev_dbg(dev, state, "completing power domain "); | 609 | info = "completing power domain "; |
667 | if (dev->pm_domain->ops.complete) | 610 | callback = dev->pm_domain->ops.complete; |
668 | dev->pm_domain->ops.complete(dev); | ||
669 | } else if (dev->type && dev->type->pm) { | 611 | } else if (dev->type && dev->type->pm) { |
670 | pm_dev_dbg(dev, state, "completing type "); | 612 | info = "completing type "; |
671 | if (dev->type->pm->complete) | 613 | callback = dev->type->pm->complete; |
672 | dev->type->pm->complete(dev); | ||
673 | } else if (dev->class && dev->class->pm) { | 614 | } else if (dev->class && dev->class->pm) { |
674 | pm_dev_dbg(dev, state, "completing class "); | 615 | info = "completing class "; |
675 | if (dev->class->pm->complete) | 616 | callback = dev->class->pm->complete; |
676 | dev->class->pm->complete(dev); | ||
677 | } else if (dev->bus && dev->bus->pm) { | 617 | } else if (dev->bus && dev->bus->pm) { |
678 | pm_dev_dbg(dev, state, "completing "); | 618 | info = "completing bus "; |
679 | if (dev->bus->pm->complete) | 619 | callback = dev->bus->pm->complete; |
680 | dev->bus->pm->complete(dev); | 620 | } |
621 | |||
622 | if (!callback && dev->driver && dev->driver->pm) { | ||
623 | info = "completing driver "; | ||
624 | callback = dev->driver->pm->complete; | ||
625 | } | ||
626 | |||
627 | if (callback) { | ||
628 | pm_dev_dbg(dev, state, info); | ||
629 | callback(dev); | ||
681 | } | 630 | } |
682 | 631 | ||
683 | device_unlock(dev); | 632 | device_unlock(dev); |
@@ -763,31 +712,29 @@ static pm_message_t resume_event(pm_message_t sleep_state) | |||
763 | */ | 712 | */ |
764 | static int device_suspend_noirq(struct device *dev, pm_message_t state) | 713 | static int device_suspend_noirq(struct device *dev, pm_message_t state) |
765 | { | 714 | { |
766 | int error; | 715 | pm_callback_t callback = NULL; |
716 | char *info = NULL; | ||
767 | 717 | ||
768 | if (dev->pm_domain) { | 718 | if (dev->pm_domain) { |
769 | pm_dev_dbg(dev, state, "LATE power domain "); | 719 | info = "LATE power domain "; |
770 | error = pm_noirq_op(dev, &dev->pm_domain->ops, state); | 720 | callback = pm_noirq_op(&dev->pm_domain->ops, state); |
771 | if (error) | ||
772 | return error; | ||
773 | } else if (dev->type && dev->type->pm) { | 721 | } else if (dev->type && dev->type->pm) { |
774 | pm_dev_dbg(dev, state, "LATE type "); | 722 | info = "LATE type "; |
775 | error = pm_noirq_op(dev, dev->type->pm, state); | 723 | callback = pm_noirq_op(dev->type->pm, state); |
776 | if (error) | ||
777 | return error; | ||
778 | } else if (dev->class && dev->class->pm) { | 724 | } else if (dev->class && dev->class->pm) { |
779 | pm_dev_dbg(dev, state, "LATE class "); | 725 | info = "LATE class "; |
780 | error = pm_noirq_op(dev, dev->class->pm, state); | 726 | callback = pm_noirq_op(dev->class->pm, state); |
781 | if (error) | ||
782 | return error; | ||
783 | } else if (dev->bus && dev->bus->pm) { | 727 | } else if (dev->bus && dev->bus->pm) { |
784 | pm_dev_dbg(dev, state, "LATE "); | 728 | info = "LATE bus "; |
785 | error = pm_noirq_op(dev, dev->bus->pm, state); | 729 | callback = pm_noirq_op(dev->bus->pm, state); |
786 | if (error) | ||
787 | return error; | ||
788 | } | 730 | } |
789 | 731 | ||
790 | return 0; | 732 | if (!callback && dev->driver && dev->driver->pm) { |
733 | info = "LATE driver "; | ||
734 | callback = pm_noirq_op(dev->driver->pm, state); | ||
735 | } | ||
736 | |||
737 | return dpm_run_callback(callback, dev, state, info); | ||
791 | } | 738 | } |
792 | 739 | ||
793 | /** | 740 | /** |
@@ -864,6 +811,8 @@ static int legacy_suspend(struct device *dev, pm_message_t state, | |||
864 | */ | 811 | */ |
865 | static int __device_suspend(struct device *dev, pm_message_t state, bool async) | 812 | static int __device_suspend(struct device *dev, pm_message_t state, bool async) |
866 | { | 813 | { |
814 | pm_callback_t callback = NULL; | ||
815 | char *info = NULL; | ||
867 | int error = 0; | 816 | int error = 0; |
868 | 817 | ||
869 | dpm_wait_for_children(dev, async); | 818 | dpm_wait_for_children(dev, async); |
@@ -884,22 +833,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
884 | device_lock(dev); | 833 | device_lock(dev); |
885 | 834 | ||
886 | if (dev->pm_domain) { | 835 | if (dev->pm_domain) { |
887 | pm_dev_dbg(dev, state, "power domain "); | 836 | info = "power domain "; |
888 | error = pm_op(dev, &dev->pm_domain->ops, state); | 837 | callback = pm_op(&dev->pm_domain->ops, state); |
889 | goto End; | 838 | goto Run; |
890 | } | 839 | } |
891 | 840 | ||
892 | if (dev->type && dev->type->pm) { | 841 | if (dev->type && dev->type->pm) { |
893 | pm_dev_dbg(dev, state, "type "); | 842 | info = "type "; |
894 | error = pm_op(dev, dev->type->pm, state); | 843 | callback = pm_op(dev->type->pm, state); |
895 | goto End; | 844 | goto Run; |
896 | } | 845 | } |
897 | 846 | ||
898 | if (dev->class) { | 847 | if (dev->class) { |
899 | if (dev->class->pm) { | 848 | if (dev->class->pm) { |
900 | pm_dev_dbg(dev, state, "class "); | 849 | info = "class "; |
901 | error = pm_op(dev, dev->class->pm, state); | 850 | callback = pm_op(dev->class->pm, state); |
902 | goto End; | 851 | goto Run; |
903 | } else if (dev->class->suspend) { | 852 | } else if (dev->class->suspend) { |
904 | pm_dev_dbg(dev, state, "legacy class "); | 853 | pm_dev_dbg(dev, state, "legacy class "); |
905 | error = legacy_suspend(dev, state, dev->class->suspend); | 854 | error = legacy_suspend(dev, state, dev->class->suspend); |
@@ -909,14 +858,23 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
909 | 858 | ||
910 | if (dev->bus) { | 859 | if (dev->bus) { |
911 | if (dev->bus->pm) { | 860 | if (dev->bus->pm) { |
912 | pm_dev_dbg(dev, state, ""); | 861 | info = "bus "; |
913 | error = pm_op(dev, dev->bus->pm, state); | 862 | callback = pm_op(dev->bus->pm, state); |
914 | } else if (dev->bus->suspend) { | 863 | } else if (dev->bus->suspend) { |
915 | pm_dev_dbg(dev, state, "legacy "); | 864 | pm_dev_dbg(dev, state, "legacy bus "); |
916 | error = legacy_suspend(dev, state, dev->bus->suspend); | 865 | error = legacy_suspend(dev, state, dev->bus->suspend); |
866 | goto End; | ||
917 | } | 867 | } |
918 | } | 868 | } |
919 | 869 | ||
870 | Run: | ||
871 | if (!callback && dev->driver && dev->driver->pm) { | ||
872 | info = "driver "; | ||
873 | callback = pm_op(dev->driver->pm, state); | ||
874 | } | ||
875 | |||
876 | error = dpm_run_callback(callback, dev, state, info); | ||
877 | |||
920 | End: | 878 | End: |
921 | if (!error) { | 879 | if (!error) { |
922 | dev->power.is_suspended = true; | 880 | dev->power.is_suspended = true; |
@@ -1022,6 +980,8 @@ int dpm_suspend(pm_message_t state) | |||
1022 | */ | 980 | */ |
1023 | static int device_prepare(struct device *dev, pm_message_t state) | 981 | static int device_prepare(struct device *dev, pm_message_t state) |
1024 | { | 982 | { |
983 | int (*callback)(struct device *) = NULL; | ||
984 | char *info = NULL; | ||
1025 | int error = 0; | 985 | int error = 0; |
1026 | 986 | ||
1027 | device_lock(dev); | 987 | device_lock(dev); |
@@ -1029,34 +989,29 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
1029 | dev->power.wakeup_path = device_may_wakeup(dev); | 989 | dev->power.wakeup_path = device_may_wakeup(dev); |
1030 | 990 | ||
1031 | if (dev->pm_domain) { | 991 | if (dev->pm_domain) { |
1032 | pm_dev_dbg(dev, state, "preparing power domain "); | 992 | info = "preparing power domain "; |
1033 | if (dev->pm_domain->ops.prepare) | 993 | callback = dev->pm_domain->ops.prepare; |
1034 | error = dev->pm_domain->ops.prepare(dev); | ||
1035 | suspend_report_result(dev->pm_domain->ops.prepare, error); | ||
1036 | if (error) | ||
1037 | goto End; | ||
1038 | } else if (dev->type && dev->type->pm) { | 994 | } else if (dev->type && dev->type->pm) { |
1039 | pm_dev_dbg(dev, state, "preparing type "); | 995 | info = "preparing type "; |
1040 | if (dev->type->pm->prepare) | 996 | callback = dev->type->pm->prepare; |
1041 | error = dev->type->pm->prepare(dev); | ||
1042 | suspend_report_result(dev->type->pm->prepare, error); | ||
1043 | if (error) | ||
1044 | goto End; | ||
1045 | } else if (dev->class && dev->class->pm) { | 997 | } else if (dev->class && dev->class->pm) { |
1046 | pm_dev_dbg(dev, state, "preparing class "); | 998 | info = "preparing class "; |
1047 | if (dev->class->pm->prepare) | 999 | callback = dev->class->pm->prepare; |
1048 | error = dev->class->pm->prepare(dev); | ||
1049 | suspend_report_result(dev->class->pm->prepare, error); | ||
1050 | if (error) | ||
1051 | goto End; | ||
1052 | } else if (dev->bus && dev->bus->pm) { | 1000 | } else if (dev->bus && dev->bus->pm) { |
1053 | pm_dev_dbg(dev, state, "preparing "); | 1001 | info = "preparing bus "; |
1054 | if (dev->bus->pm->prepare) | 1002 | callback = dev->bus->pm->prepare; |
1055 | error = dev->bus->pm->prepare(dev); | 1003 | } |
1056 | suspend_report_result(dev->bus->pm->prepare, error); | 1004 | |
1005 | if (!callback && dev->driver && dev->driver->pm) { | ||
1006 | info = "preparing driver "; | ||
1007 | callback = dev->driver->pm->prepare; | ||
1008 | } | ||
1009 | |||
1010 | if (callback) { | ||
1011 | error = callback(dev); | ||
1012 | suspend_report_result(callback, error); | ||
1057 | } | 1013 | } |
1058 | 1014 | ||
1059 | End: | ||
1060 | device_unlock(dev); | 1015 | device_unlock(dev); |
1061 | 1016 | ||
1062 | return error; | 1017 | return error; |
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 86de6c50fc41..c5d358837461 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c | |||
@@ -47,21 +47,29 @@ static DEFINE_MUTEX(dev_pm_qos_mtx); | |||
47 | static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); | 47 | static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); |
48 | 48 | ||
49 | /** | 49 | /** |
50 | * dev_pm_qos_read_value - Get PM QoS constraint for a given device. | 50 | * __dev_pm_qos_read_value - Get PM QoS constraint for a given device. |
51 | * @dev: Device to get the PM QoS constraint value for. | ||
52 | * | ||
53 | * This routine must be called with dev->power.lock held. | ||
54 | */ | ||
55 | s32 __dev_pm_qos_read_value(struct device *dev) | ||
56 | { | ||
57 | struct pm_qos_constraints *c = dev->power.constraints; | ||
58 | |||
59 | return c ? pm_qos_read_value(c) : 0; | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked). | ||
51 | * @dev: Device to get the PM QoS constraint value for. | 64 | * @dev: Device to get the PM QoS constraint value for. |
52 | */ | 65 | */ |
53 | s32 dev_pm_qos_read_value(struct device *dev) | 66 | s32 dev_pm_qos_read_value(struct device *dev) |
54 | { | 67 | { |
55 | struct pm_qos_constraints *c; | ||
56 | unsigned long flags; | 68 | unsigned long flags; |
57 | s32 ret = 0; | 69 | s32 ret; |
58 | 70 | ||
59 | spin_lock_irqsave(&dev->power.lock, flags); | 71 | spin_lock_irqsave(&dev->power.lock, flags); |
60 | 72 | ret = __dev_pm_qos_read_value(dev); | |
61 | c = dev->power.constraints; | ||
62 | if (c) | ||
63 | ret = pm_qos_read_value(c); | ||
64 | |||
65 | spin_unlock_irqrestore(&dev->power.lock, flags); | 73 | spin_unlock_irqrestore(&dev->power.lock, flags); |
66 | 74 | ||
67 | return ret; | 75 | return ret; |
@@ -412,3 +420,28 @@ int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier) | |||
412 | return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier); | 420 | return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier); |
413 | } | 421 | } |
414 | EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier); | 422 | EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier); |
423 | |||
424 | /** | ||
425 | * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor. | ||
426 | * @dev: Device whose ancestor to add the request for. | ||
427 | * @req: Pointer to the preallocated handle. | ||
428 | * @value: Constraint latency value. | ||
429 | */ | ||
430 | int dev_pm_qos_add_ancestor_request(struct device *dev, | ||
431 | struct dev_pm_qos_request *req, s32 value) | ||
432 | { | ||
433 | struct device *ancestor = dev->parent; | ||
434 | int error = -ENODEV; | ||
435 | |||
436 | while (ancestor && !ancestor->power.ignore_children) | ||
437 | ancestor = ancestor->parent; | ||
438 | |||
439 | if (ancestor) | ||
440 | error = dev_pm_qos_add_request(ancestor, req, value); | ||
441 | |||
442 | if (error) | ||
443 | req->dev = NULL; | ||
444 | |||
445 | return error; | ||
446 | } | ||
447 | EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); | ||
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 8c78443bca8f..541f821d4ea6 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -250,6 +250,9 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
250 | else | 250 | else |
251 | callback = NULL; | 251 | callback = NULL; |
252 | 252 | ||
253 | if (!callback && dev->driver && dev->driver->pm) | ||
254 | callback = dev->driver->pm->runtime_idle; | ||
255 | |||
253 | if (callback) | 256 | if (callback) |
254 | __rpm_callback(callback, dev); | 257 | __rpm_callback(callback, dev); |
255 | 258 | ||
@@ -279,6 +282,47 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) | |||
279 | return retval != -EACCES ? retval : -EIO; | 282 | return retval != -EACCES ? retval : -EIO; |
280 | } | 283 | } |
281 | 284 | ||
285 | struct rpm_qos_data { | ||
286 | ktime_t time_now; | ||
287 | s64 constraint_ns; | ||
288 | }; | ||
289 | |||
290 | /** | ||
291 | * rpm_update_qos_constraint - Update a given PM QoS constraint data. | ||
292 | * @dev: Device whose timing data to use. | ||
293 | * @data: PM QoS constraint data to update. | ||
294 | * | ||
295 | * Use the suspend timing data of @dev to update PM QoS constraint data pointed | ||
296 | * to by @data. | ||
297 | */ | ||
298 | static int rpm_update_qos_constraint(struct device *dev, void *data) | ||
299 | { | ||
300 | struct rpm_qos_data *qos = data; | ||
301 | unsigned long flags; | ||
302 | s64 delta_ns; | ||
303 | int ret = 0; | ||
304 | |||
305 | spin_lock_irqsave(&dev->power.lock, flags); | ||
306 | |||
307 | if (dev->power.max_time_suspended_ns < 0) | ||
308 | goto out; | ||
309 | |||
310 | delta_ns = dev->power.max_time_suspended_ns - | ||
311 | ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time)); | ||
312 | if (delta_ns <= 0) { | ||
313 | ret = -EBUSY; | ||
314 | goto out; | ||
315 | } | ||
316 | |||
317 | if (qos->constraint_ns > delta_ns || qos->constraint_ns == 0) | ||
318 | qos->constraint_ns = delta_ns; | ||
319 | |||
320 | out: | ||
321 | spin_unlock_irqrestore(&dev->power.lock, flags); | ||
322 | |||
323 | return ret; | ||
324 | } | ||
325 | |||
282 | /** | 326 | /** |
283 | * rpm_suspend - Carry out runtime suspend of given device. | 327 | * rpm_suspend - Carry out runtime suspend of given device. |
284 | * @dev: Device to suspend. | 328 | * @dev: Device to suspend. |
@@ -305,6 +349,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) | |||
305 | { | 349 | { |
306 | int (*callback)(struct device *); | 350 | int (*callback)(struct device *); |
307 | struct device *parent = NULL; | 351 | struct device *parent = NULL; |
352 | struct rpm_qos_data qos; | ||
308 | int retval; | 353 | int retval; |
309 | 354 | ||
310 | trace_rpm_suspend(dev, rpmflags); | 355 | trace_rpm_suspend(dev, rpmflags); |
@@ -400,8 +445,38 @@ static int rpm_suspend(struct device *dev, int rpmflags) | |||
400 | goto out; | 445 | goto out; |
401 | } | 446 | } |
402 | 447 | ||
448 | qos.constraint_ns = __dev_pm_qos_read_value(dev); | ||
449 | if (qos.constraint_ns < 0) { | ||
450 | /* Negative constraint means "never suspend". */ | ||
451 | retval = -EPERM; | ||
452 | goto out; | ||
453 | } | ||
454 | qos.constraint_ns *= NSEC_PER_USEC; | ||
455 | qos.time_now = ktime_get(); | ||
456 | |||
403 | __update_runtime_status(dev, RPM_SUSPENDING); | 457 | __update_runtime_status(dev, RPM_SUSPENDING); |
404 | 458 | ||
459 | if (!dev->power.ignore_children) { | ||
460 | if (dev->power.irq_safe) | ||
461 | spin_unlock(&dev->power.lock); | ||
462 | else | ||
463 | spin_unlock_irq(&dev->power.lock); | ||
464 | |||
465 | retval = device_for_each_child(dev, &qos, | ||
466 | rpm_update_qos_constraint); | ||
467 | |||
468 | if (dev->power.irq_safe) | ||
469 | spin_lock(&dev->power.lock); | ||
470 | else | ||
471 | spin_lock_irq(&dev->power.lock); | ||
472 | |||
473 | if (retval) | ||
474 | goto fail; | ||
475 | } | ||
476 | |||
477 | dev->power.suspend_time = qos.time_now; | ||
478 | dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1; | ||
479 | |||
405 | if (dev->pm_domain) | 480 | if (dev->pm_domain) |
406 | callback = dev->pm_domain->ops.runtime_suspend; | 481 | callback = dev->pm_domain->ops.runtime_suspend; |
407 | else if (dev->type && dev->type->pm) | 482 | else if (dev->type && dev->type->pm) |
@@ -413,28 +488,13 @@ static int rpm_suspend(struct device *dev, int rpmflags) | |||
413 | else | 488 | else |
414 | callback = NULL; | 489 | callback = NULL; |
415 | 490 | ||
491 | if (!callback && dev->driver && dev->driver->pm) | ||
492 | callback = dev->driver->pm->runtime_suspend; | ||
493 | |||
416 | retval = rpm_callback(callback, dev); | 494 | retval = rpm_callback(callback, dev); |
417 | if (retval) { | 495 | if (retval) |
418 | __update_runtime_status(dev, RPM_ACTIVE); | 496 | goto fail; |
419 | dev->power.deferred_resume = false; | ||
420 | if (retval == -EAGAIN || retval == -EBUSY) { | ||
421 | dev->power.runtime_error = 0; | ||
422 | 497 | ||
423 | /* | ||
424 | * If the callback routine failed an autosuspend, and | ||
425 | * if the last_busy time has been updated so that there | ||
426 | * is a new autosuspend expiration time, automatically | ||
427 | * reschedule another autosuspend. | ||
428 | */ | ||
429 | if ((rpmflags & RPM_AUTO) && | ||
430 | pm_runtime_autosuspend_expiration(dev) != 0) | ||
431 | goto repeat; | ||
432 | } else { | ||
433 | pm_runtime_cancel_pending(dev); | ||
434 | } | ||
435 | wake_up_all(&dev->power.wait_queue); | ||
436 | goto out; | ||
437 | } | ||
438 | no_callback: | 498 | no_callback: |
439 | __update_runtime_status(dev, RPM_SUSPENDED); | 499 | __update_runtime_status(dev, RPM_SUSPENDED); |
440 | pm_runtime_deactivate_timer(dev); | 500 | pm_runtime_deactivate_timer(dev); |
@@ -466,6 +526,29 @@ static int rpm_suspend(struct device *dev, int rpmflags) | |||
466 | trace_rpm_return_int(dev, _THIS_IP_, retval); | 526 | trace_rpm_return_int(dev, _THIS_IP_, retval); |
467 | 527 | ||
468 | return retval; | 528 | return retval; |
529 | |||
530 | fail: | ||
531 | __update_runtime_status(dev, RPM_ACTIVE); | ||
532 | dev->power.suspend_time = ktime_set(0, 0); | ||
533 | dev->power.max_time_suspended_ns = -1; | ||
534 | dev->power.deferred_resume = false; | ||
535 | if (retval == -EAGAIN || retval == -EBUSY) { | ||
536 | dev->power.runtime_error = 0; | ||
537 | |||
538 | /* | ||
539 | * If the callback routine failed an autosuspend, and | ||
540 | * if the last_busy time has been updated so that there | ||
541 | * is a new autosuspend expiration time, automatically | ||
542 | * reschedule another autosuspend. | ||
543 | */ | ||
544 | if ((rpmflags & RPM_AUTO) && | ||
545 | pm_runtime_autosuspend_expiration(dev) != 0) | ||
546 | goto repeat; | ||
547 | } else { | ||
548 | pm_runtime_cancel_pending(dev); | ||
549 | } | ||
550 | wake_up_all(&dev->power.wait_queue); | ||
551 | goto out; | ||
469 | } | 552 | } |
470 | 553 | ||
471 | /** | 554 | /** |
@@ -620,6 +703,9 @@ static int rpm_resume(struct device *dev, int rpmflags) | |||
620 | if (dev->power.no_callbacks) | 703 | if (dev->power.no_callbacks) |
621 | goto no_callback; /* Assume success. */ | 704 | goto no_callback; /* Assume success. */ |
622 | 705 | ||
706 | dev->power.suspend_time = ktime_set(0, 0); | ||
707 | dev->power.max_time_suspended_ns = -1; | ||
708 | |||
623 | __update_runtime_status(dev, RPM_RESUMING); | 709 | __update_runtime_status(dev, RPM_RESUMING); |
624 | 710 | ||
625 | if (dev->pm_domain) | 711 | if (dev->pm_domain) |
@@ -633,6 +719,9 @@ static int rpm_resume(struct device *dev, int rpmflags) | |||
633 | else | 719 | else |
634 | callback = NULL; | 720 | callback = NULL; |
635 | 721 | ||
722 | if (!callback && dev->driver && dev->driver->pm) | ||
723 | callback = dev->driver->pm->runtime_resume; | ||
724 | |||
636 | retval = rpm_callback(callback, dev); | 725 | retval = rpm_callback(callback, dev); |
637 | if (retval) { | 726 | if (retval) { |
638 | __update_runtime_status(dev, RPM_SUSPENDED); | 727 | __update_runtime_status(dev, RPM_SUSPENDED); |
@@ -1279,6 +1368,9 @@ void pm_runtime_init(struct device *dev) | |||
1279 | setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn, | 1368 | setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn, |
1280 | (unsigned long)dev); | 1369 | (unsigned long)dev); |
1281 | 1370 | ||
1371 | dev->power.suspend_time = ktime_set(0, 0); | ||
1372 | dev->power.max_time_suspended_ns = -1; | ||
1373 | |||
1282 | init_waitqueue_head(&dev->power.wait_queue); | 1374 | init_waitqueue_head(&dev->power.wait_queue); |
1283 | } | 1375 | } |
1284 | 1376 | ||
@@ -1296,3 +1388,28 @@ void pm_runtime_remove(struct device *dev) | |||
1296 | if (dev->power.irq_safe && dev->parent) | 1388 | if (dev->power.irq_safe && dev->parent) |
1297 | pm_runtime_put_sync(dev->parent); | 1389 | pm_runtime_put_sync(dev->parent); |
1298 | } | 1390 | } |
1391 | |||
1392 | /** | ||
1393 | * pm_runtime_update_max_time_suspended - Update device's suspend time data. | ||
1394 | * @dev: Device to handle. | ||
1395 | * @delta_ns: Value to subtract from the device's max_time_suspended_ns field. | ||
1396 | * | ||
1397 | * Update the device's power.max_time_suspended_ns field by subtracting | ||
1398 | * @delta_ns from it. The resulting value of power.max_time_suspended_ns is | ||
1399 | * never negative. | ||
1400 | */ | ||
1401 | void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns) | ||
1402 | { | ||
1403 | unsigned long flags; | ||
1404 | |||
1405 | spin_lock_irqsave(&dev->power.lock, flags); | ||
1406 | |||
1407 | if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) { | ||
1408 | if (dev->power.max_time_suspended_ns > delta_ns) | ||
1409 | dev->power.max_time_suspended_ns -= delta_ns; | ||
1410 | else | ||
1411 | dev->power.max_time_suspended_ns = 0; | ||
1412 | } | ||
1413 | |||
1414 | spin_unlock_irqrestore(&dev->power.lock, flags); | ||
1415 | } | ||
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 9dff77bfe1e3..409f5ce78829 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
@@ -126,7 +126,7 @@ void sysdev_class_remove_file(struct sysdev_class *c, | |||
126 | } | 126 | } |
127 | EXPORT_SYMBOL_GPL(sysdev_class_remove_file); | 127 | EXPORT_SYMBOL_GPL(sysdev_class_remove_file); |
128 | 128 | ||
129 | static struct kset *system_kset; | 129 | extern struct kset *system_kset; |
130 | 130 | ||
131 | int sysdev_class_register(struct sysdev_class *cls) | 131 | int sysdev_class_register(struct sysdev_class *cls) |
132 | { | 132 | { |
@@ -331,14 +331,6 @@ void sysdev_unregister(struct sys_device *sysdev) | |||
331 | EXPORT_SYMBOL_GPL(sysdev_register); | 331 | EXPORT_SYMBOL_GPL(sysdev_register); |
332 | EXPORT_SYMBOL_GPL(sysdev_unregister); | 332 | EXPORT_SYMBOL_GPL(sysdev_unregister); |
333 | 333 | ||
334 | int __init system_bus_init(void) | ||
335 | { | ||
336 | system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); | ||
337 | if (!system_kset) | ||
338 | return -ENOMEM; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | #define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) | 334 | #define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) |
343 | 335 | ||
344 | ssize_t sysdev_store_ulong(struct sys_device *sysdev, | 336 | ssize_t sysdev_store_ulong(struct sys_device *sysdev, |
diff --git a/drivers/base/topology.c b/drivers/base/topology.c index f6f37a05a0c3..ae989c57cd5e 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | #include <linux/sysdev.h> | ||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
29 | #include <linux/cpu.h> | 28 | #include <linux/cpu.h> |
@@ -32,14 +31,14 @@ | |||
32 | #include <linux/topology.h> | 31 | #include <linux/topology.h> |
33 | 32 | ||
34 | #define define_one_ro_named(_name, _func) \ | 33 | #define define_one_ro_named(_name, _func) \ |
35 | static SYSDEV_ATTR(_name, 0444, _func, NULL) | 34 | static DEVICE_ATTR(_name, 0444, _func, NULL) |
36 | 35 | ||
37 | #define define_one_ro(_name) \ | 36 | #define define_one_ro(_name) \ |
38 | static SYSDEV_ATTR(_name, 0444, show_##_name, NULL) | 37 | static DEVICE_ATTR(_name, 0444, show_##_name, NULL) |
39 | 38 | ||
40 | #define define_id_show_func(name) \ | 39 | #define define_id_show_func(name) \ |
41 | static ssize_t show_##name(struct sys_device *dev, \ | 40 | static ssize_t show_##name(struct device *dev, \ |
42 | struct sysdev_attribute *attr, char *buf) \ | 41 | struct device_attribute *attr, char *buf) \ |
43 | { \ | 42 | { \ |
44 | unsigned int cpu = dev->id; \ | 43 | unsigned int cpu = dev->id; \ |
45 | return sprintf(buf, "%d\n", topology_##name(cpu)); \ | 44 | return sprintf(buf, "%d\n", topology_##name(cpu)); \ |
@@ -65,16 +64,16 @@ static ssize_t show_cpumap(int type, const struct cpumask *mask, char *buf) | |||
65 | 64 | ||
66 | #ifdef arch_provides_topology_pointers | 65 | #ifdef arch_provides_topology_pointers |
67 | #define define_siblings_show_map(name) \ | 66 | #define define_siblings_show_map(name) \ |
68 | static ssize_t show_##name(struct sys_device *dev, \ | 67 | static ssize_t show_##name(struct device *dev, \ |
69 | struct sysdev_attribute *attr, char *buf) \ | 68 | struct device_attribute *attr, char *buf) \ |
70 | { \ | 69 | { \ |
71 | unsigned int cpu = dev->id; \ | 70 | unsigned int cpu = dev->id; \ |
72 | return show_cpumap(0, topology_##name(cpu), buf); \ | 71 | return show_cpumap(0, topology_##name(cpu), buf); \ |
73 | } | 72 | } |
74 | 73 | ||
75 | #define define_siblings_show_list(name) \ | 74 | #define define_siblings_show_list(name) \ |
76 | static ssize_t show_##name##_list(struct sys_device *dev, \ | 75 | static ssize_t show_##name##_list(struct device *dev, \ |
77 | struct sysdev_attribute *attr, \ | 76 | struct device_attribute *attr, \ |
78 | char *buf) \ | 77 | char *buf) \ |
79 | { \ | 78 | { \ |
80 | unsigned int cpu = dev->id; \ | 79 | unsigned int cpu = dev->id; \ |
@@ -83,15 +82,15 @@ static ssize_t show_##name##_list(struct sys_device *dev, \ | |||
83 | 82 | ||
84 | #else | 83 | #else |
85 | #define define_siblings_show_map(name) \ | 84 | #define define_siblings_show_map(name) \ |
86 | static ssize_t show_##name(struct sys_device *dev, \ | 85 | static ssize_t show_##name(struct device *dev, \ |
87 | struct sysdev_attribute *attr, char *buf) \ | 86 | struct device_attribute *attr, char *buf) \ |
88 | { \ | 87 | { \ |
89 | return show_cpumap(0, topology_##name(dev->id), buf); \ | 88 | return show_cpumap(0, topology_##name(dev->id), buf); \ |
90 | } | 89 | } |
91 | 90 | ||
92 | #define define_siblings_show_list(name) \ | 91 | #define define_siblings_show_list(name) \ |
93 | static ssize_t show_##name##_list(struct sys_device *dev, \ | 92 | static ssize_t show_##name##_list(struct device *dev, \ |
94 | struct sysdev_attribute *attr, \ | 93 | struct device_attribute *attr, \ |
95 | char *buf) \ | 94 | char *buf) \ |
96 | { \ | 95 | { \ |
97 | return show_cpumap(1, topology_##name(dev->id), buf); \ | 96 | return show_cpumap(1, topology_##name(dev->id), buf); \ |
@@ -124,16 +123,16 @@ define_one_ro_named(book_siblings_list, show_book_cpumask_list); | |||
124 | #endif | 123 | #endif |
125 | 124 | ||
126 | static struct attribute *default_attrs[] = { | 125 | static struct attribute *default_attrs[] = { |
127 | &attr_physical_package_id.attr, | 126 | &dev_attr_physical_package_id.attr, |
128 | &attr_core_id.attr, | 127 | &dev_attr_core_id.attr, |
129 | &attr_thread_siblings.attr, | 128 | &dev_attr_thread_siblings.attr, |
130 | &attr_thread_siblings_list.attr, | 129 | &dev_attr_thread_siblings_list.attr, |
131 | &attr_core_siblings.attr, | 130 | &dev_attr_core_siblings.attr, |
132 | &attr_core_siblings_list.attr, | 131 | &dev_attr_core_siblings_list.attr, |
133 | #ifdef CONFIG_SCHED_BOOK | 132 | #ifdef CONFIG_SCHED_BOOK |
134 | &attr_book_id.attr, | 133 | &dev_attr_book_id.attr, |
135 | &attr_book_siblings.attr, | 134 | &dev_attr_book_siblings.attr, |
136 | &attr_book_siblings_list.attr, | 135 | &dev_attr_book_siblings_list.attr, |
137 | #endif | 136 | #endif |
138 | NULL | 137 | NULL |
139 | }; | 138 | }; |
@@ -146,16 +145,16 @@ static struct attribute_group topology_attr_group = { | |||
146 | /* Add/Remove cpu_topology interface for CPU device */ | 145 | /* Add/Remove cpu_topology interface for CPU device */ |
147 | static int __cpuinit topology_add_dev(unsigned int cpu) | 146 | static int __cpuinit topology_add_dev(unsigned int cpu) |
148 | { | 147 | { |
149 | struct sys_device *sys_dev = get_cpu_sysdev(cpu); | 148 | struct device *dev = get_cpu_device(cpu); |
150 | 149 | ||
151 | return sysfs_create_group(&sys_dev->kobj, &topology_attr_group); | 150 | return sysfs_create_group(&dev->kobj, &topology_attr_group); |
152 | } | 151 | } |
153 | 152 | ||
154 | static void __cpuinit topology_remove_dev(unsigned int cpu) | 153 | static void __cpuinit topology_remove_dev(unsigned int cpu) |
155 | { | 154 | { |
156 | struct sys_device *sys_dev = get_cpu_sysdev(cpu); | 155 | struct device *dev = get_cpu_device(cpu); |
157 | 156 | ||
158 | sysfs_remove_group(&sys_dev->kobj, &topology_attr_group); | 157 | sysfs_remove_group(&dev->kobj, &topology_attr_group); |
159 | } | 158 | } |
160 | 159 | ||
161 | static int __cpuinit topology_cpu_callback(struct notifier_block *nfb, | 160 | static int __cpuinit topology_cpu_callback(struct notifier_block *nfb, |