From: Linus Torvalds <torvalds@woody.linux-foundation.org>
Date: Fri, 12 Oct 2007 22:42:01 +0000 (-0700)
Subject: Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
X-Git-Tag: firefly_0821_release~26012
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=4d5709a7b7d54fc5882d2943a14988a92d48c00a;p=firefly-linux-kernel-4.4.55.git

Merge /pub/scm/linux/kernel/git/davej/cpufreq

* master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq:
  [CPUFREQ] Don't take semaphore in cpufreq_quick_get()
  [CPUFREQ] Support different families in fid/did to frequency conversion
  [CPUFREQ] cpufreq_stats: misc cpuinit section annotations
  [CPUFREQ] implement !CONFIG_CPU_FREQ stub for  cpufreq_unregister_notifier()
  [CPUFREQ] mark hotplug notifier callback as __cpuinit
  [CPUFREQ] Only check for transition latency on problematic governors (kconfig fix)
  [CPUFREQ] allow ondemand and conservative cpufreq governors to be used as default
  [CPUFREQ] move policy's governor initialisation out of low-level drivers into cpufreq core
  [CPUFREQ] Longhaul - Add support for PM133 northbridge
  [CPUFREQ] x86: use num_online_nodes to get physical cpus numbers for
---

4d5709a7b7d54fc5882d2943a14988a92d48c00a
diff --cc arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index b6434a7ef8b2,000000000000..ffd01e5dcb52
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@@ -1,799 -1,0 +1,798 @@@
 +/*
 + * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.4 $)
 + *
 + *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 + *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 + *  Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
 + *  Copyright (C) 2006       Denis Sadykov <denis.m.sadykov@intel.com>
 + *
 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + *
 + *  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
 + *  the Free Software Foundation; either version 2 of the License, or (at
 + *  your option) any later version.
 + *
 + *  This program is distributed in the hope that it will be useful, but
 + *  WITHOUT ANY WARRANTY; without even the implied warranty of
 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + *  General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License along
 + *  with this program; if not, write to the Free Software Foundation, Inc.,
 + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 + *
 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/smp.h>
 +#include <linux/sched.h>
 +#include <linux/cpufreq.h>
 +#include <linux/compiler.h>
 +#include <linux/dmi.h>
 +
 +#include <linux/acpi.h>
 +#include <acpi/processor.h>
 +
 +#include <asm/io.h>
 +#include <asm/msr.h>
 +#include <asm/processor.h>
 +#include <asm/cpufeature.h>
 +#include <asm/delay.h>
 +#include <asm/uaccess.h>
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
 +
 +MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
 +MODULE_DESCRIPTION("ACPI Processor P-States Driver");
 +MODULE_LICENSE("GPL");
 +
 +enum {
 +	UNDEFINED_CAPABLE = 0,
 +	SYSTEM_INTEL_MSR_CAPABLE,
 +	SYSTEM_IO_CAPABLE,
 +};
 +
 +#define INTEL_MSR_RANGE		(0xffff)
 +#define CPUID_6_ECX_APERFMPERF_CAPABILITY	(0x1)
 +
 +struct acpi_cpufreq_data {
 +	struct acpi_processor_performance *acpi_data;
 +	struct cpufreq_frequency_table *freq_table;
 +	unsigned int max_freq;
 +	unsigned int resume;
 +	unsigned int cpu_feature;
 +};
 +
 +static struct acpi_cpufreq_data *drv_data[NR_CPUS];
 +/* acpi_perf_data is a pointer to percpu data. */
 +static struct acpi_processor_performance *acpi_perf_data;
 +
 +static struct cpufreq_driver acpi_cpufreq_driver;
 +
 +static unsigned int acpi_pstate_strict;
 +
 +static int check_est_cpu(unsigned int cpuid)
 +{
 +	struct cpuinfo_x86 *cpu = &cpu_data[cpuid];
 +
 +	if (cpu->x86_vendor != X86_VENDOR_INTEL ||
 +	    !cpu_has(cpu, X86_FEATURE_EST))
 +		return 0;
 +
 +	return 1;
 +}
 +
 +static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
 +{
 +	struct acpi_processor_performance *perf;
 +	int i;
 +
 +	perf = data->acpi_data;
 +
 +	for (i=0; i<perf->state_count; i++) {
 +		if (value == perf->states[i].status)
 +			return data->freq_table[i].frequency;
 +	}
 +	return 0;
 +}
 +
 +static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
 +{
 +	int i;
 +	struct acpi_processor_performance *perf;
 +
 +	msr &= INTEL_MSR_RANGE;
 +	perf = data->acpi_data;
 +
 +	for (i=0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
 +		if (msr == perf->states[data->freq_table[i].index].status)
 +			return data->freq_table[i].frequency;
 +	}
 +	return data->freq_table[0].frequency;
 +}
 +
 +static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data)
 +{
 +	switch (data->cpu_feature) {
 +	case SYSTEM_INTEL_MSR_CAPABLE:
 +		return extract_msr(val, data);
 +	case SYSTEM_IO_CAPABLE:
 +		return extract_io(val, data);
 +	default:
 +		return 0;
 +	}
 +}
 +
 +struct msr_addr {
 +	u32 reg;
 +};
 +
 +struct io_addr {
 +	u16 port;
 +	u8 bit_width;
 +};
 +
 +typedef union {
 +	struct msr_addr msr;
 +	struct io_addr io;
 +} drv_addr_union;
 +
 +struct drv_cmd {
 +	unsigned int type;
 +	cpumask_t mask;
 +	drv_addr_union addr;
 +	u32 val;
 +};
 +
 +static void do_drv_read(struct drv_cmd *cmd)
 +{
 +	u32 h;
 +
 +	switch (cmd->type) {
 +	case SYSTEM_INTEL_MSR_CAPABLE:
 +		rdmsr(cmd->addr.msr.reg, cmd->val, h);
 +		break;
 +	case SYSTEM_IO_CAPABLE:
 +		acpi_os_read_port((acpi_io_address)cmd->addr.io.port,
 +				&cmd->val,
 +				(u32)cmd->addr.io.bit_width);
 +		break;
 +	default:
 +		break;
 +	}
 +}
 +
 +static void do_drv_write(struct drv_cmd *cmd)
 +{
 +	u32 lo, hi;
 +
 +	switch (cmd->type) {
 +	case SYSTEM_INTEL_MSR_CAPABLE:
 +		rdmsr(cmd->addr.msr.reg, lo, hi);
 +		lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE);
 +		wrmsr(cmd->addr.msr.reg, lo, hi);
 +		break;
 +	case SYSTEM_IO_CAPABLE:
 +		acpi_os_write_port((acpi_io_address)cmd->addr.io.port,
 +				cmd->val,
 +				(u32)cmd->addr.io.bit_width);
 +		break;
 +	default:
 +		break;
 +	}
 +}
 +
 +static void drv_read(struct drv_cmd *cmd)
 +{
 +	cpumask_t saved_mask = current->cpus_allowed;
 +	cmd->val = 0;
 +
 +	set_cpus_allowed(current, cmd->mask);
 +	do_drv_read(cmd);
 +	set_cpus_allowed(current, saved_mask);
 +}
 +
 +static void drv_write(struct drv_cmd *cmd)
 +{
 +	cpumask_t saved_mask = current->cpus_allowed;
 +	unsigned int i;
 +
 +	for_each_cpu_mask(i, cmd->mask) {
 +		set_cpus_allowed(current, cpumask_of_cpu(i));
 +		do_drv_write(cmd);
 +	}
 +
 +	set_cpus_allowed(current, saved_mask);
 +	return;
 +}
 +
 +static u32 get_cur_val(cpumask_t mask)
 +{
 +	struct acpi_processor_performance *perf;
 +	struct drv_cmd cmd;
 +
 +	if (unlikely(cpus_empty(mask)))
 +		return 0;
 +
 +	switch (drv_data[first_cpu(mask)]->cpu_feature) {
 +	case SYSTEM_INTEL_MSR_CAPABLE:
 +		cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
 +		cmd.addr.msr.reg = MSR_IA32_PERF_STATUS;
 +		break;
 +	case SYSTEM_IO_CAPABLE:
 +		cmd.type = SYSTEM_IO_CAPABLE;
 +		perf = drv_data[first_cpu(mask)]->acpi_data;
 +		cmd.addr.io.port = perf->control_register.address;
 +		cmd.addr.io.bit_width = perf->control_register.bit_width;
 +		break;
 +	default:
 +		return 0;
 +	}
 +
 +	cmd.mask = mask;
 +
 +	drv_read(&cmd);
 +
 +	dprintk("get_cur_val = %u\n", cmd.val);
 +
 +	return cmd.val;
 +}
 +
 +/*
 + * Return the measured active (C0) frequency on this CPU since last call
 + * to this function.
 + * Input: cpu number
 + * Return: Average CPU frequency in terms of max frequency (zero on error)
 + *
 + * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance
 + * over a period of time, while CPU is in C0 state.
 + * IA32_MPERF counts at the rate of max advertised frequency
 + * IA32_APERF counts at the rate of actual CPU frequency
 + * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
 + * no meaning should be associated with absolute values of these MSRs.
 + */
 +static unsigned int get_measured_perf(unsigned int cpu)
 +{
 +	union {
 +		struct {
 +			u32 lo;
 +			u32 hi;
 +		} split;
 +		u64 whole;
 +	} aperf_cur, mperf_cur;
 +
 +	cpumask_t saved_mask;
 +	unsigned int perf_percent;
 +	unsigned int retval;
 +
 +	saved_mask = current->cpus_allowed;
 +	set_cpus_allowed(current, cpumask_of_cpu(cpu));
 +	if (get_cpu() != cpu) {
 +		/* We were not able to run on requested processor */
 +		put_cpu();
 +		return 0;
 +	}
 +
 +	rdmsr(MSR_IA32_APERF, aperf_cur.split.lo, aperf_cur.split.hi);
 +	rdmsr(MSR_IA32_MPERF, mperf_cur.split.lo, mperf_cur.split.hi);
 +
 +	wrmsr(MSR_IA32_APERF, 0,0);
 +	wrmsr(MSR_IA32_MPERF, 0,0);
 +
 +#ifdef __i386__
 +	/*
 +	 * We dont want to do 64 bit divide with 32 bit kernel
 +	 * Get an approximate value. Return failure in case we cannot get
 +	 * an approximate value.
 +	 */
 +	if (unlikely(aperf_cur.split.hi || mperf_cur.split.hi)) {
 +		int shift_count;
 +		u32 h;
 +
 +		h = max_t(u32, aperf_cur.split.hi, mperf_cur.split.hi);
 +		shift_count = fls(h);
 +
 +		aperf_cur.whole >>= shift_count;
 +		mperf_cur.whole >>= shift_count;
 +	}
 +
 +	if (((unsigned long)(-1) / 100) < aperf_cur.split.lo) {
 +		int shift_count = 7;
 +		aperf_cur.split.lo >>= shift_count;
 +		mperf_cur.split.lo >>= shift_count;
 +	}
 +
 +	if (aperf_cur.split.lo && mperf_cur.split.lo)
 +		perf_percent = (aperf_cur.split.lo * 100) / mperf_cur.split.lo;
 +	else
 +		perf_percent = 0;
 +
 +#else
 +	if (unlikely(((unsigned long)(-1) / 100) < aperf_cur.whole)) {
 +		int shift_count = 7;
 +		aperf_cur.whole >>= shift_count;
 +		mperf_cur.whole >>= shift_count;
 +	}
 +
 +	if (aperf_cur.whole && mperf_cur.whole)
 +		perf_percent = (aperf_cur.whole * 100) / mperf_cur.whole;
 +	else
 +		perf_percent = 0;
 +
 +#endif
 +
 +	retval = drv_data[cpu]->max_freq * perf_percent / 100;
 +
 +	put_cpu();
 +	set_cpus_allowed(current, saved_mask);
 +
 +	dprintk("cpu %d: performance percent %d\n", cpu, perf_percent);
 +	return retval;
 +}
 +
 +static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
 +{
 +	struct acpi_cpufreq_data *data = drv_data[cpu];
 +	unsigned int freq;
 +
 +	dprintk("get_cur_freq_on_cpu (%d)\n", cpu);
 +
 +	if (unlikely(data == NULL ||
 +		     data->acpi_data == NULL || data->freq_table == NULL)) {
 +		return 0;
 +	}
 +
 +	freq = extract_freq(get_cur_val(cpumask_of_cpu(cpu)), data);
 +	dprintk("cur freq = %u\n", freq);
 +
 +	return freq;
 +}
 +
 +static unsigned int check_freqs(cpumask_t mask, unsigned int freq,
 +				struct acpi_cpufreq_data *data)
 +{
 +	unsigned int cur_freq;
 +	unsigned int i;
 +
 +	for (i=0; i<100; i++) {
 +		cur_freq = extract_freq(get_cur_val(mask), data);
 +		if (cur_freq == freq)
 +			return 1;
 +		udelay(10);
 +	}
 +	return 0;
 +}
 +
 +static int acpi_cpufreq_target(struct cpufreq_policy *policy,
 +			       unsigned int target_freq, unsigned int relation)
 +{
 +	struct acpi_cpufreq_data *data = drv_data[policy->cpu];
 +	struct acpi_processor_performance *perf;
 +	struct cpufreq_freqs freqs;
 +	cpumask_t online_policy_cpus;
 +	struct drv_cmd cmd;
 +	unsigned int next_state = 0; /* Index into freq_table */
 +	unsigned int next_perf_state = 0; /* Index into perf table */
 +	unsigned int i;
 +	int result = 0;
 +
 +	dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
 +
 +	if (unlikely(data == NULL ||
 +	     data->acpi_data == NULL || data->freq_table == NULL)) {
 +		return -ENODEV;
 +	}
 +
 +	perf = data->acpi_data;
 +	result = cpufreq_frequency_table_target(policy,
 +						data->freq_table,
 +						target_freq,
 +						relation, &next_state);
 +	if (unlikely(result))
 +		return -ENODEV;
 +
 +#ifdef CONFIG_HOTPLUG_CPU
 +	/* cpufreq holds the hotplug lock, so we are safe from here on */
 +	cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
 +#else
 +	online_policy_cpus = policy->cpus;
 +#endif
 +
 +	next_perf_state = data->freq_table[next_state].index;
 +	if (perf->state == next_perf_state) {
 +		if (unlikely(data->resume)) {
 +			dprintk("Called after resume, resetting to P%d\n",
 +				next_perf_state);
 +			data->resume = 0;
 +		} else {
 +			dprintk("Already at target state (P%d)\n",
 +				next_perf_state);
 +			return 0;
 +		}
 +	}
 +
 +	switch (data->cpu_feature) {
 +	case SYSTEM_INTEL_MSR_CAPABLE:
 +		cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
 +		cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
 +		cmd.val = (u32) perf->states[next_perf_state].control;
 +		break;
 +	case SYSTEM_IO_CAPABLE:
 +		cmd.type = SYSTEM_IO_CAPABLE;
 +		cmd.addr.io.port = perf->control_register.address;
 +		cmd.addr.io.bit_width = perf->control_register.bit_width;
 +		cmd.val = (u32) perf->states[next_perf_state].control;
 +		break;
 +	default:
 +		return -ENODEV;
 +	}
 +
 +	cpus_clear(cmd.mask);
 +
 +	if (policy->shared_type != CPUFREQ_SHARED_TYPE_ANY)
 +		cmd.mask = online_policy_cpus;
 +	else
 +		cpu_set(policy->cpu, cmd.mask);
 +
 +	freqs.old = perf->states[perf->state].core_frequency * 1000;
 +	freqs.new = data->freq_table[next_state].frequency;
 +	for_each_cpu_mask(i, cmd.mask) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +	}
 +
 +	drv_write(&cmd);
 +
 +	if (acpi_pstate_strict) {
 +		if (!check_freqs(cmd.mask, freqs.new, data)) {
 +			dprintk("acpi_cpufreq_target failed (%d)\n",
 +				policy->cpu);
 +			return -EAGAIN;
 +		}
 +	}
 +
 +	for_each_cpu_mask(i, cmd.mask) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +	}
 +	perf->state = next_perf_state;
 +
 +	return result;
 +}
 +
 +static int acpi_cpufreq_verify(struct cpufreq_policy *policy)
 +{
 +	struct acpi_cpufreq_data *data = drv_data[policy->cpu];
 +
 +	dprintk("acpi_cpufreq_verify\n");
 +
 +	return cpufreq_frequency_table_verify(policy, data->freq_table);
 +}
 +
 +static unsigned long
 +acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu)
 +{
 +	struct acpi_processor_performance *perf = data->acpi_data;
 +
 +	if (cpu_khz) {
 +		/* search the closest match to cpu_khz */
 +		unsigned int i;
 +		unsigned long freq;
 +		unsigned long freqn = perf->states[0].core_frequency * 1000;
 +
 +		for (i=0; i<(perf->state_count-1); i++) {
 +			freq = freqn;
 +			freqn = perf->states[i+1].core_frequency * 1000;
 +			if ((2 * cpu_khz) > (freqn + freq)) {
 +				perf->state = i;
 +				return freq;
 +			}
 +		}
 +		perf->state = perf->state_count-1;
 +		return freqn;
 +	} else {
 +		/* assume CPU is at P0... */
 +		perf->state = 0;
 +		return perf->states[0].core_frequency * 1000;
 +	}
 +}
 +
 +/*
 + * acpi_cpufreq_early_init - initialize ACPI P-States library
 + *
 + * Initialize the ACPI P-States library (drivers/acpi/processor_perflib.c)
 + * in order to determine correct frequency and voltage pairings. We can
 + * do _PDC and _PSD and find out the processor dependency for the
 + * actual init that will happen later...
 + */
 +static int __init acpi_cpufreq_early_init(void)
 +{
 +	dprintk("acpi_cpufreq_early_init\n");
 +
 +	acpi_perf_data = alloc_percpu(struct acpi_processor_performance);
 +	if (!acpi_perf_data) {
 +		dprintk("Memory allocation error for acpi_perf_data.\n");
 +		return -ENOMEM;
 +	}
 +
 +	/* Do initialization in ACPI core */
 +	acpi_processor_preregister_performance(acpi_perf_data);
 +	return 0;
 +}
 +
 +#ifdef CONFIG_SMP
 +/*
 + * Some BIOSes do SW_ANY coordination internally, either set it up in hw
 + * or do it in BIOS firmware and won't inform about it to OS. If not
 + * detected, this has a side effect of making CPU run at a different speed
 + * than OS intended it to run at. Detect it and handle it cleanly.
 + */
 +static int bios_with_sw_any_bug;
 +
 +static int sw_any_bug_found(const struct dmi_system_id *d)
 +{
 +	bios_with_sw_any_bug = 1;
 +	return 0;
 +}
 +
 +static const struct dmi_system_id sw_any_bug_dmi_table[] = {
 +	{
 +		.callback = sw_any_bug_found,
 +		.ident = "Supermicro Server X6DLP",
 +		.matches = {
 +			DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
 +			DMI_MATCH(DMI_BIOS_VERSION, "080010"),
 +			DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
 +		},
 +	},
 +	{ }
 +};
 +#endif
 +
 +static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 +{
 +	unsigned int i;
 +	unsigned int valid_states = 0;
 +	unsigned int cpu = policy->cpu;
 +	struct acpi_cpufreq_data *data;
 +	unsigned int result = 0;
 +	struct cpuinfo_x86 *c = &cpu_data[policy->cpu];
 +	struct acpi_processor_performance *perf;
 +
 +	dprintk("acpi_cpufreq_cpu_init\n");
 +
 +	data = kzalloc(sizeof(struct acpi_cpufreq_data), GFP_KERNEL);
 +	if (!data)
 +		return -ENOMEM;
 +
 +	data->acpi_data = percpu_ptr(acpi_perf_data, cpu);
 +	drv_data[cpu] = data;
 +
 +	if (cpu_has(c, X86_FEATURE_CONSTANT_TSC))
 +		acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
 +
 +	result = acpi_processor_register_performance(data->acpi_data, cpu);
 +	if (result)
 +		goto err_free;
 +
 +	perf = data->acpi_data;
 +	policy->shared_type = perf->shared_type;
 +
 +	/*
 +	 * Will let policy->cpus know about dependency only when software
 +	 * coordination is required.
 +	 */
 +	if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
 +	    policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
 +		policy->cpus = perf->shared_cpu_map;
 +	}
 +
 +#ifdef CONFIG_SMP
 +	dmi_check_system(sw_any_bug_dmi_table);
 +	if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) {
 +		policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
 +		policy->cpus = cpu_core_map[cpu];
 +	}
 +#endif
 +
 +	/* capability check */
 +	if (perf->state_count <= 1) {
 +		dprintk("No P-States\n");
 +		result = -ENODEV;
 +		goto err_unreg;
 +	}
 +
 +	if (perf->control_register.space_id != perf->status_register.space_id) {
 +		result = -ENODEV;
 +		goto err_unreg;
 +	}
 +
 +	switch (perf->control_register.space_id) {
 +	case ACPI_ADR_SPACE_SYSTEM_IO:
 +		dprintk("SYSTEM IO addr space\n");
 +		data->cpu_feature = SYSTEM_IO_CAPABLE;
 +		break;
 +	case ACPI_ADR_SPACE_FIXED_HARDWARE:
 +		dprintk("HARDWARE addr space\n");
 +		if (!check_est_cpu(cpu)) {
 +			result = -ENODEV;
 +			goto err_unreg;
 +		}
 +		data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
 +		break;
 +	default:
 +		dprintk("Unknown addr space %d\n",
 +			(u32) (perf->control_register.space_id));
 +		result = -ENODEV;
 +		goto err_unreg;
 +	}
 +
 +	data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
 +		    (perf->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;
 +	}
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +
 +	data->max_freq = perf->states[0].core_frequency * 1000;
 +	/* table init */
 +	for (i=0; i<perf->state_count; i++) {
 +		if (i>0 && perf->states[i].core_frequency >=
 +		    data->freq_table[valid_states-1].frequency / 1000)
 +			continue;
 +
 +		data->freq_table[valid_states].index = i;
 +		data->freq_table[valid_states].frequency =
 +		    perf->states[i].core_frequency * 1000;
 +		valid_states++;
 +	}
 +	data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
 +	perf->state = 0;
 +
 +	result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
 +	if (result)
 +		goto err_freqfree;
 +
 +	switch (perf->control_register.space_id) {
 +	case ACPI_ADR_SPACE_SYSTEM_IO:
 +		/* Current speed is unknown and not detectable by IO port */
 +		policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
 +		break;
 +	case ACPI_ADR_SPACE_FIXED_HARDWARE:
 +		acpi_cpufreq_driver.get = get_cur_freq_on_cpu;
 +		policy->cur = get_cur_freq_on_cpu(cpu);
 +		break;
 +	default:
 +		break;
 +	}
 +
 +	/* notify BIOS that we exist */
 +	acpi_processor_notify_smm(THIS_MODULE);
 +
 +	/* Check for APERF/MPERF support in hardware */
 +	if (c->x86_vendor == X86_VENDOR_INTEL && c->cpuid_level >= 6) {
 +		unsigned int ecx;
 +		ecx = cpuid_ecx(6);
 +		if (ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY)
 +			acpi_cpufreq_driver.getavg = get_measured_perf;
 +	}
 +
 +	dprintk("CPU%u - ACPI performance management activated.\n", cpu);
 +	for (i = 0; i < perf->state_count; i++)
 +		dprintk("     %cP%d: %d MHz, %d mW, %d uS\n",
 +			(i == perf->state ? '*' : ' '), i,
 +			(u32) perf->states[i].core_frequency,
 +			(u32) perf->states[i].power,
 +			(u32) perf->states[i].transition_latency);
 +
 +	cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
 +
 +	/*
 +	 * the first call to ->target() should result in us actually
 +	 * writing something to the appropriate registers.
 +	 */
 +	data->resume = 1;
 +
 +	return result;
 +
 +err_freqfree:
 +	kfree(data->freq_table);
 +err_unreg:
 +	acpi_processor_unregister_performance(perf, cpu);
 +err_free:
 +	kfree(data);
 +	drv_data[cpu] = NULL;
 +
 +	return result;
 +}
 +
 +static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	struct acpi_cpufreq_data *data = drv_data[policy->cpu];
 +
 +	dprintk("acpi_cpufreq_cpu_exit\n");
 +
 +	if (data) {
 +		cpufreq_frequency_table_put_attr(policy->cpu);
 +		drv_data[policy->cpu] = NULL;
 +		acpi_processor_unregister_performance(data->acpi_data,
 +						      policy->cpu);
 +		kfree(data);
 +	}
 +
 +	return 0;
 +}
 +
 +static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
 +{
 +	struct acpi_cpufreq_data *data = drv_data[policy->cpu];
 +
 +	dprintk("acpi_cpufreq_resume\n");
 +
 +	data->resume = 1;
 +
 +	return 0;
 +}
 +
 +static struct freq_attr *acpi_cpufreq_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver acpi_cpufreq_driver = {
 +	.verify = acpi_cpufreq_verify,
 +	.target = acpi_cpufreq_target,
 +	.init = acpi_cpufreq_cpu_init,
 +	.exit = acpi_cpufreq_cpu_exit,
 +	.resume = acpi_cpufreq_resume,
 +	.name = "acpi-cpufreq",
 +	.owner = THIS_MODULE,
 +	.attr = acpi_cpufreq_attr,
 +};
 +
 +static int __init acpi_cpufreq_init(void)
 +{
 +	int ret;
 +
 +	dprintk("acpi_cpufreq_init\n");
 +
 +	ret = acpi_cpufreq_early_init();
 +	if (ret)
 +		return ret;
 +
 +	return cpufreq_register_driver(&acpi_cpufreq_driver);
 +}
 +
 +static void __exit acpi_cpufreq_exit(void)
 +{
 +	dprintk("acpi_cpufreq_exit\n");
 +
 +	cpufreq_unregister_driver(&acpi_cpufreq_driver);
 +
 +	free_percpu(acpi_perf_data);
 +
 +	return;
 +}
 +
 +module_param(acpi_pstate_strict, uint, 0644);
 +MODULE_PARM_DESC(acpi_pstate_strict,
 +	"value 0 or non-zero. non-zero -> strict ACPI checks are "
 +	"performed during frequency changes.");
 +
 +late_initcall(acpi_cpufreq_init);
 +module_exit(acpi_cpufreq_exit);
 +
 +MODULE_ALIAS("acpi");
