diff options
Diffstat (limited to 'drivers/acpi/resource.c')
-rw-r--r-- | drivers/acpi/resource.c | 162 |
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 | } |
624 | EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); | 623 | EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); |
625 | |||
626 | struct reserved_region { | ||
627 | struct list_head node; | ||
628 | u64 start; | ||
629 | u64 end; | ||
630 | }; | ||
631 | |||
632 | static LIST_HEAD(reserved_io_regions); | ||
633 | static LIST_HEAD(reserved_mem_regions); | ||
634 | |||
635 | static 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 | |||
651 | static 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(®->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 | */ | ||
694 | int 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, ®->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(®->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 | } | ||
785 | EXPORT_SYMBOL_GPL(acpi_reserve_region); | ||