diff options
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 242 |
1 files changed, 38 insertions, 204 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index f31c5c5f1b7e..fcc12d842bcc 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -83,19 +83,6 @@ static struct workqueue_struct *kacpi_notify_wq; struct workqueue_struct *kacpi_hotplug_wq; EXPORT_SYMBOL(kacpi_hotplug_wq); -struct acpi_res_list { - resource_size_t start; - resource_size_t end; - acpi_adr_space_type resource_type; /* IO port, System memory, ...*/ - char name[5]; /* only can have a length of 4 chars, make use of this - one instead of res->name, no need to kalloc then */ - struct list_head resource_list; - int count; -}; - -static LIST_HEAD(resource_list_head); -static DEFINE_SPINLOCK(acpi_res_lock); - /* * This list of permanent mappings is for memory that may be accessed from * interrupt context, where we can't do the ioremap(). @@ -166,17 +153,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) return supported; } -static void __init acpi_request_region (struct acpi_generic_address *addr, +static void __init acpi_request_region (struct acpi_generic_address *gas, unsigned int length, char *desc) { - if (!addr->address || !length) + u64 addr; + + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !length) return; /* Resources are never freed */ - if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) - request_region(addr->address, length, desc); - else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - request_mem_region(addr->address, length, desc); + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) + request_region(addr, length, desc); + else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + request_mem_region(addr, length, desc); } static int __init acpi_reserve_resources(void) @@ -427,35 +418,42 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) __acpi_unmap_table(virt, size); } -static int acpi_os_map_generic_address(struct acpi_generic_address *addr) +int acpi_os_map_generic_address(struct acpi_generic_address *gas) { + u64 addr; void __iomem *virt; - if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return 0; - if (!addr->address || !addr->bit_width) + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !gas->bit_width) return -EINVAL; - virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); + virt = acpi_os_map_memory(addr, gas->bit_width / 8); if (!virt) return -EIO; return 0; } +EXPORT_SYMBOL(acpi_os_map_generic_address); -static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) +void acpi_os_unmap_generic_address(struct acpi_generic_address *gas) { + u64 addr; struct acpi_ioremap *map; - if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return; - if (!addr->address || !addr->bit_width) + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !gas->bit_width) return; mutex_lock(&acpi_ioremap_lock); - map = acpi_map_lookup(addr->address, addr->bit_width / 8); + map = acpi_map_lookup(addr, gas->bit_width / 8); if (!map) { mutex_unlock(&acpi_ioremap_lock); return; @@ -465,6 +463,7 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) acpi_os_map_cleanup(map); } +EXPORT_SYMBOL(acpi_os_unmap_generic_address); #ifdef ACPI_FUTURE_USAGE acpi_status @@ -1278,44 +1277,28 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); * drivers */ int acpi_check_resource_conflict(const struct resource *res) { - struct acpi_res_list *res_list_elem; - int ioport = 0, clash = 0; + acpi_adr_space_type space_id; + acpi_size length; + u8 warn = 0; + int clash = 0; if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) return 0; if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM)) return 0; - ioport = res->flags & IORESOURCE_IO; - - spin_lock(&acpi_res_lock); - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - if (ioport && (res_list_elem->resource_type - != ACPI_ADR_SPACE_SYSTEM_IO)) - continue; - if (!ioport && (res_list_elem->resource_type - != ACPI_ADR_SPACE_SYSTEM_MEMORY)) - continue; + if (res->flags & IORESOURCE_IO) + space_id = ACPI_ADR_SPACE_SYSTEM_IO; + else + space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY; - if (res->end < res_list_elem->start - || res_list_elem->end < res->start) - continue; - clash = 1; - break; - } - spin_unlock(&acpi_res_lock); + length = res->end - res->start + 1; + if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) + warn = 1; + clash = acpi_check_address_range(space_id, res->start, length, warn); if (clash) { if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { - printk(KERN_WARNING "ACPI: resource %s %pR" - " conflicts with ACPI region %s " - "[%s 0x%zx-0x%zx]\n", - res->name, res, res_list_elem->name, - (res_list_elem->resource_type == - ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem", - (size_t) res_list_elem->start, - (size_t) res_list_elem->end); if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) printk(KERN_NOTICE "ACPI: This conflict may" " cause random problems and system" @@ -1467,155 +1450,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) kmem_cache_free(cache, object); return (AE_OK); } - -static inline int acpi_res_list_add(struct acpi_res_list *res) -{ - struct acpi_res_list *res_list_elem; - - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - - if (res->resource_type == res_list_elem->resource_type && - res->start == res_list_elem->start && - res->end == res_list_elem->end) { - - /* - * The Region(addr,len) already exist in the list, - * just increase the count - */ - - res_list_elem->count++; - return 0; - } - } - - res->count = 1; - list_add(&res->resource_list, &resource_list_head); - return 1; -} - -static inline void acpi_res_list_del(struct acpi_res_list *res) -{ - struct acpi_res_list *res_list_elem; - - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - - if (res->resource_type == res_list_elem->resource_type && - res->start == res_list_elem->start && - res->end == res_list_elem->end) { - - /* - * If the res count is decreased to 0, - * remove and free it - */ - - if (--res_list_elem->count == 0) { - list_del(&res_list_elem->resource_list); - kfree(res_list_elem); - } - return; - } - } -} - -acpi_status -acpi_os_invalidate_address( - u8 space_id, - acpi_physical_address address, - acpi_size length) -{ - struct acpi_res_list res; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_IO: - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - /* Only interference checks against SystemIO and SystemMemory - are needed */ - res.start = address; - res.end = address + length - 1; - res.resource_type = space_id; - spin_lock(&acpi_res_lock); - acpi_res_list_del(&res); - spin_unlock(&acpi_res_lock); - break; - case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_EC: - case ACPI_ADR_SPACE_SMBUS: - case ACPI_ADR_SPACE_CMOS: - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - case ACPI_ADR_SPACE_DATA_TABLE: - case ACPI_ADR_SPACE_FIXED_HARDWARE: - break; - } - return AE_OK; -} - -/****************************************************************************** - * - * FUNCTION: acpi_os_validate_address - * - * PARAMETERS: space_id - ACPI space ID - * address - Physical address - * length - Address length - * - * RETURN: AE_OK if address/length is valid for the space_id. Otherwise, - * should return AE_AML_ILLEGAL_ADDRESS. - * - * DESCRIPTION: Validate a system address via the host OS. Used to validate - * the addresses accessed by AML operation regions. - * - *****************************************************************************/ - -acpi_status -acpi_os_validate_address ( - u8 space_id, - acpi_physical_address address, - acpi_size length, - char *name) -{ - struct acpi_res_list *res; - int added; - if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) - return AE_OK; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_IO: - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - /* Only interference checks against SystemIO and SystemMemory - are needed */ - res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL); - if (!res) - return AE_OK; - /* ACPI names are fixed to 4 bytes, still better use strlcpy */ - strlcpy(res->name, name, 5); - res->start = address; - res->end = address + length - 1; - res->resource_type = space_id; - spin_lock(&acpi_res_lock); - added = acpi_res_list_add(res); - spin_unlock(&acpi_res_lock); - pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " - "name: %s\n", added ? "Added" : "Already exist", - (space_id == ACPI_ADR_SPACE_SYSTEM_IO) - ? "SystemIO" : "System Memory", - (unsigned long long)res->start, - (unsigned long long)res->end, - res->name); - if (!added) - kfree(res); - break; - case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_EC: - case ACPI_ADR_SPACE_SMBUS: - case ACPI_ADR_SPACE_CMOS: - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - case ACPI_ADR_SPACE_DATA_TABLE: - case ACPI_ADR_SPACE_FIXED_HARDWARE: - break; - } - return AE_OK; -} #endif acpi_status __init acpi_os_initialize(void) |