diff --cc arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
index 66acd5039918,000000000000..32f0bda3fc95
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
+++ b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
@@@ -1,441 -1,0 +1,440 @@@
 +/*
 + * (C) 2004-2006  Sebastian Witt <se.witt@gmx.net>
 + *
 + *  Licensed under the terms of the GNU GPL License version 2.
 + *  Based upon reverse engineered information
 + *
 + *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/moduleparam.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/pci.h>
 +#include <linux/delay.h>
 +
 +#define NFORCE2_XTAL 25
 +#define NFORCE2_BOOTFSB 0x48
 +#define NFORCE2_PLLENABLE 0xa8
 +#define NFORCE2_PLLREG 0xa4
 +#define NFORCE2_PLLADR 0xa0
 +#define NFORCE2_PLL(mul, div) (0x100000 | (mul << 8) | div)
 +
 +#define NFORCE2_MIN_FSB 50
 +#define NFORCE2_SAFE_DISTANCE 50
 +
 +/* Delay in ms between FSB changes */
 +//#define NFORCE2_DELAY 10
 +
 +/* nforce2_chipset:
 + * FSB is changed using the chipset
 + */
 +static struct pci_dev *nforce2_chipset_dev;
 +
 +/* fid:
 + * multiplier * 10
 + */
 +static int fid = 0;
 +
 +/* min_fsb, max_fsb:
 + * minimum and maximum FSB (= FSB at boot time)
 + */
 +static int min_fsb = 0;
 +static int max_fsb = 0;
 +
 +MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
 +MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver");
 +MODULE_LICENSE("GPL");
 +
 +module_param(fid, int, 0444);
 +module_param(min_fsb, int, 0444);
 +
 +MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
 +MODULE_PARM_DESC(min_fsb,
 +                 "Minimum FSB to use, if not defined: current FSB - 50");
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-nforce2", msg)
 +
 +/**
 + * nforce2_calc_fsb - calculate FSB
 + * @pll: PLL value
 + *
 + *   Calculates FSB from PLL value
 + */
 +static int nforce2_calc_fsb(int pll)
 +{
 +	unsigned char mul, div;
 +
 +	mul = (pll >> 8) & 0xff;
 +	div = pll & 0xff;
 +
 +	if (div > 0)
 +		return NFORCE2_XTAL * mul / div;
 +
 +	return 0;
 +}
 +
 +/**
 + * nforce2_calc_pll - calculate PLL value
 + * @fsb: FSB
 + *
 + *   Calculate PLL value for given FSB
 + */
 +static int nforce2_calc_pll(unsigned int fsb)
 +{
 +	unsigned char xmul, xdiv;
 +	unsigned char mul = 0, div = 0;
 +	int tried = 0;
 +
 +	/* Try to calculate multiplier and divider up to 4 times */
 +	while (((mul == 0) || (div == 0)) && (tried <= 3)) {
 +		for (xdiv = 2; xdiv <= 0x80; xdiv++)
 +			for (xmul = 1; xmul <= 0xfe; xmul++)
 +				if (nforce2_calc_fsb(NFORCE2_PLL(xmul, xdiv)) ==
 +				    fsb + tried) {
 +					mul = xmul;
 +					div = xdiv;
 +				}
 +		tried++;
 +	}
 +
 +	if ((mul == 0) || (div == 0))
 +		return -1;
 +
 +	return NFORCE2_PLL(mul, div);
 +}
 +
 +/**
 + * nforce2_write_pll - write PLL value to chipset
 + * @pll: PLL value
 + *
 + *   Writes new FSB PLL value to chipset
 + */
 +static void nforce2_write_pll(int pll)
 +{
 +	int temp;
 +
 +	/* Set the pll addr. to 0x00 */
 +	pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLADR, 0);
 +
 +	/* Now write the value in all 64 registers */
 +	for (temp = 0; temp <= 0x3f; temp++)
 +		pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLREG, pll);
 +
 +	return;
 +}
 +
 +/**
 + * nforce2_fsb_read - Read FSB
 + *
 + *   Read FSB from chipset
 + *   If bootfsb != 0, return FSB at boot-time
 + */
 +static unsigned int nforce2_fsb_read(int bootfsb)
 +{
 +	struct pci_dev *nforce2_sub5;
 +	u32 fsb, temp = 0;
 +
 +	/* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */
 +	nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
 +						0x01EF,PCI_ANY_ID,PCI_ANY_ID,NULL);
 +	if (!nforce2_sub5)
 +		return 0;
 +
 +	pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb);
 +	fsb /= 1000000;
 +
 +	/* Check if PLL register is already set */
 +	pci_read_config_byte(nforce2_chipset_dev,NFORCE2_PLLENABLE, (u8 *)&temp);
 +
 +	if(bootfsb || !temp)
 +		return fsb;
 +		
 +	/* Use PLL register FSB value */
 +	pci_read_config_dword(nforce2_chipset_dev,NFORCE2_PLLREG, &temp);
 +	fsb = nforce2_calc_fsb(temp);
 +
 +	return fsb;
 +}
 +
 +/**
 + * nforce2_set_fsb - set new FSB
 + * @fsb: New FSB
 + *
 + *   Sets new FSB
 + */
 +static int nforce2_set_fsb(unsigned int fsb)
 +{
 +	u32 temp = 0;
 +	unsigned int tfsb;
 +	int diff;
 +	int pll = 0;
 +
 +	if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
 +		printk(KERN_ERR "cpufreq: FSB %d is out of range!\n", fsb);
 +		return -EINVAL;
 +	}
 +
 +	tfsb = nforce2_fsb_read(0);
 +	if (!tfsb) {
 +		printk(KERN_ERR "cpufreq: Error while reading the FSB\n");
 +		return -EINVAL;
 +	}
 +
 +	/* First write? Then set actual value */
 +	pci_read_config_byte(nforce2_chipset_dev,NFORCE2_PLLENABLE, (u8 *)&temp);
 +	if (!temp) {
 +		pll = nforce2_calc_pll(tfsb);
 +
 +		if (pll < 0)
 +			return -EINVAL;
 +
 +		nforce2_write_pll(pll);
 +	}
 +
 +	/* Enable write access */
 +	temp = 0x01;
 +	pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8)temp);
 +
 +	diff = tfsb - fsb;
 +
 +	if (!diff)
 +		return 0;
 +
 +	while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) {
 +		if (diff < 0)
 +			tfsb++;
 +		else
 +			tfsb--;
 +
 +		/* Calculate the PLL reg. value */
 +		if ((pll = nforce2_calc_pll(tfsb)) == -1)
 +			return -EINVAL;
 +
 +		nforce2_write_pll(pll);
 +#ifdef NFORCE2_DELAY
 +		mdelay(NFORCE2_DELAY);
 +#endif
 +	}
 +
 +	temp = 0x40;
 +	pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLADR, (u8)temp);
 +
 +	return 0;
 +}
 +
 +/**
 + * nforce2_get - get the CPU frequency
 + * @cpu: CPU number
 + *
 + * Returns the CPU frequency
 + */
 +static unsigned int nforce2_get(unsigned int cpu)
 +{
 +	if (cpu)
 +		return 0;
 +	return nforce2_fsb_read(0) * fid * 100;
 +}
 +
 +/**
 + * nforce2_target - set a new CPUFreq policy
 + * @policy: new policy
 + * @target_freq: the target frequency
 + * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
 + *
 + * Sets a new CPUFreq policy.
 + */
 +static int nforce2_target(struct cpufreq_policy *policy,
 +			  unsigned int target_freq, unsigned int relation)
 +{
 +//        unsigned long         flags;
 +	struct cpufreq_freqs freqs;
 +	unsigned int target_fsb;
 +
 +	if ((target_freq > policy->max) || (target_freq < policy->min))
 +		return -EINVAL;
 +
 +	target_fsb = target_freq / (fid * 100);
 +
 +	freqs.old = nforce2_get(policy->cpu);
 +	freqs.new = target_fsb * fid * 100;
 +	freqs.cpu = 0;		/* Only one CPU on nForce2 plattforms */
 +
 +	if (freqs.old == freqs.new)
 +		return 0;
 +
 +	dprintk("Old CPU frequency %d kHz, new %d kHz\n",
 +	       freqs.old, freqs.new);
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +
 +	/* Disable IRQs */
 +	//local_irq_save(flags);
 +
 +	if (nforce2_set_fsb(target_fsb) < 0)
 +		printk(KERN_ERR "cpufreq: Changing FSB to %d failed\n",
 +                       target_fsb);
 +	else
 +		dprintk("Changed FSB successfully to %d\n",
 +                       target_fsb);
 +
 +	/* Enable IRQs */
 +	//local_irq_restore(flags);
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +
 +	return 0;
 +}
 +
 +/**
 + * nforce2_verify - verifies a new CPUFreq policy
 + * @policy: new policy
 + */
 +static int nforce2_verify(struct cpufreq_policy *policy)
 +{
 +	unsigned int fsb_pol_max;
 +
 +	fsb_pol_max = policy->max / (fid * 100);
 +
 +	if (policy->min < (fsb_pol_max * fid * 100))
 +		policy->max = (fsb_pol_max + 1) * fid * 100;
 +
 +	cpufreq_verify_within_limits(policy,
 +                                     policy->cpuinfo.min_freq,
 +                                     policy->cpuinfo.max_freq);
 +	return 0;
 +}
 +
 +static int nforce2_cpu_init(struct cpufreq_policy *policy)
 +{
 +	unsigned int fsb;
 +	unsigned int rfid;
 +
 +	/* capability check */
 +	if (policy->cpu != 0)
 +		return -ENODEV;
 +
 +	/* Get current FSB */
 +	fsb = nforce2_fsb_read(0);
 +
 +	if (!fsb)
 +		return -EIO;
 +
 +	/* FIX: Get FID from CPU */
 +	if (!fid) {
 +		if (!cpu_khz) {
 +			printk(KERN_WARNING
 +			       "cpufreq: cpu_khz not set, can't calculate multiplier!\n");
 +			return -ENODEV;
 +		}
 +
 +		fid = cpu_khz / (fsb * 100);
 +		rfid = fid % 5;
 +
 +		if (rfid) {
 +			if (rfid > 2)
 +				fid += 5 - rfid;
 +			else
 +				fid -= rfid;
 +		}
 +	}
 +
 +	printk(KERN_INFO "cpufreq: FSB currently at %i MHz, FID %d.%d\n", fsb,
 +	       fid / 10, fid % 10);
 +
 +	/* Set maximum FSB to FSB at boot time */
 +	max_fsb = nforce2_fsb_read(1);
 +
 +	if(!max_fsb)
 +		return -EIO;
 +
 +	if (!min_fsb)
 +		min_fsb = max_fsb - NFORCE2_SAFE_DISTANCE;
 +
 +	if (min_fsb < NFORCE2_MIN_FSB)
 +		min_fsb = NFORCE2_MIN_FSB;
 +
 +	/* cpuinfo and default policy values */
 +	policy->cpuinfo.min_freq = min_fsb * fid * 100;
 +	policy->cpuinfo.max_freq = max_fsb * fid * 100;
 +	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 +	policy->cur = nforce2_get(policy->cpu);
 +	policy->min = policy->cpuinfo.min_freq;
 +	policy->max = policy->cpuinfo.max_freq;
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +
 +	return 0;
 +}
 +
 +static int nforce2_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	return 0;
 +}
 +
 +static struct cpufreq_driver nforce2_driver = {
 +	.name = "nforce2",
 +	.verify = nforce2_verify,
 +	.target = nforce2_target,
 +	.get = nforce2_get,
 +	.init = nforce2_cpu_init,
 +	.exit = nforce2_cpu_exit,
 +	.owner = THIS_MODULE,
 +};
 +
 +/**
 + * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic
 + *
 + * Detects nForce2 A2 and C1 stepping
 + *
 + */
 +static unsigned int nforce2_detect_chipset(void)
 +{
 +	nforce2_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
 +					PCI_DEVICE_ID_NVIDIA_NFORCE2,
 +					PCI_ANY_ID, PCI_ANY_ID, NULL);
 +
 +	if (nforce2_chipset_dev == NULL)
 +		return -ENODEV;
 +
 +	printk(KERN_INFO "cpufreq: Detected nForce2 chipset revision %X\n",
 +	       nforce2_chipset_dev->revision);
 +	printk(KERN_INFO
 +	       "cpufreq: FSB changing is maybe unstable and can lead to crashes and data loss.\n");
 +
 +	return 0;
 +}
 +
 +/**
 + * nforce2_init - initializes the nForce2 CPUFreq driver
 + *
 + * Initializes the nForce2 FSB support. Returns -ENODEV on unsupported
 + * devices, -EINVAL on problems during initiatization, and zero on
 + * success.
 + */
 +static int __init nforce2_init(void)
 +{
 +	/* TODO: do we need to detect the processor? */
 +
 +	/* detect chipset */
 +	if (nforce2_detect_chipset()) {
 +		printk(KERN_ERR "cpufreq: No nForce2 chipset.\n");
 +		return -ENODEV;
 +	}
 +
 +	return cpufreq_register_driver(&nforce2_driver);
 +}
 +
 +/**
 + * nforce2_exit - unregisters cpufreq module
 + *
 + *   Unregisters nForce2 FSB change support.
 + */
 +static void __exit nforce2_exit(void)
 +{
 +	cpufreq_unregister_driver(&nforce2_driver);
 +}
 +
 +module_init(nforce2_init);
 +module_exit(nforce2_exit);
 +
diff --cc arch/x86/kernel/cpu/cpufreq/e_powersaver.c
index f43d98e11cc7,000000000000..c11baaf9f2b4
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
+++ b/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
@@@ -1,334 -1,0 +1,333 @@@
 +/*
 + *  Based on documentation provided by Dave Jones. Thanks!
 + *
 + *  Licensed under the terms of the GNU GPL License version 2.
 + *
 + *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/ioport.h>
 +#include <linux/slab.h>
 +
 +#include <asm/msr.h>
 +#include <asm/tsc.h>
 +#include <asm/timex.h>
 +#include <asm/io.h>
 +#include <asm/delay.h>
 +
 +#define EPS_BRAND_C7M	0
 +#define EPS_BRAND_C7	1
 +#define EPS_BRAND_EDEN	2
 +#define EPS_BRAND_C3	3
 +
 +struct eps_cpu_data {
 +	u32 fsb;
 +	struct cpufreq_frequency_table freq_table[];
 +};
 +
 +static struct eps_cpu_data *eps_cpu[NR_CPUS];
 +
 +
 +static unsigned int eps_get(unsigned int cpu)
 +{
 +	struct eps_cpu_data *centaur;
 +	u32 lo, hi;
 +
 +	if (cpu)
 +		return 0;
 +	centaur = eps_cpu[cpu];
 +	if (centaur == NULL)
 +		return 0;
 +
 +	/* Return current frequency */
 +	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +	return centaur->fsb * ((lo >> 8) & 0xff);
 +}
 +
 +static int eps_set_state(struct eps_cpu_data *centaur,
 +			 unsigned int cpu,
 +			 u32 dest_state)
 +{
 +	struct cpufreq_freqs freqs;
 +	u32 lo, hi;
 +	int err = 0;
 +	int i;
 +
 +	freqs.old = eps_get(cpu);
 +	freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff);
 +	freqs.cpu = cpu;
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +
 +	/* Wait while CPU is busy */
 +	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +	i = 0;
 +	while (lo & ((1 << 16) | (1 << 17))) {
 +		udelay(16);
 +		rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +		i++;
 +		if (unlikely(i > 64)) {
 +			err = -ENODEV;
 +			goto postchange;
 +		}
 +	}
 +	/* Set new multiplier and voltage */
 +	wrmsr(MSR_IA32_PERF_CTL, dest_state & 0xffff, 0);
 +	/* Wait until transition end */
 +	i = 0;
 +	do {
 +		udelay(16);
 +		rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +		i++;
 +		if (unlikely(i > 64)) {
 +			err = -ENODEV;
 +			goto postchange;
 +		}
 +	} while (lo & ((1 << 16) | (1 << 17)));
 +
 +	/* Return current frequency */
 +postchange:
 +	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +	freqs.new = centaur->fsb * ((lo >> 8) & 0xff);
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +	return err;
 +}
 +
 +static int eps_target(struct cpufreq_policy *policy,
 +			       unsigned int target_freq,
 +			       unsigned int relation)
 +{
 +	struct eps_cpu_data *centaur;
 +	unsigned int newstate = 0;
 +	unsigned int cpu = policy->cpu;
 +	unsigned int dest_state;
 +	int ret;
 +
 +	if (unlikely(eps_cpu[cpu] == NULL))
 +		return -ENODEV;
 +	centaur = eps_cpu[cpu];
 +
 +	if (unlikely(cpufreq_frequency_table_target(policy,
 +			&eps_cpu[cpu]->freq_table[0],
 +			target_freq,
 +			relation,
 +			&newstate))) {
 +		return -EINVAL;
 +	}
 +
 +	/* Make frequency transition */
 +	dest_state = centaur->freq_table[newstate].index & 0xffff;
 +	ret = eps_set_state(centaur, cpu, dest_state);
 +	if (ret)
 +		printk(KERN_ERR "eps: Timeout!\n");
 +	return ret;
 +}
 +
 +static int eps_verify(struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy,
 +			&eps_cpu[policy->cpu]->freq_table[0]);
 +}
 +
 +static int eps_cpu_init(struct cpufreq_policy *policy)
 +{
 +	unsigned int i;
 +	u32 lo, hi;
 +	u64 val;
 +	u8 current_multiplier, current_voltage;
 +	u8 max_multiplier, max_voltage;
 +	u8 min_multiplier, min_voltage;
 +	u8 brand;
 +	u32 fsb;
 +	struct eps_cpu_data *centaur;
 +	struct cpufreq_frequency_table *f_table;
 +	int k, step, voltage;
 +	int ret;
 +	int states;
 +
 +	if (policy->cpu != 0)
 +		return -ENODEV;
 +
 +	/* Check brand */
 +	printk("eps: Detected VIA ");
 +	rdmsr(0x1153, lo, hi);
 +	brand = (((lo >> 2) ^ lo) >> 18) & 3;
 +	switch(brand) {
 +	case EPS_BRAND_C7M:
 +		printk("C7-M\n");
 +		break;
 +	case EPS_BRAND_C7:
 +		printk("C7\n");
 +		break;
 +	case EPS_BRAND_EDEN:
 +		printk("Eden\n");
 +		break;
 +	case EPS_BRAND_C3:
 +		printk("C3\n");
 +		return -ENODEV;
 +		break;
 +	}
 +	/* Enable Enhanced PowerSaver */
 +	rdmsrl(MSR_IA32_MISC_ENABLE, val);
 +	if (!(val & 1 << 16)) {
 +		val |= 1 << 16;
 +		wrmsrl(MSR_IA32_MISC_ENABLE, val);
 +		/* Can be locked at 0 */
 +		rdmsrl(MSR_IA32_MISC_ENABLE, val);
 +		if (!(val & 1 << 16)) {
 +			printk("eps: Can't enable Enhanced PowerSaver\n");
 +			return -ENODEV;
 +		}
 +	}
 +
 +	/* Print voltage and multiplier */
 +	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +	current_voltage = lo & 0xff;
 +	printk("eps: Current voltage = %dmV\n", current_voltage * 16 + 700);
 +	current_multiplier = (lo >> 8) & 0xff;
 +	printk("eps: Current multiplier = %d\n", current_multiplier);
 +
 +	/* Print limits */
 +	max_voltage = hi & 0xff;
 +	printk("eps: Highest voltage = %dmV\n", max_voltage * 16 + 700);
 +	max_multiplier = (hi >> 8) & 0xff;
 +	printk("eps: Highest multiplier = %d\n", max_multiplier);
 +	min_voltage = (hi >> 16) & 0xff;
 +	printk("eps: Lowest voltage = %dmV\n", min_voltage * 16 + 700);
 +	min_multiplier = (hi >> 24) & 0xff;
 +	printk("eps: Lowest multiplier = %d\n", min_multiplier);
 +
 +	/* Sanity checks */
 +	if (current_multiplier == 0 || max_multiplier == 0
 +	    || min_multiplier == 0)
 +		return -EINVAL;
 +	if (current_multiplier > max_multiplier
 +	    || max_multiplier <= min_multiplier)
 +		return -EINVAL;
 +	if (current_voltage > 0x1c || max_voltage > 0x1c)
 +		return -EINVAL;
 +	if (max_voltage < min_voltage)
 +		return -EINVAL;
 +
 +	/* Calc FSB speed */
 +	fsb = cpu_khz / current_multiplier;
 +	/* Calc number of p-states supported */
 +	if (brand == EPS_BRAND_C7M)
 +		states = max_multiplier - min_multiplier + 1;
 +	else
 +		states = 2;
 +
 +	/* Allocate private data and frequency table for current cpu */
 +	centaur = kzalloc(sizeof(struct eps_cpu_data)
 +		    + (states + 1) * sizeof(struct cpufreq_frequency_table),
 +		    GFP_KERNEL);
 +	if (!centaur)
 +		return -ENOMEM;
 +	eps_cpu[0] = centaur;
 +
 +	/* Copy basic values */
 +	centaur->fsb = fsb;
 +
 +	/* Fill frequency and MSR value table */
 +	f_table = &centaur->freq_table[0];
 +	if (brand != EPS_BRAND_C7M) {
 +		f_table[0].frequency = fsb * min_multiplier;
 +		f_table[0].index = (min_multiplier << 8) | min_voltage;
 +		f_table[1].frequency = fsb * max_multiplier;
 +		f_table[1].index = (max_multiplier << 8) | max_voltage;
 +		f_table[2].frequency = CPUFREQ_TABLE_END;
 +	} else {
 +		k = 0;
 +		step = ((max_voltage - min_voltage) * 256)
 +			/ (max_multiplier - min_multiplier);
 +		for (i = min_multiplier; i <= max_multiplier; i++) {
 +			voltage = (k * step) / 256 + min_voltage;
 +			f_table[k].frequency = fsb * i;
 +			f_table[k].index = (i << 8) | voltage;
 +			k++;
 +		}
 +		f_table[k].frequency = CPUFREQ_TABLE_END;
 +	}
 +
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */
 +	policy->cur = fsb * current_multiplier;
 +
 +	ret = cpufreq_frequency_table_cpuinfo(policy, &centaur->freq_table[0]);
 +	if (ret) {
 +		kfree(centaur);
 +		return ret;
 +	}
 +
 +	cpufreq_frequency_table_get_attr(&centaur->freq_table[0], policy->cpu);
 +	return 0;
 +}
 +
 +static int eps_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	unsigned int cpu = policy->cpu;
 +	struct eps_cpu_data *centaur;
 +	u32 lo, hi;
 +
 +	if (eps_cpu[cpu] == NULL)
 +		return -ENODEV;
 +	centaur = eps_cpu[cpu];
 +
 +	/* Get max frequency */
 +	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +	/* Set max frequency */
 +	eps_set_state(centaur, cpu, hi & 0xffff);
 +	/* Bye */
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +	kfree(eps_cpu[cpu]);
 +	eps_cpu[cpu] = NULL;
 +	return 0;
 +}
 +
 +static struct freq_attr* eps_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver eps_driver = {
 +	.verify		= eps_verify,
 +	.target		= eps_target,
 +	.init		= eps_cpu_init,
 +	.exit		= eps_cpu_exit,
 +	.get		= eps_get,
 +	.name		= "e_powersaver",
 +	.owner		= THIS_MODULE,
 +	.attr		= eps_attr,
 +};
 +
 +static int __init eps_init(void)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +
 +	/* This driver will work only on Centaur C7 processors with
 +	 * Enhanced SpeedStep/PowerSaver registers */
 +	if (c->x86_vendor != X86_VENDOR_CENTAUR
 +	    || c->x86 != 6 || c->x86_model != 10)
 +		return -ENODEV;
 +	if (!cpu_has(c, X86_FEATURE_EST))
 +		return -ENODEV;
 +
 +	if (cpufreq_register_driver(&eps_driver))
 +		return -EINVAL;
 +	return 0;
 +}
 +
 +static void __exit eps_exit(void)
 +{
 +	cpufreq_unregister_driver(&eps_driver);
 +}
 +
 +MODULE_AUTHOR("Rafa³ Bilski <rafalbilski@interia.pl>");
 +MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
 +MODULE_LICENSE("GPL");
 +
 +module_init(eps_init);
 +module_exit(eps_exit);
diff --cc arch/x86/kernel/cpu/cpufreq/elanfreq.c
index f317276afa7a,000000000000..1e7ae7dafcf6
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/elanfreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
@@@ -1,309 -1,0 +1,308 @@@
 +/*
 + *	elanfreq:	cpufreq driver for the AMD ELAN family
 + *
 + *	(c) Copyright 2002 Robert Schwebel <r.schwebel@pengutronix.de>
 + *
 + *	Parts of this code are (c) Sven Geggus <sven@geggus.net>
 + *
 + *      All Rights Reserved.
 + *
 + *	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 the Free Software Foundation; either version
 + *	2 of the License, or (at your option) any later version.
 + *
 + *	2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel
 + *
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +
 +#include <linux/slab.h>
 +#include <linux/delay.h>
 +#include <linux/cpufreq.h>
 +
 +#include <asm/msr.h>
 +#include <asm/timex.h>
 +#include <asm/io.h>
 +
 +#define REG_CSCIR 0x22		/* Chip Setup and Control Index Register    */
 +#define REG_CSCDR 0x23		/* Chip Setup and Control Data  Register    */
 +
 +/* Module parameter */
 +static int max_freq;
 +
 +struct s_elan_multiplier {
 +	int clock;		/* frequency in kHz                         */
 +	int val40h;		/* PMU Force Mode register                  */
 +	int val80h;		/* CPU Clock Speed Register                 */
 +};
 +
 +/*
 + * It is important that the frequencies
 + * are listed in ascending order here!
 + */
 +struct s_elan_multiplier elan_multiplier[] = {
 +	{1000,	0x02,	0x18},
 +	{2000,	0x02,	0x10},
 +	{4000,	0x02,	0x08},
 +	{8000,	0x00,	0x00},
 +	{16000,	0x00,	0x02},
 +	{33000,	0x00,	0x04},
 +	{66000,	0x01,	0x04},
 +	{99000,	0x01,	0x05}
 +};
 +
 +static struct cpufreq_frequency_table elanfreq_table[] = {
 +	{0,	1000},
 +	{1,	2000},
 +	{2,	4000},
 +	{3,	8000},
 +	{4,	16000},
 +	{5,	33000},
 +	{6,	66000},
 +	{7,	99000},
 +	{0,	CPUFREQ_TABLE_END},
 +};
 +
 +
 +/**
 + *	elanfreq_get_cpu_frequency: determine current cpu speed
 + *
 + *	Finds out at which frequency the CPU of the Elan SOC runs
 + *	at the moment. Frequencies from 1 to 33 MHz are generated
 + *	the normal way, 66 and 99 MHz are called "Hyperspeed Mode"
 + *	and have the rest of the chip running with 33 MHz.
 + */
 +
 +static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
 +{
 +	u8 clockspeed_reg;    /* Clock Speed Register */
 +
 +	local_irq_disable();
 +	outb_p(0x80,REG_CSCIR);
 +	clockspeed_reg = inb_p(REG_CSCDR);
 +	local_irq_enable();
 +
 +	if ((clockspeed_reg & 0xE0) == 0xE0)
 +		return 0;
 +
 +	/* Are we in CPU clock multiplied mode (66/99 MHz)? */
 +	if ((clockspeed_reg & 0xE0) == 0xC0) {
 +		if ((clockspeed_reg & 0x01) == 0)
 +			return 66000;
 +		else
 +			return 99000;
 +	}
 +
 +	/* 33 MHz is not 32 MHz... */
 +	if ((clockspeed_reg & 0xE0)==0xA0)
 +		return 33000;
 +
 +	return ((1<<((clockspeed_reg & 0xE0) >> 5)) * 1000);
 +}
 +
 +
 +/**
 + *	elanfreq_set_cpu_frequency: Change the CPU core frequency
 + *	@cpu: cpu number
 + *	@freq: frequency in kHz
 + *
 + *	This function takes a frequency value and changes the CPU frequency
 + *	according to this. Note that the frequency has to be checked by
 + *	elanfreq_validatespeed() for correctness!
 + *
 + *	There is no return value.
 + */
 +
 +static void elanfreq_set_cpu_state (unsigned int state)
 +{
 +	struct cpufreq_freqs    freqs;
 +
 +	freqs.old = elanfreq_get_cpu_frequency(0);
 +	freqs.new = elan_multiplier[state].clock;
 +	freqs.cpu = 0; /* elanfreq.c is UP only driver */
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +
 +	printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",
 +			elan_multiplier[state].clock);
 +
 +
 +	/*
 +	 * Access to the Elan's internal registers is indexed via
 +	 * 0x22: Chip Setup & Control Register Index Register (CSCI)
 +	 * 0x23: Chip Setup & Control Register Data  Register (CSCD)
 +	 *
 +	 */
 +
 +	/*
 +	 * 0x40 is the Power Management Unit's Force Mode Register.
 +	 * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency)
 +	 */
 +
 +	local_irq_disable();
 +	outb_p(0x40,REG_CSCIR);		/* Disable hyperspeed mode */
 +	outb_p(0x00,REG_CSCDR);
 +	local_irq_enable();		/* wait till internal pipelines and */
 +	udelay(1000);			/* buffers have cleaned up          */
 +
 +	local_irq_disable();
 +
 +	/* now, set the CPU clock speed register (0x80) */
 +	outb_p(0x80,REG_CSCIR);
 +	outb_p(elan_multiplier[state].val80h,REG_CSCDR);
 +
 +	/* now, the hyperspeed bit in PMU Force Mode Register (0x40) */
 +	outb_p(0x40,REG_CSCIR);
 +	outb_p(elan_multiplier[state].val40h,REG_CSCDR);
 +	udelay(10000);
 +	local_irq_enable();
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +};
 +
 +
 +/**
 + *	elanfreq_validatespeed: test if frequency range is valid
 + *	@policy: the policy to validate
 + *
 + *	This function checks if a given frequency range in kHz is valid
 + *	for the hardware supported by the driver.
 + */
 +
 +static int elanfreq_verify (struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]);
 +}
 +
 +static int elanfreq_target (struct cpufreq_policy *policy,
 +			    unsigned int target_freq,
 +			    unsigned int relation)
 +{
 +	unsigned int newstate = 0;
 +
 +	if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], target_freq, relation, &newstate))
 +		return -EINVAL;
 +
 +	elanfreq_set_cpu_state(newstate);
 +
 +	return 0;
 +}
 +
 +
 +/*
 + *	Module init and exit code
 + */
 +
 +static int elanfreq_cpu_init(struct cpufreq_policy *policy)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +	unsigned int i;
 +	int result;
 +
 +	/* capability check */
 +	if ((c->x86_vendor != X86_VENDOR_AMD) ||
 +	    (c->x86 != 4) || (c->x86_model!=10))
 +		return -ENODEV;
 +
 +	/* max freq */
 +	if (!max_freq)
 +		max_freq = elanfreq_get_cpu_frequency(0);
 +
 +	/* table init */
 +	for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
 +		if (elanfreq_table[i].frequency > max_freq)
 +			elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +	}
 +
 +	/* cpuinfo and default policy values */
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 +	policy->cur = elanfreq_get_cpu_frequency(0);
 +
 +	result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table);
 +	if (result)
 +		return (result);
 +
 +	cpufreq_frequency_table_get_attr(elanfreq_table, policy->cpu);
 +	return 0;
 +}
 +
 +
 +static int elanfreq_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +	return 0;
 +}
 +
 +
 +#ifndef MODULE
 +/**
 + * elanfreq_setup - elanfreq command line parameter parsing
 + *
 + * elanfreq command line parameter.  Use:
 + *  elanfreq=66000
 + * to set the maximum CPU frequency to 66 MHz. Note that in
 + * case you do not give this boot parameter, the maximum
 + * frequency will fall back to _current_ CPU frequency which
 + * might be lower. If you build this as a module, use the
 + * max_freq module parameter instead.
 + */
 +static int __init elanfreq_setup(char *str)
 +{
 +	max_freq = simple_strtoul(str, &str, 0);
 +	printk(KERN_WARNING "You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n");
 +	return 1;
 +}
 +__setup("elanfreq=", elanfreq_setup);
 +#endif
 +
 +
 +static struct freq_attr* elanfreq_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +
 +static struct cpufreq_driver elanfreq_driver = {
 +	.get		= elanfreq_get_cpu_frequency,
 +	.verify		= elanfreq_verify,
 +	.target		= elanfreq_target,
 +	.init		= elanfreq_cpu_init,
 +	.exit		= elanfreq_cpu_exit,
 +	.name		= "elanfreq",
 +	.owner		= THIS_MODULE,
 +	.attr		= elanfreq_attr,
 +};
 +
 +
 +static int __init elanfreq_init(void)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +
 +	/* Test if we have the right hardware */
 +	if ((c->x86_vendor != X86_VENDOR_AMD) ||
 +		(c->x86 != 4) || (c->x86_model!=10)) {
 +		printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
 +                return -ENODEV;
 +	}
 +	return cpufreq_register_driver(&elanfreq_driver);
 +}
 +
 +
 +static void __exit elanfreq_exit(void)
 +{
 +	cpufreq_unregister_driver(&elanfreq_driver);
 +}
 +
 +
 +module_param (max_freq, int, 0444);
 +
 +MODULE_LICENSE("GPL");
 +MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
 +MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
 +
 +module_init(elanfreq_init);
 +module_exit(elanfreq_exit);
