Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

timekeeping: Add function to convert realtime to base clock

PPS (Pulse Per Second) generates a hardware pulse every second based on
CLOCK_REALTIME. This works fine when the pulse is generated in software
from a hrtimer callback function.

For hardware which generates the pulse by programming a timer it is
required to convert CLOCK_REALTIME to the underlying hardware clock.

The X86 Timed IO device is based on the Always Running Timer (ART), which
is the base clock of the TSC, which is usually the system clocksource on
X86.

The core code already has functionality to convert base clock timestamps to
system clocksource timestamps, but there is no support for converting the
other way around.

Provide the required functionality to support such devices in a generic
way to avoid code duplication in drivers:

1) ktime_real_to_base_clock() to convert a CLOCK_REALTIME timestamp to a
base clock timestamp

2) timekeeping_clocksource_has_base() to allow drivers to validate that
the system clocksource is based on a particular clocksource ID.

[ tglx: Simplify timekeeping_clocksource_has_base() and add missing READ_ONCE() ]

Co-developed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Co-developed-by: Christopher S. Hall <christopher.s.hall@intel.com>
Signed-off-by: Christopher S. Hall <christopher.s.hall@intel.com>
Signed-off-by: Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20240513103813.5666-10-lakshmi.sowjanya.d@intel.com

authored by

Lakshmi Sowjanya D and committed by
Thomas Gleixner
02ecee07 0f532a78

+90
+4
include/linux/timekeeping.h
··· 318 318 bool use_nsecs; 319 319 }; 320 320 321 + extern bool ktime_real_to_base_clock(ktime_t treal, 322 + enum clocksource_ids base_id, u64 *cycles); 323 + extern bool timekeeping_clocksource_has_base(enum clocksource_ids id); 324 + 321 325 /* 322 326 * Get cross timestamp between system clock and device clock 323 327 */
+86
kernel/time/timekeeping.c
··· 1235 1235 return true; 1236 1236 } 1237 1237 1238 + static bool convert_cs_to_base(u64 *cycles, enum clocksource_ids base_id) 1239 + { 1240 + struct clocksource *cs = tk_core.timekeeper.tkr_mono.clock; 1241 + struct clocksource_base *base; 1242 + 1243 + /* 1244 + * Check whether base_id matches the base clock. Prevent the compiler from 1245 + * re-evaluating @base as the clocksource might change concurrently. 1246 + */ 1247 + base = READ_ONCE(cs->base); 1248 + if (!base || base->id != base_id) 1249 + return false; 1250 + 1251 + *cycles -= base->offset; 1252 + if (!convert_clock(cycles, base->denominator, base->numerator)) 1253 + return false; 1254 + return true; 1255 + } 1256 + 1257 + static bool convert_ns_to_cs(u64 *delta) 1258 + { 1259 + struct tk_read_base *tkr = &tk_core.timekeeper.tkr_mono; 1260 + 1261 + if (BITS_TO_BYTES(fls64(*delta) + tkr->shift) >= sizeof(*delta)) 1262 + return false; 1263 + 1264 + *delta = div_u64((*delta << tkr->shift) - tkr->xtime_nsec, tkr->mult); 1265 + return true; 1266 + } 1267 + 1268 + /** 1269 + * ktime_real_to_base_clock() - Convert CLOCK_REALTIME timestamp to a base clock timestamp 1270 + * @treal: CLOCK_REALTIME timestamp to convert 1271 + * @base_id: base clocksource id 1272 + * @cycles: pointer to store the converted base clock timestamp 1273 + * 1274 + * Converts a supplied, future realtime clock value to the corresponding base clock value. 1275 + * 1276 + * Return: true if the conversion is successful, false otherwise. 1277 + */ 1278 + bool ktime_real_to_base_clock(ktime_t treal, enum clocksource_ids base_id, u64 *cycles) 1279 + { 1280 + struct timekeeper *tk = &tk_core.timekeeper; 1281 + unsigned int seq; 1282 + u64 delta; 1283 + 1284 + do { 1285 + seq = read_seqcount_begin(&tk_core.seq); 1286 + if ((u64)treal < tk->tkr_mono.base_real) 1287 + return false; 1288 + delta = (u64)treal - tk->tkr_mono.base_real; 1289 + if (!convert_ns_to_cs(&delta)) 1290 + return false; 1291 + *cycles = tk->tkr_mono.cycle_last + delta; 1292 + if (!convert_cs_to_base(cycles, base_id)) 1293 + return false; 1294 + } while (read_seqcount_retry(&tk_core.seq, seq)); 1295 + 1296 + return true; 1297 + } 1298 + EXPORT_SYMBOL_GPL(ktime_real_to_base_clock); 1299 + 1238 1300 /** 1239 1301 * get_device_system_crosststamp - Synchronously capture system/device timestamp 1240 1302 * @get_time_fn: Callback to get simultaneous device time and ··· 1407 1345 return 0; 1408 1346 } 1409 1347 EXPORT_SYMBOL_GPL(get_device_system_crosststamp); 1348 + 1349 + /** 1350 + * timekeeping_clocksource_has_base - Check whether the current clocksource 1351 + * is based on given a base clock 1352 + * @id: base clocksource ID 1353 + * 1354 + * Note: The return value is a snapshot which can become invalid right 1355 + * after the function returns. 1356 + * 1357 + * Return: true if the timekeeper clocksource has a base clock with @id, 1358 + * false otherwise 1359 + */ 1360 + bool timekeeping_clocksource_has_base(enum clocksource_ids id) 1361 + { 1362 + /* 1363 + * This is a snapshot, so no point in using the sequence 1364 + * count. Just prevent the compiler from re-evaluating @base as the 1365 + * clocksource might change concurrently. 1366 + */ 1367 + struct clocksource_base *base = READ_ONCE(tk_core.timekeeper.tkr_mono.clock->base); 1368 + 1369 + return base ? base->id == id : false; 1370 + } 1371 + EXPORT_SYMBOL_GPL(timekeeping_clocksource_has_base); 1410 1372 1411 1373 /** 1412 1374 * do_settimeofday64 - Sets the time of day.