aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-09 17:43:53 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-09 17:43:53 -0500
commitc488ea461359483976ff7d4838cce5c0138c6b3e (patch)
tree3bee2239b14a33c4519db8e7ca673dea37185a68
parentd64c3b0bb9195d4de856d841337368d930cdb0ed (diff)
parente7ddf4b7b3c5fe64902c4fb9edac92532c87cd75 (diff)
Merge branch 'sfi' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux into pm-cpufreq
Pull SFI-based cpufreq driver for v3.20 from Len Brown. * 'sfi' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux: cpufreq: Add SFI based cpufreq driver support SFI: fix compiler warnings
-rw-r--r--arch/x86/include/uapi/asm/msr-index.h1
-rw-r--r--drivers/cpufreq/Kconfig.x8610
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/sfi-cpufreq.c136
-rw-r--r--drivers/sfi/sfi_core.c4
5 files changed, 150 insertions, 2 deletions
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h
index c8aa65d56027..d11e1c57cfc5 100644
--- a/arch/x86/include/uapi/asm/msr-index.h
+++ b/arch/x86/include/uapi/asm/msr-index.h
@@ -358,6 +358,7 @@
358 358
359#define MSR_IA32_PERF_STATUS 0x00000198 359#define MSR_IA32_PERF_STATUS 0x00000198
360#define MSR_IA32_PERF_CTL 0x00000199 360#define MSR_IA32_PERF_CTL 0x00000199
361#define INTEL_PERF_CTL_MASK 0xffff
361#define MSR_AMD_PSTATE_DEF_BASE 0xc0010064 362#define MSR_AMD_PSTATE_DEF_BASE 0xc0010064
362#define MSR_AMD_PERF_STATUS 0xc0010063 363#define MSR_AMD_PERF_STATUS 0xc0010063
363#define MSR_AMD_PERF_CTL 0xc0010062 364#define MSR_AMD_PERF_CTL 0xc0010062
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 89ae88f91895..c59bdcb83217 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -57,6 +57,16 @@ config X86_ACPI_CPUFREQ_CPB
57 By enabling this option the acpi_cpufreq driver provides the old 57 By enabling this option the acpi_cpufreq driver provides the old
58 entry in addition to the new boost ones, for compatibility reasons. 58 entry in addition to the new boost ones, for compatibility reasons.
59 59
60config X86_SFI_CPUFREQ
61 tristate "SFI Performance-States driver"
62 depends on X86_INTEL_MID && SFI
63 help
64 This adds a CPUFreq driver for some Silvermont based Intel Atom
65 architectures like Z34xx and Z35xx which enumerate processor
66 performance states through SFI.
67
68 If in doubt, say N.
69
60config ELAN_CPUFREQ 70config ELAN_CPUFREQ
61 tristate "AMD Elan SC400 and SC410" 71 tristate "AMD Elan SC400 and SC410"
62 depends on MELAN 72 depends on MELAN
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index b3ca7b0b2c33..8b4220ac888b 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
41obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o 41obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
42obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o 42obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o
43obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o 43obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o
44obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o
44 45
45################################################################################## 46##################################################################################
46# ARM SoC drivers 47# ARM SoC drivers
diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c
new file mode 100644
index 000000000000..ffa3389e535b
--- /dev/null
+++ b/drivers/cpufreq/sfi-cpufreq.c
@@ -0,0 +1,136 @@
1/*
2 * SFI Performance States Driver
3 *
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.
7 *
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.
12 *
13 * Author: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
14 * Author: Srinidhi Kasagar <srinidhi.kasagar@intel.com>
15 */
16
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>
24
25#include <asm/msr.h>
26
27struct cpufreq_frequency_table *freq_table;
28static struct sfi_freq_table_entry *sfi_cpufreq_array;
29static int num_freq_table_entries;
30
31static int sfi_parse_freq(struct sfi_table_header *table)
32{
33 struct sfi_table_simple *sb;
34 struct sfi_freq_table_entry *pentry;
35 int totallen;
36
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");
42 return -ENODEV;
43 }
44
45 pentry = (struct sfi_freq_table_entry *)sb->pentry;
46 totallen = num_freq_table_entries * sizeof(*pentry);
47
48 sfi_cpufreq_array = kzalloc(totallen, GFP_KERNEL);
49 if (!sfi_cpufreq_array)
50 return -ENOMEM;
51
52 memcpy(sfi_cpufreq_array, pentry, totallen);
53
54 return 0;
55}
56
57static int sfi_cpufreq_target(struct cpufreq_policy *policy, unsigned int index)
58{
59 unsigned int next_perf_state = 0; /* Index into perf table */
60 u32 lo, hi;
61
62 next_perf_state = policy->freq_table[index].driver_data;
63
64 rdmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, &lo, &hi);
65 lo = (lo & ~INTEL_PERF_CTL_MASK) |
66 ((u32) sfi_cpufreq_array[next_perf_state].ctrl_val &
67 INTEL_PERF_CTL_MASK);
68 wrmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, lo, hi);
69
70 return 0;
71}
72
73static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy)
74{
75 policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
76 policy->cpuinfo.transition_latency = 100000; /* 100us */
77
78 return cpufreq_table_validate_and_show(policy, freq_table);
79}
80
81static struct cpufreq_driver sfi_cpufreq_driver = {
82 .flags = CPUFREQ_CONST_LOOPS,
83 .verify = cpufreq_generic_frequency_table_verify,
84 .target_index = sfi_cpufreq_target,
85 .init = sfi_cpufreq_cpu_init,
86 .name = "sfi-cpufreq",
87 .attr = cpufreq_generic_attr,
88};
89
90static int __init sfi_cpufreq_init(void)
91{
92 int ret, i;
93
94 /* parse the freq table from SFI */
95 ret = sfi_table_parse(SFI_SIG_FREQ, NULL, NULL, sfi_parse_freq);
96 if (ret)
97 return ret;
98
99 freq_table = kzalloc(sizeof(*freq_table) *
100 (num_freq_table_entries + 1), GFP_KERNEL);
101 if (!freq_table) {
102 ret = -ENOMEM;
103 goto err_free_array;
104 }
105
106 for (i = 0; i < num_freq_table_entries; i++) {
107 freq_table[i].driver_data = i;
108 freq_table[i].frequency = sfi_cpufreq_array[i].freq_mhz * 1000;
109 }
110 freq_table[i].frequency = CPUFREQ_TABLE_END;
111
112 ret = cpufreq_register_driver(&sfi_cpufreq_driver);
113 if (ret)
114 goto err_free_tbl;
115
116 return ret;
117
118err_free_tbl:
119 kfree(freq_table);
120err_free_array:
121 kfree(sfi_cpufreq_array);
122 return ret;
123}
124late_initcall(sfi_cpufreq_init);
125
126static void __exit sfi_cpufreq_exit(void)
127{
128 cpufreq_unregister_driver(&sfi_cpufreq_driver);
129 kfree(freq_table);
130 kfree(sfi_cpufreq_array);
131}
132module_exit(sfi_cpufreq_exit);
133
134MODULE_AUTHOR("Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>");
135MODULE_DESCRIPTION("SFI Performance-States Driver");
136MODULE_LICENSE("GPL");
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
index 1e824fb1649b..296db7a69c27 100644
--- a/drivers/sfi/sfi_core.c
+++ b/drivers/sfi/sfi_core.c
@@ -161,7 +161,7 @@ static int sfi_verify_table(struct sfi_table_header *table)
161 * Check for common case that we can re-use mapping to SYST, 161 * Check for common case that we can re-use mapping to SYST,
162 * which requires syst_pa, syst_va to be initialized. 162 * which requires syst_pa, syst_va to be initialized.
163 */ 163 */
164struct sfi_table_header *sfi_map_table(u64 pa) 164static struct sfi_table_header *sfi_map_table(u64 pa)
165{ 165{
166 struct sfi_table_header *th; 166 struct sfi_table_header *th;
167 u32 length; 167 u32 length;
@@ -189,7 +189,7 @@ struct sfi_table_header *sfi_map_table(u64 pa)
189 * Undoes effect of sfi_map_table() by unmapping table 189 * Undoes effect of sfi_map_table() by unmapping table
190 * if it did not completely fit on same page as SYST. 190 * if it did not completely fit on same page as SYST.
191 */ 191 */
192void sfi_unmap_table(struct sfi_table_header *th) 192static void sfi_unmap_table(struct sfi_table_header *th)
193{ 193{
194 if (!TABLE_ON_PAGE(syst_va, th, th->len)) 194 if (!TABLE_ON_PAGE(syst_va, th, th->len))
195 sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ? 195 sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?