History

Merge tag 'timers-ptp-2026-06-13' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip

Pull timekeeping updates from Thomas Gleixner: "Updates for NTP/timekeeping and PTP: - Expand timekeeping snapshot mechanisms The various snapshot functions are mostly used for PTP to collect "atomic" snapshots of various involved clocks. They lack support for the recently introduced AUX clocks and do not provide the underlying counter value (e.g. TSC) to user space. Exposing the counter value snapshot allows for better control and steering. Convert the hard wired ktime_get_snapshot() to take a clock ID, which allows the caller to select the clock ID to be captured along with CLOCK_MONONOTONIC_RAW. Additionally capture the underlying hardware counter value and the clock source ID of the counter. Expand the hardware based snapshot capture where devices provide a mechanism to snapshot the hardware PTP clock and the system counter (usually via PCI/PTM) to support AUX clocks and also provide the captured counter value back to the caller and not only the clock timestamps derived from it. - Add a new optional read_snapshot() callback to clocksources That is required to capture atomic snapshots from clocksources which are derived from TSC with a scaling mechanism (e.g. Hyper-V, KVMclock). The value pair is handed back in the snapshot structure to the callers, so they can do the necessary correlations in a more precise way. This touches usage sites of the affected functions and data structure all over the tree, but stays fully backwards compatible for the existing user space exposed interfaces. New PTP IOCTLs will provide access to the extended functionality in later kernel versions" * tag 'timers-ptp-2026-06-13' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip: (28 commits) ptp: vmclock: Use hw_cycles from snapshot for precise TSC pairing x86/kvmclock: Implement read_snapshot() for kvmclock clocksource clocksource/hyperv: Implement read_snapshot() for TSC page clocksource timekeeping: Add clocksource read_snapshot() method and hw_cycles to snapshot ptp: Switch to ktime_get_snapshot_id() for pre/post timestamps timekeeping: Add support for AUX clock cross timestamping timekeeping: Remove system_device_crosststamp::sys_realtime ALSA: hda/common: Use system_device_crosststamp::sys_systime wifi: iwlwifi: Use system_device_crosststamp::sys_systime ptp: Use system_device_crosststamp::sys_systime timekeeping: Prepare for cross timestamps on arbitrary clock IDs timekeeping: Remove ktime_get_snapshot() virtio_rtc: Use provided clock ID for history snapshot net/mlx5: Use provided clock ID for history snapshot igc: Use provided clock ID for history snapshot ice/ptp: Use provided clock ID for history snapshot wifi: iwlwifi: Adopt PTP cross timestamps to core changes timekeeping: Add CLOCK ID to system_device_crosststamp timekeeping: Add system_counterval_t to struct system_device_crosststamp timekeeping: Add CLOCK_AUX support for ktime_get_snapshot_id() ...

Linus Torvalds committed 5 months ago

Commit 2d6d57f2 parents a53fcff bc484a523 files · +348 −194Browse files

Showing the changes to kernel (1 of 23 files). Show all

Unified · Split

