diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/acpi_lpss.c | 7 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 12 | ||||
-rw-r--r-- | drivers/acpi/resource.c | 162 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 32 |
4 files changed, 44 insertions, 169 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 569ee090343f..46b58abb08c5 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c | |||
@@ -352,13 +352,16 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
352 | pdata->mmio_size = resource_size(rentry->res); | 352 | pdata->mmio_size = resource_size(rentry->res); |
353 | pdata->mmio_base = ioremap(rentry->res->start, | 353 | pdata->mmio_base = ioremap(rentry->res->start, |
354 | pdata->mmio_size); | 354 | pdata->mmio_size); |
355 | if (!pdata->mmio_base) | ||
356 | goto err_out; | ||
357 | break; | 355 | break; |
358 | } | 356 | } |
359 | 357 | ||
360 | acpi_dev_free_resource_list(&resource_list); | 358 | acpi_dev_free_resource_list(&resource_list); |
361 | 359 | ||
360 | if (!pdata->mmio_base) { | ||
361 | ret = -ENOMEM; | ||
362 | goto err_out; | ||
363 | } | ||
364 | |||
362 | pdata->dev_desc = dev_desc; | 365 | pdata->dev_desc = dev_desc; |
363 | 366 | ||
364 | if (dev_desc->setup) | 367 | if (dev_desc->setup) |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c262e4acd68d..3b8963f21b36 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -175,10 +175,14 @@ static void __init acpi_request_region (struct acpi_generic_address *gas, | |||
175 | if (!addr || !length) | 175 | if (!addr || !length) |
176 | return; | 176 | return; |
177 | 177 | ||
178 | acpi_reserve_region(addr, length, gas->space_id, 0, desc); | 178 | /* Resources are never freed */ |
179 | if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) | ||
180 | request_region(addr, length, desc); | ||
181 | else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) | ||
182 | request_mem_region(addr, length, desc); | ||
179 | } | 183 | } |
180 | 184 | ||
181 | static void __init acpi_reserve_resources(void) | 185 | static int __init acpi_reserve_resources(void) |
182 | { | 186 | { |
183 | acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, | 187 | acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, |
184 | "ACPI PM1a_EVT_BLK"); | 188 | "ACPI PM1a_EVT_BLK"); |
@@ -207,7 +211,10 @@ static void __init acpi_reserve_resources(void) | |||
207 | if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) | 211 | if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) |
208 | acpi_request_region(&acpi_gbl_FADT.xgpe1_block, | 212 | acpi_request_region(&acpi_gbl_FADT.xgpe1_block, |
209 | acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); | 213 | acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); |
214 | |||
215 | return 0; | ||
210 | } | 216 | } |
217 | fs_initcall_sync(acpi_reserve_resources); | ||
211 | 218 | ||
212 | void acpi_os_printf(const char *fmt, ...) | 219 | void acpi_os_printf(const char *fmt, ...) |
213 | { | 220 | { |
@@ -1862,7 +1869,6 @@ acpi_status __init acpi_os_initialize(void) | |||
1862 | 1869 | ||
1863 | acpi_status __init acpi_os_initialize1(void) | 1870 | acpi_status __init acpi_os_initialize1(void) |
1864 | { | 1871 | { |
1865 | acpi_reserve_resources(); | ||
1866 | kacpid_wq = alloc_workqueue("kacpid", 0, 1); | 1872 | kacpid_wq = alloc_workqueue("kacpid", 0, 1); |
1867 | kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); | 1873 | kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); |
1868 | kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); | 1874 | kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); |
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); | ||
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2649a068671d..ec256352f423 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -1019,6 +1019,29 @@ static bool acpi_of_match_device(struct acpi_device *adev, | |||
1019 | return false; | 1019 | return false; |
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | static bool __acpi_match_device_cls(const struct acpi_device_id *id, | ||
1023 | struct acpi_hardware_id *hwid) | ||
1024 | { | ||
1025 | int i, msk, byte_shift; | ||
1026 | char buf[3]; | ||
1027 | |||
1028 | if (!id->cls) | ||
1029 | return false; | ||
1030 | |||
1031 | /* Apply class-code bitmask, before checking each class-code byte */ | ||
1032 | for (i = 1; i <= 3; i++) { | ||
1033 | byte_shift = 8 * (3 - i); | ||
1034 | msk = (id->cls_msk >> byte_shift) & 0xFF; | ||
1035 | if (!msk) | ||
1036 | continue; | ||
1037 | |||
1038 | sprintf(buf, "%02x", (id->cls >> byte_shift) & msk); | ||
1039 | if (strncmp(buf, &hwid->id[(i - 1) * 2], 2)) | ||
1040 | return false; | ||
1041 | } | ||
1042 | return true; | ||
1043 | } | ||
1044 | |||
1022 | static const struct acpi_device_id *__acpi_match_device( | 1045 | static const struct acpi_device_id *__acpi_match_device( |
1023 | struct acpi_device *device, | 1046 | struct acpi_device *device, |
1024 | const struct acpi_device_id *ids, | 1047 | const struct acpi_device_id *ids, |
@@ -1036,9 +1059,12 @@ static const struct acpi_device_id *__acpi_match_device( | |||
1036 | 1059 | ||
1037 | list_for_each_entry(hwid, &device->pnp.ids, list) { | 1060 | list_for_each_entry(hwid, &device->pnp.ids, list) { |
1038 | /* First, check the ACPI/PNP IDs provided by the caller. */ | 1061 | /* First, check the ACPI/PNP IDs provided by the caller. */ |
1039 | for (id = ids; id->id[0]; id++) | 1062 | for (id = ids; id->id[0] || id->cls; id++) { |
1040 | if (!strcmp((char *) id->id, hwid->id)) | 1063 | if (id->id[0] && !strcmp((char *) id->id, hwid->id)) |
1041 | return id; | 1064 | return id; |
1065 | else if (id->cls && __acpi_match_device_cls(id, hwid)) | ||
1066 | return id; | ||
1067 | } | ||
1042 | 1068 | ||
1043 | /* | 1069 | /* |
1044 | * Next, check ACPI_DT_NAMESPACE_HID and try to match the | 1070 | * Next, check ACPI_DT_NAMESPACE_HID and try to match the |
@@ -2101,6 +2127,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, | |||
2101 | if (info->valid & ACPI_VALID_UID) | 2127 | if (info->valid & ACPI_VALID_UID) |
2102 | pnp->unique_id = kstrdup(info->unique_id.string, | 2128 | pnp->unique_id = kstrdup(info->unique_id.string, |
2103 | GFP_KERNEL); | 2129 | GFP_KERNEL); |
2130 | if (info->valid & ACPI_VALID_CLS) | ||
2131 | acpi_add_id(pnp, info->class_code.string); | ||
2104 | 2132 | ||
2105 | kfree(info); | 2133 | kfree(info); |
2106 | 2134 | ||