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
67{67{
68 return tk->id >= TIMEKEEPER_AUX_FIRST && tk->id <= TIMEKEEPER_AUX_LAST;68 return tk->id >= TIMEKEEPER_AUX_FIRST && tk->id <= TIMEKEEPER_AUX_LAST;
69}69}
70static inline struct tk_data *aux_get_tk_data(clockid_t id);
70#else71#else
71static inline bool tk_get_aux_ts64(unsigned int tkid, struct timespec64 *ts)72static inline bool tk_get_aux_ts64(unsigned int tkid, struct timespec64 *ts)
72{73{
@@ -77,6 +78,10 @@ static inline bool tk_is_aux(const struct timekeeper *tk) · 4 unmodified lines
77{78{
78 return false;79 return false;
79}80}
81static inline struct tk_data *aux_get_tk_data(clockid_t id)
82{
83 return NULL;
84}
80#endif85#endif
81 86
82static inline void tk_update_aux_offs(struct timekeeper *tk, ktime_t offs)87static 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
315 320
316 return clock->read(clock);321 return clock->read(clock);
317}322}
323
318static inline void clocksource_disable_inline_read(void) { }324static inline void clocksource_disable_inline_read(void) { }
319static inline void clocksource_enable_inline_read(void) { }325static inline void clocksource_enable_inline_read(void) { }
320#endif326#endif
@@ -1182,44 +1188,107 @@ noinstr time64_t __ktime_get_real_seconds(void) · 861 unmodified lines
1182 return tk->xtime_sec;1188 return tk->xtime_sec;
1183}1189}
1184 1190
1185/**1191static inline u64 tk_clock_read_snapshot(const struct tk_read_base *tkr,
1186 * ktime_get_snapshot - snapshots the realtime/monotonic raw clocks with counter1192 struct clocksource_hw_snapshot *chs)
1187 * @systime_snapshot: pointer to struct receiving the system time snapshot
1188 */
1189void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
1190{1193{
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 */
1210void 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;
1192 unsigned int seq;1216 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;
1199 1217
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;
1201 1251
1202 do {1252 do {
1203 seq = read_seqcount_begin(&tk_core.seq);1253 struct clocksource_hw_snapshot chs = { };
1204 now = tk_clock_read(&tk->tkr_mono);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);
1205 systime_snapshot->cs_id = tk->tkr_mono.clock->id;1262 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
1206 systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq;1267 systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq;
1207 systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq;1268 systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq;
1208 base_real = ktime_add(tk->tkr_mono.base,1269
1209 tk_core.timekeeper.offs_real);1270 base_sys = tk->tkr_mono.base;
1210 base_boot = ktime_add(tk->tkr_mono.base,1271 offs_sys = *offs;
1211 tk_core.timekeeper.offs_boot);
1212 base_raw = tk->tkr_raw.base;1272 base_raw = tk->tkr_raw.base;
1213 nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, now);1273
1214 nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now);1274 nsec_sys = timekeeping_cycles_to_ns(&tk->tkr_mono, now);
1215 } while (read_seqcount_retry(&tk_core.seq, seq));1275 nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now);
1276 } while (read_seqcount_retry(&tkd->seq, seq));
1216 1277
1217 systime_snapshot->cycles = now;1278 systime_snapshot->cycles = now;
1218 systime_snapshot->real = ktime_add_ns(base_real, nsec_real);1279 systime_snapshot->systime = ktime_add_ns(base_sys, offs_sys + nsec_sys);
1219 systime_snapshot->boot = ktime_add_ns(base_boot, nsec_real);1280 systime_snapshot->monoraw = ktime_add_ns(base_raw, nsec_raw);
1220 systime_snapshot->raw = 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;
1221}1290}
1222EXPORT_SYMBOL_GPL(ktime_get_snapshot);1291EXPORT_SYMBOL_GPL(ktime_get_snapshot_id);
1223 1292
1224/* Scale base by mult/div checking for overflow */1293/* Scale base by mult/div checking for overflow */
1225static int scale64_check_overflow(u64 mult, u64 div, u64 *base)1294static 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
1262 struct system_device_crosststamp *ts)1331 struct system_device_crosststamp *ts)
1263{1332{
1264 struct timekeeper *tk = &tk_core.timekeeper;1333 struct timekeeper *tk = &tk_core.timekeeper;
1265 u64 corr_raw, corr_real;1334 u64 corr_raw, corr_sys;
1266 bool interp_forward;1335 bool interp_forward;
1267 int ret;1336 int ret;
1268 1337
@@ -1279,8 +1348,7 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, · 10 unmodified lines
1279 * Scale the monotonic raw time delta by:1348 * Scale the monotonic raw time delta by:
1280 * partial_history_cycles / total_history_cycles1349 * partial_history_cycles / total_history_cycles
1281 */1350 */
1282 corr_raw = (u64)ktime_to_ns(1351 corr_raw = (u64)ktime_to_ns(ktime_sub(ts->sys_monoraw, history->monoraw));
1283 ktime_sub(ts->sys_monoraw, history->raw));
1284 ret = scale64_check_overflow(partial_history_cycles,1352 ret = scale64_check_overflow(partial_history_cycles,
1285 total_history_cycles, &corr_raw);1353 total_history_cycles, &corr_raw);
1286 if (ret)1354 if (ret)
@@ -1288,30 +1356,29 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, · 1 unmodified line
1288 1356
1289 /*1357 /*
1290 * If there is a discontinuity in the history, scale monotonic raw1358 * If there is a discontinuity in the history, scale monotonic raw
1291 * correction by:1359 * correction by:
1292 * mult(real)/mult(raw) yielding the realtime correction1360 * mult(sys)/mult(raw) yielding the system time correction
1293 * Otherwise, calculate the realtime correction similar to monotonic1361 *
1294 * raw calculation1362 * Otherwise, calculate the system time correction similar to monotonic
1363 * raw calculation
1295 */1364 */
1296 if (discontinuity) {1365 if (discontinuity) {
1297 corr_real = mul_u64_u32_div1366 corr_sys = mul_u64_u32_div(corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult);
1298 (corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult);
1299 } else {1367 } else {
1300 corr_real = (u64)ktime_to_ns(1368 corr_sys = (u64)ktime_to_ns(ktime_sub(ts->sys_systime, history->systime));
1301 ktime_sub(ts->sys_realtime, history->real));1369 ret = scale64_check_overflow(partial_history_cycles, total_history_cycles,
1302 ret = scale64_check_overflow(partial_history_cycles,1370 &corr_sys);
1303 total_history_cycles, &corr_real);
1304 if (ret)1371 if (ret)
1305 return ret;1372 return ret;
1306 }1373 }
1307 1374
1308 /* Fixup monotonic raw and real time time values */1375 /* Fixup monotonic raw and system time time values */
1309 if (interp_forward) {1376 if (interp_forward) {
1310 ts->sys_monoraw = ktime_add_ns(history->raw, corr_raw);1377 ts->sys_monoraw = ktime_add_ns(history->monoraw, corr_raw);
1311 ts->sys_realtime = ktime_add_ns(history->real, corr_real);1378 ts->sys_systime = ktime_add_ns(history->systime, corr_sys);
1312 } else {1379 } else {
1313 ts->sys_monoraw = ktime_sub_ns(ts->sys_monoraw, corr_raw);1380 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);
1315 }1382 }
1316 1383
1317 return 0;1384 return 0;
@@ -1368,6 +1435,8 @@ static bool convert_base_to_cs(struct system_counterval_t *scv) · 50 unmodified lines
1368 return false;1435 return false;
1369 1436
1370 scv->cycles += base->offset;1437 scv->cycles += base->offset;
1438 /* Set the clocksource ID as scv::cycles is now clocksource based */
1439 scv->cs_id = cs->id;
1371 return true;1440 return true;
1372}1441}
1373 1442
@@ -1435,11 +1504,11 @@ EXPORT_SYMBOL_GPL(ktime_real_to_base_clock); · 61 unmodified lines
1435 1504
1436/**1505/**
1437 * get_device_system_crosststamp - Synchronously capture system/device timestamp1506 * get_device_system_crosststamp - Synchronously capture system/device timestamp
1438 * @get_time_fn: Callback to get simultaneous device time and1507 * @get_time_fn: Callback to get simultaneous device time and system counter
1439 * system counter from the device driver1508 * from the device driver
1440 * @ctx: Context passed to get_time_fn()1509 * @ctx: Context passed to get_time_fn()
1441 * @history_begin: Historical reference point used to interpolate system1510 * @history_begin: Historical reference point used to interpolate system time when
1442 * time when counter provided by the driver is before the current interval1511 * the counter value provided by the driver is before the current interval
1443 * @xtstamp: Receives simultaneously captured system and device time1512 * @xtstamp: Receives simultaneously captured system and device time
1444 *1513 *
1445 * Reads a timestamp from a device and correlates it to system time1514 * 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
1452 struct system_time_snapshot *history_begin,1521 struct system_time_snapshot *history_begin,
1453 struct system_device_crosststamp *xtstamp)1522 struct system_device_crosststamp *xtstamp)
1454{1523{
1455 struct system_counterval_t system_counterval = {};1524 u64 syscnt_cycles, cycles, now, interval_start;
1456 struct timekeeper *tk = &tk_core.timekeeper;1525 unsigned int seq, clock_was_set_seq = 0;
1457 u64 cycles, now, interval_start;1526 ktime_t base_sys, base_raw, *offs;
1458 unsigned int clock_was_set_seq = 0;1527 u64 nsec_sys, nsec_raw;
1459 ktime_t base_real, base_raw;
1460 u64 nsec_real, nsec_raw;
1461 u8 cs_was_changed_seq;1528 u8 cs_was_changed_seq;
1462 unsigned int seq;
1463 bool do_interp;1529 bool do_interp;
1530 struct timekeeper *tk;
1531 struct tk_data *tkd;
1464 int ret;1532 int ret;
1465 1533
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
1466 do {1552 do {
1467 seq = read_seqcount_begin(&tk_core.seq);1553 seq = read_seqcount_begin(&tkd->seq);
1468 /*1554 /*
1469 * Try to synchronously capture device time and a system1555 * Try to synchronously capture device time and a system
1470 * counter value calling back into the device driver1556 * counter value calling back into the device driver
1471 */1557 */
1472 ret = get_time_fn(&xtstamp->device, &system_counterval, ctx);1558 ret = get_time_fn(&xtstamp->device, &xtstamp->sys_counter, ctx);
1473 if (ret)1559 if (ret)
1474 return ret;1560 return ret;
1475 1561
1476 /*1562 /*
1477 * Verify that the clocksource ID associated with the captured1563 * Verify that the clocksource ID associated with the captured
1478 * system counter value is the same as for the currently1564 * system counter value is the same as for the currently
1479 * installed timekeeper clocksource1565 * installed timekeeper clocksource and convert to it.
1480 */1566 */
1481 if (system_counterval.cs_id == CSID_GENERIC ||1567 if (xtstamp->sys_counter.cs_id == CSID_GENERIC ||
1482 !convert_base_to_cs(&system_counterval))1568 !convert_base_to_cs(&xtstamp->sys_counter))
1483 return -ENODEV;1569 return -ENODEV;
1484 cycles = system_counterval.cycles;1570
1571 cycles = syscnt_cycles = xtstamp->sys_counter.cycles;
1485 1572
1486 /*1573 /*
1487 * Check whether the system counter value provided by the1574 * 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
1498 do_interp = false;1585 do_interp = false;
1499 }1586 }
1500 1587
1501 base_real = ktime_add(tk->tkr_mono.base,1588 base_sys = ktime_add(tk->tkr_mono.base, *offs);
1502 tk_core.timekeeper.offs_real);
1503 base_raw = tk->tkr_raw.base;1589 base_raw = tk->tkr_raw.base;
1504 1590
1505 nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, cycles);1591 nsec_sys = timekeeping_cycles_to_ns(&tk->tkr_mono, cycles);
1506 nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, cycles);1592 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));
1508 1594
1509 xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real);1595 xtstamp->sys_systime = ktime_add_ns(base_sys, nsec_sys);
1510 xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw);1596 xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw);
1511 1597
1512 /*1598 /*
@@ -1523,24 +1609,19 @@ int get_device_system_crosststamp(int (*get_time_fn) · 10 unmodified lines
1523 * clocksource change1609 * clocksource change
1524 */1610 */
1525 if (!history_begin ||1611 if (!history_begin ||
1526 !timestamp_in_interval(history_begin->cycles,1612 !timestamp_in_interval(history_begin->cycles, cycles, syscnt_cycles) ||
1527 cycles, system_counterval.cycles) ||
1528 history_begin->cs_was_changed_seq != cs_was_changed_seq)1613 history_begin->cs_was_changed_seq != cs_was_changed_seq)
1529 return -EINVAL;1614 return -EINVAL;
1530 partial_history_cycles = cycles - system_counterval.cycles;1615
1616 partial_history_cycles = cycles - syscnt_cycles;
1531 total_history_cycles = cycles - history_begin->cycles;1617 total_history_cycles = cycles - history_begin->cycles;
1532 discontinuity =1618 discontinuity = history_begin->clock_was_set_seq != clock_was_set_seq;
1533 history_begin->clock_was_set_seq != clock_was_set_seq;
1534 1619
1535 ret = adjust_historical_crosststamp(history_begin,1620 ret = adjust_historical_crosststamp(history_begin, partial_history_cycles,
1536 partial_history_cycles,1621 total_history_cycles, discontinuity, xtstamp);
1537 total_history_cycles,
1538 discontinuity, xtstamp);
1539 if (ret)
1540 return ret;
1541 }1622 }
1542 1623
1543 return 0;1624 return ret;
1544}1625}
1545EXPORT_SYMBOL_GPL(get_device_system_crosststamp);1626EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
1546 1627

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