#include <asm/io.h>
#include <asm/delay.h>
-#ifdef CONFIG_ACPI_PROCESSOR
+#ifdef CONFIG_X86_POWERNOW_K8_ACPI
#include <linux/acpi.h>
#include <acpi/processor.h>
#endif
#define PFX "powernow-k8: "
#define BFX PFX "BIOS error: "
-#define VERSION "version 1.00.08b"
+#define VERSION "version 1.00.09b"
#include "powernow-k8.h"
/* serialize freq changes */
goto out;
eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
- if ((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) {
- dprintk(KERN_DEBUG PFX "AMD Althon 64 Processor found\n");
- } else if ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD) {
- dprintk(KERN_DEBUG PFX "AMD Opteron Processor found\n");
- } else {
- printk(KERN_INFO PFX
- "AMD Athlon 64 or AMD Opteron processor required\n");
+ if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
+ ((eax & CPUID_XFAM) != CPUID_XFAM_K8) ||
+ ((eax & CPUID_XMOD) > CPUID_XMOD_REV_E)) {
+ printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
goto out;
}
{
int j;
for (j = 0; j < data->numps; j++) {
- printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j,
- data->powernow_table[j].index & 0xff,
- data->powernow_table[j].frequency/1000,
- data->powernow_table[j].index >> 8,
- find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
+ if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID)
+ printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j,
+ data->powernow_table[j].index & 0xff,
+ data->powernow_table[j].frequency/1000,
+ data->powernow_table[j].index >> 8,
+ find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
}
if (data->batps)
printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps);
printk(KERN_ERR PFX "no p states to transition\n");
return -ENODEV;
}
-
+
if (check_pst_table(data, pst, maxvid))
return -EINVAL;
return -ENODEV;
}
-#ifdef CONFIG_ACPI_PROCESSOR
+#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)
/* verify frequency is OK */
if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) ||
(powernow_table[i].frequency < (MIN_FREQ * 1000))) {
- dprintk(KERN_INFO PFX "invalid freq %u kHz\n", powernow_table[i].frequency);
+ dprintk(KERN_INFO PFX "invalid freq %u kHz, ignoring\n", powernow_table[i].frequency);
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
continue;
}
- /* verify only 1 entry from the lo frequency table */
- if ((fid < HI_FID_TABLE_BOTTOM) && (cntlofreq++)) {
- printk(KERN_ERR PFX "Too many lo freq table entries\n");
- goto err_out;
+ /* verify voltage is OK - BIOSs are using "off" to indicate invalid */
+ if (vid == 0x1f) {
+ dprintk(KERN_INFO PFX "invalid vid %u, ignoring\n", vid);
+ powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+ continue;
}
-
+
+ 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");
+ goto err_out_mem;
+ }
+
+ dprintk(KERN_INFO PFX "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,
print_basics(data);
powernow_k8_acpi_pst_values(data, 0);
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;
}
if (smp_processor_id() != pol->cpu) {
printk(KERN_ERR "limiting to cpu %u failed\n", pol->cpu);
- goto sched_out;
+ goto err_out;
}
- /* from this point, do not exit without restoring preempt and cpu */
- preempt_disable();
-
if (pending_bit_stuck()) {
printk(KERN_ERR PFX "failing targ, change pending bit set\n");
goto err_out;
ret = 0;
err_out:
- preempt_enable_no_resched();
-sched_out:
set_cpus_allowed(current, oldmask);
schedule();
* an UP version, and is deprecated by AMD.
*/
- if (pol->cpu != 0) {
- printk(KERN_ERR PFX "init not cpu 0\n");
+ if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) {
+ printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n");
kfree(data);
return -ENODEV;
}
- if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) {
- printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n");
+ if (pol->cpu != 0) {
+ printk(KERN_ERR PFX "init not cpu 0\n");
kfree(data);
- return 0;
+ return -ENODEV;
}
rc = find_psb_table(data);
if (rc) {
return -ENODEV;
}
-static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol)
+static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
{
struct powernow_k8_data *data = powernow_data[pol->cpu];
return 0;
}
+static unsigned int powernowk8_get (unsigned int cpu)
+{
+ struct powernow_k8_data *data = powernow_data[cpu];
+ cpumask_t oldmask = current->cpus_allowed;
+ unsigned int khz = 0;
+
+ 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;
+ }
+ preempt_disable();
+
+ if (query_current_values_with_pending_wait(data))
+ goto out;
+
+ khz = find_khz_freq_from_fid(data->currfid);
+
+ out:
+ preempt_enable_no_resched();
+ set_cpus_allowed(current, oldmask);
+
+ return khz;
+}
+
static struct freq_attr* powernow_k8_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
.verify = powernowk8_verify,
.target = powernowk8_target,
.init = powernowk8_cpu_init,
- .exit = powernowk8_cpu_exit,
+ .exit = __devexit_p(powernowk8_cpu_exit),
+ .get = powernowk8_get,
.name = "powernow-k8",
.owner = THIS_MODULE,
.attr = powernow_k8_attr,