Skip to content

Commit

Permalink
clocksource: Add common vdso clock mode storage
Browse files Browse the repository at this point in the history
All architectures which use the generic VDSO code have their own storage
for the VDSO clock mode. That's pointless and just requires duplicate code.

Provide generic storage for it. The new Kconfig symbol is intermediate and
will be removed once all architectures are converted over.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Link: https://lkml.kernel.org/r/20200207124403.028046322@linutronix.de
  • Loading branch information
Thomas Gleixner committed Feb 17, 2020
1 parent eec399d commit 5d51bee
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 5 deletions.
12 changes: 11 additions & 1 deletion include/linux/clocksource.h
Expand Up @@ -23,10 +23,19 @@
struct clocksource;
struct module;

#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
#if defined(CONFIG_ARCH_CLOCKSOURCE_DATA) || \
defined(CONFIG_GENERIC_VDSO_CLOCK_MODE)
#include <asm/clocksource.h>
#endif

enum vdso_clock_mode {
VDSO_CLOCKMODE_NONE,
#ifdef CONFIG_GENERIC_VDSO_CLOCK_MODE
VDSO_ARCH_CLOCKMODES,
#endif
VDSO_CLOCKMODE_MAX,
};

/**
* struct clocksource - hardware abstraction for a free running counter
* Provides mostly state-free accessors to the underlying hardware.
Expand Down Expand Up @@ -97,6 +106,7 @@ struct clocksource {
const char *name;
struct list_head list;
int rating;
enum vdso_clock_mode vdso_clock_mode;
unsigned long flags;

int (*enable)(struct clocksource *cs);
Expand Down
9 changes: 9 additions & 0 deletions kernel/time/clocksource.c
Expand Up @@ -928,6 +928,15 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)

clocksource_arch_init(cs);

#ifdef CONFIG_GENERIC_VDSO_CLOCK_MODE
if (cs->vdso_clock_mode < 0 ||
cs->vdso_clock_mode >= VDSO_CLOCKMODE_MAX) {
pr_warn("clocksource %s registered with invalid VDSO mode %d. Disabling VDSO support.\n",
cs->name, cs->vdso_clock_mode);
cs->vdso_clock_mode = VDSO_CLOCKMODE_NONE;
}
#endif

/* Initialize mult/shift and max_idle_ns */
__clocksource_update_freq_scale(cs, scale, freq);

Expand Down
10 changes: 8 additions & 2 deletions kernel/time/vsyscall.c
Expand Up @@ -71,13 +71,19 @@ void update_vsyscall(struct timekeeper *tk)
{
struct vdso_data *vdata = __arch_get_k_vdso_data();
struct vdso_timestamp *vdso_ts;
s32 clock_mode;
u64 nsec;

/* copy vsyscall data */
vdso_write_begin(vdata);

vdata[CS_HRES_COARSE].clock_mode = __arch_get_clock_mode(tk);
vdata[CS_RAW].clock_mode = __arch_get_clock_mode(tk);
#ifdef CONFIG_GENERIC_VDSO_CLOCK_MODE
clock_mode = tk->tkr_mono.clock->vdso_clock_mode;
#else
clock_mode = __arch_get_clock_mode(tk);
#endif
vdata[CS_HRES_COARSE].clock_mode = clock_mode;
vdata[CS_RAW].clock_mode = clock_mode;

/* CLOCK_REALTIME also required for time() */
vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME];
Expand Down
3 changes: 3 additions & 0 deletions lib/vdso/Kconfig
Expand Up @@ -30,4 +30,7 @@ config GENERIC_VDSO_TIME_NS
Selected by architectures which support time namespaces in the
VDSO

config GENERIC_VDSO_CLOCK_MODE
bool

endif
13 changes: 11 additions & 2 deletions lib/vdso/gettimeofday.c
Expand Up @@ -7,6 +7,7 @@
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/hrtimer_defs.h>
#include <linux/clocksource.h>
#include <vdso/datapage.h>
#include <vdso/helpers.h>

Expand Down Expand Up @@ -64,10 +65,14 @@ static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,

do {
seq = vdso_read_begin(vd);
if (IS_ENABLED(CONFIG_GENERIC_VDSO_CLOCK_MODE) &&
vd->clock_mode == VDSO_CLOCKMODE_NONE)
return -1;
cycles = __arch_get_hw_counter(vd->clock_mode);
ns = vdso_ts->nsec;
last = vd->cycle_last;
if (unlikely((s64)cycles < 0))
if (!IS_ENABLED(CONFIG_GENERIC_VDSO_CLOCK_MODE) &&
unlikely((s64)cycles < 0))
return -1;

ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
Expand Down Expand Up @@ -132,10 +137,14 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk,
}
smp_rmb();

if (IS_ENABLED(CONFIG_GENERIC_VDSO_CLOCK_MODE) &&
vd->clock_mode == VDSO_CLOCKMODE_NONE)
return -1;
cycles = __arch_get_hw_counter(vd->clock_mode);
ns = vdso_ts->nsec;
last = vd->cycle_last;
if (unlikely((s64)cycles < 0))
if (!IS_ENABLED(CONFIG_GENERIC_VDSO_CLOCK_MODE) &&
unlikely((s64)cycles < 0))
return -1;

ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
Expand Down

0 comments on commit 5d51bee

Please sign in to comment.