Skip to content

Commit dfe101b

Browse files
paulburtondlezcano
authored andcommitted
clocksource/drivers/mips-gic-timer: Always use cluster 0 counter as clocksource
In a multi-cluster MIPS system, there are multiple GICs - one in each cluster - each of which has its independent counter. The counters in each GIC are not synchronized in any way, so they can drift relative to one another through the lifetime of the system. This is problematic for a clock source which ought to be global. Avoid problems by always accessing cluster 0's counter, using cross-cluster register access. This adds overhead so it is applied only on multi-cluster systems. Signed-off-by: Paul Burton <[email protected]> Signed-off-by: Chao-ying Fu <[email protected]> Signed-off-by: Dragan Mladjenovic <[email protected]> Signed-off-by: Aleksandar Rikalo <[email protected]> Tested-by: Serge Semin <[email protected]> Acked-by: Thomas Bogendoerfer <[email protected]> Tested-by: Gregory CLEMENT <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Daniel Lezcano <[email protected]>
1 parent 3144133 commit dfe101b

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

drivers/clocksource/mips-gic-timer.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,37 @@ static u64 gic_hpt_read(struct clocksource *cs)
166166
return gic_read_count();
167167
}
168168

169+
static u64 gic_hpt_read_multicluster(struct clocksource *cs)
170+
{
171+
unsigned int hi, hi2, lo;
172+
u64 count;
173+
174+
mips_cm_lock_other(0, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL);
175+
176+
if (mips_cm_is64) {
177+
count = read_gic_redir_counter();
178+
goto out;
179+
}
180+
181+
hi = read_gic_redir_counter_32h();
182+
while (true) {
183+
lo = read_gic_redir_counter_32l();
184+
185+
/* If hi didn't change then lo didn't wrap & we're done */
186+
hi2 = read_gic_redir_counter_32h();
187+
if (hi2 == hi)
188+
break;
189+
190+
/* Otherwise, repeat with the latest hi value */
191+
hi = hi2;
192+
}
193+
194+
count = (((u64)hi) << 32) + lo;
195+
out:
196+
mips_cm_unlock_other();
197+
return count;
198+
}
199+
169200
static struct clocksource gic_clocksource = {
170201
.name = "GIC",
171202
.read = gic_hpt_read,
@@ -203,6 +234,11 @@ static int __init __gic_clocksource_init(void)
203234
gic_clocksource.rating = 200;
204235
gic_clocksource.rating += clamp(gic_frequency / 10000000, 0, 99);
205236

237+
if (mips_cps_multicluster_cpus()) {
238+
gic_clocksource.read = &gic_hpt_read_multicluster;
239+
gic_clocksource.vdso_clock_mode = VDSO_CLOCKMODE_NONE;
240+
}
241+
206242
ret = clocksource_register_hz(&gic_clocksource, gic_frequency);
207243
if (ret < 0)
208244
pr_warn("Unable to register clocksource\n");
@@ -261,7 +297,8 @@ static int __init gic_clocksource_of_init(struct device_node *node)
261297
* stable CPU frequency or on the platforms with CM3 and CPU frequency
262298
* change performed by the CPC core clocks divider.
263299
*/
264-
if (mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ)) {
300+
if ((mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ)) &&
301+
!mips_cps_multicluster_cpus()) {
265302
sched_clock_register(mips_cm_is64 ?
266303
gic_read_count_64 : gic_read_count_2x32,
267304
gic_count_width, gic_frequency);

0 commit comments

Comments
 (0)