aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/glue.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/glue.c')
-rw-r--r--drivers/acpi/glue.c135
1 files changed, 86 insertions, 49 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 243ee85e4d2e..d1a2d74033e9 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -25,6 +25,8 @@
25static LIST_HEAD(bus_type_list); 25static LIST_HEAD(bus_type_list);
26static DECLARE_RWSEM(bus_type_sem); 26static DECLARE_RWSEM(bus_type_sem);
27 27
28#define PHYSICAL_NODE_STRING "physical_node"
29
28int register_acpi_bus_type(struct acpi_bus_type *type) 30int register_acpi_bus_type(struct acpi_bus_type *type)
29{ 31{
30 if (acpi_disabled) 32 if (acpi_disabled)
@@ -124,84 +126,119 @@ acpi_handle acpi_get_child(acpi_handle parent, u64 address)
124 126
125EXPORT_SYMBOL(acpi_get_child); 127EXPORT_SYMBOL(acpi_get_child);
126 128
127/* Link ACPI devices with physical devices */
128static void acpi_glue_data_handler(acpi_handle handle,
129 void *context)
130{
131 /* we provide an empty handler */
132}
133
134/* Note: a success call will increase reference count by one */
135struct device *acpi_get_physical_device(acpi_handle handle)
136{
137 acpi_status status;
138 struct device *dev;
139
140 status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev);
141 if (ACPI_SUCCESS(status))
142 return get_device(dev);
143 return NULL;
144}
145
146EXPORT_SYMBOL(acpi_get_physical_device);
147
148static int acpi_bind_one(struct device *dev, acpi_handle handle) 129static int acpi_bind_one(struct device *dev, acpi_handle handle)
149{ 130{
150 struct acpi_device *acpi_dev; 131 struct acpi_device *acpi_dev;
151 acpi_status status; 132 acpi_status status;
133 struct acpi_device_physical_node *physical_node;
134 char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
135 int retval = -EINVAL;
152 136
153 if (dev->archdata.acpi_handle) { 137 if (dev->archdata.acpi_handle) {
154 dev_warn(dev, "Drivers changed 'acpi_handle'\n"); 138 dev_warn(dev, "Drivers changed 'acpi_handle'\n");
155 return -EINVAL; 139 return -EINVAL;
156 } 140 }
141
157 get_device(dev); 142 get_device(dev);
158 status = acpi_attach_data(handle, acpi_glue_data_handler, dev); 143 status = acpi_bus_get_device(handle, &acpi_dev);
159 if (ACPI_FAILURE(status)) { 144 if (ACPI_FAILURE(status))
160 put_device(dev); 145 goto err;
161 return -EINVAL; 146
147 physical_node = kzalloc(sizeof(struct acpi_device_physical_node),
148 GFP_KERNEL);
149 if (!physical_node) {
150 retval = -ENOMEM;
151 goto err;
162 } 152 }
163 dev->archdata.acpi_handle = handle;
164 153
165 status = acpi_bus_get_device(handle, &acpi_dev); 154 mutex_lock(&acpi_dev->physical_node_lock);
166 if (!ACPI_FAILURE(status)) { 155 /* allocate physical node id according to physical_node_id_bitmap */
167 int ret; 156 physical_node->node_id =
168 157 find_first_zero_bit(acpi_dev->physical_node_id_bitmap,
169 ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, 158 ACPI_MAX_PHYSICAL_NODE);
170 "firmware_node"); 159 if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
171 ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, 160 retval = -ENOSPC;
172 "physical_node"); 161 mutex_unlock(&acpi_dev->physical_node_lock);
173 if (acpi_dev->wakeup.flags.valid) 162 goto err;
174 device_set_wakeup_capable(dev, true);
175 } 163 }
176 164
165 set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap);
166 physical_node->dev = dev;
167 list_add_tail(&physical_node->node, &acpi_dev->physical_node_list);
168 acpi_dev->physical_node_count++;
169 mutex_unlock(&acpi_dev->physical_node_lock);
170
171 dev->archdata.acpi_handle = handle;
172
173 if (!physical_node->node_id)
174 strcpy(physical_node_name, PHYSICAL_NODE_STRING);
175 else
176 sprintf(physical_node_name,
177 "physical_node%d", physical_node->node_id);
178 retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
179 physical_node_name);
180 retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
181 "firmware_node");
182
183 if (acpi_dev->wakeup.flags.valid)
184 device_set_wakeup_capable(dev, true);
185
177 return 0; 186 return 0;
187
188 err:
189 put_device(dev);
190 return retval;
178} 191}
179 192
180static int acpi_unbind_one(struct device *dev) 193static int acpi_unbind_one(struct device *dev)
181{ 194{
195 struct acpi_device_physical_node *entry;
196 struct acpi_device *acpi_dev;
197 acpi_status status;
198 struct list_head *node, *next;
199
182 if (!dev->archdata.acpi_handle) 200 if (!dev->archdata.acpi_handle)
183 return 0; 201 return 0;
184 if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
185 struct acpi_device *acpi_dev;
186 202
187 /* acpi_get_physical_device increase refcnt by one */ 203 status = acpi_bus_get_device(dev->archdata.acpi_handle,
188 put_device(dev); 204 &acpi_dev);
205 if (ACPI_FAILURE(status))
206 goto err;
189 207
190 if (!acpi_bus_get_device(dev->archdata.acpi_handle, 208 mutex_lock(&acpi_dev->physical_node_lock);
191 &acpi_dev)) { 209 list_for_each_safe(node, next, &acpi_dev->physical_node_list) {
192 sysfs_remove_link(&dev->kobj, "firmware_node"); 210 char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
193 sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node"); 211
194 } 212 entry = list_entry(node, struct acpi_device_physical_node,
213 node);
214 if (entry->dev != dev)
215 continue;
216
217 list_del(node);
218 clear_bit(entry->node_id, acpi_dev->physical_node_id_bitmap);
195 219
196 acpi_detach_data(dev->archdata.acpi_handle, 220 acpi_dev->physical_node_count--;
197 acpi_glue_data_handler); 221
222 if (!entry->node_id)
223 strcpy(physical_node_name, PHYSICAL_NODE_STRING);
224 else
225 sprintf(physical_node_name,
226 "physical_node%d", entry->node_id);
227
228 sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name);
229 sysfs_remove_link(&dev->kobj, "firmware_node");
198 dev->archdata.acpi_handle = NULL; 230 dev->archdata.acpi_handle = NULL;
199 /* acpi_bind_one increase refcnt by one */ 231 /* acpi_bind_one increase refcnt by one */
200 put_device(dev); 232 put_device(dev);
201 } else { 233 kfree(entry);
202 dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
203 } 234 }
235 mutex_unlock(&acpi_dev->physical_node_lock);
236
204 return 0; 237 return 0;
238
239err:
240 dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
241 return -EINVAL;
205} 242}
206 243
207static int acpi_platform_notify(struct device *dev) 244static int acpi_platform_notify(struct device *dev)