diff options
author | Alexander Graf <agraf@suse.de> | 2013-08-28 18:41:59 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2013-08-28 18:41:59 -0400 |
commit | bf550fc93d9855872a95e69e4002256110d89858 (patch) | |
tree | 10876bb4304bffe54c4160a132e7b8de6577ac4e /drivers/base | |
parent | 7e48c101e0c53e6095c5f4f5e63d14df50aae8fc (diff) | |
parent | cc2df20c7c4ce594c3e17e9cc260c330646012c8 (diff) |
Merge remote-tracking branch 'origin/next' into kvm-ppc-next
Conflicts:
mm/Kconfig
CMA DMA split and ZSWAP introduction were conflicting, fix up manually.
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/attribute_container.c | 2 | ||||
-rw-r--r-- | drivers/base/core.c | 130 | ||||
-rw-r--r-- | drivers/base/cpu.c | 101 | ||||
-rw-r--r-- | drivers/base/dma-buf.c | 5 | ||||
-rw-r--r-- | drivers/base/memory.c | 114 | ||||
-rw-r--r-- | drivers/base/platform.c | 4 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 1 | ||||
-rw-r--r-- | drivers/base/power/generic_ops.c | 23 | ||||
-rw-r--r-- | drivers/base/power/opp.c | 4 | ||||
-rw-r--r-- | drivers/base/power/qos.c | 6 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 12 | ||||
-rw-r--r-- | drivers/base/power/wakeup.c | 9 | ||||
-rw-r--r-- | drivers/base/reservation.c | 39 |
14 files changed, 309 insertions, 143 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 5d93bb519753..94e8a80e87f8 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_DMA_CMA) += dma-contiguous.o | |||
10 | obj-y += power/ | 10 | obj-y += power/ |
11 | obj-$(CONFIG_HAS_DMA) += dma-mapping.o | 11 | obj-$(CONFIG_HAS_DMA) += dma-mapping.o |
12 | obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o | 12 | obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o |
13 | obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o | 13 | obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o reservation.o |
14 | obj-$(CONFIG_ISA) += isa.o | 14 | obj-$(CONFIG_ISA) += isa.o |
15 | obj-$(CONFIG_FW_LOADER) += firmware_class.o | 15 | obj-$(CONFIG_FW_LOADER) += firmware_class.o |
16 | obj-$(CONFIG_NUMA) += node.o | 16 | obj-$(CONFIG_NUMA) += node.o |
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index d78b204e65c1..ecc1929d7f6a 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c | |||
@@ -167,7 +167,7 @@ attribute_container_add_device(struct device *dev, | |||
167 | ic->classdev.parent = get_device(dev); | 167 | ic->classdev.parent = get_device(dev); |
168 | ic->classdev.class = cont->class; | 168 | ic->classdev.class = cont->class; |
169 | cont->class->dev_release = attribute_container_release; | 169 | cont->class->dev_release = attribute_container_release; |
170 | dev_set_name(&ic->classdev, dev_name(dev)); | 170 | dev_set_name(&ic->classdev, "%s", dev_name(dev)); |
171 | if (fn) | 171 | if (fn) |
172 | fn(cont, dev, &ic->classdev); | 172 | fn(cont, dev, &ic->classdev); |
173 | else | 173 | else |
diff --git a/drivers/base/core.c b/drivers/base/core.c index 6fdc53d46fa0..dc3ea237f086 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -403,6 +403,36 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, | |||
403 | static struct device_attribute uevent_attr = | 403 | static struct device_attribute uevent_attr = |
404 | __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent); | 404 | __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent); |
405 | 405 | ||
406 | static ssize_t show_online(struct device *dev, struct device_attribute *attr, | ||
407 | char *buf) | ||
408 | { | ||
409 | bool val; | ||
410 | |||
411 | lock_device_hotplug(); | ||
412 | val = !dev->offline; | ||
413 | unlock_device_hotplug(); | ||
414 | return sprintf(buf, "%u\n", val); | ||
415 | } | ||
416 | |||
417 | static ssize_t store_online(struct device *dev, struct device_attribute *attr, | ||
418 | const char *buf, size_t count) | ||
419 | { | ||
420 | bool val; | ||
421 | int ret; | ||
422 | |||
423 | ret = strtobool(buf, &val); | ||
424 | if (ret < 0) | ||
425 | return ret; | ||
426 | |||
427 | lock_device_hotplug(); | ||
428 | ret = val ? device_online(dev) : device_offline(dev); | ||
429 | unlock_device_hotplug(); | ||
430 | return ret < 0 ? ret : count; | ||
431 | } | ||
432 | |||
433 | static struct device_attribute online_attr = | ||
434 | __ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online); | ||
435 | |||
406 | static int device_add_attributes(struct device *dev, | 436 | static int device_add_attributes(struct device *dev, |
407 | struct device_attribute *attrs) | 437 | struct device_attribute *attrs) |
408 | { | 438 | { |
@@ -516,6 +546,12 @@ static int device_add_attrs(struct device *dev) | |||
516 | if (error) | 546 | if (error) |
517 | goto err_remove_type_groups; | 547 | goto err_remove_type_groups; |
518 | 548 | ||
549 | if (device_supports_offline(dev) && !dev->offline_disabled) { | ||
550 | error = device_create_file(dev, &online_attr); | ||
551 | if (error) | ||
552 | goto err_remove_type_groups; | ||
553 | } | ||
554 | |||
519 | return 0; | 555 | return 0; |
520 | 556 | ||
521 | err_remove_type_groups: | 557 | err_remove_type_groups: |
@@ -536,6 +572,7 @@ static void device_remove_attrs(struct device *dev) | |||
536 | struct class *class = dev->class; | 572 | struct class *class = dev->class; |
537 | const struct device_type *type = dev->type; | 573 | const struct device_type *type = dev->type; |
538 | 574 | ||
575 | device_remove_file(dev, &online_attr); | ||
539 | device_remove_groups(dev, dev->groups); | 576 | device_remove_groups(dev, dev->groups); |
540 | 577 | ||
541 | if (type) | 578 | if (type) |
@@ -1435,6 +1472,99 @@ EXPORT_SYMBOL_GPL(put_device); | |||
1435 | EXPORT_SYMBOL_GPL(device_create_file); | 1472 | EXPORT_SYMBOL_GPL(device_create_file); |
1436 | EXPORT_SYMBOL_GPL(device_remove_file); | 1473 | EXPORT_SYMBOL_GPL(device_remove_file); |
1437 | 1474 | ||
1475 | static DEFINE_MUTEX(device_hotplug_lock); | ||
1476 | |||
1477 | void lock_device_hotplug(void) | ||
1478 | { | ||
1479 | mutex_lock(&device_hotplug_lock); | ||
1480 | } | ||
1481 | |||
1482 | void unlock_device_hotplug(void) | ||
1483 | { | ||
1484 | mutex_unlock(&device_hotplug_lock); | ||
1485 | } | ||
1486 | |||
1487 | static int device_check_offline(struct device *dev, void *not_used) | ||
1488 | { | ||
1489 | int ret; | ||
1490 | |||
1491 | ret = device_for_each_child(dev, NULL, device_check_offline); | ||
1492 | if (ret) | ||
1493 | return ret; | ||
1494 | |||
1495 | return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0; | ||
1496 | } | ||
1497 | |||
1498 | /** | ||
1499 | * device_offline - Prepare the device for hot-removal. | ||
1500 | * @dev: Device to be put offline. | ||
1501 | * | ||
1502 | * Execute the device bus type's .offline() callback, if present, to prepare | ||
1503 | * the device for a subsequent hot-removal. If that succeeds, the device must | ||
1504 | * not be used until either it is removed or its bus type's .online() callback | ||
1505 | * is executed. | ||
1506 | * | ||
1507 | * Call under device_hotplug_lock. | ||
1508 | */ | ||
1509 | int device_offline(struct device *dev) | ||
1510 | { | ||
1511 | int ret; | ||
1512 | |||
1513 | if (dev->offline_disabled) | ||
1514 | return -EPERM; | ||
1515 | |||
1516 | ret = device_for_each_child(dev, NULL, device_check_offline); | ||
1517 | if (ret) | ||
1518 | return ret; | ||
1519 | |||
1520 | device_lock(dev); | ||
1521 | if (device_supports_offline(dev)) { | ||
1522 | if (dev->offline) { | ||
1523 | ret = 1; | ||
1524 | } else { | ||
1525 | ret = dev->bus->offline(dev); | ||
1526 | if (!ret) { | ||
1527 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); | ||
1528 | dev->offline = true; | ||
1529 | } | ||
1530 | } | ||
1531 | } | ||
1532 | device_unlock(dev); | ||
1533 | |||
1534 | return ret; | ||
1535 | } | ||
1536 | |||
1537 | /** | ||
1538 | * device_online - Put the device back online after successful device_offline(). | ||
1539 | * @dev: Device to be put back online. | ||
1540 | * | ||
1541 | * If device_offline() has been successfully executed for @dev, but the device | ||
1542 | * has not been removed subsequently, execute its bus type's .online() callback | ||
1543 | * to indicate that the device can be used again. | ||
1544 | * | ||
1545 | * Call under device_hotplug_lock. | ||
1546 | */ | ||
1547 | int device_online(struct device *dev) | ||
1548 | { | ||
1549 | int ret = 0; | ||
1550 | |||
1551 | device_lock(dev); | ||
1552 | if (device_supports_offline(dev)) { | ||
1553 | if (dev->offline) { | ||
1554 | ret = dev->bus->online(dev); | ||
1555 | if (!ret) { | ||
1556 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); | ||
1557 | dev->offline = false; | ||
1558 | } | ||
1559 | } else { | ||
1560 | ret = 1; | ||
1561 | } | ||
1562 | } | ||
1563 | device_unlock(dev); | ||
1564 | |||
1565 | return ret; | ||
1566 | } | ||
1567 | |||
1438 | struct root_device { | 1568 | struct root_device { |
1439 | struct device dev; | 1569 | struct device dev; |
1440 | struct module *owner; | 1570 | struct module *owner; |
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index c377673320ed..a16d20e389f0 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c | |||
@@ -13,17 +13,21 @@ | |||
13 | #include <linux/gfp.h> | 13 | #include <linux/gfp.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/percpu.h> | 15 | #include <linux/percpu.h> |
16 | #include <linux/acpi.h> | ||
16 | 17 | ||
17 | #include "base.h" | 18 | #include "base.h" |
18 | 19 | ||
19 | struct bus_type cpu_subsys = { | ||
20 | .name = "cpu", | ||
21 | .dev_name = "cpu", | ||
22 | }; | ||
23 | EXPORT_SYMBOL_GPL(cpu_subsys); | ||
24 | |||
25 | static DEFINE_PER_CPU(struct device *, cpu_sys_devices); | 20 | static DEFINE_PER_CPU(struct device *, cpu_sys_devices); |
26 | 21 | ||
22 | static int cpu_subsys_match(struct device *dev, struct device_driver *drv) | ||
23 | { | ||
24 | /* ACPI style match is the only one that may succeed. */ | ||
25 | if (acpi_driver_match_device(dev, drv)) | ||
26 | return 1; | ||
27 | |||
28 | return 0; | ||
29 | } | ||
30 | |||
27 | #ifdef CONFIG_HOTPLUG_CPU | 31 | #ifdef CONFIG_HOTPLUG_CPU |
28 | static void change_cpu_under_node(struct cpu *cpu, | 32 | static void change_cpu_under_node(struct cpu *cpu, |
29 | unsigned int from_nid, unsigned int to_nid) | 33 | unsigned int from_nid, unsigned int to_nid) |
@@ -34,65 +38,38 @@ static void change_cpu_under_node(struct cpu *cpu, | |||
34 | cpu->node_id = to_nid; | 38 | cpu->node_id = to_nid; |
35 | } | 39 | } |
36 | 40 | ||
37 | static ssize_t show_online(struct device *dev, | 41 | static int __ref cpu_subsys_online(struct device *dev) |
38 | struct device_attribute *attr, | ||
39 | char *buf) | ||
40 | { | 42 | { |
41 | struct cpu *cpu = container_of(dev, struct cpu, dev); | 43 | struct cpu *cpu = container_of(dev, struct cpu, dev); |
44 | int cpuid = dev->id; | ||
45 | int from_nid, to_nid; | ||
46 | int ret; | ||
47 | |||
48 | cpu_hotplug_driver_lock(); | ||
42 | 49 | ||
43 | return sprintf(buf, "%u\n", !!cpu_online(cpu->dev.id)); | 50 | from_nid = cpu_to_node(cpuid); |
51 | ret = cpu_up(cpuid); | ||
52 | /* | ||
53 | * When hot adding memory to memoryless node and enabling a cpu | ||
54 | * on the node, node number of the cpu may internally change. | ||
55 | */ | ||
56 | to_nid = cpu_to_node(cpuid); | ||
57 | if (from_nid != to_nid) | ||
58 | change_cpu_under_node(cpu, from_nid, to_nid); | ||
59 | |||
60 | cpu_hotplug_driver_unlock(); | ||
61 | return ret; | ||
44 | } | 62 | } |
45 | 63 | ||
46 | static ssize_t __ref store_online(struct device *dev, | 64 | static int cpu_subsys_offline(struct device *dev) |
47 | struct device_attribute *attr, | ||
48 | const char *buf, size_t count) | ||
49 | { | 65 | { |
50 | struct cpu *cpu = container_of(dev, struct cpu, dev); | 66 | int ret; |
51 | int cpuid = cpu->dev.id; | ||
52 | int from_nid, to_nid; | ||
53 | ssize_t ret; | ||
54 | 67 | ||
55 | cpu_hotplug_driver_lock(); | 68 | cpu_hotplug_driver_lock(); |
56 | switch (buf[0]) { | 69 | ret = cpu_down(dev->id); |
57 | case '0': | ||
58 | ret = cpu_down(cpuid); | ||
59 | if (!ret) | ||
60 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); | ||
61 | break; | ||
62 | case '1': | ||
63 | from_nid = cpu_to_node(cpuid); | ||
64 | ret = cpu_up(cpuid); | ||
65 | |||
66 | /* | ||
67 | * When hot adding memory to memoryless node and enabling a cpu | ||
68 | * on the node, node number of the cpu may internally change. | ||
69 | */ | ||
70 | to_nid = cpu_to_node(cpuid); | ||
71 | if (from_nid != to_nid) | ||
72 | change_cpu_under_node(cpu, from_nid, to_nid); | ||
73 | |||
74 | if (!ret) | ||
75 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); | ||
76 | break; | ||
77 | default: | ||
78 | ret = -EINVAL; | ||
79 | } | ||
80 | cpu_hotplug_driver_unlock(); | 70 | cpu_hotplug_driver_unlock(); |
81 | |||
82 | if (ret >= 0) | ||
83 | ret = count; | ||
84 | return ret; | 71 | return ret; |
85 | } | 72 | } |
86 | static DEVICE_ATTR(online, 0644, show_online, store_online); | ||
87 | |||
88 | static struct attribute *hotplug_cpu_attrs[] = { | ||
89 | &dev_attr_online.attr, | ||
90 | NULL | ||
91 | }; | ||
92 | |||
93 | static struct attribute_group hotplug_cpu_attr_group = { | ||
94 | .attrs = hotplug_cpu_attrs, | ||
95 | }; | ||
96 | 73 | ||
97 | void unregister_cpu(struct cpu *cpu) | 74 | void unregister_cpu(struct cpu *cpu) |
98 | { | 75 | { |
@@ -127,6 +104,17 @@ static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); | |||
127 | #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ | 104 | #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ |
128 | #endif /* CONFIG_HOTPLUG_CPU */ | 105 | #endif /* CONFIG_HOTPLUG_CPU */ |
129 | 106 | ||
107 | struct bus_type cpu_subsys = { | ||
108 | .name = "cpu", | ||
109 | .dev_name = "cpu", | ||
110 | .match = cpu_subsys_match, | ||
111 | #ifdef CONFIG_HOTPLUG_CPU | ||
112 | .online = cpu_subsys_online, | ||
113 | .offline = cpu_subsys_offline, | ||
114 | #endif | ||
115 | }; | ||
116 | EXPORT_SYMBOL_GPL(cpu_subsys); | ||
117 | |||
130 | #ifdef CONFIG_KEXEC | 118 | #ifdef CONFIG_KEXEC |
131 | #include <linux/kexec.h> | 119 | #include <linux/kexec.h> |
132 | 120 | ||
@@ -185,9 +173,6 @@ static const struct attribute_group *hotplugable_cpu_attr_groups[] = { | |||
185 | #ifdef CONFIG_KEXEC | 173 | #ifdef CONFIG_KEXEC |
186 | &crash_note_cpu_attr_group, | 174 | &crash_note_cpu_attr_group, |
187 | #endif | 175 | #endif |
188 | #ifdef CONFIG_HOTPLUG_CPU | ||
189 | &hotplug_cpu_attr_group, | ||
190 | #endif | ||
191 | NULL | 176 | NULL |
192 | }; | 177 | }; |
193 | 178 | ||
@@ -302,6 +287,8 @@ int __cpuinit register_cpu(struct cpu *cpu, int num) | |||
302 | cpu->dev.id = num; | 287 | cpu->dev.id = num; |
303 | cpu->dev.bus = &cpu_subsys; | 288 | cpu->dev.bus = &cpu_subsys; |
304 | cpu->dev.release = cpu_device_release; | 289 | cpu->dev.release = cpu_device_release; |
290 | cpu->dev.offline_disabled = !cpu->hotpluggable; | ||
291 | cpu->dev.offline = !cpu_online(num); | ||
305 | #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE | 292 | #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE |
306 | cpu->dev.bus->uevent = arch_cpu_uevent; | 293 | cpu->dev.bus->uevent = arch_cpu_uevent; |
307 | #endif | 294 | #endif |
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index 08fe897c0b4c..6687ba741879 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c | |||
@@ -680,10 +680,7 @@ int dma_buf_debugfs_create_file(const char *name, | |||
680 | d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir, | 680 | d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir, |
681 | write, &dma_buf_debug_fops); | 681 | write, &dma_buf_debug_fops); |
682 | 682 | ||
683 | if (IS_ERR(d)) | 683 | return PTR_RET(d); |
684 | return PTR_ERR(d); | ||
685 | |||
686 | return 0; | ||
687 | } | 684 | } |
688 | #else | 685 | #else |
689 | static inline int dma_buf_init_debugfs(void) | 686 | static inline int dma_buf_init_debugfs(void) |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index e315051cfeeb..2b7813ec6d02 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -37,9 +37,14 @@ static inline int base_memory_block_id(int section_nr) | |||
37 | return section_nr / sections_per_block; | 37 | return section_nr / sections_per_block; |
38 | } | 38 | } |
39 | 39 | ||
40 | static int memory_subsys_online(struct device *dev); | ||
41 | static int memory_subsys_offline(struct device *dev); | ||
42 | |||
40 | static struct bus_type memory_subsys = { | 43 | static struct bus_type memory_subsys = { |
41 | .name = MEMORY_CLASS_NAME, | 44 | .name = MEMORY_CLASS_NAME, |
42 | .dev_name = MEMORY_CLASS_NAME, | 45 | .dev_name = MEMORY_CLASS_NAME, |
46 | .online = memory_subsys_online, | ||
47 | .offline = memory_subsys_offline, | ||
43 | }; | 48 | }; |
44 | 49 | ||
45 | static BLOCKING_NOTIFIER_HEAD(memory_chain); | 50 | static BLOCKING_NOTIFIER_HEAD(memory_chain); |
@@ -262,33 +267,64 @@ static int __memory_block_change_state(struct memory_block *mem, | |||
262 | { | 267 | { |
263 | int ret = 0; | 268 | int ret = 0; |
264 | 269 | ||
265 | if (mem->state != from_state_req) { | 270 | if (mem->state != from_state_req) |
266 | ret = -EINVAL; | 271 | return -EINVAL; |
267 | goto out; | ||
268 | } | ||
269 | 272 | ||
270 | if (to_state == MEM_OFFLINE) | 273 | if (to_state == MEM_OFFLINE) |
271 | mem->state = MEM_GOING_OFFLINE; | 274 | mem->state = MEM_GOING_OFFLINE; |
272 | 275 | ||
273 | ret = memory_block_action(mem->start_section_nr, to_state, online_type); | 276 | ret = memory_block_action(mem->start_section_nr, to_state, online_type); |
277 | mem->state = ret ? from_state_req : to_state; | ||
278 | return ret; | ||
279 | } | ||
274 | 280 | ||
275 | if (ret) { | 281 | static int memory_subsys_online(struct device *dev) |
276 | mem->state = from_state_req; | 282 | { |
277 | goto out; | 283 | struct memory_block *mem = container_of(dev, struct memory_block, dev); |
278 | } | 284 | int ret; |
279 | 285 | ||
280 | mem->state = to_state; | 286 | mutex_lock(&mem->state_mutex); |
281 | switch (mem->state) { | 287 | |
282 | case MEM_OFFLINE: | 288 | ret = mem->state == MEM_ONLINE ? 0 : |
283 | kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE); | 289 | __memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE, |
284 | break; | 290 | ONLINE_KEEP); |
285 | case MEM_ONLINE: | 291 | |
286 | kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE); | 292 | mutex_unlock(&mem->state_mutex); |
287 | break; | 293 | return ret; |
288 | default: | 294 | } |
289 | break; | 295 | |
296 | static int memory_subsys_offline(struct device *dev) | ||
297 | { | ||
298 | struct memory_block *mem = container_of(dev, struct memory_block, dev); | ||
299 | int ret; | ||
300 | |||
301 | mutex_lock(&mem->state_mutex); | ||
302 | |||
303 | ret = mem->state == MEM_OFFLINE ? 0 : | ||
304 | __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1); | ||
305 | |||
306 | mutex_unlock(&mem->state_mutex); | ||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | static int __memory_block_change_state_uevent(struct memory_block *mem, | ||
311 | unsigned long to_state, unsigned long from_state_req, | ||
312 | int online_type) | ||
313 | { | ||
314 | int ret = __memory_block_change_state(mem, to_state, from_state_req, | ||
315 | online_type); | ||
316 | if (!ret) { | ||
317 | switch (mem->state) { | ||
318 | case MEM_OFFLINE: | ||
319 | kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE); | ||
320 | break; | ||
321 | case MEM_ONLINE: | ||
322 | kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE); | ||
323 | break; | ||
324 | default: | ||
325 | break; | ||
326 | } | ||
290 | } | 327 | } |
291 | out: | ||
292 | return ret; | 328 | return ret; |
293 | } | 329 | } |
294 | 330 | ||
@@ -299,8 +335,8 @@ static int memory_block_change_state(struct memory_block *mem, | |||
299 | int ret; | 335 | int ret; |
300 | 336 | ||
301 | mutex_lock(&mem->state_mutex); | 337 | mutex_lock(&mem->state_mutex); |
302 | ret = __memory_block_change_state(mem, to_state, from_state_req, | 338 | ret = __memory_block_change_state_uevent(mem, to_state, from_state_req, |
303 | online_type); | 339 | online_type); |
304 | mutex_unlock(&mem->state_mutex); | 340 | mutex_unlock(&mem->state_mutex); |
305 | 341 | ||
306 | return ret; | 342 | return ret; |
@@ -310,22 +346,34 @@ store_mem_state(struct device *dev, | |||
310 | struct device_attribute *attr, const char *buf, size_t count) | 346 | struct device_attribute *attr, const char *buf, size_t count) |
311 | { | 347 | { |
312 | struct memory_block *mem; | 348 | struct memory_block *mem; |
349 | bool offline; | ||
313 | int ret = -EINVAL; | 350 | int ret = -EINVAL; |
314 | 351 | ||
315 | mem = container_of(dev, struct memory_block, dev); | 352 | mem = container_of(dev, struct memory_block, dev); |
316 | 353 | ||
317 | if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) | 354 | lock_device_hotplug(); |
355 | |||
356 | if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) { | ||
357 | offline = false; | ||
318 | ret = memory_block_change_state(mem, MEM_ONLINE, | 358 | ret = memory_block_change_state(mem, MEM_ONLINE, |
319 | MEM_OFFLINE, ONLINE_KERNEL); | 359 | MEM_OFFLINE, ONLINE_KERNEL); |
320 | else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) | 360 | } else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) { |
361 | offline = false; | ||
321 | ret = memory_block_change_state(mem, MEM_ONLINE, | 362 | ret = memory_block_change_state(mem, MEM_ONLINE, |
322 | MEM_OFFLINE, ONLINE_MOVABLE); | 363 | MEM_OFFLINE, ONLINE_MOVABLE); |
323 | else if (!strncmp(buf, "online", min_t(int, count, 6))) | 364 | } else if (!strncmp(buf, "online", min_t(int, count, 6))) { |
365 | offline = false; | ||
324 | ret = memory_block_change_state(mem, MEM_ONLINE, | 366 | ret = memory_block_change_state(mem, MEM_ONLINE, |
325 | MEM_OFFLINE, ONLINE_KEEP); | 367 | MEM_OFFLINE, ONLINE_KEEP); |
326 | else if(!strncmp(buf, "offline", min_t(int, count, 7))) | 368 | } else if(!strncmp(buf, "offline", min_t(int, count, 7))) { |
369 | offline = true; | ||
327 | ret = memory_block_change_state(mem, MEM_OFFLINE, | 370 | ret = memory_block_change_state(mem, MEM_OFFLINE, |
328 | MEM_ONLINE, -1); | 371 | MEM_ONLINE, -1); |
372 | } | ||
373 | if (!ret) | ||
374 | dev->offline = offline; | ||
375 | |||
376 | unlock_device_hotplug(); | ||
329 | 377 | ||
330 | if (ret) | 378 | if (ret) |
331 | return ret; | 379 | return ret; |
@@ -523,6 +571,7 @@ int register_memory(struct memory_block *memory) | |||
523 | memory->dev.id = memory->start_section_nr / sections_per_block; | 571 | memory->dev.id = memory->start_section_nr / sections_per_block; |
524 | memory->dev.release = memory_block_release; | 572 | memory->dev.release = memory_block_release; |
525 | memory->dev.groups = memory_memblk_attr_groups; | 573 | memory->dev.groups = memory_memblk_attr_groups; |
574 | memory->dev.offline = memory->state == MEM_OFFLINE; | ||
526 | 575 | ||
527 | error = device_register(&memory->dev); | 576 | error = device_register(&memory->dev); |
528 | return error; | 577 | return error; |
@@ -646,21 +695,6 @@ int unregister_memory_section(struct mem_section *section) | |||
646 | } | 695 | } |
647 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | 696 | #endif /* CONFIG_MEMORY_HOTREMOVE */ |
648 | 697 | ||
649 | /* | ||
650 | * offline one memory block. If the memory block has been offlined, do nothing. | ||
651 | */ | ||
652 | int offline_memory_block(struct memory_block *mem) | ||
653 | { | ||
654 | int ret = 0; | ||
655 | |||
656 | mutex_lock(&mem->state_mutex); | ||
657 | if (mem->state != MEM_OFFLINE) | ||
658 | ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1); | ||
659 | mutex_unlock(&mem->state_mutex); | ||
660 | |||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | /* return true if the memory block is offlined, otherwise, return false */ | 698 | /* return true if the memory block is offlined, otherwise, return false */ |
665 | bool is_memblock_offlined(struct memory_block *mem) | 699 | bool is_memblock_offlined(struct memory_block *mem) |
666 | { | 700 | { |
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index ed75cf6ef9c9..15789875128e 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -29,9 +29,6 @@ | |||
29 | /* For automatically allocated device IDs */ | 29 | /* For automatically allocated device IDs */ |
30 | static DEFINE_IDA(platform_devid_ida); | 30 | static DEFINE_IDA(platform_devid_ida); |
31 | 31 | ||
32 | #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ | ||
33 | driver)) | ||
34 | |||
35 | struct device platform_bus = { | 32 | struct device platform_bus = { |
36 | .init_name = "platform", | 33 | .init_name = "platform", |
37 | }; | 34 | }; |
@@ -890,7 +887,6 @@ int platform_pm_restore(struct device *dev) | |||
890 | static const struct dev_pm_ops platform_dev_pm_ops = { | 887 | static const struct dev_pm_ops platform_dev_pm_ops = { |
891 | .runtime_suspend = pm_generic_runtime_suspend, | 888 | .runtime_suspend = pm_generic_runtime_suspend, |
892 | .runtime_resume = pm_generic_runtime_resume, | 889 | .runtime_resume = pm_generic_runtime_resume, |
893 | .runtime_idle = pm_generic_runtime_idle, | ||
894 | USE_PLATFORM_PM_SLEEP_OPS | 890 | USE_PLATFORM_PM_SLEEP_OPS |
895 | }; | 891 | }; |
896 | 892 | ||
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 7072404c8b6d..bfb8955c406c 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -2143,7 +2143,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
2143 | genpd->max_off_time_changed = true; | 2143 | genpd->max_off_time_changed = true; |
2144 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; | 2144 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; |
2145 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; | 2145 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; |
2146 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; | ||
2147 | genpd->domain.ops.prepare = pm_genpd_prepare; | 2146 | genpd->domain.ops.prepare = pm_genpd_prepare; |
2148 | genpd->domain.ops.suspend = pm_genpd_suspend; | 2147 | genpd->domain.ops.suspend = pm_genpd_suspend; |
2149 | genpd->domain.ops.suspend_late = pm_genpd_suspend_late; | 2148 | genpd->domain.ops.suspend_late = pm_genpd_suspend_late; |
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index bfd898b8988e..5ee030a864f9 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c | |||
@@ -12,29 +12,6 @@ | |||
12 | 12 | ||
13 | #ifdef CONFIG_PM_RUNTIME | 13 | #ifdef CONFIG_PM_RUNTIME |
14 | /** | 14 | /** |
15 | * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. | ||
16 | * @dev: Device to handle. | ||
17 | * | ||
18 | * If PM operations are defined for the @dev's driver and they include | ||
19 | * ->runtime_idle(), execute it and return its error code, if nonzero. | ||
20 | * Otherwise, execute pm_runtime_suspend() for the device and return 0. | ||
21 | */ | ||
22 | int pm_generic_runtime_idle(struct device *dev) | ||
23 | { | ||
24 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
25 | |||
26 | if (pm && pm->runtime_idle) { | ||
27 | int ret = pm->runtime_idle(dev); | ||
28 | if (ret) | ||
29 | return ret; | ||
30 | } | ||
31 | |||
32 | pm_runtime_suspend(dev); | ||
33 | return 0; | ||
34 | } | ||
35 | EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); | ||
36 | |||
37 | /** | ||
38 | * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. | 15 | * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. |
39 | * @dev: Device to suspend. | 16 | * @dev: Device to suspend. |
40 | * | 17 | * |
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index f0077cb8e249..c8ec186303db 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c | |||
@@ -648,14 +648,14 @@ int opp_init_cpufreq_table(struct device *dev, | |||
648 | 648 | ||
649 | list_for_each_entry(opp, &dev_opp->opp_list, node) { | 649 | list_for_each_entry(opp, &dev_opp->opp_list, node) { |
650 | if (opp->available) { | 650 | if (opp->available) { |
651 | freq_table[i].index = i; | 651 | freq_table[i].driver_data = i; |
652 | freq_table[i].frequency = opp->rate / 1000; | 652 | freq_table[i].frequency = opp->rate / 1000; |
653 | i++; | 653 | i++; |
654 | } | 654 | } |
655 | } | 655 | } |
656 | mutex_unlock(&dev_opp_list_lock); | 656 | mutex_unlock(&dev_opp_list_lock); |
657 | 657 | ||
658 | freq_table[i].index = i; | 658 | freq_table[i].driver_data = i; |
659 | freq_table[i].frequency = CPUFREQ_TABLE_END; | 659 | freq_table[i].frequency = CPUFREQ_TABLE_END; |
660 | 660 | ||
661 | *table = &freq_table[0]; | 661 | *table = &freq_table[0]; |
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 71671c42ef45..5c1361a9e5dd 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/export.h> | 42 | #include <linux/export.h> |
43 | #include <linux/pm_runtime.h> | 43 | #include <linux/pm_runtime.h> |
44 | #include <linux/err.h> | 44 | #include <linux/err.h> |
45 | #include <trace/events/power.h> | ||
45 | 46 | ||
46 | #include "power.h" | 47 | #include "power.h" |
47 | 48 | ||
@@ -305,6 +306,7 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, | |||
305 | else if (!dev->power.qos) | 306 | else if (!dev->power.qos) |
306 | ret = dev_pm_qos_constraints_allocate(dev); | 307 | ret = dev_pm_qos_constraints_allocate(dev); |
307 | 308 | ||
309 | trace_dev_pm_qos_add_request(dev_name(dev), type, value); | ||
308 | if (!ret) { | 310 | if (!ret) { |
309 | req->dev = dev; | 311 | req->dev = dev; |
310 | req->type = type; | 312 | req->type = type; |
@@ -349,6 +351,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, | |||
349 | return -EINVAL; | 351 | return -EINVAL; |
350 | } | 352 | } |
351 | 353 | ||
354 | trace_dev_pm_qos_update_request(dev_name(req->dev), req->type, | ||
355 | new_value); | ||
352 | if (curr_value != new_value) | 356 | if (curr_value != new_value) |
353 | ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); | 357 | ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); |
354 | 358 | ||
@@ -398,6 +402,8 @@ static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req) | |||
398 | if (IS_ERR_OR_NULL(req->dev->power.qos)) | 402 | if (IS_ERR_OR_NULL(req->dev->power.qos)) |
399 | return -ENODEV; | 403 | return -ENODEV; |
400 | 404 | ||
405 | trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type, | ||
406 | PM_QOS_DEFAULT_VALUE); | ||
401 | ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); | 407 | ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); |
402 | memset(req, 0, sizeof(*req)); | 408 | memset(req, 0, sizeof(*req)); |
403 | return ret; | 409 | return ret; |
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index ef13ad08afb2..268a35097578 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -293,11 +293,8 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
293 | /* Pending requests need to be canceled. */ | 293 | /* Pending requests need to be canceled. */ |
294 | dev->power.request = RPM_REQ_NONE; | 294 | dev->power.request = RPM_REQ_NONE; |
295 | 295 | ||
296 | if (dev->power.no_callbacks) { | 296 | if (dev->power.no_callbacks) |
297 | /* Assume ->runtime_idle() callback would have suspended. */ | ||
298 | retval = rpm_suspend(dev, rpmflags); | ||
299 | goto out; | 297 | goto out; |
300 | } | ||
301 | 298 | ||
302 | /* Carry out an asynchronous or a synchronous idle notification. */ | 299 | /* Carry out an asynchronous or a synchronous idle notification. */ |
303 | if (rpmflags & RPM_ASYNC) { | 300 | if (rpmflags & RPM_ASYNC) { |
@@ -306,7 +303,8 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
306 | dev->power.request_pending = true; | 303 | dev->power.request_pending = true; |
307 | queue_work(pm_wq, &dev->power.work); | 304 | queue_work(pm_wq, &dev->power.work); |
308 | } | 305 | } |
309 | goto out; | 306 | trace_rpm_return_int(dev, _THIS_IP_, 0); |
307 | return 0; | ||
310 | } | 308 | } |
311 | 309 | ||
312 | dev->power.idle_notification = true; | 310 | dev->power.idle_notification = true; |
@@ -326,14 +324,14 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
326 | callback = dev->driver->pm->runtime_idle; | 324 | callback = dev->driver->pm->runtime_idle; |
327 | 325 | ||
328 | if (callback) | 326 | if (callback) |
329 | __rpm_callback(callback, dev); | 327 | retval = __rpm_callback(callback, dev); |
330 | 328 | ||
331 | dev->power.idle_notification = false; | 329 | dev->power.idle_notification = false; |
332 | wake_up_all(&dev->power.wait_queue); | 330 | wake_up_all(&dev->power.wait_queue); |
333 | 331 | ||
334 | out: | 332 | out: |
335 | trace_rpm_return_int(dev, _THIS_IP_, retval); | 333 | trace_rpm_return_int(dev, _THIS_IP_, retval); |
336 | return retval; | 334 | return retval ? retval : rpm_suspend(dev, rpmflags); |
337 | } | 335 | } |
338 | 336 | ||
339 | /** | 337 | /** |
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 79715e7fa43e..2d56f4113ae7 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c | |||
@@ -659,7 +659,7 @@ void pm_wakeup_event(struct device *dev, unsigned int msec) | |||
659 | } | 659 | } |
660 | EXPORT_SYMBOL_GPL(pm_wakeup_event); | 660 | EXPORT_SYMBOL_GPL(pm_wakeup_event); |
661 | 661 | ||
662 | static void print_active_wakeup_sources(void) | 662 | void pm_print_active_wakeup_sources(void) |
663 | { | 663 | { |
664 | struct wakeup_source *ws; | 664 | struct wakeup_source *ws; |
665 | int active = 0; | 665 | int active = 0; |
@@ -683,6 +683,7 @@ static void print_active_wakeup_sources(void) | |||
683 | last_activity_ws->name); | 683 | last_activity_ws->name); |
684 | rcu_read_unlock(); | 684 | rcu_read_unlock(); |
685 | } | 685 | } |
686 | EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources); | ||
686 | 687 | ||
687 | /** | 688 | /** |
688 | * pm_wakeup_pending - Check if power transition in progress should be aborted. | 689 | * pm_wakeup_pending - Check if power transition in progress should be aborted. |
@@ -707,8 +708,10 @@ bool pm_wakeup_pending(void) | |||
707 | } | 708 | } |
708 | spin_unlock_irqrestore(&events_lock, flags); | 709 | spin_unlock_irqrestore(&events_lock, flags); |
709 | 710 | ||
710 | if (ret) | 711 | if (ret) { |
711 | print_active_wakeup_sources(); | 712 | pr_info("PM: Wakeup pending, aborting suspend\n"); |
713 | pm_print_active_wakeup_sources(); | ||
714 | } | ||
712 | 715 | ||
713 | return ret; | 716 | return ret; |
714 | } | 717 | } |
diff --git a/drivers/base/reservation.c b/drivers/base/reservation.c new file mode 100644 index 000000000000..a73fbf3b8e56 --- /dev/null +++ b/drivers/base/reservation.c | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012-2013 Canonical Ltd | ||
3 | * | ||
4 | * Based on bo.c which bears the following copyright notice, | ||
5 | * but is dual licensed: | ||
6 | * | ||
7 | * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA | ||
8 | * All Rights Reserved. | ||
9 | * | ||
10 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
11 | * copy of this software and associated documentation files (the | ||
12 | * "Software"), to deal in the Software without restriction, including | ||
13 | * without limitation the rights to use, copy, modify, merge, publish, | ||
14 | * distribute, sub license, and/or sell copies of the Software, and to | ||
15 | * permit persons to whom the Software is furnished to do so, subject to | ||
16 | * the following conditions: | ||
17 | * | ||
18 | * The above copyright notice and this permission notice (including the | ||
19 | * next paragraph) shall be included in all copies or substantial portions | ||
20 | * of the Software. | ||
21 | * | ||
22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
25 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
26 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
27 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
28 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
29 | * | ||
30 | **************************************************************************/ | ||
31 | /* | ||
32 | * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> | ||
33 | */ | ||
34 | |||
35 | #include <linux/reservation.h> | ||
36 | #include <linux/export.h> | ||
37 | |||
38 | DEFINE_WW_CLASS(reservation_ww_class); | ||
39 | EXPORT_SYMBOL(reservation_ww_class); | ||