aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/container.c48
-rw-r--r--drivers/acpi/internal.h1
-rw-r--r--drivers/acpi/scan.c8
-rw-r--r--drivers/base/Makefile2
-rw-r--r--drivers/base/base.h1
-rw-r--r--drivers/base/container.c44
-rw-r--r--drivers/base/init.c1
-rw-r--r--include/linux/container.h25
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
46static 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
59static void acpi_container_release(struct device *dev)
60{
61 kfree(to_container_dev(dev));
62}
63
47static int container_device_attach(struct acpi_device *adev, 64static 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
54static void container_device_detach(struct acpi_device *adev) 89static 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
59static struct acpi_scan_handler container_handler = { 98static 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
75bool acpi_queue_hotplug_work(struct work_struct *work); 75bool acpi_queue_hotplug_work(struct work_struct *work);
76bool 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}
127static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); 127static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
128 128
129static bool acpi_scan_is_offline(struct acpi_device *adev) 129bool 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
8obj-$(CONFIG_DEVTMPFS) += devtmpfs.o 8obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
9obj-$(CONFIG_DMA_CMA) += dma-contiguous.o 9obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
10obj-y += power/ 10obj-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
101extern int platform_bus_init(void); 101extern int platform_bus_init(void);
102extern void cpu_dev_init(void); 102extern void cpu_dev_init(void);
103extern void container_dev_init(void);
103 104
104struct kobject *virtual_device_parent(struct device *dev); 105struct 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
18static int trivial_online(struct device *dev)
19{
20 return 0;
21}
22
23static 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
30struct 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
37void __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 */
15extern struct bus_type container_subsys;
16
17struct container_dev {
18 struct device dev;
19 int (*offline)(struct container_dev *cdev);
20};
21
22static inline struct container_dev *to_container_dev(struct device *dev)
23{
24 return container_of(dev, struct container_dev, dev);
25}