|
@@ -26,7 +26,6 @@
|
|
|
#include <linux/device.h>
|
|
|
#include <linux/export.h>
|
|
|
#include <linux/ioport.h>
|
|
|
-#include <linux/list.h>
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
#ifdef CONFIG_X86
|
|
@@ -622,164 +621,3 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
|
|
|
return (type & types) ? 0 : 1;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
|
|
|
-
|
|
|
-struct reserved_region {
|
|
|
- struct list_head node;
|
|
|
- u64 start;
|
|
|
- u64 end;
|
|
|
-};
|
|
|
-
|
|
|
-static LIST_HEAD(reserved_io_regions);
|
|
|
-static LIST_HEAD(reserved_mem_regions);
|
|
|
-
|
|
|
-static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags,
|
|
|
- char *desc)
|
|
|
-{
|
|
|
- unsigned int length = end - start + 1;
|
|
|
- struct resource *res;
|
|
|
-
|
|
|
- res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ?
|
|
|
- request_region(start, length, desc) :
|
|
|
- request_mem_region(start, length, desc);
|
|
|
- if (!res)
|
|
|
- return -EIO;
|
|
|
-
|
|
|
- res->flags &= ~flags;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int add_region_before(u64 start, u64 end, u8 space_id,
|
|
|
- unsigned long flags, char *desc,
|
|
|
- struct list_head *head)
|
|
|
-{
|
|
|
- struct reserved_region *reg;
|
|
|
- int error;
|
|
|
-
|
|
|
- reg = kmalloc(sizeof(*reg), GFP_KERNEL);
|
|
|
- if (!reg)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- error = request_range(start, end, space_id, flags, desc);
|
|
|
- if (error) {
|
|
|
- kfree(reg);
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- reg->start = start;
|
|
|
- reg->end = end;
|
|
|
- list_add_tail(®->node, head);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * acpi_reserve_region - Reserve an I/O or memory region as a system resource.
|
|
|
- * @start: Starting address of the region.
|
|
|
- * @length: Length of the region.
|
|
|
- * @space_id: Identifier of address space to reserve the region from.
|
|
|
- * @flags: Resource flags to clear for the region after requesting it.
|
|
|
- * @desc: Region description (for messages).
|
|
|
- *
|
|
|
- * Reserve an I/O or memory region as a system resource to prevent others from
|
|
|
- * using it. If the new region overlaps with one of the regions (in the given
|
|
|
- * address space) already reserved by this routine, only the non-overlapping
|
|
|
- * parts of it will be reserved.
|
|
|
- *
|
|
|
- * Returned is either 0 (success) or a negative error code indicating a resource
|
|
|
- * reservation problem. It is the code of the first encountered error, but the
|
|
|
- * routine doesn't abort until it has attempted to request all of the parts of
|
|
|
- * the new region that don't overlap with other regions reserved previously.
|
|
|
- *
|
|
|
- * The resources requested by this routine are never released.
|
|
|
- */
|
|
|
-int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
|
|
|
- unsigned long flags, char *desc)
|
|
|
-{
|
|
|
- struct list_head *regions;
|
|
|
- struct reserved_region *reg;
|
|
|
- u64 end = start + length - 1;
|
|
|
- int ret = 0, error = 0;
|
|
|
-
|
|
|
- if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
|
|
|
- regions = &reserved_io_regions;
|
|
|
- else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
|
|
- regions = &reserved_mem_regions;
|
|
|
- else
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (list_empty(regions))
|
|
|
- return add_region_before(start, end, space_id, flags, desc, regions);
|
|
|
-
|
|
|
- list_for_each_entry(reg, regions, node)
|
|
|
- if (reg->start == end + 1) {
|
|
|
- /* The new region can be prepended to this one. */
|
|
|
- ret = request_range(start, end, space_id, flags, desc);
|
|
|
- if (!ret)
|
|
|
- reg->start = start;
|
|
|
-
|
|
|
- return ret;
|
|
|
- } else if (reg->start > end) {
|
|
|
- /* No overlap. Add the new region here and get out. */
|
|
|
- return add_region_before(start, end, space_id, flags,
|
|
|
- desc, ®->node);
|
|
|
- } else if (reg->end == start - 1) {
|
|
|
- goto combine;
|
|
|
- } else if (reg->end >= start) {
|
|
|
- goto overlap;
|
|
|
- }
|
|
|
-
|
|
|
- /* The new region goes after the last existing one. */
|
|
|
- return add_region_before(start, end, space_id, flags, desc, regions);
|
|
|
-
|
|
|
- overlap:
|
|
|
- /*
|
|
|
- * The new region overlaps an existing one.
|
|
|
- *
|
|
|
- * The head part of the new region immediately preceding the existing
|
|
|
- * overlapping one can be combined with it right away.
|
|
|
- */
|
|
|
- if (reg->start > start) {
|
|
|
- error = request_range(start, reg->start - 1, space_id, flags, desc);
|
|
|
- if (error)
|
|
|
- ret = error;
|
|
|
- else
|
|
|
- reg->start = start;
|
|
|
- }
|
|
|
-
|
|
|
- combine:
|
|
|
- /*
|
|
|
- * The new region is adjacent to an existing one. If it extends beyond
|
|
|
- * that region all the way to the next one, it is possible to combine
|
|
|
- * all three of them.
|
|
|
- */
|
|
|
- while (reg->end < end) {
|
|
|
- struct reserved_region *next = NULL;
|
|
|
- u64 a = reg->end + 1, b = end;
|
|
|
-
|
|
|
- if (!list_is_last(®->node, regions)) {
|
|
|
- next = list_next_entry(reg, node);
|
|
|
- if (next->start <= end)
|
|
|
- b = next->start - 1;
|
|
|
- }
|
|
|
- error = request_range(a, b, space_id, flags, desc);
|
|
|
- if (!error) {
|
|
|
- if (next && next->start == b + 1) {
|
|
|
- reg->end = next->end;
|
|
|
- list_del(&next->node);
|
|
|
- kfree(next);
|
|
|
- } else {
|
|
|
- reg->end = end;
|
|
|
- break;
|
|
|
- }
|
|
|
- } else if (next) {
|
|
|
- if (!ret)
|
|
|
- ret = error;
|
|
|
-
|
|
|
- reg = next;
|
|
|
- } else {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return ret ? ret : error;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(acpi_reserve_region);
|