[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <11281928.0BBlrNprhI@vostro.rjw.lan>
Date: Mon, 12 Nov 2012 13:02:11 +0100
From: "Rafael J. Wysocki" <rjw@...k.pl>
To: Mika Westerberg <mika.westerberg@...ux.intel.com>
Cc: mathias.nyman@...ux.intel.com, linux-acpi@...r.kernel.org,
linux-kernel@...r.kernel.org, lenb@...nel.org,
rafael.j.wysocki@...el.com, broonie@...nsource.wolfsonmicro.com,
grant.likely@...retlab.ca, linus.walleij@...aro.org,
khali@...ux-fr.org, Bjorn Helgaas <bhelgaas@...gle.com>
Subject: [PATCH 3/3] ACPI: Evaluate _CRS while creating device node objects
From: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
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.
For this reason, add code to the ACPI core to execute _CRS once,
when the struct acpi_device object is created for a given device
node, and attach a list of ACPI resources returned by _CRS to that
object for future processing.
Convert the ACPI code that creates platform device objects to using
the new resources list instead of executing acpi_walk_resources() by
itself, which makes it much more straightforward and easier to
follow.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
---
drivers/acpi/acpi_platform.c | 90 ++++++++++++-------------------------------
drivers/acpi/resource.c | 12 +++++
drivers/acpi/scan.c | 56 ++++++++++++++++++++++++++
include/acpi/acpi_bus.h | 6 ++
include/linux/acpi.h | 1
5 files changed, 102 insertions(+), 63 deletions(-)
Index: linux/include/acpi/acpi_bus.h
===================================================================
--- linux.orig/include/acpi/acpi_bus.h
+++ linux/include/acpi/acpi_bus.h
@@ -259,6 +259,11 @@ struct acpi_device_physical_node {
struct device *dev;
};
+struct acpi_resource_list_entry {
+ struct list_head node;
+ struct acpi_resource resource;
+};
+
/* set maximum of physical nodes to 32 for expansibility */
#define ACPI_MAX_PHYSICAL_NODE 32
@@ -268,6 +273,7 @@ struct acpi_device {
acpi_handle handle; /* no handle for fixed hardware */
struct acpi_device *parent;
struct list_head children;
+ struct list_head resources; /* Device resources. */
struct list_head node;
struct list_head wakeup_list;
struct acpi_device_status status;
Index: linux/drivers/acpi/scan.c
===================================================================
--- linux.orig/drivers/acpi/scan.c
+++ linux/drivers/acpi/scan.c
@@ -382,6 +382,52 @@ static void acpi_device_remove_files(str
ACPI Bus operations
-------------------------------------------------------------------------- */
+static void acpi_bus_drop_resources(struct acpi_device *adev)
+{
+ struct acpi_resource_list_entry *entry, *s;
+
+ list_for_each_entry_safe(entry, s, &adev->resources, node) {
+ list_del(&entry->node);
+ kfree(entry);
+ }
+}
+
+static acpi_status acpi_bus_add_resource(struct acpi_resource *res,
+ void *context)
+{
+ struct list_head *list = context;
+ struct acpi_resource_list_entry *entry;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return AE_NO_MEMORY;
+
+ entry->resource = *res;
+ INIT_LIST_HEAD(&entry->node);
+ list_add_tail(&entry->node, list);
+ return AE_OK;
+}
+
+static int acpi_bus_get_resources(struct acpi_device *adev)
+{
+ acpi_status status;
+ acpi_handle not_used;
+ int ret = 0;
+
+ status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, ¬_used);
+ if (ACPI_FAILURE(status))
+ return 0;
+
+ status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
+ acpi_bus_add_resource, &adev->resources);
+ if (ACPI_FAILURE(status)) {
+ acpi_bus_drop_resources(adev);
+ ret = status == AE_NO_MEMORY ? -ENOMEM : -EIO;
+ }
+
+ return ret;
+}
+
static const struct acpi_device_id *__acpi_match_device(
struct acpi_device *device, const struct acpi_device_id *ids)
{
@@ -681,6 +727,7 @@ static void acpi_device_unregister(struc
acpi_device_remove_files(device);
device_unregister(&device->dev);
+ acpi_bus_drop_resources(device);
}
/* --------------------------------------------------------------------------
@@ -1412,6 +1459,15 @@ static int acpi_add_single_object(struct
acpi_device_set_id(device);
/*
+ * Device Resources
+ * ----------------
+ */
+ INIT_LIST_HEAD(&device->resources);
+ result = acpi_bus_get_resources(device);
+ if (result)
+ goto end;
+
+ /*
* Power Management
* ----------------
*/
Index: linux/drivers/acpi/resource.c
===================================================================
--- linux.orig/drivers/acpi/resource.c
+++ linux/drivers/acpi/resource.c
@@ -391,3 +391,15 @@ bool acpi_dev_resource_interrupt(struct
return true;
}
EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
+
+unsigned int acpi_dev_resource_count(struct acpi_resource *ares)
+{
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ return ares->data.irq.interrupt_count;
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ return ares->data.extended_irq.interrupt_count;
+ }
+ return 1;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_resource_count);
Index: linux/drivers/acpi/acpi_platform.c
===================================================================
--- linux.orig/drivers/acpi/acpi_platform.c
+++ linux/drivers/acpi/acpi_platform.c
@@ -19,59 +19,26 @@
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)
+static unsigned int acpi_platform_add_resource(struct acpi_resource *res,
+ struct resource *r)
{
- 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;
- }
+ || acpi_dev_resource_ext_address_space(res, r))
+ return 1;
+
if (acpi_dev_resource_interrupt(res, 0, r)) {
- int i;
+ unsigned int i;
r++;
for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++)
r++;
- ri->cur += i;
+ return i;
}
- return AE_OK;
+
+ return 0;
}
/**
@@ -89,35 +56,32 @@ struct platform_device *acpi_create_plat
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
struct device *parent = NULL;
- struct resource_info ri;
- acpi_status status;
+ struct acpi_resource_list_entry *entry;
+ struct resource *resources;
+ unsigned 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)
+ count = 0;
+ list_for_each_entry(entry, &adev->resources, node)
+ count += acpi_dev_resource_count(&entry->resource);
+
+ if (!count)
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 = kzalloc(count * sizeof(struct resource), GFP_KERNEL);
+ if (!resources) {
+ dev_err(&adev->dev, "No memory for resources\n");
return NULL;
}
- 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;
- }
+ count = 0;
+ list_for_each_entry(entry, &adev->resources, node)
+ count += acpi_platform_add_resource(&entry->resource,
+ resources + count);
/*
* If the ACPI node has a parent and that parent has a physical device
@@ -139,8 +103,9 @@ struct platform_device *acpi_create_plat
}
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 +115,7 @@ struct platform_device *acpi_create_plat
dev_name(&pdev->dev));
}
- out:
- kfree(ri.res);
+ kfree(resources);
return pdev;
}
Index: linux/include/linux/acpi.h
===================================================================
--- linux.orig/include/linux/acpi.h
+++ linux/include/linux/acpi.h
@@ -260,6 +260,7 @@ bool acpi_dev_resource_ext_address_space
unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable);
bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
struct resource *res);
+unsigned int acpi_dev_resource_count(struct acpi_resource *ares);
int acpi_check_resource_conflict(const struct resource *res);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists