Skip to content

Commit 593b876

Browse files
committed
timekeeping: Add function to convert realtime to base clock
JIRA: https://issues.redhat.com/browse/RHEL-61639 commit 02ecee0 Author: Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com> Date: Mon May 13 16:08:10 2024 +0530 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 Signed-off-by: Ivan Vecera <ivecera@redhat.com>
1 parent ff1d72a commit 593b876

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

include/linux/timekeeping.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ struct system_counterval_t {
282282
bool use_nsecs;
283283
};
284284

285+
extern bool ktime_real_to_base_clock(ktime_t treal,
286+
enum clocksource_ids base_id, u64 *cycles);
287+
extern bool timekeeping_clocksource_has_base(enum clocksource_ids id);
288+
285289
/*
286290
* Get cross timestamp between system clock and device clock
287291
*/

kernel/time/timekeeping.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,68 @@ static bool convert_base_to_cs(struct system_counterval_t *scv)
12311231
return true;
12321232
}
12331233

1234+
static bool convert_cs_to_base(u64 *cycles, enum clocksource_ids base_id)
1235+
{
1236+
struct clocksource *cs = tk_core.timekeeper.tkr_mono.clock;
1237+
struct clocksource_base *base;
1238+
1239+
/*
1240+
* Check whether base_id matches the base clock. Prevent the compiler from
1241+
* re-evaluating @base as the clocksource might change concurrently.
1242+
*/
1243+
base = READ_ONCE(cs->base);
1244+
if (!base || base->id != base_id)
1245+
return false;
1246+
1247+
*cycles -= base->offset;
1248+
if (!convert_clock(cycles, base->denominator, base->numerator))
1249+
return false;
1250+
return true;
1251+
}
1252+
1253+
static bool convert_ns_to_cs(u64 *delta)
1254+
{
1255+
struct tk_read_base *tkr = &tk_core.timekeeper.tkr_mono;
1256+
1257+
if (BITS_TO_BYTES(fls64(*delta) + tkr->shift) >= sizeof(*delta))
1258+
return false;
1259+
1260+
*delta = div_u64((*delta << tkr->shift) - tkr->xtime_nsec, tkr->mult);
1261+
return true;
1262+
}
1263+
1264+
/**
1265+
* ktime_real_to_base_clock() - Convert CLOCK_REALTIME timestamp to a base clock timestamp
1266+
* @treal: CLOCK_REALTIME timestamp to convert
1267+
* @base_id: base clocksource id
1268+
* @cycles: pointer to store the converted base clock timestamp
1269+
*
1270+
* Converts a supplied, future realtime clock value to the corresponding base clock value.
1271+
*
1272+
* Return: true if the conversion is successful, false otherwise.
1273+
*/
1274+
bool ktime_real_to_base_clock(ktime_t treal, enum clocksource_ids base_id, u64 *cycles)
1275+
{
1276+
struct timekeeper *tk = &tk_core.timekeeper;
1277+
unsigned int seq;
1278+
u64 delta;
1279+
1280+
do {
1281+
seq = read_seqcount_begin(&tk_core.seq);
1282+
if ((u64)treal < tk->tkr_mono.base_real)
1283+
return false;
1284+
delta = (u64)treal - tk->tkr_mono.base_real;
1285+
if (!convert_ns_to_cs(&delta))
1286+
return false;
1287+
*cycles = tk->tkr_mono.cycle_last + delta;
1288+
if (!convert_cs_to_base(cycles, base_id))
1289+
return false;
1290+
} while (read_seqcount_retry(&tk_core.seq, seq));
1291+
1292+
return true;
1293+
}
1294+
EXPORT_SYMBOL_GPL(ktime_real_to_base_clock);
1295+
12341296
/**
12351297
* get_device_system_crosststamp - Synchronously capture system/device timestamp
12361298
* @get_time_fn: Callback to get simultaneous device time and
@@ -1344,6 +1406,30 @@ int get_device_system_crosststamp(int (*get_time_fn)
13441406
}
13451407
EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
13461408

1409+
/**
1410+
* timekeeping_clocksource_has_base - Check whether the current clocksource
1411+
* is based on given a base clock
1412+
* @id: base clocksource ID
1413+
*
1414+
* Note: The return value is a snapshot which can become invalid right
1415+
* after the function returns.
1416+
*
1417+
* Return: true if the timekeeper clocksource has a base clock with @id,
1418+
* false otherwise
1419+
*/
1420+
bool timekeeping_clocksource_has_base(enum clocksource_ids id)
1421+
{
1422+
/*
1423+
* This is a snapshot, so no point in using the sequence
1424+
* count. Just prevent the compiler from re-evaluating @base as the
1425+
* clocksource might change concurrently.
1426+
*/
1427+
struct clocksource_base *base = READ_ONCE(tk_core.timekeeper.tkr_mono.clock->base);
1428+
1429+
return base ? base->id == id : false;
1430+
}
1431+
EXPORT_SYMBOL_GPL(timekeeping_clocksource_has_base);
1432+
13471433
/**
13481434
* do_settimeofday64 - Sets the time of day.
13491435
* @ts: pointer to the timespec64 variable containing the new time

0 commit comments

Comments
 (0)