diff --cc arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
index 461dabc4e495,000000000000..ed2bda127c44
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
@@@ -1,495 -1,0 +1,494 @@@
 +/*
 + *	Cyrix MediaGX and NatSemi Geode Suspend Modulation
 + *	(C) 2002 Zwane Mwaikambo <zwane@commfireservices.com>
 + *	(C) 2002 Hiroshi Miura   <miura@da-cha.org>
 + *	All Rights Reserved
 + *
 + *	This program is free software; you can redistribute it and/or
 + *      modify it under the terms of the GNU General Public License
 + *      version 2 as published by the Free Software Foundation
 + *
 + *      The author(s) of this software shall not be held liable for damages
 + *      of any nature resulting due to the use of this software. This
 + *      software is provided AS-IS with no warranties.
 + *
 + * Theoritical note:
 + *
 + *	(see Geode(tm) CS5530 manual (rev.4.1) page.56)
 + *
 + *	CPU frequency control on NatSemi Geode GX1/GXLV processor and CS55x0
 + *	are based on Suspend Moduration.
 + *
 + *	Suspend Modulation works by asserting and de-asserting the SUSP# pin
 + *	to CPU(GX1/GXLV) for configurable durations. When asserting SUSP#
 + *	the CPU enters an idle state. GX1 stops its core clock when SUSP# is
 + *	asserted then power consumption is reduced.
 + *
 + *	Suspend Modulation's OFF/ON duration are configurable
 + *	with 'Suspend Modulation OFF Count Register'
 + *	and 'Suspend Modulation ON Count Register'.
 + *	These registers are 8bit counters that represent the number of
 + *	32us intervals which the SUSP# pin is asserted(ON)/de-asserted(OFF)
 + *	to the processor.
 + *
 + *	These counters define a ratio which is the effective frequency
 + *	of operation of the system.
 + *
 + *			       OFF Count
 + *	F_eff = Fgx * ----------------------
 + *	                OFF Count + ON Count
 + *
 + *	0 <= On Count, Off Count <= 255
 + *
 + *	From these limits, we can get register values
 + *
 + *	off_duration + on_duration <= MAX_DURATION
 + *	on_duration = off_duration * (stock_freq - freq) / freq
 + *
 + *      off_duration  =  (freq * DURATION) / stock_freq
 + *      on_duration = DURATION - off_duration
 + *
 + *
 + *---------------------------------------------------------------------------
 + *
 + * ChangeLog:
 + *	Dec. 12, 2003	Hiroshi Miura <miura@da-cha.org>
 + *		- fix on/off register mistake
 + *		- fix cpu_khz calc when it stops cpu modulation.
 + *
 + *	Dec. 11, 2002	Hiroshi Miura <miura@da-cha.org>
 + *		- rewrite for Cyrix MediaGX Cx5510/5520 and
 + *		  NatSemi Geode Cs5530(A).
 + *
 + *	Jul. ??, 2002  Zwane Mwaikambo <zwane@commfireservices.com>
 + *		- cs5530_mod patch for 2.4.19-rc1.
 + *
 + *---------------------------------------------------------------------------
 + *
 + * Todo
 + *	Test on machines with 5510, 5530, 5530A
 + */
 +
 +/************************************************************************
 + *			Suspend Modulation - Definitions		*
 + ************************************************************************/
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/smp.h>
 +#include <linux/cpufreq.h>
 +#include <linux/pci.h>
 +#include <asm/processor-cyrix.h>
 +#include <asm/errno.h>
 +
 +/* PCI config registers, all at F0 */
 +#define PCI_PMER1	0x80	/* power management enable register 1 */
 +#define PCI_PMER2	0x81	/* power management enable register 2 */
 +#define PCI_PMER3	0x82	/* power management enable register 3 */
 +#define PCI_IRQTC	0x8c	/* irq speedup timer counter register:typical 2 to 4ms */
 +#define PCI_VIDTC	0x8d	/* video speedup timer counter register: typical 50 to 100ms */
 +#define PCI_MODOFF	0x94	/* suspend modulation OFF counter register, 1 = 32us */
 +#define PCI_MODON	0x95	/* suspend modulation ON counter register */
 +#define PCI_SUSCFG	0x96	/* suspend configuration register */
 +
 +/* PMER1 bits */
 +#define GPM		(1<<0)	/* global power management */
 +#define GIT		(1<<1)	/* globally enable PM device idle timers */
 +#define GTR		(1<<2)	/* globally enable IO traps */
 +#define IRQ_SPDUP	(1<<3)	/* disable clock throttle during interrupt handling */
 +#define VID_SPDUP	(1<<4)	/* disable clock throttle during vga video handling */
 +
 +/* SUSCFG bits */
 +#define SUSMOD		(1<<0)	/* enable/disable suspend modulation */
 +/* the belows support only with cs5530 (after rev.1.2)/cs5530A */
 +#define SMISPDUP	(1<<1)	/* select how SMI re-enable suspend modulation: */
 +				/* IRQTC timer or read SMI speedup disable reg.(F1BAR[08-09h]) */
 +#define SUSCFG		(1<<2)	/* enable powering down a GXLV processor. "Special 3Volt Suspend" mode */
 +/* the belows support only with cs5530A */
 +#define PWRSVE_ISA	(1<<3)	/* stop ISA clock  */
 +#define PWRSVE		(1<<4)	/* active idle */
 +
 +struct gxfreq_params {
 +	u8 on_duration;
 +	u8 off_duration;
 +	u8 pci_suscfg;
 +	u8 pci_pmer1;
 +	u8 pci_pmer2;
 +	struct pci_dev *cs55x0;
 +};
 +
 +static struct gxfreq_params *gx_params;
 +static int stock_freq;
 +
 +/* PCI bus clock - defaults to 30.000 if cpu_khz is not available */
 +static int pci_busclk = 0;
 +module_param (pci_busclk, int, 0444);
 +
 +/* maximum duration for which the cpu may be suspended
 + * (32us * MAX_DURATION). If no parameter is given, this defaults
 + * to 255.
 + * Note that this leads to a maximum of 8 ms(!) where the CPU clock
 + * is suspended -- processing power is just 0.39% of what it used to be,
 + * though. 781.25 kHz(!) for a 200 MHz processor -- wow. */
 +static int max_duration = 255;
 +module_param (max_duration, int, 0444);
 +
 +/* For the default policy, we want at least some processing power
 + * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV)
 + */
 +#define POLICY_MIN_DIV 20
 +
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "gx-suspmod", msg)
 +
 +/**
 + * we can detect a core multipiler from dir0_lsb
 + * from GX1 datasheet p.56,
 + *	MULT[3:0]:
 + *	0000 = SYSCLK multiplied by 4 (test only)
 + *	0001 = SYSCLK multiplied by 10
 + *	0010 = SYSCLK multiplied by 4
 + *	0011 = SYSCLK multiplied by 6
 + *	0100 = SYSCLK multiplied by 9
 + *	0101 = SYSCLK multiplied by 5
 + *	0110 = SYSCLK multiplied by 7
 + *	0111 = SYSCLK multiplied by 8
 + *              of 33.3MHz
 + **/
 +static int gx_freq_mult[16] = {
 +		4, 10, 4, 6, 9, 5, 7, 8,
 +		0, 0, 0, 0, 0, 0, 0, 0
 +};
 +
 +
 +/****************************************************************
 + *	Low Level chipset interface				*
 + ****************************************************************/
 +static struct pci_device_id gx_chipset_tbl[] __initdata = {
 +	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, PCI_ANY_ID, PCI_ANY_ID },
 +	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID },
 +	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID },
 +	{ 0, },
 +};
 +
 +/**
 + * gx_detect_chipset:
 + *
 + **/
 +static __init struct pci_dev *gx_detect_chipset(void)
 +{
 +	struct pci_dev *gx_pci = NULL;
 +
 +	/* check if CPU is a MediaGX or a Geode. */
 +	if ((current_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
 +	    (current_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
 +		dprintk("error: no MediaGX/Geode processor found!\n");
 +		return NULL;
 +	}
 +
 +	/* detect which companion chip is used */
 +	while ((gx_pci = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) {
 +		if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
 +			return gx_pci;
 +	}
 +
 +	dprintk("error: no supported chipset found!\n");
 +	return NULL;
 +}
 +
 +/**
 + * gx_get_cpuspeed:
 + *
 + * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi Geode CPU runs.
 + */
 +static unsigned int gx_get_cpuspeed(unsigned int cpu)
 +{
 +	if ((gx_params->pci_suscfg & SUSMOD) == 0)
 +		return stock_freq;
 +
 +	return (stock_freq * gx_params->off_duration)
 +		/ (gx_params->on_duration + gx_params->off_duration);
 +}
 +
 +/**
 + *      gx_validate_speed:
 + *      determine current cpu speed
 + *
 + **/
 +
 +static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration, u8 *off_duration)
 +{
 +	unsigned int i;
 +	u8 tmp_on, tmp_off;
 +	int old_tmp_freq = stock_freq;
 +	int tmp_freq;
 +
 +	*off_duration=1;
 +	*on_duration=0;
 +
 +	for (i=max_duration; i>0; i--) {
 +		tmp_off = ((khz * i) / stock_freq) & 0xff;
 +		tmp_on = i - tmp_off;
 +		tmp_freq = (stock_freq * tmp_off) / i;
 +		/* if this relation is closer to khz, use this. If it's equal,
 +		 * prefer it, too - lower latency */
 +		if (abs(tmp_freq - khz) <= abs(old_tmp_freq - khz)) {
 +			*on_duration = tmp_on;
 +			*off_duration = tmp_off;
 +			old_tmp_freq = tmp_freq;
 +		}
 +	}
 +
 +	return old_tmp_freq;
 +}
 +
 +
 +/**
 + * gx_set_cpuspeed:
 + * set cpu speed in khz.
 + **/
 +
 +static void gx_set_cpuspeed(unsigned int khz)
 +{
 +	u8 suscfg, pmer1;
 +	unsigned int new_khz;
 +	unsigned long flags;
 +	struct cpufreq_freqs freqs;
 +
 +	freqs.cpu = 0;
 +	freqs.old = gx_get_cpuspeed(0);
 +
 +	new_khz = gx_validate_speed(khz, &gx_params->on_duration, &gx_params->off_duration);
 +
 +	freqs.new = new_khz;
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +	local_irq_save(flags);
 +
 +	if (new_khz != stock_freq) {  /* if new khz == 100% of CPU speed, it is special case */
 +		switch (gx_params->cs55x0->device) {
 +		case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
 +			pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP;
 +			/* FIXME: need to test other values -- Zwane,Miura */
 +			pci_write_config_byte(gx_params->cs55x0, PCI_IRQTC, 4); /* typical 2 to 4ms */
 +			pci_write_config_byte(gx_params->cs55x0, PCI_VIDTC, 100);/* typical 50 to 100ms */
 +			pci_write_config_byte(gx_params->cs55x0, PCI_PMER1, pmer1);
 +
 +			if (gx_params->cs55x0->revision < 0x10) {   /* CS5530(rev 1.2, 1.3) */
 +				suscfg = gx_params->pci_suscfg | SUSMOD;
 +			} else {                           /* CS5530A,B.. */
 +				suscfg = gx_params->pci_suscfg | SUSMOD | PWRSVE;
 +			}
 +			break;
 +		case PCI_DEVICE_ID_CYRIX_5520:
 +		case PCI_DEVICE_ID_CYRIX_5510:
 +			suscfg = gx_params->pci_suscfg | SUSMOD;
 +			break;
 +		default:
 +			local_irq_restore(flags);
 +			dprintk("fatal: try to set unknown chipset.\n");
 +			return;
 +		}
 +	} else {
 +		suscfg = gx_params->pci_suscfg & ~(SUSMOD);
 +		gx_params->off_duration = 0;
 +		gx_params->on_duration = 0;
 +		dprintk("suspend modulation disabled: cpu runs 100 percent speed.\n");
 +	}
 +
 +	pci_write_config_byte(gx_params->cs55x0, PCI_MODOFF, gx_params->off_duration);
 +	pci_write_config_byte(gx_params->cs55x0, PCI_MODON, gx_params->on_duration);
 +
 +	pci_write_config_byte(gx_params->cs55x0, PCI_SUSCFG, suscfg);
 +	pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg);
 +
 +	local_irq_restore(flags);
 +
 +	gx_params->pci_suscfg = suscfg;
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +
 +	dprintk("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
 +		gx_params->on_duration * 32, gx_params->off_duration * 32);
 +	dprintk("suspend modulation w/ clock speed: %d kHz.\n", freqs.new);
 +}
 +
 +/****************************************************************
 + *             High level functions                             *
 + ****************************************************************/
 +
 +/*
 + *	cpufreq_gx_verify: test if frequency range is valid
 + *
 + *	This function checks if a given frequency range in kHz is valid
 + *      for the hardware supported by the driver.
 + */
 +
 +static int cpufreq_gx_verify(struct cpufreq_policy *policy)
 +{
 +	unsigned int tmp_freq = 0;
 +	u8 tmp1, tmp2;
 +
 +	if (!stock_freq || !policy)
 +		return -EINVAL;
 +
 +	policy->cpu = 0;
 +	cpufreq_verify_within_limits(policy, (stock_freq / max_duration), stock_freq);
 +
 +	/* it needs to be assured that at least one supported frequency is
 +	 * within policy->min and policy->max. If it is not, policy->max
 +	 * needs to be increased until one freuqency is supported.
 +	 * policy->min may not be decreased, though. This way we guarantee a
 +	 * specific processing capacity.
 +	 */
 +	tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2);
 +	if (tmp_freq < policy->min)
 +		tmp_freq += stock_freq / max_duration;
 +	policy->min = tmp_freq;
 +	if (policy->min > policy->max)
 +		policy->max = tmp_freq;
 +	tmp_freq = gx_validate_speed(policy->max, &tmp1, &tmp2);
 +	if (tmp_freq > policy->max)
 +		tmp_freq -= stock_freq / max_duration;
 +	policy->max = tmp_freq;
 +	if (policy->max < policy->min)
 +		policy->max = policy->min;
 +	cpufreq_verify_within_limits(policy, (stock_freq / max_duration), stock_freq);
 +
 +	return 0;
 +}
 +
 +/*
 + *      cpufreq_gx_target:
 + *
 + */
 +static int cpufreq_gx_target(struct cpufreq_policy *policy,
 +			     unsigned int target_freq,
 +			     unsigned int relation)
 +{
 +	u8 tmp1, tmp2;
 +	unsigned int tmp_freq;
 +
 +	if (!stock_freq || !policy)
 +		return -EINVAL;
 +
 +	policy->cpu = 0;
 +
 +	tmp_freq = gx_validate_speed(target_freq, &tmp1, &tmp2);
 +	while (tmp_freq < policy->min) {
 +		tmp_freq += stock_freq / max_duration;
 +		tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
 +	}
 +	while (tmp_freq > policy->max) {
 +		tmp_freq -= stock_freq / max_duration;
 +		tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
 +	}
 +
 +	gx_set_cpuspeed(tmp_freq);
 +
 +	return 0;
 +}
 +
 +static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
 +{
 +	unsigned int maxfreq, curfreq;
 +
 +	if (!policy || policy->cpu != 0)
 +		return -ENODEV;
 +
 +	/* determine maximum frequency */
 +	if (pci_busclk) {
 +		maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
 +	} else if (cpu_khz) {
 +		maxfreq = cpu_khz;
 +	} else {
 +		maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
 +	}
 +	stock_freq = maxfreq;
 +	curfreq = gx_get_cpuspeed(0);
 +
 +	dprintk("cpu max frequency is %d.\n", maxfreq);
 +	dprintk("cpu current frequency is %dkHz.\n",curfreq);
 +
 +	/* setup basic struct for cpufreq API */
 +	policy->cpu = 0;
 +
 +	if (max_duration < POLICY_MIN_DIV)
 +		policy->min = maxfreq / max_duration;
 +	else
 +		policy->min = maxfreq / POLICY_MIN_DIV;
 +	policy->max = maxfreq;
 +	policy->cur = curfreq;
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.min_freq = maxfreq / max_duration;
 +	policy->cpuinfo.max_freq = maxfreq;
 +	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 +
 +	return 0;
 +}
 +
 +/*
 + * cpufreq_gx_init:
 + *   MediaGX/Geode GX initialize cpufreq driver
 + */
 +static struct cpufreq_driver gx_suspmod_driver = {
 +	.get		= gx_get_cpuspeed,
 +	.verify		= cpufreq_gx_verify,
 +	.target		= cpufreq_gx_target,
 +	.init		= cpufreq_gx_cpu_init,
 +	.name		= "gx-suspmod",
 +	.owner		= THIS_MODULE,
 +};
 +
 +static int __init cpufreq_gx_init(void)
 +{
 +	int ret;
 +	struct gxfreq_params *params;
 +	struct pci_dev *gx_pci;
 +
 +	/* Test if we have the right hardware */
 +	if ((gx_pci = gx_detect_chipset()) == NULL)
 +		return -ENODEV;
 +
 +	/* check whether module parameters are sane */
 +	if (max_duration > 0xff)
 +		max_duration = 0xff;
 +
 +	dprintk("geode suspend modulation available.\n");
 +
 +	params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL);
 +	if (params == NULL)
 +		return -ENOMEM;
 +
 +	params->cs55x0 = gx_pci;
 +	gx_params = params;
 +
 +	/* keep cs55x0 configurations */
 +	pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg));
 +	pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1));
 +	pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2));
 +	pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration));
 +	pci_read_config_byte(params->cs55x0, PCI_MODOFF, &(params->off_duration));
 +
 +	if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) {
 +		kfree(params);
 +		return ret;                   /* register error! */
 +	}
 +
 +	return 0;
 +}
 +
 +static void __exit cpufreq_gx_exit(void)
 +{
 +	cpufreq_unregister_driver(&gx_suspmod_driver);
 +	pci_dev_put(gx_params->cs55x0);
 +	kfree(gx_params);
 +}
 +
 +MODULE_AUTHOR ("Hiroshi Miura <miura@da-cha.org>");
 +MODULE_DESCRIPTION ("Cpufreq driver for Cyrix MediaGX and NatSemi Geode");
 +MODULE_LICENSE ("GPL");
 +
 +module_init(cpufreq_gx_init);
 +module_exit(cpufreq_gx_exit);
 +
diff --cc arch/x86/kernel/cpu/cpufreq/longhaul.c
index f0cce3c2dc3a,000000000000..5045f5d583c8
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/x86/kernel/cpu/cpufreq/longhaul.c
@@@ -1,1024 -1,0 +1,1027 @@@
 +/*
 + *  (C) 2001-2004  Dave Jones. <davej@codemonkey.org.uk>
 + *  (C) 2002  Padraig Brady. <padraig@antefacto.com>
 + *
 + *  Licensed under the terms of the GNU GPL License version 2.
 + *  Based upon datasheets & sample CPUs kindly provided by VIA.
 + *
 + *  VIA have currently 3 different versions of Longhaul.
 + *  Version 1 (Longhaul) uses the BCR2 MSR at 0x1147.
 + *   It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0.
 + *  Version 2 of longhaul is backward compatible with v1, but adds
 + *   LONGHAUL MSR for purpose of both frequency and voltage scaling.
 + *   Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C).
 + *  Version 3 of longhaul got renamed to Powersaver and redesigned
 + *   to use only the POWERSAVER MSR at 0x110a.
 + *   It is present in Ezra-T (C5M), Nehemiah (C5X) and above.
 + *   It's pretty much the same feature wise to longhaul v2, though
 + *   there is provision for scaling FSB too, but this doesn't work
 + *   too well in practice so we don't even try to use this.
 + *
 + *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/moduleparam.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/pci.h>
 +#include <linux/slab.h>
 +#include <linux/string.h>
 +#include <linux/delay.h>
 +
 +#include <asm/msr.h>
 +#include <asm/timex.h>
 +#include <asm/io.h>
 +#include <asm/acpi.h>
 +#include <linux/acpi.h>
 +#include <acpi/processor.h>
 +
 +#include "longhaul.h"
 +
 +#define PFX "longhaul: "
 +
 +#define TYPE_LONGHAUL_V1	1
 +#define TYPE_LONGHAUL_V2	2
 +#define TYPE_POWERSAVER		3
 +
 +#define	CPU_SAMUEL	1
 +#define	CPU_SAMUEL2	2
 +#define	CPU_EZRA	3
 +#define	CPU_EZRA_T	4
 +#define	CPU_NEHEMIAH	5
 +#define	CPU_NEHEMIAH_C	6
 +
 +/* Flags */
 +#define USE_ACPI_C3		(1 << 1)
 +#define USE_NORTHBRIDGE		(1 << 2)
 +
 +static int cpu_model;
 +static unsigned int numscales=16;
 +static unsigned int fsb;
 +
 +static const struct mV_pos *vrm_mV_table;
 +static const unsigned char *mV_vrm_table;
 +
 +static unsigned int highest_speed, lowest_speed; /* kHz */
 +static unsigned int minmult, maxmult;
 +static int can_scale_voltage;
 +static struct acpi_processor *pr = NULL;
 +static struct acpi_processor_cx *cx = NULL;
 +static u32 acpi_regs_addr;
 +static u8 longhaul_flags;
 +static unsigned int longhaul_index;
 +
 +/* Module parameters */
 +static int scale_voltage;
 +static int disable_acpi_c3;
 +static int revid_errata;
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)
 +
 +
 +/* Clock ratios multiplied by 10 */
 +static int clock_ratio[32];
 +static int eblcr_table[32];
 +static int longhaul_version;
 +static struct cpufreq_frequency_table *longhaul_table;
 +
 +#ifdef CONFIG_CPU_FREQ_DEBUG
 +static char speedbuffer[8];
 +
 +static char *print_speed(int speed)
 +{
 +	if (speed < 1000) {
 +		snprintf(speedbuffer, sizeof(speedbuffer),"%dMHz", speed);
 +		return speedbuffer;
 +	}
 +
 +	if (speed%1000 == 0)
 +		snprintf(speedbuffer, sizeof(speedbuffer),
 +			"%dGHz", speed/1000);
 +	else
 +		snprintf(speedbuffer, sizeof(speedbuffer),
 +			"%d.%dGHz", speed/1000, (speed%1000)/100);
 +
 +	return speedbuffer;
 +}
 +#endif
 +
 +
 +static unsigned int calc_speed(int mult)
 +{
 +	int khz;
 +	khz = (mult/10)*fsb;
 +	if (mult%10)
 +		khz += fsb/2;
 +	khz *= 1000;
 +	return khz;
 +}
 +
 +
 +static int longhaul_get_cpu_mult(void)
 +{
 +	unsigned long invalue=0,lo, hi;
 +
 +	rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
 +	invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22;
 +	if (longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) {
 +		if (lo & (1<<27))
 +			invalue+=16;
 +	}
 +	return eblcr_table[invalue];
 +}
 +
 +/* For processor with BCR2 MSR */
 +
 +static void do_longhaul1(unsigned int clock_ratio_index)
 +{
 +	union msr_bcr2 bcr2;
 +
 +	rdmsrl(MSR_VIA_BCR2, bcr2.val);
 +	/* Enable software clock multiplier */
 +	bcr2.bits.ESOFTBF = 1;
 +	bcr2.bits.CLOCKMUL = clock_ratio_index & 0xff;
 +
 +	/* Sync to timer tick */
 +	safe_halt();
 +	/* Change frequency on next halt or sleep */
 +	wrmsrl(MSR_VIA_BCR2, bcr2.val);
 +	/* Invoke transition */
 +	ACPI_FLUSH_CPU_CACHE();
 +	halt();
 +
 +	/* Disable software clock multiplier */
 +	local_irq_disable();
 +	rdmsrl(MSR_VIA_BCR2, bcr2.val);
 +	bcr2.bits.ESOFTBF = 0;
 +	wrmsrl(MSR_VIA_BCR2, bcr2.val);
 +}
 +
 +/* For processor with Longhaul MSR */
 +
 +static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
 +			  unsigned int dir)
 +{
 +	union msr_longhaul longhaul;
 +	u32 t;
 +
 +	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 +	/* Setup new frequency */
 +	if (!revid_errata)
 +		longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
 +	else
 +		longhaul.bits.RevisionKey = 0;
 +	longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
 +	longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
 +	/* Setup new voltage */
 +	if (can_scale_voltage)
 +		longhaul.bits.SoftVID = (clock_ratio_index >> 8) & 0x1f;
 +	/* Sync to timer tick */
 +	safe_halt();
 +	/* Raise voltage if necessary */
 +	if (can_scale_voltage && dir) {
 +		longhaul.bits.EnableSoftVID = 1;
 +		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 +		/* Change voltage */
 +		if (!cx_address) {
 +			ACPI_FLUSH_CPU_CACHE();
 +			halt();
 +		} else {
 +			ACPI_FLUSH_CPU_CACHE();
 +			/* Invoke C3 */
 +			inb(cx_address);
 +			/* Dummy op - must do something useless after P_LVL3
 +			 * read */
 +			t = inl(acpi_gbl_FADT.xpm_timer_block.address);
 +		}
 +		longhaul.bits.EnableSoftVID = 0;
 +		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 +	}
 +
 +	/* Change frequency on next halt or sleep */
 +	longhaul.bits.EnableSoftBusRatio = 1;
 +	wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 +	if (!cx_address) {
 +		ACPI_FLUSH_CPU_CACHE();
 +		halt();
 +	} else {
 +		ACPI_FLUSH_CPU_CACHE();
 +		/* Invoke C3 */
 +		inb(cx_address);
 +		/* Dummy op - must do something useless after P_LVL3 read */
 +		t = inl(acpi_gbl_FADT.xpm_timer_block.address);
 +	}
 +	/* Disable bus ratio bit */
 +	longhaul.bits.EnableSoftBusRatio = 0;
 +	wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 +
 +	/* Reduce voltage if necessary */
 +	if (can_scale_voltage && !dir) {
 +		longhaul.bits.EnableSoftVID = 1;
 +		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 +		/* Change voltage */
 +		if (!cx_address) {
 +			ACPI_FLUSH_CPU_CACHE();
 +			halt();
 +		} else {
 +			ACPI_FLUSH_CPU_CACHE();
 +			/* Invoke C3 */
 +			inb(cx_address);
 +			/* Dummy op - must do something useless after P_LVL3
 +			 * read */
 +			t = inl(acpi_gbl_FADT.xpm_timer_block.address);
 +		}
 +		longhaul.bits.EnableSoftVID = 0;
 +		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 +	}
 +}
 +
 +/**
 + * longhaul_set_cpu_frequency()
 + * @clock_ratio_index : bitpattern of the new multiplier.
 + *
 + * Sets a new clock ratio.
 + */
 +
 +static void longhaul_setstate(unsigned int table_index)
 +{
 +	unsigned int clock_ratio_index;
 +	int speed, mult;
 +	struct cpufreq_freqs freqs;
 +	unsigned long flags;
 +	unsigned int pic1_mask, pic2_mask;
 +	u16 bm_status = 0;
 +	u32 bm_timeout = 1000;
 +	unsigned int dir = 0;
 +
 +	clock_ratio_index = longhaul_table[table_index].index;
 +	/* Safety precautions */
 +	mult = clock_ratio[clock_ratio_index & 0x1f];
 +	if (mult == -1)
 +		return;
 +	speed = calc_speed(mult);
 +	if ((speed > highest_speed) || (speed < lowest_speed))
 +		return;
 +	/* Voltage transition before frequency transition? */
 +	if (can_scale_voltage && longhaul_index < table_index)
 +		dir = 1;
 +
 +	freqs.old = calc_speed(longhaul_get_cpu_mult());
 +	freqs.new = speed;
 +	freqs.cpu = 0; /* longhaul.c is UP only driver */
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +
 +	dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
 +			fsb, mult/10, mult%10, print_speed(speed/1000));
 +retry_loop:
 +	preempt_disable();
 +	local_irq_save(flags);
 +
 +	pic2_mask = inb(0xA1);
 +	pic1_mask = inb(0x21);	/* works on C3. save mask. */
 +	outb(0xFF,0xA1);	/* Overkill */
 +	outb(0xFE,0x21);	/* TMR0 only */
 +
 +	/* Wait while PCI bus is busy. */
 +	if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE
 +	    || ((pr != NULL) && pr->flags.bm_control))) {
 +		bm_status = inw(acpi_regs_addr);
 +		bm_status &= 1 << 4;
 +		while (bm_status && bm_timeout) {
 +			outw(1 << 4, acpi_regs_addr);
 +			bm_timeout--;
 +			bm_status = inw(acpi_regs_addr);
 +			bm_status &= 1 << 4;
 +		}
 +	}
 +
 +	if (longhaul_flags & USE_NORTHBRIDGE) {
 +		/* Disable AGP and PCI arbiters */
 +		outb(3, 0x22);
 +	} else if ((pr != NULL) && pr->flags.bm_control) {
 +		/* Disable bus master arbitration */
 +		acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
 +	}
 +	switch (longhaul_version) {
 +
 +	/*
 +	 * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B])
 +	 * Software controlled multipliers only.
 +	 */
 +	case TYPE_LONGHAUL_V1:
 +		do_longhaul1(clock_ratio_index);
 +		break;
 +
 +	/*
 +	 * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C]
 +	 *
 +	 * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N])
 +	 * Nehemiah can do FSB scaling too, but this has never been proven
 +	 * to work in practice.
 +	 */
 +	case TYPE_LONGHAUL_V2:
 +	case TYPE_POWERSAVER:
 +		if (longhaul_flags & USE_ACPI_C3) {
 +			/* Don't allow wakeup */
 +			acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
 +			do_powersaver(cx->address, clock_ratio_index, dir);
 +		} else {
 +			do_powersaver(0, clock_ratio_index, dir);
 +		}
 +		break;
 +	}
 +
 +	if (longhaul_flags & USE_NORTHBRIDGE) {
 +		/* Enable arbiters */
 +		outb(0, 0x22);
 +	} else if ((pr != NULL) && pr->flags.bm_control) {
 +		/* Enable bus master arbitration */
 +		acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
 +	}
 +	outb(pic2_mask,0xA1);	/* restore mask */
 +	outb(pic1_mask,0x21);
 +
 +	local_irq_restore(flags);
 +	preempt_enable();
 +
 +	freqs.new = calc_speed(longhaul_get_cpu_mult());
 +	/* Check if requested frequency is set. */
 +	if (unlikely(freqs.new != speed)) {
 +		printk(KERN_INFO PFX "Failed to set requested frequency!\n");
 +		/* Revision ID = 1 but processor is expecting revision key
 +		 * equal to 0. Jumpers at the bottom of processor will change
 +		 * multiplier and FSB, but will not change bits in Longhaul
 +		 * MSR nor enable voltage scaling. */
 +		if (!revid_errata) {
 +			printk(KERN_INFO PFX "Enabling \"Ignore Revision ID\" "
 +						"option.\n");
 +			revid_errata = 1;
 +			msleep(200);
 +			goto retry_loop;
 +		}
 +		/* Why ACPI C3 sometimes doesn't work is a mystery for me.
 +		 * But it does happen. Processor is entering ACPI C3 state,
 +		 * but it doesn't change frequency. I tried poking various
 +		 * bits in northbridge registers, but without success. */
 +		if (longhaul_flags & USE_ACPI_C3) {
 +			printk(KERN_INFO PFX "Disabling ACPI C3 support.\n");
 +			longhaul_flags &= ~USE_ACPI_C3;
 +			if (revid_errata) {
 +				printk(KERN_INFO PFX "Disabling \"Ignore "
 +						"Revision ID\" option.\n");
 +				revid_errata = 0;
 +			}
 +			msleep(200);
 +			goto retry_loop;
 +		}
 +		/* This shouldn't happen. Longhaul ver. 2 was reported not
 +		 * working on processors without voltage scaling, but with
 +		 * RevID = 1. RevID errata will make things right. Just
 +		 * to be 100% sure. */
 +		if (longhaul_version == TYPE_LONGHAUL_V2) {
 +			printk(KERN_INFO PFX "Switching to Longhaul ver. 1\n");
 +			longhaul_version = TYPE_LONGHAUL_V1;
 +			msleep(200);
 +			goto retry_loop;
 +		}
 +	}
 +	/* Report true CPU frequency */
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +
 +	if (!bm_timeout)
 +		printk(KERN_INFO PFX "Warning: Timeout while waiting for idle PCI bus.\n");
 +}
 +
 +/*
 + * Centaur decided to make life a little more tricky.
 + * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].
 + * Samuel2 and above have to try and guess what the FSB is.
 + * We do this by assuming we booted at maximum multiplier, and interpolate
 + * between that value multiplied by possible FSBs and cpu_mhz which
 + * was calculated at boot time. Really ugly, but no other way to do this.
 + */
 +
 +#define ROUNDING	0xf
 +
 +static int guess_fsb(int mult)
 +{
 +	int speed = cpu_khz / 1000;
 +	int i;
 +	int speeds[] = { 666, 1000, 1333, 2000 };
 +	int f_max, f_min;
 +
 +	for (i = 0; i < 4; i++) {
 +		f_max = ((speeds[i] * mult) + 50) / 100;
 +		f_max += (ROUNDING / 2);
 +		f_min = f_max - ROUNDING;
 +		if ((speed <= f_max) && (speed >= f_min))
 +			return speeds[i] / 10;
 +	}
 +	return 0;
 +}
 +
 +
 +static int __init longhaul_get_ranges(void)
 +{
 +	unsigned int i, j, k = 0;
 +	unsigned int ratio;
 +	int mult;
 +
 +	/* Get current frequency */
 +	mult = longhaul_get_cpu_mult();
 +	if (mult == -1) {
 +		printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n");
 +		return -EINVAL;
 +	}
 +	fsb = guess_fsb(mult);
 +	if (fsb == 0) {
 +		printk(KERN_INFO PFX "Invalid (reserved) FSB!\n");
 +		return -EINVAL;
 +	}
 +	/* Get max multiplier - as we always did.
 +	 * Longhaul MSR is usefull only when voltage scaling is enabled.
 +	 * C3 is booting at max anyway. */
 +	maxmult = mult;
 +	/* Get min multiplier */
 +	switch (cpu_model) {
 +	case CPU_NEHEMIAH:
 +		minmult = 50;
 +		break;
 +	case CPU_NEHEMIAH_C:
 +		minmult = 40;
 +		break;
 +	default:
 +		minmult = 30;
 +		break;
 +	}
 +
 +	dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
 +		 minmult/10, minmult%10, maxmult/10, maxmult%10);
 +
 +	highest_speed = calc_speed(maxmult);
 +	lowest_speed = calc_speed(minmult);
 +	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
 +		 print_speed(lowest_speed/1000),
 +		 print_speed(highest_speed/1000));
 +
 +	if (lowest_speed == highest_speed) {
 +		printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n");
 +		return -EINVAL;
 +	}
 +	if (lowest_speed > highest_speed) {
 +		printk (KERN_INFO PFX "nonsense! lowest (%d > %d) !\n",
 +			lowest_speed, highest_speed);
 +		return -EINVAL;
 +	}
 +
 +	longhaul_table = kmalloc((numscales + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL);
 +	if(!longhaul_table)
 +		return -ENOMEM;
 +
 +	for (j = 0; j < numscales; j++) {
 +		ratio = clock_ratio[j];
 +		if (ratio == -1)
 +			continue;
 +		if (ratio > maxmult || ratio < minmult)
 +			continue;
 +		longhaul_table[k].frequency = calc_speed(ratio);
 +		longhaul_table[k].index	= j;
 +		k++;
 +	}
 +	if (k <= 1) {
 +		kfree(longhaul_table);
 +		return -ENODEV;
 +	}
 +	/* Sort */
 +	for (j = 0; j < k - 1; j++) {
 +		unsigned int min_f, min_i;
 +		min_f = longhaul_table[j].frequency;
 +		min_i = j;
 +		for (i = j + 1; i < k; i++) {
 +			if (longhaul_table[i].frequency < min_f) {
 +				min_f = longhaul_table[i].frequency;
 +				min_i = i;
 +			}
 +		}
 +		if (min_i != j) {
 +			unsigned int temp;
 +			temp = longhaul_table[j].frequency;
 +			longhaul_table[j].frequency = longhaul_table[min_i].frequency;
 +			longhaul_table[min_i].frequency = temp;
 +			temp = longhaul_table[j].index;
 +			longhaul_table[j].index = longhaul_table[min_i].index;
 +			longhaul_table[min_i].index = temp;
 +		}
 +	}
 +
 +	longhaul_table[k].frequency = CPUFREQ_TABLE_END;
 +
 +	/* Find index we are running on */
 +	for (j = 0; j < k; j++) {
 +		if (clock_ratio[longhaul_table[j].index & 0x1f] == mult) {
 +			longhaul_index = j;
 +			break;
 +		}
 +	}
 +	return 0;
 +}
 +
 +
 +static void __init longhaul_setup_voltagescaling(void)
 +{
 +	union msr_longhaul longhaul;
 +	struct mV_pos minvid, maxvid, vid;
 +	unsigned int j, speed, pos, kHz_step, numvscales;
 +	int min_vid_speed;
 +
 +	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 +	if (!(longhaul.bits.RevisionID & 1)) {
 +		printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n");
 +		return;
 +	}
 +
 +	if (!longhaul.bits.VRMRev) {
 +		printk(KERN_INFO PFX "VRM 8.5\n");
 +		vrm_mV_table = &vrm85_mV[0];
 +		mV_vrm_table = &mV_vrm85[0];
 +	} else {
 +		printk(KERN_INFO PFX "Mobile VRM\n");
 +		if (cpu_model < CPU_NEHEMIAH)
 +			return;
 +		vrm_mV_table = &mobilevrm_mV[0];
 +		mV_vrm_table = &mV_mobilevrm[0];
 +	}
 +
 +	minvid = vrm_mV_table[longhaul.bits.MinimumVID];
 +	maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
 +
 +	if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
 +		printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
 +					"Voltage scaling disabled.\n",
 +					minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000);
 +		return;
 +	}
 +
 +	if (minvid.mV == maxvid.mV) {
 +		printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "
 +				"both %d.%03d. Voltage scaling disabled\n",
 +				maxvid.mV/1000, maxvid.mV%1000);
 +		return;
 +	}
 +
 +	/* How many voltage steps */
 +	numvscales = maxvid.pos - minvid.pos + 1;
 +	printk(KERN_INFO PFX
 +		"Max VID=%d.%03d  "
 +		"Min VID=%d.%03d, "
 +		"%d possible voltage scales\n",
 +		maxvid.mV/1000, maxvid.mV%1000,
 +		minvid.mV/1000, minvid.mV%1000,
 +		numvscales);
 +
 +	/* Calculate max frequency at min voltage */
 +	j = longhaul.bits.MinMHzBR;
 +	if (longhaul.bits.MinMHzBR4)
 +		j += 16;
 +	min_vid_speed = eblcr_table[j];
 +	if (min_vid_speed == -1)
 +		return;
 +	switch (longhaul.bits.MinMHzFSB) {
 +	case 0:
 +		min_vid_speed *= 13333;
 +		break;
 +	case 1:
 +		min_vid_speed *= 10000;
 +		break;
 +	case 3:
 +		min_vid_speed *= 6666;
 +		break;
 +	default:
 +		return;
 +		break;
 +	}
 +	if (min_vid_speed >= highest_speed)
 +		return;
 +	/* Calculate kHz for one voltage step */
 +	kHz_step = (highest_speed - min_vid_speed) / numvscales;
 +
 +	j = 0;
 +	while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
 +		speed = longhaul_table[j].frequency;
 +		if (speed > min_vid_speed)
 +			pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
 +		else
 +			pos = minvid.pos;
 +		longhaul_table[j].index |= mV_vrm_table[pos] << 8;
 +		vid = vrm_mV_table[mV_vrm_table[pos]];
 +		printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", speed, j, vid.mV);
 +		j++;
 +	}
 +
 +	can_scale_voltage = 1;
 +	printk(KERN_INFO PFX "Voltage scaling enabled.\n");
 +}
 +
 +
 +static int longhaul_verify(struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, longhaul_table);
 +}
 +
 +
 +static int longhaul_target(struct cpufreq_policy *policy,
 +			    unsigned int target_freq, unsigned int relation)
 +{
 +	unsigned int table_index = 0;
 +	unsigned int i;
 +	unsigned int dir = 0;
 +	u8 vid, current_vid;
 +
 +	if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))
 +		return -EINVAL;
 +
 +	/* Don't set same frequency again */
 +	if (longhaul_index == table_index)
 +		return 0;
 +
 +	if (!can_scale_voltage)
 +		longhaul_setstate(table_index);
 +	else {
 +		/* On test system voltage transitions exceeding single
 +		 * step up or down were turning motherboard off. Both
 +		 * "ondemand" and "userspace" are unsafe. C7 is doing
 +		 * this in hardware, C3 is old and we need to do this
 +		 * in software. */
 +		i = longhaul_index;
 +		current_vid = (longhaul_table[longhaul_index].index >> 8) & 0x1f;
 +		if (table_index > longhaul_index)
 +			dir = 1;
 +		while (i != table_index) {
 +			vid = (longhaul_table[i].index >> 8) & 0x1f;
 +			if (vid != current_vid) {
 +				longhaul_setstate(i);
 +				current_vid = vid;
 +				msleep(200);
 +			}
 +			if (dir)
 +				i++;
 +			else
 +				i--;
 +		}
 +		longhaul_setstate(table_index);
 +	}
 +	longhaul_index = table_index;
 +	return 0;
 +}
 +
 +
 +static unsigned int longhaul_get(unsigned int cpu)
 +{
 +	if (cpu)
 +		return 0;
 +	return calc_speed(longhaul_get_cpu_mult());
 +}
 +
 +static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
 +					  u32 nesting_level,
 +					  void *context, void **return_value)
 +{
 +	struct acpi_device *d;
 +
 +	if ( acpi_bus_get_device(obj_handle, &d) ) {
 +		return 0;
 +	}
 +	*return_value = (void *)acpi_driver_data(d);
 +	return 1;
 +}
 +
 +/* VIA don't support PM2 reg, but have something similar */
 +static int enable_arbiter_disable(void)
 +{
 +	struct pci_dev *dev;
 +	int status = 1;
 +	int reg;
 +	u8 pci_cmd;
 +
 +	/* Find PLE133 host bridge */
 +	reg = 0x78;
 +	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
 +			     NULL);
