diff options
| -rw-r--r-- | CREDITS | 5 | ||||
| -rw-r--r-- | arch/i386/kernel/acpi/boot.c | 20 | ||||
| -rw-r--r-- | arch/i386/kernel/cpu/cpufreq/acpi.c | 638 | ||||
| -rw-r--r-- | arch/ia64/kernel/acpi.c | 22 | ||||
| -rw-r--r-- | arch/ia64/kernel/iosapic.c | 2 | ||||
| -rw-r--r-- | arch/x86_64/kernel/acpi/boot.c | 20 | ||||
| -rw-r--r-- | drivers/acpi/asus_acpi.c | 753 | ||||
| -rw-r--r-- | drivers/acpi/numa.c | 28 | ||||
| -rw-r--r-- | drivers/acpi/pci_irq.c | 12 | ||||
| -rw-r--r-- | drivers/acpi/processor.c | 769 | ||||
| -rw-r--r-- | drivers/acpi/tables.c | 28 | ||||
| -rw-r--r-- | drivers/acpi/toshiba_acpi.c | 81 | ||||
| -rw-r--r-- | include/acpi/processor.h | 30 | ||||
| -rw-r--r-- | include/asm-ia64/iosapic.h | 3 | ||||
| -rw-r--r-- | include/linux/acpi.h | 4 |
15 files changed, 1396 insertions, 1019 deletions
@@ -818,6 +818,11 @@ S: 1382 Bordeaux Drive S: Sunnyvale, CA 94087 S: USA +N: Bruno Ducrot +E: ducrot@poupinou.org +D: CPUFreq and ACPI bugfixes. +S: Mougin, France + N: Don Dugger E: n0ano@valinux.com D: Linux/IA-64 diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index b4feecc962e7..8c24f7dd3194 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -32,6 +32,7 @@ #include <asm/io_apic.h> #include <asm/apic.h> #include <asm/io.h> +#include <asm/irq.h> #include <asm/mpspec.h> #if defined (CONFIG_X86_LOCAL_APIC) @@ -45,8 +46,8 @@ int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ int acpi_ht __initdata = 1; /* enable HT */ -int acpi_lapic = 0; -int acpi_ioapic = 0; +int acpi_lapic; +int acpi_ioapic; /* -------------------------------------------------------------------------- Boot-time Configuration @@ -471,7 +472,7 @@ acpi_boot_init (void) * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); return result; @@ -479,7 +480,8 @@ acpi_boot_init (void) mp_register_lapic_address(acpi_lapic_addr); - result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + MAX_APICS); if (!result) { printk(KERN_ERR PREFIX "No LAPIC entries present\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -491,7 +493,7 @@ acpi_boot_init (void) return result; } - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -528,8 +530,8 @@ acpi_boot_init (void) return 1; } - result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic); - if (!result) { + result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS); + if (!result) { printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); return -ENODEV; } @@ -541,14 +543,14 @@ acpi_boot_init (void) /* Build a default routing table for legacy (ISA) interrupts. */ mp_config_acpi_legacy_irqs(); - result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); + result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); /* TBD: Cleanup to allow fallback to MPS */ return result; } - result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); /* TBD: Cleanup to allow fallback to MPS */ diff --git a/arch/i386/kernel/cpu/cpufreq/acpi.c b/arch/i386/kernel/cpu/cpufreq/acpi.c index 7d77643a4ee1..12ff2d16f13f 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi.c @@ -1,9 +1,9 @@ /* - * acpi_processor_perf.c - ACPI Processor P-States Driver ($Revision: 1.3 $) + * acpi-cpufreq-io.c - ACPI Processor P-States Driver ($Revision: 1.3 $) * * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> - * Copyright (C) 2002, 2003 Dominik Brodowski <linux@brodo.de> + * Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -42,7 +42,6 @@ #define ACPI_PROCESSOR_CLASS "processor" #define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor P-States Driver" #define ACPI_PROCESSOR_DEVICE_NAME "Processor" -#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME ("acpi_processor_perf") @@ -52,184 +51,13 @@ MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME); MODULE_LICENSE("GPL"); -static struct acpi_processor_performance *performance; - - -static int -acpi_processor_get_performance_control ( - struct acpi_processor_performance *perf) -{ - int result = 0; - acpi_status status = 0; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *pct = NULL; - union acpi_object obj = {0}; - struct acpi_pct_register *reg = NULL; - - ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control"); - - status = acpi_evaluate_object(perf->pr->handle, "_PCT", NULL, &buffer); - if(ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n")); - return_VALUE(-ENODEV); - } - - pct = (union acpi_object *) buffer.pointer; - if (!pct || (pct->type != ACPI_TYPE_PACKAGE) - || (pct->package.count != 2)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n")); - result = -EFAULT; - goto end; - } - - /* - * control_register - */ - - obj = pct->package.elements[0]; - - if ((obj.type != ACPI_TYPE_BUFFER) - || (obj.buffer.length < sizeof(struct acpi_pct_register)) - || (obj.buffer.pointer == NULL)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Invalid _PCT data (control_register)\n")); - result = -EFAULT; - goto end; - } - - reg = (struct acpi_pct_register *) (obj.buffer.pointer); - - if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unsupported address space [%d] (control_register)\n", - (u32) reg->space_id)); - result = -EFAULT; - goto end; - } - - perf->control_register = (u16) reg->address; - perf->control_register_bit_width = reg->bit_width; - /* - * status_register - */ - - obj = pct->package.elements[1]; - - if ((obj.type != ACPI_TYPE_BUFFER) - || (obj.buffer.length < sizeof(struct acpi_pct_register)) - || (obj.buffer.pointer == NULL)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Invalid _PCT data (status_register)\n")); - result = -EFAULT; - goto end; - } - - reg = (struct acpi_pct_register *) (obj.buffer.pointer); - - if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unsupported address space [%d] (status_register)\n", - (u32) reg->space_id)); - result = -EFAULT; - goto end; - } - - perf->status_register = (u16) reg->address; - perf->status_register_bit_width = reg->bit_width; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "control_register[0x%04x] status_register[0x%04x]\n", - perf->control_register, - perf->status_register)); - -end: - acpi_os_free(buffer.pointer); - - return_VALUE(result); -} - - -static int -acpi_processor_get_performance_states ( - struct acpi_processor_performance * perf) -{ - int result = 0; - acpi_status status = AE_OK; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - struct acpi_buffer format = {sizeof("NNNNNN"), "NNNNNN"}; - struct acpi_buffer state = {0, NULL}; - union acpi_object *pss = NULL; - int i = 0; - - ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states"); - - status = acpi_evaluate_object(perf->pr->handle, "_PSS", NULL, &buffer); - if(ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n")); - return_VALUE(-ENODEV); - } - - pss = (union acpi_object *) buffer.pointer; - if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); - result = -EFAULT; - goto end; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n", - pss->package.count)); - - if (pss->package.count > ACPI_PROCESSOR_MAX_PERFORMANCE) { - perf->state_count = ACPI_PROCESSOR_MAX_PERFORMANCE; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Limiting number of states to max (%d)\n", - ACPI_PROCESSOR_MAX_PERFORMANCE)); - } - else - perf->state_count = pss->package.count; - - if (perf->state_count > 1) - perf->pr->flags.performance = 1; - - for (i = 0; i < perf->state_count; i++) { - - struct acpi_processor_px *px = &(perf->states[i]); - - state.length = sizeof(struct acpi_processor_px); - state.pointer = px; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); - - status = acpi_extract_package(&(pss->package.elements[i]), - &format, &state); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); - result = -EFAULT; - goto end; - } - - if (!px->core_frequency) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data: freq is zero\n")); - result = -EFAULT; - goto end; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n", - i, - (u32) px->core_frequency, - (u32) px->power, - (u32) px->transition_latency, - (u32) px->bus_master_latency, - (u32) px->control, - (u32) px->status)); - } +struct cpufreq_acpi_io { + struct acpi_processor_performance acpi_data; + struct cpufreq_frequency_table *freq_table; +}; -end: - acpi_os_free(buffer.pointer); +static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; - return_VALUE(result); -} static int acpi_processor_write_port( @@ -270,7 +98,8 @@ acpi_processor_read_port( static int acpi_processor_set_performance ( - struct acpi_processor_performance *perf, + struct cpufreq_acpi_io *data, + unsigned int cpu, int state) { u16 port = 0; @@ -282,38 +111,19 @@ acpi_processor_set_performance ( ACPI_FUNCTION_TRACE("acpi_processor_set_performance"); - if (!perf || !perf->pr) - return_VALUE(-EINVAL); - - if (!perf->pr->flags.performance) - return_VALUE(-ENODEV); - - if (state >= perf->state_count) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Invalid target state (P%d)\n", state)); - return_VALUE(-ENODEV); - } - - if (state < perf->pr->performance_platform_limit) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Platform limit (P%d) overrides target state (P%d)\n", - perf->pr->performance_platform_limit, state)); - return_VALUE(-ENODEV); - } - - if (state == perf->state) { + if (state == data->acpi_data.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Already at target state (P%d)\n", state)); return_VALUE(0); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n", - perf->state, state)); + data->acpi_data.state, state)); /* cpufreq frequency struct */ - cpufreq_freqs.cpu = perf->pr->id; - cpufreq_freqs.old = perf->states[perf->state].core_frequency; - cpufreq_freqs.new = perf->states[state].core_frequency; + cpufreq_freqs.cpu = cpu; + cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency; + cpufreq_freqs.new = data->freq_table[state].frequency; /* notify cpufreq */ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); @@ -323,9 +133,9 @@ acpi_processor_set_performance ( * control_register. */ - port = perf->control_register; - bit_width = perf->control_register_bit_width; - value = (u32) perf->states[state].control; + port = data->acpi_data.control_register.address; + bit_width = data->acpi_data.control_register.bit_width; + value = (u32) data->acpi_data.states[state].control; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Writing 0x%08x to port 0x%04x\n", value, port)); @@ -344,12 +154,12 @@ acpi_processor_set_performance ( * giving up. */ - port = perf->status_register; - bit_width = perf->status_register_bit_width; + port = data->acpi_data.status_register.address; + bit_width = data->acpi_data.status_register.bit_width; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Looking for 0x%08x from port 0x%04x\n", - (u32) perf->states[state].status, port)); + (u32) data->acpi_data.states[state].status, port)); for (i=0; i<100; i++) { ret = acpi_processor_read_port(port, bit_width, &value); @@ -358,7 +168,7 @@ acpi_processor_set_performance ( "Invalid port width 0x%04x\n", bit_width)); return_VALUE(ret); } - if (value == (u32) perf->states[state].status) + if (value == (u32) data->acpi_data.states[state].status) break; udelay(10); } @@ -366,7 +176,7 @@ acpi_processor_set_performance ( /* notify cpufreq */ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); - if (value != (u32) perf->states[state].status) { + if (value != (u32) data->acpi_data.states[state].status) { unsigned int tmp = cpufreq_freqs.new; cpufreq_freqs.new = cpufreq_freqs.old; cpufreq_freqs.old = tmp; @@ -380,169 +190,33 @@ acpi_processor_set_performance ( "Transition successful after %d microseconds\n", i * 10)); - perf->state = state; + data->acpi_data.state = state; return_VALUE(0); } -#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF -/* /proc/acpi/processor/../performance interface (DEPRECATED) */ - -static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file); -static struct file_operations acpi_processor_perf_fops = { - .open = acpi_processor_perf_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_processor *pr = (struct acpi_processor *)seq->private; - int i = 0; - - ACPI_FUNCTION_TRACE("acpi_processor_perf_seq_show"); - - if (!pr) - goto end; - - if (!pr->flags.performance || !pr->performance) { - seq_puts(seq, "<not supported>\n"); - goto end; - } - - seq_printf(seq, "state count: %d\n" - "active state: P%d\n", - pr->performance->state_count, - pr->performance->state); - - seq_puts(seq, "states:\n"); - for (i = 0; i < pr->performance->state_count; i++) - seq_printf(seq, " %cP%d: %d MHz, %d mW, %d uS\n", - (i == pr->performance->state?'*':' '), i, - (u32) pr->performance->states[i].core_frequency, - (u32) pr->performance->states[i].power, - (u32) pr->performance->states[i].transition_latency); - -end: - return 0; -} - -static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_processor_perf_seq_show, - PDE(inode)->data); -} - -static int -acpi_processor_write_performance ( - struct file *file, - const char __user *buffer, - size_t count, - loff_t *data) -{ - int result = 0; - struct acpi_processor *pr = (struct acpi_processor *) data; - char state_string[12] = {'\0'}; - unsigned int new_state = 0; - struct cpufreq_policy policy; - - ACPI_FUNCTION_TRACE("acpi_processor_write_performance"); - - if (!pr || !pr->performance || (count > sizeof(state_string) - 1)) - return_VALUE(-EINVAL); - - if (copy_from_user(state_string, buffer, count)) - return_VALUE(-EFAULT); - - state_string[count] = '\0'; - new_state = simple_strtoul(state_string, NULL, 0); - - cpufreq_get_policy(&policy, pr->id); - - policy.cpu = pr->id; - policy.max = pr->performance->states[new_state].core_frequency * 1000; - - result = cpufreq_set_policy(&policy); - if (result) - return_VALUE(result); - - return_VALUE(count); -} - -static void -acpi_cpufreq_add_file ( - struct acpi_processor *pr) -{ - struct proc_dir_entry *entry = NULL; - struct acpi_device *device = NULL; - - ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile"); - - if (acpi_bus_get_device(pr->handle, &device)) - return_VOID; - - /* add file 'performance' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_PROCESSOR_FILE_PERFORMANCE)); - else { - entry->proc_fops = &acpi_processor_perf_fops; - entry->proc_fops->write = acpi_processor_write_performance; - entry->data = acpi_driver_data(device); - } - return_VOID; -} - -static void -acpi_cpufreq_remove_file ( - struct acpi_processor *pr) -{ - struct acpi_device *device = NULL; - - ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile"); - - if (acpi_bus_get_device(pr->handle, &device)) - return_VOID; - - /* remove file 'performance' */ - remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - acpi_device_dir(device)); - - return_VOID; -} - -#else -static void acpi_cpufreq_add_file (struct acpi_processor *pr) { return; } -static void acpi_cpufreq_remove_file (struct acpi_processor *pr) { return; } -#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ - - static int acpi_cpufreq_target ( struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - struct acpi_processor_performance *perf = &performance[policy->cpu]; + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; unsigned int next_state = 0; unsigned int result = 0; ACPI_FUNCTION_TRACE("acpi_cpufreq_setpolicy"); - result = cpufreq_frequency_table_target(policy, - &perf->freq_table[perf->pr->limit.state.px], + result = cpufreq_frequency_table_target(policy, + data->freq_table, target_freq, relation, &next_state); if (result) return_VALUE(result); - result = acpi_processor_set_performance (perf, next_state); + result = acpi_processor_set_performance (data, policy->cpu, next_state); return_VALUE(result); } @@ -553,119 +227,110 @@ acpi_cpufreq_verify ( struct cpufreq_policy *policy) { unsigned int result = 0; - struct acpi_processor_performance *perf = &performance[policy->cpu]; + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; ACPI_FUNCTION_TRACE("acpi_cpufreq_verify"); result = cpufreq_frequency_table_verify(policy, - &perf->freq_table[perf->pr->limit.state.px]); - - cpufreq_verify_within_limits( - policy, - perf->states[perf->state_count - 1].core_frequency * 1000, - perf->states[perf->pr->limit.state.px].core_frequency * 1000); + data->freq_table); return_VALUE(result); } static int -acpi_processor_get_performance_info ( - struct acpi_processor_performance *perf) -{ - int result = 0; - acpi_status status = AE_OK; - acpi_handle handle = NULL; - - ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info"); - - if (!perf || !perf->pr || !perf->pr->handle) - return_VALUE(-EINVAL); - - status = acpi_get_handle(perf->pr->handle, "_PCT", &handle); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "ACPI-based processor performance control unavailable\n")); - return_VALUE(-ENODEV); - } - - result = acpi_processor_get_performance_control(perf); - if (result) - return_VALUE(result); - - result = acpi_processor_get_performance_states(perf); - if (result) - return_VALUE(result); - - result = acpi_processor_get_platform_limit(perf->pr); - if (result) - return_VALUE(result); - - return_VALUE(0); -} - - -static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) { unsigned int i; unsigned int cpu = policy->cpu; - struct acpi_processor *pr = NULL; - struct acpi_processor_performance *perf = &performance[policy->cpu]; - struct acpi_device *device; + struct cpufreq_acpi_io *data; unsigned int result = 0; ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init"); - acpi_processor_register_performance(perf, &pr, cpu); + data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); + if (!data) + return_VALUE(-ENOMEM); + memset(data, 0, sizeof(struct cpufreq_acpi_io)); - pr = performance[cpu].pr; - if (!pr) - return_VALUE(-ENODEV); + acpi_io_data[cpu] = data; - result = acpi_processor_get_performance_info(perf); + result = acpi_processor_register_performance(&data->acpi_data, cpu); if (result) - return_VALUE(-ENODEV); + goto err_free; /* capability check */ - if (!pr->flags.performance) - return_VALUE(-ENODEV); + if (data->acpi_data.state_count <= 1) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No P-States\n")); + result = -ENODEV; + goto err_unreg; + } + if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) || + (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported address space [%d, %d]\n", + (u32) (data->acpi_data.control_register.space_id), + (u32) (data->acpi_data.status_register.space_id))); + result = -ENODEV; + goto err_unreg; + } + + /* alloc freq_table */ + data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL); + if (!data->freq_table) { + result = -ENOMEM; + goto err_unreg; + } /* detect transition latency */ policy->cpuinfo.transition_latency = 0; - for (i=0;i<perf->state_count;i++) { - if ((perf->states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) - policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000; + for (i=0; i<data->acpi_data.state_count; i++) { + if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) + policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000; } policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cur = perf->states[pr->limit.state.px].core_frequency * 1000; + + /* + * The current speed is unknown and not detectable by ACPI... argh! Assume + * it's P0, it will be set to this value later during initialization. + */ + policy->cur = data->acpi_data.states[0].core_frequency * 1000; /* table init */ - for (i=0; i<=perf->state_count; i++) + for (i=0; i<=data->acpi_data.state_count; i++) { - perf->freq_table[i].index = i; - if (i<perf->state_count) - perf->freq_table[i].frequency = perf->states[i].core_frequency * 1000; + data->freq_table[i].index = i; + if (i<data->acpi_data.state_count) + data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; else - perf->freq_table[i].frequency = CPUFREQ_TABLE_END; + data->freq_table[i].frequency = CPUFREQ_TABLE_END; } - result = cpufreq_frequency_table_cpuinfo(policy, &perf->freq_table[0]); - - acpi_cpufreq_add_file(pr); - - if (acpi_bus_get_device(pr->handle, &device)) - device = NULL; + result = cpufreq_frequency_table_cpuinfo(policy, &data->freq_table[0]); + if (result) { + goto err_freqfree; + } - printk(KERN_INFO "cpufreq: %s - ACPI performance management activated.\n", - device ? acpi_device_bid(device) : "CPU??"); - for (i = 0; i < pr->performance->state_count; i++) + + printk(KERN_INFO "cpufreq: CPU%u - ACPI performance management activated.\n", + cpu); + for (i = 0; i < data->acpi_data.state_count; i++) printk(KERN_INFO "cpufreq: %cP%d: %d MHz, %d mW, %d uS\n", - (i == pr->performance->state?'*':' '), i, - (u32) pr->performance->states[i].core_frequency, - (u32) pr->performance->states[i].power, - (u32) pr->performance->states[i].transition_latency); + (i == data->acpi_data.state?'*':' '), i, + (u32) data->acpi_data.states[i].core_frequency, + (u32) data->acpi_data.states[i].power, + (u32) data->acpi_data.states[i].transition_latency); + + return_VALUE(result); + + err_freqfree: + kfree(data->freq_table); + err_unreg: + acpi_processor_unregister_performance(&data->acpi_data, cpu); + err_free: + kfree(data); + acpi_io_data[cpu] = NULL; + return_VALUE(result); } @@ -674,11 +339,16 @@ static int acpi_cpufreq_cpu_exit ( struct cpufreq_policy *policy) { - struct acpi_processor *pr = performance[policy->cpu].pr; + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; + ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_exit"); - acpi_cpufreq_remove_file(pr); + if (data) { + acpi_io_data[policy->cpu] = NULL; + acpi_processor_unregister_performance(&data->acpi_data, policy->cpu); + kfree(data); + } return_VALUE(0); } @@ -698,97 +368,11 @@ static int __init acpi_cpufreq_init (void) { int result = 0; - int current_state = 0; - int i = 0; - struct acpi_processor *pr = NULL; - struct acpi_processor_performance *perf = NULL; ACPI_FUNCTION_TRACE("acpi_cpufreq_init"); - /* alloc memory */ - if (performance) - return_VALUE(-EBUSY); - - performance = kmalloc(NR_CPUS * sizeof(struct acpi_processor_performance), GFP_KERNEL); - if (!performance) - return_VALUE(-ENOMEM); - memset(performance, 0, NR_CPUS * sizeof(struct acpi_processor_performance)); - - /* register struct acpi_processor_performance performance */ - for (i=0; i<NR_CPUS; i++) { - if (cpu_online(i)) - acpi_processor_register_performance(&performance[i], &pr, i); - } - - /* initialize */ - for (i=0; i<NR_CPUS; i++) { - if (cpu_online(i) && performance[i].pr) - result = acpi_processor_get_performance_info(&performance[i]); - } - - /* test it on one CPU */ - for (i=0; i<NR_CPUS; i++) { - if (!cpu_online(i)) - continue; - pr = performance[i].pr; - if (pr && pr->flags.performance) - goto found_capable_cpu; - } - result = -ENODEV; - goto err0; - - found_capable_cpu: - result = cpufreq_register_driver(&acpi_cpufreq_driver); - if (result) - goto err0; - perf = pr->performance; - current_state = perf->state; - - if (current_state == pr->limit.state.px) { - result = acpi_processor_set_performance(perf, (perf->state_count - 1)); - if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); - result = -ENODEV; - goto err1; - } - } - - result = acpi_processor_set_performance(perf, pr->limit.state.px); - if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); - result = -ENODEV; - goto err1; - } - - if (current_state != 0) { - result = acpi_processor_set_performance(perf, current_state); - if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); - result = -ENODEV; - goto err1; - } - } - - return_VALUE(0); - - /* error handling */ - err1: - cpufreq_unregister_driver(&acpi_cpufreq_driver); - - err0: - /* unregister struct acpi_processor_performance performance */ - for (i=0; i<NR_CPUS; i++) { - if (performance[i].pr) { - performance[i].pr->flags.performance = 0; - performance[i].pr->performance = NULL; - performance[i].pr = NULL; - } - } - kfree(performance); - - printk(KERN_INFO "cpufreq: No CPUs supporting ACPI performance management found.\n"); return_VALUE(result); } @@ -796,27 +380,9 @@ acpi_cpufreq_init (void) static void __exit acpi_cpufreq_exit (void) { - int i = 0; - ACPI_FUNCTION_TRACE("acpi_cpufreq_exit"); - for (i=0; i<NR_CPUS; i++) { - if (performance[i].pr) - performance[i].pr->flags.performance = 0; - } - - cpufreq_unregister_driver(&acpi_cpufreq_driver); - - /* unregister struct acpi_processor_performance performance */ - for (i=0; i<NR_CPUS; i++) { - if (performance[i].pr) { - performance[i].pr->flags.performance = 0; - performance[i].pr->performance = NULL; - performance[i].pr = NULL; - } - } - - kfree(performance); + cpufreq_unregister_driver(&acpi_cpufreq_driver); return_VOID; } diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 2a88bf4619ba..30f55dfc6302 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -191,8 +191,6 @@ acpi_parse_lsapic (acpi_table_entry_header *header) if (!lsapic->flags.enabled) printk(" disabled"); - else if (available_cpus >= NR_CPUS) - printk(" ignored (increase NR_CPUS)"); else { printk(" enabled"); #ifdef CONFIG_SMP @@ -395,12 +393,6 @@ acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma) size = ma->length_hi; size = (size << 32) | ma->length_lo; - if (num_memblks >= NR_MEMBLKS) { - printk(KERN_ERR "Too many mem chunks in SRAT. Ignoring %ld MBytes at %lx\n", - size/(1024*1024), paddr); - return; - } - /* Ignore disabled entries */ if (!ma->flags.enabled) return; @@ -552,29 +544,29 @@ acpi_boot_init (void) /* Local APIC */ - if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr) < 0) + if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic) < 1) + if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS) < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n"); - if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi) < 0) + if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* I/O APIC */ - if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic) < 1) + if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no IOSAPIC entries\n"); /* System-Level Interrupt Routing */ - if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src) < 0) + if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src, ACPI_MAX_PLATFORM_INTERRUPTS) < 0) printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr) < 0) + if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0) printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src) < 0) + if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0) printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); skip_madt: diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 983afbfc6ad9..0957a0170591 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -114,7 +114,7 @@ static struct iosapic { char *addr; /* base address of IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned short num_rte; /* number of RTE in this IOSAPIC */ -} iosapic_lists[256]; +} iosapic_lists[NR_IOSAPICS]; static int num_iosapic; diff --git a/arch/x86_64/kernel/acpi/boot.c b/arch/x86_64/kernel/acpi/boot.c index 33a40edea70b..d46c2d41b759 100644 --- a/arch/x86_64/kernel/acpi/boot.c +++ b/arch/x86_64/kernel/acpi/boot.c @@ -51,8 +51,8 @@ int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ int acpi_ht __initdata = 1; /* enable HT */ -int acpi_lapic = 0; -int acpi_ioapic = 0; +int acpi_lapic; +int acpi_ioapic; /* -------------------------------------------------------------------------- Boot-time Configuration @@ -439,7 +439,7 @@ acpi_boot_init (void) * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); return result; @@ -447,7 +447,8 @@ acpi_boot_init (void) mp_register_lapic_address(acpi_lapic_addr); - result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + MAX_APICS); if (!result) { printk(KERN_ERR PREFIX "No LAPIC entries present\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -459,7 +460,7 @@ acpi_boot_init (void) return result; } - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -496,8 +497,8 @@ acpi_boot_init (void) return 1; } - result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic); - if (!result) { + result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS); + if (!result) { printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); return -ENODEV; } @@ -509,14 +510,15 @@ acpi_boot_init (void) /* Build a default routing table for legacy (ISA) interrupts. */ mp_config_acpi_legacy_irqs(); - result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); + result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); /* TBD: Cleanup to allow fallback to MPS */ return result; } - result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, + NR_IRQ_VECTORS); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); /* TBD: Cleanup to allow fallback to MPS */ diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 349581f250f4..0a7fba43781c 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -2,7 +2,7 @@ * asus_acpi.c - Asus Laptop ACPI Extras * * - * Copyright (C) 2002, 2003 Julien Lerouge, Karol Kozimor + * Copyright (C) 2002, 2003, 2004 Julien Lerouge, Karol Kozimor * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,16 +23,16 @@ * http://sourceforge.net/projects/acpi4asus/ * * Credits: + * Pontus Fuchs - Helper functions, cleanup * Johann Wiesner - Small compile fixes * John Belmonte - ACPI code for Toshiba laptop was a good starting point. * * TODO: * add Fn key status * Add mode selection on module loading (parameter) -> still necessary? - * Complete display switching -- may require dirty hacks? + * Complete display switching -- may require dirty hacks or calling _DOS? */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -41,12 +41,13 @@ #include <acpi/acpi_drivers.h> #include <acpi/acpi_bus.h> -#define ASUS_ACPI_VERSION "0.26" +#define ASUS_ACPI_VERSION "0.27" #define PROC_ASUS "asus" //the directory #define PROC_MLED "mled" #define PROC_WLED "wled" -#define PROC_INFOS "info" +#define PROC_TLED "tled" +#define PROC_INFO "info" #define PROC_LCD "lcd" #define PROC_BRN "brn" #define PROC_DISP "disp" @@ -67,6 +68,7 @@ */ #define MLED_ON 0x01 //is MLED ON ? #define WLED_ON 0x02 +#define TLED_ON 0x04 MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); MODULE_DESCRIPTION(ACPI_HOTK_NAME); @@ -81,22 +83,25 @@ MODULE_PARM(asus_gid, "i"); MODULE_PARM_DESC(gid, "GID for entries in /proc/acpi/asus.\n"); -/* For each model, all features implemented */ +/* For each model, all features implemented, + * those marked with R are relative to HOTK, A for absolute */ struct model_data { - char *name; //name of the laptop - char *mt_mled; //method to handle mled - char *mled_status; //node to handle mled reading - char *mt_wled; //method to handle wled - char *wled_status; //node to handle wled reading - char *mt_lcd_switch; //method to turn LCD ON/OFF - char *lcd_status; //node to read LCD panel state - char *brightness_up; //method to set brightness up - char *brightness_down; //guess what ? - char *brightness_set; //method to set absolute brightness - char *brightness_get; //method to get absolute brightness - char *brightness_status;//node to get brightness - char *display_set; //method to set video output - char *display_get; //method to get video output + char *name; //name of the laptop________________A + char *mt_mled; //method to handle mled_____________R + char *mled_status; //node to handle mled reading_______A + char *mt_wled; //method to handle wled_____________R + char *wled_status; //node to handle wled reading_______A + char *mt_tled; //method to handle tled_____________R + char *tled_status; //node to handle tled reading_______A + char *mt_lcd_switch; //method to turn LCD ON/OFF_________A + char *lcd_status; //node to read LCD panel state______A + char *brightness_up; //method to set brightness up_______A + char *brightness_down; //guess what ?______________________A + char *brightness_set; //method to set absolute brightness_R + char *brightness_get; //method to get absolute brightness_R + char *brightness_status; //node to get brightness____________A + char *display_set; //method to set video output________R + char *display_get; //method to get video output________R }; /* @@ -104,91 +109,239 @@ struct model_data { * about the hotk device */ struct asus_hotk { - struct acpi_device *device; //the device we are in - acpi_handle handle; //the handle of the hotk device - char status; //status of the hotk, for LEDs, ... - struct model_data *methods; //methods available on the laptop - u8 brightness; //brighness level + struct acpi_device *device; //the device we are in + acpi_handle handle; //the handle of the hotk device + char status; //status of the hotk, for LEDs, ... + struct model_data *methods; //methods available on the laptop + u8 brightness; //brightness level enum { - A1X=0, //A1340D, A1300F - A2X, //A2500H - D1X, //D1 - L1X, //L1400B - L2X, //L2000D -> TODO check Q11 (Fn+F8) - // Calling this method simply hangs the - // computer, ISMI method hangs the laptop. - L3D, //L3400D - L3X, //L3C - L5X, //L5C TODO this model seems to have one more - // LED, add support - M2X, //M2400E - M3N, //M3700N, but also S1300N -> TODO WLED - S1X, //S1300A -> TODO special keys do not work ? - S2X, //S200 (J1 reported), Victor MP-XP7210 - //TODO A1370D does not seem to have an ATK device - // L8400 model doesn't have ATK + A1x = 0, //A1340D, A1300F + A2x, //A2500H + D1x, //D1 + L2D, //L2000D + L3C, //L3800C + L3D, //L3400D + L3H, //L3H, but also L2000E + L5x, //L5800C + L8L, //L8400L + M1A, //M1300A + M2E, //M2400E + S1x, //S1300A, but also L1400B and M2400A (L84F) + S2x, //S200 (J1 reported), Victor MP-XP7210 + //TODO A1370D does not seem to have an ATK device + // L8400 model doesn't have ATK + xxN, //M2400N, M3700N, S1300N (Centrino) END_MODEL - } model; //Models currently supported - u16 event_count[128]; //count for each event TODO make this better + } model; //Models currently supported + u16 event_count[128]; //count for each event TODO make this better }; /* Here we go */ -#define L3X_PREFIX "\\_SB.PCI0.PX40.ECD0." -#define S1X_PREFIX "\\_SB.PCI0.PX40." -#define L1X_PREFIX S1X_PREFIX -#define A1X_PREFIX "\\_SB.PCI0.ISA.EC0." -#define S2X_PREFIX A1X_PREFIX -#define M3N_PREFIX "\\_SB.PCI0.SBRG.EC0." +#define A1x_PREFIX "\\_SB.PCI0.ISA.EC0." +#define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0." +#define M1A_PREFIX "\\_SB.PCI0.PX40.EC0." +#define S1x_PREFIX "\\_SB.PCI0.PX40." +#define S2x_PREFIX A1x_PREFIX +#define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0." static struct model_data model_conf[END_MODEL] = { /* - * name| mled |mled read| wled |wled read| lcd sw |lcd read | - * br up|br down | br set | br read | br status|set disp | get disp - * - * br set and read shall be in hotk device ! - * same for set disp + * Those pathnames are relative to the HOTK / ATKD device : + * - mt_mled + * - mt_wled + * - brightness_set + * - brightness_get + * - display_set + * - display_get * * TODO I have seen a SWBX and AIBX method on some models, like L1400B, * it seems to be a kind of switch, but what for ? * */ - {"A1X", "MLED", "\\MAIL", NULL, NULL, A1X_PREFIX "_Q10", "\\BKLI", - A1X_PREFIX "_Q0E", A1X_PREFIX "_Q0F", NULL, NULL, NULL, NULL, NULL}, - - {"A2X", "MLED", NULL, "WLED", "\\SG66", "\\Q10", "\\BAOF", - "\\Q0E", "\\Q0F", "SPLV", "GPLV", "\\CMOD", "SDSP", "\\INFB"}, - - {"D1X", "MLED", NULL, NULL, NULL, "\\Q0D", "\\GP11", - "\\Q0C", "\\Q0B", NULL, NULL, "\\BLVL", "SDSP","\\INFB"}, - - {"L1X", "MLED", NULL, "WLED", NULL, L1X_PREFIX "Q10", "\\PNOF", - L1X_PREFIX "Q0F", L1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL}, - - {"L2X", "MLED", "\\SGP6", "WLED", "\\RCP3", "\\Q10", "\\SGP0", - "\\Q0E", "\\Q0F", NULL, NULL, NULL, "SDSP", "\\INFB"}, - - {"L3D", "MLED", "\\MALD", "WLED", NULL, "\\Q10", "\\BKLG", - "\\Q0E", "\\Q0F", "SPLV", "GPLV", "\\BLVL", "SDSP", "\\INFB"}, - {"L3X", "MLED", NULL, "WLED", NULL, L3X_PREFIX "_Q10", "\\GL32", - L3X_PREFIX "_Q0F", L3X_PREFIX "_Q0E", "SPLV", "GPLV", "\\BLVL", "SDSP", - "\\_SB.PCI0.PCI1.VGAC.NMAP"}, - - {"L5X", "MLED", NULL, "WLED", "WRED", "\\Q0D", "\\BAOF", - "\\Q0C","\\Q0B", "SPLV", "GPLV", NULL, "SDSP", "\\INFB"}, - - {"M2X", "MLED", NULL, "WLED", NULL, "\\Q10", "\\GP06", - "\\Q0E","\\Q0F", "SPLV", "GPLV", NULL, "SDSP", "\\INFB"}, - - {"M3N", "MLED", NULL, "WLED", "\\PO33", M3N_PREFIX "_Q10", "\\BKLT", - M3N_PREFIX "_Q0F", M3N_PREFIX "_Q0E", "SPLV", "GPLV", "\\LBTN", "SDSP", - "\\ADVG"}, - - {"S1X", "MLED", "\\EMLE", "WLED", NULL, S1X_PREFIX "Q10", "\\PNOF", - S1X_PREFIX "Q0F", S1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL}, - - {"S2X", "MLED", "\\MAIL", NULL, NULL, S2X_PREFIX "_Q10", "\\BKLI", - S2X_PREFIX "_Q0B", S2X_PREFIX "_Q0A", NULL, NULL, NULL, NULL, NULL} + { + .name = "A1x", + .mt_mled = "MLED", + .mled_status = "\\MAIL", + .mt_lcd_switch = A1x_PREFIX "_Q10", + .lcd_status = "\\BKLI", + .brightness_up = A1x_PREFIX "_Q0E", + .brightness_down = A1x_PREFIX "_Q0F", + }, + + { + .name = "A2x", + .mt_mled = "MLED", + .mt_wled = "WLED", + .wled_status = "\\SG66", + .mt_lcd_switch = "\\Q10", + .lcd_status = "\\BAOF", + .brightness_up = "\\Q0E", + .brightness_down = "\\Q0F", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .brightness_status = "\\CMOD", + .display_set = "SDSP", + .display_get = "\\INFB" + }, + + { + .name = "D1x", + .mt_mled = "MLED", + .mt_lcd_switch = "\\Q0D", + .lcd_status = "\\GP11", + .brightness_up = "\\Q0C", + .brightness_down = "\\Q0B", + .brightness_status = "\\BLVL", + .display_set = "SDSP", + .display_get = "\\INFB" + }, + + { + .name = "L2D", + .mt_mled = "MLED", + .mled_status = "\\SGP6", + .mt_wled = "WLED", + .wled_status = "\\RCP3", + .mt_lcd_switch = "\\Q10", + .lcd_status = "\\SGP0", + .brightness_up = "\\Q0E", + .brightness_down = "\\Q0F", + .display_set = "SDSP", + .display_get = "\\INFB" + }, + + { + .name = "L3C", + .mt_mled = "MLED", + .mt_wled = "WLED", + .mt_lcd_switch = L3C_PREFIX "_Q10", + .lcd_status = "\\GL32", + .brightness_up = L3C_PREFIX "_Q0F", + .brightness_down = L3C_PREFIX "_Q0E", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .brightness_status = "\\BLVL", + .display_set = "SDSP", + .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP" + }, + + { + .name = "L3D", + .mt_mled = "MLED", + .mled_status = "\\MALD", + .mt_wled = "WLED", + .mt_lcd_switch = "\\Q10", + .lcd_status = "\\BKLG", + .brightness_up = "\\Q0E", + .brightness_down = "\\Q0F", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .brightness_status = "\\BLVL", + .display_set = "SDSP", + .display_get = "\\INFB" + }, + + { + .name = "L3H", + .mt_mled = "MLED", + .mt_wled = "WLED", + .mt_lcd_switch = "EHK", + .lcd_status = "\\_SB.PCI0.PM.PBC", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\INFB" + }, + + { + .name = "L5x", + .mt_mled = "MLED", +// .mt_wled = "WLED", +// .wled_status = "\\WRED", +/* Present, but not controlled by ACPI */ + .mt_tled = "TLED", + .mt_lcd_switch = "\\Q0D", + .lcd_status = "\\BAOF", + .brightness_up = "\\Q0C", + .brightness_down = "\\Q0B", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\INFB" + }, + + { + .name = "L8L" +/* No features, but at least support the hotkeys */ + }, + + { + .name = "M1A", + .mt_mled = "MLED", + .mt_lcd_switch = M1A_PREFIX "Q10", + .lcd_status = "\\PNOF", + .brightness_up = M1A_PREFIX "Q0E", + .brightness_down = M1A_PREFIX "Q0F", + .brightness_status = "\\BRIT", + .display_set = "SDSP", + .display_get = "\\INFB" + }, + + { + .name = "M2E", + .mt_mled = "MLED", + .mt_wled = "WLED", + .mt_lcd_switch = "\\Q10", + .lcd_status = "\\GP06", + .brightness_up = "\\Q0E", + .brightness_down = "\\Q0F", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\INFB" + }, + + { + .name = "S1x", + .mt_mled = "MLED", + .mled_status = "\\EMLE", + .mt_wled = "WLED", + .mt_lcd_switch = S1x_PREFIX "Q10" , + .lcd_status = "\\PNOF", + .brightness_up = S1x_PREFIX "Q0F", + .brightness_down = S1x_PREFIX "Q0E", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .brightness_status = "\\BRIT", + }, + + { + .name = "S2x", + .mt_mled = "MLED", + .mled_status = "\\MAIL", + .mt_lcd_switch = S2x_PREFIX "_Q10", + .lcd_status = "\\BKLI", + .brightness_up = S2x_PREFIX "_Q0B", + .brightness_down = S2x_PREFIX "_Q0A", + }, + + { + .name = "xxN", + .mt_mled = "MLED", +// .mt_wled = "WLED", +// .wled_status = "\\PO33", +/* Present, but not controlled by ACPI */ + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = "\\BKLT", + .brightness_up = xxN_PREFIX "_Q0F", + .brightness_down = xxN_PREFIX "_Q0E", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .brightness_status = "\\LBTN", + .display_set = "SDSP", + .display_get = "\\ADVG" + } }; /* procdir we use */ @@ -264,7 +417,7 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; - int sfun; + int temp; struct asus_hotk *hotk = (struct asus_hotk *) data; char buf[16]; //enough for all info /* @@ -275,8 +428,23 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof, len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n"); len += sprintf(page + len, "Model reference : %s\n", hotk->methods->name); - if(read_acpi_int(hotk->handle, "SFUN", &sfun)) - len += sprintf(page + len, "SFUN value : 0x%04x\n", sfun); + /* + * The SFUN method probably allows the original driver to get the list + * of features supported by a given model. For now, 0x0100 or 0x0800 + * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. + * The significance of others is yet to be found. + */ + if (read_acpi_int(hotk->handle, "SFUN", &temp)) + len += sprintf(page + len, "SFUN value : 0x%04x\n", temp); + /* + * Another value for userspace: the ASYM method returns 0x02 for + * battery low and 0x04 for battery critical, it's readings tend to be + * more accurate than those provided by _BST. + * Note: since not all the laptops provide this method, errors are + * silently ignored. + */ + if (read_acpi_int(hotk->handle, "ASYM", &temp)) + len += sprintf(page + len, "ASYM value : 0x%04x\n", temp); if (asus_info) { snprintf(buf, 16, "%d", asus_info->length); len += sprintf(page + len, "DSDT length : %s\n", buf); @@ -300,128 +468,179 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof, } -/* - * proc file handlers +/* + * /proc handlers + * We write our info in page, we begin at offset off and cannot write more + * than count bytes. We set eof to 1 if we handle those 2 values. We return the + * number of bytes written in page */ + +/* Generic LED functions */ static int -proc_read_mled(char *page, char **start, off_t off, int count, int *eof, - void *data) +read_led(struct asus_hotk *hotk, const char *ledname, int ledmask) { - int len = 0; - struct asus_hotk *hotk = (struct asus_hotk *) data; - int led_status = 0; - /* - * We use the easy way, we don't care of off and count, so we don't set eof - * to 1 - */ - if (hotk->methods->mled_status) { - if (read_acpi_int(NULL, hotk->methods->mled_status, - &led_status)) - len = sprintf(page, "%d\n", led_status); + if (ledname) { + int led_status; + + if (read_acpi_int(NULL, ledname, &led_status)) + return led_status; else - printk(KERN_WARNING "Asus ACPI: Error reading MLED " + printk(KERN_WARNING "Asus ACPI: Error reading LED " "status\n"); - } else { - len = sprintf(page, "%d\n", (hotk->status & MLED_ON) ? 1 : 0); } - - return len; + return (hotk->status & ledmask) ? 1 : 0; } +/* FIXME: kill extraneous args so it can be called independently */ static int -proc_write_mled(struct file *file, const char *buffer, - unsigned long count, void *data) +write_led(const char *buffer, unsigned long count, struct asus_hotk *hotk, + char *ledname, int ledmask, int invert) { int value; int led_out = 0; - struct asus_hotk *hotk = (struct asus_hotk *) data; - - - /* scan expression. Multiple expressions may be delimited with ; */ if (sscanf(buffer, "%i", &value) == 1) - led_out = ~value & 1; + led_out = value ? 1 : 0; hotk->status = - (value) ? (hotk->status | MLED_ON) : (hotk->status & ~MLED_ON); - - /* We don't have to check mt_mled exists if we are here :) */ - if (!write_acpi_int(hotk->handle, hotk->methods->mt_mled, led_out, - NULL)) - printk(KERN_WARNING "Asus ACPI: MLED write failed\n"); + (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask); + if (invert) /* invert target value */ + led_out = !led_out & 0x1; + if (!write_acpi_int(hotk->handle, ledname, led_out, NULL)) + printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n", ledname); return count; } + /* - * We write our info in page, we begin at offset off and cannot write more - * than count bytes. We set eof to 1 if we handle those 2 values. We return the - * number of bytes written in page + * Proc handlers for MLED */ static int -proc_read_wled(char *page, char **start, off_t off, int count, int *eof, +proc_read_mled(char *page, char **start, off_t off, int count, int *eof, void *data) { - int len = 0; struct asus_hotk *hotk = (struct asus_hotk *) data; - int led_status; + return sprintf(page, "%d\n", read_led(hotk, hotk->methods->mled_status, MLED_ON)); +} - if (hotk->methods->wled_status) { - if (read_acpi_int(NULL, hotk->methods->wled_status, - &led_status)) - len = sprintf(page, "%d\n", led_status); - else - printk(KERN_WARNING "Asus ACPI: Error reading WLED " - "status\n"); - } else { - len = sprintf(page, "%d\n", (hotk->status & WLED_ON) ? 1 : 0); - } - return len; +static int +proc_write_mled(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct asus_hotk *hotk = (struct asus_hotk *) data; + return write_led(buffer, count, hotk, hotk->methods->mt_mled, MLED_ON, 1); +} + +/* + * Proc handlers for WLED + */ +static int +proc_read_wled(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + struct asus_hotk *hotk = (struct asus_hotk *) data; + return sprintf(page, "%d\n", read_led(hotk, hotk->methods->wled_status, WLED_ON)); } static int proc_write_wled(struct file *file, const char *buffer, unsigned long count, void *data) { - int value; - int led_out = 0; struct asus_hotk *hotk = (struct asus_hotk *) data; + return write_led(buffer, count, hotk, hotk->methods->mt_wled, WLED_ON, 0); +} - /* scan expression. Multiple expressions may be delimited with ; */ - if (sscanf(buffer, "%i", &value) == 1) - led_out = value & 1; - - hotk->status = - (value) ? (hotk->status | WLED_ON) : (hotk->status & ~WLED_ON); - - /* We don't have to check if mt_wled exists if we are here :) */ - if (!write_acpi_int(hotk->handle, hotk->methods->mt_wled, led_out, - NULL)) - printk(KERN_WARNING "Asus ACPI: WLED write failed\n"); - +/* + * Proc handlers for TLED + */ +static int +proc_read_tled(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + struct asus_hotk *hotk = (struct asus_hotk *) data; + return sprintf(page, "%d\n", read_led(hotk, hotk->methods->tled_status, TLED_ON)); +} - return count; +static int +proc_write_tled(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct asus_hotk *hotk = (struct asus_hotk *) data; + return write_led(buffer, count, hotk, hotk->methods->mt_tled, TLED_ON, 0); } + static int get_lcd_state(struct asus_hotk *hotk) { int lcd = 0; - /* We don't have to check anything, if we are here */ - if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd)) - printk(KERN_WARNING "Asus ACPI: Error reading LCD status\n"); + if (hotk->model != L3H) { + /* We don't have to check anything if we are here */ + if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd)) + printk(KERN_WARNING "Asus ACPI: Error reading LCD status\n"); - if (hotk->model == L2X) - lcd = ~lcd; + if (hotk->model == L2D) + lcd = ~lcd; + } else { /* L3H and the like have to be handled differently */ + acpi_status status = 0; + struct acpi_object_list input; + union acpi_object mt_params[2]; + struct acpi_buffer output; + union acpi_object out_obj; + + input.count = 2; + input.pointer = mt_params; + /* Note: the following values are partly guessed up, but + otherwise they seem to work */ + mt_params[0].type = ACPI_TYPE_INTEGER; + mt_params[0].integer.value = 0x02; + mt_params[1].type = ACPI_TYPE_INTEGER; + mt_params[1].integer.value = 0x02; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(NULL, hotk->methods->lcd_status, &input, &output); + if (status != AE_OK) + return -1; + if (out_obj.type == ACPI_TYPE_INTEGER) + /* That's what the AML code does */ + lcd = out_obj.integer.value >> 8; + } return (lcd & 1); } +static int set_lcd_state(struct asus_hotk *hotk, int value) +{ + int lcd = 0; + acpi_status status = 0; + + lcd = value ? 1 : 0; + if (lcd != get_lcd_state(hotk)) { + /* switch */ + if (hotk->model != L3H) { + status = + acpi_evaluate_object(NULL, hotk->methods->mt_lcd_switch, + NULL, NULL); + } else { /* L3H and the like have to be handled differently */ + if (!write_acpi_int(hotk->handle, hotk->methods->mt_lcd_switch, 0x07, NULL)) + status = AE_ERROR; + /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress, + the exact behaviour is simulated here */ + } + if (ACPI_FAILURE(status)) + printk(KERN_WARNING "Asus ACPI: Error switching LCD\n"); + } + return 0; + +} static int proc_read_lcd(char *page, char **start, off_t off, int count, int *eof, @@ -436,26 +655,10 @@ proc_write_lcd(struct file *file, const char *buffer, unsigned long count, void *data) { int value; - int lcd = 0; - acpi_status status = 0; - int lcd_status = 0; struct asus_hotk *hotk = (struct asus_hotk *) data; - - /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%i", &value) == 1) - lcd = value & 1; - - lcd_status = get_lcd_state(hotk); - - if (lcd_status != lcd) { - /* switch */ - status = - acpi_evaluate_object(NULL, hotk->methods->mt_lcd_switch, - NULL, NULL); - if (ACPI_FAILURE(status)) - printk(KERN_WARNING "Asus ACPI: Error switching LCD\n"); - } - + set_lcd_state(hotk, value); return count; } @@ -521,7 +724,6 @@ proc_write_brn(struct file *file, const char *buffer, int value; struct asus_hotk *hotk = (struct asus_hotk *) data; - /* scan expression. Multiple expressions may be delimited with ; */ if (sscanf(buffer, "%d", &value) == 1) { value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ @@ -546,7 +748,6 @@ static void set_display(int value, struct asus_hotk *hotk) * Now, *this* one could be more user-friendly, but so far, no-one has * complained. The significance of bits is the same as in proc_write_disp() */ - static int proc_read_disp(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -560,12 +761,11 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof, } /* - * Experimental support for display switching. As of now: 0x01 should activate - * the LCD output, 0x02 should do for CRT, and 0x04 for TV-Out. Any combination + * Experimental support for display switching. As of now: 1 should activate + * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination * (bitwise) of these will suffice. I never actually tested 3 displays hooked up - * simultaneously, so be warned. + * simultaneously, so be warned. See the acpi4asus README for more info. */ - static int proc_write_disp(struct file *file, const char *buffer, unsigned long count, void *data) @@ -573,7 +773,6 @@ proc_write_disp(struct file *file, const char *buffer, int value; struct asus_hotk *hotk = (struct asus_hotk *) data; - /* scan expression. Multiple expressions may be delimited with ; */ if (sscanf(buffer, "%d", &value) == 1) set_display(value, hotk); else { @@ -583,6 +782,31 @@ proc_write_disp(struct file *file, const char *buffer, return count; } + +typedef int (proc_readfunc)(char *page, char **start, off_t off, int count, + int *eof, void *data); +typedef int (proc_writefunc)(struct file *file, const char *buffer, + unsigned long count, void *data); + +static int +__init asus_proc_add(char *name, proc_writefunc *writefunc, + proc_readfunc *readfunc, mode_t mode, + struct acpi_device *device) +{ + struct proc_dir_entry *proc = create_proc_entry(name, mode, acpi_device_dir(device)); + if(!proc) { + printk(KERN_WARNING " Unable to create %s fs entry\n", name); + return -1; + } + proc->write_proc = writefunc; + proc->read_proc = readfunc; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid; + return 0; +} + static int __init asus_hotk_add_fs(struct acpi_device *device) { struct proc_dir_entry *proc; @@ -605,46 +829,28 @@ static int __init asus_hotk_add_fs(struct acpi_device *device) if (!acpi_device_dir(device)) return(-ENODEV); - proc = create_proc_entry(PROC_INFOS, mode, acpi_device_dir(device)); + proc = create_proc_entry(PROC_INFO, mode, acpi_device_dir(device)); if (proc) { proc->read_proc = proc_read_info; proc->data = acpi_driver_data(device); proc->owner = THIS_MODULE; proc->uid = asus_uid; - proc->gid = asus_gid;; + proc->gid = asus_gid; } else { - printk(KERN_WARNING " Unable to create " PROC_INFOS + printk(KERN_WARNING " Unable to create " PROC_INFO " fs entry\n"); } if (hotk->methods->mt_wled) { - proc = create_proc_entry(PROC_WLED, mode, acpi_device_dir(device)); - if (proc) { - proc->write_proc = proc_write_wled; - proc->read_proc = proc_read_wled; - proc->data = acpi_driver_data(device); - proc->owner = THIS_MODULE; - proc->uid = asus_uid; - proc->gid = asus_gid;; - } else { - printk(KERN_WARNING " Unable to create " PROC_WLED - " fs entry\n"); - } + asus_proc_add(PROC_WLED, &proc_write_wled, &proc_read_wled, mode, device); } if (hotk->methods->mt_mled) { - proc = create_proc_entry(PROC_MLED, mode, acpi_device_dir(device)); - if (proc) { - proc->write_proc = proc_write_mled; - proc->read_proc = proc_read_mled; - proc->data = acpi_driver_data(device); - proc->owner = THIS_MODULE; - proc->uid = asus_uid; - proc->gid = asus_gid;; - } else { - printk(KERN_WARNING " Unable to create " PROC_MLED - " fs entry\n"); - } + asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled, mode, device); + } + + if (hotk->methods->mt_tled) { + asus_proc_add(PROC_TLED, &proc_write_tled, &proc_read_tled, mode, device); } /* @@ -652,49 +858,17 @@ static int __init asus_hotk_add_fs(struct acpi_device *device) * from keyboard */ if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) { - proc = create_proc_entry(PROC_LCD, mode, acpi_device_dir(device)); - if (proc) { - proc->write_proc = proc_write_lcd; - proc->read_proc = proc_read_lcd; - proc->data = acpi_driver_data(device); - proc->owner = THIS_MODULE; - proc->uid = asus_uid; - proc->gid = asus_gid;; - } else { - printk(KERN_WARNING " Unable to create " PROC_LCD - " fs entry\n"); - } + asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode, device); } if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || (hotk->methods->brightness_get && hotk->methods->brightness_get)) { - proc = create_proc_entry(PROC_BRN, mode, acpi_device_dir(device)); - if (proc) { - proc->write_proc = proc_write_brn; - proc->read_proc = proc_read_brn; - proc->data = acpi_driver_data(device); - proc->owner = THIS_MODULE; - proc->uid = asus_uid; - proc->gid = asus_gid;; - } else { - printk(KERN_WARNING " Unable to create " PROC_BRN - " fs entry\n"); - } + asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode, device); } if (hotk->methods->display_set) { - proc = create_proc_entry(PROC_DISP, mode, acpi_device_dir(device)); - if (proc) { - proc->write_proc = proc_write_disp; - proc->read_proc = proc_read_disp; - proc->data = acpi_driver_data(device); - proc->owner = THIS_MODULE; - proc->uid = asus_uid; - proc->gid = asus_gid;; - } else { - printk(KERN_WARNING " Unable to create " PROC_DISP - " fs entry\n"); - } + asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp, mode, device); + } return 0; @@ -761,11 +935,6 @@ static int __init asus_hotk_get_info(struct asus_hotk *hotk) else if (bsts_result) printk(KERN_NOTICE " BSTS called, 0x%02x returned\n", bsts_result); - /* - * Here, we also use asus_info to make decision. For example, on INIT - * method, S1X and L1X models both reports to be L84F, but they don't - * have the same methods (L1X has WLED, S1X don't) - */ model = (union acpi_object *) buffer.pointer; if (model->type == ACPI_TYPE_STRING) { printk(KERN_NOTICE " %s model detected, ", model->string.pointer); @@ -774,52 +943,63 @@ static int __init asus_hotk_get_info(struct asus_hotk *hotk) hotk->model = END_MODEL; if (strncmp(model->string.pointer, "L3D", 3) == 0) hotk->model = L3D; - /* - * L2B has same settings that L3X, except for GL32, but as - * there is no node to get the LCD status, and as GL32 is never - * used anywhere else, I assume it's safe, even if lcd get is - * broken for this model (TODO fix it ?) - */ + else if (strncmp(model->string.pointer, "L3H", 3) == 0 || + strncmp(model->string.pointer, "L2E", 3) == 0) + hotk->model = L3H; else if (strncmp(model->string.pointer, "L3", 2) == 0 || strncmp(model->string.pointer, "L2B", 3) == 0) - hotk->model = L3X; + hotk->model = L3C; + else if (strncmp(model->string.pointer, "L8L", 3) == 0) + hotk->model = L8L; + else if (strncmp(model->string.pointer, "M2N", 3) == 0 || + strncmp(model->string.pointer, "M3N", 3) == 0 || + strncmp(model->string.pointer, "S1N", 3) == 0 || + strncmp(model->string.pointer, "S5N", 3) == 0) + hotk->model = xxN; + else if (strncmp(model->string.pointer, "M1", 2) == 0) + hotk->model = M1A; else if (strncmp(model->string.pointer, "M2", 2) == 0) - hotk->model = M2X; - else if (strncmp(model->string.pointer, "M3N", 3) == 0 || - strncmp(model->string.pointer, "S1N", 3) == 0) - hotk->model = M3N; /* S1300N is similar enough */ + hotk->model = M2E; else if (strncmp(model->string.pointer, "L2", 2) == 0) - hotk->model = L2X; - else if (strncmp(model->string.pointer, "L8", 2) == 0) { - /* S1300A reports L84F, but L1400B too */ - if (asus_info) { - if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) - hotk->model = L1X; - } else - hotk->model = S1X; - } + hotk->model = L2D; + else if (strncmp(model->string.pointer, "L8", 2) == 0) + hotk->model = S1x; else if (strncmp(model->string.pointer, "D1", 2) == 0) - hotk->model = D1X; + hotk->model = D1x; else if (strncmp(model->string.pointer, "A1", 2) == 0) - hotk->model = A1X; + hotk->model = A1x; else if (strncmp(model->string.pointer, "A2", 2) == 0) - hotk->model = A2X; + hotk->model = A2x; else if (strncmp(model->string.pointer, "J1", 2) == 0) - hotk->model = S2X; + hotk->model = S2x; else if (strncmp(model->string.pointer, "L5", 2) == 0) - hotk->model = L5X; + hotk->model = L5x; if (hotk->model == END_MODEL) { /* By default use the same values, as I don't know others */ printk("unsupported, trying default values, supply the " "developers with your DSDT\n"); - hotk->model = L2X; + hotk->model = M2E; } else { printk("supported\n"); } hotk->methods = &model_conf[hotk->model]; + /* Sort of per-model blacklist */ + if (strncmp(model->string.pointer, "L2B", 3) == 0) + hotk->methods->lcd_status = NULL; + /* L2B is similar enough to L3C to use its settings, with this only + exception */ + else if (strncmp(model->string.pointer, "S5N", 3) == 0) + hotk->methods->mt_mled = NULL; + /* S5N has no MLED */ + else if (asus_info) { + if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) + hotk->methods->mled_status = NULL; + /* S1300A reports L84F, but L1400B too, account for that */ + } + acpi_os_free(model); return AE_OK; @@ -917,8 +1097,6 @@ static int __init asus_hotk_add(struct acpi_device *device) } - - static int asus_hotk_remove(struct acpi_device *device, int type) { acpi_status status = 0; @@ -940,15 +1118,13 @@ static int asus_hotk_remove(struct acpi_device *device, int type) } - - static int __init asus_acpi_init(void) { int result; asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); if (!asus_proc_dir) { - printk(KERN_ERR "Asus ACPI: Unable to create /proc entry"); + printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); return(-ENODEV); } asus_proc_dir->owner = THIS_MODULE; @@ -963,7 +1139,6 @@ static int __init asus_acpi_init(void) } - static void __exit asus_acpi_exit(void) { acpi_bus_unregister_driver(&asus_hotk_driver); diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 62a484e4f6f8..90f609127127 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -30,8 +30,9 @@ #include <linux/errno.h> #include <linux/acpi.h> #include <acpi/acpi_bus.h> +#include <acpi/acmacros.h> -extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler); +extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, unsigned int max_entries); void __init acpi_table_print_srat_entry ( @@ -46,9 +47,9 @@ acpi_table_print_srat_entry ( { struct acpi_table_processor_affinity *p = (struct acpi_table_processor_affinity*) header; - printk(KERN_INFO PREFIX "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", p->apic_id, p->lsapic_eid, p->proximity_domain, - p->flags.enabled?"enabled":"disabled"); + p->flags.enabled?"enabled":"disabled")); } break; @@ -56,11 +57,11 @@ acpi_table_print_srat_entry ( { struct acpi_table_memory_affinity *p = (struct acpi_table_memory_affinity*) header; - printk(KERN_INFO PREFIX "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n", p->base_addr_hi, p->base_addr_lo, p->length_hi, p->length_lo, p->memory_type, p->proximity_domain, p->flags.enabled ? "enabled" : "disabled", - p->flags.hot_pluggable ? " hot-pluggable" : ""); + p->flags.hot_pluggable ? " hot-pluggable" : "")); } break; @@ -97,7 +98,7 @@ acpi_parse_slit (unsigned long phys_addr, unsigned long size) static int __init acpi_parse_processor_affinity (acpi_table_entry_header *header) { - struct acpi_table_processor_affinity *processor_affinity = NULL; + struct acpi_table_processor_affinity *processor_affinity; processor_affinity = (struct acpi_table_processor_affinity*) header; if (!processor_affinity) @@ -115,7 +116,7 @@ acpi_parse_processor_affinity (acpi_table_entry_header *header) static int __init acpi_parse_memory_affinity (acpi_table_entry_header *header) { - struct acpi_table_memory_affinity *memory_affinity = NULL; + struct acpi_table_memory_affinity *memory_affinity; memory_affinity = (struct acpi_table_memory_affinity*) header; if (!memory_affinity) @@ -133,7 +134,7 @@ acpi_parse_memory_affinity (acpi_table_entry_header *header) static int __init acpi_parse_srat (unsigned long phys_addr, unsigned long size) { - struct acpi_table_srat *srat = NULL; + struct acpi_table_srat *srat; if (!phys_addr || !size) return -EINVAL; @@ -149,10 +150,11 @@ acpi_parse_srat (unsigned long phys_addr, unsigned long size) int __init acpi_table_parse_srat ( enum acpi_srat_entry_id id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { return acpi_table_parse_madt_family(ACPI_SRAT, sizeof(struct acpi_table_srat), - id, handler); + id, handler, max_entries); } @@ -166,9 +168,11 @@ acpi_numa_init() if (result > 0) { result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY, - acpi_parse_processor_affinity); + acpi_parse_processor_affinity, + NR_CPUS); result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, - acpi_parse_memory_affinity); + acpi_parse_memory_affinity, + NR_MEMBLKS); } else { /* FIXME */ printk("Warning: acpi_table_parse(ACPI_SRAT) returned %d!\n",result); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 28ffe3793400..9dbc354ba518 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -315,7 +315,6 @@ acpi_pci_irq_enable ( { int irq = 0; u8 pin = 0; - static u16 irq_mask = 0; ACPI_FUNCTION_TRACE("acpi_pci_irq_enable"); @@ -372,10 +371,13 @@ acpi_pci_irq_enable ( * Make sure all (legacy) PCI IRQs are set as level-triggered. */ #ifdef CONFIG_X86 - if ((dev->irq < 16) && !((1 << dev->irq) & irq_mask)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Setting IRQ %d as level-triggered\n", dev->irq)); - irq_mask |= (1 << dev->irq); - eisa_set_level_irq(dev->irq); + { + static u16 irq_mask; + if ((dev->irq < 16) && !((1 << dev->irq) & irq_mask)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Setting IRQ %d as level-triggered\n", dev->irq)); + irq_mask |= (1 << dev->irq); + eisa_set_level_irq(dev->irq); + } } #endif #ifdef CONFIG_IOSAPIC diff --git a/drivers/acpi/processor.c b/drivers/acpi/processor.c index 1b85aff25b96..8bf340c1a557 100644 --- a/drivers/acpi/processor.c +++ b/drivers/acpi/processor.c @@ -3,6 +3,7 @@ * * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> + * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -22,7 +23,7 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * TBD: - * 1. Make # power/performance states dynamic. + * 1. Make # power states dynamic. * 2. Support duty_cycle values that span bit 4. * 3. Optimize by having scheduler determine business instead of * having us try to calculate it here. @@ -55,9 +56,9 @@ #define ACPI_PROCESSOR_DEVICE_NAME "Processor" #define ACPI_PROCESSOR_FILE_INFO "info" #define ACPI_PROCESSOR_FILE_POWER "power" -#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define ACPI_PROCESSOR_FILE_THROTTLING "throttling" #define ACPI_PROCESSOR_FILE_LIMIT "limit" +#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 @@ -746,7 +747,62 @@ acpi_processor_get_power_info ( /* -------------------------------------------------------------------------- Performance Management -------------------------------------------------------------------------- */ -int +#ifdef CONFIG_CPU_FREQ + +static DECLARE_MUTEX(performance_sem); + +/* + * _PPC support is implemented as a CPUfreq policy notifier: + * This means each time a CPUfreq driver registered also with + * the ACPI core is asked to change the speed policy, the maximum + * value is adjusted so that it is within the platform limit. + * + * Also, when a new platform limit value is detected, the CPUfreq + * policy is adjusted accordingly. + */ + +static int acpi_processor_ppc_is_init = 0; + +static int acpi_processor_ppc_notifier(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct cpufreq_policy *policy = data; + struct acpi_processor *pr; + unsigned int ppc = 0; + + down(&performance_sem); + + if (event != CPUFREQ_INCOMPATIBLE) + goto out; + + pr = processors[policy->cpu]; + if (!pr || !pr->performance) + goto out; + + ppc = (unsigned int) pr->performance_platform_limit; + if (!ppc) + goto out; + + if (ppc > pr->performance->state_count) + goto out; + + cpufreq_verify_within_limits(policy, 0, + pr->performance->states[ppc].core_frequency * 1000); + + out: + up(&performance_sem); + + return 0; +} + + +static struct notifier_block acpi_ppc_notifier_block = { + .notifier_call = acpi_processor_ppc_notifier, +}; + + +static int acpi_processor_get_platform_limit ( struct acpi_processor* pr) { @@ -770,35 +826,491 @@ acpi_processor_get_platform_limit ( pr->performance_platform_limit = (int) ppc; - acpi_processor_get_limit_info(pr); + return_VALUE(0); +} + + +static int acpi_processor_ppc_has_changed( + struct acpi_processor *pr) +{ + int ret = acpi_processor_get_platform_limit(pr); + if (ret < 0) + return (ret); + else + return cpufreq_update_policy(pr->id); +} + + +static void acpi_processor_ppc_init(void) { + if (!cpufreq_register_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER)) + acpi_processor_ppc_is_init = 1; + else + printk(KERN_DEBUG "Warning: Processor Platform Limit not supported.\n"); +} + + +static void acpi_processor_ppc_exit(void) { + if (acpi_processor_ppc_is_init) + cpufreq_unregister_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER); + + acpi_processor_ppc_is_init = 0; +} + +/* + * when registering a cpufreq driver with this ACPI processor driver, the + * _PCT and _PSS structures are read out and written into struct + * acpi_processor_performance. + */ + +static int acpi_processor_set_pdc (struct acpi_processor *pr) +{ + acpi_status status = AE_OK; + u32 arg0_buf[3]; + union acpi_object arg0 = {ACPI_TYPE_BUFFER}; + struct acpi_object_list no_object = {1, &arg0}; + struct acpi_object_list *pdc; + + ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); + arg0.buffer.length = 12; + arg0.buffer.pointer = (u8 *) arg0_buf; + arg0_buf[0] = ACPI_PDC_REVISION_ID; + arg0_buf[1] = 0; + arg0_buf[2] = 0; + + pdc = (pr->performance->pdc) ? pr->performance->pdc : &no_object; + + status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL); + + if ((ACPI_FAILURE(status)) && (pr->performance->pdc)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n")); + + return_VALUE(status); +} + + +static int +acpi_processor_get_performance_control ( + struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = 0; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *pct = NULL; + union acpi_object obj = {0}; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control"); + + status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer); + if(ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n")); + return_VALUE(-ENODEV); + } + + pct = (union acpi_object *) buffer.pointer; + if (!pct || (pct->type != ACPI_TYPE_PACKAGE) + || (pct->package.count != 2)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n")); + result = -EFAULT; + goto end; + } + + /* + * control_register + */ + + obj = pct->package.elements[0]; + + if ((obj.type != ACPI_TYPE_BUFFER) + || (obj.buffer.length < sizeof(struct acpi_pct_register)) + || (obj.buffer.pointer == NULL)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid _PCT data (control_register)\n")); + result = -EFAULT; + goto end; + } + memcpy(&pr->performance->control_register, obj.buffer.pointer, sizeof(struct acpi_pct_register)); + + + /* + * status_register + */ + + obj = pct->package.elements[1]; + + if ((obj.type != ACPI_TYPE_BUFFER) + || (obj.buffer.length < sizeof(struct acpi_pct_register)) + || (obj.buffer.pointer == NULL)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid _PCT data (status_register)\n")); + result = -EFAULT; + goto end; + } + + memcpy(&pr->performance->status_register, obj.buffer.pointer, sizeof(struct acpi_pct_register)); + +end: + acpi_os_free(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_processor_get_performance_states ( + struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_buffer format = {sizeof("NNNNNN"), "NNNNNN"}; + struct acpi_buffer state = {0, NULL}; + union acpi_object *pss = NULL; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states"); + + status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); + if(ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n")); + return_VALUE(-ENODEV); + } + + pss = (union acpi_object *) buffer.pointer; + if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); + result = -EFAULT; + goto end; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n", + pss->package.count)); + + pr->performance->state_count = pss->package.count; + pr->performance->states = kmalloc(sizeof(struct acpi_processor_px) * pss->package.count, GFP_KERNEL); + if (!pr->performance->states) { + result = -ENOMEM; + goto end; + } + + for (i = 0; i < pr->performance->state_count; i++) { + + struct acpi_processor_px *px = &(pr->performance->states[i]); + + state.length = sizeof(struct acpi_processor_px); + state.pointer = px; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); + + status = acpi_extract_package(&(pss->package.elements[i]), + &format, &state); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); + result = -EFAULT; + kfree(pr->performance->states); + goto end; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n", + i, + (u32) px->core_frequency, + (u32) px->power, + (u32) px->transition_latency, + (u32) px->bus_master_latency, + (u32) px->control, + (u32) px->status)); + + if (!px->core_frequency) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "core_frequency is 0\n")); + result = -EFAULT; + kfree(pr->performance->states); + goto end; + } + } + +end: + acpi_os_free(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_processor_get_performance_info ( + struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = AE_OK; + acpi_handle handle = NULL; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info"); + + if (!pr || !pr->performance || !pr->handle) + return_VALUE(-EINVAL); + + status = acpi_get_handle(pr->handle, "_PCT", &handle); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "ACPI-based processor performance control unavailable\n")); + return_VALUE(-ENODEV); + } + + acpi_processor_set_pdc(pr); + + result = acpi_processor_get_performance_control(pr); + if (result) + return_VALUE(result); + + result = acpi_processor_get_performance_states(pr); + if (result) + return_VALUE(result); + + result = acpi_processor_get_platform_limit(pr); + if (result) + return_VALUE(result); + return_VALUE(0); } -EXPORT_SYMBOL(acpi_processor_get_platform_limit); + + +#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF +/* /proc/acpi/processor/../performance interface (DEPRECATED) */ + +static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file); +static struct file_operations acpi_processor_perf_fops = { + .open = acpi_processor_perf_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset) +{ + struct acpi_processor *pr = (struct acpi_processor *)seq->private; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_perf_seq_show"); + + if (!pr) + goto end; + + if (!pr->performance) { + seq_puts(seq, "<not supported>\n"); + goto end; + } + + seq_printf(seq, "state count: %d\n" + "active state: P%d\n", + pr->performance->state_count, + pr->performance->state); + + seq_puts(seq, "states:\n"); + for (i = 0; i < pr->performance->state_count; i++) + seq_printf(seq, " %cP%d: %d MHz, %d mW, %d uS\n", + (i == pr->performance->state?'*':' '), i, + (u32) pr->performance->states[i].core_frequency, + (u32) pr->performance->states[i].power, + (u32) pr->performance->states[i].transition_latency); + +end: + return 0; +} + +static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, acpi_processor_perf_seq_show, + PDE(inode)->data); +} + +static int +acpi_processor_write_performance ( + struct file *file, + const char __user *buffer, + size_t count, + loff_t *data) +{ + int result = 0; + struct seq_file *m = (struct seq_file *) file->private_data; + struct acpi_processor *pr = (struct acpi_processor *) m->private; + struct acpi_processor_performance *perf; + char state_string[12] = {'\0'}; + unsigned int new_state = 0; + struct cpufreq_policy policy; + + ACPI_FUNCTION_TRACE("acpi_processor_write_performance"); + + if (!pr || (count > sizeof(state_string) - 1)) + return_VALUE(-EINVAL); + + perf = pr->performance; + if (!perf) + return_VALUE(-EINVAL); + + if (copy_from_user(state_string, buffer, count)) + return_VALUE(-EFAULT); + + state_string[count] = '\0'; + new_state = simple_strtoul(state_string, NULL, 0); + + if (new_state >= perf->state_count) + return_VALUE(-EINVAL); + + cpufreq_get_policy(&policy, pr->id); + + policy.cpu = pr->id; + policy.min = perf->states[new_state].core_frequency * 1000; + policy.max = perf->states[new_state].core_frequency * 1000; + + result = cpufreq_set_policy(&policy); + if (result) + return_VALUE(result); + + return_VALUE(count); +} + +static void +acpi_cpufreq_add_file ( + struct acpi_processor *pr) +{ + struct proc_dir_entry *entry = NULL; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile"); + + if (acpi_bus_get_device(pr->handle, &device)) + return_VOID; + + /* add file 'performance' [R/W] */ + entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_PROCESSOR_FILE_PERFORMANCE)); + else { + entry->proc_fops = &acpi_processor_perf_fops; + entry->proc_fops->write = acpi_processor_write_performance; + entry->data = acpi_driver_data(device); + } + return_VOID; +} + +static void +acpi_cpufreq_remove_file ( + struct acpi_processor *pr) +{ + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile"); + + if (acpi_bus_get_device(pr->handle, &device)) + return_VOID; + + /* remove file 'performance' */ + remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, + acpi_device_dir(device)); + + return_VOID; +} + +#else +static void acpi_cpufreq_add_file (struct acpi_processor *pr) { return; } +static void acpi_cpufreq_remove_file (struct acpi_processor *pr) { return; } +#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ + int acpi_processor_register_performance ( struct acpi_processor_performance * performance, - struct acpi_processor ** pr, unsigned int cpu) { + struct acpi_processor *pr; + ACPI_FUNCTION_TRACE("acpi_processor_register_performance"); - *pr = processors[cpu]; - if (!*pr) + if (!acpi_processor_ppc_is_init) + return_VALUE(-EINVAL); + + down(&performance_sem); + + pr = processors[cpu]; + if (!pr) { + up(&performance_sem); return_VALUE(-ENODEV); + } - if ((*pr)->performance) + if (pr->performance) { + up(&performance_sem); return_VALUE(-EBUSY); + } - (*pr)->performance = performance; - performance->pr = *pr; - return 0; + pr->performance = performance; + + if (acpi_processor_get_performance_info(pr)) { + pr->performance = NULL; + up(&performance_sem); + return_VALUE(-EIO); + } + + acpi_cpufreq_add_file(pr); + + up(&performance_sem); + return_VALUE(0); } EXPORT_SYMBOL(acpi_processor_register_performance); -/* for the rest of it, check cpufreq/acpi.c */ +void +acpi_processor_unregister_performance ( + struct acpi_processor_performance * performance, + unsigned int cpu) +{ + struct acpi_processor *pr; + + ACPI_FUNCTION_TRACE("acpi_processor_unregister_performance"); + + if (!acpi_processor_ppc_is_init) + return_VOID; + + down(&performance_sem); + + pr = processors[cpu]; + if (!pr) { + up(&performance_sem); + return_VOID; + } + + kfree(pr->performance->states); + pr->performance = NULL; + + acpi_cpufreq_remove_file(pr); + + up(&performance_sem); + + return_VOID; +} +EXPORT_SYMBOL(acpi_processor_unregister_performance); + + +/* for the rest of it, check arch/i386/kernel/cpu/cpufreq/acpi.c */ + +#else /* !CONFIG_CPU_FREQ */ + +static void acpi_processor_ppc_init(void) { return; } +static void acpi_processor_ppc_exit(void) { return; } + +static int acpi_processor_ppc_has_changed(struct acpi_processor *pr) { + static unsigned int printout = 1; + if (printout) { + printk(KERN_WARNING "Warning: Processor Platform Limit event detected, but not handled.\n"); + printk(KERN_WARNING "Consider compiling CPUfreq support into your kernel.\n"); + printout = 0; + } + return 0; +} + +#endif /* CONFIG_CPU_FREQ */ /* -------------------------------------------------------------------------- Throttling Control @@ -1043,27 +1555,6 @@ acpi_processor_apply_limit ( if (!pr->flags.limit) return_VALUE(-ENODEV); -#ifdef CONFIG_CPU_FREQ - if (pr->flags.performance) { - px = pr->performance_platform_limit; - if (pr->limit.user.px > px) - px = pr->limit.user.px; - if (pr->limit.thermal.px > px) - px = pr->limit.thermal.px; - { - struct cpufreq_policy policy; - policy.cpu = pr->id; - cpufreq_get_policy(&policy, pr->id); - policy.max = pr->performance->states[px].core_frequency * 1000; /* racy */ - result = cpufreq_set_policy(&policy); - } - if (result) - goto end; - } else if (pr->performance_platform_limit) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Platform limit event detected. Consider using ACPI P-States CPUfreq driver\n")); - } -#endif - if (pr->flags.throttling) { if (pr->limit.user.tx > tx) tx = pr->limit.user.tx; @@ -1091,6 +1582,113 @@ end: } +#ifdef CONFIG_CPU_FREQ + +/* If a passive cooling situation is detected, primarily CPUfreq is used, as it + * offers (in most cases) voltage scaling in addition to frequency scaling, and + * thus a cubic (instead of linear) reduction of energy. Also, we allow for + * _any_ cpufreq driver and not only the acpi-cpufreq driver. + */ + +static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; +static unsigned int acpi_thermal_cpufreq_is_init = 0; + + +static int cpu_has_cpufreq(unsigned int cpu) +{ + struct cpufreq_policy policy; + if (!acpi_thermal_cpufreq_is_init) + return -ENODEV; + if (!cpufreq_get_policy(&policy, cpu)) + return -ENODEV; + return 0; +} + + +static int acpi_thermal_cpufreq_increase(unsigned int cpu) +{ + if (!cpu_has_cpufreq) + return -ENODEV; + + if (cpufreq_thermal_reduction_pctg[cpu] < 60) { + cpufreq_thermal_reduction_pctg[cpu] += 20; + cpufreq_update_policy(cpu); + return 0; + } + + return -ERANGE; +} + + +static int acpi_thermal_cpufreq_decrease(unsigned int cpu) +{ + if (!cpu_has_cpufreq) + return -ENODEV; + + if (cpufreq_thermal_reduction_pctg[cpu] >= 20) { + cpufreq_thermal_reduction_pctg[cpu] -= 20; + cpufreq_update_policy(cpu); + return 0; + } + + return -ERANGE; +} + + +static int acpi_thermal_cpufreq_notifier( + struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct cpufreq_policy *policy = data; + unsigned long max_freq = 0; + + if (event != CPUFREQ_ADJUST) + goto out; + + max_freq = (policy->cpuinfo.max_freq * (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; + + cpufreq_verify_within_limits(policy, 0, max_freq); + + out: + return 0; +} + + +static struct notifier_block acpi_thermal_cpufreq_notifier_block = { + .notifier_call = acpi_thermal_cpufreq_notifier, +}; + + +static void acpi_thermal_cpufreq_init(void) { + int i; + + for (i=0; i<NR_CPUS; i++) + cpufreq_thermal_reduction_pctg[i] = 0; + + i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); + if (!i) + acpi_thermal_cpufreq_is_init = 1; +} + +static void acpi_thermal_cpufreq_exit(void) { + if (acpi_thermal_cpufreq_is_init) + cpufreq_unregister_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); + + acpi_thermal_cpufreq_is_init = 0; +} + +#else /* ! CONFIG_CPU_FREQ */ + +static void acpi_thermal_cpufreq_init(void) { return; } +static void acpi_thermal_cpufreq_exit(void) { return; } +static int acpi_thermal_cpufreq_increase(unsigned int cpu) { return -ENODEV; } +static int acpi_thermal_cpufreq_decrease(unsigned int cpu) { return -ENODEV; } + + +#endif + + int acpi_processor_set_thermal_limit ( acpi_handle handle, @@ -1099,7 +1697,6 @@ acpi_processor_set_thermal_limit ( int result = 0; struct acpi_processor *pr = NULL; struct acpi_device *device = NULL; - int px = 0; int tx = 0; ACPI_FUNCTION_TRACE("acpi_processor_set_thermal_limit"); @@ -1116,12 +1713,7 @@ acpi_processor_set_thermal_limit ( if (!pr) return_VALUE(-ENODEV); - if (!pr->flags.limit) - return_VALUE(-ENODEV); - /* Thermal limits are always relative to the current Px/Tx state. */ - if (pr->flags.performance) - pr->limit.thermal.px = pr->performance->state; if (pr->flags.throttling) pr->limit.thermal.tx = pr->throttling.state; @@ -1130,26 +1722,27 @@ acpi_processor_set_thermal_limit ( * performance state. */ - px = pr->limit.thermal.px; tx = pr->limit.thermal.tx; switch (type) { case ACPI_PROCESSOR_LIMIT_NONE: - px = 0; + do { + result = acpi_thermal_cpufreq_decrease(pr->id); + } while (!result); tx = 0; break; case ACPI_PROCESSOR_LIMIT_INCREMENT: - if (pr->flags.performance) { - if (px == (pr->performance->state_count - 1)) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, + /* if going up: P-states first, T-states later */ + + result = acpi_thermal_cpufreq_increase(pr->id); + if (!result) + goto end; + else if (result == -ERANGE) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At maximum performance state\n")); - else { - px++; - goto end; - } - } + if (pr->flags.throttling) { if (tx == (pr->throttling.state_count - 1)) ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -1160,37 +1753,41 @@ acpi_processor_set_thermal_limit ( break; case ACPI_PROCESSOR_LIMIT_DECREMENT: - if (pr->flags.performance) { - if (px == pr->performance_platform_limit) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "At minimum performance state\n")); - else { - px--; - goto end; - } - } + /* if going down: T-states first, P-states later */ + if (pr->flags.throttling) { if (tx == 0) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At minimum throttling state\n")); - else + else { tx--; + goto end; + } } + + result = acpi_thermal_cpufreq_decrease(pr->id); + if (result == -ERANGE) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "At minimum performance state\n")); + break; } end: - pr->limit.thermal.px = px; - pr->limit.thermal.tx = tx; + if (pr->flags.throttling) { + pr->limit.thermal.px = 0; + pr->limit.thermal.tx = tx; - result = acpi_processor_apply_limit(pr); - if (result) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to set thermal limit\n")); + result = acpi_processor_apply_limit(pr); + if (result) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to set thermal limit\n")); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n", - pr->limit.thermal.px, - pr->limit.thermal.tx)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n", + pr->limit.thermal.px, + pr->limit.thermal.tx)); + } else + result = 0; return_VALUE(result); } @@ -1205,7 +1802,7 @@ acpi_processor_get_limit_info ( if (!pr) return_VALUE(-EINVAL); - if (pr->flags.performance || pr->flags.throttling) + if (pr->flags.throttling) pr->flags.limit = 1; return_VALUE(0); @@ -1232,14 +1829,12 @@ static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset) "bus mastering control: %s\n" "power management: %s\n" "throttling control: %s\n" - "performance management: %s\n" "limit interface: %s\n", pr->id, pr->acpi_id, pr->flags.bm_control ? "yes" : "no", pr->flags.power ? "yes" : "no", pr->flags.throttling ? "yes" : "no", - pr->flags.performance ? "yes" : "no", pr->flags.limit ? "yes" : "no"); end: @@ -1396,11 +1991,9 @@ static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) } seq_printf(seq, "active limit: P%d:T%d\n" - "platform limit: P%d:T0\n" "user limit: P%d:T%d\n" "thermal limit: P%d:T%d\n", pr->limit.state.px, pr->limit.state.tx, - pr->flags.performance?pr->performance_platform_limit:0, pr->limit.user.px, pr->limit.user.tx, pr->limit.thermal.px, pr->limit.thermal.tx); @@ -1447,15 +2040,6 @@ acpi_processor_write_limit ( return_VALUE(-EINVAL); } - if (pr->flags.performance) { - if ((px < pr->performance_platform_limit) - || (px > (pr->performance->state_count - 1))) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid px\n")); - return_VALUE(-EINVAL); - } - pr->limit.user.px = px; - } - if (pr->flags.throttling) { if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n")); @@ -1635,9 +2219,9 @@ acpi_processor_get_info ( } acpi_processor_get_power_info(pr); - pr->flags.performance = 0; - pr->performance_platform_limit = 0; - acpi_processor_get_platform_limit(pr); +#ifdef CONFIG_CPU_FREQ + acpi_processor_ppc_has_changed(pr); +#endif acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); @@ -1651,7 +2235,6 @@ acpi_processor_notify ( u32 event, void *data) { - int result = 0; struct acpi_processor *pr = (struct acpi_processor *) data; struct acpi_device *device = NULL; @@ -1665,9 +2248,7 @@ acpi_processor_notify ( switch (event) { case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: - result = acpi_processor_get_platform_limit(pr); - if (!result) - acpi_processor_apply_limit(pr); + acpi_processor_ppc_has_changed(pr); acpi_bus_generate_event(device, event, pr->performance_platform_limit); break; @@ -1813,6 +2394,10 @@ acpi_processor_init (void) return_VALUE(-ENODEV); } + acpi_thermal_cpufreq_init(); + + acpi_processor_ppc_init(); + return_VALUE(0); } @@ -1822,6 +2407,10 @@ acpi_processor_exit (void) { ACPI_FUNCTION_TRACE("acpi_processor_exit"); + acpi_processor_ppc_exit(); + + acpi_thermal_cpufreq_exit(); + acpi_bus_unregister_driver(&acpi_processor_driver); remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index e997203d754b..2583a0fcf2ce 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -302,13 +302,14 @@ acpi_table_parse_madt_family ( enum acpi_table_id id, unsigned long madt_size, int entry_id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { void *madt = NULL; - acpi_table_entry_header *entry = NULL; - unsigned long count = 0; - unsigned long madt_end = 0; - unsigned int i = 0; + acpi_table_entry_header *entry; + unsigned int count = 0; + unsigned long madt_end; + unsigned int i; if (!handler) return -EINVAL; @@ -342,13 +343,18 @@ acpi_table_parse_madt_family ( ((unsigned long) madt + madt_size); while (((unsigned long) entry) < madt_end) { - if (entry->type == entry_id) { - count++; + if (entry->type == entry_id && + (!max_entries || count++ < max_entries)) handler(entry); - } + entry = (acpi_table_entry_header *) ((unsigned long) entry + entry->length); } + if (max_entries && count > max_entries) { + printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of " + "%i found\n", acpi_table_signatures[id], entry_id, + count - max_entries, count); + } return count; } @@ -357,10 +363,11 @@ acpi_table_parse_madt_family ( int __init acpi_table_parse_madt ( enum acpi_madt_entry_id id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { return acpi_table_parse_madt_family(ACPI_APIC, sizeof(struct acpi_table_madt), - id, handler); + id, handler, max_entries); } @@ -585,4 +592,3 @@ acpi_table_init (void) return 0; } - diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index 29a6edd1664a..245685ab850d 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -2,7 +2,7 @@ * toshiba_acpi.c - Toshiba Laptop ACPI Extras * * - * Copyright (C) 2002-2003 John Belmonte + * Copyright (C) 2002-2004 John Belmonte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ * */ -#define TOSHIBA_ACPI_VERSION "0.16" +#define TOSHIBA_ACPI_VERSION "0.17" #define PROC_INTERFACE_VERSION 1 #include <linux/kernel.h> @@ -48,9 +48,15 @@ MODULE_AUTHOR("John Belmonte"); MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); MODULE_LICENSE("GPL"); +#define MY_LOGPREFIX "toshiba_acpi: " +#define MY_ERR KERN_ERR MY_LOGPREFIX +#define MY_NOTICE KERN_NOTICE MY_LOGPREFIX +#define MY_INFO KERN_INFO MY_LOGPREFIX + /* Toshiba ACPI method paths */ #define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM" -#define METHOD_HCI "\\_SB_.VALD.GHCI" +#define METHOD_HCI_1 "\\_SB_.VALD.GHCI" +#define METHOD_HCI_2 "\\_SB_.VALZ.GHCI" #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" /* Toshiba HCI interface definitions @@ -121,6 +127,16 @@ snscanf(const char* str, int n, const char* format, ...) */ static int +is_valid_acpi_path(const char* methodName) +{ + acpi_handle handle; + acpi_status status; + + status = acpi_get_handle(0, (char*)methodName, &handle); + return !ACPI_FAILURE(status); +} + +static int write_acpi_int(const char* methodName, int val) { struct acpi_object_list params; @@ -154,6 +170,8 @@ read_acpi_int(const char* methodName, int* pVal) } #endif +static const char* method_hci /*= 0*/; + /* Perform a raw HCI call. Here we don't care about input or output buffer * format. */ @@ -177,7 +195,7 @@ hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS]) results.length = sizeof(out_objs); results.pointer = out_objs; - status = acpi_evaluate_object(0, METHOD_HCI, ¶ms, + status = acpi_evaluate_object(0, (char*)method_hci, ¶ms, &results); if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) { for (i = 0; i < out_objs->package.count; ++i) { @@ -215,7 +233,7 @@ hci_read1(u32 reg, u32* out1, u32* result) return status; } -static struct proc_dir_entry* toshiba_proc_dir; +static struct proc_dir_entry* toshiba_proc_dir /*= 0*/; static int force_fan; static int last_key_event; static int key_event_valid; @@ -270,7 +288,7 @@ read_lcd(char* p) p += sprintf(p, "brightness_levels: %d\n", HCI_LCD_BRIGHTNESS_LEVELS); } else { - p += sprintf(p, "ERROR\n"); + printk(MY_ERR "Error reading LCD brightness\n"); } return p; @@ -310,7 +328,7 @@ read_video(char* p) p += sprintf(p, "crt_out: %d\n", is_crt); p += sprintf(p, "tv_out: %d\n", is_tv); } else { - p += sprintf(p, "ERROR\n"); + printk(MY_ERR "Error reading video out status\n"); } return p; @@ -320,25 +338,31 @@ static unsigned long write_video(const char* buffer, unsigned long count) { int value; - const char* buffer_end = buffer + count; + int remain = count; int lcd_out = -1; int crt_out = -1; int tv_out = -1; u32 hci_result; int video_out; - /* scan expression. Multiple expressions may be delimited with ; */ - do { - if (snscanf(buffer, count, " lcd_out : %i", &value) == 1) + /* scan expression. Multiple expressions may be delimited with ; + * + * NOTE: to keep scanning simple, invalid fields are ignored + */ + while (remain) { + if (snscanf(buffer, remain, " lcd_out : %i", &value) == 1) lcd_out = value & 1; - else if (snscanf(buffer, count, " crt_out : %i", &value) == 1) + else if (snscanf(buffer, remain, " crt_out : %i", &value) == 1) crt_out = value & 1; - else if (snscanf(buffer, count, " tv_out : %i", &value) == 1) + else if (snscanf(buffer, remain, " tv_out : %i", &value) == 1) tv_out = value & 1; /* advance to one character past the next ; */ - do ++buffer; - while ((buffer < buffer_end) && (*(buffer-1) != ';')); - } while (buffer < buffer_end); + do { + ++buffer; + --remain; + } + while (remain && *(buffer-1) != ';'); + } hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result); if (hci_result == HCI_SUCCESS) { @@ -353,6 +377,8 @@ write_video(const char* buffer, unsigned long count) * video setting if something changed. */ if (new_video_out != video_out) write_acpi_int(METHOD_VIDEO_OUT, new_video_out); + } else { + return -EFAULT; } return count; @@ -369,7 +395,7 @@ read_fan(char* p) p += sprintf(p, "running: %d\n", (value > 0)); p += sprintf(p, "force_on: %d\n", force_fan); } else { - p += sprintf(p, "ERROR\n"); + printk(MY_ERR "Error reading fan status\n"); } return p; @@ -413,8 +439,9 @@ read_keys(char* p) * some machines where system events sporadically * become disabled. */ hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + printk(MY_NOTICE "Re-enabled hotkeys\n"); } else { - p += sprintf(p, "ERROR\n"); + printk(MY_ERR "Error reading hotkey status\n"); goto end; } } @@ -465,7 +492,7 @@ ProcItem proc_items[] = { 0 , 0 , 0 }, }; -static acpi_status +static acpi_status __init add_device(void) { struct proc_dir_entry* proc; @@ -483,7 +510,7 @@ add_device(void) return(AE_OK); } -static acpi_status +static acpi_status __exit remove_device(void) { ProcItem* item; @@ -497,15 +524,19 @@ static int __init toshiba_acpi_init(void) { acpi_status status = AE_OK; - int value; u32 hci_result; - /* simple device detection: try reading an HCI register */ - hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result); - if (hci_result != HCI_SUCCESS) + /* simple device detection: look for HCI method */ + if (is_valid_acpi_path(METHOD_HCI_1)) + method_hci = METHOD_HCI_1; + else if (is_valid_acpi_path(METHOD_HCI_2)) + method_hci = METHOD_HCI_2; + else return -ENODEV; - printk("Toshiba Laptop ACPI Extras version %s\n", TOSHIBA_ACPI_VERSION); + printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n", + TOSHIBA_ACPI_VERSION); + printk(MY_INFO " HCI method: %s\n", method_hci); force_fan = 0; key_event_valid = 0; diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 985cc0616dd1..dab7521d8ac6 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -9,8 +9,6 @@ #define ACPI_PROCESSOR_MAX_C2_LATENCY 100 #define ACPI_PROCESSOR_MAX_C3_LATENCY 1000 -#define ACPI_PROCESSOR_MAX_PERFORMANCE 8 - #define ACPI_PROCESSOR_MAX_THROTTLING 16 #define ACPI_PROCESSOR_MAX_THROTTLE 250 /* 25% */ #define ACPI_PROCESSOR_MAX_DUTY_WIDTH 4 @@ -67,20 +65,22 @@ struct acpi_processor_px { acpi_integer status; /* success indicator */ }; +#define ACPI_PDC_REVISION_ID 0x1 + struct acpi_processor_performance { - int state; - int platform_limit; - u16 control_register; - u16 status_register; - u8 control_register_bit_width; - u8 status_register_bit_width; - int state_count; - struct acpi_processor_px states[ACPI_PROCESSOR_MAX_PERFORMANCE]; - struct cpufreq_frequency_table freq_table[ACPI_PROCESSOR_MAX_PERFORMANCE]; - struct acpi_processor *pr; + unsigned int state; + unsigned int platform_limit; + struct acpi_pct_register control_register; + struct acpi_pct_register status_register; + unsigned int state_count; + struct acpi_processor_px *states; + + /* the _PDC objects passed by the driver, if any */ + struct acpi_object_list *pdc; }; + /* Throttling Control */ struct acpi_processor_tx { @@ -133,11 +133,11 @@ struct acpi_processor { struct acpi_processor_limit limit; }; -extern int acpi_processor_get_platform_limit ( - struct acpi_processor* pr); extern int acpi_processor_register_performance ( struct acpi_processor_performance * performance, - struct acpi_processor ** pr, + unsigned int cpu); +extern void acpi_processor_unregister_performance ( + struct acpi_processor_performance * performance, unsigned int cpu); #endif diff --git a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h index 68fa169e7a5b..ba8a35f418a2 100644 --- a/include/asm-ia64/iosapic.h +++ b/include/asm-ia64/iosapic.h @@ -52,6 +52,9 @@ #ifndef __ASSEMBLY__ #ifdef CONFIG_IOSAPIC + +#define NR_IOSAPICS 256 + extern void __init iosapic_system_init (int pcat_compat); extern void __init iosapic_init (unsigned long address, unsigned int gsi_base); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 8e4eba21e7ea..f851b34903e3 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -355,8 +355,8 @@ int acpi_numa_init (void); int acpi_table_init (void); int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header); -int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler); -int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler); +int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); void acpi_table_print_madt_entry (acpi_table_entry_header *madt); void acpi_table_print_srat_entry (acpi_table_entry_header *srat); |
