Skip to content

Commit 45422f1

Browse files
Jing Liopsiff
authored andcommitted
sw64: cpufreq: optimize the granularity of cpufreq
Optimize the granularity of cpufreq according to the actual clock domain to improve system energy efficiency. Signed-off-by: Jing Li <[email protected]> Reviewed-by: He Sheng <[email protected]> Signed-off-by: Gu Zitao <[email protected]>
1 parent 280f1db commit 45422f1

File tree

7 files changed

+97
-86
lines changed

7 files changed

+97
-86
lines changed

arch/sw_64/include/asm/cpu.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#include <linux/cache.h>
88
#include <linux/cacheinfo.h>
99

10+
#define KHZ (1000UL)
11+
#define MHZ (1000UL * 1000UL)
12+
1013
#define current_cpu_data cpu_data[smp_processor_id()]
1114

1215
enum hmcall_cpuid_cmd {
@@ -48,10 +51,23 @@ extern struct cpuinfo_sw64 cpu_data[NR_CPUS];
4851
extern cpumask_t cpu_offline;
4952

5053
extern void store_cpu_data(int cpu);
51-
extern unsigned long get_cpu_freq(void);
52-
extern void update_cpu_freq(unsigned long khz);
5354

5455
extern unsigned int get_cpu_cache_size(int cpu, int level, enum cache_type type);
5556
extern unsigned int get_cpu_cacheline_size(int cpu, int level, enum cache_type type);
5657

58+
/* Hz */
59+
static inline unsigned long sunway_max_cpu_freq(void)
60+
{
61+
return cpuid(GET_CPU_FREQ, 0) * MHZ;
62+
}
63+
64+
#ifdef CONFIG_SW64_CPUFREQ
65+
extern unsigned long get_cpu_freq(unsigned int cpu);
66+
#else
67+
static inline unsigned long get_cpu_freq(unsigned int cpu)
68+
{
69+
return sunway_max_cpu_freq();
70+
}
71+
#endif
72+
5773
#endif /* _ASM_SW64_CPU_H */

arch/sw_64/kernel/cpu.c

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <linux/cacheinfo.h>
44
#include <linux/cpu.h>
5+
#include <linux/cpufreq.h>
56
#include <linux/cpumask.h>
67
#include <linux/delay.h>
78
#include <linux/seq_file.h>
@@ -40,25 +41,11 @@ EXPORT_SYMBOL(cpu_data);
4041

4142
cpumask_t cpu_offline = CPU_MASK_NONE;
4243

43-
static unsigned long cpu_freq;
4444
static unsigned long cpu_info;
4545
static __u16 family;
4646
static char vendor_id[64];
4747
static char model_id[64];
4848

49-
unsigned long get_cpu_freq(void)
50-
{
51-
if (likely(cpu_freq))
52-
return cpu_freq;
53-
54-
return cpuid(GET_CPU_FREQ, 0) * 1000UL * 1000UL;
55-
}
56-
57-
void update_cpu_freq(unsigned long khz)
58-
{
59-
cpu_freq = khz * 1000;
60-
}
61-
6249
/* Move global data into per-processor storage */
6350
void store_cpu_data(int cpu)
6451
{
@@ -240,7 +227,7 @@ static int show_cpuinfo(struct seq_file *f, void *slot)
240227
unsigned int l3_cache_size, l3_cachline_size;
241228
unsigned long freq;
242229

243-
freq = cpuid(GET_CPU_FREQ, 0);
230+
freq = sunway_max_cpu_freq() / MHZ;
244231

245232
for_each_online_cpu(i) {
246233
l3_cache_size = get_cpu_cache_size(i, 3, CACHE_TYPE_UNIFIED);
@@ -267,7 +254,7 @@ static int show_cpuinfo(struct seq_file *f, void *slot)
267254
"cache size\t: %u KB\n"
268255
"physical id\t: %d\n"
269256
"bogomips\t: %lu.%02lu\n",
270-
get_cpu_freq() / 1000 / 1000, l3_cache_size >> 10,
257+
get_cpu_freq(i) / 1000 / 1000, l3_cache_size >> 10,
271258
cpu_topology[i].package_id,
272259
loops_per_jiffy / (500000/HZ),
273260
(loops_per_jiffy / (5000/HZ)) % 100);
@@ -313,3 +300,16 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
313300
return phys_id == cpu_physical_id(cpu);
314301
}
315302

303+
#ifdef CONFIG_SW64_CPUFREQ
304+
305+
unsigned long get_cpu_freq(unsigned int cpu)
306+
{
307+
unsigned long freq = cpufreq_quick_get(cpu);
308+
309+
if (likely(freq))
310+
return freq * KHZ;
311+
312+
return sunway_max_cpu_freq();
313+
}
314+
315+
#endif

arch/sw_64/kernel/setup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ EXPORT_SYMBOL(screen_info);
133133
#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
134134
u64 hw_nmi_get_sample_period(int watchdog_thresh)
135135
{
136-
return get_cpu_freq() * watchdog_thresh;
136+
return sunway_max_cpu_freq() * watchdog_thresh;
137137
}
138138
#endif
139139

arch/sw_64/kernel/time.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ time_init(void)
3131
{
3232
unsigned long cycle_freq;
3333

34-
cycle_freq = get_cpu_freq();
34+
cycle_freq = sunway_max_cpu_freq();
3535

3636
pr_info("CPU Cycle frequency = %ld Hz\n", cycle_freq);
3737

arch/sw_64/lib/udelay.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ EXPORT_SYMBOL(__delay);
3232

3333
void udelay(unsigned long usecs)
3434
{
35-
unsigned long loops = usecs * get_cpu_freq() / 1000000;
35+
unsigned long loops = usecs * get_cpu_freq(smp_processor_id()) / 1000000;
3636
unsigned long tmp;
3737

3838
__asm__ __volatile__(
@@ -47,7 +47,7 @@ EXPORT_SYMBOL(udelay);
4747

4848
void ndelay(unsigned long nsecs)
4949
{
50-
unsigned long loops = nsecs * get_cpu_freq() / 1000000000;
50+
unsigned long loops = nsecs * get_cpu_freq(smp_processor_id()) / 1000000000;
5151
unsigned long tmp;
5252

5353
__asm__ __volatile__(

drivers/clocksource/timer-sw64.c

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ void __init sw64_setup_clocksource(void)
174174
else
175175
clocksource_register_khz(&clocksource_vtime, mclk_khz);
176176
#else
177-
clocksource_register_hz(&clocksource_tc, get_cpu_freq());
177+
clocksource_register_hz(&clocksource_tc, sunway_max_cpu_freq());
178178
pr_info("Setup clocksource TC, mult = %d\n", clocksource_tc.mult);
179179
#endif
180180
}
@@ -208,23 +208,13 @@ void __init setup_sched_clock(void)
208208

209209
sc_shift = 7;
210210
step = 1UL << sc_shift;
211-
sc_multi = step * NSEC_PER_SEC / get_cpu_freq();
211+
sc_multi = step * NSEC_PER_SEC / sunway_max_cpu_freq();
212212
calibrate_sched_clock();
213213

214214
pr_info("sched_clock: sc_multi=%llu, sc_shift=%llu\n", sc_multi, sc_shift);
215215
}
216216

217-
#ifdef CONFIG_GENERIC_SCHED_CLOCK
218-
static u64 notrace read_sched_clock(void)
219-
{
220-
return (rdtc() - sc_start) >> sc_shift;
221-
}
222-
223-
void __init sw64_sched_clock_init(void)
224-
{
225-
sched_clock_register(sched_clock_read, BITS_PER_LONG, get_cpu_freq() >> sc_shift);
226-
}
227-
#else /* !CONFIG_GENERIC_SCHED_CLOCK */
217+
#ifndef CONFIG_GENERIC_SCHED_CLOCK
228218
/*
229219
* scheduler clock - returns current time in nanoseconds.
230220
*/
@@ -428,7 +418,7 @@ void sw64_setup_timer(void)
428418
struct clock_event_device *swevt = &per_cpu(timer_events, cpu);
429419

430420
/* min_delta ticks => 100ns */
431-
min_delta = get_cpu_freq()/1000/1000/10;
421+
min_delta = sunway_max_cpu_freq()/1000/1000/10;
432422

433423
if (is_in_guest()) {
434424
memcpy(swevt, &vtimer_clockevent, sizeof(*swevt));
@@ -443,7 +433,7 @@ void sw64_setup_timer(void)
443433
}
444434
swevt->cpumask = cpumask_of(cpu);
445435
swevt->set_state_shutdown(swevt);
446-
clockevents_config_and_register(swevt, get_cpu_freq(), min_delta, ULONG_MAX);
436+
clockevents_config_and_register(swevt, sunway_max_cpu_freq(), min_delta, ULONG_MAX);
447437
}
448438

449439
void sw64_timer_interrupt(void)

drivers/cpufreq/sunway-cpufreq.c

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ struct cpufreq_frequency_table freq_table[] = {
7777
FV(2850, 0),
7878
{0, 0, CPUFREQ_TABLE_END},
7979
};
80-
static void __init fill_freq_table(struct cpufreq_frequency_table *ft)
81-
{
82-
}
8380
#endif
8481

8582
#ifdef CONFIG_PLATFORM_XUELANG
@@ -135,60 +132,65 @@ static void __init fill_freq_table(struct cpufreq_frequency_table *ft)
135132

136133
static unsigned int sunway_get_rate(struct cpufreq_policy *policy)
137134
{
138-
int i;
135+
int i, node;
139136
u64 val;
140-
void __iomem *spbu_base = misc_platform_get_spbu_base(0);
137+
void __iomem *spbu_base;
141138
struct cpufreq_frequency_table *ft = policy->freq_table;
142139

140+
node = per_cpu(hard_node_id, policy->cpu);
141+
spbu_base = misc_platform_get_spbu_base(node);
142+
143143
/* PLL2 provides working frequency for core */
144144
val = readq(spbu_base + OFFSET_CLK_CTL) >> CORE_PLL2_CFG_SHIFT;
145145
val &= CORE_PLL2_CFG_MASK;
146146

147147
for (i = 0; ft[i].frequency != CPUFREQ_TABLE_END; i++) {
148148
if (val == i) {
149149
if (ft[i].frequency == CPUFREQ_ENTRY_INVALID)
150-
return cpuid(GET_CPU_FREQ, 0) * 1000UL;
150+
return sunway_max_cpu_freq() / KHZ;
151151
return ft[i].frequency;
152152
}
153153
}
154154

155155
return 0;
156156
}
157157

158-
static int sunway_set_rate(unsigned int index)
158+
static int sunway_set_rate(struct cpufreq_policy *policy, unsigned int index)
159159
{
160-
int i, retry, cpu_num;
160+
int retry, node;
161161
void __iomem *spbu_base;
162162

163-
cpu_num = sw64_chip->get_cpu_num();
164-
for (i = 0; i < cpu_num; i++) {
165-
spbu_base = misc_platform_get_spbu_base(i);
166-
167-
/* select PLL0/PLL1 */
168-
writeq(CLK_LV1_SEL_PROTECT, spbu_base + OFFSET_CLU_LV1_SEL);
169-
/* reset PLL2 */
170-
writeq(CLK2_PROTECT | CORE_CLK2_RESET | CORE_CLK2_VALID, spbu_base + OFFSET_CLK_CTL);
171-
/* configure PLL2_CFG */
172-
writeq(CLK2_PROTECT | CORE_CLK2_VALID | (unsigned long)index << CORE_PLL2_CFG_SHIFT,
173-
spbu_base + OFFSET_CLK_CTL);
174-
udelay(1);
175-
/* reset over */
176-
writeq(CORE_CLK2_VALID, spbu_base + OFFSET_CLK_CTL);
177-
retry = 0;
178-
while (retry < MAX_RETRY) {
179-
if (readq(spbu_base + OFFSET_CLK_CTL) & CORE_CLK2_LOCK)
180-
break;
181-
retry++;
182-
udelay(100);
183-
}
184-
if (retry == MAX_RETRY)
185-
return -ETIME;
186-
/* configure over */
187-
writeq(0, spbu_base + OFFSET_CLK_CTL);
188-
/* select PLL2/PLL2 */
189-
writeq(CLK_LV1_SEL_MUXA | CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PROTECT,
190-
spbu_base + OFFSET_CLU_LV1_SEL);
163+
node = per_cpu(hard_node_id, policy->cpu);
164+
spbu_base = misc_platform_get_spbu_base(node);
165+
166+
/* select PLL0/PLL1 */
167+
writeq(CLK_LV1_SEL_PROTECT, spbu_base + OFFSET_CLU_LV1_SEL);
168+
/* reset PLL2 */
169+
writeq(CLK2_PROTECT | CORE_CLK2_RESET | CORE_CLK2_VALID, spbu_base + OFFSET_CLK_CTL);
170+
/* configure PLL2_CFG */
171+
writeq(CLK2_PROTECT | CORE_CLK2_VALID | (unsigned long)index << CORE_PLL2_CFG_SHIFT,
172+
spbu_base + OFFSET_CLK_CTL);
173+
174+
udelay(1);
175+
/* reset over */
176+
writeq(CORE_CLK2_VALID, spbu_base + OFFSET_CLK_CTL);
177+
retry = 0;
178+
while (retry < MAX_RETRY) {
179+
if (readq(spbu_base + OFFSET_CLK_CTL) & CORE_CLK2_LOCK)
180+
break;
181+
retry++;
182+
udelay(100);
191183
}
184+
185+
if (retry == MAX_RETRY)
186+
return -ETIME;
187+
188+
/* configure over */
189+
writeq(0, spbu_base + OFFSET_CLK_CTL);
190+
/* select PLL2/PLL2 */
191+
writeq(CLK_LV1_SEL_MUXA | CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PROTECT,
192+
spbu_base + OFFSET_CLU_LV1_SEL);
193+
192194
return 0;
193195
}
194196

@@ -205,9 +207,6 @@ static unsigned int sunway_cpufreq_get(unsigned int cpu)
205207
return sunway_get_rate(policy);
206208
}
207209

208-
/*
209-
* Here we notify other drivers of the proposed change and the final change.
210-
*/
211210
static int sunway_cpufreq_target(struct cpufreq_policy *policy,
212211
unsigned int index)
213212
{
@@ -218,24 +217,27 @@ static int sunway_cpufreq_target(struct cpufreq_policy *policy,
218217
return -ENODEV;
219218

220219
/* setting the cpu frequency */
221-
ret = sunway_set_rate(index);
220+
ret = sunway_set_rate(policy, index);
222221
if (ret)
223222
return ret;
224-
update_cpu_freq(freq_table[index].frequency);
225223

226224
return 0;
227225
}
228226

229227
static int sunway_cpufreq_init(struct cpufreq_policy *policy)
230228
{
231-
cpufreq_generic_init(policy, freq_table, 0);
229+
int cpu, node;
232230

233-
return 0;
234-
}
231+
node = per_cpu(hard_node_id, policy->cpu);
235232

236-
static int sunway_cpufreq_verify(struct cpufreq_policy_data *policy)
237-
{
238-
return cpufreq_frequency_table_verify(policy, freq_table);
233+
for_each_possible_cpu(cpu) {
234+
if (per_cpu(hard_node_id, cpu) == node)
235+
cpumask_set_cpu(cpu, policy->cpus);
236+
}
237+
238+
policy->freq_table = freq_table;
239+
240+
return 0;
239241
}
240242

241243
static int sunway_cpufreq_exit(struct cpufreq_policy *policy)
@@ -251,7 +253,7 @@ static struct cpufreq_driver sunway_cpufreq_driver = {
251253
.name = "sunway-cpufreq",
252254
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
253255
.init = sunway_cpufreq_init,
254-
.verify = sunway_cpufreq_verify,
256+
.verify = cpufreq_generic_frequency_table_verify,
255257
.target_index = sunway_cpufreq_target,
256258
.get = sunway_cpufreq_get,
257259
.exit = sunway_cpufreq_exit,
@@ -261,14 +263,17 @@ static struct cpufreq_driver sunway_cpufreq_driver = {
261263
static int __init cpufreq_init(void)
262264
{
263265
int i, ret;
264-
unsigned long max_rate = get_cpu_freq() / 1000;
266+
unsigned long max_rate = sunway_max_cpu_freq() / KHZ; /* KHz */
265267

266268
if (!is_in_host()) {
267269
pr_warn("cpufreq driver of Sunway platforms is only supported in host mode\n");
268270
return -ENODEV;
269271
}
270272

273+
#ifdef CONFIG_PLATFORM_XUELANG
271274
fill_freq_table(freq_table);
275+
#endif
276+
272277
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
273278
if (max_rate == freq_table[i].frequency)
274279
freq_table[i+1].frequency = CPUFREQ_TABLE_END;

0 commit comments

Comments
 (0)