++	/* Find PM133/VT8605 host bridge */
++	if (dev == NULL)
++		dev = pci_get_device(PCI_VENDOR_ID_VIA,
++				     PCI_DEVICE_ID_VIA_8605_0, NULL);
 +	/* Find CLE266 host bridge */
 +	if (dev == NULL) {
 +		reg = 0x76;
 +		dev = pci_get_device(PCI_VENDOR_ID_VIA,
 +				     PCI_DEVICE_ID_VIA_862X_0, NULL);
 +		/* Find CN400 V-Link host bridge */
 +		if (dev == NULL)
 +			dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
 +	}
 +	if (dev != NULL) {
 +		/* Enable access to port 0x22 */
 +		pci_read_config_byte(dev, reg, &pci_cmd);
 +		if (!(pci_cmd & 1<<7)) {
 +			pci_cmd |= 1<<7;
 +			pci_write_config_byte(dev, reg, pci_cmd);
 +			pci_read_config_byte(dev, reg, &pci_cmd);
 +			if (!(pci_cmd & 1<<7)) {
 +				printk(KERN_ERR PFX
 +					"Can't enable access to port 0x22.\n");
 +				status = 0;
 +			}
 +		}
 +		pci_dev_put(dev);
 +		return status;
 +	}
 +	return 0;
 +}
 +
 +static int longhaul_setup_southbridge(void)
 +{
 +	struct pci_dev *dev;
 +	u8 pci_cmd;
 +
 +	/* Find VT8235 southbridge */
 +	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
 +	if (dev == NULL)
 +	/* Find VT8237 southbridge */
 +		dev = pci_get_device(PCI_VENDOR_ID_VIA,
 +				     PCI_DEVICE_ID_VIA_8237, NULL);
 +	if (dev != NULL) {
 +		/* Set transition time to max */
 +		pci_read_config_byte(dev, 0xec, &pci_cmd);
 +		pci_cmd &= ~(1 << 2);
 +		pci_write_config_byte(dev, 0xec, pci_cmd);
 +		pci_read_config_byte(dev, 0xe4, &pci_cmd);
 +		pci_cmd &= ~(1 << 7);
 +		pci_write_config_byte(dev, 0xe4, pci_cmd);
 +		pci_read_config_byte(dev, 0xe5, &pci_cmd);
 +		pci_cmd |= 1 << 7;
 +		pci_write_config_byte(dev, 0xe5, pci_cmd);
 +		/* Get address of ACPI registers block*/
 +		pci_read_config_byte(dev, 0x81, &pci_cmd);
 +		if (pci_cmd & 1 << 7) {
 +			pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
 +			acpi_regs_addr &= 0xff00;
 +			printk(KERN_INFO PFX "ACPI I/O at 0x%x\n", acpi_regs_addr);
 +		}
 +
 +		pci_dev_put(dev);
 +		return 1;
 +	}
 +	return 0;
 +}
 +
 +static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +	char *cpuname=NULL;
 +	int ret;
 +	u32 lo, hi;
 +
 +	/* Check what we have on this motherboard */
 +	switch (c->x86_model) {
 +	case 6:
 +		cpu_model = CPU_SAMUEL;
 +		cpuname = "C3 'Samuel' [C5A]";
 +		longhaul_version = TYPE_LONGHAUL_V1;
 +		memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));
 +		memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));
 +		break;
 +
 +	case 7:
 +		switch (c->x86_mask) {
 +		case 0:
 +			longhaul_version = TYPE_LONGHAUL_V1;
 +			cpu_model = CPU_SAMUEL2;
 +			cpuname = "C3 'Samuel 2' [C5B]";
 +			/* Note, this is not a typo, early Samuel2's had
 +			 * Samuel1 ratios. */
 +			memcpy(clock_ratio, samuel1_clock_ratio,
 +				sizeof(samuel1_clock_ratio));
 +			memcpy(eblcr_table, samuel2_eblcr,
 +				sizeof(samuel2_eblcr));
 +			break;
 +		case 1 ... 15:
 +			longhaul_version = TYPE_LONGHAUL_V1;
 +			if (c->x86_mask < 8) {
 +				cpu_model = CPU_SAMUEL2;
 +				cpuname = "C3 'Samuel 2' [C5B]";
 +			} else {
 +				cpu_model = CPU_EZRA;
 +				cpuname = "C3 'Ezra' [C5C]";
 +			}
 +			memcpy(clock_ratio, ezra_clock_ratio,
 +				sizeof(ezra_clock_ratio));
 +			memcpy(eblcr_table, ezra_eblcr,
 +				sizeof(ezra_eblcr));
 +			break;
 +		}
 +		break;
 +
 +	case 8:
 +		cpu_model = CPU_EZRA_T;
 +		cpuname = "C3 'Ezra-T' [C5M]";
 +		longhaul_version = TYPE_POWERSAVER;
 +		numscales=32;
 +		memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio));
 +		memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr));
 +		break;
 +
 +	case 9:
 +		longhaul_version = TYPE_POWERSAVER;
 +		numscales = 32;
 +		memcpy(clock_ratio,
 +		       nehemiah_clock_ratio,
 +		       sizeof(nehemiah_clock_ratio));
 +		memcpy(eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));
 +		switch (c->x86_mask) {
 +		case 0 ... 1:
 +			cpu_model = CPU_NEHEMIAH;
 +			cpuname = "C3 'Nehemiah A' [C5XLOE]";
 +			break;
 +		case 2 ... 4:
 +			cpu_model = CPU_NEHEMIAH;
 +			cpuname = "C3 'Nehemiah B' [C5XLOH]";
 +			break;
 +		case 5 ... 15:
 +			cpu_model = CPU_NEHEMIAH_C;
 +			cpuname = "C3 'Nehemiah C' [C5P]";
 +			break;
 +		}
 +		break;
 +
 +	default:
 +		cpuname = "Unknown";
 +		break;
 +	}
 +	/* Check Longhaul ver. 2 */
 +	if (longhaul_version == TYPE_LONGHAUL_V2) {
 +		rdmsr(MSR_VIA_LONGHAUL, lo, hi);
 +		if (lo == 0 && hi == 0)
 +			/* Looks like MSR isn't present */
 +			longhaul_version = TYPE_LONGHAUL_V1;
 +	}
 +
 +	printk (KERN_INFO PFX "VIA %s CPU detected.  ", cpuname);
 +	switch (longhaul_version) {
 +	case TYPE_LONGHAUL_V1:
 +	case TYPE_LONGHAUL_V2:
 +		printk ("Longhaul v%d supported.\n", longhaul_version);
 +		break;
 +	case TYPE_POWERSAVER:
 +		printk ("Powersaver supported.\n");
 +		break;
 +	};
 +
 +	/* Doesn't hurt */
 +	longhaul_setup_southbridge();
 +
 +	/* Find ACPI data for processor */
 +	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
 +				ACPI_UINT32_MAX, &longhaul_walk_callback,
 +				NULL, (void *)&pr);
 +
 +	/* Check ACPI support for C3 state */
 +	if (pr != NULL && longhaul_version == TYPE_POWERSAVER) {
 +		cx = &pr->power.states[ACPI_STATE_C3];
 +		if (cx->address > 0 && cx->latency <= 1000)
 +			longhaul_flags |= USE_ACPI_C3;
 +	}
 +	/* Disable if it isn't working */
 +	if (disable_acpi_c3)
 +		longhaul_flags &= ~USE_ACPI_C3;
 +	/* Check if northbridge is friendly */
 +	if (enable_arbiter_disable())
 +		longhaul_flags |= USE_NORTHBRIDGE;
 +
 +	/* Check ACPI support for bus master arbiter disable */
 +	if (!(longhaul_flags & USE_ACPI_C3
 +	     || longhaul_flags & USE_NORTHBRIDGE)
 +	    && ((pr == NULL) || !(pr->flags.bm_control))) {
 +		printk(KERN_ERR PFX
 +			"No ACPI support. Unsupported northbridge.\n");
 +		return -ENODEV;
 +	}
 +
 +	if (longhaul_flags & USE_NORTHBRIDGE)
 +		printk(KERN_INFO PFX "Using northbridge support.\n");
 +	if (longhaul_flags & USE_ACPI_C3)
 +		printk(KERN_INFO PFX "Using ACPI support.\n");
 +
 +	ret = longhaul_get_ranges();
 +	if (ret != 0)
 +		return ret;
 +
 +	if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
 +		longhaul_setup_voltagescaling();
 +
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.transition_latency = 200000;	/* nsec */
 +	policy->cur = calc_speed(longhaul_get_cpu_mult());
 +
 +	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
 +	if (ret)
 +		return ret;
 +
 +	cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu);
 +
 +	return 0;
 +}
 +
 +static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +	return 0;
 +}
 +
 +static struct freq_attr* longhaul_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver longhaul_driver = {
 +	.verify	= longhaul_verify,
 +	.target	= longhaul_target,
 +	.get	= longhaul_get,
 +	.init	= longhaul_cpu_init,
 +	.exit	= __devexit_p(longhaul_cpu_exit),
 +	.name	= "longhaul",
 +	.owner	= THIS_MODULE,
 +	.attr	= longhaul_attr,
 +};
 +
 +
 +static int __init longhaul_init(void)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +
 +	if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)
 +		return -ENODEV;
 +
 +#ifdef CONFIG_SMP
 +	if (num_online_cpus() > 1) {
 +		printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n");
 +		return -ENODEV;
 +	}
 +#endif
 +#ifdef CONFIG_X86_IO_APIC
 +	if (cpu_has_apic) {
 +		printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n");
 +		return -ENODEV;
 +	}
 +#endif
 +	switch (c->x86_model) {
 +	case 6 ... 9:
 +		return cpufreq_register_driver(&longhaul_driver);
 +	case 10:
 +		printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n");
 +	default:
 +		;;
 +	}
 +
 +	return -ENODEV;
 +}
 +
 +
 +static void __exit longhaul_exit(void)
 +{
 +	int i;
 +
 +	for (i=0; i < numscales; i++) {
 +		if (clock_ratio[i] == maxmult) {
 +			longhaul_setstate(i);
 +			break;
 +		}
 +	}
 +
 +	cpufreq_unregister_driver(&longhaul_driver);
 +	kfree(longhaul_table);
 +}
 +
 +/* Even if BIOS is exporting ACPI C3 state, and it is used
 + * with success when CPU is idle, this state doesn't
 + * trigger frequency transition in some cases. */
 +module_param (disable_acpi_c3, int, 0644);
 +MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");
 +/* Change CPU voltage with frequency. Very usefull to save
 + * power, but most VIA C3 processors aren't supporting it. */
 +module_param (scale_voltage, int, 0644);
 +MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
 +/* Force revision key to 0 for processors which doesn't
 + * support voltage scaling, but are introducing itself as
 + * such. */
 +module_param(revid_errata, int, 0644);
 +MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");
 +
 +MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
 +MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
 +MODULE_LICENSE ("GPL");
 +
 +late_initcall(longhaul_init);
 +module_exit(longhaul_exit);
diff --cc arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
index 4c76b511e194,000000000000..8eb414b906d2
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
@@@ -1,316 -1,0 +1,315 @@@
 +/*
 + *	Pentium 4/Xeon CPU on demand clock modulation/speed scaling
 + *	(C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
 + *	(C) 2002 Zwane Mwaikambo <zwane@commfireservices.com>
 + *	(C) 2002 Arjan van de Ven <arjanv@redhat.com>
 + *	(C) 2002 Tora T. Engstad
 + *	All Rights Reserved
 + *
 + *	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 the Free Software Foundation; either version
 + *      2 of the License, or (at your option) any later version.
 + *
 + *      The author(s) of this software shall not be held liable for damages
 + *      of any nature resulting due to the use of this software. This
 + *      software is provided AS-IS with no warranties.
 + *
 + *	Date		Errata			Description
 + *	20020525	N44, O17	12.5% or 25% DC causes lockup
 + *
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/smp.h>
 +#include <linux/cpufreq.h>
 +#include <linux/slab.h>
 +#include <linux/cpumask.h>
 +
 +#include <asm/processor.h>
 +#include <asm/msr.h>
 +#include <asm/timex.h>
 +
 +#include "speedstep-lib.h"
 +
 +#define PFX	"p4-clockmod: "
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "p4-clockmod", msg)
 +
 +/*
 + * Duty Cycle (3bits), note DC_DISABLE is not specified in
 + * intel docs i just use it to mean disable
 + */
 +enum {
 +	DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT,
 +	DC_64PT, DC_75PT, DC_88PT, DC_DISABLE
 +};
 +
 +#define DC_ENTRIES	8
 +
 +
 +static int has_N44_O17_errata[NR_CPUS];
 +static unsigned int stock_freq;
 +static struct cpufreq_driver p4clockmod_driver;
 +static unsigned int cpufreq_p4_get(unsigned int cpu);
 +
 +static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
 +{
 +	u32 l, h;
 +
 +	if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV))
 +		return -EINVAL;
 +
 +	rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
 +
 +	if (l & 0x01)
 +		dprintk("CPU#%d currently thermal throttled\n", cpu);
 +
 +	if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT))
 +		newstate = DC_38PT;
 +
 +	rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
 +	if (newstate == DC_DISABLE) {
 +		dprintk("CPU#%d disabling modulation\n", cpu);
 +		wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
 +	} else {
 +		dprintk("CPU#%d setting duty cycle to %d%%\n",
 +			cpu, ((125 * newstate) / 10));
 +		/* bits 63 - 5	: reserved
 +		 * bit  4	: enable/disable
 +		 * bits 3-1	: duty cycle
 +		 * bit  0	: reserved
 +		 */
 +		l = (l & ~14);
 +		l = l | (1<<4) | ((newstate & 0x7)<<1);
 +		wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h);
 +	}
 +
 +	return 0;
 +}
 +
 +
 +static struct cpufreq_frequency_table p4clockmod_table[] = {
 +	{DC_RESV, CPUFREQ_ENTRY_INVALID},
 +	{DC_DFLT, 0},
 +	{DC_25PT, 0},
 +	{DC_38PT, 0},
 +	{DC_50PT, 0},
 +	{DC_64PT, 0},
 +	{DC_75PT, 0},
 +	{DC_88PT, 0},
 +	{DC_DISABLE, 0},
 +	{DC_RESV, CPUFREQ_TABLE_END},
 +};
 +
 +
 +static int cpufreq_p4_target(struct cpufreq_policy *policy,
 +			     unsigned int target_freq,
 +			     unsigned int relation)
 +{
 +	unsigned int    newstate = DC_RESV;
 +	struct cpufreq_freqs freqs;
 +	int i;
 +
 +	if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate))
 +		return -EINVAL;
 +
 +	freqs.old = cpufreq_p4_get(policy->cpu);
 +	freqs.new = stock_freq * p4clockmod_table[newstate].index / 8;
 +
 +	if (freqs.new == freqs.old)
 +		return 0;
 +
 +	/* notifiers */
 +	for_each_cpu_mask(i, policy->cpus) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +	}
 +
 +	/* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software
 +	 * Developer's Manual, Volume 3
 +	 */
 +	for_each_cpu_mask(i, policy->cpus)
 +		cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
 +
 +	/* notifiers */
 +	for_each_cpu_mask(i, policy->cpus) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +	}
 +
 +	return 0;
 +}
 +
 +
 +static int cpufreq_p4_verify(struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, &p4clockmod_table[0]);
 +}
 +
 +
 +static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
 +{
 +	if (c->x86 == 0x06) {
 +		if (cpu_has(c, X86_FEATURE_EST))
 +			printk(KERN_WARNING PFX "Warning: EST-capable CPU detected. "
 +			       "The acpi-cpufreq module offers voltage scaling"
 +			       " in addition of frequency scaling. You should use "
 +			       "that instead of p4-clockmod, if possible.\n");
 +		switch (c->x86_model) {
 +		case 0x0E: /* Core */
 +		case 0x0F: /* Core Duo */
 +			p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
 +			return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PCORE);
 +		case 0x0D: /* Pentium M (Dothan) */
 +			p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
 +			/* fall through */
 +		case 0x09: /* Pentium M (Banias) */
 +			return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
 +		}
 +	}
 +
 +	if (c->x86 != 0xF) {
 +		printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <cpufreq@lists.linux.org.uk>\n");
 +		return 0;
 +	}
 +
 +	/* on P-4s, the TSC runs with constant frequency independent whether
 +	 * throttling is active or not. */
 +	p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
 +
 +	if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) {
 +		printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. "
 +		       "The speedstep-ich or acpi cpufreq modules offer "
 +		       "voltage scaling in addition of frequency scaling. "
 +		       "You should use either one instead of p4-clockmod, "
 +		       "if possible.\n");
 +		return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M);
 +	}
 +
 +	return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4D);
 +}
 +
 +
 +
 +static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
 +{
 +	struct cpuinfo_x86 *c = &cpu_data[policy->cpu];
 +	int cpuid = 0;
 +	unsigned int i;
 +
 +#ifdef CONFIG_SMP
 +	policy->cpus = cpu_sibling_map[policy->cpu];
 +#endif
 +
 +	/* Errata workaround */
 +	cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask;
 +	switch (cpuid) {
 +	case 0x0f07:
 +	case 0x0f0a:
 +	case 0x0f11:
 +	case 0x0f12:
 +		has_N44_O17_errata[policy->cpu] = 1;
 +		dprintk("has errata -- disabling low frequencies\n");
 +	}
 +
 +	/* get max frequency */
 +	stock_freq = cpufreq_p4_get_frequency(c);
 +	if (!stock_freq)
 +		return -EINVAL;
 +
 +	/* table init */
 +	for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
 +		if ((i<2) && (has_N44_O17_errata[policy->cpu]))
 +			p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +		else
 +			p4clockmod_table[i].frequency = (stock_freq * i)/8;
 +	}
 +	cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
 +
 +	/* cpuinfo and default policy values */
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.transition_latency = 1000000; /* assumed */
 +	policy->cur = stock_freq;
 +
 +	return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]);
 +}
 +
 +
 +static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +	return 0;
 +}
 +
 +static unsigned int cpufreq_p4_get(unsigned int cpu)
 +{
 +	u32 l, h;
 +
 +	rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
 +
 +	if (l & 0x10) {
 +		l = l >> 1;
 +		l &= 0x7;
 +	} else
 +		l = DC_DISABLE;
 +
 +	if (l != DC_DISABLE)
 +		return (stock_freq * l / 8);
 +
 +	return stock_freq;
 +}
 +
 +static struct freq_attr* p4clockmod_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver p4clockmod_driver = {
 +	.verify		= cpufreq_p4_verify,
 +	.target		= cpufreq_p4_target,
 +	.init		= cpufreq_p4_cpu_init,
 +	.exit		= cpufreq_p4_cpu_exit,
 +	.get		= cpufreq_p4_get,
 +	.name		= "p4-clockmod",
 +	.owner		= THIS_MODULE,
 +	.attr		= p4clockmod_attr,
 +};
 +
 +
 +static int __init cpufreq_p4_init(void)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +	int ret;
 +
 +	/*
 +	 * THERM_CONTROL is architectural for IA32 now, so
 +	 * we can rely on the capability checks
 +	 */
 +	if (c->x86_vendor != X86_VENDOR_INTEL)
 +		return -ENODEV;
 +
 +	if (!test_bit(X86_FEATURE_ACPI, c->x86_capability) ||
 +		!test_bit(X86_FEATURE_ACC, c->x86_capability))
 +		return -ENODEV;
 +
 +	ret = cpufreq_register_driver(&p4clockmod_driver);
 +	if (!ret)
 +		printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n");
 +
 +	return (ret);
 +}
 +
 +
 +static void __exit cpufreq_p4_exit(void)
 +{
 +	cpufreq_unregister_driver(&p4clockmod_driver);
 +}
 +
 +
 +MODULE_AUTHOR ("Zwane Mwaikambo <zwane@commfireservices.com>");
 +MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
 +MODULE_LICENSE ("GPL");
 +
 +late_initcall(cpufreq_p4_init);
 +module_exit(cpufreq_p4_exit);