kernel/time/timekeeping.c+158−77
@@ -67,6 +67,7 @@ static inline bool tk_is_aux(const struct timekeeper *tk) · 66 unmodified lines
6767 {
6868 return tk->id >= TIMEKEEPER_AUX_FIRST && tk->id <= TIMEKEEPER_AUX_LAST;
6969 }
70+static inline struct tk_data *aux_get_tk_data(clockid_t id);
7071 #else
7172 static inline bool tk_get_aux_ts64(unsigned int tkid, struct timespec64 *ts)
7273 {
@@ -77,6 +78,10 @@ static inline bool tk_is_aux(const struct timekeeper *tk) · 4 unmodified lines
7778 {
7879 return false;
7980 }
81+static inline struct tk_data *aux_get_tk_data(clockid_t id)
82+{
83+ return NULL;
84+}
8085 #endif
8186
8287 static inline void tk_update_aux_offs(struct timekeeper *tk, ktime_t offs)
@@ -315,6 +320,7 @@ static __always_inline u64 tk_clock_read(const struct tk_read_base *tkr) · 232 unmodified lines
315320
316321 return clock->read(clock);
317322 }
323+
318324 static inline void clocksource_disable_inline_read(void) { }
319325 static inline void clocksource_enable_inline_read(void) { }
320326 #endif
@@ -1182,44 +1188,107 @@ noinstr time64_t __ktime_get_real_seconds(void) · 861 unmodified lines
11821188 return tk->xtime_sec;
11831189 }
11841190
1185−/**
1186− * ktime_get_snapshot - snapshots the realtime/monotonic raw clocks with counter
1187− * @systime_snapshot: pointer to struct receiving the system time snapshot
1188− */
1189−void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
1191+static inline u64 tk_clock_read_snapshot(const struct tk_read_base *tkr,
1192+ struct clocksource_hw_snapshot *chs)
11901193 {
1191− struct timekeeper *tk = &tk_core.timekeeper;
1194+ struct clocksource *clock = READ_ONCE(tkr->clock);
1195+
1196+ if (unlikely(clock->read_snapshot))
1197+ return clock->read_snapshot(clock, chs);
1198+
1199+ return clock->read(clock);
1200+}
1201+
1202+
1203+/**
1204+ * ktime_get_snapshot_id - Simultaneously snapshot a given clock ID with
1205+ * CLOCK_MONOTONIC_RAW and the underlying
1206+ * clocksource counter value.
1207+ * @clock_id: The clock ID to snapshot
1208+ * @systime_snapshot: Pointer to struct receiving the system time snapshot
1209+ */
1210+void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *systime_snapshot)
1211+{
1212+ ktime_t base_raw, base_sys, offs_sys, *offs, offs_zero = 0;
1213+ u64 nsec_raw, nsec_sys, now;
1214+ struct timekeeper *tk;
1215+ struct tk_data *tkd;
11921216 unsigned int seq;
1193− ktime_t base_raw;
1194− ktime_t base_real;
1195− ktime_t base_boot;
1196− u64 nsec_raw;
1197− u64 nsec_real;
1198− u64 now;
11991217
1200− WARN_ON_ONCE(timekeeping_suspended);
1218+ /* Invalidate the snapshot for all failure cases */
1219+ systime_snapshot->valid = false;
1220+
1221+ if (WARN_ON_ONCE(timekeeping_suspended))
1222+ return;
1223+
1224+ switch (clock_id) {
1225+ case CLOCK_REALTIME:
1226+ tkd = &tk_core;
1227+ offs = &tk_core.timekeeper.offs_real;
1228+ break;
1229+ /* Map RAW to MONOTONIC so the loop below is trivial */
1230+ case CLOCK_MONOTONIC_RAW:
1231+ case CLOCK_MONOTONIC:
1232+ tkd = &tk_core;
1233+ offs = &offs_zero;
1234+ break;
1235+ case CLOCK_BOOTTIME:
1236+ tkd = &tk_core;
1237+ offs = &tk_core.timekeeper.offs_boot;
1238+ break;
1239+ case CLOCK_AUX ... CLOCK_AUX_LAST:
1240+ tkd = aux_get_tk_data(clock_id);
1241+ if (!tkd)
1242+ return;
1243+ offs = &tkd->timekeeper.offs_aux;
1244+ break;
1245+ default:
1246+ WARN_ON_ONCE(1);
1247+ return;
1248+ }
1249+
1250+ tk = &tkd->timekeeper;
12011251
12021252 do {
1203− seq = read_seqcount_begin(&tk_core.seq);
1204− now = tk_clock_read(&tk->tkr_mono);
1253+ struct clocksource_hw_snapshot chs = { };
1254+
1255+ seq = read_seqcount_begin(&tkd->seq);
1256+
1257+ /* Aux clocks can be invalid */
1258+ if (!tk->clock_valid)
1259+ return;
1260+
1261+ now = tk_clock_read_snapshot(&tk->tkr_mono, &chs);
12051262 systime_snapshot->cs_id = tk->tkr_mono.clock->id;
1263+
1264+ systime_snapshot->hw_cycles = chs.hw_cycles;
1265+ systime_snapshot->hw_csid = chs.hw_csid;
1266+
12061267 systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq;
12071268 systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq;
1208− base_real = ktime_add(tk->tkr_mono.base,
1209− tk_core.timekeeper.offs_real);
1210− base_boot = ktime_add(tk->tkr_mono.base,
1211− tk_core.timekeeper.offs_boot);
1269+
1270+ base_sys = tk->tkr_mono.base;
1271+ offs_sys = *offs;
12121272 base_raw = tk->tkr_raw.base;
1213− nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, now);
1214− nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now);
1215− } while (read_seqcount_retry(&tk_core.seq, seq));
1273+
1274+ nsec_sys = timekeeping_cycles_to_ns(&tk->tkr_mono, now);
1275+ nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now);
1276+ } while (read_seqcount_retry(&tkd->seq, seq));
12161277
12171278 systime_snapshot->cycles = now;
1218− systime_snapshot->real = ktime_add_ns(base_real, nsec_real);
1219− systime_snapshot->boot = ktime_add_ns(base_boot, nsec_real);
1220− systime_snapshot->raw = ktime_add_ns(base_raw, nsec_raw);
1279+ systime_snapshot->systime = ktime_add_ns(base_sys, offs_sys + nsec_sys);
1280+ systime_snapshot->monoraw = ktime_add_ns(base_raw, nsec_raw);
1281+
1282+ /*
1283+ * Special case for PTP. Just transfer the raw time into sys,
1284+ * so the call sites can consistently use snap::systime.
1285+ */
1286+ if (clock_id == CLOCK_MONOTONIC_RAW)
1287+ systime_snapshot->systime = systime_snapshot->monoraw;
1288+ /* Tell the consumer that this snapshot is valid */
1289+ systime_snapshot->valid = true;
12211290 }
1222−EXPORT_SYMBOL_GPL(ktime_get_snapshot);
1291+EXPORT_SYMBOL_GPL(ktime_get_snapshot_id);
12231292
12241293 /* Scale base by mult/div checking for overflow */
12251294 static int scale64_check_overflow(u64 mult, u64 div, u64 *base)
@@ -1262,7 +1331,7 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, · 36 unmodified lines
12621331 struct system_device_crosststamp *ts)
12631332 {
12641333 struct timekeeper *tk = &tk_core.timekeeper;
1265− u64 corr_raw, corr_real;
1334+ u64 corr_raw, corr_sys;
12661335 bool interp_forward;
12671336 int ret;
12681337
@@ -1279,8 +1348,7 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, · 10 unmodified lines
12791348 * Scale the monotonic raw time delta by:
12801349 * partial_history_cycles / total_history_cycles
12811350 */
1282− corr_raw = (u64)ktime_to_ns(
1283− ktime_sub(ts->sys_monoraw, history->raw));
1351+ corr_raw = (u64)ktime_to_ns(ktime_sub(ts->sys_monoraw, history->monoraw));
12841352 ret = scale64_check_overflow(partial_history_cycles,
12851353 total_history_cycles, &corr_raw);
12861354 if (ret)
@@ -1288,30 +1356,29 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, · 1 unmodified line
12881356
12891357 /*
12901358 * If there is a discontinuity in the history, scale monotonic raw
1291− * correction by:
1292− * mult(real)/mult(raw) yielding the realtime correction
1293− * Otherwise, calculate the realtime correction similar to monotonic
1294− * raw calculation
1359+ * correction by:
1360+ * mult(sys)/mult(raw) yielding the system time correction
1361+ *
1362+ * Otherwise, calculate the system time correction similar to monotonic
1363+ * raw calculation
12951364 */
12961365 if (discontinuity) {
1297− corr_real = mul_u64_u32_div
1298− (corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult);
1366+ corr_sys = mul_u64_u32_div(corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult);
12991367 } else {
1300− corr_real = (u64)ktime_to_ns(
1301− ktime_sub(ts->sys_realtime, history->real));
1302− ret = scale64_check_overflow(partial_history_cycles,
1303− total_history_cycles, &corr_real);
1368+ corr_sys = (u64)ktime_to_ns(ktime_sub(ts->sys_systime, history->systime));
1369+ ret = scale64_check_overflow(partial_history_cycles, total_history_cycles,
1370+ &corr_sys);
13041371 if (ret)
13051372 return ret;
13061373 }
13071374
1308− /* Fixup monotonic raw and real time time values */
1375+ /* Fixup monotonic raw and system time time values */
13091376 if (interp_forward) {
1310− ts->sys_monoraw = ktime_add_ns(history->raw, corr_raw);
1311− ts->sys_realtime = ktime_add_ns(history->real, corr_real);
1377+ ts->sys_monoraw = ktime_add_ns(history->monoraw, corr_raw);
1378+ ts->sys_systime = ktime_add_ns(history->systime, corr_sys);
13121379 } else {
13131380 ts->sys_monoraw = ktime_sub_ns(ts->sys_monoraw, corr_raw);
1314− ts->sys_realtime = ktime_sub_ns(ts->sys_realtime, corr_real);
1381+ ts->sys_systime = ktime_sub_ns(ts->sys_systime, corr_sys);
13151382 }
13161383
13171384 return 0;
@@ -1368,6 +1435,8 @@ static bool convert_base_to_cs(struct system_counterval_t *scv) · 50 unmodified lines
13681435 return false;
13691436
13701437 scv->cycles += base->offset;
1438+ /* Set the clocksource ID as scv::cycles is now clocksource based */
1439+ scv->cs_id = cs->id;
13711440 return true;
13721441 }
13731442
@@ -1435,11 +1504,11 @@ EXPORT_SYMBOL_GPL(ktime_real_to_base_clock); · 61 unmodified lines
14351504
14361505 /**
14371506 * get_device_system_crosststamp - Synchronously capture system/device timestamp
1438− * @get_time_fn: Callback to get simultaneous device time and
1439− * system counter from the device driver
1507+ * @get_time_fn: Callback to get simultaneous device time and system counter
1508+ * from the device driver
14401509 * @ctx: Context passed to get_time_fn()
1441− * @history_begin: Historical reference point used to interpolate system
1442− * time when counter provided by the driver is before the current interval
1510+ * @history_begin: Historical reference point used to interpolate system time when
1511+ * the counter value provided by the driver is before the current interval
14431512 * @xtstamp: Receives simultaneously captured system and device time
14441513 *
14451514 * Reads a timestamp from a device and correlates it to system time
@@ -1452,36 +1521,54 @@ int get_device_system_crosststamp(int (*get_time_fn) · 6 unmodified lines
14521521 struct system_time_snapshot *history_begin,
14531522 struct system_device_crosststamp *xtstamp)
14541523 {
1455− struct system_counterval_t system_counterval = {};
1456− struct timekeeper *tk = &tk_core.timekeeper;
1457− u64 cycles, now, interval_start;
1458− unsigned int clock_was_set_seq = 0;
1459− ktime_t base_real, base_raw;
1460− u64 nsec_real, nsec_raw;
1524+ u64 syscnt_cycles, cycles, now, interval_start;
1525+ unsigned int seq, clock_was_set_seq = 0;
1526+ ktime_t base_sys, base_raw, *offs;
1527+ u64 nsec_sys, nsec_raw;
14611528 u8 cs_was_changed_seq;
1462− unsigned int seq;
14631529 bool do_interp;
1530+ struct timekeeper *tk;
1531+ struct tk_data *tkd;
14641532 int ret;
14651533
1534+ switch (xtstamp->clock_id) {
1535+ case CLOCK_REALTIME:
1536+ tkd = &tk_core;
1537+ offs = &tk_core.timekeeper.offs_real;
1538+ break;
1539+ case CLOCK_AUX ... CLOCK_AUX_LAST:
1540+ tkd = aux_get_tk_data(xtstamp->clock_id);
1541+ if (!tkd)
1542+ return -ENODEV;
1543+ offs = &tkd->timekeeper.offs_aux;
1544+ break;
1545+ default:
1546+ WARN_ON_ONCE(1);
1547+ return -ENODEV;
1548+ }
1549+
1550+ tk = &tkd->timekeeper;
1551+
14661552 do {
1467− seq = read_seqcount_begin(&tk_core.seq);
1553+ seq = read_seqcount_begin(&tkd->seq);
14681554 /*
14691555 * Try to synchronously capture device time and a system
14701556 * counter value calling back into the device driver
14711557 */
1472− ret = get_time_fn(&xtstamp->device, &system_counterval, ctx);
1558+ ret = get_time_fn(&xtstamp->device, &xtstamp->sys_counter, ctx);
14731559 if (ret)
14741560 return ret;
14751561
14761562 /*
14771563 * Verify that the clocksource ID associated with the captured
14781564 * system counter value is the same as for the currently
1479− * installed timekeeper clocksource
1565+ * installed timekeeper clocksource and convert to it.
14801566 */
1481− if (system_counterval.cs_id == CSID_GENERIC ||
1482− !convert_base_to_cs(&system_counterval))
1567+ if (xtstamp->sys_counter.cs_id == CSID_GENERIC ||
1568+ !convert_base_to_cs(&xtstamp->sys_counter))
14831569 return -ENODEV;
1484− cycles = system_counterval.cycles;
1570+
1571+ cycles = syscnt_cycles = xtstamp->sys_counter.cycles;
14851572
14861573 /*
14871574 * Check whether the system counter value provided by the
@@ -1498,15 +1585,14 @@ int get_device_system_crosststamp(int (*get_time_fn) · 10 unmodified lines
14981585 do_interp = false;
14991586 }
15001587
1501− base_real = ktime_add(tk->tkr_mono.base,
1502− tk_core.timekeeper.offs_real);
1588+ base_sys = ktime_add(tk->tkr_mono.base, *offs);
15031589 base_raw = tk->tkr_raw.base;
15041590
1505− nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, cycles);
1591+ nsec_sys = timekeeping_cycles_to_ns(&tk->tkr_mono, cycles);
15061592 nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, cycles);
1507− } while (read_seqcount_retry(&tk_core.seq, seq));
1593+ } while (read_seqcount_retry(&tkd->seq, seq));
15081594
1509− xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real);
1595+ xtstamp->sys_systime = ktime_add_ns(base_sys, nsec_sys);
15101596 xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw);
15111597
15121598 /*
@@ -1523,24 +1609,19 @@ int get_device_system_crosststamp(int (*get_time_fn) · 10 unmodified lines
15231609 * clocksource change
15241610 */
15251611 if (!history_begin ||
1526− !timestamp_in_interval(history_begin->cycles,
1527− cycles, system_counterval.cycles) ||
1612+ !timestamp_in_interval(history_begin->cycles, cycles, syscnt_cycles) ||
15281613 history_begin->cs_was_changed_seq != cs_was_changed_seq)
15291614 return -EINVAL;
1530− partial_history_cycles = cycles - system_counterval.cycles;
1615+
1616+ partial_history_cycles = cycles - syscnt_cycles;
15311617 total_history_cycles = cycles - history_begin->cycles;
1532− discontinuity =
1533− history_begin->clock_was_set_seq != clock_was_set_seq;
1618+ discontinuity = history_begin->clock_was_set_seq != clock_was_set_seq;
15341619
1535− ret = adjust_historical_crosststamp(history_begin,
1536− partial_history_cycles,
1537− total_history_cycles,
1538− discontinuity, xtstamp);
1539− if (ret)
1540− return ret;
1620+ ret = adjust_historical_crosststamp(history_begin, partial_history_cycles,
1621+ total_history_cycles, discontinuity, xtstamp);
15411622 }
15421623
1543− return 0;
1624+ return ret;
15441625 }
15451626 EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
15461627

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t