diff options
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 144 |
1 files changed, 80 insertions, 64 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e5f416c7f66e..54a20ff4b864 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -61,7 +61,6 @@ struct acpi_os_dpc { acpi_osd_exec_callback function; void *context; struct work_struct work; - int wait; }; #ifdef CONFIG_ACPI_CUSTOM_DSDT @@ -569,8 +568,10 @@ static const char * const table_sigs[] = { #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) -/* Must not increase 10 or needs code modification below */ -#define ACPI_OVERRIDE_TABLES 10 +#define ACPI_OVERRIDE_TABLES 64 +static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES]; + +#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) void __init acpi_initrd_override(void *data, size_t size) { @@ -579,8 +580,6 @@ void __init acpi_initrd_override(void *data, size_t size) struct acpi_table_header *table; char cpio_path[32] = "kernel/firmware/acpi/"; struct cpio_data file; - struct cpio_data early_initrd_files[ACPI_OVERRIDE_TABLES]; - char *p; if (data == NULL || size == 0) return; @@ -625,8 +624,8 @@ void __init acpi_initrd_override(void *data, size_t size) table->signature, cpio_path, file.name, table->length); all_tables_size += table->length; - early_initrd_files[table_nr].data = file.data; - early_initrd_files[table_nr].size = file.size; + acpi_initrd_files[table_nr].data = file.data; + acpi_initrd_files[table_nr].size = file.size; table_nr++; } if (table_nr == 0) @@ -652,14 +651,34 @@ void __init acpi_initrd_override(void *data, size_t size) memblock_reserve(acpi_tables_addr, all_tables_size); arch_reserve_mem_area(acpi_tables_addr, all_tables_size); - p = early_ioremap(acpi_tables_addr, all_tables_size); - + /* + * early_ioremap only can remap 256k one time. If we map all + * tables one time, we will hit the limit. Need to map chunks + * one by one during copying the same as that in relocate_initrd(). + */ for (no = 0; no < table_nr; no++) { - memcpy(p + total_offset, early_initrd_files[no].data, - early_initrd_files[no].size); - total_offset += early_initrd_files[no].size; + unsigned char *src_p = acpi_initrd_files[no].data; + phys_addr_t size = acpi_initrd_files[no].size; + phys_addr_t dest_addr = acpi_tables_addr + total_offset; + phys_addr_t slop, clen; + char *dest_p; + + total_offset += size; + + while (size) { + slop = dest_addr & ~PAGE_MASK; + clen = size; + if (clen > MAP_CHUNK_SIZE - slop) + clen = MAP_CHUNK_SIZE - slop; + dest_p = early_ioremap(dest_addr & PAGE_MASK, + clen + slop); + memcpy(dest_p + slop, src_p, clen); + early_iounmap(dest_p, clen + slop); + src_p += clen; + dest_addr += clen; + size -= clen; + } } - early_iounmap(p, all_tables_size); } #endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ @@ -820,7 +839,7 @@ acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) void acpi_os_sleep(u64 ms) { - schedule_timeout_interruptible(msecs_to_jiffies(ms)); + msleep(ms); } void acpi_os_stall(u32 us) @@ -1067,9 +1086,6 @@ static void acpi_os_execute_deferred(struct work_struct *work) { struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); - if (dpc->wait) - acpi_os_wait_events_complete(); - dpc->function(dpc->context); kfree(dpc); } @@ -1089,8 +1105,8 @@ static void acpi_os_execute_deferred(struct work_struct *work) * ******************************************************************************/ -static acpi_status __acpi_os_execute(acpi_execute_type type, - acpi_osd_exec_callback function, void *context, int hp) +acpi_status acpi_os_execute(acpi_execute_type type, + acpi_osd_exec_callback function, void *context) { acpi_status status = AE_OK; struct acpi_os_dpc *dpc; @@ -1117,20 +1133,11 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, dpc->context = context; /* - * We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq - * because the hotplug code may call driver .remove() functions, - * which invoke flush_scheduled_work/acpi_os_wait_events_complete - * to flush these workqueues. - * * To prevent lockdep from complaining unnecessarily, make sure that * there is a different static lockdep key for each workqueue by using * INIT_WORK() for each of them separately. */ - if (hp) { - queue = kacpi_hotplug_wq; - dpc->wait = 1; - INIT_WORK(&dpc->work, acpi_os_execute_deferred); - } else if (type == OSL_NOTIFY_HANDLER) { + if (type == OSL_NOTIFY_HANDLER) { queue = kacpi_notify_wq; INIT_WORK(&dpc->work, acpi_os_execute_deferred); } else { @@ -1155,28 +1162,59 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, } return status; } +EXPORT_SYMBOL(acpi_os_execute); -acpi_status acpi_os_execute(acpi_execute_type type, - acpi_osd_exec_callback function, void *context) +void acpi_os_wait_events_complete(void) { - return __acpi_os_execute(type, function, context, 0); + flush_workqueue(kacpid_wq); + flush_workqueue(kacpi_notify_wq); } -EXPORT_SYMBOL(acpi_os_execute); -acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function, - void *context) +struct acpi_hp_work { + struct work_struct work; + acpi_hp_callback func; + void *data; + u32 src; +}; + +static void acpi_hotplug_work_fn(struct work_struct *work) { - return __acpi_os_execute(0, function, context, 1); + struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work); + + acpi_os_wait_events_complete(); + hpw->func(hpw->data, hpw->src); + kfree(hpw); } -EXPORT_SYMBOL(acpi_os_hotplug_execute); -void acpi_os_wait_events_complete(void) +acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src) { - flush_workqueue(kacpid_wq); - flush_workqueue(kacpi_notify_wq); + struct acpi_hp_work *hpw; + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Scheduling function [%p(%p, %u)] for deferred execution.\n", + func, data, src)); + + hpw = kmalloc(sizeof(*hpw), GFP_KERNEL); + if (!hpw) + return AE_NO_MEMORY; + + INIT_WORK(&hpw->work, acpi_hotplug_work_fn); + hpw->func = func; + hpw->data = data; + hpw->src = src; + /* + * We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because + * the hotplug code may call driver .remove() functions, which may + * invoke flush_scheduled_work()/acpi_os_wait_events_complete() to flush + * these workqueues. + */ + if (!queue_work(kacpi_hotplug_wq, &hpw->work)) { + kfree(hpw); + return AE_ERROR; + } + return AE_OK; } -EXPORT_SYMBOL(acpi_os_wait_events_complete); acpi_status acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) @@ -1335,7 +1373,7 @@ static int __init acpi_os_name_setup(char *str) if (!str || !*str) return 0; - for (; count-- && str && *str; str++) { + for (; count-- && *str; str++) { if (isalnum(*str) || *str == ' ' || *str == ':') *p++ = *str; else if (*str == '\'' || *str == '"') @@ -1825,25 +1863,3 @@ void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, { __acpi_os_prepare_extended_sleep = func; } - - -void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context, - void (*func)(struct work_struct *work)) -{ - struct acpi_hp_work *hp_work; - int ret; - - hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL); - if (!hp_work) - return; - - hp_work->handle = handle; - hp_work->type = type; - hp_work->context = context; - - INIT_WORK(&hp_work->work, func); - ret = queue_work(kacpi_hotplug_wq, &hp_work->work); - if (!ret) - kfree(hp_work); -} -EXPORT_SYMBOL_GPL(alloc_acpi_hp_work); |