Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 336622
b: refs/heads/master
c: 8e345c9
h: refs/heads/master
v: v3
  • Loading branch information
Rafael J. Wysocki committed Nov 14, 2012
1 parent c30984e commit 324678a
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 78 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 97d69dc061e968b5e9e56f48bb223b9ab7764b48
refs/heads/master: 8e345c991c8c7a3c081199ef77deada79e37618a
94 changes: 17 additions & 77 deletions trunk/drivers/acpi/acpi_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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));
Expand All @@ -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;
}

Expand Down
134 changes: 134 additions & 0 deletions trunk/drivers/acpi/resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/device.h>
#include <linux/export.h>
#include <linux/ioport.h>
#include <linux/slab.h>

#ifdef CONFIG_X86
#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
Expand Down Expand Up @@ -391,3 +392,136 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
return true;
}
EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);

/**
* acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources().
* @list: The head of the resource list to free.
*/
void acpi_dev_free_resource_list(struct list_head *list)
{
struct resource_list_entry *rentry, *re;

list_for_each_entry_safe(rentry, re, list, node) {
list_del(&rentry->node);
kfree(rentry);
}
}
EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);

struct res_proc_context {
struct list_head *list;
int (*preproc)(struct acpi_resource *, void *);
void *preproc_data;
int count;
int error;
};

static acpi_status acpi_dev_new_resource_entry(struct resource *r,
struct res_proc_context *c)
{
struct resource_list_entry *rentry;

rentry = kmalloc(sizeof(*rentry), GFP_KERNEL);
if (!rentry) {
c->error = -ENOMEM;
return AE_NO_MEMORY;
}
INIT_LIST_HEAD(&rentry->node);
rentry->res = *r;
list_add_tail(&rentry->node, c->list);
c->count++;
return AE_OK;
}

static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
void *context)
{
struct res_proc_context *c = context;
struct resource r;
int i;

if (c->preproc) {
int ret;

ret = c->preproc(ares, c->preproc_data);
if (ret < 0) {
c->error = ret;
return AE_ABORT_METHOD;
} else if (ret > 0) {
return AE_OK;
}
}

memset(&r, 0, sizeof(r));

if (acpi_dev_resource_memory(ares, &r)
|| acpi_dev_resource_io(ares, &r)
|| acpi_dev_resource_address_space(ares, &r)
|| acpi_dev_resource_ext_address_space(ares, &r))
return acpi_dev_new_resource_entry(&r, c);

for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) {
acpi_status status;

status = acpi_dev_new_resource_entry(&r, c);
if (ACPI_FAILURE(status))
return status;
}

return AE_OK;
}

/**
* acpi_dev_get_resources - Get current resources of a device.
* @adev: ACPI device node to get the resources for.
* @list: Head of the resultant list of resources (must be empty).
* @preproc: The caller's preprocessing routine.
* @preproc_data: Pointer passed to the caller's preprocessing routine.
*
* Evaluate the _CRS method for the given device node and process its output by
* (1) executing the @preproc() rountine provided by the caller, passing the
* resource pointer and @preproc_data to it as arguments, for each ACPI resource
* returned and (2) converting all of the returned ACPI resources into struct
* resource objects if possible. If the return value of @preproc() in step (1)
* is different from 0, step (2) is not applied to the given ACPI resource and
* if that value is negative, the whole processing is aborted and that value is
* returned as the final error code.
*
* The resultant struct resource objects are put on the list pointed to by
* @list, that must be empty initially, as members of struct resource_list_entry
* objects. Callers of this routine should use %acpi_dev_free_resource_list() to
* free that list.
*
* The number of resources in the output list is returned on success, an error
* code reflecting the error condition is returned otherwise.
*/
int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
int (*preproc)(struct acpi_resource *, void *),
void *preproc_data)
{
struct res_proc_context c;
acpi_handle not_used;
acpi_status status;

if (!adev || !adev->handle || !list_empty(list))
return -EINVAL;

status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, &not_used);
if (ACPI_FAILURE(status))
return 0;

c.list = list;
c.preproc = preproc;
c.preproc_data = preproc_data;
c.count = 0;
c.error = 0;
status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
acpi_dev_process_resource, &c);
if (ACPI_FAILURE(status)) {
acpi_dev_free_resource_list(list);
return c.error ? c.error : -EIO;
}

return c.count;
}
EXPORT_SYMBOL_GPL(acpi_dev_get_resources);
10 changes: 10 additions & 0 deletions trunk/include/linux/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,16 @@ 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);

struct resource_list_entry {
struct list_head node;
struct resource res;
};

void acpi_dev_free_resource_list(struct list_head *list);
int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
int (*preproc)(struct acpi_resource *, void *),
void *preproc_data);

int acpi_check_resource_conflict(const struct resource *res);

int acpi_check_region(resource_size_t start, resource_size_t n,
Expand Down

0 comments on commit 324678a

Please sign in to comment.