aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/resource.c')
-rw-r--r--drivers/acpi/resource.c162
1 files changed, 0 insertions, 162 deletions
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 10561ce16ed1..8244f013f210 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -26,7 +26,6 @@
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/list.h>
30#include <linux/slab.h> 29#include <linux/slab.h>
31 30
32#ifdef CONFIG_X86 31#ifdef CONFIG_X86
@@ -622,164 +621,3 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
622 return (type & types) ? 0 : 1; 621 return (type & types) ? 0 : 1;
623} 622}
624EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); 623EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
625
626struct reserved_region {
627 struct list_head node;
628 u64 start;
629 u64 end;
630};
631
632static LIST_HEAD(reserved_io_regions);
633static LIST_HEAD(reserved_mem_regions);
634
635static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags,
636 char *desc)
637{
638 unsigned int length = end - start + 1;
639 struct resource *res;
640
641 res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ?
642 request_region(start, length, desc) :
643 request_mem_region(start, length, desc);
644 if (!res)
645 return -EIO;
646
647 res->flags &= ~flags;
648 return 0;
649}
650
651static int add_region_before(u64 start, u64 end, u8 space_id,
652 unsigned long flags, char *desc,
653 struct list_head *head)
654{
655 struct reserved_region *reg;
656 int error;
657
658 reg = kmalloc(sizeof(*reg), GFP_KERNEL);
659 if (!reg)
660 return -ENOMEM;
661
662 error = request_range(start, end, space_id, flags, desc);
663 if (error) {
664 kfree(reg);
665 return error;
666 }
667
668 reg->start = start;
669 reg->end = end;
670 list_add_tail(&reg->node, head);
671 return 0;
672}
673
674/**
675 * acpi_reserve_region - Reserve an I/O or memory region as a system resource.
676 * @start: Starting address of the region.
677 * @length: Length of the region.
678 * @space_id: Identifier of address space to reserve the region from.
679 * @flags: Resource flags to clear for the region after requesting it.
680 * @desc: Region description (for messages).
681 *
682 * Reserve an I/O or memory region as a system resource to prevent others from
683 * using it. If the new region overlaps with one of the regions (in the given
684 * address space) already reserved by this routine, only the non-overlapping
685 * parts of it will be reserved.
686 *
687 * Returned is either 0 (success) or a negative error code indicating a resource
688 * reservation problem. It is the code of the first encountered error, but the
689 * routine doesn't abort until it has attempted to request all of the parts of
690 * the new region that don't overlap with other regions reserved previously.
691 *
692 * The resources requested by this routine are never released.
693 */
694int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
695 unsigned long flags, char *desc)
696{
697 struct list_head *regions;
698 struct reserved_region *reg;
699 u64 end = start + length - 1;
700 int ret = 0, error = 0;
701
702 if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
703 regions = &reserved_io_regions;
704 else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
705 regions = &reserved_mem_regions;
706 else
707 return -EINVAL;
708
709 if (list_empty(regions))
710 return add_region_before(start, end, space_id, flags, desc, regions);
711
712 list_for_each_entry(reg, regions, node)
713 if (reg->start == end + 1) {
714 /* The new region can be prepended to this one. */
715 ret = request_range(start, end, space_id, flags, desc);
716 if (!ret)
717 reg->start = start;
718
719 return ret;
720 } else if (reg->start > end) {
721 /* No overlap. Add the new region here and get out. */
722 return add_region_before(start, end, space_id, flags,
723 desc, &reg->node);
724 } else if (reg->end == start - 1) {
725 goto combine;
726 } else if (reg->end >= start) {
727 goto overlap;
728 }
729
730 /* The new region goes after the last existing one. */
731 return add_region_before(start, end, space_id, flags, desc, regions);
732
733 overlap:
734 /*
735 * The new region overlaps an existing one.
736 *
737 * The head part of the new region immediately preceding the existing
738 * overlapping one can be combined with it right away.
739 */
740 if (reg->start > start) {
741 error = request_range(start, reg->start - 1, space_id, flags, desc);
742 if (error)
743 ret = error;
744 else
745 reg->start = start;
746 }
747
748 combine:
749 /*
750 * The new region is adjacent to an existing one. If it extends beyond
751 * that region all the way to the next one, it is possible to combine
752 * all three of them.
753 */
754 while (reg->end < end) {
755 struct reserved_region *next = NULL;
756 u64 a = reg->end + 1, b = end;
757
758 if (!list_is_last(&reg->node, regions)) {
759 next = list_next_entry(reg, node);
760 if (next->start <= end)
761 b = next->start - 1;
762 }
763 error = request_range(a, b, space_id, flags, desc);
764 if (!error) {
765 if (next && next->start == b + 1) {
766 reg->end = next->end;
767 list_del(&next->node);
768 kfree(next);
769 } else {
770 reg->end = end;
771 break;
772 }
773 } else if (next) {
774 if (!ret)
775 ret = error;
776
777 reg = next;
778 } else {
779 break;
780 }
781 }
782
783 return ret ? ret : error;
784}
785EXPORT_SYMBOL_GPL(acpi_reserve_region);