X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Facpi%2Fosl.c;h=aabc6ca4a81c72463529c3e711b012f8b6e909a7;hb=c4ec20717313daafba59225f812db89595952b83;hp=7d4cc122b026a4a98d071a1e1f25f21494d04fa8;hpb=6468463abd7051fcc29f3ee7c931f9bbbb26f5a4;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 7d4cc12..aabc6ca 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -25,19 +25,18 @@ * */ -#include #include #include #include #include #include -#include #include #include #include +#include #include #include -#include +#include #include #include #include @@ -47,11 +46,12 @@ #include #define _COMPONENT ACPI_OS_SERVICES -ACPI_MODULE_NAME("osl") +ACPI_MODULE_NAME("osl"); #define PREFIX "ACPI: " struct acpi_os_dpc { acpi_osd_exec_callback function; void *context; + struct work_struct work; }; #ifdef CONFIG_ACPI_CUSTOM_DSDT @@ -68,16 +68,72 @@ EXPORT_SYMBOL(acpi_in_debugger); extern char line_buf[80]; #endif /*ENABLE_DEBUGGER */ -int acpi_specific_hotkey_enabled = TRUE; -EXPORT_SYMBOL(acpi_specific_hotkey_enabled); - static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; +static struct workqueue_struct *kacpi_notify_wq; + +#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ +static char osi_additional_string[OSI_STRING_LENGTH_MAX]; + +static int osi_linux; /* disable _OSI(Linux) by default */ + +#ifdef CONFIG_DMI +static struct __initdata dmi_system_id acpi_osl_dmi_table[]; +#endif + +static void __init acpi_request_region (struct acpi_generic_address *addr, + unsigned int length, char *desc) +{ + struct resource *res; + + if (!addr->address || !length) + return; + + if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) + res = request_region(addr->address, length, desc); + else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + res = request_mem_region(addr->address, length, desc); +} -acpi_status acpi_os_initialize(void) +static int __init acpi_reserve_resources(void) { + acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, + "ACPI PM1a_EVT_BLK"); + + acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length, + "ACPI PM1b_EVT_BLK"); + + acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length, + "ACPI PM1a_CNT_BLK"); + + acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length, + "ACPI PM1b_CNT_BLK"); + + if (acpi_gbl_FADT.pm_timer_length == 4) + acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR"); + + acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length, + "ACPI PM2_CNT_BLK"); + + /* Length of GPE blocks must be a non-negative multiple of 2 */ + + if (!(acpi_gbl_FADT.gpe0_block_length & 0x1)) + acpi_request_region(&acpi_gbl_FADT.xgpe0_block, + acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK"); + + if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) + acpi_request_region(&acpi_gbl_FADT.xgpe1_block, + acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); + + return 0; +} +device_initcall(acpi_reserve_resources); + +acpi_status __init acpi_os_initialize(void) +{ + dmi_check_system(acpi_osl_dmi_table); return AE_OK; } @@ -93,8 +149,9 @@ acpi_status acpi_os_initialize1(void) return AE_NULL_ENTRY; } kacpid_wq = create_singlethread_workqueue("kacpid"); + kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify"); BUG_ON(!kacpid_wq); - + BUG_ON(!kacpi_notify_wq); return AE_OK; } @@ -106,6 +163,7 @@ acpi_status acpi_os_terminate(void) } destroy_workqueue(kacpid_wq); + destroy_workqueue(kacpi_notify_wq); return AE_OK; } @@ -137,70 +195,43 @@ void acpi_os_vprintf(const char *fmt, va_list args) #endif } - -extern int acpi_in_resume; -void *acpi_os_allocate(acpi_size size) -{ - if (acpi_in_resume) - return kmalloc(size, GFP_ATOMIC); - else - return kmalloc(size, GFP_KERNEL); -} - -void acpi_os_free(void *ptr) -{ - kfree(ptr); -} - -EXPORT_SYMBOL(acpi_os_free); - -acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr) +acpi_physical_address __init acpi_os_get_root_pointer(void) { if (efi_enabled) { - addr->pointer_type = ACPI_PHYSICAL_POINTER; if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) - addr->pointer.physical = efi.acpi20; + return efi.acpi20; else if (efi.acpi != EFI_INVALID_TABLE_ADDR) - addr->pointer.physical = efi.acpi; + return efi.acpi; else { printk(KERN_ERR PREFIX "System description tables not found\n"); - return AE_NOT_FOUND; - } - } else { - if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) { - printk(KERN_ERR PREFIX - "System description tables not found\n"); - return AE_NOT_FOUND; + return 0; } - } - - return AE_OK; + } else + return acpi_find_rsdp(); } -acpi_status -acpi_os_map_memory(acpi_physical_address phys, acpi_size size, - void __iomem ** virt) +void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); - return AE_BAD_PARAMETER; + return NULL; } - /* - * ioremap checks to ensure this is in reserved space - */ - *virt = ioremap((unsigned long)phys, size); - - if (!*virt) - return AE_NO_MEMORY; - - return AE_OK; + if (acpi_gbl_permanent_mmap) + /* + * ioremap checks to ensure this is in reserved space + */ + return ioremap((unsigned long)phys, size); + else + return __acpi_map_table((unsigned long)phys, size); } EXPORT_SYMBOL_GPL(acpi_os_map_memory); void acpi_os_unmap_memory(void __iomem * virt, acpi_size size) { - iounmap(virt); + if (acpi_gbl_permanent_mmap) { + iounmap(virt); + } } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); @@ -256,7 +287,7 @@ acpi_os_table_override(struct acpi_table_header * existing_table, return AE_OK; } -static irqreturn_t acpi_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t acpi_irq(int irq, void *dev_id) { return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE; } @@ -272,7 +303,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, * FADT. It may not be the same if an interrupt source override exists * for the SCI. */ - gsi = acpi_fadt.sci_int; + gsi = acpi_gbl_FADT.sci_interrupt; if (acpi_gsi_to_irq(gsi, &irq) < 0) { printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", gsi); @@ -281,7 +312,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, acpi_irq_handler = handler; acpi_irq_context = context; - if (request_irq(irq, acpi_irq, SA_SHIRQ, "acpi", acpi_irq)) { + if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); return AE_NOT_ACQUIRED; } @@ -583,33 +614,37 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number); } -static void acpi_os_execute_deferred(void *context) +static void acpi_os_execute_deferred(struct work_struct *work) { - struct acpi_os_dpc *dpc = NULL; - - ACPI_FUNCTION_TRACE("os_execute_deferred"); - - dpc = (struct acpi_os_dpc *)context; + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); if (!dpc) { printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); - return_VOID; + return; } dpc->function(dpc->context); - kfree(dpc); - return_VOID; + /* Yield cpu to notify thread */ + cond_resched(); + + return; } -static int acpi_os_execute_thread(void *context) +static void acpi_os_execute_notify(struct work_struct *work) { - struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context; - if (dpc) { - dpc->function(dpc->context); - kfree(dpc); + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); + + if (!dpc) { + printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); + return; } - do_exit(0); + + dpc->function(dpc->context); + + kfree(dpc); + + return; } /******************************************************************************* @@ -632,49 +667,46 @@ acpi_status acpi_os_execute(acpi_execute_type type, { acpi_status status = AE_OK; struct acpi_os_dpc *dpc; - struct work_struct *task; - struct task_struct *p; + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Scheduling function [%p(%p)] for deferred execution.\n", + function, context)); if (!function) return AE_BAD_PARAMETER; + /* * Allocate/initialize DPC structure. Note that this memory will be - * freed by the callee. The kernel handles the tq_struct list in a + * freed by the callee. The kernel handles the work_struct list in a * way that allows us to also free its memory inside the callee. * Because we may want to schedule several tasks with different * parameters we can't use the approach some kernel code uses of - * having a static tq_struct. - * We can save time and code by allocating the DPC and tq_structs - * from the same memory. + * having a static work_struct. */ - if (type == OSL_NOTIFY_HANDLER) { - dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_KERNEL); - } else { - dpc = kmalloc(sizeof(struct acpi_os_dpc) + - sizeof(struct work_struct), GFP_ATOMIC); - } + + dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); if (!dpc) - return AE_NO_MEMORY; + return_ACPI_STATUS(AE_NO_MEMORY); + dpc->function = function; dpc->context = context; if (type == OSL_NOTIFY_HANDLER) { - p = kthread_create(acpi_os_execute_thread, dpc, "kacpid_notify"); - if (!IS_ERR(p)) { - wake_up_process(p); - } else { - status = AE_NO_MEMORY; + INIT_WORK(&dpc->work, acpi_os_execute_notify); + if (!queue_work(kacpi_notify_wq, &dpc->work)) { + status = AE_ERROR; kfree(dpc); } } else { - task = (void *)(dpc + 1); - INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc); - if (!queue_work(kacpid_wq, task)) { + INIT_WORK(&dpc->work, acpi_os_execute_deferred); + if (!queue_work(kacpid_wq, &dpc->work)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Call to queue_work() failed.\n")); status = AE_ERROR; kfree(dpc); } } - return status; + return_ACPI_STATUS(status); } EXPORT_SYMBOL(acpi_os_execute); @@ -689,35 +721,19 @@ EXPORT_SYMBOL(acpi_os_wait_events_complete); /* * Allocate the memory for a spinlock and initialize it. */ -acpi_status acpi_os_create_lock(acpi_handle * out_handle) +acpi_status acpi_os_create_lock(acpi_spinlock * handle) { - spinlock_t *lock_ptr; - - ACPI_FUNCTION_TRACE("os_create_lock"); - - lock_ptr = acpi_os_allocate(sizeof(spinlock_t)); - - spin_lock_init(lock_ptr); - - ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating spinlock[%p].\n", lock_ptr)); + spin_lock_init(*handle); - *out_handle = lock_ptr; - - return_ACPI_STATUS(AE_OK); + return AE_OK; } /* * Deallocate the memory for a spinlock. */ -void acpi_os_delete_lock(acpi_handle handle) +void acpi_os_delete_lock(acpi_spinlock handle) { - ACPI_FUNCTION_TRACE("os_create_lock"); - - ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting spinlock[%p].\n", handle)); - - acpi_os_free(handle); - - return_VOID; + return; } acpi_status @@ -725,11 +741,10 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) { struct semaphore *sem = NULL; - ACPI_FUNCTION_TRACE("os_create_semaphore"); sem = acpi_os_allocate(sizeof(struct semaphore)); if (!sem) - return_ACPI_STATUS(AE_NO_MEMORY); + return AE_NO_MEMORY; memset(sem, 0, sizeof(struct semaphore)); sema_init(sem, initial_units); @@ -739,7 +754,7 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n", *handle, initial_units)); - return_ACPI_STATUS(AE_OK); + return AE_OK; } EXPORT_SYMBOL(acpi_os_create_semaphore); @@ -755,17 +770,16 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle) { struct semaphore *sem = (struct semaphore *)handle; - ACPI_FUNCTION_TRACE("os_delete_semaphore"); if (!sem) - return_ACPI_STATUS(AE_BAD_PARAMETER); + return AE_BAD_PARAMETER; ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle)); - acpi_os_free(sem); + kfree(sem); sem = NULL; - return_ACPI_STATUS(AE_OK); + return AE_OK; } EXPORT_SYMBOL(acpi_os_delete_semaphore); @@ -785,17 +799,26 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) struct semaphore *sem = (struct semaphore *)handle; int ret = 0; - ACPI_FUNCTION_TRACE("os_wait_semaphore"); if (!sem || (units < 1)) - return_ACPI_STATUS(AE_BAD_PARAMETER); + return AE_BAD_PARAMETER; if (units > 1) - return_ACPI_STATUS(AE_SUPPORT); + return AE_SUPPORT; ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); + /* + * This can be called during resume with interrupts off. + * Like boot-time, we should be single threaded and will + * always get the lock if we try -- timeout or not. + * If this doesn't succeed, then we will oops courtesy of + * might_sleep() in down(). + */ + if (!down_trylock(sem)) + return AE_OK; + switch (timeout) { /* * No Wait: @@ -850,7 +873,7 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) units, timeout)); } - return_ACPI_STATUS(status); + return status; } EXPORT_SYMBOL(acpi_os_wait_semaphore); @@ -862,20 +885,19 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) { struct semaphore *sem = (struct semaphore *)handle; - ACPI_FUNCTION_TRACE("os_signal_semaphore"); if (!sem || (units < 1)) - return_ACPI_STATUS(AE_BAD_PARAMETER); + return AE_BAD_PARAMETER; if (units > 1) - return_ACPI_STATUS(AE_SUPPORT); + return AE_SUPPORT; ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle, units)); up(sem); - return_ACPI_STATUS(AE_OK); + return AE_OK; } EXPORT_SYMBOL(acpi_os_signal_semaphore); @@ -900,26 +922,6 @@ u32 acpi_os_get_line(char *buffer) } #endif /* ACPI_FUTURE_USAGE */ -/* Assumes no unreadable holes inbetween */ -u8 acpi_os_readable(void *ptr, acpi_size len) -{ -#if defined(__i386__) || defined(__x86_64__) - char tmp; - return !__get_user(tmp, (char __user *)ptr) - && !__get_user(tmp, (char __user *)ptr + len - 1); -#endif - return 1; -} - -#ifdef ACPI_FUTURE_USAGE -u8 acpi_os_writable(void *ptr, acpi_size len) -{ - /* could do dummy write (racy) or a kernel page table lookup. - The later may be difficult at early boot when kmap doesn't work yet. */ - return 1; -} -#endif - acpi_status acpi_os_signal(u32 function, void *info) { switch (function) { @@ -969,20 +971,38 @@ static int __init acpi_os_name_setup(char *str) __setup("acpi_os_name=", acpi_os_name_setup); +static void enable_osi_linux(int enable) { + + if (osi_linux != enable) + printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n", + enable ? "En": "Dis"); + + osi_linux = enable; + return; +} + /* - * _OSI control + * Modify the list of "OS Interfaces" reported to BIOS via _OSI + * * empty string disables _OSI - * TBD additional string adds to _OSI + * string starting with '!' disables that string + * otherwise string is added to list, augmenting built-in strings */ static int __init acpi_osi_setup(char *str) { if (str == NULL || *str == '\0') { printk(KERN_INFO PREFIX "_OSI method disabled\n"); acpi_gbl_create_osi_method = FALSE; - } else { - /* TBD */ - printk(KERN_ERR PREFIX "_OSI additional string ignored -- %s\n", - str); + } else if (!strcmp("!Linux", str)) { + enable_osi_linux(0); + } else if (*str == '!') { + if (acpi_osi_invalidate(++str) == AE_OK) + printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); + } else if (!strcmp("Linux", str)) { + enable_osi_linux(1); + } else if (*osi_additional_string == '\0') { + strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); + printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); } return 1; @@ -1022,32 +1042,16 @@ static int __init acpi_wake_gpes_always_on_setup(char *str) __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); -static int __init acpi_hotkey_setup(char *str) -{ - acpi_specific_hotkey_enabled = FALSE; - return 1; -} - -__setup("acpi_generic_hotkey", acpi_hotkey_setup); - -/* - * max_cstate is defined in the base kernel so modules can - * change it w/o depending on the state of the processor module. - */ -unsigned int max_cstate = ACPI_PROCESSOR_MAX_POWER; - -EXPORT_SYMBOL(max_cstate); - /* * Acquire a spinlock. * * handle is a pointer to the spinlock_t. */ -acpi_cpu_flags acpi_os_acquire_lock(acpi_handle handle) +acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) { acpi_cpu_flags flags; - spin_lock_irqsave((spinlock_t *) handle, flags); + spin_lock_irqsave(lockp, flags); return flags; } @@ -1055,9 +1059,9 @@ acpi_cpu_flags acpi_os_acquire_lock(acpi_handle handle) * Release a spinlock. See above. */ -void acpi_os_release_lock(acpi_handle handle, acpi_cpu_flags flags) +void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) { - spin_unlock_irqrestore((spinlock_t *) handle, flags); + spin_unlock_irqrestore(lockp, flags); } #ifndef ACPI_USE_LOCAL_CACHE @@ -1080,8 +1084,8 @@ void acpi_os_release_lock(acpi_handle handle, acpi_cpu_flags flags) acpi_status acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) { - *cache = kmem_cache_create(name, size, 0, 0, NULL, NULL); - if (cache == NULL) + *cache = kmem_cache_create(name, size, 0, 0, NULL); + if (*cache == NULL) return AE_ERROR; else return AE_OK; @@ -1101,7 +1105,7 @@ acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) acpi_status acpi_os_purge_cache(acpi_cache_t * cache) { - (void)kmem_cache_shrink(cache); + kmem_cache_shrink(cache); return (AE_OK); } @@ -1120,7 +1124,7 @@ acpi_status acpi_os_purge_cache(acpi_cache_t * cache) acpi_status acpi_os_delete_cache(acpi_cache_t * cache) { - (void)kmem_cache_destroy(cache); + kmem_cache_destroy(cache); return (AE_OK); } @@ -1144,26 +1148,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) return (AE_OK); } -/******************************************************************************* - * - * FUNCTION: acpi_os_acquire_object - * - * PARAMETERS: Cache - Handle to cache object - * ReturnObject - Where the object is returned - * - * RETURN: Status - * - * DESCRIPTION: Return a zero-filled object. - * - ******************************************************************************/ - -void *acpi_os_acquire_object(acpi_cache_t * cache) -{ - void *object = kmem_cache_zalloc(cache, GFP_KERNEL); - WARN_ON(!object); - return object; -} - /****************************************************************************** * * FUNCTION: acpi_os_validate_interface @@ -1180,11 +1164,21 @@ void *acpi_os_acquire_object(acpi_cache_t * cache) acpi_status acpi_os_validate_interface (char *interface) { - - return AE_SUPPORT; + if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) + return AE_OK; + if (!strcmp("Linux", interface)) { + printk(KERN_WARNING PREFIX + "System BIOS is requesting _OSI(Linux)\n"); + printk(KERN_WARNING PREFIX + "If \"acpi_osi=Linux\" works better,\n" + "Please send dmidecode " + "to linux-acpi@vger.kernel.org\n"); + if(osi_linux) + return AE_OK; + } + return AE_SUPPORT; } - /****************************************************************************** * * FUNCTION: acpi_os_validate_address @@ -1211,5 +1205,28 @@ acpi_os_validate_address ( return AE_OK; } +#ifdef CONFIG_DMI +static int dmi_osi_linux(const struct dmi_system_id *d) +{ + printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident); + enable_osi_linux(1); + return 0; +} + +static struct dmi_system_id acpi_osl_dmi_table[] __initdata = { + /* + * Boxes that need _OSI(Linux) + */ + { + .callback = dmi_osi_linux, + .ident = "Intel Napa CRB", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"), + }, + }, + {} +}; +#endif /* CONFIG_DMI */ #endif