diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Mon Feb 2 22:05:54 2004 +++ b/CREDITS Mon Feb 2 22:05:54 2004 @@ -818,6 +818,11 @@ 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 -Nru a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c --- a/arch/i386/kernel/acpi/boot.c Mon Feb 2 22:05:54 2004 +++ b/arch/i386/kernel/acpi/boot.c Mon Feb 2 22:05:54 2004 @@ -31,6 +31,7 @@ #include #include #include +#include #include #if defined (CONFIG_X86_LOCAL_APIC) @@ -44,8 +45,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 @@ -463,7 +464,7 @@ * 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; @@ -471,7 +472,8 @@ 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 */ @@ -483,7 +485,7 @@ 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 */ @@ -520,8 +522,8 @@ 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; } @@ -533,14 +535,14 @@ /* 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 -Nru a/arch/i386/kernel/cpu/cpufreq/acpi.c b/arch/i386/kernel/cpu/cpufreq/acpi.c --- a/arch/i386/kernel/cpu/cpufreq/acpi.c Mon Feb 2 22:05:54 2004 +++ b/arch/i386/kernel/cpu/cpufreq/acpi.c Mon Feb 2 22:05:54 2004 @@ -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 * Copyright (C) 2001, 2002 Paul Diefenbaugh - * Copyright (C) 2002, 2003 Dominik Brodowski + * Copyright (C) 2002 - 2004 Dominik Brodowski * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -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_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 @@ 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_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 @@ * 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 @@ * 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 @@ "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 @@ /* 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 @@ "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, "\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 @@ 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;istate_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; iacpi_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 (istate_count) - perf->freq_table[i].frequency = perf->states[i].core_frequency * 1000; + data->freq_table[i].index = i; + if (iacpi_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 @@ 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 @@ 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; iflags.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; iflags.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 @@ static void __exit acpi_cpufreq_exit (void) { - int i = 0; - ACPI_FUNCTION_TRACE("acpi_cpufreq_exit"); - for (i=0; iflags.performance = 0; - } - - cpufreq_unregister_driver(&acpi_cpufreq_driver); - - /* unregister struct acpi_processor_performance performance */ - for (i=0; iflags.performance = 0; - performance[i].pr->performance = NULL; - performance[i].pr = NULL; - } - } - - kfree(performance); + cpufreq_unregister_driver(&acpi_cpufreq_driver); return_VOID; } diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c --- a/arch/ia64/kernel/acpi.c Mon Feb 2 22:05:54 2004 +++ b/arch/ia64/kernel/acpi.c Mon Feb 2 22:05:54 2004 @@ -191,8 +191,6 @@ 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 @@ 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 @@ /* 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 -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c --- a/arch/ia64/kernel/iosapic.c Mon Feb 2 22:05:54 2004 +++ b/arch/ia64/kernel/iosapic.c Mon Feb 2 22:05:54 2004 @@ -114,7 +114,7 @@ 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 -Nru a/arch/x86_64/kernel/acpi/boot.c b/arch/x86_64/kernel/acpi/boot.c --- a/arch/x86_64/kernel/acpi/boot.c Mon Feb 2 22:05:54 2004 +++ b/arch/x86_64/kernel/acpi/boot.c Mon Feb 2 22:05:54 2004 @@ -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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ /* 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 -Nru a/drivers/acpi/numa.c b/drivers/acpi/numa.c --- a/drivers/acpi/numa.c Mon Feb 2 22:05:54 2004 +++ b/drivers/acpi/numa.c Mon Feb 2 22:05:54 2004 @@ -30,8 +30,9 @@ #include #include #include +#include -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 @@ { 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c --- a/drivers/acpi/processor.c Mon Feb 2 22:05:54 2004 +++ b/drivers/acpi/processor.c Mon Feb 2 22:05:54 2004 @@ -3,6 +3,7 @@ * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2004 Dominik Brodowski * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -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 @@ /* -------------------------------------------------------------------------- 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 @@ 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, "\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 @@ 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 @@ } +#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; iflags.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 @@ * 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 @@ 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 @@ 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 @@ "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 @@ } 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 @@ 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_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 @@ u32 event, void *data) { - int result = 0; struct acpi_processor *pr = (struct acpi_processor *) data; struct acpi_device *device = NULL; @@ -1665,9 +2248,7 @@ 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 @@ return_VALUE(-ENODEV); } + acpi_thermal_cpufreq_init(); + + acpi_processor_ppc_init(); + return_VALUE(0); } @@ -1821,6 +2406,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); diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c --- a/drivers/acpi/tables.c Mon Feb 2 22:05:54 2004 +++ b/drivers/acpi/tables.c Mon Feb 2 22:05:54 2004 @@ -302,13 +302,14 @@ 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 @@ ((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 @@ 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 @@ return 0; } - diff -Nru a/include/acpi/processor.h b/include/acpi/processor.h --- a/include/acpi/processor.h Mon Feb 2 22:05:54 2004 +++ b/include/acpi/processor.h Mon Feb 2 22:05:54 2004 @@ -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 @@ 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_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 -Nru a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h --- a/include/asm-ia64/iosapic.h Mon Feb 2 22:05:54 2004 +++ b/include/asm-ia64/iosapic.h Mon Feb 2 22:05:54 2004 @@ -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 -Nru a/include/linux/acpi.h b/include/linux/acpi.h --- a/include/linux/acpi.h Mon Feb 2 22:05:54 2004 +++ b/include/linux/acpi.h Mon Feb 2 22:05:54 2004 @@ -355,8 +355,8 @@ 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);