summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/resource.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-14 18:30:21 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-14 18:30:21 -0500
commit8e345c991c8c7a3c081199ef77deada79e37618a (patch)
tree9ea6b8ee785146eabbb75403926f0fc6d7c68ee1 /drivers/acpi/resource.c
parent97d69dc061e968b5e9e56f48bb223b9ab7764b48 (diff)
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/resource.c')
-rw-r--r--drivers/acpi/resource.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 3e7fd349e29d..2bafc25482b3 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -26,6 +26,7 @@
26#include <linux/device.h> 26#include <linux/device.h>
27#include <linux/export.h> 27#include <linux/export.h>
28#include <linux/ioport.h> 28#include <linux/ioport.h>
29#include <linux/slab.h>
29 30
30#ifdef CONFIG_X86 31#ifdef CONFIG_X86
31#define valid_IRQ(i) (((i) != 0) && ((i) != 2)) 32#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
@@ -391,3 +392,136 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
391 return true; 392 return true;
392} 393}
393EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); 394EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
395
396/**
397 * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources().
398 * @list: The head of the resource list to free.
399 */
400void acpi_dev_free_resource_list(struct list_head *list)
401{
402 struct resource_list_entry *rentry, *re;
403
404 list_for_each_entry_safe(rentry, re, list, node) {
405 list_del(&rentry->node);
406 kfree(rentry);
407 }
408}
409EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);
410
411struct res_proc_context {
412 struct list_head *list;
413 int (*preproc)(struct acpi_resource *, void *);
414 void *preproc_data;
415 int count;
416 int error;
417};
418
419static acpi_status acpi_dev_new_resource_entry(struct resource *r,
420 struct res_proc_context *c)
421{
422 struct resource_list_entry *rentry;
423
424 rentry = kmalloc(sizeof(*rentry), GFP_KERNEL);
425 if (!rentry) {
426 c->error = -ENOMEM;
427 return AE_NO_MEMORY;
428 }
429 INIT_LIST_HEAD(&rentry->node);
430 rentry->res = *r;
431 list_add_tail(&rentry->node, c->list);
432 c->count++;
433 return AE_OK;
434}
435
436static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
437 void *context)
438{
439 struct res_proc_context *c = context;
440 struct resource r;
441 int i;
442
443 if (c->preproc) {
444 int ret;
445
446 ret = c->preproc(ares, c->preproc_data);
447 if (ret < 0) {
448 c->error = ret;
449 return AE_ABORT_METHOD;
450 } else if (ret > 0) {
451 return AE_OK;
452 }
453 }
454
455 memset(&r, 0, sizeof(r));
456
457 if (acpi_dev_resource_memory(ares, &r)
458 || acpi_dev_resource_io(ares, &r)
459 || acpi_dev_resource_address_space(ares, &r)
460 || acpi_dev_resource_ext_address_space(ares, &r))
461 return acpi_dev_new_resource_entry(&r, c);
462
463 for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) {
464 acpi_status status;
465
466 status = acpi_dev_new_resource_entry(&r, c);
467 if (ACPI_FAILURE(status))
468 return status;
469 }
470
471 return AE_OK;
472}
473
474/**
475 * acpi_dev_get_resources - Get current resources of a device.
476 * @adev: ACPI device node to get the resources for.
477 * @list: Head of the resultant list of resources (must be empty).
478 * @preproc: The caller's preprocessing routine.
479 * @preproc_data: Pointer passed to the caller's preprocessing routine.
480 *
481 * Evaluate the _CRS method for the given device node and process its output by
482 * (1) executing the @preproc() rountine provided by the caller, passing the
483 * resource pointer and @preproc_data to it as arguments, for each ACPI resource
484 * returned and (2) converting all of the returned ACPI resources into struct
485 * resource objects if possible. If the return value of @preproc() in step (1)
486 * is different from 0, step (2) is not applied to the given ACPI resource and
487 * if that value is negative, the whole processing is aborted and that value is
488 * returned as the final error code.
489 *
490 * The resultant struct resource objects are put on the list pointed to by
491 * @list, that must be empty initially, as members of struct resource_list_entry
492 * objects. Callers of this routine should use %acpi_dev_free_resource_list() to
493 * free that list.
494 *
495 * The number of resources in the output list is returned on success, an error
496 * code reflecting the error condition is returned otherwise.
497 */
498int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
499 int (*preproc)(struct acpi_resource *, void *),
500 void *preproc_data)
501{
502 struct res_proc_context c;
503 acpi_handle not_used;
504 acpi_status status;
505
506 if (!adev || !adev->handle || !list_empty(list))
507 return -EINVAL;
508
509 status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, &not_used);
510 if (ACPI_FAILURE(status))
511 return 0;
512
513 c.list = list;
514 c.preproc = preproc;
515 c.preproc_data = preproc_data;
516 c.count = 0;
517 c.error = 0;
518 status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
519 acpi_dev_process_resource, &c);
520 if (ACPI_FAILURE(status)) {
521 acpi_dev_free_resource_list(list);
522 return c.error ? c.error : -EIO;
523 }
524
525 return c.count;
526}
527EXPORT_SYMBOL_GPL(acpi_dev_get_resources);