2 * SFI Performance States Driver
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * Author: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
14 * Author: Srinidhi Kasagar <srinidhi.kasagar@intel.com>
17 #include <linux/cpufreq.h>
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/sfi.h>
22 #include <linux/slab.h>
23 #include <linux/smp.h>
27 struct cpufreq_frequency_table
*freq_table
;
28 static struct sfi_freq_table_entry
*sfi_cpufreq_array
;
29 static int num_freq_table_entries
;
31 static int sfi_parse_freq(struct sfi_table_header
*table
)
33 struct sfi_table_simple
*sb
;
34 struct sfi_freq_table_entry
*pentry
;
37 sb
= (struct sfi_table_simple
*)table
;
38 num_freq_table_entries
= SFI_GET_NUM_ENTRIES(sb
,
39 struct sfi_freq_table_entry
);
40 if (num_freq_table_entries
<= 1) {
41 pr_err("No p-states discovered\n");
45 pentry
= (struct sfi_freq_table_entry
*)sb
->pentry
;
46 totallen
= num_freq_table_entries
* sizeof(*pentry
);
48 sfi_cpufreq_array
= kmemdup(pentry
, totallen
, GFP_KERNEL
);
49 if (!sfi_cpufreq_array
)
55 static int sfi_cpufreq_target(struct cpufreq_policy
*policy
, unsigned int index
)
57 unsigned int next_perf_state
= 0; /* Index into perf table */
60 next_perf_state
= policy
->freq_table
[index
].driver_data
;
62 rdmsr_on_cpu(policy
->cpu
, MSR_IA32_PERF_CTL
, &lo
, &hi
);
63 lo
= (lo
& ~INTEL_PERF_CTL_MASK
) |
64 ((u32
) sfi_cpufreq_array
[next_perf_state
].ctrl_val
&
66 wrmsr_on_cpu(policy
->cpu
, MSR_IA32_PERF_CTL
, lo
, hi
);
71 static int sfi_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
73 policy
->shared_type
= CPUFREQ_SHARED_TYPE_HW
;
74 policy
->cpuinfo
.transition_latency
= 100000; /* 100us */
76 return cpufreq_table_validate_and_show(policy
, freq_table
);
79 static struct cpufreq_driver sfi_cpufreq_driver
= {
80 .flags
= CPUFREQ_CONST_LOOPS
,
81 .verify
= cpufreq_generic_frequency_table_verify
,
82 .target_index
= sfi_cpufreq_target
,
83 .init
= sfi_cpufreq_cpu_init
,
84 .name
= "sfi-cpufreq",
85 .attr
= cpufreq_generic_attr
,
88 static int __init
sfi_cpufreq_init(void)
92 /* parse the freq table from SFI */
93 ret
= sfi_table_parse(SFI_SIG_FREQ
, NULL
, NULL
, sfi_parse_freq
);
97 freq_table
= kzalloc(sizeof(*freq_table
) *
98 (num_freq_table_entries
+ 1), GFP_KERNEL
);
104 for (i
= 0; i
< num_freq_table_entries
; i
++) {
105 freq_table
[i
].driver_data
= i
;
106 freq_table
[i
].frequency
= sfi_cpufreq_array
[i
].freq_mhz
* 1000;
108 freq_table
[i
].frequency
= CPUFREQ_TABLE_END
;
110 ret
= cpufreq_register_driver(&sfi_cpufreq_driver
);
119 kfree(sfi_cpufreq_array
);
122 late_initcall(sfi_cpufreq_init
);
124 static void __exit
sfi_cpufreq_exit(void)
126 cpufreq_unregister_driver(&sfi_cpufreq_driver
);
128 kfree(sfi_cpufreq_array
);
130 module_exit(sfi_cpufreq_exit
);
132 MODULE_AUTHOR("Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>");
133 MODULE_DESCRIPTION("SFI Performance-States Driver");
134 MODULE_LICENSE("GPL");