summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CREDITS5
-rw-r--r--arch/i386/kernel/acpi/boot.c20
-rw-r--r--arch/i386/kernel/cpu/cpufreq/acpi.c638
-rw-r--r--arch/ia64/kernel/acpi.c22
-rw-r--r--arch/ia64/kernel/iosapic.c2
-rw-r--r--arch/x86_64/kernel/acpi/boot.c20
-rw-r--r--drivers/acpi/asus_acpi.c753
-rw-r--r--drivers/acpi/numa.c28
-rw-r--r--drivers/acpi/pci_irq.c12
-rw-r--r--drivers/acpi/processor.c769
-rw-r--r--drivers/acpi/tables.c28
-rw-r--r--drivers/acpi/toshiba_acpi.c81
-rw-r--r--include/acpi/processor.h30
-rw-r--r--include/asm-ia64/iosapic.h3
-rw-r--r--include/linux/acpi.h4
15 files changed, 1396 insertions, 1019 deletions
diff --git a/CREDITS b/CREDITS
index b93f59a16f02..13eba329ee16 100644
--- a/CREDITS
+++ b/CREDITS
@@ -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, &params,
+ status = acpi_evaluate_object(0, (char*)method_hci, &params,
&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);