[CPUFREQ] powernow-k8: Get transition latency from ACPI _PSS table
[pandora-kernel.git] / arch / x86 / kernel / cpu / cpufreq / powernow-k8.c
index 7f05f44..fb039cd 100644 (file)
@@ -766,7 +766,7 @@ static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned
 static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
 {
        struct cpufreq_frequency_table *powernow_table;
-       int ret_val;
+       int ret_val = -ENODEV;
 
        if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
                dprintk("register performance failed: bad ACPI data\n");
@@ -815,6 +815,13 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
        /* notify BIOS that we exist */
        acpi_processor_notify_smm(THIS_MODULE);
 
+       if (!alloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) {
+               printk(KERN_ERR PFX
+                               "unable to alloc powernow_k8_data cpumask\n");
+               ret_val = -ENOMEM;
+               goto err_out_mem;
+       }
+
        return 0;
 
 err_out_mem:
@@ -826,7 +833,7 @@ err_out:
        /* data->acpi_data.state_count informs us at ->exit() whether ACPI was used */
        data->acpi_data.state_count = 0;
 
-       return -ENODEV;
+       return ret_val;
 }
 
 static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table)
@@ -929,12 +936,28 @@ 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);
+       free_cpumask_var(data->acpi_data.shared_cpu_map);
+}
+
+static int get_transition_latency(struct powernow_k8_data *data)
+{
+       int max_latency = 0;
+       int i;
+       for (i = 0; i < data->acpi_data.state_count; i++) {
+               int cur_latency = data->acpi_data.states[i].transition_latency
+                       + data->acpi_data.states[i].bus_master_latency;
+               if (cur_latency > max_latency)
+                       max_latency = cur_latency;
+       }
+       /* value in usecs, needs to be in nanoseconds */
+       return 1000 * max_latency;
 }
 
 #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; }
+static int get_transition_latency(struct powernow_k8_data *data) { return 0; }
 #endif /* CONFIG_X86_POWERNOW_K8_ACPI */
 
 /* Take a frequency, and issue the fid/vid transition command */
@@ -1134,7 +1157,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        data->cpu = pol->cpu;
        data->currpstate = HW_PSTATE_INVALID;
 
-       if (powernow_k8_cpu_init_acpi(data)) {
+       rc = powernow_k8_cpu_init_acpi(data);
+       if (rc) {
                /*
                 * Use the PSB BIOS structure. This is only availabe on
                 * an UP version, and is deprecated by AMD.
@@ -1152,22 +1176,25 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
                               "ACPI maintainers and complain to your BIOS "
                               "vendor.\n");
 #endif
-                       kfree(data);
-                       return -ENODEV;
+                       goto err_out;
                }
                if (pol->cpu != 0) {
                        printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
                               "CPU other than CPU0. Complain to your BIOS "
                               "vendor.\n");
-                       kfree(data);
-                       return -ENODEV;
+                       goto err_out;
                }
                rc = find_psb_table(data);
                if (rc) {
-                       kfree(data);
-                       return -ENODEV;
+                       goto err_out;
                }
-       }
+               /* 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) +
+                        ((1 << data->irt) * 30)) * 1000;
+       } else /* ACPI _PSS objects available */
+               pol->cpuinfo.transition_latency = get_transition_latency(data);
 
        /* only run on specific CPU from here on */
        oldmask = current->cpus_allowed;
@@ -1193,15 +1220,10 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        set_cpus_allowed_ptr(current, &oldmask);
 
        if (cpu_family == CPU_HW_PSTATE)
-               pol->cpus = cpumask_of_cpu(pol->cpu);
+               cpumask_copy(pol->cpus, cpumask_of(pol->cpu));
        else
-               pol->cpus = per_cpu(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;
+               cpumask_copy(pol->cpus, &per_cpu(cpu_core_map, pol->cpu));
+       data->available_cores = pol->cpus;
 
        if (cpu_family == CPU_HW_PSTATE)
                pol->cur = find_khz_freq_from_pstate(data->powernow_table, data->currpstate);