lkml.org 
[lkml]   [2012]   [Nov]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 3/3] ACPI: Evaluate _CRS while creating device node objects
Date
From: Rafael J. Wysocki <rafael.j.wysocki@intel.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@intel.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, &not_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);



\
 
 \ /
  Last update: 2012-11-12 13:41    [W:0.400 / U:1.944 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site