aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorWang Dongsheng <dongsheng.wang@freescale.com>2013-12-17 03:17:02 -0500
committerScott Wood <scottwood@freescale.com>2014-01-09 18:51:38 -0500
commita7189483f03d4c4b93219ff27a2e0a01716abd21 (patch)
tree9a3412e1a8b7a13f2fd31cdbeea4f6d3a205f9fb /arch/powerpc/kernel
parent1d47ddf7c3725e889763b1fffa70a04e1061940b (diff)
powerpc/85xx: add sysfs for pw20 state and altivec idle
Add a sys interface to enable/diable pw20 state or altivec idle, and control the wait entry time. Enable/Disable interface: 0, disable. 1, enable. /sys/devices/system/cpu/cpuX/pw20_state /sys/devices/system/cpu/cpuX/altivec_idle Set wait time interface:(Nanosecond) /sys/devices/system/cpu/cpuX/pw20_wait_time /sys/devices/system/cpu/cpuX/altivec_idle_wait_time Example: Base on TBfreq is 41MHZ. 1~48(ns): TB[63] 49~97(ns): TB[62] 98~195(ns): TB[61] 196~390(ns): TB[60] 391~780(ns): TB[59] 781~1560(ns): TB[58] ... Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com> [scottwood@freescale.com: change ifdef] Signed-off-by: Scott Wood <scottwood@freescale.com>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/sysfs.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index cad777eb613a..d4a43e64a6a9 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -86,6 +86,304 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay);
86 86
87#endif /* CONFIG_PPC64 */ 87#endif /* CONFIG_PPC64 */
88 88
89#ifdef CONFIG_PPC_FSL_BOOK3E
90#define MAX_BIT 63
91
92static u64 pw20_wt;
93static u64 altivec_idle_wt;
94
95static unsigned int get_idle_ticks_bit(u64 ns)
96{
97 u64 cycle;
98
99 if (ns >= 10000)
100 cycle = div_u64(ns + 500, 1000) * tb_ticks_per_usec;
101 else
102 cycle = div_u64(ns * tb_ticks_per_usec, 1000);
103
104 if (!cycle)
105 return 0;
106
107 return ilog2(cycle);
108}
109
110static void do_show_pwrmgtcr0(void *val)
111{
112 u32 *value = val;
113
114 *value = mfspr(SPRN_PWRMGTCR0);
115}
116
117static ssize_t show_pw20_state(struct device *dev,
118 struct device_attribute *attr, char *buf)
119{
120 u32 value;
121 unsigned int cpu = dev->id;
122
123 smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1);
124
125 value &= PWRMGTCR0_PW20_WAIT;
126
127 return sprintf(buf, "%u\n", value ? 1 : 0);
128}
129
130static void do_store_pw20_state(void *val)
131{
132 u32 *value = val;
133 u32 pw20_state;
134
135 pw20_state = mfspr(SPRN_PWRMGTCR0);
136
137 if (*value)
138 pw20_state |= PWRMGTCR0_PW20_WAIT;
139 else
140 pw20_state &= ~PWRMGTCR0_PW20_WAIT;
141
142 mtspr(SPRN_PWRMGTCR0, pw20_state);
143}
144
145static ssize_t store_pw20_state(struct device *dev,
146 struct device_attribute *attr,
147 const char *buf, size_t count)
148{
149 u32 value;
150 unsigned int cpu = dev->id;
151
152 if (kstrtou32(buf, 0, &value))
153 return -EINVAL;
154
155 if (value > 1)
156 return -EINVAL;
157
158 smp_call_function_single(cpu, do_store_pw20_state, &value, 1);
159
160 return count;
161}
162
163static ssize_t show_pw20_wait_time(struct device *dev,
164 struct device_attribute *attr, char *buf)
165{
166 u32 value;
167 u64 tb_cycle = 1;
168 u64 time;
169
170 unsigned int cpu = dev->id;
171
172 if (!pw20_wt) {
173 smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1);
174 value = (value & PWRMGTCR0_PW20_ENT) >>
175 PWRMGTCR0_PW20_ENT_SHIFT;
176
177 tb_cycle = (tb_cycle << (MAX_BIT - value + 1));
178 /* convert ms to ns */
179 if (tb_ticks_per_usec > 1000) {
180 time = div_u64(tb_cycle, tb_ticks_per_usec / 1000);
181 } else {
182 u32 rem_us;
183
184 time = div_u64_rem(tb_cycle, tb_ticks_per_usec,
185 &rem_us);
186 time = time * 1000 + rem_us * 1000 / tb_ticks_per_usec;
187 }
188 } else {
189 time = pw20_wt;
190 }
191
192 return sprintf(buf, "%llu\n", time > 0 ? time : 0);
193}
194
195static void set_pw20_wait_entry_bit(void *val)
196{
197 u32 *value = val;
198 u32 pw20_idle;
199
200 pw20_idle = mfspr(SPRN_PWRMGTCR0);
201
202 /* Set Automatic PW20 Core Idle Count */
203 /* clear count */
204 pw20_idle &= ~PWRMGTCR0_PW20_ENT;
205
206 /* set count */
207 pw20_idle |= ((MAX_BIT - *value) << PWRMGTCR0_PW20_ENT_SHIFT);
208
209 mtspr(SPRN_PWRMGTCR0, pw20_idle);
210}
211
212static ssize_t store_pw20_wait_time(struct device *dev,
213 struct device_attribute *attr,
214 const char *buf, size_t count)
215{
216 u32 entry_bit;
217 u64 value;
218
219 unsigned int cpu = dev->id;
220
221 if (kstrtou64(buf, 0, &value))
222 return -EINVAL;
223
224 if (!value)
225 return -EINVAL;
226
227 entry_bit = get_idle_ticks_bit(value);
228 if (entry_bit > MAX_BIT)
229 return -EINVAL;
230
231 pw20_wt = value;
232
233 smp_call_function_single(cpu, set_pw20_wait_entry_bit,
234 &entry_bit, 1);
235
236 return count;
237}
238
239static ssize_t show_altivec_idle(struct device *dev,
240 struct device_attribute *attr, char *buf)
241{
242 u32 value;
243 unsigned int cpu = dev->id;
244
245 smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1);
246
247 value &= PWRMGTCR0_AV_IDLE_PD_EN;
248
249 return sprintf(buf, "%u\n", value ? 1 : 0);
250}
251
252static void do_store_altivec_idle(void *val)
253{
254 u32 *value = val;
255 u32 altivec_idle;
256
257 altivec_idle = mfspr(SPRN_PWRMGTCR0);
258
259 if (*value)
260 altivec_idle |= PWRMGTCR0_AV_IDLE_PD_EN;
261 else
262 altivec_idle &= ~PWRMGTCR0_AV_IDLE_PD_EN;
263
264 mtspr(SPRN_PWRMGTCR0, altivec_idle);
265}
266
267static ssize_t store_altivec_idle(struct device *dev,
268 struct device_attribute *attr,
269 const char *buf, size_t count)
270{
271 u32 value;
272 unsigned int cpu = dev->id;
273
274 if (kstrtou32(buf, 0, &value))
275 return -EINVAL;
276
277 if (value > 1)
278 return -EINVAL;
279
280 smp_call_function_single(cpu, do_store_altivec_idle, &value, 1);
281
282 return count;
283}
284
285static ssize_t show_altivec_idle_wait_time(struct device *dev,
286 struct device_attribute *attr, char *buf)
287{
288 u32 value;
289 u64 tb_cycle = 1;
290 u64 time;
291
292 unsigned int cpu = dev->id;
293
294 if (!altivec_idle_wt) {
295 smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1);
296 value = (value & PWRMGTCR0_AV_IDLE_CNT) >>
297 PWRMGTCR0_AV_IDLE_CNT_SHIFT;
298
299 tb_cycle = (tb_cycle << (MAX_BIT - value + 1));
300 /* convert ms to ns */
301 if (tb_ticks_per_usec > 1000) {
302 time = div_u64(tb_cycle, tb_ticks_per_usec / 1000);
303 } else {
304 u32 rem_us;
305
306 time = div_u64_rem(tb_cycle, tb_ticks_per_usec,
307 &rem_us);
308 time = time * 1000 + rem_us * 1000 / tb_ticks_per_usec;
309 }
310 } else {
311 time = altivec_idle_wt;
312 }
313
314 return sprintf(buf, "%llu\n", time > 0 ? time : 0);
315}
316
317static void set_altivec_idle_wait_entry_bit(void *val)
318{
319 u32 *value = val;
320 u32 altivec_idle;
321
322 altivec_idle = mfspr(SPRN_PWRMGTCR0);
323
324 /* Set Automatic AltiVec Idle Count */
325 /* clear count */
326 altivec_idle &= ~PWRMGTCR0_AV_IDLE_CNT;
327
328 /* set count */
329 altivec_idle |= ((MAX_BIT - *value) << PWRMGTCR0_AV_IDLE_CNT_SHIFT);
330
331 mtspr(SPRN_PWRMGTCR0, altivec_idle);
332}
333
334static ssize_t store_altivec_idle_wait_time(struct device *dev,
335 struct device_attribute *attr,
336 const char *buf, size_t count)
337{
338 u32 entry_bit;
339 u64 value;
340
341 unsigned int cpu = dev->id;
342
343 if (kstrtou64(buf, 0, &value))
344 return -EINVAL;
345
346 if (!value)
347 return -EINVAL;
348
349 entry_bit = get_idle_ticks_bit(value);
350 if (entry_bit > MAX_BIT)
351 return -EINVAL;
352
353 altivec_idle_wt = value;
354
355 smp_call_function_single(cpu, set_altivec_idle_wait_entry_bit,
356 &entry_bit, 1);
357
358 return count;
359}
360
361/*
362 * Enable/Disable interface:
363 * 0, disable. 1, enable.
364 */
365static DEVICE_ATTR(pw20_state, 0600, show_pw20_state, store_pw20_state);
366static DEVICE_ATTR(altivec_idle, 0600, show_altivec_idle, store_altivec_idle);
367
368/*
369 * Set wait time interface:(Nanosecond)
370 * Example: Base on TBfreq is 41MHZ.
371 * 1~48(ns): TB[63]
372 * 49~97(ns): TB[62]
373 * 98~195(ns): TB[61]
374 * 196~390(ns): TB[60]
375 * 391~780(ns): TB[59]
376 * 781~1560(ns): TB[58]
377 * ...
378 */
379static DEVICE_ATTR(pw20_wait_time, 0600,
380 show_pw20_wait_time,
381 store_pw20_wait_time);
382static DEVICE_ATTR(altivec_idle_wait_time, 0600,
383 show_altivec_idle_wait_time,
384 store_altivec_idle_wait_time);
385#endif
386
89/* 387/*
90 * Enabling PMCs will slow partition context switch times so we only do 388 * Enabling PMCs will slow partition context switch times so we only do
91 * it the first time we write to the PMCs. 389 * it the first time we write to the PMCs.
@@ -425,6 +723,15 @@ static void register_cpu_online(unsigned int cpu)
425 device_create_file(s, &dev_attr_pir); 723 device_create_file(s, &dev_attr_pir);
426#endif /* CONFIG_PPC64 */ 724#endif /* CONFIG_PPC64 */
427 725
726#ifdef CONFIG_PPC_FSL_BOOK3E
727 if (PVR_VER(cur_cpu_spec->pvr_value) == PVR_VER_E6500) {
728 device_create_file(s, &dev_attr_pw20_state);
729 device_create_file(s, &dev_attr_pw20_wait_time);
730
731 device_create_file(s, &dev_attr_altivec_idle);
732 device_create_file(s, &dev_attr_altivec_idle_wait_time);
733 }
734#endif
428 cacheinfo_cpu_online(cpu); 735 cacheinfo_cpu_online(cpu);
429} 736}
430 737
@@ -497,6 +804,15 @@ static void unregister_cpu_online(unsigned int cpu)
497 device_remove_file(s, &dev_attr_pir); 804 device_remove_file(s, &dev_attr_pir);
498#endif /* CONFIG_PPC64 */ 805#endif /* CONFIG_PPC64 */
499 806
807#ifdef CONFIG_PPC_FSL_BOOK3E
808 if (PVR_VER(cur_cpu_spec->pvr_value) == PVR_VER_E6500) {
809 device_remove_file(s, &dev_attr_pw20_state);
810 device_remove_file(s, &dev_attr_pw20_wait_time);
811
812 device_remove_file(s, &dev_attr_altivec_idle);
813 device_remove_file(s, &dev_attr_altivec_idle_wait_time);
814 }
815#endif
500 cacheinfo_cpu_offline(cpu); 816 cacheinfo_cpu_offline(cpu);
501} 817}
502 818