summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpi_platform.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-15 00:30:21 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-15 00:30:21 +0100
commit8e345c991c8c7a3c081199ef77deada79e37618a (patch)
tree9ea6b8ee785146eabbb75403926f0fc6d7c68ee1 /drivers/acpi/acpi_platform.c
parentACPI / platform: Use common ACPI device resource parsing routines (diff)
downloadlinux-8e345c991c8c7a3c081199ef77deada79e37618a.tar.xz
linux-8e345c991c8c7a3c081199ef77deada79e37618a.zip
ACPI: Centralized processing of ACPI device resources
Currently, whoever wants to use ACPI device resources has to call acpi_walk_resources() to browse the buffer returned by the _CRS method for the given device and create filters passed to that routine to apply to the individual resource items. This generally is cumbersome, time-consuming and inefficient. Moreover, it may be problematic if resource conflicts need to be resolved, because the different users of _CRS will need to do that in a consistent way. However, if there are resource conflicts, the ACPI core should be able to resolve them centrally instead of relying on various users of acpi_walk_resources() to handle them correctly together. For this reason, introduce a new function, acpi_dev_get_resources(), that can be used by subsystems to obtain a list of struct resource objects corresponding to the ACPI device resources returned by _CRS and, if necessary, to apply additional preprocessing routine to the ACPI resources before converting them to the struct resource format. Make the ACPI code that creates platform device objects use acpi_dev_get_resources() for resource processing instead of executing acpi_walk_resources() twice by itself, which causes it to be much more straightforward and easier to follow. In the future, acpi_dev_get_resources() can be extended to meet the needs of the ACPI PNP subsystem and other users of _CRS in the kernel. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/acpi/acpi_platform.c')
-rw-r--r--drivers/acpi/acpi_platform.c94
1 files changed, 17 insertions, 77 deletions
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index bcbb00ce6d99..7ac20d8b8f07 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -19,61 +19,6 @@
ACPI_MODULE_NAME("platform");
-struct resource_info {
- struct device *dev;
- struct resource *res;
- size_t n, cur;
-};
-
-static acpi_status acpi_platform_count_resources(struct acpi_resource *res,
- void *data)
-{
- struct acpi_resource_extended_irq *acpi_xirq;
- struct acpi_resource_irq *acpi_irq;
- struct resource_info *ri = data;
-
- switch (res->type) {
- case ACPI_RESOURCE_TYPE_IRQ:
- acpi_irq = &res->data.irq;
- ri->n += acpi_irq->interrupt_count;
- break;
- case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- acpi_xirq = &res->data.extended_irq;
- ri->n += acpi_xirq->interrupt_count;
- break;
- default:
- ri->n++;
- }
-
- return AE_OK;
-}
-
-static acpi_status acpi_platform_add_resources(struct acpi_resource *res,
- void *data)
-{
- struct resource_info *ri = data;
- struct resource *r;
-
- r = ri->res + ri->cur;
- if (acpi_dev_resource_memory(res, r)
- || acpi_dev_resource_io(res, r)
- || acpi_dev_resource_address_space(res, r)
- || acpi_dev_resource_ext_address_space(res, r)) {
- ri->cur++;
- return AE_OK;
- }
- if (acpi_dev_resource_interrupt(res, 0, r)) {
- int i;
-
- r++;
- for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++)
- r++;
-
- ri->cur += i;
- }
- return AE_OK;
-}
-
/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
@@ -89,35 +34,31 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
struct device *parent = NULL;
- struct resource_info ri;
- acpi_status status;
+ struct resource_list_entry *rentry;
+ struct list_head resource_list;
+ struct resource *resources;
+ int count;
/* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count)
return NULL;
- memset(&ri, 0, sizeof(ri));
- /* First, count the resources. */
- status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
- acpi_platform_count_resources, &ri);
- if (ACPI_FAILURE(status) || !ri.n)
+ INIT_LIST_HEAD(&resource_list);
+ count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+ if (count <= 0)
return NULL;
- /* Next, allocate memory for all the resources and populate it. */
- ri.dev = &adev->dev;
- ri.res = kzalloc(ri.n * sizeof(struct resource), GFP_KERNEL);
- if (!ri.res) {
- dev_err(&adev->dev,
- "failed to allocate memory for resources\n");
+ resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
+ if (!resources) {
+ dev_err(&adev->dev, "No memory for resources\n");
+ acpi_dev_free_resource_list(&resource_list);
return NULL;
}
+ count = 0;
+ list_for_each_entry(rentry, &resource_list, node)
+ resources[count++] = rentry->res;
- status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
- acpi_platform_add_resources, &ri);
- if (ACPI_FAILURE(status)) {
- dev_err(&adev->dev, "failed to walk resources\n");
- goto out;
- }
+ acpi_dev_free_resource_list(&resource_list);
/*
* If the ACPI node has a parent and that parent has a physical device
@@ -140,7 +81,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
mutex_unlock(&acpi_parent->physical_node_lock);
}
pdev = platform_device_register_resndata(parent, dev_name(&adev->dev),
- -1, ri.res, ri.cur, NULL, 0);
+ -1, resources, count, NULL, 0);
if (IS_ERR(pdev)) {
dev_err(&adev->dev, "platform device creation failed: %ld\n",
PTR_ERR(pdev));
@@ -150,8 +91,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
dev_name(&pdev->dev));
}
- out:
- kfree(ri.res);
+ kfree(resources);
return pdev;
}