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)
 
 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)
 
        list_for_each_safe(node, next, &acpi_wakeup_device_list) {
                struct acpi_device *dev =
                    container_of(node, struct acpi_device, wakeup_list);
-               struct device *ldev;
+               struct acpi_device_physical_node *entry;
 
                if (!dev->wakeup.flags.valid)
                        continue;
 
-               ldev = acpi_get_physical_device(dev->handle);
-               seq_printf(seq, "%s\t  S%d\t%c%-8s  ",
+               seq_printf(seq, "%s\t  S%d\t",
                           dev->pnp.bus_id,
-                          (u32) dev->wakeup.sleep_state,
-                          dev->wakeup.flags.run_wake ? '*' : ' ',
-                          (device_may_wakeup(&dev->dev)
-                            || (ldev && device_may_wakeup(ldev))) ?
-                              "enabled" : "disabled");
-               if (ldev)
-                       seq_printf(seq, "%s:%s",
-                                  ldev->bus ? ldev->bus->name : "no-bus",
-                                  dev_name(ldev));
-               seq_printf(seq, "\n");
-               put_device(ldev);
-
+                          (u32) dev->wakeup.sleep_state);
+
+               if (!dev->physical_node_count)
+                       seq_printf(seq, "%c%-8s\n",
+                               dev->wakeup.flags.run_wake ?
+                               '*' : ' ', "disabled");
+               else {
+                       struct device *ldev;
+                       list_for_each_entry(entry, &dev->physical_node_list,
+                                       node) {
+                               ldev = get_device(entry->dev);
+                               if (!ldev)
+                                       continue;
+
+                               if (&entry->node !=
+                                               dev->physical_node_list.next)
+                                       seq_printf(seq, "\t\t");
+
+                               seq_printf(seq, "%c%-8s  %s:%s\n",
+                                       dev->wakeup.flags.run_wake ? '*' : ' ',
+                                       (device_may_wakeup(&dev->dev) ||
+                                       (ldev && device_may_wakeup(ldev))) ?
+                                       "enabled" : "disabled",
+                                       ldev->bus ? ldev->bus->name :
+                                       "no-bus", dev_name(ldev));
+                               put_device(ldev);
+                       }
+               }
        }
        mutex_unlock(&acpi_device_lock);
        return 0;
 
 static void physical_device_enable_wakeup(struct acpi_device *adev)
 {
-       struct device *dev = acpi_get_physical_device(adev->handle);
+       struct acpi_device_physical_node *entry;
 
-       if (dev && device_can_wakeup(dev)) {
-               bool enable = !device_may_wakeup(dev);
-               device_set_wakeup_enable(dev, enable);
-       }
+       list_for_each_entry(entry,
+               &adev->physical_node_list, node)
+               if (entry->dev && device_can_wakeup(entry->dev)) {
+                       bool enable = !device_may_wakeup(entry->dev);
+                       device_set_wakeup_enable(entry->dev, enable);
+               }
 }
 
 static ssize_t