Skip to content

Commit 2d9db77

Browse files
committed
Merge tag 'timers-core-2024-05-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timers and timekeeping updates from Thomas Gleixner: "Core code: - Make timekeeping and VDSO time readouts resilent against math overflow: In guest context the kernel is prone to math overflow when the host defers the timer interrupt due to overload, malfunction or malice. This can be mitigated by checking the clocksource delta for the maximum deferrement which is readily available. If that value is exceeded then the code uses a slowpath function which can handle the multiplication overflow. This functionality is enabled unconditionally in the kernel, but made conditional in the VDSO code. The latter is conditional because it allows architectures to optimize the check so it is not causing performance regressions. On X86 this is achieved by reworking the existing check for negative TSC deltas as a negative delta obviously exceeds the maximum deferrement when it is evaluated as an unsigned value. That avoids two conditionals in the hotpath and allows to hide both the negative delta and the large delta handling in the same slow path. - Add an initial minimal ktime_t abstraction for Rust - The usual boring cleanups and enhancements Drivers: - Boring updates to device trees and trivial enhancements in various drivers" * tag 'timers-core-2024-05-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (33 commits) clocksource/drivers/arm_arch_timer: Mark hisi_161010101_oem_info const clocksource/drivers/timer-ti-dm: Remove an unused field in struct dmtimer clocksource/drivers/renesas-ostm: Avoid reprobe after successful early probe clocksource/drivers/renesas-ostm: Allow OSTM driver to reprobe for RZ/V2H(P) SoC dt-bindings: timer: renesas: ostm: Document Renesas RZ/V2H(P) SoC rust: time: doc: Add missing C header links clocksource: Make the int help prompt unit readable in ncurses hrtimer: Rename __hrtimer_hres_active() to hrtimer_hres_active() timerqueue: Remove never used function timerqueue_node_expires() rust: time: Add Ktime vdso: Fix powerpc build U64_MAX undeclared error clockevents: Convert s[n]printf() to sysfs_emit() clocksource: Convert s[n]printf() to sysfs_emit() clocksource: Make watchdog and suspend-timing multiplication overflow safe timekeeping: Let timekeeping_cycles_to_ns() handle both under and overflow timekeeping: Make delta calculation overflow safe timekeeping: Prepare timekeeping_cycles_to_ns() for overflow safety timekeeping: Fold in timekeeping_delta_to_ns() timekeeping: Consolidate timekeeping helpers timekeeping: Refactor timekeeping helpers ...
2 parents 61deafa + a3825a7 commit 2d9db77

File tree

21 files changed

+284
-173
lines changed

21 files changed

+284
-173
lines changed

Documentation/devicetree/bindings/timer/renesas,ostm.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ properties:
2626
- renesas,r9a07g043-ostm # RZ/G2UL and RZ/Five
2727
- renesas,r9a07g044-ostm # RZ/G2{L,LC}
2828
- renesas,r9a07g054-ostm # RZ/V2L
29+
- renesas,r9a09g057-ostm # RZ/V2H(P)
2930
- const: renesas,ostm # Generic
3031

3132
reg:
@@ -58,6 +59,7 @@ if:
5859
- renesas,r9a07g043-ostm
5960
- renesas,r9a07g044-ostm
6061
- renesas,r9a07g054-ostm
62+
- renesas,r9a09g057-ostm
6163
then:
6264
required:
6365
- resets

arch/powerpc/include/asm/vdso/gettimeofday.h

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@
1313

1414
#define VDSO_HAS_TIME 1
1515

16+
/*
17+
* powerpc specific delta calculation.
18+
*
19+
* This variant removes the masking of the subtraction because the
20+
* clocksource mask of all VDSO capable clocksources on powerpc is U64_MAX
21+
* which would result in a pointless operation. The compiler cannot
22+
* optimize it away as the mask comes from the vdso data and is not compile
23+
* time constant.
24+
*/
25+
#define VDSO_DELTA_NOMASK 1
26+
1627
static __always_inline int do_syscall_2(const unsigned long _r0, const unsigned long _r3,
1728
const unsigned long _r4)
1829
{
@@ -104,21 +115,6 @@ static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
104115
}
105116
#define vdso_clocksource_ok vdso_clocksource_ok
106117