diff --cc arch/x86/kernel/cpu/cpufreq/powernow-k6.c
index f89524051e4a,000000000000..6d0285339317
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
@@@ -1,256 -1,0 +1,255 @@@
 +/*
 + *  This file was based upon code in Powertweak Linux (http://powertweak.sf.net)
 + *  (C) 2000-2003  Dave Jones, Arjan van de Ven, Janne Pänkälä, Dominik Brodowski.
 + *
 + *  Licensed under the terms of the GNU GPL License version 2.
 + *
 + *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/ioport.h>
 +#include <linux/slab.h>
 +
 +#include <asm/msr.h>
 +#include <asm/timex.h>
 +#include <asm/io.h>
 +
 +
 +#define POWERNOW_IOPORT 0xfff0         /* it doesn't matter where, as long
 +					  as it is unused */
 +
 +static unsigned int                     busfreq;   /* FSB, in 10 kHz */
 +static unsigned int                     max_multiplier;
 +
 +
 +/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
 +static struct cpufreq_frequency_table clock_ratio[] = {
 +	{45,  /* 000 -> 4.5x */ 0},
 +	{50,  /* 001 -> 5.0x */ 0},
 +	{40,  /* 010 -> 4.0x */ 0},
 +	{55,  /* 011 -> 5.5x */ 0},
 +	{20,  /* 100 -> 2.0x */ 0},
 +	{30,  /* 101 -> 3.0x */ 0},
 +	{60,  /* 110 -> 6.0x */ 0},
 +	{35,  /* 111 -> 3.5x */ 0},
 +	{0, CPUFREQ_TABLE_END}
 +};
 +
 +
 +/**
 + * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
 + *
 + *   Returns the current setting of the frequency multiplier. Core clock
 + * speed is frequency of the Front-Side Bus multiplied with this value.
 + */
 +static int powernow_k6_get_cpu_multiplier(void)
 +{
 +	u64             invalue = 0;
 +	u32             msrval;
 +
 +	msrval = POWERNOW_IOPORT + 0x1;
 +	wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
 +	invalue=inl(POWERNOW_IOPORT + 0x8);
 +	msrval = POWERNOW_IOPORT + 0x0;
 +	wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
 +
 +	return clock_ratio[(invalue >> 5)&7].index;
 +}
 +
 +
 +/**
 + * powernow_k6_set_state - set the PowerNow! multiplier
 + * @best_i: clock_ratio[best_i] is the target multiplier
 + *
 + *   Tries to change the PowerNow! multiplier
 + */
 +static void powernow_k6_set_state (unsigned int best_i)
 +{
 +	unsigned long           outvalue=0, invalue=0;
 +	unsigned long           msrval;
 +	struct cpufreq_freqs    freqs;
 +
 +	if (clock_ratio[best_i].index > max_multiplier) {
 +		printk(KERN_ERR "cpufreq: invalid target frequency\n");
 +		return;
 +	}
 +
 +	freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
 +	freqs.new = busfreq * clock_ratio[best_i].index;
 +	freqs.cpu = 0; /* powernow-k6.c is UP only driver */
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +
 +	/* we now need to transform best_i to the BVC format, see AMD#23446 */
 +
 +	outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
 +
 +	msrval = POWERNOW_IOPORT + 0x1;
 +	wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
 +	invalue=inl(POWERNOW_IOPORT + 0x8);
 +	invalue = invalue & 0xf;
 +	outvalue = outvalue | invalue;
 +	outl(outvalue ,(POWERNOW_IOPORT + 0x8));
 +	msrval = POWERNOW_IOPORT + 0x0;
 +	wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +
 +	return;
 +}
 +
 +
 +/**
 + * powernow_k6_verify - verifies a new CPUfreq policy
 + * @policy: new policy
 + *
 + * Policy must be within lowest and highest possible CPU Frequency,
 + * and at least one possible state must be within min and max.
 + */
 +static int powernow_k6_verify(struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, &clock_ratio[0]);
 +}
 +
 +
 +/**
 + * powernow_k6_setpolicy - sets a new CPUFreq policy
 + * @policy: new policy
 + * @target_freq: the target frequency
 + * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
 + *
 + * sets a new CPUFreq policy
 + */
 +static int powernow_k6_target (struct cpufreq_policy *policy,
 +			       unsigned int target_freq,
 +			       unsigned int relation)
 +{
 +	unsigned int    newstate = 0;
 +
 +	if (cpufreq_frequency_table_target(policy, &clock_ratio[0], target_freq, relation, &newstate))
 +		return -EINVAL;
 +
 +	powernow_k6_set_state(newstate);
 +
 +	return 0;
 +}
 +
 +
 +static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
 +{
 +	unsigned int i;
 +	int result;
 +
 +	if (policy->cpu != 0)
 +		return -ENODEV;
 +
 +	/* get frequencies */
 +	max_multiplier = powernow_k6_get_cpu_multiplier();
 +	busfreq = cpu_khz / max_multiplier;
 +
 +	/* table init */
 +	for (i=0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
 +		if (clock_ratio[i].index > max_multiplier)
 +			clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
 +		else
 +			clock_ratio[i].frequency = busfreq * clock_ratio[i].index;
 +	}
 +
 +	/* cpuinfo and default policy values */
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 +	policy->cur = busfreq * max_multiplier;
 +
 +	result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio);
 +	if (result)
 +		return (result);
 +
 +	cpufreq_frequency_table_get_attr(clock_ratio, policy->cpu);
 +
 +	return 0;
 +}
 +
 +
 +static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	unsigned int i;
 +	for (i=0; i<8; i++) {
 +		if (i==max_multiplier)
 +			powernow_k6_set_state(i);
 +	}
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +	return 0;
 +}
 +
 +static unsigned int powernow_k6_get(unsigned int cpu)
 +{
 +	return busfreq * powernow_k6_get_cpu_multiplier();
 +}
 +
 +static struct freq_attr* powernow_k6_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver powernow_k6_driver = {
 +	.verify		= powernow_k6_verify,
 +	.target		= powernow_k6_target,
 +	.init		= powernow_k6_cpu_init,
 +	.exit		= powernow_k6_cpu_exit,
 +	.get		= powernow_k6_get,
 +	.name		= "powernow-k6",
 +	.owner		= THIS_MODULE,
 +	.attr		= powernow_k6_attr,
 +};
 +
 +
 +/**
 + * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
 + *
 + *   Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported
 + * devices, -EINVAL or -ENOMEM on problems during initiatization, and zero
 + * on success.
 + */
 +static int __init powernow_k6_init(void)
 +{
 +	struct cpuinfo_x86      *c = cpu_data;
 +
 +	if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
 +		((c->x86_model != 12) && (c->x86_model != 13)))
 +		return -ENODEV;
 +
 +	if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
 +		printk("cpufreq: PowerNow IOPORT region already used.\n");
 +		return -EIO;
 +	}
 +
 +	if (cpufreq_register_driver(&powernow_k6_driver)) {
 +		release_region (POWERNOW_IOPORT, 16);
 +		return -EINVAL;
 +	}
 +
 +	return 0;
 +}
 +
 +
 +/**
 + * powernow_k6_exit - unregisters AMD K6-2+/3+ PowerNow! support
 + *
 + *   Unregisters AMD K6-2+ / K6-3+ PowerNow! support.
 + */
 +static void __exit powernow_k6_exit(void)
 +{
 +	cpufreq_unregister_driver(&powernow_k6_driver);
 +	release_region (POWERNOW_IOPORT, 16);
 +}
 +
 +
 +MODULE_AUTHOR ("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@codemonkey.org.uk>, Dominik Brodowski <linux@brodo.de>");
 +MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
 +MODULE_LICENSE ("GPL");
 +
 +module_init(powernow_k6_init);
 +module_exit(powernow_k6_exit);
diff --cc arch/x86/kernel/cpu/cpufreq/powernow-k7.c
index ca3e1d341889,000000000000..7decd6a50ffa
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
@@@ -1,703 -1,0 +1,701 @@@
 +/*
 + *  AMD K7 Powernow driver.
 + *  (C) 2003 Dave Jones <davej@codemonkey.org.uk> on behalf of SuSE Labs.
 + *  (C) 2003-2004 Dave Jones <davej@redhat.com>
 + *
 + *  Licensed under the terms of the GNU GPL License version 2.
 + *  Based upon datasheets & sample CPUs kindly provided by AMD.
 + *
 + * Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt.
 + * - We cli/sti on stepping A0 CPUs around the FID/VID transition.
 + * Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect.
 + * - We disable half multipliers if ACPI is used on A0 stepping CPUs.
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/moduleparam.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/slab.h>
 +#include <linux/string.h>
 +#include <linux/dmi.h>
 +
 +#include <asm/msr.h>
 +#include <asm/timer.h>
 +#include <asm/timex.h>
 +#include <asm/io.h>
 +#include <asm/system.h>
 +
 +#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 +#include <linux/acpi.h>
 +#include <acpi/processor.h>
 +#endif
 +
 +#include "powernow-k7.h"
 +
 +#define PFX "powernow: "
 +
 +
 +struct psb_s {
 +	u8 signature[10];
 +	u8 tableversion;
 +	u8 flags;
 +	u16 settlingtime;
 +	u8 reserved1;
 +	u8 numpst;
 +};
 +
 +struct pst_s {
 +	u32 cpuid;
 +	u8 fsbspeed;
 +	u8 maxfid;
 +	u8 startvid;
 +	u8 numpstates;
 +};
 +
 +#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 +union powernow_acpi_control_t {
 +	struct {
 +		unsigned long fid:5,
 +		vid:5,
 +		sgtc:20,
 +		res1:2;
 +	} bits;
 +	unsigned long val;
 +};
 +#endif
 +
 +#ifdef CONFIG_CPU_FREQ_DEBUG
 +/* divide by 1000 to get VCore voltage in V. */
 +static const int mobile_vid_table[32] = {
 +    2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
 +    1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
 +    1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
 +    1075, 1050, 1025, 1000, 975, 950, 925, 0,
 +};
 +#endif
 +
 +/* divide by 10 to get FID. */
 +static const int fid_codes[32] = {
 +    110, 115, 120, 125, 50, 55, 60, 65,
 +    70, 75, 80, 85, 90, 95, 100, 105,
 +    30, 190, 40, 200, 130, 135, 140, 210,
 +    150, 225, 160, 165, 170, 180, -1, -1,
 +};
 +
 +/* This parameter is used in order to force ACPI instead of legacy method for
 + * configuration purpose.
 + */
 +
 +static int acpi_force;
 +
 +static struct cpufreq_frequency_table *powernow_table;
 +
 +static unsigned int can_scale_bus;
 +static unsigned int can_scale_vid;
 +static unsigned int minimum_speed=-1;
 +static unsigned int maximum_speed;
 +static unsigned int number_scales;
 +static unsigned int fsb;
 +static unsigned int latency;
 +static char have_a0;
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k7", msg)
 +
 +static int check_fsb(unsigned int fsbspeed)
 +{
 +	int delta;
 +	unsigned int f = fsb / 1000;
 +
 +	delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
 +	return (delta < 5);
 +}
 +
 +static int check_powernow(void)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +	unsigned int maxei, eax, ebx, ecx, edx;
 +
 +	if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 !=6)) {
 +#ifdef MODULE
 +		printk (KERN_INFO PFX "This module only works with AMD K7 CPUs\n");
 +#endif
 +		return 0;
 +	}
 +
 +	/* Get maximum capabilities */
 +	maxei = cpuid_eax (0x80000000);
 +	if (maxei < 0x80000007) {	/* Any powernow info ? */
 +#ifdef MODULE
 +		printk (KERN_INFO PFX "No powernow capabilities detected\n");
 +#endif
 +		return 0;
 +	}
 +
 +	if ((c->x86_model == 6) && (c->x86_mask == 0)) {
 +		printk (KERN_INFO PFX "K7 660[A0] core detected, enabling errata workarounds\n");
 +		have_a0 = 1;
 +	}
 +
 +	cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
 +
 +	/* Check we can actually do something before we say anything.*/
 +	if (!(edx & (1 << 1 | 1 << 2)))
 +		return 0;
 +
 +	printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
 +
 +	if (edx & 1 << 1) {
 +		printk ("frequency");
 +		can_scale_bus=1;
 +	}
 +
 +	if ((edx & (1 << 1 | 1 << 2)) == 0x6)
 +		printk (" and ");
 +
 +	if (edx & 1 << 2) {
 +		printk ("voltage");
 +		can_scale_vid=1;
 +	}
 +
 +	printk (".\n");
 +	return 1;
 +}
 +
 +
 +static int get_ranges (unsigned char *pst)
 +{
 +	unsigned int j;
 +	unsigned int speed;
 +	u8 fid, vid;
 +
 +	powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL);
 +	if (!powernow_table)
 +		return -ENOMEM;
 +
 +	for (j=0 ; j < number_scales; j++) {
 +		fid = *pst++;
 +
 +		powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
 +		powernow_table[j].index = fid; /* lower 8 bits */
 +
 +		speed = powernow_table[j].frequency;
 +
 +		if ((fid_codes[fid] % 10)==5) {
 +#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 +			if (have_a0 == 1)
 +				powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID;
 +#endif
 +		}
 +
 +		if (speed < minimum_speed)
 +			minimum_speed = speed;
 +		if (speed > maximum_speed)
 +			maximum_speed = speed;
 +
 +		vid = *pst++;
 +		powernow_table[j].index |= (vid << 8); /* upper 8 bits */
 +
 +		dprintk ("   FID: 0x%x (%d.%dx [%dMHz])  "
 +			 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
 +			 fid_codes[fid] % 10, speed/1000, vid,
 +			 mobile_vid_table[vid]/1000,
 +			 mobile_vid_table[vid]%1000);
 +	}
 +	powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;
 +	powernow_table[number_scales].index = 0;
 +
 +	return 0;
 +}
 +
 +
 +static void change_FID(int fid)
 +{
 +	union msr_fidvidctl fidvidctl;
 +
 +	rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
 +	if (fidvidctl.bits.FID != fid) {
 +		fidvidctl.bits.SGTC = latency;
 +		fidvidctl.bits.FID = fid;
 +		fidvidctl.bits.VIDC = 0;
 +		fidvidctl.bits.FIDC = 1;
 +		wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
 +	}
 +}
 +
 +
 +static void change_VID(int vid)
 +{
 +	union msr_fidvidctl fidvidctl;
 +
 +	rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
 +	if (fidvidctl.bits.VID != vid) {
 +		fidvidctl.bits.SGTC = latency;
 +		fidvidctl.bits.VID = vid;
 +		fidvidctl.bits.FIDC = 0;
 +		fidvidctl.bits.VIDC = 1;
 +		wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
 +	}
 +}
 +
 +
 +static void change_speed (unsigned int index)
 +{
 +	u8 fid, vid;
 +	struct cpufreq_freqs freqs;
 +	union msr_fidvidstatus fidvidstatus;
 +	int cfid;
 +
 +	/* fid are the lower 8 bits of the index we stored into
 +	 * the cpufreq frequency table in powernow_decode_bios,
 +	 * vid are the upper 8 bits.
 +	 */
 +
 +	fid = powernow_table[index].index & 0xFF;
 +	vid = (powernow_table[index].index & 0xFF00) >> 8;
 +
 +	freqs.cpu = 0;
 +
 +	rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
 +	cfid = fidvidstatus.bits.CFID;
 +	freqs.old = fsb * fid_codes[cfid] / 10;
 +
 +	freqs.new = powernow_table[index].frequency;
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +
 +	/* Now do the magic poking into the MSRs.  */
 +
 +	if (have_a0 == 1)	/* A0 errata 5 */
 +		local_irq_disable();
 +
 +	if (freqs.old > freqs.new) {
 +		/* Going down, so change FID first */
 +		change_FID(fid);
 +		change_VID(vid);
 +	} else {
 +		/* Going up, so change VID first */
 +		change_VID(vid);
 +		change_FID(fid);
 +	}
 +
 +
 +	if (have_a0 == 1)
 +		local_irq_enable();
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +}
 +
 +
 +#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 +
 +static struct acpi_processor_performance *acpi_processor_perf;
 +
 +static int powernow_acpi_init(void)
 +{
 +	int i;
 +	int retval = 0;
 +	union powernow_acpi_control_t pc;
 +
 +	if (acpi_processor_perf != NULL && powernow_table != NULL) {
 +		retval = -EINVAL;
 +		goto err0;
 +	}
 +
 +	acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance),
 +				      GFP_KERNEL);
 +	if (!acpi_processor_perf) {
 +		retval = -ENOMEM;
 +		goto err0;
 +	}
 +
 +	if (acpi_processor_register_performance(acpi_processor_perf, 0)) {
 +		retval = -EIO;
 +		goto err1;
 +	}
 +
 +	if (acpi_processor_perf->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
 +		retval = -ENODEV;
 +		goto err2;
 +	}
 +
 +	if (acpi_processor_perf->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
 +		retval = -ENODEV;
 +		goto err2;
 +	}
 +
 +	number_scales = acpi_processor_perf->state_count;
 +
 +	if (number_scales < 2) {
 +		retval = -ENODEV;
 +		goto err2;
 +	}
 +
 +	powernow_table = kzalloc((number_scales + 1) * (sizeof(struct cpufreq_frequency_table)), GFP_KERNEL);
 +	if (!powernow_table) {
 +		retval = -ENOMEM;
 +		goto err2;
 +	}
 +
 +	pc.val = (unsigned long) acpi_processor_perf->states[0].control;
 +	for (i = 0; i < number_scales; i++) {
 +		u8 fid, vid;
 +		struct acpi_processor_px *state =
 +			&acpi_processor_perf->states[i];
 +		unsigned int speed, speed_mhz;
 +
 +		pc.val = (unsigned long) state->control;
 +		dprintk ("acpi:  P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
 +			 i,
 +			 (u32) state->core_frequency,
 +			 (u32) state->power,
 +			 (u32) state->transition_latency,
 +			 (u32) state->control,
 +			 pc.bits.sgtc);
 +
 +		vid = pc.bits.vid;
 +		fid = pc.bits.fid;
 +
 +		powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
 +		powernow_table[i].index = fid; /* lower 8 bits */
 +		powernow_table[i].index |= (vid << 8); /* upper 8 bits */
 +
 +		speed = powernow_table[i].frequency;
 +		speed_mhz = speed / 1000;
 +
 +		/* processor_perflib will multiply the MHz value by 1000 to
 +		 * get a KHz value (e.g. 1266000). However, powernow-k7 works
 +		 * with true KHz values (e.g. 1266768). To ensure that all
 +		 * powernow frequencies are available, we must ensure that
 +		 * ACPI doesn't restrict them, so we round up the MHz value
 +		 * to ensure that perflib's computed KHz value is greater than
 +		 * or equal to powernow's KHz value.
 +		 */
 +		if (speed % 1000 > 0)
 +			speed_mhz++;
 +
 +		if ((fid_codes[fid] % 10)==5) {
 +			if (have_a0 == 1)
 +				powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +		}
 +
 +		dprintk ("   FID: 0x%x (%d.%dx [%dMHz])  "
 +			 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
 +			 fid_codes[fid] % 10, speed_mhz, vid,
 +			 mobile_vid_table[vid]/1000,
 +			 mobile_vid_table[vid]%1000);
 +
 +		if (state->core_frequency != speed_mhz) {
 +			state->core_frequency = speed_mhz;
 +			dprintk("   Corrected ACPI frequency to %d\n",
 +				speed_mhz);
 +		}
 +
 +		if (latency < pc.bits.sgtc)
 +			latency = pc.bits.sgtc;
 +
 +		if (speed < minimum_speed)
 +			minimum_speed = speed;
 +		if (speed > maximum_speed)
 +			maximum_speed = speed;
 +	}
 +
 +	powernow_table[i].frequency = CPUFREQ_TABLE_END;
 +	powernow_table[i].index = 0;
 +
 +	/* notify BIOS that we exist */
 +	acpi_processor_notify_smm(THIS_MODULE);
 +
 +	return 0;
 +
 +err2:
 +	acpi_processor_unregister_performance(acpi_processor_perf, 0);
 +err1:
 +	kfree(acpi_processor_perf);
 +err0:
 +	printk(KERN_WARNING PFX "ACPI perflib can not be used in this platform\n");
 +	acpi_processor_perf = NULL;
 +	return retval;
 +}
 +#else
 +static int powernow_acpi_init(void)
 +{
 +	printk(KERN_INFO PFX "no support for ACPI processor found."
 +	       "  Please recompile your kernel with ACPI processor\n");
 +	return -EINVAL;
 +}
 +#endif
 +
 +static int powernow_decode_bios (int maxfid, int startvid)
 +{
 +	struct psb_s *psb;
 +	struct pst_s *pst;
 +	unsigned int i, j;
 +	unsigned char *p;
 +	unsigned int etuple;
 +	unsigned int ret;
 +
 +	etuple = cpuid_eax(0x80000001);
 +
 +	for (i=0xC0000; i < 0xffff0 ; i+=16) {
 +
 +		p = phys_to_virt(i);
 +
 +		if (memcmp(p, "AMDK7PNOW!",  10) == 0){
 +			dprintk ("Found PSB header at %p\n", p);
 +			psb = (struct psb_s *) p;
 +			dprintk ("Table version: 0x%x\n", psb->tableversion);
 +			if (psb->tableversion != 0x12) {
 +				printk (KERN_INFO PFX "Sorry, only v1.2 tables supported right now\n");
 +				return -ENODEV;
 +			}
 +
 +			dprintk ("Flags: 0x%x\n", psb->flags);
 +			if ((psb->flags & 1)==0) {
 +				dprintk ("Mobile voltage regulator\n");
 +			} else {
 +				dprintk ("Desktop voltage regulator\n");
 +			}
 +
 +			latency = psb->settlingtime;
 +			if (latency < 100) {
 +				printk (KERN_INFO PFX "BIOS set settling time to %d microseconds."
 +						"Should be at least 100. Correcting.\n", latency);
 +				latency = 100;
 +			}
 +			dprintk ("Settling Time: %d microseconds.\n", psb->settlingtime);
 +			dprintk ("Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst);
 +
 +			p += sizeof (struct psb_s);
 +
 +			pst = (struct pst_s *) p;
 +
 +			for (j=0; j<psb->numpst; j++) {
 +				pst = (struct pst_s *) p;
 +				number_scales = pst->numpstates;
 +
 +				if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) &&
 +				    (maxfid==pst->maxfid) && (startvid==pst->startvid))
 +				{
 +					dprintk ("PST:%d (@%p)\n", j, pst);
 +					dprintk (" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",
 +						 pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
 +
 +					ret = get_ranges ((char *) pst + sizeof (struct pst_s));
 +					return ret;
 +				} else {
 +					unsigned int k;
 +					p = (char *) pst + sizeof (struct pst_s);
 +					for (k=0; k<number_scales; k++)
 +						p+=2;
 +				}
 +			}
 +			printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple);
 +			printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n");
 +
 +			return -EINVAL;
 +		}
 +		p++;
 +	}
 +
 +	return -ENODEV;
 +}
 +
 +
 +static int powernow_target (struct cpufreq_policy *policy,
 +			    unsigned int target_freq,
 +			    unsigned int relation)
 +{
 +	unsigned int newstate;
 +
 +	if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, relation, &newstate))
 +		return -EINVAL;
 +
 +	change_speed(newstate);
 +
 +	return 0;
 +}
 +
 +
 +static int powernow_verify (struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, powernow_table);
 +}
 +
 +/*
 + * We use the fact that the bus frequency is somehow
 + * a multiple of 100000/3 khz, then we compute sgtc according
 + * to this multiple.
 + * That way, we match more how AMD thinks all of that work.
 + * We will then get the same kind of behaviour already tested under
 + * the "well-known" other OS.
 + */
 +static int __init fixup_sgtc(void)
 +{
 +	unsigned int sgtc;
 +	unsigned int m;
 +
 +	m = fsb / 3333;
 +	if ((m % 10) >= 5)
 +		m += 5;
 +
 +	m /= 10;
 +
 +	sgtc = 100 * m * latency;
 +	sgtc = sgtc / 3;
 +	if (sgtc > 0xfffff) {
 +		printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc);
 +		sgtc = 0xfffff;
 +	}
 +	return sgtc;
 +}
 +
 +static unsigned int powernow_get(unsigned int cpu)
 +{
 +	union msr_fidvidstatus fidvidstatus;
 +	unsigned int cfid;
 +
 +	if (cpu)
 +		return 0;
 +	rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
 +	cfid = fidvidstatus.bits.CFID;
 +
 +	return (fsb * fid_codes[cfid] / 10);
 +}
 +
 +
 +static int __init acer_cpufreq_pst(struct dmi_system_id *d)
 +{
 +	printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident);
 +	printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
 +	printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n");
 +	return 0;
 +}
 +
 +/*
 + * Some Athlon laptops have really fucked PST tables.
 + * A BIOS update is all that can save them.
 + * Mention this, and disable cpufreq.
 + */
 +static struct dmi_system_id __initdata powernow_dmi_table[] = {
 +	{
 +		.callback = acer_cpufreq_pst,
 +		.ident = "Acer Aspire",
 +		.matches = {
 +			DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
 +			DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
 +		},
 +	},
 +	{ }
 +};
 +
 +static int __init powernow_cpu_init (struct cpufreq_policy *policy)
 +{
 +	union msr_fidvidstatus fidvidstatus;
 +	int result;
 +
 +	if (policy->cpu != 0)
 +		return -ENODEV;
 +
 +	rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
 +
 +	recalibrate_cpu_khz();
 +
 +	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
 +	if (!fsb) {
 +		printk(KERN_WARNING PFX "can not determine bus frequency\n");
 +		return -EINVAL;
 +	}
 +	dprintk("FSB: %3dMHz\n", fsb/1000);
 +
 +	if (dmi_check_system(powernow_dmi_table) || acpi_force) {
 +		printk (KERN_INFO PFX "PSB/PST known to be broken.  Trying ACPI instead\n");
 +		result = powernow_acpi_init();
 +	} else {
 +		result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID);
 +		if (result) {
 +			printk (KERN_INFO PFX "Trying ACPI perflib\n");
 +			maximum_speed = 0;
 +			minimum_speed = -1;
 +			latency = 0;
 +			result = powernow_acpi_init();
 +			if (result) {
 +				printk (KERN_INFO PFX "ACPI and legacy methods failed\n");
 +				printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.html\n");
 +			}
 +		} else {
 +			/* SGTC use the bus clock as timer */
 +			latency = fixup_sgtc();
 +			printk(KERN_INFO PFX "SGTC: %d\n", latency);
 +		}
 +	}
 +
 +	if (result)
 +		return result;
 +
 +	printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
 +				minimum_speed/1000, maximum_speed/1000);
 +
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- 
 +	policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
 +
 +	policy->cur = powernow_get(0);
 +
 +	cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);
 +
 +	return cpufreq_frequency_table_cpuinfo(policy, powernow_table);
 +}
 +
 +static int powernow_cpu_exit (struct cpufreq_policy *policy) {
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +
 +#ifdef CONFIG_X86_POWERNOW_K7_ACPI
 +	if (acpi_processor_perf) {
 +		acpi_processor_unregister_performance(acpi_processor_perf, 0);
 +		kfree(acpi_processor_perf);
 +	}
 +#endif
 +
 +	kfree(powernow_table);
 +	return 0;
 +}
 +
 +static struct freq_attr* powernow_table_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver powernow_driver = {
 +	.verify	= powernow_verify,
 +	.target	= powernow_target,
 +	.get	= powernow_get,
 +	.init	= powernow_cpu_init,
 +	.exit	= powernow_cpu_exit,
 +	.name	= "powernow-k7",
 +	.owner	= THIS_MODULE,
 +	.attr	= powernow_table_attr,
 +};
 +
 +static int __init powernow_init (void)
 +{
 +	if (check_powernow()==0)
 +		return -ENODEV;
 +	return cpufreq_register_driver(&powernow_driver);
 +}
 +
 +
 +static void __exit powernow_exit (void)
 +{
 +	cpufreq_unregister_driver(&powernow_driver);
 +}
 +
 +module_param(acpi_force,  int, 0444);
 +MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
 +
 +MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
 +MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");
 +MODULE_LICENSE ("GPL");
 +
 +late_initcall(powernow_init);
 +module_exit(powernow_exit);
 +
