|
@@ -44,23 +44,58 @@ static struct cpufreq_frequency_table clock_ratio[] = {
|
|
|
/**
|
|
|
* powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
|
|
|
*
|
|
|
- * Returns the current setting of the frequency multiplier. Core clock
|
|
|
+ * 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;
|
|
|
+ unsigned long invalue = 0;
|
|
|
u32 msrval;
|
|
|
|
|
|
+ local_irq_disable();
|
|
|
+
|
|
|
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 */
|
|
|
|
|
|
+ local_irq_enable();
|
|
|
+
|
|
|
return clock_ratio[(invalue >> 5)&7].driver_data;
|
|
|
}
|
|
|
|
|
|
+static void powernow_k6_set_cpu_multiplier(unsigned int best_i)
|
|
|
+{
|
|
|
+ unsigned long outvalue, invalue;
|
|
|
+ unsigned long msrval;
|
|
|
+ unsigned long cr0;
|
|
|
+
|
|
|
+ /* we now need to transform best_i to the BVC format, see AMD#23446 */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The processor doesn't respond to inquiry cycles while changing the
|
|
|
+ * frequency, so we must disable cache.
|
|
|
+ */
|
|
|
+ local_irq_disable();
|
|
|
+ cr0 = read_cr0();
|
|
|
+ write_cr0(cr0 | X86_CR0_CD);
|
|
|
+ wbinvd();
|
|
|
+
|
|
|
+ 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 & 0x1f;
|
|
|
+ outvalue = outvalue | invalue;
|
|
|
+ outl(outvalue, (POWERNOW_IOPORT + 0x8));
|
|
|
+ msrval = POWERNOW_IOPORT + 0x0;
|
|
|
+ wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
|
|
+
|
|
|
+ write_cr0(cr0);
|
|
|
+ local_irq_enable();
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* powernow_k6_target - set the PowerNow! multiplier
|
|
@@ -71,8 +106,6 @@ static int powernow_k6_get_cpu_multiplier(void)
|
|
|
static int powernow_k6_target(struct cpufreq_policy *policy,
|
|
|
unsigned int best_i)
|
|
|
{
|
|
|
- unsigned long outvalue = 0, invalue = 0;
|
|
|
- unsigned long msrval;
|
|
|
struct cpufreq_freqs freqs;
|
|
|
|
|
|
if (clock_ratio[best_i].driver_data > max_multiplier) {
|
|
@@ -85,18 +118,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
|
|
|
|
|
|
cpufreq_notify_transition(policy, &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 */
|
|
|
+ powernow_k6_set_cpu_multiplier(best_i);
|
|
|
|
|
|
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
|
|
|
|
@@ -125,7 +147,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
|
|
}
|
|
|
|
|
|
/* cpuinfo and default policy values */
|
|
|
- policy->cpuinfo.transition_latency = 200000;
|
|
|
+ policy->cpuinfo.transition_latency = 500000;
|
|
|
|
|
|
return cpufreq_table_validate_and_show(policy, clock_ratio);
|
|
|
}
|