/
0002-cpufreq-OMAP-Add-SMP-support-for-OMAP4.patch
191 lines (163 loc) · 5.64 KB
/
0002-cpufreq-OMAP-Add-SMP-support-for-OMAP4.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
From 167b038976b2aabb55906998d5f8782b85d9f1c3 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Wed, 21 Sep 2011 23:53:00 -0700
Subject: [PATCH 02/12] cpufreq: OMAP: Add SMP support for OMAP4+
On OMAP SMP configuartion, both processors share the voltage
and clock. So both CPUs needs to be scaled together and hence
needs software co-ordination.
Also, update lpj with reference value to avoid progressive error.
Adjust _both_ the per-cpu loops_per_jiffy and global lpj. Calibrate
them with with reference to the initial values to avoid a
progressively bigger and bigger error in the value over time.
While at this, re-use the notifiers for UP/SMP since on UP machine or
UP_ON_SMP policy->cpus mask would contain only the boot CPU.
Based on initial SMP support by Santosh Shilimkar.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[khilman@ti.com: due to overlap/rework, combined original Santosh patch
and Russell's rework]
Signed-off-by: Kevin Hilman <khilman@ti.com>
---
drivers/cpufreq/omap-cpufreq.c | 81 +++++++++++++++++++++++++++++++++++-----
1 files changed, 71 insertions(+), 10 deletions(-)
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index a6b2be7..1953f9d 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -23,9 +23,11 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/opp.h>
+#include <linux/cpu.h>
#include <asm/system.h>
#include <asm/smp_plat.h>
+#include <asm/cpu.h>
#include <plat/clock.h>
#include <plat/omap-pm.h>
@@ -35,6 +37,16 @@
#define VERY_HI_RATE 900000000
+#ifdef CONFIG_SMP
+struct lpj_info {
+ unsigned long ref;
+ unsigned int freq;
+};
+
+static DEFINE_PER_CPU(struct lpj_info, lpj_ref);
+static struct lpj_info global_lpj_ref;
+#endif
+
static struct cpufreq_frequency_table *freq_table;
static struct clk *mpu_clk;
@@ -60,7 +72,7 @@ static unsigned int omap_getspeed(unsigned int cpu)
{
unsigned long rate;
- if (cpu)
+ if (cpu >= NR_CPUS)
return 0;
rate = clk_get_rate(mpu_clk) / 1000;
@@ -71,7 +83,7 @@ static int omap_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
- int ret = 0;
+ int i, ret = 0;
struct cpufreq_freqs freqs;
/* Ensure desired rate is within allowed range. Some govenors
@@ -81,22 +93,57 @@ static int omap_target(struct cpufreq_policy *policy,
if (target_freq > policy->max)
target_freq = policy->max;
- freqs.old = omap_getspeed(0);
+ freqs.old = omap_getspeed(policy->cpu);
freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
- freqs.cpu = 0;
+ freqs.cpu = policy->cpu;
if (freqs.old == freqs.new)
return ret;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ /* notifiers */
+ for_each_cpu(i, policy->cpus) {
+ freqs.cpu = i;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ }
#ifdef CONFIG_CPU_FREQ_DEBUG
pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
#endif
ret = clk_set_rate(mpu_clk, freqs.new * 1000);
+ freqs.new = omap_getspeed(policy->cpu);
+
+#ifdef CONFIG_SMP
+ /*
+ * Note that loops_per_jiffy is not updated on SMP systems in
+ * cpufreq driver. So, update the per-CPU loops_per_jiffy value
+ * on frequency transition. We need to update all dependent CPUs.
+ */
+ for_each_cpu(i, policy->cpus) {
+ struct lpj_info *lpj = &per_cpu(lpj_ref, i);
+ if (!lpj->freq) {
+ lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy;
+ lpj->freq = freqs.old;
+ }
+
+ per_cpu(cpu_data, i).loops_per_jiffy =
+ cpufreq_scale(lpj->ref, lpj->freq, freqs.new);
+ }
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ /* And don't forget to adjust the global one */
+ if (!global_lpj_ref.freq) {
+ global_lpj_ref.ref = loops_per_jiffy;
+ global_lpj_ref.freq = freqs.old;
+ }
+ loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq,
+ freqs.new);
+#endif
+
+ /* notifiers */
+ for_each_cpu(i, policy->cpus) {
+ freqs.cpu = i;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
return ret;
}
@@ -105,6 +152,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
struct device *mpu_dev;
+ static cpumask_var_t cpumask;
if (cpu_is_omap24xx())
mpu_clk = clk_get(NULL, "virt_prcm_set");
@@ -116,12 +164,12 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
if (IS_ERR(mpu_clk))
return PTR_ERR(mpu_clk);
- if (policy->cpu != 0)
+ if (policy->cpu >= NR_CPUS)
return -EINVAL;
- policy->cur = policy->min = policy->max = omap_getspeed(0);
-
+ policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
mpu_dev = omap2_get_mpuss_device();
+
if (!mpu_dev) {
pr_warning("%s: unable to get the mpu device\n", __func__);
return -EINVAL;
@@ -141,7 +189,20 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
- policy->cur = omap_getspeed(0);
+ policy->cur = omap_getspeed(policy->cpu);
+
+ /*
+ * On OMAP SMP configuartion, both processors share the voltage
+ * and clock. So both CPUs needs to be scaled together and hence
+ * needs software co-ordination. Use cpufreq affected_cpus
+ * interface to handle this scenario. Additional is_smp() check
+ * is to keep SMP_ON_UP build working.
+ */
+ if (is_smp()) {
+ policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+ cpumask_or(cpumask, cpumask_of(policy->cpu), cpumask);
+ cpumask_copy(policy->cpus, cpumask);
+ }
/* FIXME: what's the actual transition time? */
policy->cpuinfo.transition_latency = 300 * 1000;
--
1.7.5.4