X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Facpi%2Fosl.c;h=2e7ba615d76043845f23c3dbd1f9192b5e4df072;hb=9657d75c5f0f7d0a9cb507521d3ad1436aea28c9;hp=c212d19443c5f0ce238e2c0abe3254512612127c;hpb=f6869979bec3cc2efddc7359f30ba37642084fb7;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c212d19..2e7ba61 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -25,18 +25,18 @@ * */ -#include #include #include #include #include #include -#include #include #include #include +#include #include #include +#include #include #include #include @@ -45,16 +45,13 @@ #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 acpi_os_dpc { + acpi_osd_exec_callback function; + void *context; + struct work_struct work; }; #ifdef CONFIG_ACPI_CUSTOM_DSDT @@ -69,43 +66,102 @@ int acpi_in_debugger; 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); +#endif /*ENABLE_DEBUGGER */ 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; -acpi_status -acpi_os_initialize(void) +#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ +static char osi_additional_string[OSI_STRING_LENGTH_MAX]; + +#define OSI_LINUX_ENABLED +#ifdef OSI_LINUX_ENABLED +int osi_linux = 1; /* enable _OSI(Linux) by default */ +#else +int osi_linux; /* disable _OSI(Linux) by default */ +#endif + + +#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); +} + +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; } -acpi_status -acpi_os_initialize1(void) +acpi_status acpi_os_initialize1(void) { /* * Initialize PCI configuration space access, as we'll need to access * it while walking the namespace (bus 0 and root bridges w/ _BBNs). */ -#ifdef CONFIG_ACPI_PCI if (!raw_pci_ops) { - printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n"); + printk(KERN_ERR PREFIX + "Access to PCI configuration space unavailable\n"); return AE_NULL_ENTRY; } -#endif 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; } -acpi_status -acpi_os_terminate(void) +acpi_status acpi_os_terminate(void) { if (acpi_irq_handler) { acpi_os_remove_interrupt_handler(acpi_irq_irq, @@ -113,25 +169,25 @@ acpi_os_terminate(void) } destroy_workqueue(kacpid_wq); + destroy_workqueue(kacpi_notify_wq); return AE_OK; } -void -acpi_os_printf(const char *fmt,...) +void acpi_os_printf(const char *fmt, ...) { va_list args; va_start(args, fmt); acpi_os_vprintf(fmt, args); va_end(args); } + EXPORT_SYMBOL(acpi_os_printf); -void -acpi_os_vprintf(const char *fmt, va_list args) +void acpi_os_vprintf(const char *fmt, va_list args) { static char buffer[512]; - + vsprintf(buffer, fmt, args); #ifdef ENABLE_DEBUGGER @@ -145,81 +201,51 @@ acpi_os_vprintf(const char *fmt, va_list args) #endif } -void * -acpi_os_allocate(acpi_size size) -{ - 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) - addr->pointer.physical = - (acpi_physical_address) virt_to_phys(efi.acpi20); - else if (efi.acpi) - addr->pointer.physical = - (acpi_physical_address) virt_to_phys(efi.acpi); + if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) + return efi.acpi20; + else if (efi.acpi != EFI_INVALID_TABLE_ADDR) + return efi.acpi; else { - printk(KERN_ERR PREFIX "System description tables not found\n"); - return AE_NOT_FOUND; + printk(KERN_ERR PREFIX + "System description tables not found\n"); + return 0; } - } 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 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 (efi_enabled) { - if (EFI_MEMORY_WB & efi_mem_attributes(phys)) { - *virt = (void __iomem *) phys_to_virt(phys); - } else { - *virt = ioremap(phys, size); - } - } else { - if (phys > ULONG_MAX) { - printk(KERN_ERR PREFIX "Cannot map memory that high\n"); - return AE_BAD_PARAMETER; - } - /* - * ioremap checks to ensure this is in reserved space - */ - *virt = ioremap((unsigned long) phys, size); + if (phys > ULONG_MAX) { + printk(KERN_ERR PREFIX "Cannot map memory that high\n"); + return NULL; } - - 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) +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); #ifdef ACPI_FUTURE_USAGE acpi_status -acpi_os_get_physical_address(void *virt, acpi_physical_address *phys) +acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) { - if(!phys || !virt) + if (!phys || !virt) return AE_BAD_PARAMETER; *phys = virt_to_phys(virt); @@ -233,16 +259,16 @@ acpi_os_get_physical_address(void *virt, acpi_physical_address *phys) static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN]; acpi_status -acpi_os_predefined_override (const struct acpi_predefined_names *init_val, - acpi_string *new_val) +acpi_os_predefined_override(const struct acpi_predefined_names *init_val, + acpi_string * new_val) { if (!init_val || !new_val) return AE_BAD_PARAMETER; *new_val = NULL; - if (!memcmp (init_val->name, "_OS_", 4) && strlen(acpi_os_name)) { + if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) { printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n", - acpi_os_name); + acpi_os_name); *new_val = acpi_os_name; } @@ -250,15 +276,15 @@ acpi_os_predefined_override (const struct acpi_predefined_names *init_val, } acpi_status -acpi_os_table_override (struct acpi_table_header *existing_table, - struct acpi_table_header **new_table) +acpi_os_table_override(struct acpi_table_header * existing_table, + struct acpi_table_header ** new_table) { if (!existing_table || !new_table) return AE_BAD_PARAMETER; #ifdef CONFIG_ACPI_CUSTOM_DSDT if (strncmp(existing_table->signature, "DSDT", 4) == 0) - *new_table = (struct acpi_table_header*)AmlCode; + *new_table = (struct acpi_table_header *)AmlCode; else *new_table = NULL; #else @@ -267,14 +293,14 @@ 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; + return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE; } acpi_status -acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, void *context) +acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, + void *context) { unsigned int irq; @@ -283,7 +309,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, void *conte * 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); @@ -292,7 +318,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, void *conte 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; } @@ -301,8 +327,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, void *conte return AE_OK; } -acpi_status -acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) +acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) { if (irq) { free_irq(irq, acpi_irq); @@ -317,16 +342,14 @@ acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) * Running in interpreter thread context, safe to sleep */ -void -acpi_os_sleep(acpi_integer ms) +void acpi_os_sleep(acpi_integer ms) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(((signed long) ms * HZ) / 1000); + schedule_timeout_interruptible(msecs_to_jiffies(ms)); } + EXPORT_SYMBOL(acpi_os_sleep); -void -acpi_os_stall(u32 us) +void acpi_os_stall(u32 us) { while (us) { u32 delay = 1000; @@ -338,6 +361,7 @@ acpi_os_stall(u32 us) us -= delay; } } + EXPORT_SYMBOL(acpi_os_stall); /* @@ -345,8 +369,7 @@ EXPORT_SYMBOL(acpi_os_stall); * Returns 64-bit free-running, monotonically increasing timer * with 100ns granularity */ -u64 -acpi_os_get_timer (void) +u64 acpi_os_get_timer(void) { static u64 t; @@ -363,27 +386,22 @@ acpi_os_get_timer (void) return ++t; } -acpi_status -acpi_os_read_port( - acpi_io_address port, - u32 *value, - u32 width) +acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width) { u32 dummy; if (!value) value = &dummy; - switch (width) - { + switch (width) { case 8: - *(u8*) value = inb(port); + *(u8 *) value = inb(port); break; case 16: - *(u16*) value = inw(port); + *(u16 *) value = inw(port); break; case 32: - *(u32*) value = inl(port); + *(u32 *) value = inl(port); break; default: BUG(); @@ -391,16 +409,12 @@ acpi_os_read_port( return AE_OK; } + EXPORT_SYMBOL(acpi_os_read_port); -acpi_status -acpi_os_write_port( - acpi_io_address port, - u32 value, - u32 width) +acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width) { - switch (width) - { + switch (width) { case 8: outb(value, port); break; @@ -416,72 +430,44 @@ acpi_os_write_port( return AE_OK; } + EXPORT_SYMBOL(acpi_os_write_port); acpi_status -acpi_os_read_memory( - acpi_physical_address phys_addr, - u32 *value, - u32 width) +acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) { - u32 dummy; - void __iomem *virt_addr; - int iomem = 0; + u32 dummy; + void __iomem *virt_addr; - if (efi_enabled) { - if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { - /* HACK ALERT! We can use readb/w/l on real memory too.. */ - virt_addr = (void __iomem *) phys_to_virt(phys_addr); - } else { - iomem = 1; - virt_addr = ioremap(phys_addr, width); - } - } else - virt_addr = (void __iomem *) phys_to_virt(phys_addr); + virt_addr = ioremap(phys_addr, width); if (!value) value = &dummy; switch (width) { case 8: - *(u8*) value = readb(virt_addr); + *(u8 *) value = readb(virt_addr); break; case 16: - *(u16*) value = readw(virt_addr); + *(u16 *) value = readw(virt_addr); break; case 32: - *(u32*) value = readl(virt_addr); + *(u32 *) value = readl(virt_addr); break; default: BUG(); } - if (efi_enabled) { - if (iomem) - iounmap(virt_addr); - } + iounmap(virt_addr); return AE_OK; } acpi_status -acpi_os_write_memory( - acpi_physical_address phys_addr, - u32 value, - u32 width) +acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) { - void __iomem *virt_addr; - int iomem = 0; + void __iomem *virt_addr; - if (efi_enabled) { - if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { - /* HACK ALERT! We can use writeb/w/l on real memory too */ - virt_addr = (void __iomem *) phys_to_virt(phys_addr); - } else { - iomem = 1; - virt_addr = ioremap(phys_addr, width); - } - } else - virt_addr = (void __iomem *) phys_to_virt(phys_addr); + virt_addr = ioremap(phys_addr, width); switch (width) { case 8: @@ -497,16 +483,14 @@ acpi_os_write_memory( BUG(); } - if (iomem) - iounmap(virt_addr); + iounmap(virt_addr); return AE_OK; } -#ifdef CONFIG_ACPI_PCI - acpi_status -acpi_os_read_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, void *value, u32 width) +acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, + void *value, u32 width) { int result, size; @@ -530,15 +514,17 @@ acpi_os_read_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, void *value BUG_ON(!raw_pci_ops); result = raw_pci_ops->read(pci_id->segment, pci_id->bus, - PCI_DEVFN(pci_id->device, pci_id->function), - reg, size, value); + PCI_DEVFN(pci_id->device, pci_id->function), + reg, size, value); return (result ? AE_ERROR : AE_OK); } + EXPORT_SYMBOL(acpi_os_read_pci_configuration); acpi_status -acpi_os_write_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, acpi_integer value, u32 width) +acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, + acpi_integer value, u32 width) { int result, size; @@ -559,56 +545,62 @@ acpi_os_write_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, acpi_integ BUG_ON(!raw_pci_ops); result = raw_pci_ops->write(pci_id->segment, pci_id->bus, - PCI_DEVFN(pci_id->device, pci_id->function), - reg, size, value); + PCI_DEVFN(pci_id->device, pci_id->function), + reg, size, value); return (result ? AE_ERROR : AE_OK); } /* TODO: Change code to take advantage of driver model more */ -static void -acpi_os_derive_pci_id_2 ( - acpi_handle rhandle, /* upper bound */ - acpi_handle chandle, /* current node */ - struct acpi_pci_id **id, - int *is_bridge, - u8 *bus_number) +static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */ + acpi_handle chandle, /* current node */ + struct acpi_pci_id **id, + int *is_bridge, u8 * bus_number) { - acpi_handle handle; - struct acpi_pci_id *pci_id = *id; - acpi_status status; - unsigned long temp; - acpi_object_type type; - u8 tu8; + acpi_handle handle; + struct acpi_pci_id *pci_id = *id; + acpi_status status; + unsigned long temp; + acpi_object_type type; + u8 tu8; acpi_get_parent(chandle, &handle); if (handle != rhandle) { - acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge, bus_number); + acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge, + bus_number); status = acpi_get_type(handle, &type); - if ( (ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE) ) + if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE)) return; - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &temp); + status = + acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, + &temp); if (ACPI_SUCCESS(status)) { - pci_id->device = ACPI_HIWORD (ACPI_LODWORD (temp)); - pci_id->function = ACPI_LOWORD (ACPI_LODWORD (temp)); + pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp)); + pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp)); if (*is_bridge) pci_id->bus = *bus_number; /* any nicer way to get bus number of bridge ? */ - status = acpi_os_read_pci_configuration(pci_id, 0x0e, &tu8, 8); - if (ACPI_SUCCESS(status) && - ((tu8 & 0x7f) == 1 || (tu8 & 0x7f) == 2)) { - status = acpi_os_read_pci_configuration(pci_id, 0x18, &tu8, 8); + status = + acpi_os_read_pci_configuration(pci_id, 0x0e, &tu8, + 8); + if (ACPI_SUCCESS(status) + && ((tu8 & 0x7f) == 1 || (tu8 & 0x7f) == 2)) { + status = + acpi_os_read_pci_configuration(pci_id, 0x18, + &tu8, 8); if (!ACPI_SUCCESS(status)) { /* Certainly broken... FIX ME */ return; } *is_bridge = 1; pci_id->bus = tu8; - status = acpi_os_read_pci_configuration(pci_id, 0x19, &tu8, 8); + status = + acpi_os_read_pci_configuration(pci_id, 0x19, + &tu8, 8); if (ACPI_SUCCESS(status)) { *bus_number = tu8; } @@ -618,11 +610,9 @@ acpi_os_derive_pci_id_2 ( } } -void -acpi_os_derive_pci_id ( - acpi_handle rhandle, /* upper bound */ - acpi_handle chandle, /* current node */ - struct acpi_pci_id **id) +void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ + acpi_handle chandle, /* current node */ + struct acpi_pci_id **id) { int is_bridge = 1; u8 bus_number = (*id)->bus; @@ -630,179 +620,150 @@ acpi_os_derive_pci_id ( acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number); } -#else /*!CONFIG_ACPI_PCI*/ - -acpi_status -acpi_os_write_pci_configuration ( - struct acpi_pci_id *pci_id, - u32 reg, - acpi_integer value, - u32 width) +static void acpi_os_execute_deferred(struct work_struct *work) { - return AE_SUPPORT; -} + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); + if (!dpc) { + printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); + return; + } -acpi_status -acpi_os_read_pci_configuration ( - struct acpi_pci_id *pci_id, - u32 reg, - void *value, - u32 width) -{ - return AE_SUPPORT; -} + dpc->function(dpc->context); + kfree(dpc); -void -acpi_os_derive_pci_id ( - acpi_handle rhandle, /* upper bound */ - acpi_handle chandle, /* current node */ - struct acpi_pci_id **id) -{ -} + /* Yield cpu to notify thread */ + cond_resched(); -#endif /*CONFIG_ACPI_PCI*/ + return; +} -static void -acpi_os_execute_deferred ( - void *context) +static void acpi_os_execute_notify(struct work_struct *work) { - struct acpi_os_dpc *dpc = NULL; - - ACPI_FUNCTION_TRACE ("os_execute_deferred"); + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); - dpc = (struct acpi_os_dpc *) context; if (!dpc) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); - return_VOID; + printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); + return; } dpc->function(dpc->context); kfree(dpc); - return_VOID; + return; } -acpi_status -acpi_os_queue_for_execution( - u32 priority, - acpi_osd_exec_callback function, - void *context) -{ - acpi_status status = AE_OK; - struct acpi_os_dpc *dpc; - struct work_struct *task; +/******************************************************************************* + * + * FUNCTION: acpi_os_execute + * + * PARAMETERS: Type - Type of the callback + * Function - Function to be executed + * Context - Function parameters + * + * RETURN: Status + * + * DESCRIPTION: Depending on type, either queues function for deferred execution or + * immediately executes function on a separate thread. + * + ******************************************************************************/ - ACPI_FUNCTION_TRACE ("os_queue_for_execution"); +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; - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Scheduling function [%p(%p)] for deferred execution.\n", + function, context)); if (!function) - return_ACPI_STATUS (AE_BAD_PARAMETER); + 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. */ - 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_ACPI_STATUS (AE_NO_MEMORY); + return_ACPI_STATUS(AE_NO_MEMORY); dpc->function = function; dpc->context = context; - task = (void *)(dpc+1); - INIT_WORK(task, acpi_os_execute_deferred, (void*)dpc); - - if (!queue_work(kacpid_wq, task)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to queue_work() failed.\n")); - kfree(dpc); - status = AE_ERROR; + if (type == OSL_NOTIFY_HANDLER) { + INIT_WORK(&dpc->work, acpi_os_execute_notify); + if (!queue_work(kacpi_notify_wq, &dpc->work)) { + status = AE_ERROR; + kfree(dpc); + } + } else { + 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_ACPI_STATUS (status); + return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_os_queue_for_execution); -void -acpi_os_wait_events_complete( - void *context) +EXPORT_SYMBOL(acpi_os_execute); + +void acpi_os_wait_events_complete(void *context) { flush_workqueue(kacpid_wq); } + 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)); - - *out_handle = lock_ptr; + spin_lock_init(*handle); - 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 -acpi_os_create_semaphore( - u32 max_units, - u32 initial_units, - acpi_handle *handle) +acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) { - struct semaphore *sem = NULL; + 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); - *handle = (acpi_handle*)sem; + *handle = (acpi_handle *) sem; - ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n", *handle, initial_units)); + 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); +EXPORT_SYMBOL(acpi_os_create_semaphore); /* * TODO: A better way to delete semaphores? Linux doesn't have a @@ -811,25 +772,23 @@ EXPORT_SYMBOL(acpi_os_create_semaphore); * we at least check for blocked threads and signal/cancel them? */ -acpi_status -acpi_os_delete_semaphore( - acpi_handle handle) +acpi_status acpi_os_delete_semaphore(acpi_handle handle) { - struct semaphore *sem = (struct semaphore*) 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_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle)); - acpi_os_free(sem); sem = NULL; + kfree(sem); + sem = NULL; - return_ACPI_STATUS (AE_OK); + return AE_OK; } -EXPORT_SYMBOL(acpi_os_delete_semaphore); +EXPORT_SYMBOL(acpi_os_delete_semaphore); /* * TODO: The kernel doesn't have a 'down_timeout' function -- had to @@ -840,31 +799,33 @@ EXPORT_SYMBOL(acpi_os_delete_semaphore); * * TODO: Support for units > 1? */ -acpi_status -acpi_os_wait_semaphore( - acpi_handle handle, - u32 units, - u16 timeout) +acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) { - acpi_status status = AE_OK; - struct semaphore *sem = (struct semaphore*)handle; - int ret = 0; + acpi_status status = AE_OK; + 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)); + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", + handle, units, timeout)); - if (in_atomic()) - timeout = 0; + /* + * 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) - { + switch (timeout) { /* * No Wait: * -------- @@ -872,8 +833,8 @@ acpi_os_wait_semaphore( * acquire the semaphore if available otherwise return AE_TIME * (a.k.a. 'would block'). */ - case 0: - if(down_trylock(sem)) + case 0: + if (down_trylock(sem)) status = AE_TIME; break; @@ -881,7 +842,7 @@ acpi_os_wait_semaphore( * Wait Indefinitely: * ------------------ */ - case ACPI_WAIT_FOREVER: + case ACPI_WAIT_FOREVER: down(sem); break; @@ -889,19 +850,18 @@ acpi_os_wait_semaphore( * Wait w/ Timeout: * ---------------- */ - default: + default: // TODO: A better timeout algorithm? { int i = 0; - static const int quantum_ms = 1000/HZ; + static const int quantum_ms = 1000 / HZ; ret = down_trylock(sem); - for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + for (i = timeout; (i > 0 && ret != 0); i -= quantum_ms) { + schedule_timeout_interruptible(1); ret = down_trylock(sem); } - + if (ret != 0) status = AE_TIME; } @@ -909,47 +869,47 @@ acpi_os_wait_semaphore( } if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Failed to acquire semaphore[%p|%d|%d], %s\n", - handle, units, timeout, acpi_format_exception(status))); - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Acquired semaphore[%p|%d|%d]\n", handle, units, timeout)); + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, + "Failed to acquire semaphore[%p|%d|%d], %s", + handle, units, timeout, + acpi_format_exception(status))); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, + "Acquired semaphore[%p|%d|%d]", handle, + units, timeout)); } - return_ACPI_STATUS (status); + return status; } -EXPORT_SYMBOL(acpi_os_wait_semaphore); +EXPORT_SYMBOL(acpi_os_wait_semaphore); /* * TODO: Support for units > 1? */ -acpi_status -acpi_os_signal_semaphore( - acpi_handle handle, - u32 units) +acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) { - struct semaphore *sem = (struct semaphore *) handle; + 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)); + 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); #ifdef ACPI_FUTURE_USAGE -u32 -acpi_os_get_line(char *buffer) +u32 acpi_os_get_line(char *buffer) { #ifdef ENABLE_DEBUGGER @@ -966,45 +926,11 @@ acpi_os_get_line(char *buffer) return 0; } -#endif /* ACPI_FUTURE_USAGE */ +#endif /* ACPI_FUTURE_USAGE */ -/* Assumes no unreadable holes inbetween */ -u8 -acpi_os_readable(void *ptr, acpi_size len) +acpi_status acpi_os_signal(u32 function, void *info) { -#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 - -u32 -acpi_os_get_thread_id (void) -{ - if (!in_atomic()) - return current->pid; - - return 0; -} - -acpi_status -acpi_os_signal ( - u32 function, - void *info) -{ - switch (function) - { + switch (function) { case ACPI_SIGNAL_FATAL: printk(KERN_ERR PREFIX "Fatal opcode executed\n"); break; @@ -1024,13 +950,13 @@ acpi_os_signal ( return AE_OK; } + EXPORT_SYMBOL(acpi_os_signal); -static int __init -acpi_os_name_setup(char *str) +static int __init acpi_os_name_setup(char *str) { char *p = acpi_os_name; - int count = ACPI_MAX_OVERRIDE_LEN-1; + int count = ACPI_MAX_OVERRIDE_LEN - 1; if (!str || !*str) return 0; @@ -1046,26 +972,43 @@ acpi_os_name_setup(char *str) *p = 0; return 1; - + } __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) +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; @@ -1074,8 +1017,7 @@ acpi_osi_setup(char *str) __setup("acpi_osi=", acpi_osi_setup); /* enable serialization to combat AE_ALREADY_EXISTS errors */ -static int __init -acpi_serialize_setup(char *str) +static int __init acpi_serialize_setup(char *str) { printk(KERN_INFO PREFIX "serialize enabled\n"); @@ -1095,8 +1037,7 @@ __setup("acpi_serialize", acpi_serialize_setup); * Run-time events on the same GPE this flag is available * to tell Linux to keep the wake-time GPEs enabled at run-time. */ -static int __init -acpi_wake_gpes_always_on_setup(char *str) +static int __init acpi_wake_gpes_always_on_setup(char *str) { printk(KERN_INFO PREFIX "wake GPEs not disabled\n"); @@ -1107,38 +1048,24 @@ acpi_wake_gpes_always_on_setup(char *str) __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); -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. - * flags is *not* the result of save_flags - it is an ACPI-specific flag variable - * that indicates whether we are at interrupt level. */ -unsigned long -acpi_os_acquire_lock ( - acpi_handle handle) +acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) { - unsigned long flags; - spin_lock_irqsave((spinlock_t *)handle, flags); + acpi_cpu_flags flags; + spin_lock_irqsave(lockp, flags); return flags; } @@ -1146,41 +1073,36 @@ acpi_os_acquire_lock ( * Release a spinlock. See above. */ -void -acpi_os_release_lock ( - acpi_handle handle, - unsigned long 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 /******************************************************************************* * * FUNCTION: acpi_os_create_cache * - * PARAMETERS: CacheName - Ascii name for the cache - * ObjectSize - Size of each cached object - * MaxDepth - Maximum depth of the cache (in objects) - * ReturnCache - Where the new cache object is returned + * PARAMETERS: name - Ascii name for the cache + * size - Size of each cached object + * depth - Maximum depth of the cache (in objects) + * cache - Where the new cache object is returned * - * RETURN: Status + * RETURN: status * * DESCRIPTION: Create a cache object * ******************************************************************************/ acpi_status -acpi_os_create_cache ( - char *name, - u16 size, - u16 depth, - acpi_cache_t **cache) +acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) { - *cache = kmem_cache_create (name, size, 0, 0, NULL, NULL); - return AE_OK; + *cache = kmem_cache_create(name, size, 0, 0, NULL, NULL); + if (*cache == NULL) + return AE_ERROR; + else + return AE_OK; } /******************************************************************************* @@ -1195,12 +1117,10 @@ acpi_os_create_cache ( * ******************************************************************************/ -acpi_status -acpi_os_purge_cache ( - acpi_cache_t *cache) +acpi_status acpi_os_purge_cache(acpi_cache_t * cache) { - (void) kmem_cache_shrink(cache); - return (AE_OK); + kmem_cache_shrink(cache); + return (AE_OK); } /******************************************************************************* @@ -1216,12 +1136,10 @@ acpi_os_purge_cache ( * ******************************************************************************/ -acpi_status -acpi_os_delete_cache ( - acpi_cache_t *cache) +acpi_status acpi_os_delete_cache(acpi_cache_t * cache) { - (void)kmem_cache_destroy(cache); - return (AE_OK); + kmem_cache_destroy(cache); + return (AE_OK); } /******************************************************************************* @@ -1238,37 +1156,121 @@ acpi_os_delete_cache ( * ******************************************************************************/ +acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) +{ + kmem_cache_free(cache, object); + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_os_validate_interface + * + * PARAMETERS: interface - Requested interface to be validated + * + * RETURN: AE_OK if interface is supported, AE_SUPPORT otherwise + * + * DESCRIPTION: Match an interface string to the interfaces supported by the + * host. Strings originate from an AML call to the _OSI method. + * + *****************************************************************************/ + acpi_status -acpi_os_release_object ( - acpi_cache_t *cache, - void *object) +acpi_os_validate_interface (char *interface) { - kmem_cache_free(cache, object); - return (AE_OK); + 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"); +#ifdef OSI_LINUX_ENABLED + printk(KERN_WARNING PREFIX + "Please test with \"acpi_osi=!Linux\"\n" + "Please send dmidecode " + "to linux-acpi@vger.kernel.org\n"); +#else + printk(KERN_WARNING PREFIX + "If \"acpi_osi=Linux\" works better,\n" + "Please send dmidecode " + "to linux-acpi@vger.kernel.org\n"); +#endif + if(osi_linux) + return AE_OK; + } + return AE_SUPPORT; } -/******************************************************************************* +/****************************************************************************** * - * FUNCTION: acpi_os_acquire_object + * FUNCTION: acpi_os_validate_address * - * PARAMETERS: Cache - Handle to cache object - * ReturnObject - Where the object is returned + * PARAMETERS: space_id - ACPI space ID + * address - Physical address + * length - Address length * - * RETURN: Status + * RETURN: AE_OK if address/length is valid for the space_id. Otherwise, + * should return AE_AML_ILLEGAL_ADDRESS. * - * DESCRIPTION: Get an object from the specified cache. If cache is empty, - * the object is allocated. + * DESCRIPTION: Validate a system address via the host OS. Used to validate + * the addresses accessed by AML operation regions. * - ******************************************************************************/ + *****************************************************************************/ -void * -acpi_os_acquire_object ( - acpi_cache_t *cache) +acpi_status +acpi_os_validate_address ( + u8 space_id, + acpi_physical_address address, + acpi_size length) { - void *object = kmem_cache_alloc(cache, GFP_KERNEL); - WARN_ON(!object); - return object; + + return AE_OK; } +#ifdef CONFIG_DMI +#ifdef OSI_LINUX_ENABLED +static int dmi_osi_not_linux(struct dmi_system_id *d) +{ + printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident); + enable_osi_linux(0); + return 0; +} +#else +static int dmi_osi_linux(struct dmi_system_id *d) +{ + printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident); + enable_osi_linux(1); + return 0; +} +#endif + +static struct dmi_system_id acpi_osl_dmi_table[] __initdata = { +#ifdef OSI_LINUX_ENABLED + /* + * Boxes that need NOT _OSI(Linux) + */ + { + .callback = dmi_osi_not_linux, + .ident = "Toshiba Satellite P100", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"), + }, + }, +#else + /* + * 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 + {} +}; +#endif /* CONFIG_DMI */ +#endif