107-
/*
108-
* powerpc specific delta calculation.
109-
*
110-
* This variant removes the masking of the subtraction because the
111-
* clocksource mask of all VDSO capable clocksources on powerpc is U64_MAX
112-
* which would result in a pointless operation. The compiler cannot
113-
* optimize it away as the mask comes from the vdso data and is not compile
114-
* time constant.
115-
*/
116-
static __always_inline u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
117-
{
118-
return (cycles - last) * mult;
119-
}
120-
#define vdso_calc_delta vdso_calc_delta
121-
122118
#ifndef __powerpc64__
123119
static __always_inline u64 vdso_shift_ns(u64 ns, unsigned long shift)
124120
{

arch/s390/include/asm/vdso/gettimeofday.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@
66

77
#define VDSO_HAS_CLOCK_GETRES 1
88

9+
#define VDSO_DELTA_NOMASK 1
10+
911
#include <asm/syscall.h>
1012
#include <asm/timex.h>
1113
#include <asm/unistd.h>
1214
#include <linux/compiler.h>
1315

14-
#define vdso_calc_delta __arch_vdso_calc_delta
15-
static __always_inline u64 __arch_vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
16-
{
17-
return (cycles - last) * mult;
18-
}
1916

2017
static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
2118
{

arch/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ config X86
169169
select GENERIC_TIME_VSYSCALL
170170
select GENERIC_GETTIMEOFDAY
171171
select GENERIC_VDSO_TIME_NS
172+
select GENERIC_VDSO_OVERFLOW_PROTECT
172173
select GUP_GET_PXX_LOW_HIGH if X86_PAE
173174
select HARDIRQS_SW_RESEND
174175
select HARDLOCKUP_CHECK_TIMESTAMP if X86_64

arch/x86/include/asm/vdso/gettimeofday.h

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -300,42 +300,54 @@ static inline bool arch_vdso_cycles_ok(u64 cycles)
300300
#define vdso_cycles_ok arch_vdso_cycles_ok
301301

302302
/*
303-
* x86 specific delta calculation.
303+
* x86 specific calculation of nanoseconds for the current cycle count
304304
*
305305
* The regular implementation assumes that clocksource reads are globally
306306
* monotonic. The TSC can be slightly off across sockets which can cause
307307
* the regular delta calculation (@cycles - @last) to return a huge time
308308
* jump.
309309
*
310310
* Therefore it needs to be verified that @cycles are greater than
311-
* @last. If not then use @last, which is the base time of the current
312-
* conversion period.
311+
* @vd->cycles_last. If not then use @vd->cycles_last, which is the base
312+
* time of the current conversion period.
313313
*
314314
* This variant also uses a custom mask because while the clocksource mask of
315315
* all the VDSO capable clocksources on x86 is U64_MAX, the above code uses
316316
* U64_MASK as an exception value, additionally arch_vdso_cycles_ok() above
317317
* declares everything with the MSB/Sign-bit set as invalid. Therefore the
318318
* effective mask is S64_MAX.
319319
*/
320-
static __always_inline
321-
u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
320+
static __always_inline u64 vdso_calc_ns(const struct vdso_data *vd, u64 cycles, u64 base)
322321
{
323-
/*
324-
* Due to the MSB/Sign-bit being used as invalid marker (see
325-
* arch_vdso_cycles_valid() above), the effective mask is S64_MAX.
326-
*/
327-
u64 delta = (cycles - last) & S64_MAX;
322+
u64 delta = cycles - vd->cycle_last;
328323

329324
/*
330-
* Due to the above mentioned TSC wobbles, filter out negative motion.
331-
* Per the above masking, the effective sign bit is now bit 62.
325+
* Negative motion and deltas which can cause multiplication
326+
* overflow require special treatment. This check covers both as
327+
* negative motion is guaranteed to be greater than @vd::max_cycles
328+
* due to unsigned comparison.
329+
*
330+
* Due to the MSB/Sign-bit being used as invalid marker (see
331+
* arch_vdso_cycles_valid() above), the effective mask is S64_MAX,
332+
* but that case is also unlikely and will also take the unlikely path
333+
* here.
332334
*/
333-
if (unlikely(delta & (1ULL << 62)))
334-
return 0;
335+
if (unlikely(delta > vd->max_cycles)) {
336+
/*
337+
* Due to the above mentioned TSC wobbles, filter out
338+
* negative motion. Per the above masking, the effective
339+
* sign bit is now bit 62.
340+
*/
341+
if (delta & (1ULL << 62))
342+
return base >> vd->shift;
343+
344+
/* Handle multiplication overflow gracefully */
345+
return mul_u64_u32_add_u64_shr(delta & S64_MAX, vd->mult, base, vd->shift);
346+
}
335347

336-
return delta * mult;
348+
return ((delta * vd->mult) + base) >> vd->shift;
337349
}
338-
#define vdso_calc_delta vdso_calc_delta
350+
#define vdso_calc_ns vdso_calc_ns
339351

340352
#endif /* !__ASSEMBLY__ */
341353

drivers/clocksource/arm_arch_timer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ static u64 notrace hisi_161010101_read_cntvct_el0(void)
331331
return __hisi_161010101_read_reg(cntvct_el0);
332332
}
333333

334-
static struct ate_acpi_oem_info hisi_161010101_oem_info[] = {
334+
static const struct ate_acpi_oem_info hisi_161010101_oem_info[] = {
335335
/*
336336
* Note that trailing spaces are required to properly match
337337
* the OEM table information.

drivers/clocksource/renesas-ostm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ static int __init ostm_init(struct device_node *np)
210210
pr_info("%pOF: used for clock events\n", np);
211211
}
212212

213+
of_node_set_flag(np, OF_POPULATED);
213214
return 0;
214215

215216
err_cleanup:
@@ -224,7 +225,7 @@ static int __init ostm_init(struct device_node *np)
224225

225226
TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init);
226227

227-
#ifdef CONFIG_ARCH_RZG2L
228+
#if defined(CONFIG_ARCH_RZG2L) || defined(CONFIG_ARCH_R9A09G057)
228229
static int __init ostm_probe(struct platform_device *pdev)
229230
{
230231
struct device *dev = &pdev->dev;

drivers/clocksource/timer-ti-dm.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ struct dmtimer {
129129
void __iomem *func_base; /* function register base */
130130

131131
atomic_t enabled;
132-
unsigned long rate;
133132
unsigned reserved:1;
134133
unsigned posted:1;
135134
unsigned omap1:1;

include/linux/math64.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
#include <linux/types.h>
66
#include <linux/math.h>
7-
#include <vdso/math64.h>
87
#include <asm/div64.h>
8+
#include <vdso/math64.h>
99

1010
#if BITS_PER_LONG == 64
1111

@@ -179,16 +179,12 @@ static __always_inline u64 mul_u64_u64_shr(u64 a, u64 mul, unsigned int shift)
179179
#ifndef mul_u64_u32_shr
180180
static __always_inline u64 mul_u64_u32_shr(u64 a, u32 mul, unsigned int shift)
181181
{
182-
u32 ah, al;
182+
u32 ah = a >> 32, al = a;
183183
u64 ret;
184184

185-
al = a;
186-
ah = a >> 32;
187-
188185
ret = mul_u32_u32(al, mul) >> shift;
189186
if (ah)
190187
ret += mul_u32_u32(ah, mul) << (32 - shift);
191-
192188
return ret;
193189
}
194190
#endif /* mul_u64_u32_shr */

include/linux/timerqueue.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ static inline bool timerqueue_node_queued(struct timerqueue_node *node)
3737
return !RB_EMPTY_NODE(&node->node);
3838
}
3939

40-
static inline bool timerqueue_node_expires(struct timerqueue_node *node)
41-
{
42-
return node->expires;
43-
}
44-
4540
static inline void timerqueue_init_head(struct timerqueue_head *head)
4641
{
4742
head->rb_root = RB_ROOT_CACHED;

0 commit comments

Comments
 (0)