diff --cc arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index 34ed53a06730,000000000000..b273b69cfddf
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@@ -1,1363 -1,0 +1,1360 @@@
 +/*
 + *   (c) 2003-2006 Advanced Micro Devices, Inc.
 + *  Your use of this code is subject to the terms and conditions of the
 + *  GNU general public license version 2. See "COPYING" or
 + *  http://www.gnu.org/licenses/gpl.html
 + *
 + *  Support : mark.langsdorf@amd.com
 + *
 + *  Based on the powernow-k7.c module written by Dave Jones.
 + *  (C) 2003 Dave Jones <davej@codemonkey.org.uk> on behalf of SuSE Labs
 + *  (C) 2004 Dominik Brodowski <linux@brodo.de>
 + *  (C) 2004 Pavel Machek <pavel@suse.cz>
 + *  Licensed under the terms of the GNU GPL License version 2.
 + *  Based upon datasheets & sample CPUs kindly provided by AMD.
 + *
 + *  Valuable input gratefully received from Dave Jones, Pavel Machek,
 + *  Dominik Brodowski, Jacob Shin, and others.
 + *  Originally developed by Paul Devriendt.
 + *  Processor information obtained from Chapter 9 (Power and Thermal Management)
 + *  of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
 + *  Opteron Processors" available for download from www.amd.com
 + *
 + *  Tables for specific CPUs can be inferred from
 + *     http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/smp.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/slab.h>
 +#include <linux/string.h>
 +#include <linux/cpumask.h>
 +#include <linux/sched.h>	/* for current / set_cpus_allowed() */
 +
 +#include <asm/msr.h>
 +#include <asm/io.h>
 +#include <asm/delay.h>
 +
 +#ifdef CONFIG_X86_POWERNOW_K8_ACPI
 +#include <linux/acpi.h>
 +#include <linux/mutex.h>
 +#include <acpi/processor.h>
 +#endif
 +
 +#define PFX "powernow-k8: "
 +#define BFX PFX "BIOS error: "
 +#define VERSION "version 2.00.00"
 +#include "powernow-k8.h"
 +
 +/* serialize freq changes  */
 +static DEFINE_MUTEX(fidvid_mutex);
 +
 +static struct powernow_k8_data *powernow_data[NR_CPUS];
 +
 +static int cpu_family = CPU_OPTERON;
 +
 +#ifndef CONFIG_SMP
 +static cpumask_t cpu_core_map[1];
 +#endif
 +
 +/* Return a frequency in MHz, given an input fid */
 +static u32 find_freq_from_fid(u32 fid)
 +{
 +	return 800 + (fid * 100);
 +}
 +
 +
 +/* Return a frequency in KHz, given an input fid */
 +static u32 find_khz_freq_from_fid(u32 fid)
 +{
 +	return 1000 * find_freq_from_fid(fid);
 +}
 +
 +/* Return a frequency in MHz, given an input fid and did */
 +static u32 find_freq_from_fiddid(u32 fid, u32 did)
 +{
- 	return 100 * (fid + 0x10) >> did;
++	if (current_cpu_data.x86 == 0x10)
++		return 100 * (fid + 0x10) >> did;
++	else
++		return 100 * (fid + 0x8) >> did;
 +}
 +
 +static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
 +{
 +	return 1000 * find_freq_from_fiddid(fid, did);
 +}
 +
 +static u32 find_fid_from_pstate(u32 pstate)
 +{
 +	u32 hi, lo;
 +	rdmsr(MSR_PSTATE_DEF_BASE + pstate, lo, hi);
 +	return lo & HW_PSTATE_FID_MASK;
 +}
 +
 +static u32 find_did_from_pstate(u32 pstate)
 +{
 +	u32 hi, lo;
 +	rdmsr(MSR_PSTATE_DEF_BASE + pstate, lo, hi);
 +	return (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
 +}
 +
 +/* Return the vco fid for an input fid
 + *
 + * Each "low" fid has corresponding "high" fid, and you can get to "low" fids
 + * only from corresponding high fids. This returns "high" fid corresponding to
 + * "low" one.
 + */
 +static u32 convert_fid_to_vco_fid(u32 fid)
 +{
 +	if (fid < HI_FID_TABLE_BOTTOM)
 +		return 8 + (2 * fid);
 +	else
 +		return fid;
 +}
 +
 +/*
 + * Return 1 if the pending bit is set. Unless we just instructed the processor
 + * to transition to a new state, seeing this bit set is really bad news.
 + */
 +static int pending_bit_stuck(void)
 +{
 +	u32 lo, hi;
 +
 +	if (cpu_family == CPU_HW_PSTATE)
 +		return 0;
 +
 +	rdmsr(MSR_FIDVID_STATUS, lo, hi);
 +	return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
 +}
 +
 +/*
 + * Update the global current fid / vid values from the status msr.
 + * Returns 1 on error.
 + */
 +static int query_current_values_with_pending_wait(struct powernow_k8_data *data)
 +{
 +	u32 lo, hi;
 +	u32 i = 0;
 +
 +	if (cpu_family == CPU_HW_PSTATE) {
 +		rdmsr(MSR_PSTATE_STATUS, lo, hi);
 +		i = lo & HW_PSTATE_MASK;
 +		rdmsr(MSR_PSTATE_DEF_BASE + i, lo, hi);
 +		data->currfid = lo & HW_PSTATE_FID_MASK;
 +		data->currdid = (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
 +		return 0;
 +	}
 +	do {
 +		if (i++ > 10000) {
 +			dprintk("detected change pending stuck\n");
 +			return 1;
 +		}
 +		rdmsr(MSR_FIDVID_STATUS, lo, hi);
 +	} while (lo & MSR_S_LO_CHANGE_PENDING);
 +
 +	data->currvid = hi & MSR_S_HI_CURRENT_VID;
 +	data->currfid = lo & MSR_S_LO_CURRENT_FID;
 +
 +	return 0;
 +}
 +
 +/* the isochronous relief time */
 +static void count_off_irt(struct powernow_k8_data *data)
 +{
 +	udelay((1 << data->irt) * 10);
 +	return;
 +}
 +
 +/* the voltage stabalization time */
 +static void count_off_vst(struct powernow_k8_data *data)
 +{
 +	udelay(data->vstable * VST_UNITS_20US);
 +	return;
 +}
 +
 +/* need to init the control msr to a safe value (for each cpu) */
 +static void fidvid_msr_init(void)
 +{
 +	u32 lo, hi;
 +	u8 fid, vid;
 +
 +	rdmsr(MSR_FIDVID_STATUS, lo, hi);
 +	vid = hi & MSR_S_HI_CURRENT_VID;
 +	fid = lo & MSR_S_LO_CURRENT_FID;
 +	lo = fid | (vid << MSR_C_LO_VID_SHIFT);
 +	hi = MSR_C_HI_STP_GNT_BENIGN;
 +	dprintk("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi);
 +	wrmsr(MSR_FIDVID_CTL, lo, hi);
 +}
 +
 +
 +/* write the new fid value along with the other control fields to the msr */
 +static int write_new_fid(struct powernow_k8_data *data, u32 fid)
 +{
 +	u32 lo;
 +	u32 savevid = data->currvid;
 +	u32 i = 0;
 +
 +	if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) {
 +		printk(KERN_ERR PFX "internal error - overflow on fid write\n");
 +		return 1;
 +	}
 +
 +	lo = fid | (data->currvid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID;
 +
 +	dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
 +		fid, lo, data->plllock * PLL_LOCK_CONVERSION);
 +
 +	do {
 +		wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
 +		if (i++ > 100) {
 +			printk(KERN_ERR PFX "Hardware error - pending bit very stuck - no further pstate changes possible\n");
 +			return 1;
 +		}
 +	} while (query_current_values_with_pending_wait(data));
 +
 +	count_off_irt(data);
 +
 +	if (savevid != data->currvid) {
 +		printk(KERN_ERR PFX "vid change on fid trans, old 0x%x, new 0x%x\n",
 +		       savevid, data->currvid);
 +		return 1;
 +	}
 +
 +	if (fid != data->currfid) {
 +		printk(KERN_ERR PFX "fid trans failed, fid 0x%x, curr 0x%x\n", fid,
 +		        data->currfid);
 +		return 1;
 +	}
 +
 +	return 0;
 +}
 +
 +/* Write a new vid to the hardware */
 +static int write_new_vid(struct powernow_k8_data *data, u32 vid)
 +{
 +	u32 lo;
 +	u32 savefid = data->currfid;
 +	int i = 0;
 +
 +	if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) {
 +		printk(KERN_ERR PFX "internal error - overflow on vid write\n");
 +		return 1;
 +	}
 +
 +	lo = data->currfid | (vid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID;
 +
 +	dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
 +		vid, lo, STOP_GRANT_5NS);
 +
 +	do {
 +		wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
 +		if (i++ > 100) {
 +			printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n");
 +			return 1;
 +		}
 +	} while (query_current_values_with_pending_wait(data));
 +
 +	if (savefid != data->currfid) {
 +		printk(KERN_ERR PFX "fid changed on vid trans, old 0x%x new 0x%x\n",
 +		       savefid, data->currfid);
 +		return 1;
 +	}
 +
 +	if (vid != data->currvid) {
 +		printk(KERN_ERR PFX "vid trans failed, vid 0x%x, curr 0x%x\n", vid,
 +				data->currvid);
 +		return 1;
 +	}
 +
 +	return 0;
 +}
 +
 +/*
 + * Reduce the vid by the max of step or reqvid.
 + * Decreasing vid codes represent increasing voltages:
 + * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off.
 + */
 +static int decrease_vid_code_by_step(struct powernow_k8_data *data, u32 reqvid, u32 step)
 +{
 +	if ((data->currvid - reqvid) > step)
 +		reqvid = data->currvid - step;
 +
 +	if (write_new_vid(data, reqvid))
 +		return 1;
 +
 +	count_off_vst(data);
 +
 +	return 0;
 +}
 +
 +/* Change hardware pstate by single MSR write */
 +static int transition_pstate(struct powernow_k8_data *data, u32 pstate)
 +{
 +	wrmsr(MSR_PSTATE_CTRL, pstate, 0);
 +	data->currfid = find_fid_from_pstate(pstate);
 +	return 0;
 +}
 +
 +/* Change Opteron/Athlon64 fid and vid, by the 3 phases. */
 +static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 reqvid)
 +{
 +	if (core_voltage_pre_transition(data, reqvid))
 +		return 1;
 +
 +	if (core_frequency_transition(data, reqfid))
 +		return 1;
 +
 +	if (core_voltage_post_transition(data, reqvid))
 +		return 1;
 +
 +	if (query_current_values_with_pending_wait(data))
 +		return 1;
 +
 +	if ((reqfid != data->currfid) || (reqvid != data->currvid)) {
 +		printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, curr 0x%x 0x%x\n",
 +				smp_processor_id(),
 +				reqfid, reqvid, data->currfid, data->currvid);
 +		return 1;
 +	}
 +
 +	dprintk("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n",
 +		smp_processor_id(), data->currfid, data->currvid);
 +
 +	return 0;
 +}
 +
 +/* Phase 1 - core voltage transition ... setup voltage */
 +static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid)
 +{
 +	u32 rvosteps = data->rvo;
 +	u32 savefid = data->currfid;
 +	u32 maxvid, lo;
 +
 +	dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n",
 +		smp_processor_id(),
 +		data->currfid, data->currvid, reqvid, data->rvo);
 +
 +	rdmsr(MSR_FIDVID_STATUS, lo, maxvid);
 +	maxvid = 0x1f & (maxvid >> 16);
 +	dprintk("ph1 maxvid=0x%x\n", maxvid);
 +	if (reqvid < maxvid) /* lower numbers are higher voltages */
 +		reqvid = maxvid;
 +
 +	while (data->currvid > reqvid) {
 +		dprintk("ph1: curr 0x%x, req vid 0x%x\n",
 +			data->currvid, reqvid);
 +		if (decrease_vid_code_by_step(data, reqvid, data->vidmvs))
 +			return 1;
 +	}
 +
 +	while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) {
 +		if (data->currvid == maxvid) {
 +			rvosteps = 0;
 +		} else {
 +			dprintk("ph1: changing vid for rvo, req 0x%x\n",
 +				data->currvid - 1);
 +			if (decrease_vid_code_by_step(data, data->currvid - 1, 1))
 +				return 1;
 +			rvosteps--;
 +		}
 +	}
 +
 +	if (query_current_values_with_pending_wait(data))
 +		return 1;
 +
 +	if (savefid != data->currfid) {
 +		printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n", data->currfid);
 +		return 1;
 +	}
 +
 +	dprintk("ph1 complete, currfid 0x%x, currvid 0x%x\n",
 +		data->currfid, data->currvid);
 +
 +	return 0;
 +}
 +
 +/* Phase 2 - core frequency transition */
 +static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
 +{
 +	u32 vcoreqfid, vcocurrfid, vcofiddiff, fid_interval, savevid = data->currvid;
 +
 +	if ((reqfid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
 +		printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n",
 +			reqfid, data->currfid);
 +		return 1;
 +	}
 +
 +	if (data->currfid == reqfid) {
 +		printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", data->currfid);
 +		return 0;
 +	}
 +
 +	dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n",
 +		smp_processor_id(),
 +		data->currfid, data->currvid, reqfid);
 +
 +	vcoreqfid = convert_fid_to_vco_fid(reqfid);
 +	vcocurrfid = convert_fid_to_vco_fid(data->currfid);
 +	vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
 +	    : vcoreqfid - vcocurrfid;
 +
 +	while (vcofiddiff > 2) {
 +		(data->currfid & 1) ? (fid_interval = 1) : (fid_interval = 2);
 +
 +		if (reqfid > data->currfid) {
 +			if (data->currfid > LO_FID_TABLE_TOP) {
 +				if (write_new_fid(data, data->currfid + fid_interval)) {
 +					return 1;
 +				}
 +			} else {
 +				if (write_new_fid
 +				    (data, 2 + convert_fid_to_vco_fid(data->currfid))) {
 +					return 1;
 +				}
 +			}
 +		} else {
 +			if (write_new_fid(data, data->currfid - fid_interval))
 +				return 1;
 +		}
 +
 +		vcocurrfid = convert_fid_to_vco_fid(data->currfid);
 +		vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
 +		    : vcoreqfid - vcocurrfid;
 +	}
 +
 +	if (write_new_fid(data, reqfid))
 +		return 1;
 +
 +	if (query_current_values_with_pending_wait(data))
 +		return 1;
 +
 +	if (data->currfid != reqfid) {
 +		printk(KERN_ERR PFX
 +			"ph2: mismatch, failed fid transition, curr 0x%x, req 0x%x\n",
 +			data->currfid, reqfid);
 +		return 1;
 +	}
 +
 +	if (savevid != data->currvid) {
 +		printk(KERN_ERR PFX "ph2: vid changed, save 0x%x, curr 0x%x\n",
 +			savevid, data->currvid);
 +		return 1;
 +	}
 +
 +	dprintk("ph2 complete, currfid 0x%x, currvid 0x%x\n",
 +		data->currfid, data->currvid);
 +
 +	return 0;
 +}
 +
 +/* Phase 3 - core voltage transition flow ... jump to the final vid. */
 +static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid)
 +{
 +	u32 savefid = data->currfid;
 +	u32 savereqvid = reqvid;
 +
 +	dprintk("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n",
 +		smp_processor_id(),
 +		data->currfid, data->currvid);
 +
 +	if (reqvid != data->currvid) {
 +		if (write_new_vid(data, reqvid))
 +			return 1;
 +
 +		if (savefid != data->currfid) {
 +			printk(KERN_ERR PFX
 +			       "ph3: bad fid change, save 0x%x, curr 0x%x\n",
 +			       savefid, data->currfid);
 +			return 1;
 +		}
 +
 +		if (data->currvid != reqvid) {
 +			printk(KERN_ERR PFX
 +			       "ph3: failed vid transition\n, req 0x%x, curr 0x%x",
 +			       reqvid, data->currvid);
 +			return 1;
 +		}
 +	}
 +
 +	if (query_current_values_with_pending_wait(data))
 +		return 1;
 +
 +	if (savereqvid != data->currvid) {
 +		dprintk("ph3 failed, currvid 0x%x\n", data->currvid);
 +		return 1;
 +	}
 +
 +	if (savefid != data->currfid) {
 +		dprintk("ph3 failed, currfid changed 0x%x\n",
 +			data->currfid);
 +		return 1;
 +	}
 +
 +	dprintk("ph3 complete, currfid 0x%x, currvid 0x%x\n",
 +		data->currfid, data->currvid);
 +
 +	return 0;
 +}
 +
 +static int check_supported_cpu(unsigned int cpu)
 +{
 +	cpumask_t oldmask = CPU_MASK_ALL;
 +	u32 eax, ebx, ecx, edx;
 +	unsigned int rc = 0;
 +
 +	oldmask = current->cpus_allowed;
 +	set_cpus_allowed(current, cpumask_of_cpu(cpu));
 +
 +	if (smp_processor_id() != cpu) {
 +		printk(KERN_ERR PFX "limiting to cpu %u failed\n", cpu);
 +		goto out;
 +	}
 +
 +	if (current_cpu_data.x86_vendor != X86_VENDOR_AMD)
 +		goto out;
 +
 +	eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
 +	if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) &&
 +	    ((eax & CPUID_XFAM) < CPUID_XFAM_10H))
 +		goto out;
 +
 +	if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
 +		if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
 +		    ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) {
 +			printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
 +			goto out;
 +		}
 +
 +		eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
 +		if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
 +			printk(KERN_INFO PFX
 +			       "No frequency change capabilities detected\n");
 +			goto out;
 +		}
 +
 +		cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
 +		if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
 +			printk(KERN_INFO PFX "Power state transitions not supported\n");
 +			goto out;
 +		}
 +	} else { /* must be a HW Pstate capable processor */
 +		cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
 +		if ((edx & USE_HW_PSTATE) == USE_HW_PSTATE)
 +			cpu_family = CPU_HW_PSTATE;
 +		else
 +			goto out;
 +	}
 +
 +	rc = 1;
 +
 +out:
 +	set_cpus_allowed(current, oldmask);
 +	return rc;
 +}
 +
 +static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid)
 +{
 +	unsigned int j;
 +	u8 lastfid = 0xff;
 +
 +	for (j = 0; j < data->numps; j++) {
 +		if (pst[j].vid > LEAST_VID) {
 +			printk(KERN_ERR PFX "vid %d invalid : 0x%x\n", j, pst[j].vid);
 +			return -EINVAL;
 +		}
 +		if (pst[j].vid < data->rvo) {	/* vid + rvo >= 0 */
 +			printk(KERN_ERR BFX "0 vid exceeded with pstate %d\n", j);
 +			return -ENODEV;
 +		}
 +		if (pst[j].vid < maxvid + data->rvo) {	/* vid + rvo >= maxvid */
 +			printk(KERN_ERR BFX "maxvid exceeded with pstate %d\n", j);
 +			return -ENODEV;
 +		}
 +		if (pst[j].fid > MAX_FID) {
 +			printk(KERN_ERR BFX "maxfid exceeded with pstate %d\n", j);
 +			return -ENODEV;
 +		}
 +		if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) {
 +			/* Only first fid is allowed to be in "low" range */
 +			printk(KERN_ERR BFX "two low fids - %d : 0x%x\n", j, pst[j].fid);
 +			return -EINVAL;
 +		}
 +		if (pst[j].fid < lastfid)
 +			lastfid = pst[j].fid;
 +	}
 +	if (lastfid & 1) {
 +		printk(KERN_ERR BFX "lastfid invalid\n");
 +		return -EINVAL;
 +	}
 +	if (lastfid > LO_FID_TABLE_TOP)
 +		printk(KERN_INFO BFX  "first fid not from lo freq table\n");
 +
 +	return 0;
 +}
 +
 +static void print_basics(struct powernow_k8_data *data)
 +{
 +	int j;
 +	for (j = 0; j < data->numps; j++) {
 +		if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) {
 +			if (cpu_family == CPU_HW_PSTATE) {
 +				printk(KERN_INFO PFX "   %d : fid 0x%x did 0x%x (%d MHz)\n",
 +					j,
 +					(data->powernow_table[j].index & 0xff00) >> 8,
 +					(data->powernow_table[j].index & 0xff0000) >> 16,
 +					data->powernow_table[j].frequency/1000);
 +			} else {
 +				printk(KERN_INFO PFX "   %d : fid 0x%x (%d MHz), vid 0x%x\n",
 +					j,
 +					data->powernow_table[j].index & 0xff,
 +					data->powernow_table[j].frequency/1000,
 +					data->powernow_table[j].index >> 8);
 +			}
 +		}
 +	}
 +	if (data->batps)
 +		printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps);
 +}
 +
 +static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid)
 +{
 +	struct cpufreq_frequency_table *powernow_table;
 +	unsigned int j;
 +
 +	if (data->batps) {    /* use ACPI support to get full speed on mains power */
 +		printk(KERN_WARNING PFX "Only %d pstates usable (use ACPI driver for full range\n", data->batps);
 +		data->numps = data->batps;
 +	}
 +
 +	for ( j=1; j<data->numps; j++ ) {
 +		if (pst[j-1].fid >= pst[j].fid) {
 +			printk(KERN_ERR PFX "PST out of sequence\n");
 +			return -EINVAL;
 +		}
 +	}
 +
 +	if (data->numps < 2) {
 +		printk(KERN_ERR PFX "no p states to transition\n");
 +		return -ENODEV;
 +	}
 +
 +	if (check_pst_table(data, pst, maxvid))
 +		return -EINVAL;
 +
 +	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
 +		* (data->numps + 1)), GFP_KERNEL);
 +	if (!powernow_table) {
 +		printk(KERN_ERR PFX "powernow_table memory alloc failure\n");
 +		return -ENOMEM;
 +	}
 +
 +	for (j = 0; j < data->numps; j++) {
 +		powernow_table[j].index = pst[j].fid; /* lower 8 bits */
 +		powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */
 +		powernow_table[j].frequency = find_khz_freq_from_fid(pst[j].fid);
 +	}
 +	powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;
 +	powernow_table[data->numps].index = 0;
 +
 +	if (query_current_values_with_pending_wait(data)) {
 +		kfree(powernow_table);
 +		return -EIO;
 +	}
 +
 +	dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
 +	data->powernow_table = powernow_table;
 +	if (first_cpu(cpu_core_map[data->cpu]) == data->cpu)
 +		print_basics(data);
 +
 +	for (j = 0; j < data->numps; j++)
 +		if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid))
 +			return 0;
 +
 +	dprintk("currfid/vid do not match PST, ignoring\n");
 +	return 0;
 +}
 +
 +/* Find and validate the PSB/PST table in BIOS. */
 +static int find_psb_table(struct powernow_k8_data *data)
 +{
 +	struct psb_s *psb;
 +	unsigned int i;
 +	u32 mvs;
 +	u8 maxvid;
 +	u32 cpst = 0;
 +	u32 thiscpuid;
 +
 +	for (i = 0xc0000; i < 0xffff0; i += 0x10) {
 +		/* Scan BIOS looking for the signature. */
 +		/* It can not be at ffff0 - it is too big. */
 +
 +		psb = phys_to_virt(i);
 +		if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0)
 +			continue;
 +
 +		dprintk("found PSB header at 0x%p\n", psb);
 +
 +		dprintk("table vers: 0x%x\n", psb->tableversion);
 +		if (psb->tableversion != PSB_VERSION_1_4) {
 +			printk(KERN_ERR BFX "PSB table is not v1.4\n");
 +			return -ENODEV;
 +		}
 +
 +		dprintk("flags: 0x%x\n", psb->flags1);
 +		if (psb->flags1) {
 +			printk(KERN_ERR BFX "unknown flags\n");
 +			return -ENODEV;
 +		}
 +
 +		data->vstable = psb->vstable;
 +		dprintk("voltage stabilization time: %d(*20us)\n", data->vstable);
 +
 +		dprintk("flags2: 0x%x\n", psb->flags2);
 +		data->rvo = psb->flags2 & 3;
 +		data->irt = ((psb->flags2) >> 2) & 3;
 +		mvs = ((psb->flags2) >> 4) & 3;
 +		data->vidmvs = 1 << mvs;
 +		data->batps = ((psb->flags2) >> 6) & 3;
 +
 +		dprintk("ramp voltage offset: %d\n", data->rvo);
 +		dprintk("isochronous relief time: %d\n", data->irt);
 +		dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
 +
 +		dprintk("numpst: 0x%x\n", psb->num_tables);
 +		cpst = psb->num_tables;
 +		if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){
 +			thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
 +			if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) {
 +				cpst = 1;
 +			}
 +		}
 +		if (cpst != 1) {
 +			printk(KERN_ERR BFX "numpst must be 1\n");
 +			return -ENODEV;
 +		}
 +
 +		data->plllock = psb->plllocktime;
 +		dprintk("plllocktime: 0x%x (units 1us)\n", psb->plllocktime);
 +		dprintk("maxfid: 0x%x\n", psb->maxfid);
 +		dprintk("maxvid: 0x%x\n", psb->maxvid);
 +		maxvid = psb->maxvid;
 +
 +		data->numps = psb->numps;
 +		dprintk("numpstates: 0x%x\n", data->numps);
 +		return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid);
 +	}
 +	/*
 +	 * If you see this message, complain to BIOS manufacturer. If
 +	 * he tells you "we do not support Linux" or some similar
 +	 * nonsense, remember that Windows 2000 uses the same legacy
 +	 * mechanism that the old Linux PSB driver uses. Tell them it
 +	 * is broken with Windows 2000.
 +	 *
 +	 * The reference to the AMD documentation is chapter 9 in the
 +	 * BIOS and Kernel Developer's Guide, which is available on
 +	 * www.amd.com
 +	 */
 +	printk(KERN_ERR PFX "BIOS error - no PSB or ACPI _PSS objects\n");
 +	return -ENODEV;
 +}
 +
 +#ifdef CONFIG_X86_POWERNOW_K8_ACPI
 +static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index)
 +{
 +	if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE))
 +		return;
 +
 +	data->irt = (data->acpi_data.states[index].control >> IRT_SHIFT) & IRT_MASK;
 +	data->rvo = (data->acpi_data.states[index].control >> RVO_SHIFT) & RVO_MASK;
 +	data->exttype = (data->acpi_data.states[index].control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
 +	data->plllock = (data->acpi_data.states[index].control >> PLL_L_SHIFT) & PLL_L_MASK;
 +	data->vidmvs = 1 << ((data->acpi_data.states[index].control >> MVS_SHIFT) & MVS_MASK);
 +	data->vstable = (data->acpi_data.states[index].control >> VST_SHIFT) & VST_MASK;
 +}
 +
 +static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
 +{
 +	struct cpufreq_frequency_table *powernow_table;
 +	int ret_val;
 +
 +	if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
 +		dprintk("register performance failed: bad ACPI data\n");
 +		return -EIO;
 +	}
 +
 +	/* verify the data contained in the ACPI structures */
 +	if (data->acpi_data.state_count <= 1) {
 +		dprintk("No ACPI P-States\n");
 +		goto err_out;
 +	}
 +
 +	if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
 +		(data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
 +		dprintk("Invalid control/status registers (%x - %x)\n",
 +			data->acpi_data.control_register.space_id,
 +			data->acpi_data.status_register.space_id);
 +		goto err_out;
 +	}
 +
 +	/* fill in data->powernow_table */
 +	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
 +		* (data->acpi_data.state_count + 1)), GFP_KERNEL);
 +	if (!powernow_table) {
 +		dprintk("powernow_table memory alloc failure\n");
 +		goto err_out;
 +	}
 +
 +	if (cpu_family == CPU_HW_PSTATE)
 +		ret_val = fill_powernow_table_pstate(data, powernow_table);
 +	else
 +		ret_val = fill_powernow_table_fidvid(data, powernow_table);
 +	if (ret_val)
 +		goto err_out_mem;
 +
 +	powernow_table[data->acpi_data.state_count].frequency = CPUFREQ_TABLE_END;
 +	powernow_table[data->acpi_data.state_count].index = 0;
 +	data->powernow_table = powernow_table;
 +
 +	/* fill in data */
 +	data->numps = data->acpi_data.state_count;
 +	if (first_cpu(cpu_core_map[data->cpu]) == data->cpu)
 +		print_basics(data);
 +	powernow_k8_acpi_pst_values(data, 0);
 +
 +	/* notify BIOS that we exist */
 +	acpi_processor_notify_smm(THIS_MODULE);
 +
 +	return 0;
 +
 +err_out_mem:
 +	kfree(powernow_table);
 +
 +err_out:
 +	acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
 +
 +	/* data->acpi_data.state_count informs us at ->exit() whether ACPI was used */
 +	data->acpi_data.state_count = 0;
 +
 +	return -ENODEV;
 +}
 +
 +static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table)
 +{
 +	int i;
 +
 +	for (i = 0; i < data->acpi_data.state_count; i++) {
 +		u32 index;
 +		u32 hi = 0, lo = 0;
 +		u32 fid;
 +		u32 did;
 +
 +		index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
 +		if (index > MAX_HW_PSTATE) {
 +			printk(KERN_ERR PFX "invalid pstate %d - bad value %d.\n", i, index);
 +			printk(KERN_ERR PFX "Please report to BIOS manufacturer\n");
 +		}
 +		rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
 +		if (!(hi & HW_PSTATE_VALID_MASK)) {
 +			dprintk("invalid pstate %d, ignoring\n", index);
 +			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +			continue;
 +		}
 +
 +		fid = lo & HW_PSTATE_FID_MASK;
 +		did = (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
 +
 +		dprintk("   %d : fid 0x%x, did 0x%x\n", index, fid, did);
 +
 +		powernow_table[i].index = index | (fid << HW_FID_INDEX_SHIFT) | (did << HW_DID_INDEX_SHIFT);
 +
 +		powernow_table[i].frequency = find_khz_freq_from_fiddid(fid, did);
 +
 +		if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
 +			printk(KERN_INFO PFX "invalid freq entries %u kHz vs. %u kHz\n",
 +				powernow_table[i].frequency,
 +				(unsigned int) (data->acpi_data.states[i].core_frequency * 1000));
 +			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +			continue;
 +		}
 +	}
 +	return 0;
 +}
 +
 +static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table)
 +{
 +	int i;
 +	int cntlofreq = 0;
 +	for (i = 0; i < data->acpi_data.state_count; i++) {
 +		u32 fid;
 +		u32 vid;
 +
 +		if (data->exttype) {
 +			fid = data->acpi_data.states[i].status & EXT_FID_MASK;
 +			vid = (data->acpi_data.states[i].status >> VID_SHIFT) & EXT_VID_MASK;
 +		} else {
 +			fid = data->acpi_data.states[i].control & FID_MASK;
 +			vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK;
 +		}
 +
 +		dprintk("   %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
 +
 +		powernow_table[i].index = fid; /* lower 8 bits */
 +		powernow_table[i].index |= (vid << 8); /* upper 8 bits */
 +		powernow_table[i].frequency = find_khz_freq_from_fid(fid);
 +
 +		/* verify frequency is OK */
 +		if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) ||
 +			(powernow_table[i].frequency < (MIN_FREQ * 1000))) {
 +			dprintk("invalid freq %u kHz, ignoring\n", powernow_table[i].frequency);
 +			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +			continue;
 +		}
 +
 +		/* verify voltage is OK - BIOSs are using "off" to indicate invalid */
 +		if (vid == VID_OFF) {
 +			dprintk("invalid vid %u, ignoring\n", vid);
 +			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +			continue;
 +		}
 +
 +		/* verify only 1 entry from the lo frequency table */
 +		if (fid < HI_FID_TABLE_BOTTOM) {
 +			if (cntlofreq) {
 +				/* if both entries are the same, ignore this one ... */
 +				if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) ||
 +				    (powernow_table[i].index != powernow_table[cntlofreq].index)) {
 +					printk(KERN_ERR PFX "Too many lo freq table entries\n");
 +					return 1;
 +				}
 +
 +				dprintk("double low frequency table entry, ignoring it.\n");
 +				powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +				continue;
 +			} else
 +				cntlofreq = i;
 +		}
 +
 +		if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
 +			printk(KERN_INFO PFX "invalid freq entries %u kHz vs. %u kHz\n",
 +				powernow_table[i].frequency,
 +				(unsigned int) (data->acpi_data.states[i].core_frequency * 1000));
 +			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 +			continue;
 +		}
 +	}
 +	return 0;
 +}
 +
 +static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data)
 +{
 +	if (data->acpi_data.state_count)
 +		acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
 +}
 +
 +#else
 +static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { return -ENODEV; }
 +static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { return; }
 +static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { return; }
 +#endif /* CONFIG_X86_POWERNOW_K8_ACPI */
 +
 +/* Take a frequency, and issue the fid/vid transition command */
 +static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned int index)
 +{
 +	u32 fid = 0;
 +	u32 vid = 0;
 +	int res, i;
 +	struct cpufreq_freqs freqs;
 +
 +	dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
 +
 +	/* fid/vid correctness check for k8 */
 +	/* fid are the lower 8 bits of the index we stored into
 +	 * the cpufreq frequency table in find_psb_table, vid
 +	 * are the upper 8 bits.
 +	 */
 +	fid = data->powernow_table[index].index & 0xFF;
 +	vid = (data->powernow_table[index].index & 0xFF00) >> 8;
 +
 +	dprintk("table matched fid 0x%x, giving vid 0x%x\n", fid, vid);
 +
 +	if (query_current_values_with_pending_wait(data))
 +		return 1;
 +
 +	if ((data->currvid == vid) && (data->currfid == fid)) {
 +		dprintk("target matches current values (fid 0x%x, vid 0x%x)\n",
 +			fid, vid);
 +		return 0;
 +	}
 +
 +	if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
 +		printk(KERN_ERR PFX
 +		       "ignoring illegal change in lo freq table-%x to 0x%x\n",
 +		       data->currfid, fid);
 +		return 1;
 +	}
 +
 +	dprintk("cpu %d, changing to fid 0x%x, vid 0x%x\n",
 +		smp_processor_id(), fid, vid);
 +	freqs.old = find_khz_freq_from_fid(data->currfid);
 +	freqs.new = find_khz_freq_from_fid(fid);
 +
 +	for_each_cpu_mask(i, *(data->available_cores)) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +	}
 +
 +	res = transition_fid_vid(data, fid, vid);
 +	freqs.new = find_khz_freq_from_fid(data->currfid);
 +
 +	for_each_cpu_mask(i, *(data->available_cores)) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +	}
 +	return res;
 +}
 +
 +/* Take a frequency, and issue the hardware pstate transition command */
 +static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned int index)
 +{
 +	u32 fid = 0;
 +	u32 did = 0;
 +	u32 pstate = 0;
 +	int res, i;
 +	struct cpufreq_freqs freqs;
 +
 +	dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
 +
 +	/* get fid did for hardware pstate transition */
 +	pstate = index & HW_PSTATE_MASK;
 +	if (pstate > MAX_HW_PSTATE)
 +		return 0;
 +	fid = (index & HW_FID_INDEX_MASK) >> HW_FID_INDEX_SHIFT;
 +	did = (index & HW_DID_INDEX_MASK) >> HW_DID_INDEX_SHIFT;
 +	freqs.old = find_khz_freq_from_fiddid(data->currfid, data->currdid);
 +	freqs.new = find_khz_freq_from_fiddid(fid, did);
 +
 +	for_each_cpu_mask(i, *(data->available_cores)) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +	}
 +
 +	res = transition_pstate(data, pstate);
 +	data->currfid = find_fid_from_pstate(pstate);
 +	data->currdid = find_did_from_pstate(pstate);
 +	freqs.new = find_khz_freq_from_fiddid(data->currfid, data->currdid);
 +
 +	for_each_cpu_mask(i, *(data->available_cores)) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +	}
 +	return res;
 +}
 +
 +/* Driver entry point to switch to the target frequency */
 +static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsigned relation)
 +{
 +	cpumask_t oldmask = CPU_MASK_ALL;
 +	struct powernow_k8_data *data = powernow_data[pol->cpu];
 +	u32 checkfid;
 +	u32 checkvid;
 +	unsigned int newstate;
 +	int ret = -EIO;
 +
 +	if (!data)
 +		return -EINVAL;
 +
 +	checkfid = data->currfid;
 +	checkvid = data->currvid;
 +
 +	/* only run on specific CPU from here on */
 +	oldmask = current->cpus_allowed;
 +	set_cpus_allowed(current, cpumask_of_cpu(pol->cpu));
 +
 +	if (smp_processor_id() != pol->cpu) {
 +		printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu);
 +		goto err_out;
 +	}
 +
 +	if (pending_bit_stuck()) {
 +		printk(KERN_ERR PFX "failing targ, change pending bit set\n");
 +		goto err_out;
 +	}
 +
 +	dprintk("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
 +		pol->cpu, targfreq, pol->min, pol->max, relation);
 +
 +	if (query_current_values_with_pending_wait(data))
 +		goto err_out;
 +
 +	if (cpu_family == CPU_HW_PSTATE)
 +		dprintk("targ: curr fid 0x%x, did 0x%x\n",
 +			data->currfid, data->currdid);
 +	else {
 +		dprintk("targ: curr fid 0x%x, vid 0x%x\n",
 +		data->currfid, data->currvid);
 +
 +		if ((checkvid != data->currvid) || (checkfid != data->currfid)) {
 +			printk(KERN_INFO PFX
 +				"error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
 +				checkfid, data->currfid, checkvid, data->currvid);
 +		}
 +	}
 +
 +	if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate))
 +		goto err_out;
 +
 +	mutex_lock(&fidvid_mutex);
 +
 +	powernow_k8_acpi_pst_values(data, newstate);
 +
 +	if (cpu_family == CPU_HW_PSTATE)
 +		ret = transition_frequency_pstate(data, newstate);
 +	else
 +		ret = transition_frequency_fidvid(data, newstate);
 +	if (ret) {
 +		printk(KERN_ERR PFX "transition frequency failed\n");
 +		ret = 1;
 +		mutex_unlock(&fidvid_mutex);
 +		goto err_out;
 +	}
 +	mutex_unlock(&fidvid_mutex);
 +
 +	if (cpu_family == CPU_HW_PSTATE)
 +		pol->cur = find_khz_freq_from_fiddid(data->currfid, data->currdid);
 +	else
 +		pol->cur = find_khz_freq_from_fid(data->currfid);
 +	ret = 0;
 +
 +err_out:
 +	set_cpus_allowed(current, oldmask);
 +	return ret;
 +}
 +
 +/* Driver entry point to verify the policy and range of frequencies */
 +static int powernowk8_verify(struct cpufreq_policy *pol)
 +{
 +	struct powernow_k8_data *data = powernow_data[pol->cpu];
 +
 +	if (!data)
 +		return -EINVAL;
 +
 +	return cpufreq_frequency_table_verify(pol, data->powernow_table);
 +}
 +
 +/* per CPU init entry point to the driver */
 +static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
 +{
 +	struct powernow_k8_data *data;
 +	cpumask_t oldmask = CPU_MASK_ALL;
 +	int rc;
 +
 +	if (!cpu_online(pol->cpu))
 +		return -ENODEV;
 +
 +	if (!check_supported_cpu(pol->cpu))
 +		return -ENODEV;
 +
 +	data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL);
 +	if (!data) {
 +		printk(KERN_ERR PFX "unable to alloc powernow_k8_data");
 +		return -ENOMEM;
 +	}
 +
 +	data->cpu = pol->cpu;
 +
 +	if (powernow_k8_cpu_init_acpi(data)) {
 +		/*
 +		 * Use the PSB BIOS structure. This is only availabe on
 +		 * an UP version, and is deprecated by AMD.
 +		 */
 +		if (num_online_cpus() != 1) {
 +			printk(KERN_ERR PFX "MP systems not supported by PSB BIOS structure\n");
 +			kfree(data);
 +			return -ENODEV;
 +		}
 +		if (pol->cpu != 0) {
 +			printk(KERN_ERR PFX "No _PSS objects for CPU other than CPU0\n");
 +			kfree(data);
 +			return -ENODEV;
 +		}
 +		rc = find_psb_table(data);
 +		if (rc) {
 +			kfree(data);
 +			return -ENODEV;
 +		}
 +	}
 +
 +	/* only run on specific CPU from here on */
 +	oldmask = current->cpus_allowed;
 +	set_cpus_allowed(current, cpumask_of_cpu(pol->cpu));
 +
 +	if (smp_processor_id() != pol->cpu) {
 +		printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu);
 +		goto err_out;
 +	}
 +
 +	if (pending_bit_stuck()) {
 +		printk(KERN_ERR PFX "failing init, change pending bit set\n");
 +		goto err_out;
 +	}
 +
 +	if (query_current_values_with_pending_wait(data))
 +		goto err_out;
 +
 +	if (cpu_family == CPU_OPTERON)
 +		fidvid_msr_init();
 +
 +	/* run on any CPU again */
 +	set_cpus_allowed(current, oldmask);
 +
