aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-20 18:21:59 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-20 18:21:59 -0500
commit863f9f30e6c1e30cb19a0cd17c5cf8879257dfd7 (patch)
tree774ce5240f210f60fe20c3454bc5a8520633d8ba
parent95f8a082b9b1ead0c2859f2a7b1ac91ff63d8765 (diff)
ACPI / platform: Initialize ACPI handles of platform devices in advance
The current platform device creation and registration code in acpi_create_platform_device() is quite convoluted. This function takes an ACPI device node as an argument and eventually calls platform_device_register_resndata() to create and register a platform device object on the basis of the information contained in that code. However, it doesn't associate the new platform device with the ACPI node directly, but instead it relies on acpi_platform_notify(), called from within device_add(), to find that ACPI node again with the help of acpi_platform_find_device() and acpi_platform_match() and then attach the new platform device to it. This causes an additional ACPI namespace walk to happen and is clearly suboptimal. Use the observation that it is now possible to initialize the ACPI handle of a device before calling device_add() for it to make this code more straightforward. Namely, add a new field to struct platform_device_info allowing us to pass the ACPI handle of interest to platform_device_register_full(), which will then use it to initialize the new device's ACPI handle before registering it. This will cause acpi_platform_notify() to use the ACPI handle from the device structure directly instead of using the .find_device() routine provided by the device's bus type. In consequence, acpi_platform_bus, acpi_platform_find_device(), and acpi_platform_match() are not necessary any more, so remove them. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/acpi/acpi_platform.c76
-rw-r--r--drivers/base/platform.c2
-rw-r--r--include/linux/platform_device.h1
3 files changed, 13 insertions, 66 deletions
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 7ac20d8b8f07..b7df9b197bcf 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -33,7 +33,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
33{ 33{
34 struct platform_device *pdev = NULL; 34 struct platform_device *pdev = NULL;
35 struct acpi_device *acpi_parent; 35 struct acpi_device *acpi_parent;
36 struct device *parent = NULL; 36 struct platform_device_info pdevinfo;
37 struct resource_list_entry *rentry; 37 struct resource_list_entry *rentry;
38 struct list_head resource_list; 38 struct list_head resource_list;
39 struct resource *resources; 39 struct resource *resources;
@@ -60,11 +60,13 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
60 60
61 acpi_dev_free_resource_list(&resource_list); 61 acpi_dev_free_resource_list(&resource_list);
62 62
63 memset(&pdevinfo, 0, sizeof(pdevinfo));
63 /* 64 /*
64 * If the ACPI node has a parent and that parent has a physical device 65 * If the ACPI node has a parent and that parent has a physical device
65 * attached to it, that physical device should be the parent of the 66 * attached to it, that physical device should be the parent of the
66 * platform device we are about to create. 67 * platform device we are about to create.
67 */ 68 */
69 pdevinfo.parent = NULL;
68 acpi_parent = adev->parent; 70 acpi_parent = adev->parent;
69 if (acpi_parent) { 71 if (acpi_parent) {
70 struct acpi_device_physical_node *entry; 72 struct acpi_device_physical_node *entry;
@@ -76,12 +78,16 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
76 entry = list_first_entry(list, 78 entry = list_first_entry(list,
77 struct acpi_device_physical_node, 79 struct acpi_device_physical_node,
78 node); 80 node);
79 parent = entry->dev; 81 pdevinfo.parent = entry->dev;
80 } 82 }
81 mutex_unlock(&acpi_parent->physical_node_lock); 83 mutex_unlock(&acpi_parent->physical_node_lock);
82 } 84 }
83 pdev = platform_device_register_resndata(parent, dev_name(&adev->dev), 85 pdevinfo.name = dev_name(&adev->dev);
84 -1, resources, count, NULL, 0); 86 pdevinfo.id = -1;
87 pdevinfo.res = resources;
88 pdevinfo.num_res = count;
89 pdevinfo.acpi_node.handle = adev->handle;
90 pdev = platform_device_register_full(&pdevinfo);
85 if (IS_ERR(pdev)) { 91 if (IS_ERR(pdev)) {
86 dev_err(&adev->dev, "platform device creation failed: %ld\n", 92 dev_err(&adev->dev, "platform device creation failed: %ld\n",
87 PTR_ERR(pdev)); 93 PTR_ERR(pdev));
@@ -94,65 +100,3 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
94 kfree(resources); 100 kfree(resources);
95 return pdev; 101 return pdev;
96} 102}
97
98static acpi_status acpi_platform_match(acpi_handle handle, u32 depth,
99 void *data, void **return_value)
100{
101 struct platform_device *pdev = data;
102 struct acpi_device *adev;
103 acpi_status status;
104
105 status = acpi_bus_get_device(handle, &adev);
106 if (ACPI_FAILURE(status))
107 return status;
108
109 /* Skip ACPI devices that have physical device attached */
110 if (adev->physical_node_count)
111 return AE_OK;
112
113 if (!strcmp(dev_name(&pdev->dev), dev_name(&adev->dev))) {
114 *(acpi_handle *)return_value = handle;
115 return AE_CTRL_TERMINATE;
116 }
117
118 return AE_OK;
119}
120
121static int acpi_platform_find_device(struct device *dev, acpi_handle *handle)
122{
123 struct platform_device *pdev = to_platform_device(dev);
124 char *name, *tmp, *hid;
125
126 /*
127 * The platform device is named using the ACPI device name
128 * _HID:INSTANCE so we strip the INSTANCE out in order to find the
129 * correct device using its _HID.
130 */
131 name = kstrdup(dev_name(dev), GFP_KERNEL);
132 if (!name)
133 return -ENOMEM;
134
135 tmp = name;
136 hid = strsep(&tmp, ":");
137 if (!hid) {
138 kfree(name);
139 return -ENODEV;
140 }
141
142 *handle = NULL;
143 acpi_get_devices(hid, acpi_platform_match, pdev, handle);
144
145 kfree(name);
146 return *handle ? 0 : -ENODEV;
147}
148
149static struct acpi_bus_type acpi_platform_bus = {
150 .bus = &platform_bus_type,
151 .find_device = acpi_platform_find_device,
152};
153
154static int __init acpi_platform_init(void)
155{
156 return register_acpi_bus_type(&acpi_platform_bus);
157}
158arch_initcall(acpi_platform_init);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 7de29ebfce7f..49fd96e23460 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -437,6 +437,7 @@ struct platform_device *platform_device_register_full(
437 goto err_alloc; 437 goto err_alloc;
438 438
439 pdev->dev.parent = pdevinfo->parent; 439 pdev->dev.parent = pdevinfo->parent;
440 ACPI_HANDLE_SET(&pdev->dev, pdevinfo->acpi_node.handle);
440 441
441 if (pdevinfo->dma_mask) { 442 if (pdevinfo->dma_mask) {
442 /* 443 /*
@@ -467,6 +468,7 @@ struct platform_device *platform_device_register_full(
467 ret = platform_device_add(pdev); 468 ret = platform_device_add(pdev);
468 if (ret) { 469 if (ret) {
469err: 470err:
471 ACPI_HANDLE_SET(&pdev->dev, NULL);
470 kfree(pdev->dev.dma_mask); 472 kfree(pdev->dev.dma_mask);
471 473
472err_alloc: 474err_alloc:
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 5711e9525a2a..a9ded9a3c175 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -55,6 +55,7 @@ extern int platform_add_devices(struct platform_device **, int);
55 55
56struct platform_device_info { 56struct platform_device_info {
57 struct device *parent; 57 struct device *parent;
58 struct acpi_dev_node acpi_node;
58 59
59 const char *name; 60 const char *name;
60 int id; 61 int id;