|
@@ -25,6 +25,8 @@
|
|
|
static LIST_HEAD(bus_type_list);
|
|
|
static DECLARE_RWSEM(bus_type_sem);
|
|
|
|
|
|
+#define PHYSICAL_NODE_STRING "physical_node"
|
|
|
+
|
|
|
int register_acpi_bus_type(struct acpi_bus_type *type)
|
|
|
{
|
|
|
if (acpi_disabled)
|
|
@@ -124,84 +126,119 @@ acpi_handle acpi_get_child(acpi_handle parent, u64 address)
|
|
|
|
|
|
EXPORT_SYMBOL(acpi_get_child);
|
|
|
|
|
|
-/* Link ACPI devices with physical devices */
|
|
|
-static void acpi_glue_data_handler(acpi_handle handle,
|
|
|
- void *context)
|
|
|
-{
|
|
|
- /* we provide an empty handler */
|
|
|
-}
|
|
|
-
|
|
|
-/* Note: a success call will increase reference count by one */
|
|
|
-struct device *acpi_get_physical_device(acpi_handle handle)
|
|
|
-{
|
|
|
- acpi_status status;
|
|
|
- struct device *dev;
|
|
|
-
|
|
|
- status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev);
|
|
|
- if (ACPI_SUCCESS(status))
|
|
|
- return get_device(dev);
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-EXPORT_SYMBOL(acpi_get_physical_device);
|
|
|
-
|
|
|
static int acpi_bind_one(struct device *dev, acpi_handle handle)
|
|
|
{
|
|
|
struct acpi_device *acpi_dev;
|
|
|
acpi_status status;
|
|
|
+ struct acpi_device_physical_node *physical_node;
|
|
|
+ char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
|
|
|
+ int retval = -EINVAL;
|
|
|
|
|
|
if (dev->archdata.acpi_handle) {
|
|
|
dev_warn(dev, "Drivers changed 'acpi_handle'\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
+
|
|
|
get_device(dev);
|
|
|
- status = acpi_attach_data(handle, acpi_glue_data_handler, dev);
|
|
|
- if (ACPI_FAILURE(status)) {
|
|
|
- put_device(dev);
|
|
|
- return -EINVAL;
|
|
|
+ status = acpi_bus_get_device(handle, &acpi_dev);
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ physical_node = kzalloc(sizeof(struct acpi_device_physical_node),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!physical_node) {
|
|
|
+ retval = -ENOMEM;
|
|
|
+ goto err;
|
|
|
}
|
|
|
- dev->archdata.acpi_handle = handle;
|
|
|
|
|
|
- status = acpi_bus_get_device(handle, &acpi_dev);
|
|
|
- if (!ACPI_FAILURE(status)) {
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
|
|
|
- "firmware_node");
|
|
|
- ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
|
|
|
- "physical_node");
|
|
|
- if (acpi_dev->wakeup.flags.valid)
|
|
|
- device_set_wakeup_capable(dev, true);
|
|
|
+ mutex_lock(&acpi_dev->physical_node_lock);
|
|
|
+ /* allocate physical node id according to physical_node_id_bitmap */
|
|
|
+ physical_node->node_id =
|
|
|
+ find_first_zero_bit(acpi_dev->physical_node_id_bitmap,
|
|
|
+ ACPI_MAX_PHYSICAL_NODE);
|
|
|
+ if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
|
|
|
+ retval = -ENOSPC;
|
|
|
+ mutex_unlock(&acpi_dev->physical_node_lock);
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
+ set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap);
|
|
|
+ physical_node->dev = dev;
|
|
|
+ list_add_tail(&physical_node->node, &acpi_dev->physical_node_list);
|
|
|
+ acpi_dev->physical_node_count++;
|
|
|
+ mutex_unlock(&acpi_dev->physical_node_lock);
|
|
|
+
|
|
|
+ dev->archdata.acpi_handle = handle;
|
|
|
+
|
|
|
+ if (!physical_node->node_id)
|
|
|
+ strcpy(physical_node_name, PHYSICAL_NODE_STRING);
|
|
|
+ else
|
|
|
+ sprintf(physical_node_name,
|
|
|
+ "physical_node%d", physical_node->node_id);
|
|
|
+ retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
|
|
|
+ physical_node_name);
|
|
|
+ retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
|
|
|
+ "firmware_node");
|
|
|
+
|
|
|
+ if (acpi_dev->wakeup.flags.valid)
|
|
|
+ device_set_wakeup_capable(dev, true);
|
|
|
+
|
|
|
return 0;
|
|
|
+
|
|
|
+ err:
|
|
|
+ put_device(dev);
|
|
|
+ return retval;
|
|
|
}
|
|
|
|
|
|
static int acpi_unbind_one(struct device *dev)
|
|
|
{
|
|
|
+ struct acpi_device_physical_node *entry;
|
|
|
+ struct acpi_device *acpi_dev;
|
|
|
+ acpi_status status;
|
|
|
+ struct list_head *node, *next;
|
|
|
+
|
|
|
if (!dev->archdata.acpi_handle)
|
|
|
return 0;
|
|
|
- if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
|
|
|
- struct acpi_device *acpi_dev;
|
|
|
|
|
|
- /* acpi_get_physical_device increase refcnt by one */
|
|
|
- put_device(dev);
|
|
|
+ status = acpi_bus_get_device(dev->archdata.acpi_handle,
|
|
|
+ &acpi_dev);
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
+ goto err;
|
|
|
|
|
|
- if (!acpi_bus_get_device(dev->archdata.acpi_handle,
|
|
|
- &acpi_dev)) {
|
|
|
- sysfs_remove_link(&dev->kobj, "firmware_node");
|
|
|
- sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node");
|
|
|
- }
|
|
|
+ mutex_lock(&acpi_dev->physical_node_lock);
|
|
|
+ list_for_each_safe(node, next, &acpi_dev->physical_node_list) {
|
|
|
+ char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
|
|
|
+
|
|
|
+ entry = list_entry(node, struct acpi_device_physical_node,
|
|
|
+ node);
|
|
|
+ if (entry->dev != dev)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ list_del(node);
|
|
|
+ clear_bit(entry->node_id, acpi_dev->physical_node_id_bitmap);
|
|
|
|
|
|
- acpi_detach_data(dev->archdata.acpi_handle,
|
|
|
- acpi_glue_data_handler);
|
|
|
+ acpi_dev->physical_node_count--;
|
|
|
+
|
|
|
+ if (!entry->node_id)
|
|
|
+ strcpy(physical_node_name, PHYSICAL_NODE_STRING);
|
|
|
+ else
|
|
|
+ sprintf(physical_node_name,
|
|
|
+ "physical_node%d", entry->node_id);
|
|
|
+
|
|
|
+ sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name);
|
|
|
+ sysfs_remove_link(&dev->kobj, "firmware_node");
|
|
|
dev->archdata.acpi_handle = NULL;
|
|
|
/* acpi_bind_one increase refcnt by one */
|
|
|
put_device(dev);
|
|
|
- } else {
|
|
|
- dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
|
|
|
+ kfree(entry);
|
|
|
}
|
|
|
+ mutex_unlock(&acpi_dev->physical_node_lock);
|
|
|
+
|
|
|
return 0;
|
|
|
+
|
|
|
+err:
|
|
|
+ dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
static int acpi_platform_notify(struct device *dev)
|