- 	pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	if (cpu_family == CPU_HW_PSTATE)
 +		pol->cpus = cpumask_of_cpu(pol->cpu);
 +	else
 +		pol->cpus = cpu_core_map[pol->cpu];
 +	data->available_cores = &(pol->cpus);
 +
 +	/* Take a crude guess here.
 +	 * That guess was in microseconds, so multiply with 1000 */
 +	pol->cpuinfo.transition_latency = (((data->rvo + 8) * data->vstable * VST_UNITS_20US)
 +	    + (3 * (1 << data->irt) * 10)) * 1000;
 +
 +	if (cpu_family == CPU_HW_PSTATE)
 +		pol->cur = find_khz_freq_from_fiddid(data->currfid, data->currdid);
 +	else
 +		pol->cur = find_khz_freq_from_fid(data->currfid);
 +	dprintk("policy current frequency %d kHz\n", pol->cur);
 +
 +	/* min/max the cpu is capable of */
 +	if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
 +		printk(KERN_ERR PFX "invalid powernow_table\n");
 +		powernow_k8_cpu_exit_acpi(data);
 +		kfree(data->powernow_table);
 +		kfree(data);
 +		return -EINVAL;
 +	}
 +
 +	cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
 +
 +	if (cpu_family == CPU_HW_PSTATE)
 +		dprintk("cpu_init done, current fid 0x%x, did 0x%x\n",
 +			data->currfid, data->currdid);
 +	else
 +		dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
 +			data->currfid, data->currvid);
 +
 +	powernow_data[pol->cpu] = data;
 +
 +	return 0;
 +
 +err_out:
 +	set_cpus_allowed(current, oldmask);
 +	powernow_k8_cpu_exit_acpi(data);
 +
 +	kfree(data);
 +	return -ENODEV;
 +}
 +
 +static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
 +{
 +	struct powernow_k8_data *data = powernow_data[pol->cpu];
 +
 +	if (!data)
 +		return -EINVAL;
 +
 +	powernow_k8_cpu_exit_acpi(data);
 +
 +	cpufreq_frequency_table_put_attr(pol->cpu);
 +
 +	kfree(data->powernow_table);
 +	kfree(data);
 +
 +	return 0;
 +}
 +
 +static unsigned int powernowk8_get (unsigned int cpu)
 +{
 +	struct powernow_k8_data *data;
 +	cpumask_t oldmask = current->cpus_allowed;
 +	unsigned int khz = 0;
 +
 +	data = powernow_data[first_cpu(cpu_core_map[cpu])];
 +
 +	if (!data)
 +		return -EINVAL;
 +
 +	set_cpus_allowed(current, cpumask_of_cpu(cpu));
 +	if (smp_processor_id() != cpu) {
 +		printk(KERN_ERR PFX "limiting to CPU %d failed in powernowk8_get\n", cpu);
 +		set_cpus_allowed(current, oldmask);
 +		return 0;
 +	}
 +
 +	if (query_current_values_with_pending_wait(data))
 +		goto out;
 +
 +	if (cpu_family == CPU_HW_PSTATE)
 +		khz = find_khz_freq_from_fiddid(data->currfid, data->currdid);
 +	else
 +		khz = find_khz_freq_from_fid(data->currfid);
 +
 +
 +out:
 +	set_cpus_allowed(current, oldmask);
 +	return khz;
 +}
 +
 +static struct freq_attr* powernow_k8_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver cpufreq_amd64_driver = {
 +	.verify = powernowk8_verify,
 +	.target = powernowk8_target,
 +	.init = powernowk8_cpu_init,
 +	.exit = __devexit_p(powernowk8_cpu_exit),
 +	.get = powernowk8_get,
 +	.name = "powernow-k8",
 +	.owner = THIS_MODULE,
 +	.attr = powernow_k8_attr,
 +};
 +
 +/* driver entry point for init */
 +static int __cpuinit powernowk8_init(void)
 +{
 +	unsigned int i, supported_cpus = 0;
- 	unsigned int booted_cores = 1;
 +
 +	for_each_online_cpu(i) {
 +		if (check_supported_cpu(i))
 +			supported_cpus++;
 +	}
 +
- #ifdef CONFIG_SMP
- 	booted_cores = cpu_data[0].booted_cores;
- #endif
- 
 +	if (supported_cpus == num_online_cpus()) {
 +		printk(KERN_INFO PFX "Found %d %s "
 +			"processors (%d cpu cores) (" VERSION ")\n",
- 			supported_cpus/booted_cores,
++			num_online_nodes(),
 +			boot_cpu_data.x86_model_id, supported_cpus);
 +		return cpufreq_register_driver(&cpufreq_amd64_driver);
 +	}
 +
 +	return -ENODEV;
 +}
 +
 +/* driver entry point for term */
 +static void __exit powernowk8_exit(void)
 +{
 +	dprintk("exit\n");
 +
 +	cpufreq_unregister_driver(&cpufreq_amd64_driver);
 +}
 +
 +MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and Mark Langsdorf <mark.langsdorf@amd.com>");
 +MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
 +MODULE_LICENSE("GPL");
 +
 +late_initcall(powernowk8_init);
 +module_exit(powernowk8_exit);
diff --cc arch/x86/kernel/cpu/cpufreq/sc520_freq.c
index b8fb4b521c62,000000000000..d9f3e90a7ae0
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
+++ b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
@@@ -1,191 -1,0 +1,190 @@@
 +/*
 + *	sc520_freq.c: cpufreq driver for the AMD Elan sc520
 + *
 + *	Copyright (C) 2005 Sean Young <sean@mess.org>
 + *
 + *	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 the Free Software Foundation; either version
 + *	2 of the License, or (at your option) any later version.
 + *
 + *	Based on elanfreq.c
 + *
 + *	2005-03-30: - initial revision
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +
 +#include <linux/delay.h>
 +#include <linux/cpufreq.h>
 +
 +#include <asm/msr.h>
 +#include <asm/timex.h>
 +#include <asm/io.h>
 +
 +#define MMCR_BASE	0xfffef000	/* The default base address */
 +#define OFFS_CPUCTL	0x2   /* CPU Control Register */
 +
 +static __u8 __iomem *cpuctl;
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "sc520_freq", msg)
 +
 +static struct cpufreq_frequency_table sc520_freq_table[] = {
 +	{0x01,	100000},
 +	{0x02,	133000},
 +	{0,	CPUFREQ_TABLE_END},
 +};
 +
 +static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
 +{
 +	u8 clockspeed_reg = *cpuctl;
 +
 +	switch (clockspeed_reg & 0x03) {
 +	default:
 +		printk(KERN_ERR "sc520_freq: error: cpuctl register has unexpected value %02x\n", clockspeed_reg);
 +	case 0x01:
 +		return 100000;
 +	case 0x02:
 +		return 133000;
 +	}
 +}
 +
 +static void sc520_freq_set_cpu_state (unsigned int state)
 +{
 +
 +	struct cpufreq_freqs	freqs;
 +	u8 clockspeed_reg;
 +
 +	freqs.old = sc520_freq_get_cpu_frequency(0);
 +	freqs.new = sc520_freq_table[state].frequency;
 +	freqs.cpu = 0; /* AMD Elan is UP */
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +
 +	dprintk("attempting to set frequency to %i kHz\n",
 +			sc520_freq_table[state].frequency);
 +
 +	local_irq_disable();
 +
 +	clockspeed_reg = *cpuctl & ~0x03;
 +	*cpuctl = clockspeed_reg | sc520_freq_table[state].index;
 +
 +	local_irq_enable();
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +};
 +
 +static int sc520_freq_verify (struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]);
 +}
 +
 +static int sc520_freq_target (struct cpufreq_policy *policy,
 +			    unsigned int target_freq,
 +			    unsigned int relation)
 +{
 +	unsigned int newstate = 0;
 +
 +	if (cpufreq_frequency_table_target(policy, sc520_freq_table, target_freq, relation, &newstate))
 +		return -EINVAL;
 +
 +	sc520_freq_set_cpu_state(newstate);
 +
 +	return 0;
 +}
 +
 +
 +/*
 + *	Module init and exit code
 + */
 +
 +static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +	int result;
 +
 +	/* capability check */
 +	if (c->x86_vendor != X86_VENDOR_AMD ||
 +	    c->x86 != 4 || c->x86_model != 9)
 +		return -ENODEV;
 +
 +	/* cpuinfo and default policy values */
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.transition_latency = 1000000; /* 1ms */
 +	policy->cur = sc520_freq_get_cpu_frequency(0);
 +
 +	result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table);
 +	if (result)
 +		return (result);
 +
 +	cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu);
 +
 +	return 0;
 +}
 +
 +
 +static int sc520_freq_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +	return 0;
 +}
 +
 +
 +static struct freq_attr* sc520_freq_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +
 +static struct cpufreq_driver sc520_freq_driver = {
 +	.get	= sc520_freq_get_cpu_frequency,
 +	.verify	= sc520_freq_verify,
 +	.target	= sc520_freq_target,
 +	.init	= sc520_freq_cpu_init,
 +	.exit	= sc520_freq_cpu_exit,
 +	.name	= "sc520_freq",
 +	.owner	= THIS_MODULE,
 +	.attr	= sc520_freq_attr,
 +};
 +
 +
 +static int __init sc520_freq_init(void)
 +{
 +	struct cpuinfo_x86 *c = cpu_data;
 +	int err;
 +
 +	/* Test if we have the right hardware */
 +	if(c->x86_vendor != X86_VENDOR_AMD ||
 +				c->x86 != 4 || c->x86_model != 9) {
 +		dprintk("no Elan SC520 processor found!\n");
 +		return -ENODEV;
 +	}
 +	cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
 +	if(!cpuctl) {
 +		printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
 +		return -ENOMEM;
 +	}
 +
 +	err = cpufreq_register_driver(&sc520_freq_driver);
 +	if (err)
 +		iounmap(cpuctl);
 +
 +	return err;
 +}
 +
 +
 +static void __exit sc520_freq_exit(void)
 +{
 +	cpufreq_unregister_driver(&sc520_freq_driver);
 +	iounmap(cpuctl);
 +}
 +
 +
 +MODULE_LICENSE("GPL");
 +MODULE_AUTHOR("Sean Young <sean@mess.org>");
 +MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU");
 +
 +module_init(sc520_freq_init);
 +module_exit(sc520_freq_exit);
 +
diff --cc arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
index 6c5dc2c85aeb,000000000000..811d47438546
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
@@@ -1,634 -1,0 +1,633 @@@
 +/*
 + * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium
 + * M (part of the Centrino chipset).
 + *
 + * Since the original Pentium M, most new Intel CPUs support Enhanced
 + * SpeedStep.
 + *
 + * Despite the "SpeedStep" in the name, this is almost entirely unlike
 + * traditional SpeedStep.
 + *
 + * Modelled on speedstep.c
 + *
 + * Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org>
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/sched.h>	/* current */
 +#include <linux/delay.h>
 +#include <linux/compiler.h>
 +
 +#include <asm/msr.h>
 +#include <asm/processor.h>
 +#include <asm/cpufeature.h>
 +
 +#define PFX		"speedstep-centrino: "
 +#define MAINTAINER	"cpufreq@lists.linux.org.uk"
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg)
 +
 +#define INTEL_MSR_RANGE	(0xffff)
 +
 +struct cpu_id
 +{
 +	__u8	x86;            /* CPU family */
 +	__u8	x86_model;	/* model */
 +	__u8	x86_mask;	/* stepping */
 +};
 +
 +enum {
 +	CPU_BANIAS,
 +	CPU_DOTHAN_A1,
 +	CPU_DOTHAN_A2,
 +	CPU_DOTHAN_B0,
 +	CPU_MP4HT_D0,
 +	CPU_MP4HT_E0,
 +};
 +
 +static const struct cpu_id cpu_ids[] = {
 +	[CPU_BANIAS]	= { 6,  9, 5 },
 +	[CPU_DOTHAN_A1]	= { 6, 13, 1 },
 +	[CPU_DOTHAN_A2]	= { 6, 13, 2 },
 +	[CPU_DOTHAN_B0]	= { 6, 13, 6 },
 +	[CPU_MP4HT_D0]	= {15,  3, 4 },
 +	[CPU_MP4HT_E0]	= {15,  4, 1 },
 +};
 +#define N_IDS	ARRAY_SIZE(cpu_ids)
 +
 +struct cpu_model
 +{
 +	const struct cpu_id *cpu_id;
 +	const char	*model_name;
 +	unsigned	max_freq; /* max clock in kHz */
 +
 +	struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */
 +};
 +static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x);
 +
 +/* Operating points for current CPU */
 +static struct cpu_model *centrino_model[NR_CPUS];
 +static const struct cpu_id *centrino_cpu[NR_CPUS];
 +
 +static struct cpufreq_driver centrino_driver;
 +
 +#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE
 +
 +/* Computes the correct form for IA32_PERF_CTL MSR for a particular
 +   frequency/voltage operating point; frequency in MHz, volts in mV.
 +   This is stored as "index" in the structure. */
 +#define OP(mhz, mv)							\
 +	{								\
 +		.frequency = (mhz) * 1000,				\
 +		.index = (((mhz)/100) << 8) | ((mv - 700) / 16)		\
 +	}
 +
 +/*
 + * These voltage tables were derived from the Intel Pentium M
 + * datasheet, document 25261202.pdf, Table 5.  I have verified they
 + * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium
 + * M.
 + */
 +
 +/* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */
 +static struct cpufreq_frequency_table banias_900[] =
 +{
 +	OP(600,  844),
 +	OP(800,  988),
 +	OP(900, 1004),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +
 +/* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */
 +static struct cpufreq_frequency_table banias_1000[] =
 +{
 +	OP(600,   844),
 +	OP(800,   972),
 +	OP(900,   988),
 +	OP(1000, 1004),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +
 +/* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */
 +static struct cpufreq_frequency_table banias_1100[] =
 +{
 +	OP( 600,  956),
 +	OP( 800, 1020),
 +	OP( 900, 1100),
 +	OP(1000, 1164),
 +	OP(1100, 1180),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +
 +
 +/* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */
 +static struct cpufreq_frequency_table banias_1200[] =
 +{
 +	OP( 600,  956),
 +	OP( 800, 1004),
 +	OP( 900, 1020),
 +	OP(1000, 1100),
 +	OP(1100, 1164),
 +	OP(1200, 1180),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +
 +/* Intel Pentium M processor 1.30GHz (Banias) */
 +static struct cpufreq_frequency_table banias_1300[] =
 +{
 +	OP( 600,  956),
 +	OP( 800, 1260),
 +	OP(1000, 1292),
 +	OP(1200, 1356),
 +	OP(1300, 1388),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +
 +/* Intel Pentium M processor 1.40GHz (Banias) */
 +static struct cpufreq_frequency_table banias_1400[] =
 +{
 +	OP( 600,  956),
 +	OP( 800, 1180),
 +	OP(1000, 1308),
 +	OP(1200, 1436),
 +	OP(1400, 1484),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +
 +/* Intel Pentium M processor 1.50GHz (Banias) */
 +static struct cpufreq_frequency_table banias_1500[] =
 +{
 +	OP( 600,  956),
 +	OP( 800, 1116),
 +	OP(1000, 1228),
 +	OP(1200, 1356),
 +	OP(1400, 1452),
 +	OP(1500, 1484),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +
 +/* Intel Pentium M processor 1.60GHz (Banias) */
 +static struct cpufreq_frequency_table banias_1600[] =
 +{
 +	OP( 600,  956),
 +	OP( 800, 1036),
 +	OP(1000, 1164),
 +	OP(1200, 1276),
 +	OP(1400, 1420),
 +	OP(1600, 1484),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +
 +/* Intel Pentium M processor 1.70GHz (Banias) */
 +static struct cpufreq_frequency_table banias_1700[] =
 +{
 +	OP( 600,  956),
 +	OP( 800, 1004),
 +	OP(1000, 1116),
 +	OP(1200, 1228),
 +	OP(1400, 1308),
 +	OP(1700, 1484),
 +	{ .frequency = CPUFREQ_TABLE_END }
 +};
 +#undef OP
 +
 +#define _BANIAS(cpuid, max, name)	\
 +{	.cpu_id		= cpuid,	\
 +	.model_name	= "Intel(R) Pentium(R) M processor " name "MHz", \
 +	.max_freq	= (max)*1000,	\
 +	.op_points	= banias_##max,	\
 +}
 +#define BANIAS(max)	_BANIAS(&cpu_ids[CPU_BANIAS], max, #max)
 +
 +/* CPU models, their operating frequency range, and freq/voltage
 +   operating points */
 +static struct cpu_model models[] =
 +{
 +	_BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"),
 +	BANIAS(1000),
 +	BANIAS(1100),
 +	BANIAS(1200),
 +	BANIAS(1300),
 +	BANIAS(1400),
 +	BANIAS(1500),
 +	BANIAS(1600),
 +	BANIAS(1700),
 +
 +	/* NULL model_name is a wildcard */
 +	{ &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL },
 +	{ &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL },
 +	{ &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL },
 +	{ &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL },
 +	{ &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL },
 +
 +	{ NULL, }
 +};
 +#undef _BANIAS
 +#undef BANIAS
 +
 +static int centrino_cpu_init_table(struct cpufreq_policy *policy)
 +{
 +	struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu];
 +	struct cpu_model *model;
 +
 +	for(model = models; model->cpu_id != NULL; model++)
 +		if (centrino_verify_cpu_id(cpu, model->cpu_id) &&
 +		    (model->model_name == NULL ||
 +		     strcmp(cpu->x86_model_id, model->model_name) == 0))
 +			break;
 +
 +	if (model->cpu_id == NULL) {
 +		/* No match at all */
 +		dprintk("no support for CPU model \"%s\": "
 +		       "send /proc/cpuinfo to " MAINTAINER "\n",
 +		       cpu->x86_model_id);
 +		return -ENOENT;
 +	}
 +
 +	if (model->op_points == NULL) {
 +		/* Matched a non-match */
 +		dprintk("no table support for CPU model \"%s\"\n",
 +		       cpu->x86_model_id);
 +		dprintk("try using the acpi-cpufreq driver\n");
 +		return -ENOENT;
 +	}
 +
 +	centrino_model[policy->cpu] = model;
 +
 +	dprintk("found \"%s\": max frequency: %dkHz\n",
 +	       model->model_name, model->max_freq);
 +
 +	return 0;
 +}
 +
 +#else
 +static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; }
 +#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */
 +
 +static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x)
 +{
 +	if ((c->x86 == x->x86) &&
 +	    (c->x86_model == x->x86_model) &&
 +	    (c->x86_mask == x->x86_mask))
 +		return 1;
 +	return 0;
 +}
 +
 +/* To be called only after centrino_model is initialized */
 +static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe)
 +{
 +	int i;
 +
 +	/*
 +	 * Extract clock in kHz from PERF_CTL value
 +	 * for centrino, as some DSDTs are buggy.
 +	 * Ideally, this can be done using the acpi_data structure.
 +	 */
 +	if ((centrino_cpu[cpu] == &cpu_ids[CPU_BANIAS]) ||
 +	    (centrino_cpu[cpu] == &cpu_ids[CPU_DOTHAN_A1]) ||
 +	    (centrino_cpu[cpu] == &cpu_ids[CPU_DOTHAN_B0])) {
 +		msr = (msr >> 8) & 0xff;
 +		return msr * 100000;
 +	}
 +
 +	if ((!centrino_model[cpu]) || (!centrino_model[cpu]->op_points))
 +		return 0;
 +
 +	msr &= 0xffff;
 +	for (i=0;centrino_model[cpu]->op_points[i].frequency != CPUFREQ_TABLE_END; i++) {
 +		if (msr == centrino_model[cpu]->op_points[i].index)
 +			return centrino_model[cpu]->op_points[i].frequency;
 +	}
 +	if (failsafe)
 +		return centrino_model[cpu]->op_points[i-1].frequency;
 +	else
 +		return 0;
 +}
 +
 +/* Return the current CPU frequency in kHz */
 +static unsigned int get_cur_freq(unsigned int cpu)
 +{
 +	unsigned l, h;
 +	unsigned clock_freq;
 +	cpumask_t saved_mask;
 +
 +	saved_mask = current->cpus_allowed;
 +	set_cpus_allowed(current, cpumask_of_cpu(cpu));
 +	if (smp_processor_id() != cpu)
 +		return 0;
 +
 +	rdmsr(MSR_IA32_PERF_STATUS, l, h);
 +	clock_freq = extract_clock(l, cpu, 0);
 +
 +	if (unlikely(clock_freq == 0)) {
 +		/*
 +		 * On some CPUs, we can see transient MSR values (which are
 +		 * not present in _PSS), while CPU is doing some automatic
 +		 * P-state transition (like TM2). Get the last freq set 
 +		 * in PERF_CTL.
 +		 */
 +		rdmsr(MSR_IA32_PERF_CTL, l, h);
 +		clock_freq = extract_clock(l, cpu, 1);
 +	}
 +
 +	set_cpus_allowed(current, saved_mask);
 +	return clock_freq;
 +}
 +
 +
 +static int centrino_cpu_init(struct cpufreq_policy *policy)
 +{
 +	struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu];
 +	unsigned freq;
 +	unsigned l, h;
 +	int ret;
 +	int i;
 +
 +	/* Only Intel makes Enhanced Speedstep-capable CPUs */
 +	if (cpu->x86_vendor != X86_VENDOR_INTEL || !cpu_has(cpu, X86_FEATURE_EST))
 +		return -ENODEV;
 +
 +	if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC))
 +		centrino_driver.flags |= CPUFREQ_CONST_LOOPS;
 +
 +	if (policy->cpu != 0)
 +		return -ENODEV;
 +
 +	for (i = 0; i < N_IDS; i++)
 +		if (centrino_verify_cpu_id(cpu, &cpu_ids[i]))
 +			break;
 +
 +	if (i != N_IDS)
 +		centrino_cpu[policy->cpu] = &cpu_ids[i];
 +
 +	if (!centrino_cpu[policy->cpu]) {
 +		dprintk("found unsupported CPU with "
 +		"Enhanced SpeedStep: send /proc/cpuinfo to "
 +		MAINTAINER "\n");
 +		return -ENODEV;
 +	}
 +
 +	if (centrino_cpu_init_table(policy)) {
 +		return -ENODEV;
 +	}
 +
 +	/* Check to see if Enhanced SpeedStep is enabled, and try to
 +	   enable it if not. */
 +	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
 +
 +	if (!(l & (1<<16))) {
 +		l |= (1<<16);
 +		dprintk("trying to enable Enhanced SpeedStep (%x)\n", l);
 +		wrmsr(MSR_IA32_MISC_ENABLE, l, h);
 +
 +		/* check to see if it stuck */
 +		rdmsr(MSR_IA32_MISC_ENABLE, l, h);
 +		if (!(l & (1<<16))) {
 +			printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n");
 +			return -ENODEV;
 +		}
 +	}
 +
 +	freq = get_cur_freq(policy->cpu);
 +
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
 +	policy->cur = freq;
 +
 +	dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur);
 +
 +	ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model[policy->cpu]->op_points);
 +	if (ret)
 +		return (ret);
 +
 +	cpufreq_frequency_table_get_attr(centrino_model[policy->cpu]->op_points, policy->cpu);
 +
 +	return 0;
 +}
 +
 +static int centrino_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	unsigned int cpu = policy->cpu;
 +
 +	if (!centrino_model[cpu])
 +		return -ENODEV;
 +
 +	cpufreq_frequency_table_put_attr(cpu);
 +
 +	centrino_model[cpu] = NULL;
 +
 +	return 0;
 +}
 +
 +/**
 + * centrino_verify - verifies a new CPUFreq policy
 + * @policy: new policy
 + *
 + * Limit must be within this model's frequency range at least one
 + * border included.
 + */
 +static int centrino_verify (struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, centrino_model[policy->cpu]->op_points);
 +}
 +
 +/**
 + * centrino_setpolicy - set a new CPUFreq policy
 + * @policy: new policy
 + * @target_freq: the target frequency
 + * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
 + *
 + * Sets a new CPUFreq policy.
 + */
 +static int centrino_target (struct cpufreq_policy *policy,
 +			    unsigned int target_freq,
 +			    unsigned int relation)
 +{
 +	unsigned int    newstate = 0;
 +	unsigned int	msr, oldmsr = 0, h = 0, cpu = policy->cpu;
 +	struct cpufreq_freqs	freqs;
 +	cpumask_t		online_policy_cpus;
 +	cpumask_t		saved_mask;
 +	cpumask_t		set_mask;
 +	cpumask_t		covered_cpus;
 +	int			retval = 0;
 +	unsigned int		j, k, first_cpu, tmp;
 +
 +	if (unlikely(centrino_model[cpu] == NULL))
 +		return -ENODEV;
 +
 +	if (unlikely(cpufreq_frequency_table_target(policy,
 +			centrino_model[cpu]->op_points,
 +			target_freq,
 +			relation,
 +			&newstate))) {
 +		return -EINVAL;
 +	}
 +
 +#ifdef CONFIG_HOTPLUG_CPU
 +	/* cpufreq holds the hotplug lock, so we are safe from here on */
 +	cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
 +#else
 +	online_policy_cpus = policy->cpus;
 +#endif
 +
 +	saved_mask = current->cpus_allowed;
 +	first_cpu = 1;
 +	cpus_clear(covered_cpus);
 +	for_each_cpu_mask(j, online_policy_cpus) {
 +		/*
 +		 * Support for SMP systems.
 +		 * Make sure we are running on CPU that wants to change freq
 +		 */
 +		cpus_clear(set_mask);
 +		if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
 +			cpus_or(set_mask, set_mask, online_policy_cpus);
 +		else
 +			cpu_set(j, set_mask);
 +
 +		set_cpus_allowed(current, set_mask);
 +		preempt_disable();
 +		if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
 +			dprintk("couldn't limit to CPUs in this domain\n");
 +			retval = -EAGAIN;
 +			if (first_cpu) {
 +				/* We haven't started the transition yet. */
 +				goto migrate_end;
 +			}
 +			preempt_enable();
 +			break;
 +		}
 +
 +		msr = centrino_model[cpu]->op_points[newstate].index;
 +
 +		if (first_cpu) {
 +			rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
 +			if (msr == (oldmsr & 0xffff)) {
 +				dprintk("no change needed - msr was and needs "
 +					"to be %x\n", oldmsr);
 +				retval = 0;
 +				goto migrate_end;
 +			}
 +
 +			freqs.old = extract_clock(oldmsr, cpu, 0);
 +			freqs.new = extract_clock(msr, cpu, 0);
 +
 +			dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
 +				target_freq, freqs.old, freqs.new, msr);
 +
 +			for_each_cpu_mask(k, online_policy_cpus) {
 +				freqs.cpu = k;
 +				cpufreq_notify_transition(&freqs,
 +					CPUFREQ_PRECHANGE);
 +			}
 +
 +			first_cpu = 0;
 +			/* all but 16 LSB are reserved, treat them with care */
 +			oldmsr &= ~0xffff;
 +			msr &= 0xffff;
 +			oldmsr |= msr;
 +		}
 +
 +		wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
 +		if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
 +			preempt_enable();
 +			break;
 +		}
 +
 +		cpu_set(j, covered_cpus);
 +		preempt_enable();
 +	}
 +
 +	for_each_cpu_mask(k, online_policy_cpus) {
 +		freqs.cpu = k;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +	}
 +
 +	if (unlikely(retval)) {
 +		/*
 +		 * We have failed halfway through the frequency change.
 +		 * We have sent callbacks to policy->cpus and
 +		 * MSRs have already been written on coverd_cpus.
 +		 * Best effort undo..
 +		 */
 +
 +		if (!cpus_empty(covered_cpus)) {
 +			for_each_cpu_mask(j, covered_cpus) {
 +				set_cpus_allowed(current, cpumask_of_cpu(j));
 +				wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
 +			}
 +		}
 +
 +		tmp = freqs.new;
 +		freqs.new = freqs.old;
 +		freqs.old = tmp;
 +		for_each_cpu_mask(j, online_policy_cpus) {
 +			freqs.cpu = j;
 +			cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +			cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +		}
 +	}
 +	set_cpus_allowed(current, saved_mask);
 +	return 0;
 +
 +migrate_end:
 +	preempt_enable();
 +	set_cpus_allowed(current, saved_mask);
 +	return 0;
 +}
 +
 +static struct freq_attr* centrino_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver centrino_driver = {
 +	.name		= "centrino", /* should be speedstep-centrino,
 +					 but there's a 16 char limit */
 +	.init		= centrino_cpu_init,
 +	.exit		= centrino_cpu_exit,
 +	.verify		= centrino_verify,
 +	.target		= centrino_target,
 +	.get		= get_cur_freq,
 +	.attr           = centrino_attr,
 +	.owner		= THIS_MODULE,
 +};
 +
 +
 +/**
 + * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver
 + *
 + * Initializes the Enhanced SpeedStep support. Returns -ENODEV on
 + * unsupported devices, -ENOENT if there's no voltage table for this
 + * particular CPU model, -EINVAL on problems during initiatization,
 + * and zero on success.
 + *
 + * This is quite picky.  Not only does the CPU have to advertise the
 + * "est" flag in the cpuid capability flags, we look for a specific
 + * CPU model and stepping, and we need to have the exact model name in
 + * our voltage tables.  That is, be paranoid about not releasing
 + * someone's valuable magic smoke.
 + */
 +static int __init centrino_init(void)
 +{
 +	struct cpuinfo_x86 *cpu = cpu_data;
 +
 +	if (!cpu_has(cpu, X86_FEATURE_EST))
 +		return -ENODEV;
 +
 +	return cpufreq_register_driver(&centrino_driver);
 +}
 +
 +static void __exit centrino_exit(void)
 +{
 +	cpufreq_unregister_driver(&centrino_driver);
 +}
 +
 +MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
 +MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors.");
 +MODULE_LICENSE ("GPL");
 +
 +late_initcall(centrino_init);
 +module_exit(centrino_exit);
