diff options
-rw-r--r-- | drivers/acpi/container.c | 48 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 1 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 8 | ||||
-rw-r--r-- | drivers/base/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/base.h | 1 | ||||
-rw-r--r-- | drivers/base/container.c | 44 | ||||
-rw-r--r-- | drivers/base/init.c | 1 | ||||
-rw-r--r-- | include/linux/container.h | 25 |
8 files changed, 122 insertions, 8 deletions
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 83d232c10f13..0b6ae6eb5c4a 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c | |||
@@ -27,8 +27,7 @@ | |||
27 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 27 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
28 | */ | 28 | */ |
29 | #include <linux/acpi.h> | 29 | #include <linux/acpi.h> |
30 | 30 | #include <linux/container.h> | |
31 | #include "internal.h" | ||
32 | 31 | ||
33 | #include "internal.h" | 32 | #include "internal.h" |
34 | 33 | ||
@@ -44,16 +43,56 @@ static const struct acpi_device_id container_device_ids[] = { | |||
44 | {"", 0}, | 43 | {"", 0}, |
45 | }; | 44 | }; |
46 | 45 | ||
46 | static int acpi_container_offline(struct container_dev *cdev) | ||
47 | { | ||
48 | struct acpi_device *adev = ACPI_COMPANION(&cdev->dev); | ||
49 | struct acpi_device *child; | ||
50 | |||
51 | /* Check all of the dependent devices' physical companions. */ | ||
52 | list_for_each_entry(child, &adev->children, node) | ||
53 | if (!acpi_scan_is_offline(child, false)) | ||
54 | return -EBUSY; | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static void acpi_container_release(struct device *dev) | ||
60 | { | ||
61 | kfree(to_container_dev(dev)); | ||
62 | } | ||
63 | |||
47 | static int container_device_attach(struct acpi_device *adev, | 64 | static int container_device_attach(struct acpi_device *adev, |
48 | const struct acpi_device_id *not_used) | 65 | const struct acpi_device_id *not_used) |
49 | { | 66 | { |
50 | kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE); | 67 | struct container_dev *cdev; |
68 | struct device *dev; | ||
69 | int ret; | ||
70 | |||
71 | cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); | ||
72 | if (!cdev) | ||
73 | return -ENOMEM; | ||
74 | |||
75 | cdev->offline = acpi_container_offline; | ||
76 | dev = &cdev->dev; | ||
77 | dev->bus = &container_subsys; | ||
78 | dev_set_name(dev, "%s", dev_name(&adev->dev)); | ||
79 | ACPI_COMPANION_SET(dev, adev); | ||
80 | dev->release = acpi_container_release; | ||
81 | ret = device_register(dev); | ||
82 | if (ret) | ||
83 | return ret; | ||
84 | |||
85 | adev->driver_data = dev; | ||
51 | return 1; | 86 | return 1; |
52 | } | 87 | } |
53 | 88 | ||
54 | static void container_device_detach(struct acpi_device *adev) | 89 | static void container_device_detach(struct acpi_device *adev) |
55 | { | 90 | { |
56 | kobject_uevent(&adev->dev.kobj, KOBJ_OFFLINE); | 91 | struct device *dev = acpi_driver_data(adev); |
92 | |||
93 | adev->driver_data = NULL; | ||
94 | if (dev) | ||
95 | device_unregister(dev); | ||
57 | } | 96 | } |
58 | 97 | ||
59 | static struct acpi_scan_handler container_handler = { | 98 | static struct acpi_scan_handler container_handler = { |
@@ -62,6 +101,7 @@ static struct acpi_scan_handler container_handler = { | |||
62 | .detach = container_device_detach, | 101 | .detach = container_device_detach, |
63 | .hotplug = { | 102 | .hotplug = { |
64 | .enabled = true, | 103 | .enabled = true, |
104 | .demand_offline = true, | ||
65 | }, | 105 | }, |
66 | }; | 106 | }; |
67 | 107 | ||
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index b125fdb0b30c..3375129bb5b7 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) {} | |||
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | bool acpi_queue_hotplug_work(struct work_struct *work); | 75 | bool acpi_queue_hotplug_work(struct work_struct *work); |
76 | bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); | ||
76 | 77 | ||
77 | /* -------------------------------------------------------------------------- | 78 | /* -------------------------------------------------------------------------- |
78 | Device Node Initialization / Removal | 79 | Device Node Initialization / Removal |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 65243b9dd868..32b340171d41 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -126,7 +126,7 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha | |||
126 | } | 126 | } |
127 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); | 127 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); |
128 | 128 | ||
129 | static bool acpi_scan_is_offline(struct acpi_device *adev) | 129 | bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) |
130 | { | 130 | { |
131 | struct acpi_device_physical_node *pn; | 131 | struct acpi_device_physical_node *pn; |
132 | bool offline = true; | 132 | bool offline = true; |
@@ -135,7 +135,9 @@ static bool acpi_scan_is_offline(struct acpi_device *adev) | |||
135 | 135 | ||
136 | list_for_each_entry(pn, &adev->physical_node_list, node) | 136 | list_for_each_entry(pn, &adev->physical_node_list, node) |
137 | if (device_supports_offline(pn->dev) && !pn->dev->offline) { | 137 | if (device_supports_offline(pn->dev) && !pn->dev->offline) { |
138 | kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE); | 138 | if (uevent) |
139 | kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE); | ||
140 | |||
139 | offline = false; | 141 | offline = false; |
140 | break; | 142 | break; |
141 | } | 143 | } |
@@ -267,7 +269,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device) | |||
267 | acpi_status status; | 269 | acpi_status status; |
268 | 270 | ||
269 | if (device->handler->hotplug.demand_offline && !acpi_force_hot_remove) { | 271 | if (device->handler->hotplug.demand_offline && !acpi_force_hot_remove) { |
270 | if (!acpi_scan_is_offline(device)) | 272 | if (!acpi_scan_is_offline(device, true)) |
271 | return -EBUSY; | 273 | return -EBUSY; |
272 | } else { | 274 | } else { |
273 | int error = acpi_scan_try_to_offline(device); | 275 | int error = acpi_scan_try_to_offline(device); |
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 94e8a80e87f8..d08c9d3b1d37 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -4,7 +4,7 @@ obj-y := core.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 | topology.o container.o |
8 | obj-$(CONFIG_DEVTMPFS) += devtmpfs.o | 8 | obj-$(CONFIG_DEVTMPFS) += devtmpfs.o |
9 | obj-$(CONFIG_DMA_CMA) += dma-contiguous.o | 9 | obj-$(CONFIG_DMA_CMA) += dma-contiguous.o |
10 | obj-y += power/ | 10 | obj-y += power/ |
diff --git a/drivers/base/base.h b/drivers/base/base.h index 2cbc6774f4cd..24f424249d9b 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h | |||
@@ -100,6 +100,7 @@ static inline int hypervisor_init(void) { return 0; } | |||
100 | #endif | 100 | #endif |
101 | extern int platform_bus_init(void); | 101 | extern int platform_bus_init(void); |
102 | extern void cpu_dev_init(void); | 102 | extern void cpu_dev_init(void); |
103 | extern void container_dev_init(void); | ||
103 | 104 | ||
104 | struct kobject *virtual_device_parent(struct device *dev); | 105 | struct kobject *virtual_device_parent(struct device *dev); |
105 | 106 | ||
diff --git a/drivers/base/container.c b/drivers/base/container.c new file mode 100644 index 000000000000..ecbfbe2e908f --- /dev/null +++ b/drivers/base/container.c | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * System bus type for containers. | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation | ||
5 | * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/container.h> | ||
13 | |||
14 | #include "base.h" | ||
15 | |||
16 | #define CONTAINER_BUS_NAME "container" | ||
17 | |||
18 | static int trivial_online(struct device *dev) | ||
19 | { | ||
20 | return 0; | ||
21 | } | ||
22 | |||
23 | static int container_offline(struct device *dev) | ||
24 | { | ||
25 | struct container_dev *cdev = to_container_dev(dev); | ||
26 | |||
27 | return cdev->offline ? cdev->offline(cdev) : 0; | ||
28 | } | ||
29 | |||
30 | struct bus_type container_subsys = { | ||
31 | .name = CONTAINER_BUS_NAME, | ||
32 | .dev_name = CONTAINER_BUS_NAME, | ||
33 | .online = trivial_online, | ||
34 | .offline = container_offline, | ||
35 | }; | ||
36 | |||
37 | void __init container_dev_init(void) | ||
38 | { | ||
39 | int ret; | ||
40 | |||
41 | ret = subsys_system_register(&container_subsys, NULL); | ||
42 | if (ret) | ||
43 | pr_err("%s() failed: %d\n", __func__, ret); | ||
44 | } | ||
diff --git a/drivers/base/init.c b/drivers/base/init.c index c16f0b808a17..da033d3bab3c 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c | |||
@@ -33,4 +33,5 @@ void __init driver_init(void) | |||
33 | platform_bus_init(); | 33 | platform_bus_init(); |
34 | cpu_dev_init(); | 34 | cpu_dev_init(); |
35 | memory_dev_init(); | 35 | memory_dev_init(); |
36 | container_dev_init(); | ||
36 | } | 37 | } |
diff --git a/include/linux/container.h b/include/linux/container.h new file mode 100644 index 000000000000..3c03e6fd2035 --- /dev/null +++ b/include/linux/container.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Definitions for container bus type. | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation | ||
5 | * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/device.h> | ||
13 | |||
14 | /* drivers/base/power/container.c */ | ||
15 | extern struct bus_type container_subsys; | ||
16 | |||
17 | struct container_dev { | ||
18 | struct device dev; | ||
19 | int (*offline)(struct container_dev *cdev); | ||
20 | }; | ||
21 | |||
22 | static inline struct container_dev *to_container_dev(struct device *dev) | ||
23 | { | ||
24 | return container_of(dev, struct container_dev, dev); | ||
25 | } | ||