A set oftimekeeping/VDSO updates:
- Preparatory work to allow S390 to switch over to the generic VDSO implementation. S390 requires that the VDSO data pointer is handed in to the counter read function when time namespace support is enabled. Adding the pointer is a NOOP for all other architectures because the compiler is supposed to optimize that out when it is unused in the architecture specific inline. The change also solved a similar problem for MIPS which fortunately has time namespaces not yet enabled. S390 needs to update clock related VDSO data independent of the timekeeping updates. This was solved so far with yet another sequence counter in the S390 implementation. A better solution is to utilize the already existing VDSO sequence count for this. The core code now exposes helper functions which allow to serialize against the timekeeper code and against concurrent readers. S390 needs extra data for their clock readout function. The initial common VDSO data structure did not provide a way to add that. It now has an embedded architecture specific struct embedded which defaults to an empty struct. Doing this now avoids tree dependencies and conflicts post rc1 and allows all other architectures which work on generic VDSO support to work from a common upstream base. - A trivial comment fix. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAl82tGYTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYoRkKD/9YEYlYPQ4omRNVNIJRnalBH6OB/GOk jTJ4RCvNP2ew6XtgEz5Yg1VqxrmJP4MLNCnMr7mQulfezUmslK0uJMlqZC4dgYth PUhliLyFi5PK+CKaY+2NFlZMAoE53YlJ2FVPq114FUW4ASVbucDPXpmhO22cc2Iu 0RD3z9/+vQmA8lUqI6wPIFTC+euN+2kbkeZjt7BlkBAdiRBga5UnarFzetq0nWyc kcprQ2qZfGLYzRY6dRuvNLz27Ta7SAlVGOGUDpWr9MISLDFQzHwhVATDNFW3hLGT Fr5xNqStUVxxTzYkfCj/Podez0aR3por8bm9SoWxZn7oeLdLgTsDwn2pY0J0PjyB wWz9lmqT1vzrHEfQH1YhHvycowl6azue9rT2ERWwZTdbADEwu6Zr8ufv2XHcMu0J dyzSYa81cQrTeAwwdNjODs+QCTX+0G6u86AU2Xg+YgqkAywcAMvzcff/9D62hfv2 5BSz+0OeitQCnSvHILUPw4XT/2rNZfhlcmc4tkzoBFewzDsMEqWT19p+GgqcRNiU 5Jl4kGnaeHjP0e5Vn/ZJurKaF3YEJwgjkohDORloaqo0AXiYo1ANhDlKvSRu5hnU GDIWOVu8ATXwkjMFcLQz7O5/J1MqJCkleIjSCDjLDhhMbLY/nR9L3QS9jbqiVVRN nTZlSMF6HeQmew== =y8Z5 -----END PGP SIGNATURE----- Merge tag 'timers-urgent-2020-08-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull timekeeping updates from Thomas Gleixner: "A set of timekeeping/VDSO updates: - Preparatory work to allow S390 to switch over to the generic VDSO implementation. S390 requires that the VDSO data pointer is handed in to the counter read function when time namespace support is enabled. Adding the pointer is a NOOP for all other architectures because the compiler is supposed to optimize that out when it is unused in the architecture specific inline. The change also solved a similar problem for MIPS which fortunately has time namespaces not yet enabled. S390 needs to update clock related VDSO data independent of the timekeeping updates. This was solved so far with yet another sequence counter in the S390 implementation. A better solution is to utilize the already existing VDSO sequence count for this. The core code now exposes helper functions which allow to serialize against the timekeeper code and against concurrent readers. S390 needs extra data for their clock readout function. The initial common VDSO data structure did not provide a way to add that. It now has an embedded architecture specific struct embedded which defaults to an empty struct. Doing this now avoids tree dependencies and conflicts post rc1 and allows all other architectures which work on generic VDSO support to work from a common upstream base. - A trivial comment fix" * tag 'timers-urgent-2020-08-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: time: Delete repeated words in comments lib/vdso: Allow to add architecture-specific vdso data timekeeping/vsyscall: Provide vdso_update_begin/end() vdso/treewide: Add vdso_data pointer argument to __arch_get_hw_counter()
This commit is contained in:
commit
b923f1247b
|
@ -972,6 +972,9 @@ config HAVE_SPARSE_SYSCALL_NR
|
|||
entries at 4000, 5000 and 6000 locations. This option turns on syscall
|
||||
related optimizations for a given architecture.
|
||||
|
||||
config ARCH_HAS_VDSO_DATA
|
||||
bool
|
||||
|
||||
source "kernel/gcov/Kconfig"
|
||||
|
||||
source "scripts/gcc-plugins/Kconfig"
|
||||
|
|
|
@ -113,7 +113,8 @@ static inline bool arm_vdso_hres_capable(void)
|
|||
}
|
||||
#define __arch_vdso_hres_capable arm_vdso_hres_capable
|
||||
|
||||
static __always_inline u64 __arch_get_hw_counter(int clock_mode)
|
||||
static __always_inline u64 __arch_get_hw_counter(int clock_mode,
|
||||
const struct vdso_data *vd)
|
||||
{
|
||||
#ifdef CONFIG_ARM_ARCH_TIMER
|
||||
u64 cycle_now;
|
||||
|
|
|
@ -103,7 +103,8 @@ int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
|
||||
const struct vdso_data *vd)
|
||||
{
|
||||
u64 res;
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
|
||||
const struct vdso_data *vd)
|
||||
{
|
||||
u64 res;
|
||||
|
||||
|
|
|
@ -167,7 +167,8 @@ static __always_inline u64 read_gic_count(const struct vdso_data *data)
|
|||
|
||||
#endif
|
||||
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
|
||||
const struct vdso_data *vd)
|
||||
{
|
||||
#ifdef CONFIG_CSRC_R4K
|
||||
if (clock_mode == VDSO_CLOCKMODE_R4K)
|
||||
|
@ -175,7 +176,7 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
|
|||
#endif
|
||||
#ifdef CONFIG_CLKSRC_MIPS_GIC
|
||||
if (clock_mode == VDSO_CLOCKMODE_GIC)
|
||||
return read_gic_count(get_vdso_data());
|
||||
return read_gic_count(vd);
|
||||
#endif
|
||||
/*
|
||||
* Core checks mode already. So this raced against a concurrent
|
||||
|
|
|
@ -60,7 +60,8 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
|
||||
const struct vdso_data *vd)
|
||||
{
|
||||
/*
|
||||
* The purpose of csr_read(CSR_TIME) is to trap the system into
|
||||
|
|
|
@ -241,7 +241,8 @@ static u64 vread_hvclock(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static inline u64 __arch_get_hw_counter(s32 clock_mode)
|
||||
static inline u64 __arch_get_hw_counter(s32 clock_mode,
|
||||
const struct vdso_data *vd)
|
||||
{
|
||||
if (likely(clock_mode == VDSO_CLOCKMODE_TSC))
|
||||
return (u64)rdtsc_ordered();
|
||||
|
|
|
@ -19,6 +19,12 @@
|
|||
#include <vdso/time32.h>
|
||||
#include <vdso/time64.h>
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_VDSO_DATA
|
||||
#include <asm/vdso/data.h>
|
||||
#else
|
||||
struct arch_vdso_data {};
|
||||
#endif
|
||||
|
||||
#define VDSO_BASES (CLOCK_TAI + 1)
|
||||
#define VDSO_HRES (BIT(CLOCK_REALTIME) | \
|
||||
BIT(CLOCK_MONOTONIC) | \
|
||||
|
@ -64,6 +70,8 @@ struct vdso_timestamp {
|
|||
* @tz_dsttime: type of DST correction
|
||||
* @hrtimer_res: hrtimer resolution
|
||||
* @__unused: unused
|
||||
* @arch_data: architecture specific data (optional, defaults
|
||||
* to an empty struct)
|
||||
*
|
||||
* vdso_data will be accessed by 64 bit and compat code at the same time
|
||||
* so we should be careful before modifying this structure.
|
||||
|
@ -97,6 +105,8 @@ struct vdso_data {
|
|||
s32 tz_dsttime;
|
||||
u32 hrtimer_res;
|
||||
u32 __unused;
|
||||
|
||||
struct arch_vdso_data arch_data;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
#include <asm/vdso/vsyscall.h>
|
||||
|
||||
unsigned long vdso_update_begin(void);
|
||||
void vdso_update_end(unsigned long flags);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#endif /* __VDSO_VSYSCALL_H */
|
||||
|
|
|
@ -192,7 +192,7 @@ static void alarmtimer_dequeue(struct alarm_base *base, struct alarm *alarm)
|
|||
* When a alarm timer fires, this runs through the timerqueue to
|
||||
* see which alarms expired, and runs those. If there are more alarm
|
||||
* timers queued for the future, we set the hrtimer to fire when
|
||||
* when the next future alarm timer expires.
|
||||
* the next future alarm timer expires.
|
||||
*/
|
||||
static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
|
||||
{
|
||||
|
|
|
@ -229,7 +229,7 @@ void __init generic_sched_clock_init(void)
|
|||
{
|
||||
/*
|
||||
* If no sched_clock() function has been provided at that point,
|
||||
* make it the final one one.
|
||||
* make it the final one.
|
||||
*/
|
||||
if (cd.actual_read_sched_clock == jiffy_sched_clock_read)
|
||||
sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);
|
||||
|
|
|
@ -39,7 +39,7 @@ enum timekeeping_adv_mode {
|
|||
TK_ADV_FREQ
|
||||
};
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(timekeeper_lock);
|
||||
DEFINE_RAW_SPINLOCK(timekeeper_lock);
|
||||
|
||||
/*
|
||||
* The most important data for readout fits into a single 64 byte
|
||||
|
@ -2004,7 +2004,7 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
|
|||
* logarithmic_accumulation - shifted accumulation of cycles
|
||||
*
|
||||
* This functions accumulates a shifted interval of cycles into
|
||||
* into a shifted interval nanoseconds. Allows for O(log) accumulation
|
||||
* a shifted interval nanoseconds. Allows for O(log) accumulation
|
||||
* loop.
|
||||
*
|
||||
* Returns the unconsumed cycles.
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _TIMEKEEPING_INTERNAL_H
|
||||
#define _TIMEKEEPING_INTERNAL_H
|
||||
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
/*
|
||||
* timekeeping debug functions
|
||||
*/
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern void tk_debug_account_sleep_time(const struct timespec64 *t);
|
||||
#else
|
||||
|
@ -31,4 +33,7 @@ static inline u64 clocksource_delta(u64 now, u64 last, u64 mask)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Semi public for serialization of non timekeeper VDSO updates. */
|
||||
extern raw_spinlock_t timekeeper_lock;
|
||||
|
||||
#endif /* _TIMEKEEPING_INTERNAL_H */
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <vdso/helpers.h>
|
||||
#include <vdso/vsyscall.h>
|
||||
|
||||
#include "timekeeping_internal.h"
|
||||
|
||||
static inline void update_vdso_data(struct vdso_data *vdata,
|
||||
struct timekeeper *tk)
|
||||
{
|
||||
|
@ -127,3 +129,42 @@ void update_vsyscall_tz(void)
|
|||
|
||||
__arch_sync_vdso_data(vdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* vdso_update_begin - Start of a VDSO update section
|
||||
*
|
||||
* Allows architecture code to safely update the architecture specific VDSO
|
||||
* data. Disables interrupts, acquires timekeeper lock to serialize against
|
||||
* concurrent updates from timekeeping and invalidates the VDSO data
|
||||
* sequence counter to prevent concurrent readers from accessing
|
||||
* inconsistent data.
|
||||
*
|
||||
* Returns: Saved interrupt flags which need to be handed in to
|
||||
* vdso_update_end().
|
||||
*/
|
||||
unsigned long vdso_update_begin(void)
|
||||
{
|
||||
struct vdso_data *vdata = __arch_get_k_vdso_data();
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&timekeeper_lock, flags);
|
||||
vdso_write_begin(vdata);
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* vdso_update_end - End of a VDSO update section
|
||||
* @flags: Interrupt flags as returned from vdso_update_begin()
|
||||
*
|
||||
* Pairs with vdso_update_begin(). Marks vdso data consistent, invokes data
|
||||
* synchronization if the architecture requires it, drops timekeeper lock
|
||||
* and restores interrupt flags.
|
||||
*/
|
||||
void vdso_update_end(unsigned long flags)
|
||||
{
|
||||
struct vdso_data *vdata = __arch_get_k_vdso_data();
|
||||
|
||||
vdso_write_end(vdata);
|
||||
__arch_sync_vdso_data(vdata);
|
||||
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
|
|||
if (unlikely(!vdso_clocksource_ok(vd)))
|
||||
return -1;
|
||||
|
||||
cycles = __arch_get_hw_counter(vd->clock_mode);
|
||||
cycles = __arch_get_hw_counter(vd->clock_mode, vd);
|
||||
if (unlikely(!vdso_cycles_ok(cycles)))
|
||||
return -1;
|
||||
ns = vdso_ts->nsec;
|
||||
|
@ -138,7 +138,7 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk,
|
|||
if (unlikely(!vdso_clocksource_ok(vd)))
|
||||
return -1;
|
||||
|
||||
cycles = __arch_get_hw_counter(vd->clock_mode);
|
||||
cycles = __arch_get_hw_counter(vd->clock_mode, vd);
|
||||
if (unlikely(!vdso_cycles_ok(cycles)))
|
||||
return -1;
|
||||
ns = vdso_ts->nsec;
|
||||
|
|
Loading…
Reference in New Issue