Commit 2d9db778 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
  ...
parents 61deafa9 a3825a76
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ properties:
          - renesas,r9a07g043-ostm # RZ/G2UL and RZ/Five
          - renesas,r9a07g044-ostm # RZ/G2{L,LC}
          - renesas,r9a07g054-ostm # RZ/V2L
          - renesas,r9a09g057-ostm # RZ/V2H(P)
      - const: renesas,ostm        # Generic

  reg:
@@ -58,6 +59,7 @@ if:
          - renesas,r9a07g043-ostm
          - renesas,r9a07g044-ostm
          - renesas,r9a07g054-ostm
          - renesas,r9a09g057-ostm
then:
  required:
    - resets
+11 −15
Original line number Diff line number Diff line
@@ -13,6 +13,17 @@

#define VDSO_HAS_TIME			1

/*
 * powerpc specific delta calculation.
 *
 * This variant removes the masking of the subtraction because the
 * clocksource mask of all VDSO capable clocksources on powerpc is U64_MAX
 * which would result in a pointless operation. The compiler cannot
 * optimize it away as the mask comes from the vdso data and is not compile
 * time constant.
 */
#define VDSO_DELTA_NOMASK		1

static __always_inline int do_syscall_2(const unsigned long _r0, const unsigned long _r3,
					const unsigned long _r4)
{
@@ -104,21 +115,6 @@ static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
}
#define vdso_clocksource_ok vdso_clocksource_ok

/*
 * powerpc specific delta calculation.
 *
 * This variant removes the masking of the subtraction because the
 * clocksource mask of all VDSO capable clocksources on powerpc is U64_MAX
 * which would result in a pointless operation. The compiler cannot
 * optimize it away as the mask comes from the vdso data and is not compile
 * time constant.
 */
static __always_inline u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
{
	return (cycles - last) * mult;
}
#define vdso_calc_delta vdso_calc_delta

#ifndef __powerpc64__
static __always_inline u64 vdso_shift_ns(u64 ns, unsigned long shift)
{
+2 −5
Original line number Diff line number Diff line
@@ -6,16 +6,13 @@

#define VDSO_HAS_CLOCK_GETRES 1

#define VDSO_DELTA_NOMASK 1

#include <asm/syscall.h>
#include <asm/timex.h>
#include <asm/unistd.h>
#include <linux/compiler.h>

#define vdso_calc_delta __arch_vdso_calc_delta
static __always_inline u64 __arch_vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
{
	return (cycles - last) * mult;
}

static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
{
+1 −0
Original line number Diff line number Diff line
@@ -169,6 +169,7 @@ config X86
	select GENERIC_TIME_VSYSCALL
	select GENERIC_GETTIMEOFDAY
	select GENERIC_VDSO_TIME_NS
	select GENERIC_VDSO_OVERFLOW_PROTECT
	select GUP_GET_PXX_LOW_HIGH		if X86_PAE
	select HARDIRQS_SW_RESEND
	select HARDLOCKUP_CHECK_TIMESTAMP	if X86_64
+28 −16
Original line number Diff line number Diff line
@@ -300,7 +300,7 @@ static inline bool arch_vdso_cycles_ok(u64 cycles)
#define vdso_cycles_ok arch_vdso_cycles_ok

/*
 * x86 specific delta calculation.
 * x86 specific calculation of nanoseconds for the current cycle count
 *
 * The regular implementation assumes that clocksource reads are globally
 * monotonic. The TSC can be slightly off across sockets which can cause
@@ -308,8 +308,8 @@ static inline bool arch_vdso_cycles_ok(u64 cycles)
 * jump.
 *
 * Therefore it needs to be verified that @cycles are greater than
 * @last. If not then use @last, which is the base time of the current
 * conversion period.
 * @vd->cycles_last. If not then use @vd->cycles_last, which is the base
 * time of the current conversion period.
 *
 * This variant also uses a custom mask because while the clocksource mask of
 * all the VDSO capable clocksources on x86 is U64_MAX, the above code uses
@@ -317,25 +317,37 @@ static inline bool arch_vdso_cycles_ok(u64 cycles)
 * declares everything with the MSB/Sign-bit set as invalid. Therefore the
 * effective mask is S64_MAX.
 */
static __always_inline
u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
static __always_inline u64 vdso_calc_ns(const struct vdso_data *vd, u64 cycles, u64 base)
{
	u64 delta = cycles - vd->cycle_last;

	/*
	 * Negative motion and deltas which can cause multiplication
	 * overflow require special treatment. This check covers both as
	 * negative motion is guaranteed to be greater than @vd::max_cycles
	 * due to unsigned comparison.
	 *
	 * Due to the MSB/Sign-bit being used as invalid marker (see
	 * arch_vdso_cycles_valid() above), the effective mask is S64_MAX.
	 * arch_vdso_cycles_valid() above), the effective mask is S64_MAX,
	 * but that case is also unlikely and will also take the unlikely path
	 * here.
	 */
	u64 delta = (cycles - last) & S64_MAX;

	if (unlikely(delta > vd->max_cycles)) {
		/*
	 * Due to the above mentioned TSC wobbles, filter out negative motion.
	 * Per the above masking, the effective sign bit is now bit 62.
		 * Due to the above mentioned TSC wobbles, filter out
		 * negative motion.  Per the above masking, the effective
		 * sign bit is now bit 62.
		 */
	if (unlikely(delta & (1ULL << 62)))
		return 0;
		if (delta & (1ULL << 62))
			return base >> vd->shift;

		/* Handle multiplication overflow gracefully */
		return mul_u64_u32_add_u64_shr(delta & S64_MAX, vd->mult, base, vd->shift);
	}

	return delta * mult;
	return ((delta * vd->mult) + base) >> vd->shift;
}
#define vdso_calc_delta vdso_calc_delta
#define vdso_calc_ns vdso_calc_ns

#endif /* !__ASSEMBLY__ */

Loading