diff --cc arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
index a5b2346faf1f,000000000000..36685e8f7be1
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
@@@ -1,440 -1,0 +1,439 @@@
 +/*
 + * (C) 2001  Dave Jones, Arjan van de ven.
 + * (C) 2002 - 2003  Dominik Brodowski <linux@brodo.de>
 + *
 + *  Licensed under the terms of the GNU GPL License version 2.
 + *  Based upon reverse engineered information, and on Intel documentation
 + *  for chipsets ICH2-M and ICH3-M.
 + *
 + *  Many thanks to Ducrot Bruno for finding and fixing the last
 + *  "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler
 + *  for extensive testing.
 + *
 + *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
 + */
 +
 +
 +/*********************************************************************
 + *                        SPEEDSTEP - DEFINITIONS                    *
 + *********************************************************************/
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/pci.h>
 +#include <linux/slab.h>
 +#include <linux/sched.h>
 +
 +#include "speedstep-lib.h"
 +
 +
 +/* speedstep_chipset:
 + *   It is necessary to know which chipset is used. As accesses to
 + * this device occur at various places in this module, we need a
 + * static struct pci_dev * pointing to that device.
 + */
 +static struct pci_dev *speedstep_chipset_dev;
 +
 +
 +/* speedstep_processor
 + */
 +static unsigned int speedstep_processor = 0;
 +
 +static u32 pmbase;
 +
 +/*
 + *   There are only two frequency states for each processor. Values
 + * are in kHz for the time being.
 + */
 +static struct cpufreq_frequency_table speedstep_freqs[] = {
 +	{SPEEDSTEP_HIGH,	0},
 +	{SPEEDSTEP_LOW,		0},
 +	{0,			CPUFREQ_TABLE_END},
 +};
 +
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-ich", msg)
 +
 +
 +/**
 + * speedstep_find_register - read the PMBASE address
 + *
 + * Returns: -ENODEV if no register could be found
 + */
 +static int speedstep_find_register (void)
 +{
 +	if (!speedstep_chipset_dev)
 +		return -ENODEV;
 +
 +	/* get PMBASE */
 +	pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
 +	if (!(pmbase & 0x01)) {
 +		printk(KERN_ERR "speedstep-ich: could not find speedstep register\n");
 +		return -ENODEV;
 +	}
 +
 +	pmbase &= 0xFFFFFFFE;
 +	if (!pmbase) {
 +		printk(KERN_ERR "speedstep-ich: could not find speedstep register\n");
 +		return -ENODEV;
 +	}
 +
 +	dprintk("pmbase is 0x%x\n", pmbase);
 +	return 0;
 +}
 +
 +/**
 + * speedstep_set_state - set the SpeedStep state
 + * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
 + *
 + *   Tries to change the SpeedStep state.
 + */
 +static void speedstep_set_state (unsigned int state)
 +{
 +	u8 pm2_blk;
 +	u8 value;
 +	unsigned long flags;
 +
 +	if (state > 0x1)
 +		return;
 +
 +	/* Disable IRQs */
 +	local_irq_save(flags);
 +
 +	/* read state */
 +	value = inb(pmbase + 0x50);
 +
 +	dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
 +
 +	/* write new state */
 +	value &= 0xFE;
 +	value |= state;
 +
 +	dprintk("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
 +
 +	/* Disable bus master arbitration */
 +	pm2_blk = inb(pmbase + 0x20);
 +	pm2_blk |= 0x01;
 +	outb(pm2_blk, (pmbase + 0x20));
 +
 +	/* Actual transition */
 +	outb(value, (pmbase + 0x50));
 +
 +	/* Restore bus master arbitration */
 +	pm2_blk &= 0xfe;
 +	outb(pm2_blk, (pmbase + 0x20));
 +
 +	/* check if transition was successful */
 +	value = inb(pmbase + 0x50);
 +
 +	/* Enable IRQs */
 +	local_irq_restore(flags);
 +
 +	dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
 +
 +	if (state == (value & 0x1)) {
 +		dprintk("change to %u MHz succeeded\n", (speedstep_get_processor_frequency(speedstep_processor) / 1000));
 +	} else {
 +		printk (KERN_ERR "cpufreq: change failed - I/O error\n");
 +	}
 +
 +	return;
 +}
 +
 +
 +/**
 + * speedstep_activate - activate SpeedStep control in the chipset
 + *
 + *   Tries to activate the SpeedStep status and control registers.
 + * Returns -EINVAL on an unsupported chipset, and zero on success.
 + */
 +static int speedstep_activate (void)
 +{
 +	u16 value = 0;
 +
 +	if (!speedstep_chipset_dev)
 +		return -EINVAL;
 +
 +	pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value);
 +	if (!(value & 0x08)) {
 +		value |= 0x08;
 +		dprintk("activating SpeedStep (TM) registers\n");
 +		pci_write_config_word(speedstep_chipset_dev, 0x00A0, value);
 +	}
 +
 +	return 0;
 +}
 +
 +
 +/**
 + * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic
 + *
 + *   Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to
 + * the LPC bridge / PM module which contains all power-management
 + * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
 + * chipset, or zero on failure.
 + */
 +static unsigned int speedstep_detect_chipset (void)
 +{
 +	speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
 +			      PCI_DEVICE_ID_INTEL_82801DB_12,
 +			      PCI_ANY_ID,
 +			      PCI_ANY_ID,
 +			      NULL);
 +	if (speedstep_chipset_dev)
 +		return 4; /* 4-M */
 +
 +	speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
 +			      PCI_DEVICE_ID_INTEL_82801CA_12,
 +			      PCI_ANY_ID,
 +			      PCI_ANY_ID,
 +			      NULL);
 +	if (speedstep_chipset_dev)
 +		return 3; /* 3-M */
 +
 +
 +	speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
 +			      PCI_DEVICE_ID_INTEL_82801BA_10,
 +			      PCI_ANY_ID,
 +			      PCI_ANY_ID,
 +			      NULL);
 +	if (speedstep_chipset_dev) {
 +		/* speedstep.c causes lockups on Dell Inspirons 8000 and
 +		 * 8100 which use a pretty old revision of the 82815
 +		 * host brige. Abort on these systems.
 +		 */
 +		static struct pci_dev *hostbridge;
 +
 +		hostbridge  = pci_get_subsys(PCI_VENDOR_ID_INTEL,
 +			      PCI_DEVICE_ID_INTEL_82815_MC,
 +			      PCI_ANY_ID,
 +			      PCI_ANY_ID,
 +			      NULL);
 +
 +		if (!hostbridge)
 +			return 2; /* 2-M */
 +
 +		if (hostbridge->revision < 5) {
 +			dprintk("hostbridge does not support speedstep\n");
 +			speedstep_chipset_dev = NULL;
 +			pci_dev_put(hostbridge);
 +			return 0;
 +		}
 +
 +		pci_dev_put(hostbridge);
 +		return 2; /* 2-M */
 +	}
 +
 +	return 0;
 +}
 +
 +static unsigned int _speedstep_get(cpumask_t cpus)
 +{
 +	unsigned int speed;
 +	cpumask_t cpus_allowed;
 +
 +	cpus_allowed = current->cpus_allowed;
 +	set_cpus_allowed(current, cpus);
 +	speed = speedstep_get_processor_frequency(speedstep_processor);
 +	set_cpus_allowed(current, cpus_allowed);
 +	dprintk("detected %u kHz as current frequency\n", speed);
 +	return speed;
 +}
 +
 +static unsigned int speedstep_get(unsigned int cpu)
 +{
 +	return _speedstep_get(cpumask_of_cpu(cpu));
 +}
 +
 +/**
 + * speedstep_target - set a new CPUFreq policy
 + * @policy: new policy
 + * @target_freq: the target frequency
 + * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
 + *
 + * Sets a new CPUFreq policy.
 + */
 +static int speedstep_target (struct cpufreq_policy *policy,
 +			     unsigned int target_freq,
 +			     unsigned int relation)
 +{
 +	unsigned int newstate = 0;
 +	struct cpufreq_freqs freqs;
 +	cpumask_t cpus_allowed;
 +	int i;
 +
 +	if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
 +		return -EINVAL;
 +
 +	freqs.old = _speedstep_get(policy->cpus);
 +	freqs.new = speedstep_freqs[newstate].frequency;
 +	freqs.cpu = policy->cpu;
 +
 +	dprintk("transiting from %u to %u kHz\n", freqs.old, freqs.new);
 +
 +	/* no transition necessary */
 +	if (freqs.old == freqs.new)
 +		return 0;
 +
 +	cpus_allowed = current->cpus_allowed;
 +
 +	for_each_cpu_mask(i, policy->cpus) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +	}
 +
 +	/* switch to physical CPU where state is to be changed */
 +	set_cpus_allowed(current, policy->cpus);
 +
 +	speedstep_set_state(newstate);
 +
 +	/* allow to be run on all CPUs */
 +	set_cpus_allowed(current, cpus_allowed);
 +
 +	for_each_cpu_mask(i, policy->cpus) {
 +		freqs.cpu = i;
 +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +	}
 +
 +	return 0;
 +}
 +
 +
 +/**
 + * speedstep_verify - verifies a new CPUFreq policy
 + * @policy: new policy
 + *
 + * Limit must be within speedstep_low_freq and speedstep_high_freq, with
 + * at least one border included.
 + */
 +static int speedstep_verify (struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
 +}
 +
 +
 +static int speedstep_cpu_init(struct cpufreq_policy *policy)
 +{
 +	int result = 0;
 +	unsigned int speed;
 +	cpumask_t cpus_allowed;
 +
 +	/* only run on CPU to be set, or on its sibling */
 +#ifdef CONFIG_SMP
 +	policy->cpus = cpu_sibling_map[policy->cpu];
 +#endif
 +
 +	cpus_allowed = current->cpus_allowed;
 +	set_cpus_allowed(current, policy->cpus);
 +
 +	/* detect low and high frequency and transition latency */
 +	result = speedstep_get_freqs(speedstep_processor,
 +				     &speedstep_freqs[SPEEDSTEP_LOW].frequency,
 +				     &speedstep_freqs[SPEEDSTEP_HIGH].frequency,
 +				     &policy->cpuinfo.transition_latency,
 +				     &speedstep_set_state);
 +	set_cpus_allowed(current, cpus_allowed);
 +	if (result)
 +		return result;
 +
 +	/* get current speed setting */
 +	speed = _speedstep_get(policy->cpus);
 +	if (!speed)
 +		return -EIO;
 +
 +	dprintk("currently at %s speed setting - %i MHz\n",
 +		(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
 +		(speed / 1000));
 +
 +	/* cpuinfo and default policy values */
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cur = speed;
 +
 +	result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
 +	if (result)
 +		return (result);
 +
 +        cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
 +
 +	return 0;
 +}
 +
 +
 +static int speedstep_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +	return 0;
 +}
 +
 +static struct freq_attr* speedstep_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +
 +static struct cpufreq_driver speedstep_driver = {
 +	.name	= "speedstep-ich",
 +	.verify	= speedstep_verify,
 +	.target	= speedstep_target,
 +	.init	= speedstep_cpu_init,
 +	.exit	= speedstep_cpu_exit,
 +	.get	= speedstep_get,
 +	.owner	= THIS_MODULE,
 +	.attr	= speedstep_attr,
 +};
 +
 +
 +/**
 + * speedstep_init - initializes the SpeedStep CPUFreq driver
 + *
 + *   Initializes the SpeedStep support. Returns -ENODEV on unsupported
 + * devices, -EINVAL on problems during initiatization, and zero on
 + * success.
 + */
 +static int __init speedstep_init(void)
 +{
 +	/* detect processor */
 +	speedstep_processor = speedstep_detect_processor();
 +	if (!speedstep_processor) {
 +		dprintk("Intel(R) SpeedStep(TM) capable processor not found\n");
 +		return -ENODEV;
 +	}
 +
 +	/* detect chipset */
 +	if (!speedstep_detect_chipset()) {
 +		dprintk("Intel(R) SpeedStep(TM) for this chipset not (yet) available.\n");
 +		return -ENODEV;
 +	}
 +
 +	/* activate speedstep support */
 +	if (speedstep_activate()) {
 +		pci_dev_put(speedstep_chipset_dev);
 +		return -EINVAL;
 +	}
 +
 +	if (speedstep_find_register())
 +		return -ENODEV;
 +
 +	return cpufreq_register_driver(&speedstep_driver);
 +}
 +
 +
 +/**
 + * speedstep_exit - unregisters SpeedStep support
 + *
 + *   Unregisters SpeedStep support.
 + */
 +static void __exit speedstep_exit(void)
 +{
 +	pci_dev_put(speedstep_chipset_dev);
 +	cpufreq_unregister_driver(&speedstep_driver);
 +}
 +
 +
 +MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>, Dominik Brodowski <linux@brodo.de>");
 +MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors on chipsets with ICH-M southbridges.");
 +MODULE_LICENSE ("GPL");
 +
 +module_init(speedstep_init);
 +module_exit(speedstep_exit);
diff --cc arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
index e1c509aa3054,000000000000..f2b5a621d27b
mode 100644,000000..100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
@@@ -1,424 -1,0 +1,423 @@@
 +/*
 + * Intel SpeedStep SMI driver.
 + *
 + * (C) 2003  Hiroshi Miura <miura@da-cha.org>
 + *
 + *  Licensed under the terms of the GNU GPL License version 2.
 + *
 + */
 +
 +
 +/*********************************************************************
 + *                        SPEEDSTEP - DEFINITIONS                    *
 + *********************************************************************/
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/moduleparam.h>
 +#include <linux/init.h>
 +#include <linux/cpufreq.h>
 +#include <linux/slab.h>
 +#include <linux/delay.h>
 +#include <asm/ist.h>
 +#include <asm/io.h>
 +
 +#include "speedstep-lib.h"
 +
 +/* speedstep system management interface port/command.
 + *
 + * These parameters are got from IST-SMI BIOS call.
 + * If user gives it, these are used.
 + *
 + */
 +static int smi_port = 0;
 +static int smi_cmd = 0;
 +static unsigned int smi_sig = 0;
 +
 +/* info about the processor */
 +static unsigned int speedstep_processor = 0;
 +
 +/*
 + * There are only two frequency states for each processor. Values
 + * are in kHz for the time being.
 + */
 +static struct cpufreq_frequency_table speedstep_freqs[] = {
 +	{SPEEDSTEP_HIGH,	0},
 +	{SPEEDSTEP_LOW,		0},
 +	{0,			CPUFREQ_TABLE_END},
 +};
 +
 +#define GET_SPEEDSTEP_OWNER 0
 +#define GET_SPEEDSTEP_STATE 1
 +#define SET_SPEEDSTEP_STATE 2
 +#define GET_SPEEDSTEP_FREQS 4
 +
 +/* how often shall the SMI call be tried if it failed, e.g. because
 + * of DMA activity going on? */
 +#define SMI_TRIES 5
 +
 +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-smi", msg)
 +
 +/**
 + * speedstep_smi_ownership
 + */
 +static int speedstep_smi_ownership (void)
 +{
 +	u32 command, result, magic;
 +	u32 function = GET_SPEEDSTEP_OWNER;
 +	unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation";
 +
 +	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 +	magic = virt_to_phys(magic_data);
 +
 +	dprintk("trying to obtain ownership with command %x at port %x\n", command, smi_port);
 +
 +	__asm__ __volatile__(
 +		"out %%al, (%%dx)\n"
 +		: "=D" (result)
 +		: "a" (command), "b" (function), "c" (0), "d" (smi_port),
 +			"D" (0), "S" (magic)
 +		: "memory"
 +	);
 +
 +	dprintk("result is %x\n", result);
 +
 +	return result;
 +}
 +
 +/**
 + * speedstep_smi_get_freqs - get SpeedStep preferred & current freq.
 + * @low: the low frequency value is placed here
 + * @high: the high frequency value is placed here
 + *
 + * Only available on later SpeedStep-enabled systems, returns false results or
 + * even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing
 + * shows that the latter occurs if !(ist_info.event & 0xFFFF).
 + */
 +static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
 +{
 +	u32 command, result = 0, edi, high_mhz, low_mhz;
 +	u32 state=0;
 +	u32 function = GET_SPEEDSTEP_FREQS;
 +
 +	if (!(ist_info.event & 0xFFFF)) {
 +		dprintk("bug #1422 -- can't read freqs from BIOS\n");
 +		return -ENODEV;
 +	}
 +
 +	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 +
 +	dprintk("trying to determine frequencies with command %x at port %x\n", command, smi_port);
 +
 +	__asm__ __volatile__("movl $0, %%edi\n"
 +		"out %%al, (%%dx)\n"
 +		: "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi)
 +		: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0)
 +	);
 +
 +	dprintk("result %x, low_freq %u, high_freq %u\n", result, low_mhz, high_mhz);
 +
 +	/* abort if results are obviously incorrect... */
 +	if ((high_mhz + low_mhz) < 600)
 +		return -EINVAL;
 +
 +	*high = high_mhz * 1000;
 +	*low  = low_mhz  * 1000;
 +
 +	return result;
 +}
 +
 +/**
 + * speedstep_get_state - set the SpeedStep state
 + * @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
 + *
 + */
 +static int speedstep_get_state (void)
 +{
 +	u32 function=GET_SPEEDSTEP_STATE;
 +	u32 result, state, edi, command;
 +
 +	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 +
 +	dprintk("trying to determine current setting with command %x at port %x\n", command, smi_port);
 +
 +	__asm__ __volatile__("movl $0, %%edi\n"
 +		"out %%al, (%%dx)\n"
 +		: "=a" (result), "=b" (state), "=D" (edi)
 +		: "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0)
 +	);
 +
 +	dprintk("state is %x, result is %x\n", state, result);
 +
 +	return (state & 1);
 +}
 +
 +
 +/**
 + * speedstep_set_state - set the SpeedStep state
 + * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
 + *
 + */
 +static void speedstep_set_state (unsigned int state)
 +{
 +	unsigned int result = 0, command, new_state;
 +	unsigned long flags;
 +	unsigned int function=SET_SPEEDSTEP_STATE;
 +	unsigned int retry = 0;
 +
 +	if (state > 0x1)
 +		return;
 +
 +	/* Disable IRQs */
 +	local_irq_save(flags);
 +
 +	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
 +
 +	dprintk("trying to set frequency to state %u with command %x at port %x\n", state, command, smi_port);
 +
 +	do {
 +		if (retry) {
 +			dprintk("retry %u, previous result %u, waiting...\n", retry, result);
 +			mdelay(retry * 50);
 +		}
 +		retry++;
 +		__asm__ __volatile__(
 +			"movl $0, %%edi\n"
 +			"out %%al, (%%dx)\n"
 +			: "=b" (new_state), "=D" (result)
 +			: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0)
 +			);
 +	} while ((new_state != state) && (retry <= SMI_TRIES));
 +
 +	/* enable IRQs */
 +	local_irq_restore(flags);
 +
 +	if (new_state == state) {
 +		dprintk("change to %u MHz succeeded after %u tries with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result);
 +	} else {
 +		printk(KERN_ERR "cpufreq: change failed with new_state %u and result %u\n", new_state, result);
 +	}
 +
 +	return;
 +}
 +
 +
 +/**
 + * speedstep_target - set a new CPUFreq policy
 + * @policy: new policy
 + * @target_freq: new freq
 + * @relation:
 + *
 + * Sets a new CPUFreq policy/freq.
 + */
 +static int speedstep_target (struct cpufreq_policy *policy,
 +			unsigned int target_freq, unsigned int relation)
 +{
 +	unsigned int newstate = 0;
 +	struct cpufreq_freqs freqs;
 +
 +	if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
 +		return -EINVAL;
 +
 +	freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
 +	freqs.new = speedstep_freqs[newstate].frequency;
 +	freqs.cpu = 0; /* speedstep.c is UP only driver */
 +
 +	if (freqs.old == freqs.new)
 +		return 0;
 +
 +	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 +	speedstep_set_state(newstate);
 +	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 +
 +	return 0;
 +}
 +
 +
 +/**
 + * speedstep_verify - verifies a new CPUFreq policy
 + * @policy: new policy
 + *
 + * Limit must be within speedstep_low_freq and speedstep_high_freq, with
 + * at least one border included.
 + */
 +static int speedstep_verify (struct cpufreq_policy *policy)
 +{
 +	return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
 +}
 +
 +
 +static int speedstep_cpu_init(struct cpufreq_policy *policy)
 +{
 +	int result;
 +	unsigned int speed,state;
 +
 +	/* capability check */
 +	if (policy->cpu != 0)
 +		return -ENODEV;
 +
 +	result = speedstep_smi_ownership();
 +	if (result) {
 +		dprintk("fails in aquiring ownership of a SMI interface.\n");
 +		return -EINVAL;
 +	}
 +
 +	/* detect low and high frequency */
 +	result = speedstep_smi_get_freqs(&speedstep_freqs[SPEEDSTEP_LOW].frequency,
 +				&speedstep_freqs[SPEEDSTEP_HIGH].frequency);
 +	if (result) {
 +		/* fall back to speedstep_lib.c dection mechanism: try both states out */
 +		dprintk("could not detect low and high frequencies by SMI call.\n");
 +		result = speedstep_get_freqs(speedstep_processor,
 +				&speedstep_freqs[SPEEDSTEP_LOW].frequency,
 +				&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
 +				NULL,
 +				&speedstep_set_state);
 +
 +		if (result) {
 +			dprintk("could not detect two different speeds -- aborting.\n");
 +			return result;
 +		} else
 +			dprintk("workaround worked.\n");
 +	}
 +
 +	/* get current speed setting */
 +	state = speedstep_get_state();
 +	speed = speedstep_freqs[state].frequency;
 +
 +	dprintk("currently at %s speed setting - %i MHz\n",
 +		(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
 +		(speed / 1000));
 +
 +	/* cpuinfo and default policy values */
- 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 +	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 +	policy->cur = speed;
 +
 +	result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
 +	if (result)
 +		return (result);
 +
 +	cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
 +
 +	return 0;
 +}
 +
 +static int speedstep_cpu_exit(struct cpufreq_policy *policy)
 +{
 +	cpufreq_frequency_table_put_attr(policy->cpu);
 +	return 0;
 +}
 +
 +static unsigned int speedstep_get(unsigned int cpu)
 +{
 +	if (cpu)
 +		return -ENODEV;
 +	return speedstep_get_processor_frequency(speedstep_processor);
 +}
 +
 +
 +static int speedstep_resume(struct cpufreq_policy *policy)
 +{
 +	int result = speedstep_smi_ownership();
 +
 +	if (result)
 +		dprintk("fails in re-aquiring ownership of a SMI interface.\n");
 +
 +	return result;
 +}
 +
 +static struct freq_attr* speedstep_attr[] = {
 +	&cpufreq_freq_attr_scaling_available_freqs,
 +	NULL,
 +};
 +
 +static struct cpufreq_driver speedstep_driver = {
 +	.name		= "speedstep-smi",
 +	.verify		= speedstep_verify,
 +	.target		= speedstep_target,
 +	.init		= speedstep_cpu_init,
 +	.exit		= speedstep_cpu_exit,
 +	.get		= speedstep_get,
 +	.resume		= speedstep_resume,
 +	.owner		= THIS_MODULE,
 +	.attr		= speedstep_attr,
 +};
 +
 +/**
 + * speedstep_init - initializes the SpeedStep CPUFreq driver
 + *
 + *   Initializes the SpeedStep support. Returns -ENODEV on unsupported
 + * BIOS, -EINVAL on problems during initiatization, and zero on
 + * success.
 + */
 +static int __init speedstep_init(void)
 +{
 +	speedstep_processor = speedstep_detect_processor();
 +
 +	switch (speedstep_processor) {
 +	case SPEEDSTEP_PROCESSOR_PIII_T:
 +	case SPEEDSTEP_PROCESSOR_PIII_C:
 +	case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
 +		break;
 +	default:
 +		speedstep_processor = 0;
 +	}
 +
 +	if (!speedstep_processor) {
 +		dprintk ("No supported Intel CPU detected.\n");
 +		return -ENODEV;
 +	}
 +
 +	dprintk("signature:0x%.8lx, command:0x%.8lx, event:0x%.8lx, perf_level:0x%.8lx.\n",
 +		ist_info.signature, ist_info.command, ist_info.event, ist_info.perf_level);
 +
 +	/* Error if no IST-SMI BIOS or no PARM
 +		 sig= 'ISGE' aka 'Intel Speedstep Gate E' */
 +	if ((ist_info.signature !=  0x47534943) && (
 +	    (smi_port == 0) || (smi_cmd == 0)))
 +		return -ENODEV;
 +
 +	if (smi_sig == 1)
 +		smi_sig = 0x47534943;
 +	else
 +		smi_sig = ist_info.signature;
 +
 +	/* setup smi_port from MODLULE_PARM or BIOS */
 +	if ((smi_port > 0xff) || (smi_port < 0))
 +		return -EINVAL;
 +	else if (smi_port == 0)
 +		smi_port = ist_info.command & 0xff;
 +
 +	if ((smi_cmd > 0xff) || (smi_cmd < 0))
 +		return -EINVAL;
 +	else if (smi_cmd == 0)
 +		smi_cmd = (ist_info.command >> 16) & 0xff;
 +
 +	return cpufreq_register_driver(&speedstep_driver);
 +}
 +
 +
 +/**
 + * speedstep_exit - unregisters SpeedStep support
 + *
 + *   Unregisters SpeedStep support.
 + */
 +static void __exit speedstep_exit(void)
 +{
 +	cpufreq_unregister_driver(&speedstep_driver);
 +}
 +
 +module_param(smi_port,  int, 0444);
 +module_param(smi_cmd,   int, 0444);
 +module_param(smi_sig,  uint, 0444);
 +
 +MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value -- Intel's default setting is 0xb2");
 +MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value -- Intel's default setting is 0x82");
 +MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the SMI interface.");
 +
 +MODULE_AUTHOR ("Hiroshi Miura");
 +MODULE_DESCRIPTION ("Speedstep driver for IST applet SMI interface.");
 +MODULE_LICENSE ("GPL");
 +
 +module_init(speedstep_init);
 +module_exit(speedstep_exit);