From 50e818715821b89c7abac90a97721f106e893d83 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:48 +0100 Subject: x86/vdso: Mark the TSC clocksource path likely Jumping out of line for the TSC clcoksource read is creating awful code. TSC is likely to be the clocksource at least on bare metal and the PV interfaces are sufficiently more work that the jump over the TSC read is just in the noise. Signed-off-by: Thomas Gleixner Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124402.328922847@linutronix.de --- arch/x86/include/asm/vdso/gettimeofday.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h index 6ee1f7dba34b..264d4fd3ff2c 100644 --- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -243,7 +243,7 @@ static u64 vread_hvclock(void) static inline u64 __arch_get_hw_counter(s32 clock_mode) { - if (clock_mode == VCLOCK_TSC) + if (likely(clock_mode == VCLOCK_TSC)) return (u64)rdtsc_ordered(); /* * For any memory-mapped vclock type, we need to make sure that gcc -- cgit v1.2.3-70-g09d2 From 78560d41064ad3d377e3d1a1ee87526301f4e946 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:49 +0100 Subject: ARM: vdso: Remove unused function The function is nowhere used. Aside of that this check should only cover the high resolution parts of the VDSO which require a VDSO capable clocksource and not the complete functionality as the name suggests. Will be replaced with something more useful. Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124402.438179009@linutronix.de --- arch/arm/include/asm/vdso/vsyscall.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/include/asm/vdso/vsyscall.h b/arch/arm/include/asm/vdso/vsyscall.h index cff87d8d30da..85a7e58b7228 100644 --- a/arch/arm/include/asm/vdso/vsyscall.h +++ b/arch/arm/include/asm/vdso/vsyscall.h @@ -49,13 +49,6 @@ int __arm_get_clock_mode(struct timekeeper *tk) } #define __arch_get_clock_mode __arm_get_clock_mode -static __always_inline -int __arm_use_vsyscall(struct vdso_data *vdata) -{ - return vdata[CS_HRES_COARSE].clock_mode; -} -#define __arch_use_vsyscall __arm_use_vsyscall - static __always_inline void __arm_sync_vdso_data(struct vdso_data *vdata) { -- cgit v1.2.3-70-g09d2 From 1dff4156d1f63b525c54aea7f097a657cbbbf837 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:50 +0100 Subject: lib/vdso: Allow the high resolution parts to be compiled out If the architecture knows at compile time that there is no VDSO capable clocksource supported it makes sense to optimize the guts of the high resolution parts of the VDSO out at build time. Add a helper function to check whether the VDSO should be high resolution capable and provide a stub which can be overridden by an architecture. Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124402.530143168@linutronix.de --- lib/vdso/gettimeofday.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index f8b8ec5e63ac..5804e4e168e7 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -38,6 +38,13 @@ u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) } #endif +#ifndef __arch_vdso_hres_capable +static inline bool __arch_vdso_hres_capable(void) +{ + return true; +} +#endif + #ifdef CONFIG_TIME_NS static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk, struct __kernel_timespec *ts) @@ -101,6 +108,10 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk, u64 cycles, last, sec, ns; u32 seq; + /* Allows to compile the high resolution parts out */ + if (!__arch_vdso_hres_capable()) + return -1; + do { /* * Open coded to handle VCLOCK_TIMENS. Time namespace -- cgit v1.2.3-70-g09d2 From 3280badbe1b289622ce12b94d064ddb624cbaef1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:51 +0100 Subject: ARM: vdso: Compile high resolution parts conditionally If the architected timer is disabled in the kernel configuration then let the core VDSO code drop the high resolution parts at compile time. Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124402.622587341@linutronix.de --- arch/arm/include/asm/vdso/gettimeofday.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h index fe6e1f65932d..f4757d327f43 100644 --- a/arch/arm/include/asm/vdso/gettimeofday.h +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -106,6 +106,12 @@ static __always_inline int clock_getres32_fallback( return ret; } +static inline bool arm_vdso_hres_capable(void) +{ + return IS_ENABLED(CONFIG_ARM_ARCH_TIMER); +} +#define __arch_vdso_hres_capable arm_vdso_hres_capable + static __always_inline u64 __arch_get_hw_counter(int clock_mode) { #ifdef CONFIG_ARM_ARCH_TIMER -- cgit v1.2.3-70-g09d2 From 25a2a6567829119f5e3e11eb0ce3d8ae985b6019 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:52 +0100 Subject: MIPS: vdso: Compile high resolution parts conditionally If neither the R4K nor the GIC timer is enabled in the kernel configuration then let the core VDSO code drop the high resolution parts at compile time. Signed-off-by: Thomas Gleixner Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124402.714585315@linutronix.de --- arch/mips/include/asm/vdso/gettimeofday.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/mips/include/asm/vdso/gettimeofday.h b/arch/mips/include/asm/vdso/gettimeofday.h index a58687e26c5d..a9f846b1a920 100644 --- a/arch/mips/include/asm/vdso/gettimeofday.h +++ b/arch/mips/include/asm/vdso/gettimeofday.h @@ -199,6 +199,13 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) return cycle_now; } +static inline bool mips_vdso_hres_capable(void) +{ + return IS_ENABLED(CONFIG_CSRC_R4K) || + IS_ENABLED(CONFIG_CLKSRC_MIPS_GIC); +} +#define __arch_vdso_hres_capable mips_vdso_hres_capable + static __always_inline const struct vdso_data *__arch_get_vdso_data(void) { return get_vdso_data(); -- cgit v1.2.3-70-g09d2 From 3bd142a46b561a12408e8db78cc6d62eb1c6b84e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:53 +0100 Subject: clocksource: Cleanup struct clocksource and documentation Reformat the struct definition, add missing member documentation. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124402.825471920@linutronix.de --- include/linux/clocksource.h | 87 ++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index b21db536fd52..2c4574b517d2 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -32,9 +32,19 @@ struct module; * Provides mostly state-free accessors to the underlying hardware. * This is the structure used for system time. * - * @name: ptr to clocksource name - * @list: list head for registration - * @rating: rating value for selection (higher is better) + * @read: Returns a cycle value, passes clocksource as argument + * @mask: Bitmask for two's complement + * subtraction of non 64 bit counters + * @mult: Cycle to nanosecond multiplier + * @shift: Cycle to nanosecond divisor (power of two) + * @max_idle_ns: Maximum idle time permitted by the clocksource (nsecs) + * @maxadj: Maximum adjustment value to mult (~11%) + * @archdata: Optional arch-specific data + * @max_cycles: Maximum safe cycle value which won't overflow on + * multiplication + * @name: Pointer to clocksource name + * @list: List head for registration (internal) + * @rating: Rating value for selection (higher is better) * To avoid rating inflation the following * list should give you a guide as to how * to assign your clocksource a rating @@ -49,27 +59,23 @@ struct module; * 400-499: Perfect * The ideal clocksource. A must-use where * available. - * @read: returns a cycle value, passes clocksource as argument - * @enable: optional function to enable the clocksource - * @disable: optional function to disable the clocksource - * @mask: bitmask for two's complement - * subtraction of non 64 bit counters - * @mult: cycle to nanosecond multiplier - * @shift: cycle to nanosecond divisor (power of two) - * @max_idle_ns: max idle time permitted by the clocksource (nsecs) - * @maxadj: maximum adjustment value to mult (~11%) - * @max_cycles: maximum safe cycle value which won't overflow on multiplication - * @flags: flags describing special properties - * @archdata: arch-specific data - * @suspend: suspend function for the clocksource, if necessary - * @resume: resume function for the clocksource, if necessary + * @flags: Flags describing special properties + * @enable: Optional function to enable the clocksource + * @disable: Optional function to disable the clocksource + * @suspend: Optional suspend function for the clocksource + * @resume: Optional resume function for the clocksource * @mark_unstable: Optional function to inform the clocksource driver that * the watchdog marked the clocksource unstable - * @owner: module reference, must be set by clocksource in modules + * @tick_stable: Optional function called periodically from the watchdog + * code to provide stable syncrhonization points + * @wd_list: List head to enqueue into the watchdog list (internal) + * @cs_last: Last clocksource value for clocksource watchdog + * @wd_last: Last watchdog value corresponding to @cs_last + * @owner: Module reference, must be set by clocksource in modules * * Note: This struct is not used in hotpathes of the timekeeping code * because the timekeeper caches the hot path fields in its own data - * structure, so no line cache alignment is required, + * structure, so no cache line alignment is required, * * The pointer to the clocksource itself is handed to the read * callback. If you need extra information there you can wrap struct @@ -78,35 +84,36 @@ struct module; * structure. */ struct clocksource { - u64 (*read)(struct clocksource *cs); - u64 mask; - u32 mult; - u32 shift; - u64 max_idle_ns; - u32 maxadj; + u64 (*read)(struct clocksource *cs); + u64 mask; + u32 mult; + u32 shift; + u64 max_idle_ns; + u32 maxadj; #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA struct arch_clocksource_data archdata; #endif - u64 max_cycles; - const char *name; - struct list_head list; - int rating; - int (*enable)(struct clocksource *cs); - void (*disable)(struct clocksource *cs); - unsigned long flags; - void (*suspend)(struct clocksource *cs); - void (*resume)(struct clocksource *cs); - void (*mark_unstable)(struct clocksource *cs); - void (*tick_stable)(struct clocksource *cs); + u64 max_cycles; + const char *name; + struct list_head list; + int rating; + unsigned long flags; + + int (*enable)(struct clocksource *cs); + void (*disable)(struct clocksource *cs); + void (*suspend)(struct clocksource *cs); + void (*resume)(struct clocksource *cs); + void (*mark_unstable)(struct clocksource *cs); + void (*tick_stable)(struct clocksource *cs); /* private: */ #ifdef CONFIG_CLOCKSOURCE_WATCHDOG /* Watchdog related data, used by the framework */ - struct list_head wd_list; - u64 cs_last; - u64 wd_last; + struct list_head wd_list; + u64 cs_last; + u64 wd_last; #endif - struct module *owner; + struct module *owner; }; /* -- cgit v1.2.3-70-g09d2 From eec399dd862762b9594df3659f15839a4e12f17a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:54 +0100 Subject: x86/vdso: Move VDSO clocksource state tracking to callback 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. X86 abuses the function which retrieves the architecture specific clock mode storage to mark the clocksource as used in the VDSO. That's silly because this is invoked on every tick when the VDSO data is updated. Move this functionality to the clocksource::enable() callback so it gets invoked once when the clocksource is installed. This allows to make the clock mode storage generic. Signed-off-by: Thomas Gleixner Reviewed-by: Michael Kelley (Hyper-V parts) Reviewed-by: Vincenzo Frascino (VDSO parts) Acked-by: Juergen Gross (Xen parts) Link: https://lkml.kernel.org/r/20200207124402.934519777@linutronix.de --- arch/x86/entry/vdso/vma.c | 4 ++++ arch/x86/include/asm/clocksource.h | 12 ++++++++++++ arch/x86/include/asm/mshyperv.h | 2 ++ arch/x86/include/asm/vdso/vsyscall.h | 10 +--------- arch/x86/include/asm/vgtod.h | 6 ------ arch/x86/kernel/kvmclock.c | 7 +++++++ arch/x86/kernel/tsc.c | 32 ++++++++++++++++++++------------ arch/x86/xen/time.c | 17 ++++++++++++----- drivers/clocksource/hyperv_timer.c | 7 +++++++ 9 files changed, 65 insertions(+), 32 deletions(-) diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index c1b8496b5606..cce3e809f17e 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -38,6 +38,8 @@ struct vdso_data *arch_get_vdso_data(void *vvar_page) } #undef EMIT_VVAR +unsigned int vclocks_used __read_mostly; + #if defined(CONFIG_X86_64) unsigned int __read_mostly vdso64_enabled = 1; #endif @@ -445,6 +447,8 @@ __setup("vdso=", vdso_setup); static int __init init_vdso(void) { + BUILD_BUG_ON(VCLOCK_MAX >= 32); + init_vdso_image(&vdso_image_64); #ifdef CONFIG_X86_X32_ABI diff --git a/arch/x86/include/asm/clocksource.h b/arch/x86/include/asm/clocksource.h index dc4cfc888d6d..2450d6e02a5d 100644 --- a/arch/x86/include/asm/clocksource.h +++ b/arch/x86/include/asm/clocksource.h @@ -14,4 +14,16 @@ struct arch_clocksource_data { int vclock_mode; }; +extern unsigned int vclocks_used; + +static inline bool vclock_was_used(int vclock) +{ + return READ_ONCE(vclocks_used) & (1U << vclock); +} + +static inline void vclocks_set_used(unsigned int which) +{ + WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << which)); +} + #endif /* _ASM_X86_CLOCKSOURCE_H */ diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 6b79515abb82..f7cbc01f128e 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -47,6 +47,8 @@ typedef int (*hyperv_fill_flush_list_func)( wrmsrl(HV_X64_MSR_REFERENCE_TSC, val) #define hv_set_clocksource_vdso(val) \ ((val).archdata.vclock_mode = VCLOCK_HVCLOCK) +#define hv_enable_vdso_clocksource() \ + vclocks_set_used(VCLOCK_HVCLOCK); #define hv_get_raw_timer() rdtsc_ordered() void hyperv_callback_vector(void); diff --git a/arch/x86/include/asm/vdso/vsyscall.h b/arch/x86/include/asm/vdso/vsyscall.h index 0026ab2123ce..01f5733d14d6 100644 --- a/arch/x86/include/asm/vdso/vsyscall.h +++ b/arch/x86/include/asm/vdso/vsyscall.h @@ -10,8 +10,6 @@ #include #include -int vclocks_used __read_mostly; - DEFINE_VVAR(struct vdso_data, _vdso_data); /* * Update the vDSO data page to keep in sync with kernel timekeeping. @@ -26,13 +24,7 @@ struct vdso_data *__x86_get_k_vdso_data(void) static __always_inline int __x86_get_clock_mode(struct timekeeper *tk) { - int vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; - - /* Mark the new vclock used. */ - BUILD_BUG_ON(VCLOCK_MAX >= 32); - WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << vclock_mode)); - - return vclock_mode; + return tk->tkr_mono.clock->archdata.vclock_mode; } #define __arch_get_clock_mode __x86_get_clock_mode diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h index a2638c6124ed..fc8e4cd342cc 100644 --- a/arch/x86/include/asm/vgtod.h +++ b/arch/x86/include/asm/vgtod.h @@ -15,10 +15,4 @@ typedef u64 gtod_long_t; typedef unsigned long gtod_long_t; #endif -extern int vclocks_used; -static inline bool vclock_was_used(int vclock) -{ - return READ_ONCE(vclocks_used) & (1 << vclock); -} - #endif /* _ASM_X86_VGTOD_H */ diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index 904494b924c1..33f2cac25f13 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -159,12 +159,19 @@ bool kvm_check_and_clear_guest_paused(void) return ret; } +static int kvm_cs_enable(struct clocksource *cs) +{ + vclocks_set_used(VCLOCK_PVCLOCK); + return 0; +} + struct clocksource kvm_clock = { .name = "kvm-clock", .read = kvm_clock_get_cycles, .rating = 400, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .enable = kvm_cs_enable, }; EXPORT_SYMBOL_GPL(kvm_clock); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 7e322e2daaf5..742da141a30a 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -1108,17 +1108,24 @@ static void tsc_cs_tick_stable(struct clocksource *cs) sched_clock_tick_stable(); } +static int tsc_cs_enable(struct clocksource *cs) +{ + vclocks_set_used(VCLOCK_TSC); + return 0; +} + /* * .mask MUST be CLOCKSOURCE_MASK(64). See comment above read_tsc() */ static struct clocksource clocksource_tsc_early = { - .name = "tsc-early", - .rating = 299, - .read = read_tsc, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS | + .name = "tsc-early", + .rating = 299, + .read = read_tsc, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, - .archdata = { .vclock_mode = VCLOCK_TSC }, + .archdata = { .vclock_mode = VCLOCK_TSC }, + .enable = tsc_cs_enable, .resume = tsc_resume, .mark_unstable = tsc_cs_mark_unstable, .tick_stable = tsc_cs_tick_stable, @@ -1131,14 +1138,15 @@ static struct clocksource clocksource_tsc_early = { * been found good. */ static struct clocksource clocksource_tsc = { - .name = "tsc", - .rating = 300, - .read = read_tsc, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS | + .name = "tsc", + .rating = 300, + .read = read_tsc, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_MUST_VERIFY, - .archdata = { .vclock_mode = VCLOCK_TSC }, + .archdata = { .vclock_mode = VCLOCK_TSC }, + .enable = tsc_cs_enable, .resume = tsc_resume, .mark_unstable = tsc_cs_mark_unstable, .tick_stable = tsc_cs_tick_stable, diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index befbdd8b17f0..5d1568ff19ea 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -145,12 +145,19 @@ static struct notifier_block xen_pvclock_gtod_notifier = { .notifier_call = xen_pvclock_gtod_notify, }; +static int xen_cs_enable(struct clocksource *cs) +{ + vclocks_set_used(VCLOCK_PVCLOCK); + return 0; +} + static struct clocksource xen_clocksource __read_mostly = { - .name = "xen", - .rating = 400, - .read = xen_clocksource_get_cycles, - .mask = ~0, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .name = "xen", + .rating = 400, + .read = xen_clocksource_get_cycles, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .enable = xen_cs_enable, }; /* diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 9d808d595ca8..a86859ccc61b 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -369,6 +369,12 @@ static void resume_hv_clock_tsc(struct clocksource *arg) hv_set_reference_tsc(tsc_msr); } +static int hv_cs_enable(struct clocksource *cs) +{ + hv_enable_vdso_clocksource(); + return 0; +} + static struct clocksource hyperv_cs_tsc = { .name = "hyperv_clocksource_tsc_page", .rating = 250, @@ -377,6 +383,7 @@ static struct clocksource hyperv_cs_tsc = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, .suspend= suspend_hv_clock_tsc, .resume = resume_hv_clock_tsc, + .enable = hv_cs_enable, }; static u64 notrace read_hv_clock_msr(void) -- cgit v1.2.3-70-g09d2 From 5d51bee725cc1497352d6b0b604e42a90c680540 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:55 +0100 Subject: clocksource: Add common vdso clock mode storage 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 Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124403.028046322@linutronix.de --- include/linux/clocksource.h | 12 +++++++++++- kernel/time/clocksource.c | 9 +++++++++ kernel/time/vsyscall.c | 10 ++++++++-- lib/vdso/Kconfig | 3 +++ lib/vdso/gettimeofday.c | 13 +++++++++++-- 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 2c4574b517d2..6d5ed1b4d24d 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -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 #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. @@ -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); diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 428beb69426a..7cb09c4cf21c 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -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); diff --git a/kernel/time/vsyscall.c b/kernel/time/vsyscall.c index 9577c89179cd..f9a5178c69bb 100644 --- a/kernel/time/vsyscall.c +++ b/kernel/time/vsyscall.c @@ -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]; diff --git a/lib/vdso/Kconfig b/lib/vdso/Kconfig index d883ac299508..d9f43c84fcc6 100644 --- a/lib/vdso/Kconfig +++ b/lib/vdso/Kconfig @@ -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 diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 5804e4e168e7..3f2d8b859130 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -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); @@ -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); -- cgit v1.2.3-70-g09d2 From b95a8a27c300d1a39a4e36f63a518ef36e4b966c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:56 +0100 Subject: x86/vdso: Use generic VDSO clock mode storage Switch to the generic VDSO clock mode storage. Signed-off-by: Thomas Gleixner Reviewed-by: Vincenzo Frascino (VDSO parts) Acked-by: Juergen Gross (Xen parts) Acked-by: Paolo Bonzini (KVM parts) Link: https://lkml.kernel.org/r/20200207124403.152039903@linutronix.de --- arch/x86/Kconfig | 2 +- arch/x86/entry/vdso/vma.c | 6 +++--- arch/x86/include/asm/clocksource.h | 13 ++++--------- arch/x86/include/asm/mshyperv.h | 4 ++-- arch/x86/include/asm/vdso/gettimeofday.h | 6 +++--- arch/x86/include/asm/vdso/vsyscall.h | 7 ------- arch/x86/kernel/kvmclock.c | 4 ++-- arch/x86/kernel/pvclock.c | 2 +- arch/x86/kernel/time.c | 12 +++--------- arch/x86/kernel/tsc.c | 6 +++--- arch/x86/kvm/trace.h | 4 ++-- arch/x86/kvm/x86.c | 22 +++++++++++----------- arch/x86/xen/time.c | 21 +++++++++++---------- 13 files changed, 46 insertions(+), 63 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index beea77046f9b..698e9c835cc5 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -57,7 +57,6 @@ config X86 select ACPI_LEGACY_TABLES_LOOKUP if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_32BIT_OFF_T if X86_32 - select ARCH_CLOCKSOURCE_DATA select ARCH_CLOCKSOURCE_INIT select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI select ARCH_HAS_DEBUG_VIRTUAL @@ -126,6 +125,7 @@ config X86 select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select GENERIC_GETTIMEOFDAY + select GENERIC_VDSO_CLOCK_MODE select GENERIC_VDSO_TIME_NS select GUP_GET_PTE_LOW_HIGH if X86_PAE select HARDLOCKUP_CHECK_TIMESTAMP if X86_64 diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index cce3e809f17e..43428cc514c8 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -221,7 +221,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, } else if (sym_offset == image->sym_pvclock_page) { struct pvclock_vsyscall_time_info *pvti = pvclock_get_pvti_cpu0_va(); - if (pvti && vclock_was_used(VCLOCK_PVCLOCK)) { + if (pvti && vclock_was_used(VDSO_CLOCKMODE_PVCLOCK)) { return vmf_insert_pfn_prot(vma, vmf->address, __pa(pvti) >> PAGE_SHIFT, pgprot_decrypted(vma->vm_page_prot)); @@ -229,7 +229,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, } else if (sym_offset == image->sym_hvclock_page) { struct ms_hyperv_tsc_page *tsc_pg = hv_get_tsc_page(); - if (tsc_pg && vclock_was_used(VCLOCK_HVCLOCK)) + if (tsc_pg && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK)) return vmf_insert_pfn(vma, vmf->address, virt_to_phys(tsc_pg) >> PAGE_SHIFT); } else if (sym_offset == image->sym_timens_page) { @@ -447,7 +447,7 @@ __setup("vdso=", vdso_setup); static int __init init_vdso(void) { - BUILD_BUG_ON(VCLOCK_MAX >= 32); + BUILD_BUG_ON(VDSO_CLOCKMODE_MAX >= 32); init_vdso_image(&vdso_image_64); diff --git a/arch/x86/include/asm/clocksource.h b/arch/x86/include/asm/clocksource.h index 2450d6e02a5d..d561db67f96d 100644 --- a/arch/x86/include/asm/clocksource.h +++ b/arch/x86/include/asm/clocksource.h @@ -4,15 +4,10 @@ #ifndef _ASM_X86_CLOCKSOURCE_H #define _ASM_X86_CLOCKSOURCE_H -#define VCLOCK_NONE 0 /* No vDSO clock available. */ -#define VCLOCK_TSC 1 /* vDSO should use vread_tsc. */ -#define VCLOCK_PVCLOCK 2 /* vDSO should use vread_pvclock. */ -#define VCLOCK_HVCLOCK 3 /* vDSO should use vread_hvclock. */ -#define VCLOCK_MAX 3 - -struct arch_clocksource_data { - int vclock_mode; -}; +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_TSC, \ + VDSO_CLOCKMODE_PVCLOCK, \ + VDSO_CLOCKMODE_HVCLOCK extern unsigned int vclocks_used; diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index f7cbc01f128e..edc2c581704a 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -46,9 +46,9 @@ typedef int (*hyperv_fill_flush_list_func)( #define hv_set_reference_tsc(val) \ wrmsrl(HV_X64_MSR_REFERENCE_TSC, val) #define hv_set_clocksource_vdso(val) \ - ((val).archdata.vclock_mode = VCLOCK_HVCLOCK) + ((val).vdso_clock_mode = VDSO_CLOCKMODE_HVCLOCK) #define hv_enable_vdso_clocksource() \ - vclocks_set_used(VCLOCK_HVCLOCK); + vclocks_set_used(VDSO_CLOCKMODE_HVCLOCK); #define hv_get_raw_timer() rdtsc_ordered() void hyperv_callback_vector(void); diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h index 264d4fd3ff2c..9a6dc9b4ec99 100644 --- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -243,7 +243,7 @@ static u64 vread_hvclock(void) static inline u64 __arch_get_hw_counter(s32 clock_mode) { - if (likely(clock_mode == VCLOCK_TSC)) + if (likely(clock_mode == VDSO_CLOCKMODE_TSC)) return (u64)rdtsc_ordered(); /* * For any memory-mapped vclock type, we need to make sure that gcc @@ -252,13 +252,13 @@ static inline u64 __arch_get_hw_counter(s32 clock_mode) * question isn't enabled, which will segfault. Hence the barriers. */ #ifdef CONFIG_PARAVIRT_CLOCK - if (clock_mode == VCLOCK_PVCLOCK) { + if (clock_mode == VDSO_CLOCKMODE_PVCLOCK) { barrier(); return vread_pvclock(); } #endif #ifdef CONFIG_HYPERV_TIMER - if (clock_mode == VCLOCK_HVCLOCK) { + if (clock_mode == VDSO_CLOCKMODE_HVCLOCK) { barrier(); return vread_hvclock(); } diff --git a/arch/x86/include/asm/vdso/vsyscall.h b/arch/x86/include/asm/vdso/vsyscall.h index 01f5733d14d6..be199a9b2676 100644 --- a/arch/x86/include/asm/vdso/vsyscall.h +++ b/arch/x86/include/asm/vdso/vsyscall.h @@ -21,13 +21,6 @@ struct vdso_data *__x86_get_k_vdso_data(void) } #define __arch_get_k_vdso_data __x86_get_k_vdso_data -static __always_inline -int __x86_get_clock_mode(struct timekeeper *tk) -{ - return tk->tkr_mono.clock->archdata.vclock_mode; -} -#define __arch_get_clock_mode __x86_get_clock_mode - /* The asm-generic header needs to be included after the definitions above */ #include diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index 33f2cac25f13..34b18f6eeb2c 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -161,7 +161,7 @@ bool kvm_check_and_clear_guest_paused(void) static int kvm_cs_enable(struct clocksource *cs) { - vclocks_set_used(VCLOCK_PVCLOCK); + vclocks_set_used(VDSO_CLOCKMODE_PVCLOCK); return 0; } @@ -279,7 +279,7 @@ static int __init kvm_setup_vsyscall_timeinfo(void) if (!(flags & PVCLOCK_TSC_STABLE_BIT)) return 0; - kvm_clock.archdata.vclock_mode = VCLOCK_PVCLOCK; + kvm_clock.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK; #endif kvmclock_init_mem(); diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c index 10125358b9c4..11065dc03f5b 100644 --- a/arch/x86/kernel/pvclock.c +++ b/arch/x86/kernel/pvclock.c @@ -145,7 +145,7 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock, void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti) { - WARN_ON(vclock_was_used(VCLOCK_PVCLOCK)); + WARN_ON(vclock_was_used(VDSO_CLOCKMODE_PVCLOCK)); pvti_cpu0_va = pvti; } diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c index d8673d8a779b..4d545db52efc 100644 --- a/arch/x86/kernel/time.c +++ b/arch/x86/kernel/time.c @@ -122,18 +122,12 @@ void __init time_init(void) */ void clocksource_arch_init(struct clocksource *cs) { - if (cs->archdata.vclock_mode == VCLOCK_NONE) + if (cs->vdso_clock_mode == VDSO_CLOCKMODE_NONE) return; - if (cs->archdata.vclock_mode > VCLOCK_MAX) { - pr_warn("clocksource %s registered with invalid vclock_mode %d. Disabling vclock.\n", - cs->name, cs->archdata.vclock_mode); - cs->archdata.vclock_mode = VCLOCK_NONE; - } - if (cs->mask != CLOCKSOURCE_MASK(64)) { - pr_warn("clocksource %s registered with invalid mask %016llx. Disabling vclock.\n", + pr_warn("clocksource %s registered with invalid mask %016llx for VDSO. Disabling VDSO support.\n", cs->name, cs->mask); - cs->archdata.vclock_mode = VCLOCK_NONE; + cs->vdso_clock_mode = VDSO_CLOCKMODE_NONE; } } diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 742da141a30a..971d6f0216df 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -1110,7 +1110,7 @@ static void tsc_cs_tick_stable(struct clocksource *cs) static int tsc_cs_enable(struct clocksource *cs) { - vclocks_set_used(VCLOCK_TSC); + vclocks_set_used(VDSO_CLOCKMODE_TSC); return 0; } @@ -1124,7 +1124,7 @@ static struct clocksource clocksource_tsc_early = { .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, - .archdata = { .vclock_mode = VCLOCK_TSC }, + .vdso_clock_mode = VDSO_CLOCKMODE_TSC, .enable = tsc_cs_enable, .resume = tsc_resume, .mark_unstable = tsc_cs_mark_unstable, @@ -1145,7 +1145,7 @@ static struct clocksource clocksource_tsc = { .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_MUST_VERIFY, - .archdata = { .vclock_mode = VCLOCK_TSC }, + .vdso_clock_mode = VDSO_CLOCKMODE_TSC, .enable = tsc_cs_enable, .resume = tsc_resume, .mark_unstable = tsc_cs_mark_unstable, diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index f194dd058470..cef5a344fedb 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -815,8 +815,8 @@ TRACE_EVENT(kvm_write_tsc_offset, #ifdef CONFIG_X86_64 #define host_clocks \ - {VCLOCK_NONE, "none"}, \ - {VCLOCK_TSC, "tsc"} \ + {VDSO_CLOCKMODE_NONE, "none"}, \ + {VDSO_CLOCKMODE_TSC, "tsc"} \ TRACE_EVENT(kvm_update_master_clock, TP_PROTO(bool use_master_clock, unsigned int host_clock, bool offset_matched), diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index fb5d64ebc35d..0e7ef2955db3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1631,7 +1631,7 @@ static void update_pvclock_gtod(struct timekeeper *tk) write_seqcount_begin(&vdata->seq); /* copy pvclock gtod data */ - vdata->clock.vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; + vdata->clock.vclock_mode = tk->tkr_mono.clock->vdso_clock_mode; vdata->clock.cycle_last = tk->tkr_mono.cycle_last; vdata->clock.mask = tk->tkr_mono.mask; vdata->clock.mult = tk->tkr_mono.mult; @@ -1639,7 +1639,7 @@ static void update_pvclock_gtod(struct timekeeper *tk) vdata->clock.base_cycles = tk->tkr_mono.xtime_nsec; vdata->clock.offset = tk->tkr_mono.base; - vdata->raw_clock.vclock_mode = tk->tkr_raw.clock->archdata.vclock_mode; + vdata->raw_clock.vclock_mode = tk->tkr_raw.clock->vdso_clock_mode; vdata->raw_clock.cycle_last = tk->tkr_raw.cycle_last; vdata->raw_clock.mask = tk->tkr_raw.mask; vdata->raw_clock.mult = tk->tkr_raw.mult; @@ -1840,7 +1840,7 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns) static inline int gtod_is_based_on_tsc(int mode) { - return mode == VCLOCK_TSC || mode == VCLOCK_HVCLOCK; + return mode == VDSO_CLOCKMODE_TSC || mode == VDSO_CLOCKMODE_HVCLOCK; } static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu) @@ -1933,7 +1933,7 @@ static inline bool kvm_check_tsc_unstable(void) * TSC is marked unstable when we're running on Hyper-V, * 'TSC page' clocksource is good. */ - if (pvclock_gtod_data.clock.vclock_mode == VCLOCK_HVCLOCK) + if (pvclock_gtod_data.clock.vclock_mode == VDSO_CLOCKMODE_HVCLOCK) return false; #endif return check_tsc_unstable(); @@ -2088,30 +2088,30 @@ static inline u64 vgettsc(struct pvclock_clock *clock, u64 *tsc_timestamp, u64 tsc_pg_val; switch (clock->vclock_mode) { - case VCLOCK_HVCLOCK: + case VDSO_CLOCKMODE_HVCLOCK: tsc_pg_val = hv_read_tsc_page_tsc(hv_get_tsc_page(), tsc_timestamp); if (tsc_pg_val != U64_MAX) { /* TSC page valid */ - *mode = VCLOCK_HVCLOCK; + *mode = VDSO_CLOCKMODE_HVCLOCK; v = (tsc_pg_val - clock->cycle_last) & clock->mask; } else { /* TSC page invalid */ - *mode = VCLOCK_NONE; + *mode = VDSO_CLOCKMODE_NONE; } break; - case VCLOCK_TSC: - *mode = VCLOCK_TSC; + case VDSO_CLOCKMODE_TSC: + *mode = VDSO_CLOCKMODE_TSC; *tsc_timestamp = read_tsc(); v = (*tsc_timestamp - clock->cycle_last) & clock->mask; break; default: - *mode = VCLOCK_NONE; + *mode = VDSO_CLOCKMODE_NONE; } - if (*mode == VCLOCK_NONE) + if (*mode == VDSO_CLOCKMODE_NONE) *tsc_timestamp = v = 0; return v * clock->mult; diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 5d1568ff19ea..c8897aad13cd 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -147,7 +147,7 @@ static struct notifier_block xen_pvclock_gtod_notifier = { static int xen_cs_enable(struct clocksource *cs) { - vclocks_set_used(VCLOCK_PVCLOCK); + vclocks_set_used(VDSO_CLOCKMODE_PVCLOCK); return 0; } @@ -419,12 +419,13 @@ void xen_restore_time_memory_area(void) ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t); /* - * We don't disable VCLOCK_PVCLOCK entirely if it fails to register the - * secondary time info with Xen or if we migrated to a host without the - * necessary flags. On both of these cases what happens is either - * process seeing a zeroed out pvti or seeing no PVCLOCK_TSC_STABLE_BIT - * bit set. Userspace checks the latter and if 0, it discards the data - * in pvti and fallbacks to a system call for a reliable timestamp. + * We don't disable VDSO_CLOCKMODE_PVCLOCK entirely if it fails to + * register the secondary time info with Xen or if we migrated to a + * host without the necessary flags. On both of these cases what + * happens is either process seeing a zeroed out pvti or seeing no + * PVCLOCK_TSC_STABLE_BIT bit set. Userspace checks the latter and + * if 0, it discards the data in pvti and fallbacks to a system + * call for a reliable timestamp. */ if (ret != 0) pr_notice("Cannot restore secondary vcpu_time_info (err %d)", @@ -450,7 +451,7 @@ static void xen_setup_vsyscall_time_info(void) ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t); if (ret) { - pr_notice("xen: VCLOCK_PVCLOCK not supported (err %d)\n", ret); + pr_notice("xen: VDSO_CLOCKMODE_PVCLOCK not supported (err %d)\n", ret); free_page((unsigned long)ti); return; } @@ -467,14 +468,14 @@ static void xen_setup_vsyscall_time_info(void) if (!ret) free_page((unsigned long)ti); - pr_notice("xen: VCLOCK_PVCLOCK not supported (tsc unstable)\n"); + pr_notice("xen: VDSO_CLOCKMODE_PVCLOCK not supported (tsc unstable)\n"); return; } xen_clock = ti; pvclock_set_pvti_cpu0_va(xen_clock); - xen_clocksource.archdata.vclock_mode = VCLOCK_PVCLOCK; + xen_clocksource.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK; } static void __init xen_time_init(void) -- cgit v1.2.3-70-g09d2 From e1bdb22ebe5363ed75ddedf836ca9f19e1195337 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:57 +0100 Subject: mips: vdso: Use generic VDSO clock mode storage Switch to the generic VDSO clock mode storage. Signed-off-by: Thomas Gleixner Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124403.244684017@linutronix.de --- arch/mips/Kconfig | 2 +- arch/mips/include/asm/clocksource.h | 18 +++--------------- arch/mips/include/asm/vdso/gettimeofday.h | 30 ++++++++++-------------------- arch/mips/include/asm/vdso/vsyscall.h | 9 --------- arch/mips/kernel/csrc-r4k.c | 2 +- drivers/clocksource/mips-gic-timer.c | 8 ++++---- 6 files changed, 19 insertions(+), 50 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 797d7f1ad5fe..23b5c0578776 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -4,7 +4,6 @@ config MIPS default y select ARCH_32BIT_OFF_T if !64BIT select ARCH_BINFMT_ELF_STATE if MIPS_FP_SUPPORT - select ARCH_CLOCKSOURCE_DATA select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_KCOV select ARCH_HAS_PTE_SPECIAL if !(32BIT && CPU_HAS_RIXI) @@ -38,6 +37,7 @@ config MIPS select GENERIC_SCHED_CLOCK if !CAVIUM_OCTEON_SOC select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL + select GENERIC_VDSO_CLOCK_MODE select GUP_GET_PTE_LOW_HIGH if CPU_MIPS32 && PHYS_ADDR_T_64BIT select HANDLE_DOMAIN_IRQ select HAVE_ARCH_COMPILER_H diff --git a/arch/mips/include/asm/clocksource.h b/arch/mips/include/asm/clocksource.h index cab9ae9f1e14..de659cae0d4e 100644 --- a/arch/mips/include/asm/clocksource.h +++ b/arch/mips/include/asm/clocksource.h @@ -3,23 +3,11 @@ * Copyright (C) 2015 Imagination Technologies * Author: Alex Smith */ - #ifndef __ASM_CLOCKSOURCE_H #define __ASM_CLOCKSOURCE_H -#include - -/* VDSO clocksources. */ -#define VDSO_CLOCK_NONE 0 /* No suitable clocksource. */ -#define VDSO_CLOCK_R4K 1 /* Use the coprocessor 0 count. */ -#define VDSO_CLOCK_GIC 2 /* Use the GIC. */ - -/** - * struct arch_clocksource_data - Architecture-specific clocksource information. - * @vdso_clock_mode: Method the VDSO should use to access the clocksource. - */ -struct arch_clocksource_data { - u8 vdso_clock_mode; -}; +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_R4K, \ + VDSO_CLOCKMODE_GIC #endif /* __ASM_CLOCKSOURCE_H */ diff --git a/arch/mips/include/asm/vdso/gettimeofday.h b/arch/mips/include/asm/vdso/gettimeofday.h index a9f846b1a920..88c3de1bdf22 100644 --- a/arch/mips/include/asm/vdso/gettimeofday.h +++ b/arch/mips/include/asm/vdso/gettimeofday.h @@ -24,8 +24,6 @@ #define VDSO_HAS_CLOCK_GETRES 1 -#define __VDSO_USE_SYSCALL ULLONG_MAX - static __always_inline long gettimeofday_fallback( struct __kernel_old_timeval *_tv, struct timezone *_tz) @@ -175,28 +173,20 @@ static __always_inline u64 read_gic_count(const struct vdso_data *data) static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) { -#ifdef CONFIG_CLKSRC_MIPS_GIC - const struct vdso_data *data = get_vdso_data(); -#endif - u64 cycle_now; - - switch (clock_mode) { #ifdef CONFIG_CSRC_R4K - case VDSO_CLOCK_R4K: - cycle_now = read_r4k_count(); - break; + if (clock_mode == VDSO_CLOCKMODE_R4K) + return read_r4k_count(); #endif #ifdef CONFIG_CLKSRC_MIPS_GIC - case VDSO_CLOCK_GIC: - cycle_now = read_gic_count(data); - break; + if (clock_mode == VDSO_CLOCKMODE_GIC) + return read_gic_count(get_vdso_data()); #endif - default: - cycle_now = __VDSO_USE_SYSCALL; - break; - } - - return cycle_now; + /* + * Core checks mode already. So this raced against a concurrent + * update. Return something. Core will do another round see the + * change and fallback to syscall. + */ + return 0; } static inline bool mips_vdso_hres_capable(void) diff --git a/arch/mips/include/asm/vdso/vsyscall.h b/arch/mips/include/asm/vdso/vsyscall.h index 00d41b94ba31..47168aaf1eff 100644 --- a/arch/mips/include/asm/vdso/vsyscall.h +++ b/arch/mips/include/asm/vdso/vsyscall.h @@ -19,15 +19,6 @@ struct vdso_data *__mips_get_k_vdso_data(void) } #define __arch_get_k_vdso_data __mips_get_k_vdso_data -static __always_inline -int __mips_get_clock_mode(struct timekeeper *tk) -{ - u32 clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode; - - return clock_mode; -} -#define __arch_get_clock_mode __mips_get_clock_mode - /* The asm-generic header needs to be included after the definitions above */ #include diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c index eed099f35bf1..437dda64fd7a 100644 --- a/arch/mips/kernel/csrc-r4k.c +++ b/arch/mips/kernel/csrc-r4k.c @@ -78,7 +78,7 @@ int __init init_r4k_clocksource(void) * by the VDSO (HWREna is configured by configure_hwrena()). */ if (cpu_has_mips_r2_r6 && rdhwr_count_usable()) - clocksource_mips.archdata.vdso_clock_mode = VDSO_CLOCK_R4K; + clocksource_mips.vdso_clock_mode = VDSO_CLOCKMODE_R4K; clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 37671a5d4ed9..8b5f8ae723cb 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -155,10 +155,10 @@ static u64 gic_hpt_read(struct clocksource *cs) } static struct clocksource gic_clocksource = { - .name = "GIC", - .read = gic_hpt_read, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .archdata = { .vdso_clock_mode = VDSO_CLOCK_GIC }, + .name = "GIC", + .read = gic_hpt_read, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .vdso_clock_mode = VDSO_CLOCKMODE_GIC, }; static int __init __gic_clocksource_init(void) -- cgit v1.2.3-70-g09d2 From 5e3c6a312a0946d2d83e32359612cbb925a8bed0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:58 +0100 Subject: ARM/arm64: vdso: Use common vdso clock mode storage Convert ARM/ARM64 to the generic VDSO clock mode storage. This needs to happen in one go as they share the clocksource driver. Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124403.363235229@linutronix.de --- arch/arm/Kconfig | 1 - arch/arm/include/asm/clocksource.h | 5 ++--- arch/arm/include/asm/vdso/gettimeofday.h | 12 +++++++++--- arch/arm/include/asm/vdso/vsyscall.h | 21 --------------------- arch/arm/mm/Kconfig | 1 + arch/arm64/Kconfig | 2 +- arch/arm64/include/asm/clocksource.h | 5 ++--- arch/arm64/include/asm/vdso/compat_gettimeofday.h | 11 +++++------ arch/arm64/include/asm/vdso/gettimeofday.h | 11 +++++------ arch/arm64/include/asm/vdso/vsyscall.h | 9 --------- drivers/clocksource/arm_arch_timer.c | 8 ++++---- 11 files changed, 29 insertions(+), 57 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 97864aabc2a6..03bbfc312fe7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -3,7 +3,6 @@ config ARM bool default y select ARCH_32BIT_OFF_T - select ARCH_CLOCKSOURCE_DATA select ARCH_HAS_BINFMT_FLAT select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEVMEM_IS_ALLOWED diff --git a/arch/arm/include/asm/clocksource.h b/arch/arm/include/asm/clocksource.h index 0b350a7e26f3..73beb7f131de 100644 --- a/arch/arm/include/asm/clocksource.h +++ b/arch/arm/include/asm/clocksource.h @@ -1,8 +1,7 @@ #ifndef _ASM_CLOCKSOURCE_H #define _ASM_CLOCKSOURCE_H -struct arch_clocksource_data { - bool vdso_direct; /* Usable for direct VDSO access? */ -}; +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_ARCHTIMER #endif diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h index f4757d327f43..07d791c65cf7 100644 --- a/arch/arm/include/asm/vdso/gettimeofday.h +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -117,15 +117,21 @@ static __always_inline u64 __arch_get_hw_counter(int clock_mode) #ifdef CONFIG_ARM_ARCH_TIMER u64 cycle_now; - if (!clock_mode) - return -EINVAL; + /* + * Core checks for mode already, so this raced against a concurrent + * update. Return something. Core will do another round and then + * see the mode change and fallback to the syscall. + */ + if (clock_mode == VDSO_CLOCKMODE_NONE) + return 0; isb(); cycle_now = read_sysreg(CNTVCT); return cycle_now; #else - return -EINVAL; /* use fallback */ + /* Make GCC happy. This is compiled out anyway */ + return 0; #endif } diff --git a/arch/arm/include/asm/vdso/vsyscall.h b/arch/arm/include/asm/vdso/vsyscall.h index 85a7e58b7228..002f9edd8a2b 100644 --- a/arch/arm/include/asm/vdso/vsyscall.h +++ b/arch/arm/include/asm/vdso/vsyscall.h @@ -11,18 +11,6 @@ extern struct vdso_data *vdso_data; extern bool cntvct_ok; -static __always_inline -bool tk_is_cntvct(const struct timekeeper *tk) -{ - if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) - return false; - - if (!tk->tkr_mono.clock->archdata.vdso_direct) - return false; - - return true; -} - /* * Update the vDSO data page to keep in sync with kernel timekeeping. */ @@ -40,15 +28,6 @@ bool __arm_update_vdso_data(void) } #define __arch_update_vdso_data __arm_update_vdso_data -static __always_inline -int __arm_get_clock_mode(struct timekeeper *tk) -{ - u32 __tk_is_cntvct = tk_is_cntvct(tk); - - return __tk_is_cntvct; -} -#define __arch_get_clock_mode __arm_get_clock_mode - static __always_inline void __arm_sync_vdso_data(struct vdso_data *vdata) { diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 65e4482e3849..865e888bb84f 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -900,6 +900,7 @@ config VDSO select GENERIC_TIME_VSYSCALL select GENERIC_VDSO_32 select GENERIC_GETTIMEOFDAY + select GENERIC_VDSO_CLOCK_MODE help Place in the process address space an ELF shared object providing fast implementations of gettimeofday and diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 0b30e884e088..7809d4976269 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -9,7 +9,6 @@ config ARM64 select ACPI_MCFG if (ACPI && PCI) select ACPI_SPCR_TABLE if ACPI select ACPI_PPTT if ACPI - select ARCH_CLOCKSOURCE_DATA select ARCH_HAS_DEBUG_VIRTUAL select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_DMA_PREP_COHERENT @@ -111,6 +110,7 @@ config ARM64 select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select GENERIC_GETTIMEOFDAY + select GENERIC_VDSO_CLOCK_MODE select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND select HAVE_PCI diff --git a/arch/arm64/include/asm/clocksource.h b/arch/arm64/include/asm/clocksource.h index 0ece64a26c8c..eb82e9d95c5d 100644 --- a/arch/arm64/include/asm/clocksource.h +++ b/arch/arm64/include/asm/clocksource.h @@ -2,8 +2,7 @@ #ifndef _ASM_CLOCKSOURCE_H #define _ASM_CLOCKSOURCE_H -struct arch_clocksource_data { - bool vdso_direct; /* Usable for direct VDSO access? */ -}; +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_ARCHTIMER #endif diff --git a/arch/arm64/include/asm/vdso/compat_gettimeofday.h b/arch/arm64/include/asm/vdso/compat_gettimeofday.h index 537b1e695365..81b0c394f1d8 100644 --- a/arch/arm64/include/asm/vdso/compat_gettimeofday.h +++ b/arch/arm64/include/asm/vdso/compat_gettimeofday.h @@ -12,8 +12,6 @@ #include -#define __VDSO_USE_SYSCALL ULLONG_MAX - #define VDSO_HAS_CLOCK_GETRES 1 #define BUILD_VDSO32 1 @@ -117,11 +115,12 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) u64 res; /* - * clock_mode == 0 implies that vDSO are enabled otherwise - * fallback on syscall. + * Core checks for mode already, so this raced against a concurrent + * update. Return something. Core will do another round and then + * see the mode change and fallback to the syscall. */ - if (clock_mode) - return __VDSO_USE_SYSCALL; + if (clock_mode == VDSO_CLOCKMODE_NONE) + return 0; /* * This isb() is required to prevent that the counter value diff --git a/arch/arm64/include/asm/vdso/gettimeofday.h b/arch/arm64/include/asm/vdso/gettimeofday.h index b08f476b72b4..5a534432aa5d 100644 --- a/arch/arm64/include/asm/vdso/gettimeofday.h +++ b/arch/arm64/include/asm/vdso/gettimeofday.h @@ -10,8 +10,6 @@ #include #include -#define __VDSO_USE_SYSCALL ULLONG_MAX - #define VDSO_HAS_CLOCK_GETRES 1 static __always_inline @@ -71,11 +69,12 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) u64 res; /* - * clock_mode == 0 implies that vDSO are enabled otherwise - * fallback on syscall. + * Core checks for mode already, so this raced against a concurrent + * update. Return something. Core will do another round and then + * see the mode change and fallback to the syscall. */ - if (clock_mode) - return __VDSO_USE_SYSCALL; + if (clock_mode == VDSO_CLOCKMODE_NONE) + return 0; /* * This isb() is required to prevent that the counter value diff --git a/arch/arm64/include/asm/vdso/vsyscall.h b/arch/arm64/include/asm/vdso/vsyscall.h index 0c20a7c1bee5..f94b1457c117 100644 --- a/arch/arm64/include/asm/vdso/vsyscall.h +++ b/arch/arm64/include/asm/vdso/vsyscall.h @@ -21,15 +21,6 @@ struct vdso_data *__arm64_get_k_vdso_data(void) } #define __arch_get_k_vdso_data __arm64_get_k_vdso_data -static __always_inline -int __arm64_get_clock_mode(struct timekeeper *tk) -{ - u32 use_syscall = !tk->tkr_mono.clock->archdata.vdso_direct; - - return use_syscall; -} -#define __arch_get_clock_mode __arm64_get_clock_mode - static __always_inline void __arm64_update_vsyscall(struct vdso_data *vdata, struct timekeeper *tk) { diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 9a5464c625b4..ee2420d56f67 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -69,7 +69,7 @@ static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI; static bool arch_timer_c3stop; static bool arch_timer_mem_use_virtual; static bool arch_counter_suspend_stop; -static bool vdso_default = true; +static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER; static cpumask_t evtstrm_available = CPU_MASK_NONE; static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); @@ -560,8 +560,8 @@ void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa * change both the default value and the vdso itself. */ if (wa->read_cntvct_el0) { - clocksource_counter.archdata.vdso_direct = false; - vdso_default = false; + clocksource_counter.vdso_clock_mode = VDSO_CLOCKMODE_NONE; + vdso_default = VDSO_CLOCKMODE_NONE; } } @@ -979,7 +979,7 @@ static void __init arch_counter_register(unsigned type) } arch_timer_read_counter = rd; - clocksource_counter.archdata.vdso_direct = vdso_default; + clocksource_counter.vdso_clock_mode = vdso_default; } else { arch_timer_read_counter = arch_counter_get_cntvct_mem; } -- cgit v1.2.3-70-g09d2 From f86fd32db706613fe8d0104057efa6e83e0d7e8f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:38:59 +0100 Subject: lib/vdso: Cleanup clock mode storage leftovers Now that all architectures are converted to use the generic storage the helpers and conditionals can be removed. Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124403.470699892@linutronix.de --- arch/arm/mm/Kconfig | 1 - arch/arm64/Kconfig | 1 - arch/mips/Kconfig | 1 - arch/x86/Kconfig | 1 - include/asm-generic/vdso/vsyscall.h | 7 ------- include/linux/clocksource.h | 4 ++-- kernel/time/vsyscall.c | 4 ---- lib/vdso/Kconfig | 3 --- lib/vdso/gettimeofday.c | 17 +++++------------ 9 files changed, 7 insertions(+), 32 deletions(-) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 865e888bb84f..65e4482e3849 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -900,7 +900,6 @@ config VDSO select GENERIC_TIME_VSYSCALL select GENERIC_VDSO_32 select GENERIC_GETTIMEOFDAY - select GENERIC_VDSO_CLOCK_MODE help Place in the process address space an ELF shared object providing fast implementations of gettimeofday and diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7809d4976269..c6c32fb7f546 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -110,7 +110,6 @@ config ARM64 select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select GENERIC_GETTIMEOFDAY - select GENERIC_VDSO_CLOCK_MODE select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND select HAVE_PCI diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 23b5c0578776..654369a7209d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -37,7 +37,6 @@ config MIPS select GENERIC_SCHED_CLOCK if !CAVIUM_OCTEON_SOC select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL - select GENERIC_VDSO_CLOCK_MODE select GUP_GET_PTE_LOW_HIGH if CPU_MIPS32 && PHYS_ADDR_T_64BIT select HANDLE_DOMAIN_IRQ select HAVE_ARCH_COMPILER_H diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 698e9c835cc5..8b995db3d10f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -125,7 +125,6 @@ config X86 select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select GENERIC_GETTIMEOFDAY - select GENERIC_VDSO_CLOCK_MODE select GENERIC_VDSO_TIME_NS select GUP_GET_PTE_LOW_HIGH if X86_PAE select HARDLOCKUP_CHECK_TIMESTAMP if X86_64 diff --git a/include/asm-generic/vdso/vsyscall.h b/include/asm-generic/vdso/vsyscall.h index cec543d9e87b..4a28797495d7 100644 --- a/include/asm-generic/vdso/vsyscall.h +++ b/include/asm-generic/vdso/vsyscall.h @@ -18,13 +18,6 @@ static __always_inline bool __arch_update_vdso_data(void) } #endif /* __arch_update_vdso_data */ -#ifndef __arch_get_clock_mode -static __always_inline int __arch_get_clock_mode(struct timekeeper *tk) -{ - return 0; -} -#endif /* __arch_get_clock_mode */ - #ifndef __arch_update_vsyscall static __always_inline void __arch_update_vsyscall(struct vdso_data *vdata, struct timekeeper *tk) diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 6d5ed1b4d24d..7fefe0b21a14 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -24,13 +24,13 @@ struct clocksource; struct module; #if defined(CONFIG_ARCH_CLOCKSOURCE_DATA) || \ - defined(CONFIG_GENERIC_VDSO_CLOCK_MODE) + defined(CONFIG_GENERIC_GETTIMEOFDAY) #include #endif enum vdso_clock_mode { VDSO_CLOCKMODE_NONE, -#ifdef CONFIG_GENERIC_VDSO_CLOCK_MODE +#ifdef CONFIG_GENERIC_GETTIMEOFDAY VDSO_ARCH_CLOCKMODES, #endif VDSO_CLOCKMODE_MAX, diff --git a/kernel/time/vsyscall.c b/kernel/time/vsyscall.c index f9a5178c69bb..d31a5ef4ade5 100644 --- a/kernel/time/vsyscall.c +++ b/kernel/time/vsyscall.c @@ -77,11 +77,7 @@ void update_vsyscall(struct timekeeper *tk) /* copy vsyscall data */ vdso_write_begin(vdata); -#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; diff --git a/lib/vdso/Kconfig b/lib/vdso/Kconfig index d9f43c84fcc6..d883ac299508 100644 --- a/lib/vdso/Kconfig +++ b/lib/vdso/Kconfig @@ -30,7 +30,4 @@ config GENERIC_VDSO_TIME_NS Selected by architectures which support time namespaces in the VDSO -config GENERIC_VDSO_CLOCK_MODE - bool - endif diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 3f2d8b859130..00f8d1f1405b 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -65,16 +65,13 @@ 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) + + if (unlikely(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 (!IS_ENABLED(CONFIG_GENERIC_VDSO_CLOCK_MODE) && - unlikely((s64)cycles < 0)) - return -1; - ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult); ns >>= vd->shift; sec = vdso_ts->sec; @@ -137,16 +134,12 @@ 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) + if (unlikely(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 (!IS_ENABLED(CONFIG_GENERIC_VDSO_CLOCK_MODE) && - unlikely((s64)cycles < 0)) - return -1; - ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult); ns >>= vd->shift; sec = vdso_ts->sec; -- cgit v1.2.3-70-g09d2 From c7a18100bdffdff440c7291db6e80863fab0461e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:39:00 +0100 Subject: lib/vdso: Avoid highres update if clocksource is not VDSO capable If the current clocksource is not VDSO capable there is no point in updating the high resolution parts of the VDSO data. Replace the architecture specific check with a check for a VDSO capable clocksource and skip the update if there is none. Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124403.563379423@linutronix.de --- arch/arm/include/asm/vdso/vsyscall.h | 7 ------- include/asm-generic/vdso/vsyscall.h | 7 ------- kernel/time/vsyscall.c | 6 +++--- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/arch/arm/include/asm/vdso/vsyscall.h b/arch/arm/include/asm/vdso/vsyscall.h index 002f9edd8a2b..47e41ae8ccd0 100644 --- a/arch/arm/include/asm/vdso/vsyscall.h +++ b/arch/arm/include/asm/vdso/vsyscall.h @@ -21,13 +21,6 @@ struct vdso_data *__arm_get_k_vdso_data(void) } #define __arch_get_k_vdso_data __arm_get_k_vdso_data -static __always_inline -bool __arm_update_vdso_data(void) -{ - return cntvct_ok; -} -#define __arch_update_vdso_data __arm_update_vdso_data - static __always_inline void __arm_sync_vdso_data(struct vdso_data *vdata) { diff --git a/include/asm-generic/vdso/vsyscall.h b/include/asm-generic/vdso/vsyscall.h index 4a28797495d7..c835607f78ae 100644 --- a/include/asm-generic/vdso/vsyscall.h +++ b/include/asm-generic/vdso/vsyscall.h @@ -11,13 +11,6 @@ static __always_inline struct vdso_data *__arch_get_k_vdso_data(void) } #endif /* __arch_get_k_vdso_data */ -#ifndef __arch_update_vdso_data -static __always_inline bool __arch_update_vdso_data(void) -{ - return true; -} -#endif /* __arch_update_vdso_data */ - #ifndef __arch_update_vsyscall static __always_inline void __arch_update_vsyscall(struct vdso_data *vdata, struct timekeeper *tk) diff --git a/kernel/time/vsyscall.c b/kernel/time/vsyscall.c index d31a5ef4ade5..54ce6eb2ca36 100644 --- a/kernel/time/vsyscall.c +++ b/kernel/time/vsyscall.c @@ -105,10 +105,10 @@ void update_vsyscall(struct timekeeper *tk) WRITE_ONCE(vdata[CS_HRES_COARSE].hrtimer_res, hrtimer_resolution); /* - * Architectures can opt out of updating the high resolution part - * of the VDSO. + * If the current clocksource is not VDSO capable, then spare the + * update of the high reolution parts. */ - if (__arch_update_vdso_data()) + if (clock_mode != VDSO_CLOCKMODE_NONE) update_vdso_data(vdata, tk); __arch_update_vsyscall(vdata, tk); -- cgit v1.2.3-70-g09d2 From 2d6b01bd88ccabba06d342ef80eaab6b39d12497 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 7 Feb 2020 13:39:01 +0100 Subject: lib/vdso: Move VCLOCK_TIMENS to vdso_clock_modes Move the time namespace indicator clock mode to the other ones for consistency sake. Signed-off-by: Thomas Gleixner Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124403.656097274@linutronix.de --- include/linux/clocksource.h | 3 +++ include/vdso/datapage.h | 2 -- kernel/time/namespace.c | 7 ++++--- lib/vdso/gettimeofday.c | 18 ++++++++++-------- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 7fefe0b21a14..02e3282719bd 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -34,6 +34,9 @@ enum vdso_clock_mode { VDSO_ARCH_CLOCKMODES, #endif VDSO_CLOCKMODE_MAX, + + /* Indicator for time namespace VDSO */ + VDSO_CLOCKMODE_TIMENS = INT_MAX }; /** diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h index c5f347cc5e55..30c4cb0428d1 100644 --- a/include/vdso/datapage.h +++ b/include/vdso/datapage.h @@ -21,8 +21,6 @@ #define CS_RAW 1 #define CS_BASES (CS_RAW + 1) -#define VCLOCK_TIMENS UINT_MAX - /** * struct vdso_timestamp - basetime per clock_id * @sec: seconds diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c index 12858507d75a..e6ba064ce773 100644 --- a/kernel/time/namespace.c +++ b/kernel/time/namespace.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -172,8 +173,8 @@ static struct timens_offset offset_from_ts(struct timespec64 off) * for vdso_data->clock_mode is a non-issue. The task is spin waiting for the * update to finish and for 'seq' to become even anyway. * - * Timens page has vdso_data->clock_mode set to VCLOCK_TIMENS which enforces - * the time namespace handling path. + * Timens page has vdso_data->clock_mode set to VDSO_CLOCKMODE_TIMENS which + * enforces the time namespace handling path. */ static void timens_setup_vdso_data(struct vdso_data *vdata, struct time_namespace *ns) @@ -183,7 +184,7 @@ static void timens_setup_vdso_data(struct vdso_data *vdata, struct timens_offset boottime = offset_from_ts(ns->offsets.boottime); vdata->seq = 1; - vdata->clock_mode = VCLOCK_TIMENS; + vdata->clock_mode = VDSO_CLOCKMODE_TIMENS; offset[CLOCK_MONOTONIC] = monotonic; offset[CLOCK_MONOTONIC_RAW] = monotonic; offset[CLOCK_MONOTONIC_COARSE] = monotonic; diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 00f8d1f1405b..a76ac8d17c5f 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -116,10 +116,10 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk, do { /* - * Open coded to handle VCLOCK_TIMENS. Time namespace + * Open coded to handle VDSO_CLOCKMODE_TIMENS. Time namespace * enabled tasks have a special VVAR page installed which * has vd->seq set to 1 and vd->clock_mode set to - * VCLOCK_TIMENS. For non time namespace affected tasks + * VDSO_CLOCKMODE_TIMENS. For non time namespace affected tasks * this does not affect performance because if vd->seq is * odd, i.e. a concurrent update is in progress the extra * check for vd->clock_mode is just a few extra @@ -128,7 +128,7 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk, */ while (unlikely((seq = READ_ONCE(vd->seq)) & 1)) { if (IS_ENABLED(CONFIG_TIME_NS) && - vd->clock_mode == VCLOCK_TIMENS) + vd->clock_mode == VDSO_CLOCKMODE_TIMENS) return do_hres_timens(vd, clk, ts); cpu_relax(); } @@ -200,12 +200,12 @@ static __always_inline int do_coarse(const struct vdso_data *vd, clockid_t clk, do { /* - * Open coded to handle VCLOCK_TIMENS. See comment in + * Open coded to handle VDSO_CLOCK_TIMENS. See comment in * do_hres(). */ while ((seq = READ_ONCE(vd->seq)) & 1) { if (IS_ENABLED(CONFIG_TIME_NS) && - vd->clock_mode == VCLOCK_TIMENS) + vd->clock_mode == VDSO_CLOCKMODE_TIMENS) return do_coarse_timens(vd, clk, ts); cpu_relax(); } @@ -292,7 +292,7 @@ __cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) if (unlikely(tz != NULL)) { if (IS_ENABLED(CONFIG_TIME_NS) && - vd->clock_mode == VCLOCK_TIMENS) + vd->clock_mode == VDSO_CLOCKMODE_TIMENS) vd = __arch_get_timens_vdso_data(); tz->tz_minuteswest = vd[CS_HRES_COARSE].tz_minuteswest; @@ -308,7 +308,8 @@ static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time const struct vdso_data *vd = __arch_get_vdso_data(); __kernel_old_time_t t; - if (IS_ENABLED(CONFIG_TIME_NS) && vd->clock_mode == VCLOCK_TIMENS) + if (IS_ENABLED(CONFIG_TIME_NS) && + vd->clock_mode == VDSO_CLOCKMODE_TIMENS) vd = __arch_get_timens_vdso_data(); t = READ_ONCE(vd[CS_HRES_COARSE].basetime[CLOCK_REALTIME].sec); @@ -332,7 +333,8 @@ int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res) if (unlikely((u32) clock >= MAX_CLOCKS)) return -1; - if (IS_ENABLED(CONFIG_TIME_NS) && vd->clock_mode == VCLOCK_TIMENS) + if (IS_ENABLED(CONFIG_TIME_NS) && + vd->clock_mode == VDSO_CLOCKMODE_TIMENS) vd = __arch_get_timens_vdso_data(); /* -- cgit v1.2.3-70-g09d2 From ae12e08539de6717502c2f9f83bd60df939b5c08 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 7 Feb 2020 13:39:02 +0100 Subject: lib/vdso: Allow fixed clock mode Some architectures have a fixed clocksource which is known at compile time and cannot be replaced or disabled at runtime, e.g. timebase on PowerPC. For such cases the clock mode check in the VDSO code is pointless. Move the check for a VDSO capable clocksource into an inline function and allow architectures to redefine it via a macro. [ tglx: Removed the #ifdef mess ] Signed-off-by: Christophe Leroy Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lkml.kernel.org/r/20200207124403.748756829@linutronix.de --- lib/vdso/gettimeofday.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index a76ac8d17c5f..8eb6d1e9a8ff 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -46,6 +46,13 @@ static inline bool __arch_vdso_hres_capable(void) } #endif +#ifndef vdso_clocksource_ok +static inline bool vdso_clocksource_ok(const struct vdso_data *vd) +{ + return vd->clock_mode != VDSO_CLOCKMODE_NONE; +} +#endif + #ifdef CONFIG_TIME_NS static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk, struct __kernel_timespec *ts) @@ -66,7 +73,7 @@ static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk, do { seq = vdso_read_begin(vd); - if (unlikely(vd->clock_mode == VDSO_CLOCKMODE_NONE)) + if (unlikely(!vdso_clocksource_ok(vd))) return -1; cycles = __arch_get_hw_counter(vd->clock_mode); @@ -134,7 +141,7 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk, } smp_rmb(); - if (unlikely(vd->clock_mode == VDSO_CLOCKMODE_NONE)) + if (unlikely(!vdso_clocksource_ok(vd))) return -1; cycles = __arch_get_hw_counter(vd->clock_mode); -- cgit v1.2.3-70-g09d2 From 8345228ccf31f94e3ff7ec5458ac7cc13cb323fa Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 7 Feb 2020 13:39:03 +0100 Subject: lib/vdso: Allow architectures to override the ns shift operation On powerpc/32, GCC (8.1) generates pretty bad code for the ns >>= vd->shift operation taking into account that the shift is always <= 32 and the upper part of the result is likely to be zero. GCC makes reversed assumptions considering the shift to be likely >= 32 and the upper part to be like not zero. unsigned long long shift(unsigned long long x, unsigned char s) { return x >> s; } results in: 00000018 : 18: 35 25 ff e0 addic. r9,r5,-32 1c: 41 80 00 10 blt 2c 20: 7c 64 4c 30 srw r4,r3,r9 24: 38 60 00 00 li r3,0 28: 4e 80 00 20 blr 2c: 54 69 08 3c rlwinm r9,r3,1,0,30 30: 21 45 00 1f subfic r10,r5,31 34: 7c 84 2c 30 srw r4,r4,r5 38: 7d 29 50 30 slw r9,r9,r10 3c: 7c 63 2c 30 srw r3,r3,r5 40: 7d 24 23 78 or r4,r9,r4 44: 4e 80 00 20 blr Even when forcing the shift to be smaller than 32 with an &= 31, it still considers the shift as likely >= 32. Move the default shift implementation into an inline which can be redefined in architecture code via a macro. [ tglx: Made the shift argument u32 and removed the __arch prefix ] Signed-off-by: Christophe Leroy Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lore.kernel.org/r/b3d449de856982ed060a71e6ace8eeca4654e685.1580399657.git.christophe.leroy@c-s.fr Link: https://lkml.kernel.org/r/20200207124403.857649978@linutronix.de --- lib/vdso/gettimeofday.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 8eb6d1e9a8ff..b95aef97501e 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -39,6 +39,13 @@ u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) } #endif +#ifndef vdso_shift_ns +static __always_inline u64 vdso_shift_ns(u64 ns, u32 shift) +{ + return ns >> shift; +} +#endif + #ifndef __arch_vdso_hres_capable static inline bool __arch_vdso_hres_capable(void) { @@ -80,7 +87,7 @@ static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk, ns = vdso_ts->nsec; last = vd->cycle_last; ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult); - ns >>= vd->shift; + ns = vdso_shift_ns(ns, vd->shift); sec = vdso_ts->sec; } while (unlikely(vdso_read_retry(vd, seq))); @@ -148,7 +155,7 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk, ns = vdso_ts->nsec; last = vd->cycle_last; ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult); - ns >>= vd->shift; + ns = vdso_shift_ns(ns, vd->shift); sec = vdso_ts->sec; } while (unlikely(vdso_read_retry(vd, seq))); -- cgit v1.2.3-70-g09d2 From e876f0b69dc993e86ca7795e63e98385aa9a7ef3 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 7 Feb 2020 13:39:04 +0100 Subject: lib/vdso: Allow architectures to provide the vdso data pointer On powerpc, __arch_get_vdso_data() clobbers the link register, requiring the caller to save it. As the parent function already has to set a stack frame and saves the link register before calling the C vdso function, retrieving the vdso data pointer there is less overhead. Split out the functional code from the __cvdso.*() interfaces into new static functions which can either be called from the existing interfaces with the vdso data pointer supplied via __arch_get_vdso_data() or directly from ASM code. Signed-off-by: Christophe Leroy Signed-off-by: Thomas Gleixner Tested-by: Vincenzo Frascino Reviewed-by: Vincenzo Frascino Link: https://lore.kernel.org/r/abf97996602ef07223fec30c005df78e5ed41b2e.1580399657.git.christophe.leroy@c-s.fr Link: https://lkml.kernel.org/r/20200207124403.965789141@linutronix.de --- lib/vdso/gettimeofday.c | 72 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index b95aef97501e..72d282ffd156 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -233,9 +233,9 @@ static __always_inline int do_coarse(const struct vdso_data *vd, clockid_t clk, } static __maybe_unused int -__cvdso_clock_gettime_common(clockid_t clock, struct __kernel_timespec *ts) +__cvdso_clock_gettime_common(const struct vdso_data *vd, clockid_t clock, + struct __kernel_timespec *ts) { - const struct vdso_data *vd = __arch_get_vdso_data(); u32 msk; /* Check for negative values or invalid clocks */ @@ -260,23 +260,31 @@ __cvdso_clock_gettime_common(clockid_t clock, struct __kernel_timespec *ts) } static __maybe_unused int -__cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) +__cvdso_clock_gettime_data(const struct vdso_data *vd, clockid_t clock, + struct __kernel_timespec *ts) { - int ret = __cvdso_clock_gettime_common(clock, ts); + int ret = __cvdso_clock_gettime_common(vd, clock, ts); if (unlikely(ret)) return clock_gettime_fallback(clock, ts); return 0; } +static __maybe_unused int +__cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) +{ + return __cvdso_clock_gettime_data(__arch_get_vdso_data(), clock, ts); +} + #ifdef BUILD_VDSO32 static __maybe_unused int -__cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res) +__cvdso_clock_gettime32_data(const struct vdso_data *vd, clockid_t clock, + struct old_timespec32 *res) { struct __kernel_timespec ts; int ret; - ret = __cvdso_clock_gettime_common(clock, &ts); + ret = __cvdso_clock_gettime_common(vd, clock, &ts); if (unlikely(ret)) return clock_gettime32_fallback(clock, res); @@ -287,12 +295,18 @@ __cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res) return ret; } + +static __maybe_unused int +__cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res) +{ + return __cvdso_clock_gettime32_data(__arch_get_vdso_data(), clock, res); +} #endif /* BUILD_VDSO32 */ static __maybe_unused int -__cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) +__cvdso_gettimeofday_data(const struct vdso_data *vd, + struct __kernel_old_timeval *tv, struct timezone *tz) { - const struct vdso_data *vd = __arch_get_vdso_data(); if (likely(tv != NULL)) { struct __kernel_timespec ts; @@ -316,10 +330,16 @@ __cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) return 0; } +static __maybe_unused int +__cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) +{ + return __cvdso_gettimeofday_data(__arch_get_vdso_data(), tv, tz); +} + #ifdef VDSO_HAS_TIME -static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time) +static __maybe_unused __kernel_old_time_t +__cvdso_time_data(const struct vdso_data *vd, __kernel_old_time_t *time) { - const struct vdso_data *vd = __arch_get_vdso_data(); __kernel_old_time_t t; if (IS_ENABLED(CONFIG_TIME_NS) && @@ -333,13 +353,18 @@ static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time return t; } + +static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time) +{ + return __cvdso_time_data(__arch_get_vdso_data(), time); +} #endif /* VDSO_HAS_TIME */ #ifdef VDSO_HAS_CLOCK_GETRES static __maybe_unused -int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res) +int __cvdso_clock_getres_common(const struct vdso_data *vd, clockid_t clock, + struct __kernel_timespec *res) { - const struct vdso_data *vd = __arch_get_vdso_data(); u32 msk; u64 ns; @@ -378,23 +403,31 @@ int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res) } static __maybe_unused -int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res) +int __cvdso_clock_getres_data(const struct vdso_data *vd, clockid_t clock, + struct __kernel_timespec *res) { - int ret = __cvdso_clock_getres_common(clock, res); + int ret = __cvdso_clock_getres_common(vd, clock, res); if (unlikely(ret)) return clock_getres_fallback(clock, res); return 0; } +static __maybe_unused +int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res) +{ + return __cvdso_clock_getres_data(__arch_get_vdso_data(), clock, res); +} + #ifdef BUILD_VDSO32 static __maybe_unused int -__cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res) +__cvdso_clock_getres_time32_data(const struct vdso_data *vd, clockid_t clock, + struct old_timespec32 *res) { struct __kernel_timespec ts; int ret; - ret = __cvdso_clock_getres_common(clock, &ts); + ret = __cvdso_clock_getres_common(vd, clock, &ts); if (unlikely(ret)) return clock_getres32_fallback(clock, res); @@ -405,5 +438,12 @@ __cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res) } return ret; } + +static __maybe_unused int +__cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res) +{ + return __cvdso_clock_getres_time32_data(__arch_get_vdso_data(), + clock, res); +} #endif /* BUILD_VDSO32 */ #endif /* VDSO_HAS_CLOCK_GETRES */ -- cgit v1.2.3-70-g09d2 From 6e317c32fd39a13e4854a27958d5e35d15d196be Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Sat, 18 Jan 2020 01:59:00 +0300 Subject: timer: Improve the comment describing schedule_timeout() When working commit 6dcd5d7a7a29c1e, a mistake was noticed by Linus: schedule_timeout() was called without setting the task state to anything particular. It calls the scheduler, but doesn't delay anything, because the task stays runnable. That happens because sched_submit_work() does nothing for tasks in TASK_RUNNING state. That turned out to be the intended behavior. Adding a WARN() is not useful as the task could be woken up right after setting the state and before reaching schedule_timeout(). Improve the comment about schedule_timeout() and describe that more explicitly. Signed-off-by: Alexander Popov Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200117225900.16340-1-alex.popov@linux.com --- kernel/time/timer.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 4820823515e9..cb34fac9d9f7 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1828,21 +1828,23 @@ static void process_timeout(struct timer_list *t) * schedule_timeout - sleep until timeout * @timeout: timeout value in jiffies * - * Make the current task sleep until @timeout jiffies have - * elapsed. The routine will return immediately unless - * the current task state has been set (see set_current_state()). + * Make the current task sleep until @timeout jiffies have elapsed. + * The function behavior depends on the current task state + * (see also set_current_state() description): * - * You can set the task state as follows - + * %TASK_RUNNING - the scheduler is called, but the task does not sleep + * at all. That happens because sched_submit_work() does nothing for + * tasks in %TASK_RUNNING state. * * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to * pass before the routine returns unless the current task is explicitly - * woken up, (e.g. by wake_up_process())". + * woken up, (e.g. by wake_up_process()). * * %TASK_INTERRUPTIBLE - the routine may return early if a signal is * delivered to the current task or the current task is explicitly woken * up. * - * The current task state is guaranteed to be TASK_RUNNING when this + * The current task state is guaranteed to be %TASK_RUNNING when this * routine returns. * * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule @@ -1850,7 +1852,7 @@ static void process_timeout(struct timer_list *t) * value will be %MAX_SCHEDULE_TIMEOUT. * * Returns 0 when the timer has expired otherwise the remaining time in - * jiffies will be returned. In all cases the return value is guaranteed + * jiffies will be returned. In all cases the return value is guaranteed * to be non-negative. */ signed long __sched schedule_timeout(signed long timeout) -- cgit v1.2.3-70-g09d2 From 5fb1c2a5bbf79ccca8d17cf97f66085be5808027 Mon Sep 17 00:00:00 2001 From: Amol Grover Date: Sun, 16 Feb 2020 13:13:30 +0530 Subject: posix-timers: Pass lockdep expression to RCU lists head is traversed using hlist_for_each_entry_rcu outside an RCU read-side critical section but under the protection of hash_lock. Hence, add corresponding lockdep expression to silence false-positive lockdep warnings, and harden RCU lists. [ tglx: Removed the macro and put the condition right where it's used ] Signed-off-by: Amol Grover Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200216074330.GA14025@workstation-portable --- kernel/time/posix-timers.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index ff0eb30de346..07709ac30439 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -121,7 +121,8 @@ static struct k_itimer *__posix_timers_find(struct hlist_head *head, { struct k_itimer *timer; - hlist_for_each_entry_rcu(timer, head, t_hash) { + hlist_for_each_entry_rcu(timer, head, t_hash, + lockdep_is_held(&hash_lock)) { if ((timer->it_signal == sig) && (timer->it_id == id)) return timer; } -- cgit v1.2.3-70-g09d2 From 84fb64c28acd85ae4d29b9c81926bdfa5f1bf25e Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Thu, 7 Nov 2019 20:12:15 +1030 Subject: clocksource/drivers/fttmr010: Parametrise shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for supporting the ast2600 which uses a different method to clear bits in the control register, use a callback for performing the shutdown sequence. Reviewed-by: Cédric Le Goater Reviewed-by: Linus Walleij Signed-off-by: Joel Stanley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191107094218.13210-2-joel@jms.id.au --- drivers/clocksource/timer-fttmr010.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c index fadff7915dd9..c2d30eb9dc72 100644 --- a/drivers/clocksource/timer-fttmr010.c +++ b/drivers/clocksource/timer-fttmr010.c @@ -97,6 +97,7 @@ struct fttmr010 { bool is_aspeed; u32 t1_enable_val; struct clock_event_device clkevt; + int (*timer_shutdown)(struct clock_event_device *evt); #ifdef CONFIG_ARM struct delay_timer delay_timer; #endif @@ -140,9 +141,7 @@ static int fttmr010_timer_set_next_event(unsigned long cycles, u32 cr; /* Stop */ - cr = readl(fttmr010->base + TIMER_CR); - cr &= ~fttmr010->t1_enable_val; - writel(cr, fttmr010->base + TIMER_CR); + fttmr010->timer_shutdown(evt); if (fttmr010->is_aspeed) { /* @@ -183,9 +182,7 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) u32 cr; /* Stop */ - cr = readl(fttmr010->base + TIMER_CR); - cr &= ~fttmr010->t1_enable_val; - writel(cr, fttmr010->base + TIMER_CR); + fttmr010->timer_shutdown(evt); /* Setup counter start from 0 or ~0 */ writel(0, fttmr010->base + TIMER1_COUNT); @@ -211,9 +208,7 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt) u32 cr; /* Stop */ - cr = readl(fttmr010->base + TIMER_CR); - cr &= ~fttmr010->t1_enable_val; - writel(cr, fttmr010->base + TIMER_CR); + fttmr010->timer_shutdown(evt); /* Setup timer to fire at 1/HZ intervals. */ if (fttmr010->is_aspeed) { @@ -350,6 +345,8 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed) fttmr010->tick_rate); } + fttmr010->timer_shutdown = fttmr010_timer_shutdown; + /* * Setup clockevent timer (interrupt-driven) on timer 1. */ @@ -370,10 +367,10 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed) fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event; - fttmr010->clkevt.set_state_shutdown = fttmr010_timer_shutdown; + fttmr010->clkevt.set_state_shutdown = fttmr010->timer_shutdown; fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic; fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot; - fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown; + fttmr010->clkevt.tick_resume = fttmr010->timer_shutdown; fttmr010->clkevt.cpumask = cpumask_of(0); fttmr010->clkevt.irq = irq; clockevents_config_and_register(&fttmr010->clkevt, -- cgit v1.2.3-70-g09d2 From 5422413ce56877f35415f6e4b53171e6e13ec4c1 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Thu, 7 Nov 2019 20:12:16 +1030 Subject: clocksource/drivers/fttmr010: Set interrupt and shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for supporting the ast2600, pass the shutdown and interrupt functions to the common init callback. Reviewed-by: Cédric Le Goater Reviewed-by: Linus Walleij Signed-off-by: Joel Stanley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191107094218.13210-3-joel@jms.id.au --- drivers/clocksource/timer-fttmr010.c | 51 ++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c index c2d30eb9dc72..edb1d5f193f5 100644 --- a/drivers/clocksource/timer-fttmr010.c +++ b/drivers/clocksource/timer-fttmr010.c @@ -37,6 +37,11 @@ #define TIMER3_MATCH2 (0x2c) #define TIMER_CR (0x30) +/* + * Control register set to clear for ast2600 only. + */ +#define AST2600_TIMER_CR_CLR (0x3c) + /* * Control register (TMC30) bit fields for fttmr010/gemini/moxart timers. */ @@ -163,6 +168,16 @@ static int fttmr010_timer_set_next_event(unsigned long cycles, return 0; } +static int ast2600_timer_shutdown(struct clock_event_device *evt) +{ + struct fttmr010 *fttmr010 = to_fttmr010(evt); + + /* Stop */ + writel(fttmr010->t1_enable_val, fttmr010->base + AST2600_TIMER_CR_CLR); + + return 0; +} + static int fttmr010_timer_shutdown(struct clock_event_device *evt) { struct fttmr010 *fttmr010 = to_fttmr010(evt); @@ -244,7 +259,21 @@ static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed) +static irqreturn_t ast2600_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + struct fttmr010 *fttmr010 = to_fttmr010(evt); + + writel(0x1, fttmr010->base + TIMER_INTR_STATE); + + evt->event_handler(evt); + return IRQ_HANDLED; +} + +static int __init fttmr010_common_init(struct device_node *np, + bool is_aspeed, + int (*timer_shutdown)(struct clock_event_device *), + irq_handler_t irq_handler) { struct fttmr010 *fttmr010; int irq; @@ -345,7 +374,7 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed) fttmr010->tick_rate); } - fttmr010->timer_shutdown = fttmr010_timer_shutdown; + fttmr010->timer_shutdown = timer_shutdown; /* * Setup clockevent timer (interrupt-driven) on timer 1. @@ -354,7 +383,7 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed) writel(0, fttmr010->base + TIMER1_LOAD); writel(0, fttmr010->base + TIMER1_MATCH1); writel(0, fttmr010->base + TIMER1_MATCH2); - ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER, + ret = request_irq(irq, irq_handler, IRQF_TIMER, "FTTMR010-TIMER1", &fttmr010->clkevt); if (ret) { pr_err("FTTMR010-TIMER1 no IRQ\n"); @@ -401,14 +430,25 @@ out_disable_clock: return ret; } +static __init int ast2600_timer_init(struct device_node *np) +{ + return fttmr010_common_init(np, true, + ast2600_timer_shutdown, + ast2600_timer_interrupt); +} + static __init int aspeed_timer_init(struct device_node *np) { - return fttmr010_common_init(np, true); + return fttmr010_common_init(np, true, + fttmr010_timer_shutdown, + fttmr010_timer_interrupt); } static __init int fttmr010_timer_init(struct device_node *np) { - return fttmr010_common_init(np, false); + return fttmr010_common_init(np, false, + fttmr010_timer_shutdown, + fttmr010_timer_interrupt); } TIMER_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); @@ -416,3 +456,4 @@ TIMER_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); TIMER_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init); TIMER_OF_DECLARE(ast2400, "aspeed,ast2400-timer", aspeed_timer_init); TIMER_OF_DECLARE(ast2500, "aspeed,ast2500-timer", aspeed_timer_init); +TIMER_OF_DECLARE(ast2600, "aspeed,ast2600-timer", ast2600_timer_init); -- cgit v1.2.3-70-g09d2 From 5be8badcb64be4c6ac5b0e8b882eca8eb175ec2d Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Thu, 7 Nov 2019 20:12:18 +1030 Subject: dt-bindings: fttmr010: Add ast2600 compatible The ast2600 contains a fttmr010 derivative. Reviewed-by: Linus Walleij Acked-by: Rob Herring Signed-off-by: Joel Stanley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191107094218.13210-5-joel@jms.id.au --- Documentation/devicetree/bindings/timer/faraday,fttmr010.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/timer/faraday,fttmr010.txt b/Documentation/devicetree/bindings/timer/faraday,fttmr010.txt index 195792270414..3cb2f4c98d64 100644 --- a/Documentation/devicetree/bindings/timer/faraday,fttmr010.txt +++ b/Documentation/devicetree/bindings/timer/faraday,fttmr010.txt @@ -11,6 +11,7 @@ Required properties: "moxa,moxart-timer", "faraday,fttmr010" "aspeed,ast2400-timer" "aspeed,ast2500-timer" + "aspeed,ast2600-timer" - reg : Should contain registers location and length - interrupts : Should contain the three timer interrupts usually with -- cgit v1.2.3-70-g09d2 From a67de48b3075cbb6ec030205d7b78981def6596d Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Mon, 24 Feb 2020 15:15:52 +0000 Subject: clocksource/drivers/arm_arch_timer: Fix vDSO clockmode when vDSO disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The arm_arch_timer requires VDSO_CLOCKMODE_ARCHTIMER to be defined to compile correctly. On ARM the vDSO can be disabled and when this is the case the compilation ends prematurely with an error: $ make ARCH=arm multi_v7_defconfig $ ./scripts/config -d VDSO $ make drivers/clocksource/arm_arch_timer.c:73:44: error: ‘VDSO_CLOCKMODE_ARCHTIMER’ undeclared here (not in a function) static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER; Make the usage of VDSO_CLOCKMODE_ARCHTIMER depend on the VDSO enablement and initialize the vdso clockmode variable with VDSO_CLOCKMODE_NONE otherwise. [ tglx: Match changelog and patch content. ] Fixes: 5e3c6a312a09 ("ARM/arm64: vdso: Use common vdso clock mode storage") Reported-by: Marek Szyprowski Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200224151552.57274-1-vincenzo.frascino@arm.com --- drivers/clocksource/arm_arch_timer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index ee2420d56f67..d53f4c7ccaae 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -69,7 +69,11 @@ static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI; static bool arch_timer_c3stop; static bool arch_timer_mem_use_virtual; static bool arch_counter_suspend_stop; +#ifdef CONFIG_GENERIC_GETTIMEOFDAY static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER; +#else +static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_NONE; +#endif /* CONFIG_GENERIC_GETTIMEOFDAY */ static cpumask_t evtstrm_available = CPU_MASK_NONE; static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); -- cgit v1.2.3-70-g09d2 From ca7b72b5a5f248b72c88441a93bdcee22f42b9b3 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 12 Feb 2020 15:04:08 -0300 Subject: clocksource: Add driver for the Ingenic JZ47xx OST OST is the OS Timer, a 64-bit timer/counter with buffered reading. SoCs before the JZ4770 had (if any) a 32-bit OST; the JZ4770 and JZ4780 have a 64-bit OST. This driver will register both a clocksource and a sched_clock to the system. Signed-off-by: Maarten ter Huurne Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Tested-by: Artur Rojek Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200212180408.30872-1-paul@crapouillou.net --- drivers/clocksource/Kconfig | 8 ++ drivers/clocksource/Makefile | 1 + drivers/clocksource/ingenic-ost.c | 189 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/clocksource/ingenic-ost.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cc909e465823..f2142e6bbea3 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -697,6 +697,14 @@ config INGENIC_TIMER help Support for the timer/counter unit of the Ingenic JZ SoCs. +config INGENIC_OST + bool "Clocksource for Ingenic OS Timer" + depends on MIPS || COMPILE_TEST + depends on COMMON_CLK + select MFD_SYSCON + help + Support for the Operating System Timer of the Ingenic JZ SoCs. + config MICROCHIP_PIT64B bool "Microchip PIT64B support" depends on OF || COMPILE_TEST diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 713686faa549..641ba5383ab5 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o obj-$(CONFIG_H8300_TPU) += h8300_tpu.o +obj-$(CONFIG_INGENIC_OST) += ingenic-ost.o obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o obj-$(CONFIG_X86_NUMACHIP) += numachip.o diff --git a/drivers/clocksource/ingenic-ost.c b/drivers/clocksource/ingenic-ost.c new file mode 100644 index 000000000000..029efc2731b4 --- /dev/null +++ b/drivers/clocksource/ingenic-ost.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ47xx SoCs TCU Operating System Timer driver + * + * Copyright (C) 2016 Maarten ter Huurne + * Copyright (C) 2020 Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TCU_OST_TCSR_MASK 0xffc0 +#define TCU_OST_TCSR_CNT_MD BIT(15) + +#define TCU_OST_CHANNEL 15 + +/* + * The TCU_REG_OST_CNT{L,R} from are only for the + * regmap; these are for use with the __iomem pointer. + */ +#define OST_REG_CNTL 0x4 +#define OST_REG_CNTH 0x8 + +struct ingenic_ost_soc_info { + bool is64bit; +}; + +struct ingenic_ost { + void __iomem *regs; + struct clk *clk; + + struct clocksource cs; +}; + +static struct ingenic_ost *ingenic_ost; + +static u64 notrace ingenic_ost_read_cntl(void) +{ + /* Read using __iomem pointer instead of regmap to avoid locking */ + return readl(ingenic_ost->regs + OST_REG_CNTL); +} + +static u64 notrace ingenic_ost_read_cnth(void) +{ + /* Read using __iomem pointer instead of regmap to avoid locking */ + return readl(ingenic_ost->regs + OST_REG_CNTH); +} + +static u64 notrace ingenic_ost_clocksource_readl(struct clocksource *cs) +{ + return ingenic_ost_read_cntl(); +} + +static u64 notrace ingenic_ost_clocksource_readh(struct clocksource *cs) +{ + return ingenic_ost_read_cnth(); +} + +static int __init ingenic_ost_probe(struct platform_device *pdev) +{ + const struct ingenic_ost_soc_info *soc_info; + struct device *dev = &pdev->dev; + struct ingenic_ost *ost; + struct clocksource *cs; + struct regmap *map; + unsigned long rate; + int err; + + soc_info = device_get_match_data(dev); + if (!soc_info) + return -EINVAL; + + ost = devm_kzalloc(dev, sizeof(*ost), GFP_KERNEL); + if (!ost) + return -ENOMEM; + + ingenic_ost = ost; + + ost->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ost->regs)) + return PTR_ERR(ost->regs); + + map = device_node_to_regmap(dev->parent->of_node); + if (!map) { + dev_err(dev, "regmap not found"); + return -EINVAL; + } + + ost->clk = devm_clk_get(dev, "ost"); + if (IS_ERR(ost->clk)) + return PTR_ERR(ost->clk); + + err = clk_prepare_enable(ost->clk); + if (err) + return err; + + /* Clear counter high/low registers */ + if (soc_info->is64bit) + regmap_write(map, TCU_REG_OST_CNTL, 0); + regmap_write(map, TCU_REG_OST_CNTH, 0); + + /* Don't reset counter at compare value. */ + regmap_update_bits(map, TCU_REG_OST_TCSR, + TCU_OST_TCSR_MASK, TCU_OST_TCSR_CNT_MD); + + rate = clk_get_rate(ost->clk); + + /* Enable OST TCU channel */ + regmap_write(map, TCU_REG_TESR, BIT(TCU_OST_CHANNEL)); + + cs = &ost->cs; + cs->name = "ingenic-ost"; + cs->rating = 320; + cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + cs->mask = CLOCKSOURCE_MASK(32); + + if (soc_info->is64bit) + cs->read = ingenic_ost_clocksource_readl; + else + cs->read = ingenic_ost_clocksource_readh; + + err = clocksource_register_hz(cs, rate); + if (err) { + dev_err(dev, "clocksource registration failed"); + clk_disable_unprepare(ost->clk); + return err; + } + + if (soc_info->is64bit) + sched_clock_register(ingenic_ost_read_cntl, 32, rate); + else + sched_clock_register(ingenic_ost_read_cnth, 32, rate); + + return 0; +} + +static int __maybe_unused ingenic_ost_suspend(struct device *dev) +{ + struct ingenic_ost *ost = dev_get_drvdata(dev); + + clk_disable(ost->clk); + + return 0; +} + +static int __maybe_unused ingenic_ost_resume(struct device *dev) +{ + struct ingenic_ost *ost = dev_get_drvdata(dev); + + return clk_enable(ost->clk); +} + +static const struct dev_pm_ops __maybe_unused ingenic_ost_pm_ops = { + /* _noirq: We want the OST clock to be gated last / ungated first */ + .suspend_noirq = ingenic_ost_suspend, + .resume_noirq = ingenic_ost_resume, +}; + +static const struct ingenic_ost_soc_info jz4725b_ost_soc_info = { + .is64bit = false, +}; + +static const struct ingenic_ost_soc_info jz4770_ost_soc_info = { + .is64bit = true, +}; + +static const struct of_device_id ingenic_ost_of_match[] = { + { .compatible = "ingenic,jz4725b-ost", .data = &jz4725b_ost_soc_info, }, + { .compatible = "ingenic,jz4770-ost", .data = &jz4770_ost_soc_info, }, + { } +}; + +static struct platform_driver ingenic_ost_driver = { + .driver = { + .name = "ingenic-ost", +#ifdef CONFIG_PM_SUSPEND + .pm = &ingenic_ost_pm_ops, +#endif + .of_match_table = ingenic_ost_of_match, + }, +}; +builtin_platform_driver_probe(ingenic_ost_driver, ingenic_ost_probe); -- cgit v1.2.3-70-g09d2 From ad1ded9d2e3d1eb452ff58d325aadf237e187bd9 Mon Sep 17 00:00:00 2001 From: Matheus Castello Date: Tue, 18 Feb 2020 21:48:10 -0300 Subject: clocksource/drivers/owl: Improve owl_timer_init fail messages Check the return from clocksource_mmio_init, add messages in case of an error and in case of not having a defined clock property. Signed-off-by: Matheus Castello Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200219004810.411190-1-matheus@castello.eng.br --- drivers/clocksource/timer-owl.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/clocksource/timer-owl.c b/drivers/clocksource/timer-owl.c index 900fe736145d..ac97420bfa7c 100644 --- a/drivers/clocksource/timer-owl.c +++ b/drivers/clocksource/timer-owl.c @@ -135,8 +135,11 @@ static int __init owl_timer_init(struct device_node *node) } clk = of_clk_get(node, 0); - if (IS_ERR(clk)) - return PTR_ERR(clk); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + pr_err("Failed to get clock for clocksource (%d)\n", ret); + return ret; + } rate = clk_get_rate(clk); @@ -144,8 +147,12 @@ static int __init owl_timer_init(struct device_node *node) owl_timer_set_enabled(owl_clksrc_base, true); sched_clock_register(owl_timer_sched_read, 32, rate); - clocksource_mmio_init(owl_clksrc_base + OWL_Tx_VAL, node->name, - rate, 200, 32, clocksource_mmio_readl_up); + ret = clocksource_mmio_init(owl_clksrc_base + OWL_Tx_VAL, node->name, + rate, 200, 32, clocksource_mmio_readl_up); + if (ret) { + pr_err("Failed to register clocksource (%d)\n", ret); + return ret; + } owl_timer_reset(owl_clkevt_base); -- cgit v1.2.3-70-g09d2 From 6ce4fcb015a1a1290ffafcf3554901b40f9322df Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Mon, 24 Feb 2020 10:37:53 +0530 Subject: clocksource/drivers/timer-ti-dm: Do not update counter on updating the period Write to trigger register(OMAP_TIMER_TRIGGER_REG) will load the value in Load register(OMAP_TIMER_LOAD_REG) into Counter register (OMAP_TIMER_COUNTER_REG). omap_dm_timer_set_load() writes into trigger register every time load register is updated. When timer is configured in pwm mode, this causes disruption in current pwm cycle, which is not expected especially when pwm is used as PPS signal for synchronized PTP clocks. So do not write into trigger register on updating the period. Signed-off-by: Lokesh Vutla Tested-by: Tony Lindgren Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200224050753.17784-3-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 269a994d6a99..acc93600d351 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -577,7 +577,6 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); - omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); /* Save the context */ timer->context.tclr = l; timer->context.tldr = load; -- cgit v1.2.3-70-g09d2 From 753e83408b7f2980b7a5bfcf01f1175a937a2340 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 12 Feb 2020 23:35:04 -0600 Subject: clocksource/drivers/timer-ti-dm: Drop bogus omap_dm_timer_of_set_source() The function omap_dm_timer_of_set_source() was originally added in commit 31a7448f4fa8a ("ARM: OMAP: dmtimer: Add clock source from DT"), and is designed to set a clock source from DT using the clocks property of a timer node. This design choice is okay for clk provider nodes but otherwise is a bad design as typically the clocks property is used to specify the functional clocks for a device, and not its parents. The timer nodes now all define a timer functional clock after the conversion to ti-sysc and the new clkctrl layout, and this results in an attempt to set the same functional clock as its parent when a consumer driver attempts to acquire any of these timers in the omap_dm_timer_prepare() function. This was masked and worked around in commit 983a5a43ec25 ("clocksource: timer-ti-dm: Fix pwm dmtimer usage of fck reparenting"). Fix all of this by simply dropping the entire function. Any DT configuration of clock sources should be achieved using assigned-clocks and assigned-clock-parents properties provided by the Common Clock Framework. Cc: Tony Lindgren Cc: Tero Kristo Cc: Neil Armstrong Cc: H. Nikolaus Schaller Cc: Bartosz Golaszewski Cc: Keerthy Cc: Ladislav Michl Cc: Pavel Machek Cc: Sebastian Reichel Signed-off-by: Suman Anna Tested-by: Lokesh Vutla Tested-by: Tony Lindgren Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200213053504.22638-1-s-anna@ti.com --- drivers/clocksource/timer-ti-dm.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index acc93600d351..6a0adb7104b3 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -138,35 +138,6 @@ static int omap_dm_timer_reset(struct omap_dm_timer *timer) return 0; } -static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer) -{ - int ret; - struct clk *parent; - - /* - * FIXME: OMAP1 devices do not use the clock framework for dmtimers so - * do not call clk_get() for these devices. - */ - if (!timer->fclk) - return -ENODEV; - - parent = clk_get(&timer->pdev->dev, NULL); - if (IS_ERR(parent)) - return -ENODEV; - - /* Bail out if both clocks point to fck */ - if (clk_is_match(parent, timer->fclk)) - return 0; - - ret = clk_set_parent(timer->fclk, parent); - if (ret < 0) - pr_err("%s: failed to set parent\n", __func__); - - clk_put(parent); - - return ret; -} - static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { int ret; @@ -276,9 +247,7 @@ static int omap_dm_timer_prepare(struct omap_dm_timer *timer) __omap_dm_timer_enable_posted(timer); omap_dm_timer_disable(timer); - rc = omap_dm_timer_of_set_source(timer); - if (rc == -ENODEV) - return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); + rc = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); return rc; } -- cgit v1.2.3-70-g09d2 From fe6c2d6a80680a875a856eb174d12acea7681247 Mon Sep 17 00:00:00 2001 From: "周琰杰 (Zhou Yanjie)" Date: Wed, 19 Feb 2020 16:29:31 +0800 Subject: dt-bindings: timer: Add X1000 bindings. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the timer bindings for the X1000 Soc from Ingenic. Signed-off-by: 周琰杰 (Zhou Yanjie) Acked-by: Rob Herring Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1582100974-129559-3-git-send-email-zhouyanjie@wanyeetech.com --- Documentation/devicetree/bindings/timer/ingenic,tcu.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/timer/ingenic,tcu.txt b/Documentation/devicetree/bindings/timer/ingenic,tcu.txt index 0b63cebc5f45..91f704951845 100644 --- a/Documentation/devicetree/bindings/timer/ingenic,tcu.txt +++ b/Documentation/devicetree/bindings/timer/ingenic,tcu.txt @@ -10,6 +10,7 @@ Required properties: * ingenic,jz4740-tcu * ingenic,jz4725b-tcu * ingenic,jz4770-tcu + * ingenic,x1000-tcu followed by "simple-mfd". - reg: Should be the offset/length value corresponding to the TCU registers - clocks: List of phandle & clock specifiers for clocks external to the TCU. -- cgit v1.2.3-70-g09d2 From a7cd39552194954bcdecfd9ff775466a61bda5bb Mon Sep 17 00:00:00 2001 From: "周琰杰 (Zhou Yanjie)" Date: Wed, 19 Feb 2020 16:29:33 +0800 Subject: clocksource/drivers/ingenic: Add support for TCU of X1000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X1000 has a different TCU containing OST, since X1000, OST has been independent of TCU. This patch is prepare for later OST driver. Signed-off-by: 周琰杰 (Zhou Yanjie) Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1582100974-129559-5-git-send-email-zhouyanjie@wanyeetech.com --- drivers/clocksource/ingenic-timer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/ingenic-timer.c b/drivers/clocksource/ingenic-timer.c index 4bbdb3d3d0c6..496333650de2 100644 --- a/drivers/clocksource/ingenic-timer.c +++ b/drivers/clocksource/ingenic-timer.c @@ -230,6 +230,7 @@ static const struct of_device_id ingenic_tcu_of_match[] = { { .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, }, { .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, }, { .compatible = "ingenic,jz4770-tcu", .data = &jz4740_soc_info, }, + { .compatible = "ingenic,x1000-tcu", .data = &jz4740_soc_info, }, { /* sentinel */ } }; @@ -302,7 +303,7 @@ err_free_ingenic_tcu: TIMER_OF_DECLARE(jz4740_tcu_intc, "ingenic,jz4740-tcu", ingenic_tcu_init); TIMER_OF_DECLARE(jz4725b_tcu_intc, "ingenic,jz4725b-tcu", ingenic_tcu_init); TIMER_OF_DECLARE(jz4770_tcu_intc, "ingenic,jz4770-tcu", ingenic_tcu_init); - +TIMER_OF_DECLARE(x1000_tcu_intc, "ingenic,x1000-tcu", ingenic_tcu_init); static int __init ingenic_tcu_probe(struct platform_device *pdev) { -- cgit v1.2.3-70-g09d2 From cc2550b421aa30e3da67e5a7f6d14f3ecd3527b3 Mon Sep 17 00:00:00 2001 From: afzal mohammed Date: Thu, 27 Feb 2020 16:29:02 +0530 Subject: clocksource: Replace setup_irq() by request_irq() request_irq() is preferred over setup_irq(). The early boot setup_irq() invocations happen either via 'init_IRQ()' or 'time_init()', while memory allocators are ready by 'mm_init()'. Per tglx[1], setup_irq() existed in olden days when allocators were not ready by the time early interrupts were initialized. Hence replace setup_irq() by request_irq(). Seldom remove_irq() usage has been observed coupled with setup_irq(), wherever that has been found, it too has been replaced by free_irq(). A build error that was reported by kbuild test robot in the previous version of the patch also has been fixed. [1] https://lkml.kernel.org/r/alpine.DEB.2.20.1710191609480.1971@nanos Signed-off-by: afzal mohammed Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/91961c77c1cf93d41523f5e1ac52043f32f97077.1582799709.git.afzal.mohd.ma@gmail.com --- drivers/clocksource/bcm2835_timer.c | 8 ++--- drivers/clocksource/bcm_kona_timer.c | 10 ++----- drivers/clocksource/dw_apb_timer.c | 11 ++----- drivers/clocksource/exynos_mct.c | 12 +++----- drivers/clocksource/mxs_timer.c | 10 ++----- drivers/clocksource/nomadik-mtu.c | 11 ++----- drivers/clocksource/samsung_pwm_timer.c | 12 +++----- drivers/clocksource/timer-atlas7.c | 50 ++++++++++++++----------------- drivers/clocksource/timer-cs5535.c | 10 ++----- drivers/clocksource/timer-efm32.c | 10 ++----- drivers/clocksource/timer-fsl-ftm.c | 10 ++----- drivers/clocksource/timer-imx-gpt.c | 10 ++----- drivers/clocksource/timer-integrator-ap.c | 11 ++----- drivers/clocksource/timer-meson6.c | 11 ++----- drivers/clocksource/timer-orion.c | 9 ++---- drivers/clocksource/timer-prima2.c | 14 +++------ drivers/clocksource/timer-pxa.c | 10 ++----- drivers/clocksource/timer-sp804.c | 11 ++----- drivers/clocksource/timer-u300.c | 9 ++---- drivers/clocksource/timer-vf-pit.c | 10 ++----- drivers/clocksource/timer-vt8500.c | 11 ++----- drivers/clocksource/timer-zevio.c | 13 ++++---- include/linux/dw_apb_timer.h | 1 - 23 files changed, 83 insertions(+), 191 deletions(-) diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index b235f446ee50..1592650b2c92 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -31,7 +31,6 @@ struct bcm2835_timer { void __iomem *compare; int match_mask; struct clock_event_device evt; - struct irqaction act; }; static void __iomem *system_clock __read_mostly; @@ -113,12 +112,9 @@ static int __init bcm2835_timer_init(struct device_node *node) timer->evt.features = CLOCK_EVT_FEAT_ONESHOT; timer->evt.set_next_event = bcm2835_time_set_next_event; timer->evt.cpumask = cpumask_of(0); - timer->act.name = node->name; - timer->act.flags = IRQF_TIMER | IRQF_SHARED; - timer->act.dev_id = timer; - timer->act.handler = bcm2835_time_interrupt; - ret = setup_irq(irq, &timer->act); + ret = request_irq(irq, bcm2835_time_interrupt, IRQF_TIMER | IRQF_SHARED, + node->name, timer); if (ret) { pr_err("Can't set up timer IRQ\n"); goto err_timer_free; diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index 5c40be9880f5..a50ab5c2154f 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -160,12 +160,6 @@ static irqreturn_t kona_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction kona_timer_irq = { - .name = "Kona Timer Tick", - .flags = IRQF_TIMER, - .handler = kona_timer_interrupt, -}; - static int __init kona_timer_init(struct device_node *node) { u32 freq; @@ -192,7 +186,9 @@ static int __init kona_timer_init(struct device_node *node) kona_timer_disable_and_clear(timers.tmr_regs); kona_timer_clockevents_init(); - setup_irq(timers.tmr_irq, &kona_timer_irq); + if (request_irq(timers.tmr_irq, kona_timer_interrupt, IRQF_TIMER, + "Kona Timer Tick", NULL)) + pr_err("%s: request_irq() failed\n", "Kona Timer Tick"); kona_timer_set_next_event((arch_timer_rate / HZ), NULL); return 0; diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index 654766538f93..b207a77b0831 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -270,15 +270,10 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, dw_ced->ced.rating = rating; dw_ced->ced.name = name; - dw_ced->irqaction.name = dw_ced->ced.name; - dw_ced->irqaction.handler = dw_apb_clockevent_irq; - dw_ced->irqaction.dev_id = &dw_ced->ced; - dw_ced->irqaction.irq = irq; - dw_ced->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | - IRQF_NOBALANCING; - dw_ced->eoi = apbt_eoi; - err = setup_irq(irq, &dw_ced->irqaction); + err = request_irq(irq, dw_apb_clockevent_irq, + IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, + dw_ced->ced.name, &dw_ced->ced); if (err) { pr_err("failed to request timer irq\n"); kfree(dw_ced); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index a267fe31ef13..fabad79baafc 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -329,19 +329,15 @@ static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction mct_comp_event_irq = { - .name = "mct_comp_irq", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = exynos4_mct_comp_isr, - .dev_id = &mct_comp_device, -}; - static int exynos4_clockevent_init(void) { mct_comp_device.cpumask = cpumask_of(0); clockevents_config_and_register(&mct_comp_device, clk_rate, 0xf, 0xffffffff); - setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); + if (request_irq(mct_irqs[MCT_G0_IRQ], exynos4_mct_comp_isr, + IRQF_TIMER | IRQF_IRQPOLL, "mct_comp_irq", + &mct_comp_device)) + pr_err("%s: request_irq() failed\n", "mct_comp_irq"); return 0; } diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index f6ddae30933f..bc96a4cbf26c 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -117,13 +117,6 @@ static irqreturn_t mxs_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction mxs_timer_irq = { - .name = "MXS Timer Tick", - .dev_id = &mxs_clockevent_device, - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = mxs_timer_interrupt, -}; - static void mxs_irq_clear(char *state) { /* Disable interrupt in timer module */ @@ -277,6 +270,7 @@ static int __init mxs_timer_init(struct device_node *np) if (irq <= 0) return -EINVAL; - return setup_irq(irq, &mxs_timer_irq); + return request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, + "MXS Timer Tick", &mxs_clockevent_device); } TIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init); diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 3f7fa8c01367..f49a631d8f58 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -181,13 +181,6 @@ static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction nmdk_timer_irq = { - .name = "Nomadik Timer Tick", - .flags = IRQF_TIMER, - .handler = nmdk_timer_interrupt, - .dev_id = &nmdk_clkevt, -}; - static int __init nmdk_timer_init(void __iomem *base, int irq, struct clk *pclk, struct clk *clk) { @@ -232,7 +225,9 @@ static int __init nmdk_timer_init(void __iomem *base, int irq, sched_clock_register(nomadik_read_sched_clock, 32, rate); /* Timer 1 is used for events, register irq and clockevents */ - setup_irq(irq, &nmdk_timer_irq); + if (request_irq(irq, nmdk_timer_interrupt, IRQF_TIMER, + "Nomadik Timer Tick", &nmdk_clkevt)) + pr_err("%s: request_irq() failed\n", "Nomadik Timer Tick"); nmdk_clkevt.cpumask = cpumask_of(0); nmdk_clkevt.irq = irq; clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU); diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index dae1b2b5a0c5..f760229d0c7f 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -256,13 +256,6 @@ static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction samsung_clock_event_irq = { - .name = "samsung_time_irq", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = samsung_clock_event_isr, - .dev_id = &time_event_device, -}; - static void __init samsung_clockevent_init(void) { unsigned long pclk; @@ -282,7 +275,10 @@ static void __init samsung_clockevent_init(void) clock_rate, 1, pwm.tcnt_max); irq_number = pwm.irq[pwm.event_id]; - setup_irq(irq_number, &samsung_clock_event_irq); + if (request_irq(irq_number, samsung_clock_event_isr, + IRQF_TIMER | IRQF_IRQPOLL, "samsung_time_irq", + &time_event_device)) + pr_err("%s: request_irq() failed\n", "samsung_time_irq"); if (pwm.variant.has_tint_cstat) { u32 mask = (1 << pwm.event_id); diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c index 93c3ac6d72bd..c21c91c2bc56 100644 --- a/drivers/clocksource/timer-atlas7.c +++ b/drivers/clocksource/timer-atlas7.c @@ -159,29 +159,23 @@ static struct clocksource sirfsoc_clocksource = { .resume = sirfsoc_clocksource_resume, }; -static struct irqaction sirfsoc_timer_irq = { - .name = "sirfsoc_timer0", - .flags = IRQF_TIMER | IRQF_NOBALANCING, - .handler = sirfsoc_timer_interrupt, -}; - -static struct irqaction sirfsoc_timer1_irq = { - .name = "sirfsoc_timer1", - .flags = IRQF_TIMER | IRQF_NOBALANCING, - .handler = sirfsoc_timer_interrupt, -}; +static unsigned int sirfsoc_timer_irq, sirfsoc_timer1_irq; static int sirfsoc_local_timer_starting_cpu(unsigned int cpu) { struct clock_event_device *ce = per_cpu_ptr(sirfsoc_clockevent, cpu); - struct irqaction *action; - - if (cpu == 0) - action = &sirfsoc_timer_irq; - else - action = &sirfsoc_timer1_irq; + unsigned int irq; + const char *name; + + if (cpu == 0) { + irq = sirfsoc_timer_irq; + name = "sirfsoc_timer0"; + } else { + irq = sirfsoc_timer1_irq; + name = "sirfsoc_timer1"; + } - ce->irq = action->irq; + ce->irq = irq; ce->name = "local_timer"; ce->features = CLOCK_EVT_FEAT_ONESHOT; ce->rating = 200; @@ -196,9 +190,9 @@ static int sirfsoc_local_timer_starting_cpu(unsigned int cpu) ce->min_delta_ticks = 2; ce->cpumask = cpumask_of(cpu); - action->dev_id = ce; - BUG_ON(setup_irq(ce->irq, action)); - irq_force_affinity(action->irq, cpumask_of(cpu)); + BUG_ON(request_irq(ce->irq, sirfsoc_timer_interrupt, + IRQF_TIMER | IRQF_NOBALANCING, name, ce)); + irq_force_affinity(ce->irq, cpumask_of(cpu)); clockevents_register_device(ce); return 0; @@ -206,12 +200,14 @@ static int sirfsoc_local_timer_starting_cpu(unsigned int cpu) static int sirfsoc_local_timer_dying_cpu(unsigned int cpu) { + struct clock_event_device *ce = per_cpu_ptr(sirfsoc_clockevent, cpu); + sirfsoc_timer_count_disable(1); if (cpu == 0) - remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); + free_irq(sirfsoc_timer_irq, ce); else - remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); + free_irq(sirfsoc_timer1_irq, ce); return 0; } @@ -268,14 +264,14 @@ static int __init sirfsoc_of_timer_init(struct device_node *np) return -ENXIO; } - sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); - if (!sirfsoc_timer_irq.irq) { + sirfsoc_timer_irq = irq_of_parse_and_map(np, 0); + if (!sirfsoc_timer_irq) { pr_err("No irq passed for timer0 via DT\n"); return -EINVAL; } - sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); - if (!sirfsoc_timer1_irq.irq) { + sirfsoc_timer1_irq = irq_of_parse_and_map(np, 1); + if (!sirfsoc_timer1_irq) { pr_err("No irq passed for timer1 via DT\n"); return -EINVAL; } diff --git a/drivers/clocksource/timer-cs5535.c b/drivers/clocksource/timer-cs5535.c index 8f6bc536bef2..51ea0509fb25 100644 --- a/drivers/clocksource/timer-cs5535.c +++ b/drivers/clocksource/timer-cs5535.c @@ -131,12 +131,6 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction mfgptirq = { - .handler = mfgpt_tick, - .flags = IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED, - .name = DRV_NAME, -}; - static int __init cs5535_mfgpt_init(void) { struct cs5535_mfgpt_timer *timer; @@ -158,7 +152,9 @@ static int __init cs5535_mfgpt_init(void) } /* And register it with the kernel */ - ret = setup_irq(timer_irq, &mfgptirq); + ret = request_irq(timer_irq, mfgpt_tick, + IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED, + DRV_NAME, NULL); if (ret) { printk(KERN_ERR DRV_NAME ": Unable to set up the interrupt.\n"); goto err_irq; diff --git a/drivers/clocksource/timer-efm32.c b/drivers/clocksource/timer-efm32.c index 5a22cb079ad3..441a4b916841 100644 --- a/drivers/clocksource/timer-efm32.c +++ b/drivers/clocksource/timer-efm32.c @@ -119,13 +119,6 @@ static struct efm32_clock_event_ddata clock_event_ddata = { }, }; -static struct irqaction efm32_clock_event_irq = { - .name = "efm32 clockevent", - .flags = IRQF_TIMER, - .handler = efm32_clock_event_handler, - .dev_id = &clock_event_ddata, -}; - static int __init efm32_clocksource_init(struct device_node *np) { struct clk *clk; @@ -230,7 +223,8 @@ static int __init efm32_clockevent_init(struct device_node *np) DIV_ROUND_CLOSEST(rate, 1024), 0xf, 0xffff); - ret = setup_irq(irq, &efm32_clock_event_irq); + ret = request_irq(irq, efm32_clock_event_handler, IRQF_TIMER, + "efm32 clockevent", &clock_event_ddata); if (ret) { pr_err("Failed setup irq\n"); goto err_setup_irq; diff --git a/drivers/clocksource/timer-fsl-ftm.c b/drivers/clocksource/timer-fsl-ftm.c index a9d9a3ca5996..12a2ed7cfaff 100644 --- a/drivers/clocksource/timer-fsl-ftm.c +++ b/drivers/clocksource/timer-fsl-ftm.c @@ -176,13 +176,6 @@ static struct clock_event_device ftm_clockevent = { .rating = 300, }; -static struct irqaction ftm_timer_irq = { - .name = "Freescale ftm timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = ftm_evt_interrupt, - .dev_id = &ftm_clockevent, -}; - static int __init ftm_clockevent_init(unsigned long freq, int irq) { int err; @@ -192,7 +185,8 @@ static int __init ftm_clockevent_init(unsigned long freq, int irq) ftm_reset_counter(priv->clkevt_base); - err = setup_irq(irq, &ftm_timer_irq); + err = request_irq(irq, ftm_evt_interrupt, IRQF_TIMER | IRQF_IRQPOLL, + "Freescale ftm timer", &ftm_clockevent); if (err) { pr_err("ftm: setup irq failed: %d\n", err); return err; diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 706c0d0ff56c..7b2c70f2f353 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -67,7 +67,6 @@ struct imx_timer { struct clk *clk_ipg; const struct imx_gpt_data *gpt; struct clock_event_device ced; - struct irqaction act; }; struct imx_gpt_data { @@ -273,7 +272,6 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id) static int __init mxc_clockevent_init(struct imx_timer *imxtm) { struct clock_event_device *ced = &imxtm->ced; - struct irqaction *act = &imxtm->act; ced->name = "mxc_timer1"; ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ; @@ -287,12 +285,8 @@ static int __init mxc_clockevent_init(struct imx_timer *imxtm) clockevents_config_and_register(ced, clk_get_rate(imxtm->clk_per), 0xff, 0xfffffffe); - act->name = "i.MX Timer Tick"; - act->flags = IRQF_TIMER | IRQF_IRQPOLL; - act->handler = mxc_timer_interrupt; - act->dev_id = ced; - - return setup_irq(imxtm->irq, act); + return request_irq(imxtm->irq, mxc_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, "i.MX Timer Tick", ced); } static void imx1_gpt_setup_tctl(struct imx_timer *imxtm) diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index c90a69c7b5fa..b0fcbaac58b0 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -123,13 +123,6 @@ static struct clock_event_device integrator_clockevent = { .rating = 300, }; -static struct irqaction integrator_timer_irq = { - .name = "timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = integrator_timer_interrupt, - .dev_id = &integrator_clockevent, -}; - static int integrator_clockevent_init(unsigned long inrate, void __iomem *base, int irq) { @@ -149,7 +142,9 @@ static int integrator_clockevent_init(unsigned long inrate, timer_reload = rate / HZ; writel(ctrl, clkevt_base + TIMER_CTRL); - ret = setup_irq(irq, &integrator_timer_irq); + ret = request_irq(irq, integrator_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, "timer", + &integrator_clockevent); if (ret) return ret; diff --git a/drivers/clocksource/timer-meson6.c b/drivers/clocksource/timer-meson6.c index 9e8b467c71da..99f5510a2b56 100644 --- a/drivers/clocksource/timer-meson6.c +++ b/drivers/clocksource/timer-meson6.c @@ -150,13 +150,6 @@ static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction meson6_timer_irq = { - .name = "meson6_timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = meson6_timer_interrupt, - .dev_id = &meson6_clockevent, -}; - static int __init meson6_timer_init(struct device_node *node) { u32 val; @@ -194,7 +187,9 @@ static int __init meson6_timer_init(struct device_node *node) /* Stop the timer A */ meson6_clkevt_time_stop(); - ret = setup_irq(irq, &meson6_timer_irq); + ret = request_irq(irq, meson6_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, "meson6_timer", + &meson6_clockevent); if (ret) { pr_warn("failed to setup irq %d\n", irq); return ret; diff --git a/drivers/clocksource/timer-orion.c b/drivers/clocksource/timer-orion.c index 7d487107e3cd..d01ff4181867 100644 --- a/drivers/clocksource/timer-orion.c +++ b/drivers/clocksource/timer-orion.c @@ -114,12 +114,6 @@ static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction orion_clkevt_irq = { - .name = "orion_event", - .flags = IRQF_TIMER, - .handler = orion_clkevt_irq_handler, -}; - static int __init orion_timer_init(struct device_node *np) { unsigned long rate; @@ -172,7 +166,8 @@ static int __init orion_timer_init(struct device_node *np) sched_clock_register(orion_read_sched_clock, 32, rate); /* setup timer1 as clockevent timer */ - ret = setup_irq(irq, &orion_clkevt_irq); + ret = request_irq(irq, orion_clkevt_irq_handler, IRQF_TIMER, + "orion_event", NULL); if (ret) { pr_err("%pOFn: unable to setup irq\n", np); return ret; diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index d4a9dcf5fba2..c5d469342a9d 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -165,14 +165,6 @@ static struct clocksource sirfsoc_clocksource = { .resume = sirfsoc_clocksource_resume, }; -static struct irqaction sirfsoc_timer_irq = { - .name = "sirfsoc_timer0", - .flags = IRQF_TIMER, - .irq = 0, - .handler = sirfsoc_timer_interrupt, - .dev_id = &sirfsoc_clockevent, -}; - /* Overwrite weak default sched_clock with more precise one */ static u64 notrace sirfsoc_read_sched_clock(void) { @@ -190,6 +182,7 @@ static void __init sirfsoc_clockevent_init(void) static int __init sirfsoc_prima2_timer_init(struct device_node *np) { unsigned long rate; + unsigned int irq; struct clk *clk; int ret; @@ -218,7 +211,7 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np) return -ENXIO; } - sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); + irq = irq_of_parse_and_map(np, 0); writel_relaxed(rate / PRIMA2_CLOCK_FREQ / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV); @@ -234,7 +227,8 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np) sched_clock_register(sirfsoc_read_sched_clock, 64, PRIMA2_CLOCK_FREQ); - ret = setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); + ret = request_irq(irq, sirfsoc_timer_interrupt, IRQF_TIMER, + "sirfsoc_timer0", &sirfsoc_clockevent); if (ret) { pr_err("Failed to setup irq\n"); return ret; diff --git a/drivers/clocksource/timer-pxa.c b/drivers/clocksource/timer-pxa.c index 913a5d354a1f..7ad0e5adb2ff 100644 --- a/drivers/clocksource/timer-pxa.c +++ b/drivers/clocksource/timer-pxa.c @@ -143,13 +143,6 @@ static struct clock_event_device ckevt_pxa_osmr0 = { .resume = pxa_timer_resume, }; -static struct irqaction pxa_ost0_irq = { - .name = "ost0", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = pxa_ost0_interrupt, - .dev_id = &ckevt_pxa_osmr0, -}; - static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate) { int ret; @@ -161,7 +154,8 @@ static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate) ckevt_pxa_osmr0.cpumask = cpumask_of(0); - ret = setup_irq(irq, &pxa_ost0_irq); + ret = request_irq(irq, pxa_ost0_interrupt, IRQF_TIMER | IRQF_IRQPOLL, + "ost0", &ckevt_pxa_osmr0); if (ret) { pr_err("Failed to setup irq\n"); return ret; diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index 9c841980eed1..5cd0abf9b396 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -168,13 +168,6 @@ static struct clock_event_device sp804_clockevent = { .rating = 300, }; -static struct irqaction sp804_timer_irq = { - .name = "timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = sp804_timer_interrupt, - .dev_id = &sp804_clockevent, -}; - int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name) { struct clock_event_device *evt = &sp804_clockevent; @@ -200,7 +193,9 @@ int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct writel(0, base + TIMER_CTRL); - setup_irq(irq, &sp804_timer_irq); + if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, + "timer", &sp804_clockevent)) + pr_err("%s: request_irq() failed\n", "timer"); clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); return 0; diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c index 32adc3057dda..37cba8dfd45f 100644 --- a/drivers/clocksource/timer-u300.c +++ b/drivers/clocksource/timer-u300.c @@ -330,12 +330,6 @@ static irqreturn_t u300_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction u300_timer_irq = { - .name = "U300 Timer Tick", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = u300_timer_interrupt, -}; - /* * Override the global weak sched_clock symbol with this * local implementation which uses the clocksource to get some @@ -420,7 +414,8 @@ static int __init u300_timer_init_of(struct device_node *np) u300_timer_base + U300_TIMER_APP_RGPT1); /* Set up the IRQ handler */ - ret = setup_irq(irq, &u300_timer_irq); + ret = request_irq(irq, u300_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, "U300 Timer Tick", NULL); if (ret) return ret; diff --git a/drivers/clocksource/timer-vf-pit.c b/drivers/clocksource/timer-vf-pit.c index fef0bb4e0c8c..7ad4a8b008c2 100644 --- a/drivers/clocksource/timer-vf-pit.c +++ b/drivers/clocksource/timer-vf-pit.c @@ -123,19 +123,13 @@ static struct clock_event_device clockevent_pit = { .rating = 300, }; -static struct irqaction pit_timer_irq = { - .name = "VF pit timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = pit_timer_interrupt, - .dev_id = &clockevent_pit, -}; - static int __init pit_clockevent_init(unsigned long rate, int irq) { __raw_writel(0, clkevt_base + PITTCTRL); __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); - BUG_ON(setup_irq(irq, &pit_timer_irq)); + BUG_ON(request_irq(irq, pit_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, + "VF pit timer", &clockevent_pit); clockevent_pit.cpumask = cpumask_of(0); clockevent_pit.irq = irq; diff --git a/drivers/clocksource/timer-vt8500.c b/drivers/clocksource/timer-vt8500.c index bb424bcefbb3..a469b1b5f972 100644 --- a/drivers/clocksource/timer-vt8500.c +++ b/drivers/clocksource/timer-vt8500.c @@ -101,13 +101,6 @@ static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction irq = { - .name = "vt8500_timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = vt8500_timer_interrupt, - .dev_id = &clockevent, -}; - static int __init vt8500_timer_init(struct device_node *np) { int timer_irq, ret; @@ -139,7 +132,9 @@ static int __init vt8500_timer_init(struct device_node *np) clockevent.cpumask = cpumask_of(0); - ret = setup_irq(timer_irq, &irq); + ret = request_irq(timer_irq, vt8500_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, "vt8500_timer", + &clockevent); if (ret) { pr_err("%s: setup_irq failed for %s\n", __func__, clockevent.name); diff --git a/drivers/clocksource/timer-zevio.c b/drivers/clocksource/timer-zevio.c index c0041561f1be..ecaa3568841c 100644 --- a/drivers/clocksource/timer-zevio.c +++ b/drivers/clocksource/timer-zevio.c @@ -53,7 +53,6 @@ struct zevio_timer { struct clk *clk; struct clock_event_device clkevt; - struct irqaction clkevt_irq; char clocksource_name[64]; char clockevent_name[64]; @@ -172,12 +171,12 @@ static int __init zevio_timer_add(struct device_node *node) /* Interrupt to occur when timer value matches 0 */ writel(0, timer->base + IO_MATCH(TIMER_MATCH)); - timer->clkevt_irq.name = timer->clockevent_name; - timer->clkevt_irq.handler = zevio_timer_interrupt; - timer->clkevt_irq.dev_id = timer; - timer->clkevt_irq.flags = IRQF_TIMER | IRQF_IRQPOLL; - - setup_irq(irqnr, &timer->clkevt_irq); + if (request_irq(irqnr, zevio_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, + timer->clockevent_name, timer)) { + pr_err("%s: request_irq() failed\n", + timer->clockevent_name); + } clockevents_config_and_register(&timer->clkevt, clk_get_rate(timer->clk), 0x0001, 0xffff); diff --git a/include/linux/dw_apb_timer.h b/include/linux/dw_apb_timer.h index 14f072edbca5..82ebf9223948 100644 --- a/include/linux/dw_apb_timer.h +++ b/include/linux/dw_apb_timer.h @@ -25,7 +25,6 @@ struct dw_apb_timer { struct dw_apb_clock_event_device { struct clock_event_device ced; struct dw_apb_timer timer; - struct irqaction irqaction; void (*eoi)(struct dw_apb_timer *); }; -- cgit v1.2.3-70-g09d2 From a2efdbf4fcb38ec1ae99c9d54d52c34fa867dc71 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 28 Feb 2020 11:08:45 -0600 Subject: posix-cpu-timers: cpu_clock_sample_group() no longer needs siglock As of e78c3496790e ("time, signal: Protect resource use statistics with seqlock") cpu_clock_sample_group() no longer needs siglock protection so remove the stale comment. Signed-off-by: "Eric W. Biederman" Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/87eeuevduq.fsf@x220.int.ebiederm.org --- kernel/time/posix-cpu-timers.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 8ff6da77a01f..46cc188bf5ab 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -336,9 +336,7 @@ static void __thread_group_cputime(struct task_struct *tsk, u64 *samples) /* * Sample a process (thread group) clock for the given task clkid. If the * group's cputime accounting is already enabled, read the atomic - * store. Otherwise a full update is required. Task's sighand lock must be - * held to protect the task traversal on a full update. clkid is already - * validated. + * store. Otherwise a full update is required. clkid is already validated. */ static u64 cpu_clock_sample_group(const clockid_t clkid, struct task_struct *p, bool start) -- cgit v1.2.3-70-g09d2 From 60f2ceaa8111d9ec51af87bde4a6809f2b3235e4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 28 Feb 2020 11:09:19 -0600 Subject: posix-cpu-timers: Remove unnecessary locking around cpu_clock_sample_group As of e78c3496790e ("time, signal: Protect resource use statistics with seqlock") cpu_clock_sample_group no longers needs siglock protection. Unfortunately no one realized it at the time. Remove the extra locking that is for cpu_clock_sample_group and not for cpu_clock_sample. This significantly simplifies the code. Signed-off-by: "Eric W. Biederman" Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/878skmvdts.fsf@x220.int.ebiederm.org --- kernel/time/posix-cpu-timers.c | 66 ++++++++---------------------------------- 1 file changed, 12 insertions(+), 54 deletions(-) diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 46cc188bf5ab..40c2d8396bb9 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -718,31 +718,10 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp /* * Sample the clock to take the difference with the expiry time. */ - if (CPUCLOCK_PERTHREAD(timer->it_clock)) { + if (CPUCLOCK_PERTHREAD(timer->it_clock)) now = cpu_clock_sample(clkid, p); - } else { - struct sighand_struct *sighand; - unsigned long flags; - - /* - * Protect against sighand release/switch in exit/exec and - * also make timer sampling safe if it ends up calling - * thread_group_cputime(). - */ - sighand = lock_task_sighand(p, &flags); - if (unlikely(sighand == NULL)) { - /* - * The process has been reaped. - * We can't even collect a sample any more. - * Disarm the timer, nothing else to do. - */ - cpu_timer_setexpires(ctmr, 0); - return; - } else { - now = cpu_clock_sample_group(clkid, p, false); - unlock_task_sighand(p, &flags); - } - } + else + now = cpu_clock_sample_group(clkid, p, false); if (now < expires) { itp->it_value = ns_to_timespec64(expires - now); @@ -986,43 +965,22 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer) /* * Fetch the current sample and update the timer's expiry time. */ - if (CPUCLOCK_PERTHREAD(timer->it_clock)) { + if (CPUCLOCK_PERTHREAD(timer->it_clock)) now = cpu_clock_sample(clkid, p); - bump_cpu_timer(timer, now); - if (unlikely(p->exit_state)) - return; - - /* Protect timer list r/w in arm_timer() */ - sighand = lock_task_sighand(p, &flags); - if (!sighand) - return; - } else { - /* - * Protect arm_timer() and timer sampling in case of call to - * thread_group_cputime(). - */ - sighand = lock_task_sighand(p, &flags); - if (unlikely(sighand == NULL)) { - /* - * The process has been reaped. - * We can't even collect a sample any more. - */ - cpu_timer_setexpires(ctmr, 0); - return; - } else if (unlikely(p->exit_state) && thread_group_empty(p)) { - /* If the process is dying, no need to rearm */ - goto unlock; - } + else now = cpu_clock_sample_group(clkid, p, true); - bump_cpu_timer(timer, now); - /* Leave the sighand locked for the call below. */ - } + + bump_cpu_timer(timer, now); + + /* Protect timer list r/w in arm_timer() */ + sighand = lock_task_sighand(p, &flags); + if (unlikely(sighand == NULL)) + return; /* * Now re-arm for the new expiry time. */ arm_timer(timer); -unlock: unlock_task_sighand(p, &flags); } -- cgit v1.2.3-70-g09d2 From beb41d9cbe4179058634e05d60235b6155c7b6c6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 28 Feb 2020 11:09:46 -0600 Subject: posix-cpu-timers: Pass the task into arm_timer() The task has been already computed to take siglock before calling arm_timer. So pass the benefit of that labor into arm_timer(). Signed-off-by: "Eric W. Biederman" Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/8736auvdt1.fsf@x220.int.ebiederm.org --- kernel/time/posix-cpu-timers.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 40c2d8396bb9..ef936c5a910b 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -482,12 +482,11 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk) * Insert the timer on the appropriate list before any timers that * expire later. This must be called with the sighand lock held. */ -static void arm_timer(struct k_itimer *timer) +static void arm_timer(struct k_itimer *timer, struct task_struct *p) { int clkidx = CPUCLOCK_WHICH(timer->it_clock); struct cpu_timer *ctmr = &timer->it.cpu; u64 newexp = cpu_timer_getexpires(ctmr); - struct task_struct *p = ctmr->task; struct posix_cputimer_base *base; if (CPUCLOCK_PERTHREAD(timer->it_clock)) @@ -660,7 +659,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, */ cpu_timer_setexpires(ctmr, new_expires); if (new_expires != 0 && val < new_expires) { - arm_timer(timer); + arm_timer(timer, p); } unlock_task_sighand(p, &flags); @@ -980,7 +979,7 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer) /* * Now re-arm for the new expiry time. */ - arm_timer(timer); + arm_timer(timer, p); unlock_task_sighand(p, &flags); } -- cgit v1.2.3-70-g09d2 From 55e8c8eb2c7b6bf30e99423ccfe7ca032f498f59 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 28 Feb 2020 11:11:06 -0600 Subject: posix-cpu-timers: Store a reference to a pid not a task posix cpu timers do not handle the death of a process well. This is most clearly seen when a multi-threaded process calls exec from a thread that is not the leader of the thread group. The posix cpu timer code continues to pin the old thread group leader and is unable to find the siglock from there. This results in posix_cpu_timer_del being unable to delete a timer, posix_cpu_timer_set being unable to set a timer. Further to compensate for the problems in posix_cpu_timer_del on a multi-threaded exec all timers that point at the multi-threaded task are stopped. The code for the timers fundamentally needs to check if the target process/thread is alive. This needs an extra level of indirection. This level of indirection is already available in struct pid. So replace cpu.task with cpu.pid to get the needed extra layer of indirection. In addition to handling things more cleanly this reduces the amount of memory a timer can pin when a process exits and then is reaped from a task_struct to the vastly smaller struct pid. Fixes: e0a70217107e ("posix-cpu-timers: workaround to suppress the problems with mt exec") Signed-off-by: "Eric W. Biederman" Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/87wo86tz6d.fsf@x220.int.ebiederm.org --- include/linux/posix-timers.h | 2 +- kernel/time/posix-cpu-timers.c | 73 +++++++++++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 3d10c84a97a9..e3f0f8585da4 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -69,7 +69,7 @@ static inline int clockid_to_fd(const clockid_t clk) struct cpu_timer { struct timerqueue_node node; struct timerqueue_head *head; - struct task_struct *task; + struct pid *pid; struct list_head elist; int firing; }; diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index ef936c5a910b..6df468a622fe 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -118,6 +118,16 @@ static inline int validate_clock_permissions(const clockid_t clock) return __get_task_for_clock(clock, false, false) ? 0 : -EINVAL; } +static inline enum pid_type cpu_timer_pid_type(struct k_itimer *timer) +{ + return CPUCLOCK_PERTHREAD(timer->it_clock) ? PIDTYPE_PID : PIDTYPE_TGID; +} + +static inline struct task_struct *cpu_timer_task_rcu(struct k_itimer *timer) +{ + return pid_task(timer->it.cpu.pid, cpu_timer_pid_type(timer)); +} + /* * Update expiry time from increment, and increase overrun count, * given the current clock sample. @@ -391,7 +401,12 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer) new_timer->kclock = &clock_posix_cpu; timerqueue_init(&new_timer->it.cpu.node); - new_timer->it.cpu.task = p; + new_timer->it.cpu.pid = get_task_pid(p, cpu_timer_pid_type(new_timer)); + /* + * get_task_for_clock() took a reference on @p. Drop it as the timer + * holds a reference on the pid of @p. + */ + put_task_struct(p); return 0; } @@ -404,13 +419,15 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer) static int posix_cpu_timer_del(struct k_itimer *timer) { struct cpu_timer *ctmr = &timer->it.cpu; - struct task_struct *p = ctmr->task; struct sighand_struct *sighand; + struct task_struct *p; unsigned long flags; int ret = 0; - if (WARN_ON_ONCE(!p)) - return -EINVAL; + rcu_read_lock(); + p = cpu_timer_task_rcu(timer); + if (!p) + goto out; /* * Protect against sighand release/switch in exit/exec and process/ @@ -432,8 +449,10 @@ static int posix_cpu_timer_del(struct k_itimer *timer) unlock_task_sighand(p, &flags); } +out: + rcu_read_unlock(); if (!ret) - put_task_struct(p); + put_pid(ctmr->pid); return ret; } @@ -561,13 +580,21 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock); u64 old_expires, new_expires, old_incr, val; struct cpu_timer *ctmr = &timer->it.cpu; - struct task_struct *p = ctmr->task; struct sighand_struct *sighand; + struct task_struct *p; unsigned long flags; int ret = 0; - if (WARN_ON_ONCE(!p)) - return -EINVAL; + rcu_read_lock(); + p = cpu_timer_task_rcu(timer); + if (!p) { + /* + * If p has just been reaped, we can no + * longer get any information about it at all. + */ + rcu_read_unlock(); + return -ESRCH; + } /* * Use the to_ktime conversion because that clamps the maximum @@ -584,8 +611,10 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, * If p has just been reaped, we can no * longer get any information about it at all. */ - if (unlikely(sighand == NULL)) + if (unlikely(sighand == NULL)) { + rcu_read_unlock(); return -ESRCH; + } /* * Disarm any old timer after extracting its expiry time. @@ -690,6 +719,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, ret = 0; out: + rcu_read_unlock(); if (old) old->it_interval = ns_to_timespec64(old_incr); @@ -701,10 +731,12 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock); struct cpu_timer *ctmr = &timer->it.cpu; u64 now, expires = cpu_timer_getexpires(ctmr); - struct task_struct *p = ctmr->task; + struct task_struct *p; - if (WARN_ON_ONCE(!p)) - return; + rcu_read_lock(); + p = cpu_timer_task_rcu(timer); + if (!p) + goto out; /* * Easy part: convert the reload time. @@ -712,7 +744,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp itp->it_interval = ktime_to_timespec64(timer->it_interval); if (!expires) - return; + goto out; /* * Sample the clock to take the difference with the expiry time. @@ -732,6 +764,8 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp itp->it_value.tv_nsec = 1; itp->it_value.tv_sec = 0; } +out: + rcu_read_unlock(); } #define MAX_COLLECTED 20 @@ -952,14 +986,15 @@ static void check_process_timers(struct task_struct *tsk, static void posix_cpu_timer_rearm(struct k_itimer *timer) { clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock); - struct cpu_timer *ctmr = &timer->it.cpu; - struct task_struct *p = ctmr->task; + struct task_struct *p; struct sighand_struct *sighand; unsigned long flags; u64 now; - if (WARN_ON_ONCE(!p)) - return; + rcu_read_lock(); + p = cpu_timer_task_rcu(timer); + if (!p) + goto out; /* * Fetch the current sample and update the timer's expiry time. @@ -974,13 +1009,15 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer) /* Protect timer list r/w in arm_timer() */ sighand = lock_task_sighand(p, &flags); if (unlikely(sighand == NULL)) - return; + goto out; /* * Now re-arm for the new expiry time. */ arm_timer(timer, p); unlock_task_sighand(p, &flags); +out: + rcu_read_unlock(); } /** -- cgit v1.2.3-70-g09d2 From b95e31c07c5eb4f5c0769f12b38b0343d7961040 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 28 Feb 2020 11:15:03 -0600 Subject: posix-cpu-timers: Stop disabling timers on mt-exec The reasons why the extra posix_cpu_timers_exit_group() invocation has been added are not entirely clear from the commit message. Today all that posix_cpu_timers_exit_group() does is stop timers that are tracking the task from firing. Every other operation on those timers is still allowed. The practical implication of this is posix_cpu_timer_del() which could not get the siglock after the thread group leader has exited (because sighand == NULL) would be able to run successfully because the timer was already dequeued. With that locking issue fixed there is no point in disabling all of the timers. So remove this ``tempoary'' hack. Fixes: e0a70217107e ("posix-cpu-timers: workaround to suppress the problems with mt exec") Signed-off-by: "Eric W. Biederman" Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/87o8tityzs.fsf@x220.int.ebiederm.org --- kernel/exit.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/kernel/exit.c b/kernel/exit.c index 2833ffb0c211..df546315f699 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -103,17 +103,8 @@ static void __exit_signal(struct task_struct *tsk) #ifdef CONFIG_POSIX_TIMERS posix_cpu_timers_exit(tsk); - if (group_dead) { + if (group_dead) posix_cpu_timers_exit_group(tsk); - } else { - /* - * This can only happen if the caller is de_thread(). - * FIXME: this is the temporary hack, we should teach - * posix-cpu-timers to handle this case correctly. - */ - if (unlikely(has_group_leader_pid(tsk))) - posix_cpu_timers_exit_group(tsk); - } #endif if (group_dead) { -- cgit v1.2.3-70-g09d2 From 4cbbc3a0eeed675449b1a4d080008927121f3da3 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Mon, 20 Jan 2020 18:05:23 +0800 Subject: timekeeping: Prevent 32bit truncation in scale64_check_overflow() While unlikely the divisor in scale64_check_overflow() could be >= 32bit in scale64_check_overflow(). do_div() truncates the divisor to 32bit at least on 32bit platforms. Use div64_u64() instead to avoid the truncation to 32-bit. [ tglx: Massaged changelog ] Signed-off-by: Wen Yang Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200120100523.45656-1-wenyang@linux.alibaba.com --- kernel/time/timekeeping.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index ca69290bee2a..4fc2af4367a7 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1005,9 +1005,8 @@ static int scale64_check_overflow(u64 mult, u64 div, u64 *base) ((int)sizeof(u64)*8 - fls64(mult) < fls64(rem))) return -EOVERFLOW; tmp *= mult; - rem *= mult; - do_div(rem, div); + rem = div64_u64(rem * mult, div); *base = tmp + rem; return 0; } -- cgit v1.2.3-70-g09d2 From 38f7b0b1316d435f38ec3f2bb078897b7a1cfdea Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Thu, 30 Jan 2020 21:08:51 +0800 Subject: hrtimer: Cast explicitely to u32t in __ktime_divns() do_div() does a 64-by-32 division at least on 32bit platforms, while the divisor 'div' is explicitly casted to unsigned long, thus 64-bit on 64-bit platforms. The code already ensures that the divisor is less than 2^32. Hence the proper cast type is u32. Signed-off-by: Wen Yang Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200130130851.29204-1-wenyang@linux.alibaba.com --- kernel/time/hrtimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 3a609e7344f3..d74fdcd3ced4 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -311,7 +311,7 @@ s64 __ktime_divns(const ktime_t kt, s64 div) div >>= 1; } tmp >>= sft; - do_div(tmp, (unsigned long) div); + do_div(tmp, (u32) div); return dclc < 0 ? -tmp : tmp; } EXPORT_SYMBOL_GPL(__ktime_divns); -- cgit v1.2.3-70-g09d2 From d441dceb5dce71150f28add80d36d91bbfccba99 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Fri, 7 Feb 2020 14:39:29 -0500 Subject: tick/common: Make tick_periodic() check for missing ticks The tick_periodic() function is used at the beginning part of the bootup process for time keeping while the other clock sources are being initialized. The current code assumes that all the timer interrupts are handled in a timely manner with no missing ticks. That is not actually true. Some ticks are missed and there are some discrepancies between the tick time (jiffies) and the timestamp reported in the kernel log. Some systems, however, are more prone to missing ticks than the others. In the extreme case, the discrepancy can actually cause a soft lockup message to be printed by the watchdog kthread. For example, on a Cavium ThunderX2 Sabre arm64 system: [ 25.496379] watchdog: BUG: soft lockup - CPU#14 stuck for 22s! On that system, the missing ticks are especially prevalent during the smp_init() phase of the boot process. With an instrumented kernel, it was found that it took about 24s as reported by the timestamp for the tick to accumulate 4s of time. Investigation and bisection done by others seemed to point to the commit 73f381660959 ("arm64: Advertise mitigation of Spectre-v2, or lack thereof") as the culprit. It could also be a firmware issue as new firmware was promised that would fix the issue. To properly address this problem, stop assuming that there will be no missing tick in tick_periodic(). Modify it to follow the example of tick_do_update_jiffies64() by using another reference clock to check for missing ticks. Since the watchdog timer uses running_clock(), it is used here as the reference. With this applied, the soft lockup problem in the affected arm64 system is gone and tick time tracks much more closely to the timestamp time. Signed-off-by: Waiman Long Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200207193929.27308-1-longman@redhat.com --- kernel/time/tick-common.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 7e5d3524e924..cce4ed1515c7 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -84,12 +85,41 @@ int tick_is_oneshot_available(void) static void tick_periodic(int cpu) { if (tick_do_timer_cpu == cpu) { + /* + * Use running_clock() as reference to check for missing ticks. + */ + static ktime_t last_update; + ktime_t now; + int ticks = 1; + + now = ns_to_ktime(running_clock()); write_seqlock(&jiffies_lock); - /* Keep track of the next tick event */ - tick_next_period = ktime_add(tick_next_period, tick_period); + if (last_update) { + u64 delta = ktime_sub(now, last_update); - do_timer(1); + /* + * Check for eventually missed ticks + * + * There is likely a persistent delta between + * last_update and tick_next_period. So they are + * updated separately. + */ + if (delta >= 2 * tick_period) { + s64 period = ktime_to_ns(tick_period); + + ticks = ktime_divns(delta, period); + } + last_update = ktime_add(last_update, + ticks * tick_period); + } else { + last_update = now; + } + + /* Keep track of the next tick event */ + tick_next_period = ktime_add(tick_next_period, + ticks * tick_period); + do_timer(ticks); write_sequnlock(&jiffies_lock); update_wall_time(); } -- cgit v1.2.3-70-g09d2 From 470cf1c28d2f601ea666a96d676c10b09b2321ab Mon Sep 17 00:00:00 2001 From: afzal mohammed Date: Thu, 12 Mar 2020 12:18:17 +0530 Subject: clocksource/drivers/timer-cs5535: Request irq with non-NULL dev_id Recently all usages of setup_irq() was replaced by request_irq(). request_irq() does a few sanity checks that were not done in setup_irq(), if they fail irq registration will fail. One of the check is to ensure that non-NULL dev_id is passed in the case of shared irq. Fix it by passing non-NULL dev_id while registering the shared irq. Fixes: cc2550b421aa ("clocksource: Replace setup_irq() by request_irq()") Signed-off-by: afzal mohammed Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200312064817.19000-1-afzal.mohd.ma@gmail.com --- drivers/clocksource/timer-cs5535.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clocksource/timer-cs5535.c b/drivers/clocksource/timer-cs5535.c index 51ea0509fb25..d47acfe848ae 100644 --- a/drivers/clocksource/timer-cs5535.c +++ b/drivers/clocksource/timer-cs5535.c @@ -133,6 +133,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) static int __init cs5535_mfgpt_init(void) { + unsigned long flags = IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED; struct cs5535_mfgpt_timer *timer; int ret; uint16_t val; @@ -152,9 +153,7 @@ static int __init cs5535_mfgpt_init(void) } /* And register it with the kernel */ - ret = request_irq(timer_irq, mfgpt_tick, - IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED, - DRV_NAME, NULL); + ret = request_irq(timer_irq, mfgpt_tick, flags, DRV_NAME, timer); if (ret) { printk(KERN_ERR DRV_NAME ": Unable to set up the interrupt.\n"); goto err_irq; -- cgit v1.2.3-70-g09d2 From 0585244523f0f4de7e4480375e871617a79cab98 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 16 Mar 2020 11:52:56 +0200 Subject: clocksource/drivers/timer-microchip-pit64b: Fix rate for gck Generic clock rate needs to be set in case it was selected as timer clock source in mchp_pit64b_init_mode(). Otherwise it will be enabled with wrong rate. Fixes: 625022a5f160 ("clocksource/drivers/timer-microchip-pit64b: Add Microchip PIT64B support") Signed-off-by: Claudiu Beznea Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1584352376-32585-1-git-send-email-claudiu.beznea@microchip.com --- drivers/clocksource/timer-microchip-pit64b.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c index bd63d3484838..59e11ca8ee73 100644 --- a/drivers/clocksource/timer-microchip-pit64b.c +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -264,6 +264,7 @@ static int __init mchp_pit64b_init_mode(struct mchp_pit64b_timer *timer, if (!best_diff) { timer->mode |= MCHP_PIT64B_MR_SGCLK; + clk_set_rate(timer->gclk, gclk_round); goto done; } -- cgit v1.2.3-70-g09d2 From 341e8cba6c32bb7509eabb91619a233b7ae249b9 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Thu, 5 Mar 2020 13:57:10 +0530 Subject: clocksource/drivers/timer-ti-dm: Convert to SPDX identifier Use SPDX-License-Identifier instead of a verbose license text. Signed-off-by: Lokesh Vutla Acked-by: Tony Lindgren Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-2-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 269a994d6a99..c0e9e9978cdd 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * linux/arch/arm/plat-omap/dmtimer.c * @@ -15,24 +16,6 @@ * * Copyright (C) 2009 Texas Instruments * Added OMAP4 support - Santosh Shilimkar - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include -- cgit v1.2.3-70-g09d2 From 5e20931c6a750b4b1ea9a2f7b863cc2dd9222ead Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 5 Mar 2020 13:57:11 +0530 Subject: clocksource/drivers/timer-ti-dm: Prepare for using cpuidle Let's add runtime_suspend and resume functions and atomic enabled flag. This way we can use these when converting to use cpuidle for saving and restoring device context. And we need to maintain the driver state in the driver as documented in "9. Autosuspend, or automatically-delayed suspends" in the Documentation/power/runtime_pm.rst document related to using driver private lock and races with runtime_suspend(). Signed-off-by: Tony Lindgren Signed-off-by: Lokesh Vutla Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-3-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 36 +++++++++++++++++++++++++++++++----- include/clocksource/timer-ti-dm.h | 1 + 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index c0e9e9978cdd..fe939d1c0b38 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -491,7 +491,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) int omap_dm_timer_trigger(struct omap_dm_timer *timer) { - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { + if (unlikely(!timer || !atomic_read(&timer->enabled))) { pr_err("%s: timer not available or enabled.\n", __func__); return -EINVAL; } @@ -690,7 +690,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) { unsigned int l; - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { + if (unlikely(!timer || !atomic_read(&timer->enabled))) { pr_err("%s: timer not available or enabled.\n", __func__); return 0; } @@ -702,7 +702,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) { - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) + if (unlikely(!timer || !atomic_read(&timer->enabled))) return -EINVAL; __omap_dm_timer_write_status(timer, value); @@ -712,7 +712,7 @@ static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) { - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { + if (unlikely(!timer || !atomic_read(&timer->enabled))) { pr_err("%s: timer not iavailable or enabled.\n", __func__); return 0; } @@ -722,7 +722,7 @@ static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) static int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) { - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { + if (unlikely(!timer || !atomic_read(&timer->enabled))) { pr_err("%s: timer not available or enabled.\n", __func__); return -EINVAL; } @@ -750,6 +750,29 @@ int omap_dm_timers_active(void) return 0; } +static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev) +{ + struct omap_dm_timer *timer = dev_get_drvdata(dev); + + atomic_set(&timer->enabled, 0); + + return 0; +} + +static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev) +{ + struct omap_dm_timer *timer = dev_get_drvdata(dev); + + atomic_set(&timer->enabled, 1); + + return 0; +} + +static const struct dev_pm_ops omap_dm_timer_pm_ops = { + SET_RUNTIME_PM_OPS(omap_dm_timer_runtime_suspend, + omap_dm_timer_runtime_resume, NULL) +}; + static const struct of_device_id omap_timer_match[]; /** @@ -791,6 +814,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev) if (IS_ERR(timer->io_base)) return PTR_ERR(timer->io_base); + platform_set_drvdata(pdev, timer); + if (dev->of_node) { if (of_find_property(dev->of_node, "ti,timer-alwon", NULL)) timer->capability |= OMAP_TIMER_ALWON; @@ -936,6 +961,7 @@ static struct platform_driver omap_dm_timer_driver = { .driver = { .name = "omap_timer", .of_match_table = of_match_ptr(omap_timer_match), + .pm = &omap_dm_timer_pm_ops, }, }; diff --git a/include/clocksource/timer-ti-dm.h b/include/clocksource/timer-ti-dm.h index 7d9598dc578d..eef5de300731 100644 --- a/include/clocksource/timer-ti-dm.h +++ b/include/clocksource/timer-ti-dm.h @@ -105,6 +105,7 @@ struct omap_dm_timer { void __iomem *pend; /* write pending */ void __iomem *func_base; /* function register base */ + atomic_t enabled; unsigned long rate; unsigned reserved:1; unsigned posted:1; -- cgit v1.2.3-70-g09d2 From b34677b0999a7c0de45e57b780508c14cb438ed8 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Mon, 16 Mar 2020 16:44:53 +0530 Subject: clocksource/drivers/timer-ti-dm: Implement cpu_pm notifier for context save and restore omap_dm_timer_enable() restores the entire context(including counter) based on 2 conditions: - If get_context_loss_count is populated and context is lost. - If get_context_loss_count is not populated update unconditionally. Case2 has a side effect of updating the counter register even though context is not lost. When timer is configured in pwm mode, this is causing undesired behaviour in the pwm period. Instead of using get_context_loss_count call back, implement cpu_pm notifier with context save and restore support. And delete the get_context_loss_count callback all together. Suggested-by: Tony Lindgren Signed-off-by: Lokesh Vutla [tony@atomide.com: removed pm_runtime calls from cpuidle calls] Signed-off-by: Tony Lindgren Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200316111453.15441-1-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 97 +++++++++++++++++++++++---------------- include/clocksource/timer-ti-dm.h | 3 +- 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index fe939d1c0b38..1d1bea79cbf1 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -92,6 +93,47 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer) timer->context.tclr); } +static void omap_timer_save_context(struct omap_dm_timer *timer) +{ + timer->context.tclr = + omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + timer->context.twer = + omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG); + timer->context.tldr = + omap_dm_timer_read_reg(timer, OMAP_TIMER_LOAD_REG); + timer->context.tmar = + omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG); + timer->context.tier = readl_relaxed(timer->irq_ena); + timer->context.tsicr = + omap_dm_timer_read_reg(timer, OMAP_TIMER_IF_CTRL_REG); +} + +static int omap_timer_context_notifier(struct notifier_block *nb, + unsigned long cmd, void *v) +{ + struct omap_dm_timer *timer; + + timer = container_of(nb, struct omap_dm_timer, nb); + + switch (cmd) { + case CPU_CLUSTER_PM_ENTER: + if ((timer->capability & OMAP_TIMER_ALWON) || + !atomic_read(&timer->enabled)) + break; + omap_timer_save_context(timer); + break; + case CPU_CLUSTER_PM_ENTER_FAILED: + case CPU_CLUSTER_PM_EXIT: + if ((timer->capability & OMAP_TIMER_ALWON) || + !atomic_read(&timer->enabled)) + break; + omap_timer_restore_context(timer); + break; + } + + return NOTIFY_OK; +} + static int omap_dm_timer_reset(struct omap_dm_timer *timer) { u32 l, timeout = 100000; @@ -208,21 +250,7 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) static void omap_dm_timer_enable(struct omap_dm_timer *timer) { - int c; - pm_runtime_get_sync(&timer->pdev->dev); - - if (!(timer->capability & OMAP_TIMER_ALWON)) { - if (timer->get_context_loss_count) { - c = timer->get_context_loss_count(&timer->pdev->dev); - if (c != timer->ctx_loss_count) { - omap_timer_restore_context(timer); - timer->ctx_loss_count = c; - } - } else { - omap_timer_restore_context(timer); - } - } } static void omap_dm_timer_disable(struct omap_dm_timer *timer) @@ -515,8 +543,6 @@ static int omap_dm_timer_start(struct omap_dm_timer *timer) omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } - /* Save the context */ - timer->context.tclr = l; return 0; } @@ -532,13 +558,6 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer) __omap_dm_timer_stop(timer, timer->posted, rate); - /* - * Since the register values are computed and written within - * __omap_dm_timer_stop, we need to use read to retrieve the - * context. - */ - timer->context.tclr = - omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); omap_dm_timer_disable(timer); return 0; } @@ -561,9 +580,6 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); - /* Save the context */ - timer->context.tclr = l; - timer->context.tldr = load; omap_dm_timer_disable(timer); return 0; } @@ -585,9 +601,6 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - /* Save the context */ - timer->context.tclr = l; - timer->context.tmar = match; omap_dm_timer_disable(timer); return 0; } @@ -611,8 +624,6 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, l |= trigger << 10; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - /* Save the context */ - timer->context.tclr = l; omap_dm_timer_disable(timer); return 0; } @@ -634,8 +645,6 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, } omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - /* Save the context */ - timer->context.tclr = l; omap_dm_timer_disable(timer); return 0; } @@ -649,9 +658,6 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, omap_dm_timer_enable(timer); __omap_dm_timer_int_enable(timer, value); - /* Save the context */ - timer->context.tier = value; - timer->context.twer = value; omap_dm_timer_disable(timer); return 0; } @@ -679,9 +685,6 @@ static int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask) l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask; omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l); - /* Save the context */ - timer->context.tier &= ~mask; - timer->context.twer &= ~mask; omap_dm_timer_disable(timer); return 0; } @@ -756,6 +759,11 @@ static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev) atomic_set(&timer->enabled, 0); + if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base) + return 0; + + omap_timer_save_context(timer); + return 0; } @@ -763,6 +771,9 @@ static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev) { struct omap_dm_timer *timer = dev_get_drvdata(dev); + if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base) + omap_timer_restore_context(timer); + atomic_set(&timer->enabled, 1); return 0; @@ -829,7 +840,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev) timer->id = pdev->id; timer->capability = pdata->timer_capability; timer->reserved = omap_dm_timer_reserved_systimer(timer->id); - timer->get_context_loss_count = pdata->get_context_loss_count; + } + + if (!(timer->capability & OMAP_TIMER_ALWON)) { + timer->nb.notifier_call = omap_timer_context_notifier; + cpu_pm_register_notifier(&timer->nb); } if (pdata) @@ -883,6 +898,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev) list_for_each_entry(timer, &omap_timer_list, node) if (!strcmp(dev_name(&timer->pdev->dev), dev_name(&pdev->dev))) { + if (!(timer->capability & OMAP_TIMER_ALWON)) + cpu_pm_unregister_notifier(&timer->nb); list_del(&timer->node); ret = 0; break; diff --git a/include/clocksource/timer-ti-dm.h b/include/clocksource/timer-ti-dm.h index eef5de300731..25f05235866e 100644 --- a/include/clocksource/timer-ti-dm.h +++ b/include/clocksource/timer-ti-dm.h @@ -110,13 +110,12 @@ struct omap_dm_timer { unsigned reserved:1; unsigned posted:1; struct timer_regs context; - int (*get_context_loss_count)(struct device *); - int ctx_loss_count; int revision; u32 capability; u32 errata; struct platform_device *pdev; struct list_head node; + struct notifier_block nb; }; int omap_dm_timer_reserve_systimer(int id); -- cgit v1.2.3-70-g09d2 From aff7665dc64b60c1f93d6e52fde297ae6b8999ae Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Thu, 5 Mar 2020 13:57:13 +0530 Subject: clocksource/drivers/timer-ti-dm: Do not update counter on updating the period Write to trigger register(OMAP_TIMER_TRIGGER_REG) will load the value in Load register(OMAP_TIMER_LOAD_REG) into Counter register (OMAP_TIMER_COUNTER_REG). omap_dm_timer_set_load() writes into trigger register every time load register is updated. When timer is configured in pwm mode, this causes disruption in current pwm cycle, which is not expected especially when pwm is used as PPS signal for synchronized PTP clocks. So do not write into trigger register on updating the period. Tested-by: Tony Lindgren Signed-off-by: Lokesh Vutla Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-5-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 1d1bea79cbf1..b565b8456e5c 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -579,7 +579,6 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); - omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); omap_dm_timer_disable(timer); return 0; } -- cgit v1.2.3-70-g09d2 From 92fd86864ec4ac089de47f0f1f4c47418b343448 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Thu, 5 Mar 2020 13:57:14 +0530 Subject: clocksource/drivers/timer-ti-dm: Add support to get pwm current status omap_dm_timer_ops provide support to configure the pwm but there is no support to get the current status. For configuring pwm it is advised to check the current hw status instead of relying on pwm framework. So implement a new timer ops to get the current status of pwm. Signed-off-by: Lokesh Vutla Acked-by: Tony Lindgen Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-6-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 15 +++++++++++++++ include/linux/platform_data/dmtimer-omap.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index b565b8456e5c..73ac73efdef8 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -627,6 +627,20 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, return 0; } +static int omap_dm_timer_get_pwm_status(struct omap_dm_timer *timer) +{ + u32 l; + + if (unlikely(!timer)) + return -EINVAL; + + omap_dm_timer_enable(timer); + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + omap_dm_timer_disable(timer); + + return l; +} + static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) { @@ -927,6 +941,7 @@ static const struct omap_dm_timer_ops dmtimer_ops = { .set_load = omap_dm_timer_set_load, .set_match = omap_dm_timer_set_match, .set_pwm = omap_dm_timer_set_pwm, + .get_pwm_status = omap_dm_timer_get_pwm_status, .set_prescaler = omap_dm_timer_set_prescaler, .read_counter = omap_dm_timer_read_counter, .write_counter = omap_dm_timer_write_counter, diff --git a/include/linux/platform_data/dmtimer-omap.h b/include/linux/platform_data/dmtimer-omap.h index bdaaf537604a..3173b7b6ff6f 100644 --- a/include/linux/platform_data/dmtimer-omap.h +++ b/include/linux/platform_data/dmtimer-omap.h @@ -36,6 +36,7 @@ struct omap_dm_timer_ops { unsigned int match); int (*set_pwm)(struct omap_dm_timer *timer, int def_on, int toggle, int trigger); + int (*get_pwm_status)(struct omap_dm_timer *timer); int (*set_prescaler)(struct omap_dm_timer *timer, int prescaler); unsigned int (*read_counter)(struct omap_dm_timer *timer); -- cgit v1.2.3-70-g09d2 From 02e6d546e3bdc1a8a764343cd1ba354da07e8623 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Thu, 5 Mar 2020 13:57:15 +0530 Subject: clocksource/drivers/timer-ti-dm: Enable autoreload in set_pwm dm timer ops set_load() api allows to configure the load value and to set the auto reload feature. But auto reload feature is independent of load value and should be part of configuring pwm. This way pwm can be disabled by disabling auto reload feature using set_pwm() so that the current pwm cycle will be completed. Else pwm disabling causes the cycle to be stopped abruptly. Signed-off-by: Lokesh Vutla Acked-by: Tony Lindgren Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-7-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 16 +++++----------- drivers/pwm/pwm-omap-dmtimer.c | 8 +++++--- include/linux/platform_data/dmtimer-omap.h | 5 ++--- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 73ac73efdef8..f5c73ebfe4ca 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -562,21 +562,13 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer) return 0; } -static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, +static int omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) { - u32 l; - if (unlikely(!timer)) return -EINVAL; omap_dm_timer_enable(timer); - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (autoreload) - l |= OMAP_TIMER_CTRL_AR; - else - l &= ~OMAP_TIMER_CTRL_AR; - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); omap_dm_timer_disable(timer); @@ -605,7 +597,7 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, } static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, - int toggle, int trigger) + int toggle, int trigger, int autoreload) { u32 l; @@ -615,12 +607,14 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, omap_dm_timer_enable(timer); l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | - OMAP_TIMER_CTRL_PT | (0x03 << 10)); + OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR); if (def_on) l |= OMAP_TIMER_CTRL_SCPWM; if (toggle) l |= OMAP_TIMER_CTRL_PT; l |= trigger << 10; + if (autoreload) + l |= OMAP_TIMER_CTRL_AR; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_disable(timer); diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 88a3c5690fea..9e4378dc6897 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -183,7 +183,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, if (timer_active) omap->pdata->stop(omap->dm_timer); - omap->pdata->set_load(omap->dm_timer, true, load_value); + omap->pdata->set_load(omap->dm_timer, load_value); omap->pdata->set_match(omap->dm_timer, true, match_value); dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n", @@ -192,7 +192,8 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, omap->pdata->set_pwm(omap->dm_timer, pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED, true, - PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE); + PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE, + true); /* If config was called while timer was running it must be reenabled. */ if (timer_active) @@ -222,7 +223,8 @@ static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip, omap->pdata->set_pwm(omap->dm_timer, polarity == PWM_POLARITY_INVERSED, true, - PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE); + PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE, + true); mutex_unlock(&omap->mutex); return 0; diff --git a/include/linux/platform_data/dmtimer-omap.h b/include/linux/platform_data/dmtimer-omap.h index 3173b7b6ff6f..95d852aef130 100644 --- a/include/linux/platform_data/dmtimer-omap.h +++ b/include/linux/platform_data/dmtimer-omap.h @@ -30,12 +30,11 @@ struct omap_dm_timer_ops { int (*stop)(struct omap_dm_timer *timer); int (*set_source)(struct omap_dm_timer *timer, int source); - int (*set_load)(struct omap_dm_timer *timer, int autoreload, - unsigned int value); + int (*set_load)(struct omap_dm_timer *timer, unsigned int value); int (*set_match)(struct omap_dm_timer *timer, int enable, unsigned int match); int (*set_pwm)(struct omap_dm_timer *timer, int def_on, - int toggle, int trigger); + int toggle, int trigger, int autoreload); int (*get_pwm_status)(struct omap_dm_timer *timer); int (*set_prescaler)(struct omap_dm_timer *timer, int prescaler); -- cgit v1.2.3-70-g09d2 From 55a690f4199d8ab111dceb0a3fd181b52d0938bf Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 17 Mar 2020 10:35:49 +0800 Subject: clocksource/drivers/imx-tpm: Remove unused includes There is nothing in use from of_address.h/of_irq.h, remove them. Signed-off-by: Anson Huang Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1584412549-18354-1-git-send-email-Anson.Huang@nxp.com --- drivers/clocksource/timer-imx-tpm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c index c1d52d5264c2..6334a35fdc2f 100644 --- a/drivers/clocksource/timer-imx-tpm.c +++ b/drivers/clocksource/timer-imx-tpm.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include "timer-of.h" -- cgit v1.2.3-70-g09d2 From 3d17cee291e8a4bc4c8b29b1c8a1b79e12f95473 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 17 Mar 2020 10:55:13 +0800 Subject: clocksource/drivers/imx-sysctr: Remove unused includes There is nothing in use from of_address.h/of_irq.h, remove them. Signed-off-by: Anson Huang Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1584413713-7376-1-git-send-email-Anson.Huang@nxp.com --- drivers/clocksource/timer-imx-sysctr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c index b7c80a368a1b..18b90fc56bfc 100644 --- a/drivers/clocksource/timer-imx-sysctr.c +++ b/drivers/clocksource/timer-imx-sysctr.c @@ -4,8 +4,6 @@ #include #include -#include -#include #include "timer-of.h" -- cgit v1.2.3-70-g09d2 From 4f41fe386a94639cd9a1831298d4f85db5662f1e Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Fri, 10 Jan 2020 21:21:25 -0800 Subject: clocksource/drivers/timer-probe: Avoid creating dead devices Timer initialization is done during early boot way before the driver core starts processing devices and drivers. Timers initialized during this early boot period don't really need or use a struct device. However, for timers represented as device tree nodes, the struct devices are still created and sit around unused and wasting memory. This change avoid this by marking the device tree nodes as "populated" if the corresponding timer is successfully initialized. Signed-off-by: Saravana Kannan Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200111052125.238212-1-saravanak@google.com --- drivers/clocksource/timer-probe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clocksource/timer-probe.c b/drivers/clocksource/timer-probe.c index ee9574da53c0..a10f28d750a9 100644 --- a/drivers/clocksource/timer-probe.c +++ b/drivers/clocksource/timer-probe.c @@ -27,8 +27,10 @@ void __init timer_probe(void) init_func_ret = match->data; + of_node_set_flag(np, OF_POPULATED); ret = init_func_ret(np); if (ret) { + of_node_clear_flag(np, OF_POPULATED); if (ret != -EPROBE_DEFER) pr_err("Failed to initialize '%pOF': %d\n", np, ret); -- cgit v1.2.3-70-g09d2 From 2c8bd58812ee3dbf0d78b566822f7eacd34bdd7b Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Mon, 9 Mar 2020 18:15:29 +0000 Subject: time/sched_clock: Expire timer in hardirq context To minimize latency, PREEMPT_RT kernels expires hrtimers in preemptible softirq context by default. This can be overriden by marking the timer's expiry with HRTIMER_MODE_HARD. sched_clock_timer is missing this annotation: if its callback is preempted and the duration of the preemption exceeds the wrap around time of the underlying clocksource, sched clock will get out of sync. Mark the sched_clock_timer for expiry in hard interrupt context. Signed-off-by: Ahmed S. Darwish Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200309181529.26558-1-a.darwish@linutronix.de --- kernel/time/sched_clock.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c index e4332e3e2d56..fa3f800d7d76 100644 --- a/kernel/time/sched_clock.c +++ b/kernel/time/sched_clock.c @@ -208,7 +208,8 @@ sched_clock_register(u64 (*read)(void), int bits, unsigned long rate) if (sched_clock_timer.function != NULL) { /* update timeout for clock wrap */ - hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); + hrtimer_start(&sched_clock_timer, cd.wrap_kt, + HRTIMER_MODE_REL_HARD); } r = rate; @@ -254,9 +255,9 @@ void __init generic_sched_clock_init(void) * Start the timer to keep sched_clock() properly updated and * sets the initial epoch. */ - hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); sched_clock_timer.function = sched_clock_poll; - hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); + hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD); } /* @@ -293,7 +294,7 @@ void sched_clock_resume(void) struct clock_read_data *rd = &cd.read_data[0]; rd->epoch_cyc = cd.actual_read_sched_clock(); - hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); + hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD); rd->read_sched_clock = cd.actual_read_sched_clock; } -- cgit v1.2.3-70-g09d2 From 52da479a9aee630d2cdf37d05edfe5bcfff3e17f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 19 Mar 2020 19:47:06 +0100 Subject: Revert "tick/common: Make tick_periodic() check for missing ticks" This reverts commit d441dceb5dce71150f28add80d36d91bbfccba99 due to boot failures. Reported-by: Qian Cai Signed-off-by: Thomas Gleixner Cc: Waiman Long --- kernel/time/tick-common.c | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index cce4ed1515c7..7e5d3524e924 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -85,41 +84,12 @@ int tick_is_oneshot_available(void) static void tick_periodic(int cpu) { if (tick_do_timer_cpu == cpu) { - /* - * Use running_clock() as reference to check for missing ticks. - */ - static ktime_t last_update; - ktime_t now; - int ticks = 1; - - now = ns_to_ktime(running_clock()); write_seqlock(&jiffies_lock); - if (last_update) { - u64 delta = ktime_sub(now, last_update); - - /* - * Check for eventually missed ticks - * - * There is likely a persistent delta between - * last_update and tick_next_period. So they are - * updated separately. - */ - if (delta >= 2 * tick_period) { - s64 period = ktime_to_ns(tick_period); - - ticks = ktime_divns(delta, period); - } - last_update = ktime_add(last_update, - ticks * tick_period); - } else { - last_update = now; - } - /* Keep track of the next tick event */ - tick_next_period = ktime_add(tick_next_period, - ticks * tick_period); - do_timer(ticks); + tick_next_period = ktime_add(tick_next_period, tick_period); + + do_timer(1); write_sequnlock(&jiffies_lock); update_wall_time(); } -- cgit v1.2.3-70-g09d2 From 8165b57bca2167acc150b708a9a6b7322f235e91 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:26 +0000 Subject: linux/const.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split const.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-2-vincenzo.frascino@arm.com --- include/linux/const.h | 5 +---- include/vdso/const.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 include/vdso/const.h diff --git a/include/linux/const.h b/include/linux/const.h index 7b55a55f5911..81b8aae5a855 100644 --- a/include/linux/const.h +++ b/include/linux/const.h @@ -1,9 +1,6 @@ #ifndef _LINUX_CONST_H #define _LINUX_CONST_H -#include - -#define UL(x) (_UL(x)) -#define ULL(x) (_ULL(x)) +#include #endif /* _LINUX_CONST_H */ diff --git a/include/vdso/const.h b/include/vdso/const.h new file mode 100644 index 000000000000..94b385ad438d --- /dev/null +++ b/include/vdso/const.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_CONST_H +#define __VDSO_CONST_H + +#include + +#define UL(x) (_UL(x)) +#define ULL(x) (_ULL(x)) + +#endif /* __VDSO_CONST_H */ -- cgit v1.2.3-70-g09d2 From 3945ff37d2f48d39fd1751d282c80176654049e4 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:27 +0000 Subject: linux/bits.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split bits.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-3-vincenzo.frascino@arm.com --- include/linux/bits.h | 2 +- include/vdso/bits.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 include/vdso/bits.h diff --git a/include/linux/bits.h b/include/linux/bits.h index 669d69441a62..a740bbcf3cd2 100644 --- a/include/linux/bits.h +++ b/include/linux/bits.h @@ -3,9 +3,9 @@ #define __LINUX_BITS_H #include +#include #include -#define BIT(nr) (UL(1) << (nr)) #define BIT_ULL(nr) (ULL(1) << (nr)) #define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) diff --git a/include/vdso/bits.h b/include/vdso/bits.h new file mode 100644 index 000000000000..6d005a1f5d94 --- /dev/null +++ b/include/vdso/bits.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_BITS_H +#define __VDSO_BITS_H + +#include + +#define BIT(nr) (UL(1) << (nr)) + +#endif /* __VDSO_BITS_H */ -- cgit v1.2.3-70-g09d2 From 3e0e9f8c6e3ca92154a74edc23a8872da921d2b6 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:28 +0000 Subject: linux/limits.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split limits.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-4-vincenzo.frascino@arm.com --- include/linux/limits.h | 13 +------------ include/vdso/limits.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 include/vdso/limits.h diff --git a/include/linux/limits.h b/include/linux/limits.h index 76afcd24ff8c..7fc497ee1393 100644 --- a/include/linux/limits.h +++ b/include/linux/limits.h @@ -4,19 +4,8 @@ #include #include +#include -#define USHRT_MAX ((unsigned short)~0U) -#define SHRT_MAX ((short)(USHRT_MAX >> 1)) -#define SHRT_MIN ((short)(-SHRT_MAX - 1)) -#define INT_MAX ((int)(~0U >> 1)) -#define INT_MIN (-INT_MAX - 1) -#define UINT_MAX (~0U) -#define LONG_MAX ((long)(~0UL >> 1)) -#define LONG_MIN (-LONG_MAX - 1) -#define ULONG_MAX (~0UL) -#define LLONG_MAX ((long long)(~0ULL >> 1)) -#define LLONG_MIN (-LLONG_MAX - 1) -#define ULLONG_MAX (~0ULL) #define SIZE_MAX (~(size_t)0) #define PHYS_ADDR_MAX (~(phys_addr_t)0) diff --git a/include/vdso/limits.h b/include/vdso/limits.h new file mode 100644 index 000000000000..0197888ad0e0 --- /dev/null +++ b/include/vdso/limits.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_LIMITS_H +#define __VDSO_LIMITS_H + +#define USHRT_MAX ((unsigned short)~0U) +#define SHRT_MAX ((short)(USHRT_MAX >> 1)) +#define SHRT_MIN ((short)(-SHRT_MAX - 1)) +#define INT_MAX ((int)(~0U >> 1)) +#define INT_MIN (-INT_MAX - 1) +#define UINT_MAX (~0U) +#define LONG_MAX ((long)(~0UL >> 1)) +#define LONG_MIN (-LONG_MAX - 1) +#define ULONG_MAX (~0UL) +#define LLONG_MAX ((long long)(~0ULL >> 1)) +#define LLONG_MIN (-LLONG_MAX - 1) +#define ULLONG_MAX (~0ULL) +#define UINTPTR_MAX ULONG_MAX + +#endif /* __VDSO_LIMITS_H */ -- cgit v1.2.3-70-g09d2 From 659a9faa3f3c89de4c34c30c3da676059864e0fe Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:29 +0000 Subject: x86: Introduce asm/vdso/clocksource.h The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Introduce asm/vdso/clocksource.h to contain all the arm64 specific functions that are suitable for vDSO inclusion. This header will be required by a future patch that will generalize vdso/clocksource.h. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-5-vincenzo.frascino@arm.com --- arch/x86/include/asm/clocksource.h | 5 +---- arch/x86/include/asm/vdso/clocksource.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 arch/x86/include/asm/vdso/clocksource.h diff --git a/arch/x86/include/asm/clocksource.h b/arch/x86/include/asm/clocksource.h index d561db67f96d..dc9dc7b3911a 100644 --- a/arch/x86/include/asm/clocksource.h +++ b/arch/x86/include/asm/clocksource.h @@ -4,10 +4,7 @@ #ifndef _ASM_X86_CLOCKSOURCE_H #define _ASM_X86_CLOCKSOURCE_H -#define VDSO_ARCH_CLOCKMODES \ - VDSO_CLOCKMODE_TSC, \ - VDSO_CLOCKMODE_PVCLOCK, \ - VDSO_CLOCKMODE_HVCLOCK +#include extern unsigned int vclocks_used; diff --git a/arch/x86/include/asm/vdso/clocksource.h b/arch/x86/include/asm/vdso/clocksource.h new file mode 100644 index 000000000000..119ac8612d89 --- /dev/null +++ b/arch/x86/include/asm/vdso/clocksource.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSO_CLOCKSOURCE_H +#define __ASM_VDSO_CLOCKSOURCE_H + +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_TSC, \ + VDSO_CLOCKMODE_PVCLOCK, \ + VDSO_CLOCKMODE_HVCLOCK + +#endif /* __ASM_VDSO_CLOCKSOURCE_H */ -- cgit v1.2.3-70-g09d2 From c16b270b171177d1a602b270aef9bff45585bfa2 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:30 +0000 Subject: arm: Introduce asm/vdso/clocksource.h The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Introduce asm/vdso/clocksource.h to contain all the arm64 specific functions that are suitable for vDSO inclusion. This header will be required by a future patch that will generalize vdso/clocksource.h. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Cc: Russell King Link: https://lkml.kernel.org/r/20200320145351.32292-6-vincenzo.frascino@arm.com --- arch/arm/include/asm/clocksource.h | 6 +++--- arch/arm/include/asm/vdso/clocksource.h | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 arch/arm/include/asm/vdso/clocksource.h diff --git a/arch/arm/include/asm/clocksource.h b/arch/arm/include/asm/clocksource.h index 73beb7f131de..13651c731a81 100644 --- a/arch/arm/include/asm/clocksource.h +++ b/arch/arm/include/asm/clocksource.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _ASM_CLOCKSOURCE_H #define _ASM_CLOCKSOURCE_H -#define VDSO_ARCH_CLOCKMODES \ - VDSO_CLOCKMODE_ARCHTIMER +#include -#endif +#endif /* _ASM_CLOCKSOURCE_H */ diff --git a/arch/arm/include/asm/vdso/clocksource.h b/arch/arm/include/asm/vdso/clocksource.h new file mode 100644 index 000000000000..50c0b19fb755 --- /dev/null +++ b/arch/arm/include/asm/vdso/clocksource.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSOCLOCKSOURCE_H +#define __ASM_VDSOCLOCKSOURCE_H + +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_ARCHTIMER + +#endif /* __ASM_VDSOCLOCKSOURCE_H */ -- cgit v1.2.3-70-g09d2 From 31fdcac07f679848b5ba371500292b685fd39217 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:31 +0000 Subject: arm64: Introduce asm/vdso/clocksource.h The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Introduce asm/vdso/clocksource.h to contain all the arm64 specific functions that are suitable for vDSO inclusion. This header will be required by a future patch that will generalize vdso/clocksource.h. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Acked-by: Catalin Marinas Cc: Will Deacon Link: https://lkml.kernel.org/r/20200320145351.32292-7-vincenzo.frascino@arm.com --- arch/arm64/include/asm/clocksource.h | 3 +-- arch/arm64/include/asm/vdso/clocksource.h | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/include/asm/vdso/clocksource.h diff --git a/arch/arm64/include/asm/clocksource.h b/arch/arm64/include/asm/clocksource.h index eb82e9d95c5d..482185566b0c 100644 --- a/arch/arm64/include/asm/clocksource.h +++ b/arch/arm64/include/asm/clocksource.h @@ -2,7 +2,6 @@ #ifndef _ASM_CLOCKSOURCE_H #define _ASM_CLOCKSOURCE_H -#define VDSO_ARCH_CLOCKMODES \ - VDSO_CLOCKMODE_ARCHTIMER +#include #endif diff --git a/arch/arm64/include/asm/vdso/clocksource.h b/arch/arm64/include/asm/vdso/clocksource.h new file mode 100644 index 000000000000..df6ea65c1dec --- /dev/null +++ b/arch/arm64/include/asm/vdso/clocksource.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSOCLOCKSOURCE_H +#define __ASM_VDSOCLOCKSOURCE_H + +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_ARCHTIMER + +#endif -- cgit v1.2.3-70-g09d2 From 17e46656a82fc4645324043241b3294f6db9a6ce Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:32 +0000 Subject: mips: Introduce asm/vdso/clocksource.h The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Introduce asm/vdso/clocksource.h to contain all the arm64 specific functions that are suitable for vDSO inclusion. This header will be required by a future patch that will generalize vdso/clocksource.h. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Cc: Paul Burton Link: https://lkml.kernel.org/r/20200320145351.32292-8-vincenzo.frascino@arm.com --- arch/mips/include/asm/clocksource.h | 4 +--- arch/mips/include/asm/vdso/clocksource.h | 9 +++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 arch/mips/include/asm/vdso/clocksource.h diff --git a/arch/mips/include/asm/clocksource.h b/arch/mips/include/asm/clocksource.h index de659cae0d4e..2f1ebbea3d72 100644 --- a/arch/mips/include/asm/clocksource.h +++ b/arch/mips/include/asm/clocksource.h @@ -6,8 +6,6 @@ #ifndef __ASM_CLOCKSOURCE_H #define __ASM_CLOCKSOURCE_H -#define VDSO_ARCH_CLOCKMODES \ - VDSO_CLOCKMODE_R4K, \ - VDSO_CLOCKMODE_GIC +#include #endif /* __ASM_CLOCKSOURCE_H */ diff --git a/arch/mips/include/asm/vdso/clocksource.h b/arch/mips/include/asm/vdso/clocksource.h new file mode 100644 index 000000000000..510e1671d898 --- /dev/null +++ b/arch/mips/include/asm/vdso/clocksource.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __ASM_VDSOCLOCKSOURCE_H +#define __ASM_VDSOCLOCKSOURCE_H + +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_R4K, \ + VDSO_CLOCKMODE_GIC + +#endif /* __ASM_VDSOCLOCKSOURCE_H */ -- cgit v1.2.3-70-g09d2 From 14ee2ac618e49e767c9af4aa007f951eb9e35153 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:33 +0000 Subject: linux/clocksource.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split clocksource.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-9-vincenzo.frascino@arm.com --- include/linux/clocksource.h | 11 +---------- include/vdso/clocksource.h | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 include/vdso/clocksource.h diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 02e3282719bd..86d143db6523 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -28,16 +28,7 @@ struct module; #include #endif -enum vdso_clock_mode { - VDSO_CLOCKMODE_NONE, -#ifdef CONFIG_GENERIC_GETTIMEOFDAY - VDSO_ARCH_CLOCKMODES, -#endif - VDSO_CLOCKMODE_MAX, - - /* Indicator for time namespace VDSO */ - VDSO_CLOCKMODE_TIMENS = INT_MAX -}; +#include /** * struct clocksource - hardware abstraction for a free running counter diff --git a/include/vdso/clocksource.h b/include/vdso/clocksource.h new file mode 100644 index 000000000000..ab58330e4e5d --- /dev/null +++ b/include/vdso/clocksource.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_CLOCKSOURCE_H +#define __VDSO_CLOCKSOURCE_H + +#include + +#if defined(CONFIG_ARCH_CLOCKSOURCE_DATA) || \ + defined(CONFIG_GENERIC_GETTIMEOFDAY) +#include +#endif /* CONFIG_ARCH_CLOCKSOURCE_DATA || CONFIG_GENERIC_GETTIMEOFDAY */ + +enum vdso_clock_mode { + VDSO_CLOCKMODE_NONE, +#ifdef CONFIG_GENERIC_GETTIMEOFDAY + VDSO_ARCH_CLOCKMODES, +#endif + VDSO_CLOCKMODE_MAX, + + /* Indicator for time namespace VDSO */ + VDSO_CLOCKMODE_TIMENS = INT_MAX +}; + +#endif /* __VDSO_CLOCKSOURCE_H */ -- cgit v1.2.3-70-g09d2 From b874b8358c756f2503c55686af842d99f5b1f312 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:34 +0000 Subject: linux/math64.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split math64.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-10-vincenzo.frascino@arm.com --- include/linux/math64.h | 20 +------------------- include/vdso/math64.h | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 19 deletions(-) create mode 100644 include/vdso/math64.h diff --git a/include/linux/math64.h b/include/linux/math64.h index 65bef21cdddb..11a267413e8e 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -3,6 +3,7 @@ #define _LINUX_MATH64_H #include +#include #include #if BITS_PER_LONG == 64 @@ -142,25 +143,6 @@ static inline s64 div_s64(s64 dividend, s32 divisor) u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder); -static __always_inline u32 -__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) -{ - u32 ret = 0; - - while (dividend >= divisor) { - /* The following asm() prevents the compiler from - optimising this loop into a modulo operation. */ - asm("" : "+rm"(dividend)); - - dividend -= divisor; - ret++; - } - - *remainder = dividend; - - return ret; -} - #ifndef mul_u32_u32 /* * Many a GCC version messes this up and generates a 64x64 mult :-( diff --git a/include/vdso/math64.h b/include/vdso/math64.h new file mode 100644 index 000000000000..7da703ee5561 --- /dev/null +++ b/include/vdso/math64.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_MATH64_H +#define __VDSO_MATH64_H + +static __always_inline u32 +__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) +{ + u32 ret = 0; + + while (dividend >= divisor) { + /* The following asm() prevents the compiler from + optimising this loop into a modulo operation. */ + asm("" : "+rm"(dividend)); + + dividend -= divisor; + ret++; + } + + *remainder = dividend; + + return ret; +} + +#endif /* __VDSO_MATH64_H */ -- cgit v1.2.3-70-g09d2 From 639fff1cce0f7462bb4440deeffc1048ecfc6ebb Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:35 +0000 Subject: linux/time.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split time.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-11-vincenzo.frascino@arm.com --- include/linux/time.h | 5 +---- include/vdso/time.h | 12 ++++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 include/vdso/time.h diff --git a/include/linux/time.h b/include/linux/time.h index 8ef5e5cc9f57..4c325bf44ce0 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -111,9 +111,6 @@ static inline bool itimerspec64_valid(const struct itimerspec64 *its) */ #define time_between32(t, l, h) ((u32)(h) - (u32)(l) >= (u32)(t) - (u32)(l)) -struct timens_offset { - s64 sec; - u64 nsec; -}; +# include #endif diff --git a/include/vdso/time.h b/include/vdso/time.h new file mode 100644 index 000000000000..739f53cd2949 --- /dev/null +++ b/include/vdso/time.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_TIME_H +#define __VDSO_TIME_H + +#include + +struct timens_offset { + s64 sec; + u64 nsec; +}; + +#endif /* __VDSO_TIME_H */ -- cgit v1.2.3-70-g09d2 From 9a4162316965818ea73701b611915deca97afece Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:36 +0000 Subject: linux/time32.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split time32.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-12-vincenzo.frascino@arm.com --- include/linux/time32.h | 14 ++------------ include/vdso/time32.h | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 include/vdso/time32.h diff --git a/include/linux/time32.h b/include/linux/time32.h index cad4c3186002..0933f28214c0 100644 --- a/include/linux/time32.h +++ b/include/linux/time32.h @@ -12,19 +12,9 @@ #include #include -#define TIME_T_MAX (__kernel_old_time_t)((1UL << ((sizeof(__kernel_old_time_t) << 3) - 1)) - 1) - -typedef s32 old_time32_t; - -struct old_timespec32 { - old_time32_t tv_sec; - s32 tv_nsec; -}; +#include -struct old_timeval32 { - old_time32_t tv_sec; - s32 tv_usec; -}; +#define TIME_T_MAX (__kernel_old_time_t)((1UL << ((sizeof(__kernel_old_time_t) << 3) - 1)) - 1) struct old_itimerspec32 { struct old_timespec32 it_interval; diff --git a/include/vdso/time32.h b/include/vdso/time32.h new file mode 100644 index 000000000000..fdf56f932f67 --- /dev/null +++ b/include/vdso/time32.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_TIME32_H +#define __VDSO_TIME32_H + +typedef s32 old_time32_t; + +struct old_timespec32 { + old_time32_t tv_sec; + s32 tv_nsec; +}; + +struct old_timeval32 { + old_time32_t tv_sec; + s32 tv_usec; +}; + +#endif /* __VDSO_TIME32_H */ -- cgit v1.2.3-70-g09d2 From b72a9c5e023bf405e62b858eb5384eb34e2b7a74 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:37 +0000 Subject: linux/time64.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split time64.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-13-vincenzo.frascino@arm.com --- include/linux/time64.h | 10 +--------- include/vdso/time64.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 include/vdso/time64.h diff --git a/include/linux/time64.h b/include/linux/time64.h index 19125489ae94..c9dcb3e5781f 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -3,6 +3,7 @@ #define _LINUX_TIME64_H #include +#include typedef __s64 time64_t; typedef __u64 timeu64_t; @@ -19,15 +20,6 @@ struct itimerspec64 { struct timespec64 it_value; }; -/* Parameters used to convert the timespec values: */ -#define MSEC_PER_SEC 1000L -#define USEC_PER_MSEC 1000L -#define NSEC_PER_USEC 1000L -#define NSEC_PER_MSEC 1000000L -#define USEC_PER_SEC 1000000L -#define NSEC_PER_SEC 1000000000L -#define FSEC_PER_SEC 1000000000000000LL - /* Located here for timespec[64]_valid_strict */ #define TIME64_MAX ((s64)~((u64)1 << 63)) #define TIME64_MIN (-TIME64_MAX - 1) diff --git a/include/vdso/time64.h b/include/vdso/time64.h new file mode 100644 index 000000000000..9d43c3f5e89d --- /dev/null +++ b/include/vdso/time64.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_TIME64_H +#define __VDSO_TIME64_H + +/* Parameters used to convert the timespec values: */ +#define MSEC_PER_SEC 1000L +#define USEC_PER_MSEC 1000L +#define NSEC_PER_USEC 1000L +#define NSEC_PER_MSEC 1000000L +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000L +#define FSEC_PER_SEC 1000000000000000LL + +#endif /* __VDSO_TIME64_H */ -- cgit v1.2.3-70-g09d2 From 97b01d2eabd8c0fa650a9d513febeae35dbc6de4 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:38 +0000 Subject: linux/jiffies.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split jiffies.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-14-vincenzo.frascino@arm.com --- include/linux/jiffies.h | 4 +--- include/vdso/jiffies.h | 11 +++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 include/vdso/jiffies.h diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index e3279ef24d28..fed6ba96c527 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -8,6 +8,7 @@ #include #include #include +#include #include /* for HZ */ #include @@ -59,9 +60,6 @@ extern int register_refined_jiffies(long clock_tick_rate); -/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */ -#define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ) - /* TICK_USEC is the time between ticks in usec assuming SHIFTED_HZ */ #define TICK_USEC ((USEC_PER_SEC + HZ/2) / HZ) diff --git a/include/vdso/jiffies.h b/include/vdso/jiffies.h new file mode 100644 index 000000000000..2f9d596c8b29 --- /dev/null +++ b/include/vdso/jiffies.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_JIFFIES_H +#define __VDSO_JIFFIES_H + +#include /* for HZ */ +#include + +/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */ +#define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ) + +#endif /* __VDSO_JIFFIES_H */ -- cgit v1.2.3-70-g09d2 From cc56f32f00154ff3586e8346c91f5253882cd8a5 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:39 +0000 Subject: linux/ktime.h: Extract common header for vDSO The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Split ktime.h into linux and common headers to make the latter suitable for inclusion in the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-15-vincenzo.frascino@arm.com --- include/linux/ktime.h | 9 +-------- include/vdso/ktime.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 include/vdso/ktime.h diff --git a/include/linux/ktime.h b/include/linux/ktime.h index b2bb44f87f5a..1fcfce97a020 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -253,14 +253,7 @@ static inline __must_check bool ktime_to_timespec64_cond(const ktime_t kt, } } -/* - * The resolution of the clocks. The resolution value is returned in - * the clock_getres() system call to give application programmers an - * idea of the (in)accuracy of timers. Timer values are rounded up to - * this resolution values. - */ -#define LOW_RES_NSEC TICK_NSEC -#define KTIME_LOW_RES (LOW_RES_NSEC) +#include static inline ktime_t ns_to_ktime(u64 ns) { diff --git a/include/vdso/ktime.h b/include/vdso/ktime.h new file mode 100644 index 000000000000..a0fd07239e0e --- /dev/null +++ b/include/vdso/ktime.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_KTIME_H +#define __VDSO_KTIME_H + +#include + +/* + * The resolution of the clocks. The resolution value is returned in + * the clock_getres() system call to give application programmers an + * idea of the (in)accuracy of timers. Timer values are rounded up to + * this resolution values. + */ +#define LOW_RES_NSEC TICK_NSEC +#define KTIME_LOW_RES (LOW_RES_NSEC) + +#endif /* __VDSO_KTIME_H */ -- cgit v1.2.3-70-g09d2 From d8bb6993d871f5d3cd6d65d3772e4b1f4ef17380 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:40 +0000 Subject: common: Introduce processor.h The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Introduce processor.h to contain all the processor specific functions that are suitable for vDSO inclusion. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-16-vincenzo.frascino@arm.com --- include/vdso/processor.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 include/vdso/processor.h diff --git a/include/vdso/processor.h b/include/vdso/processor.h new file mode 100644 index 000000000000..fbe8265ea3c4 --- /dev/null +++ b/include/vdso/processor.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 ARM Ltd. + */ +#ifndef __VDSO_PROCESSOR_H +#define __VDSO_PROCESSOR_H + +#ifndef __ASSEMBLY__ + +#include + +#endif /* __ASSEMBLY__ */ + +#endif /* __VDSO_PROCESSOR_H */ -- cgit v1.2.3-70-g09d2 From f58dd03b1157bdf3b64c36e9525f8d7f69c25df2 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:41 +0000 Subject: scripts: Fix the inclusion order in modpost In the process of creating the source file of a module modpost injects a set of includes that are not required if the compilation unit is statically built into the kernel. The order of inclusion of the headers can cause redefinition problems (e.g.): In file included from include/linux/elf.h:5:0, from include/linux/module.h:18, from crypto/arc4.mod.c:2: #define ELF_OSABI ELFOSABI_LINUX In file included from include/linux/elfnote.h:62:0, from include/linux/build-salt.h:4, from crypto/arc4.mod.c:1: include/uapi/linux/elf.h:363:0: note: this is the location of the previous definition #define ELF_OSABI ELFOSABI_NONE The issue was exposed during the development of the series [1]. [1] https://lore.kernel.org/lkml/20200306133242.26279-1-vincenzo.frascino@arm.com/ Reported-by: kbuild test robot Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Cc: Masahiro Yamada Cc: Michal Marek Link: https://lkml.kernel.org/r/20200320145351.32292-17-vincenzo.frascino@arm.com --- scripts/mod/modpost.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 7edfdb2f4497..0f354b1ee2aa 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2251,8 +2251,12 @@ static int check_modname_len(struct module *mod) **/ static void add_header(struct buffer *b, struct module *mod) { - buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); + /* + * Include build-salt.h after module.h in order to + * inherit the definitions. + */ + buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "\n"); -- cgit v1.2.3-70-g09d2 From b558051725c5f7caa1f390ab28f3ab9db085cbfc Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:42 +0000 Subject: linux/elfnote.h: Replace elf.h with UAPI equivalent The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Replace linux/elf.h with UAPI equivalent in elfnote.h to make the header suitable for vDSO inclusion. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-18-vincenzo.frascino@arm.com --- include/linux/elfnote.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h index f236f5b931b2..594d4e78654f 100644 --- a/include/linux/elfnote.h +++ b/include/linux/elfnote.h @@ -59,7 +59,7 @@ ELFNOTE_END #else /* !__ASSEMBLER__ */ -#include +#include /* * Use an anonymous structure which matches the shape of * Elf{32,64}_Nhdr, but includes the name and desc data. The size and -- cgit v1.2.3-70-g09d2 From 94d0f5be885ce1e6ca2886af1543165c16745d13 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:43 +0000 Subject: arm64: vdso32: Code clean up The compat vdso library had some checks that are not anymore relevant. Remove the unused code from the compat vDSO library. Note: This patch is preparatory for a future one that will introduce asm/vdso/processor.h on arm64. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Acked-by: Catalin Marinas Cc: Will Deacon Link: https://lore.kernel.org/lkml/20200317122220.30393-19-vincenzo.frascino@arm.com Link: https://lkml.kernel.org/r/20200320145351.32292-19-vincenzo.frascino@arm.com --- arch/arm64/include/asm/vdso/compat_gettimeofday.h | 8 -------- arch/arm64/kernel/vdso32/vgettimeofday.c | 12 ------------ 2 files changed, 20 deletions(-) diff --git a/arch/arm64/include/asm/vdso/compat_gettimeofday.h b/arch/arm64/include/asm/vdso/compat_gettimeofday.h index 81b0c394f1d8..401df2bcd741 100644 --- a/arch/arm64/include/asm/vdso/compat_gettimeofday.h +++ b/arch/arm64/include/asm/vdso/compat_gettimeofday.h @@ -76,10 +76,6 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) register long ret asm ("r0"); register long nr asm("r7") = __NR_compat_clock_getres_time64; - /* The checks below are required for ABI consistency with arm */ - if ((_clkid >= MAX_CLOCKS) && (_ts == NULL)) - return -EINVAL; - asm volatile( " swi #0\n" : "=r" (ret) @@ -97,10 +93,6 @@ int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) register long ret asm ("r0"); register long nr asm("r7") = __NR_compat_clock_getres; - /* The checks below are required for ABI consistency with arm */ - if ((_clkid >= MAX_CLOCKS) && (_ts == NULL)) - return -EINVAL; - asm volatile( " swi #0\n" : "=r" (ret) diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c index 54fc1c2ce93f..ddbad47efaa4 100644 --- a/arch/arm64/kernel/vdso32/vgettimeofday.c +++ b/arch/arm64/kernel/vdso32/vgettimeofday.c @@ -11,20 +11,12 @@ int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { - /* The checks below are required for ABI consistency with arm */ - if ((u32)ts >= TASK_SIZE_32) - return -EFAULT; - return __cvdso_clock_gettime32(clock, ts); } int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts) { - /* The checks below are required for ABI consistency with arm */ - if ((u32)ts >= TASK_SIZE_32) - return -EFAULT; - return __cvdso_clock_gettime(clock, ts); } @@ -37,10 +29,6 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv, int __vdso_clock_getres(clockid_t clock_id, struct old_timespec32 *res) { - /* The checks below are required for ABI consistency with arm */ - if ((u32)res >= TASK_SIZE_32) - return -EFAULT; - return __cvdso_clock_getres_time32(clock_id, res); } -- cgit v1.2.3-70-g09d2 From f511e079177a9b97175a9a3b0ee2374d55682403 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:44 +0000 Subject: arm64: Introduce asm/vdso/processor.h The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Introduce asm/vdso/processor.h to contain all the arm64 specific functions that are suitable for vDSO inclusion. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Acked-by: Catalin Marinas Cc: Will Deacon Link: https://lkml.kernel.org/r/20200320145351.32292-20-vincenzo.frascino@arm.com --- arch/arm64/include/asm/processor.h | 7 ++----- arch/arm64/include/asm/vdso/processor.h | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 arch/arm64/include/asm/vdso/processor.h diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 5ba63204d078..e51ef2dc5749 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -256,11 +258,6 @@ extern void release_thread(struct task_struct *); unsigned long get_wchan(struct task_struct *p); -static inline void cpu_relax(void) -{ - asm volatile("yield" ::: "memory"); -} - /* Thread switching */ extern struct task_struct *cpu_switch_to(struct task_struct *prev, struct task_struct *next); diff --git a/arch/arm64/include/asm/vdso/processor.h b/arch/arm64/include/asm/vdso/processor.h new file mode 100644 index 000000000000..ff830b766ad2 --- /dev/null +++ b/arch/arm64/include/asm/vdso/processor.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 ARM Ltd. + */ +#ifndef __ASM_VDSO_PROCESSOR_H +#define __ASM_VDSO_PROCESSOR_H + +#ifndef __ASSEMBLY__ + +static inline void cpu_relax(void) +{ + asm volatile("yield" ::: "memory"); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_VDSO_PROCESSOR_H */ -- cgit v1.2.3-70-g09d2 From 60ad903e9477a832e4575734540db32023a605e9 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:45 +0000 Subject: arm64: vdso: Include common headers in the vdso library The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Refactor the vdso implementation to include common headers. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Acked-by: Catalin Marinas Cc: Will Deacon Link: https://lkml.kernel.org/r/20200320145351.32292-21-vincenzo.frascino@arm.com --- arch/arm64/include/asm/vdso/gettimeofday.h | 1 - arch/arm64/kernel/vdso/vgettimeofday.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/arch/arm64/include/asm/vdso/gettimeofday.h b/arch/arm64/include/asm/vdso/gettimeofday.h index 5a534432aa5d..afba6ba332f8 100644 --- a/arch/arm64/include/asm/vdso/gettimeofday.h +++ b/arch/arm64/include/asm/vdso/gettimeofday.h @@ -8,7 +8,6 @@ #ifndef __ASSEMBLY__ #include -#include #define VDSO_HAS_CLOCK_GETRES 1 diff --git a/arch/arm64/kernel/vdso/vgettimeofday.c b/arch/arm64/kernel/vdso/vgettimeofday.c index 747635501a14..4236cf34d7d9 100644 --- a/arch/arm64/kernel/vdso/vgettimeofday.c +++ b/arch/arm64/kernel/vdso/vgettimeofday.c @@ -5,8 +5,6 @@ * Copyright (C) 2018 ARM Limited * */ -#include -#include int __kernel_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) -- cgit v1.2.3-70-g09d2 From 5340e873576ee04186eca3c70844c576d714cc6a Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:46 +0000 Subject: arm64: vdso32: Include common headers in the vdso library The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Refactor the vdso32 implementation to include common headers. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Acked-by: Catalin Marinas Cc: Will Deacon Link: https://lkml.kernel.org/r/20200320145351.32292-22-vincenzo.frascino@arm.com --- arch/arm64/include/asm/vdso/compat_gettimeofday.h | 2 +- arch/arm64/kernel/vdso32/vgettimeofday.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/vdso/compat_gettimeofday.h b/arch/arm64/include/asm/vdso/compat_gettimeofday.h index 401df2bcd741..b6907ae78e53 100644 --- a/arch/arm64/include/asm/vdso/compat_gettimeofday.h +++ b/arch/arm64/include/asm/vdso/compat_gettimeofday.h @@ -8,7 +8,7 @@ #ifndef __ASSEMBLY__ #include -#include +#include #include diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c index ddbad47efaa4..5acff29c5991 100644 --- a/arch/arm64/kernel/vdso32/vgettimeofday.c +++ b/arch/arm64/kernel/vdso32/vgettimeofday.c @@ -5,8 +5,6 @@ * Copyright (C) 2018 ARM Limited * */ -#include -#include int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) -- cgit v1.2.3-70-g09d2 From c135fc875ce363ff8405a8e64408bca0aa2a865b Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:47 +0000 Subject: mips: vdso: Enable mips to use common headers Enable mips to use only the common headers in the implementation of the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Cc: Paul Burton Link: https://lkml.kernel.org/r/20200320145351.32292-23-vincenzo.frascino@arm.com --- arch/mips/include/asm/processor.h | 16 +--------------- arch/mips/include/asm/vdso/gettimeofday.h | 4 ---- arch/mips/include/asm/vdso/processor.h | 27 +++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 arch/mips/include/asm/vdso/processor.h diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 7619ad319400..4c9cc667f3ed 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -22,6 +22,7 @@ #include #include #include +#include /* * System setup and hardware flags.. @@ -385,21 +386,6 @@ unsigned long get_wchan(struct task_struct *p); #define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[29]) #define KSTK_STATUS(tsk) (task_pt_regs(tsk)->cp0_status) -#ifdef CONFIG_CPU_LOONGSON64 -/* - * Loongson-3's SFB (Store-Fill-Buffer) may buffer writes indefinitely when a - * tight read loop is executed, because reads take priority over writes & the - * hardware (incorrectly) doesn't ensure that writes will eventually occur. - * - * Since spin loops of any kind should have a cpu_relax() in them, force an SFB - * flush from cpu_relax() such that any pending writes will become visible as - * expected. - */ -#define cpu_relax() smp_mb() -#else -#define cpu_relax() barrier() -#endif - /* * Return_address is a replacement for __builtin_return_address(count) * which on certain architectures cannot reasonably be implemented in GCC diff --git a/arch/mips/include/asm/vdso/gettimeofday.h b/arch/mips/include/asm/vdso/gettimeofday.h index 88c3de1bdf22..c63ddcaea54c 100644 --- a/arch/mips/include/asm/vdso/gettimeofday.h +++ b/arch/mips/include/asm/vdso/gettimeofday.h @@ -13,12 +13,8 @@ #ifndef __ASSEMBLY__ -#include -#include - #include #include -#include #include #include diff --git a/arch/mips/include/asm/vdso/processor.h b/arch/mips/include/asm/vdso/processor.h new file mode 100644 index 000000000000..511c95d735e6 --- /dev/null +++ b/arch/mips/include/asm/vdso/processor.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 ARM Ltd. + */ +#ifndef __ASM_VDSO_PROCESSOR_H +#define __ASM_VDSO_PROCESSOR_H + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_CPU_LOONGSON64 +/* + * Loongson-3's SFB (Store-Fill-Buffer) may buffer writes indefinitely when a + * tight read loop is executed, because reads take priority over writes & the + * hardware (incorrectly) doesn't ensure that writes will eventually occur. + * + * Since spin loops of any kind should have a cpu_relax() in them, force an SFB + * flush from cpu_relax() such that any pending writes will become visible as + * expected. + */ +#define cpu_relax() smp_mb() +#else +#define cpu_relax() barrier() +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_VDSO_PROCESSOR_H */ -- cgit v1.2.3-70-g09d2 From abc22418db02b986fc5623c035507b6357e191ed Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:48 +0000 Subject: x86/vdso: Enable x86 to use common headers Enable x86 to use only the common headers in the implementation of the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-24-vincenzo.frascino@arm.com --- arch/x86/include/asm/processor.h | 12 +----------- arch/x86/include/asm/vdso/processor.h | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 arch/x86/include/asm/vdso/processor.h diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 09705ccc393c..94789db550df 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -26,6 +26,7 @@ struct vm86; #include #include #include +#include #include #include @@ -677,17 +678,6 @@ static inline unsigned int cpuid_edx(unsigned int op) return edx; } -/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ -static __always_inline void rep_nop(void) -{ - asm volatile("rep; nop" ::: "memory"); -} - -static __always_inline void cpu_relax(void) -{ - rep_nop(); -} - /* * This function forces the icache and prefetched instruction stream to * catch up with reality in two very specific cases: diff --git a/arch/x86/include/asm/vdso/processor.h b/arch/x86/include/asm/vdso/processor.h new file mode 100644 index 000000000000..57b1a7034c64 --- /dev/null +++ b/arch/x86/include/asm/vdso/processor.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 ARM Ltd. + */ +#ifndef __ASM_VDSO_PROCESSOR_H +#define __ASM_VDSO_PROCESSOR_H + +#ifndef __ASSEMBLY__ + +/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ +static __always_inline void rep_nop(void) +{ + asm volatile("rep; nop" ::: "memory"); +} + +static __always_inline void cpu_relax(void) +{ + rep_nop(); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_VDSO_PROCESSOR_H */ -- cgit v1.2.3-70-g09d2 From 78c8516141014cf6322ac899c3832f66612504bb Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:49 +0000 Subject: arm: vdso: Enable arm to use common headers Enable arm to use only the common headers in the implementation of the vDSO library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Cc: Russell King Link: https://lkml.kernel.org/r/20200320145351.32292-25-vincenzo.frascino@arm.com --- arch/arm/include/asm/cp15.h | 20 +---------------- arch/arm/include/asm/processor.h | 11 +-------- arch/arm/include/asm/vdso/cp15.h | 38 ++++++++++++++++++++++++++++++++ arch/arm/include/asm/vdso/gettimeofday.h | 4 ++-- arch/arm/include/asm/vdso/processor.h | 22 ++++++++++++++++++ 5 files changed, 64 insertions(+), 31 deletions(-) create mode 100644 arch/arm/include/asm/vdso/cp15.h create mode 100644 arch/arm/include/asm/vdso/processor.h diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h index d2453e2d3f1f..a54230e65647 100644 --- a/arch/arm/include/asm/cp15.h +++ b/arch/arm/include/asm/cp15.h @@ -50,25 +50,7 @@ #ifdef CONFIG_CPU_CP15 -#define __ACCESS_CP15(CRn, Op1, CRm, Op2) \ - "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32 -#define __ACCESS_CP15_64(Op1, CRm) \ - "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64 - -#define __read_sysreg(r, w, c, t) ({ \ - t __val; \ - asm volatile(r " " c : "=r" (__val)); \ - __val; \ -}) -#define read_sysreg(...) __read_sysreg(__VA_ARGS__) - -#define __write_sysreg(v, r, w, c, t) asm volatile(w " " c : : "r" ((t)(v))) -#define write_sysreg(v, ...) __write_sysreg(v, __VA_ARGS__) - -#define BPIALL __ACCESS_CP15(c7, 0, c5, 6) -#define ICIALLU __ACCESS_CP15(c7, 0, c5, 0) - -#define CNTVCT __ACCESS_CP15_64(1, c14) +#include extern unsigned long cr_alignment; /* defined in entry-armv.S */ diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index 614bf829e454..b9241051e5cb 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef __KERNEL__ #define STACK_TOP ((current->personality & ADDR_LIMIT_32BIT) ? \ @@ -85,16 +86,6 @@ extern void release_thread(struct task_struct *); unsigned long get_wchan(struct task_struct *p); -#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327) -#define cpu_relax() \ - do { \ - smp_mb(); \ - __asm__ __volatile__("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"); \ - } while (0) -#else -#define cpu_relax() barrier() -#endif - #define task_pt_regs(p) \ ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) diff --git a/arch/arm/include/asm/vdso/cp15.h b/arch/arm/include/asm/vdso/cp15.h new file mode 100644 index 000000000000..bed16fa1865e --- /dev/null +++ b/arch/arm/include/asm/vdso/cp15.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 ARM Ltd. + */ +#ifndef __ASM_VDSO_CP15_H +#define __ASM_VDSO_CP15_H + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_CPU_CP15 + +#include + +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) \ + "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32 +#define __ACCESS_CP15_64(Op1, CRm) \ + "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64 + +#define __read_sysreg(r, w, c, t) ({ \ + t __val; \ + asm volatile(r " " c : "=r" (__val)); \ + __val; \ +}) +#define read_sysreg(...) __read_sysreg(__VA_ARGS__) + +#define __write_sysreg(v, r, w, c, t) asm volatile(w " " c : : "r" ((t)(v))) +#define write_sysreg(v, ...) __write_sysreg(v, __VA_ARGS__) + +#define BPIALL __ACCESS_CP15(c7, 0, c5, 6) +#define ICIALLU __ACCESS_CP15(c7, 0, c5, 0) + +#define CNTVCT __ACCESS_CP15_64(1, c14) + +#endif /* CONFIG_CPU_CP15 */ + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_VDSO_CP15_H */ diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h index 07d791c65cf7..36dc18553ed8 100644 --- a/arch/arm/include/asm/vdso/gettimeofday.h +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -7,9 +7,9 @@ #ifndef __ASSEMBLY__ -#include -#include +#include #include +#include #include #define VDSO_HAS_CLOCK_GETRES 1 diff --git a/arch/arm/include/asm/vdso/processor.h b/arch/arm/include/asm/vdso/processor.h new file mode 100644 index 000000000000..45efb3ff511c --- /dev/null +++ b/arch/arm/include/asm/vdso/processor.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 ARM Ltd. + */ +#ifndef __ASM_VDSO_PROCESSOR_H +#define __ASM_VDSO_PROCESSOR_H + +#ifndef __ASSEMBLY__ + +#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327) +#define cpu_relax() \ + do { \ + smp_mb(); \ + __asm__ __volatile__("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"); \ + } while (0) +#else +#define cpu_relax() barrier() +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_VDSO_PROCESSOR_H */ -- cgit v1.2.3-70-g09d2 From 8c59ab839f526437831ff6d1405c9a6d93f475eb Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:50 +0000 Subject: lib/vdso: Enable common headers The vDSO library should only include the necessary headers required for a userspace library (UAPI and a minimal set of kernel headers). To make this possible it is necessary to isolate from the kernel headers the common parts that are strictly necessary to build the library. Refactor the unified vdso code to use the common headers. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200320145351.32292-26-vincenzo.frascino@arm.com --- include/vdso/datapage.h | 33 ++++++++++++++++++++++++++++++--- lib/vdso/gettimeofday.c | 22 ---------------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h index 30c4cb0428d1..5cbc9fcbfd45 100644 --- a/include/vdso/datapage.h +++ b/include/vdso/datapage.h @@ -4,9 +4,20 @@ #ifndef __ASSEMBLY__ -#include -#include -#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #define VDSO_BASES (CLOCK_TAI + 1) #define VDSO_HRES (BIT(CLOCK_REALTIME) | \ @@ -99,6 +110,22 @@ struct vdso_data { */ extern struct vdso_data _vdso_data[CS_BASES] __attribute__((visibility("hidden"))); +/* + * The generic vDSO implementation requires that gettimeofday.h + * provides: + * - __arch_get_vdso_data(): to get the vdso datapage. + * - __arch_get_hw_counter(): to get the hw counter based on the + * clock_mode. + * - gettimeofday_fallback(): fallback for gettimeofday. + * - clock_gettime_fallback(): fallback for clock_gettime. + * - clock_getres_fallback(): fallback for clock_getres. + */ +#ifdef ENABLE_COMPAT_VDSO +#include +#else +#include +#endif /* ENABLE_COMPAT_VDSO */ + #endif /* !__ASSEMBLY__ */ #endif /* __VDSO_DATAPAGE_H */ diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 72d282ffd156..a2909af4b924 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -2,31 +2,9 @@ /* * Generic userspace implementations of gettimeofday() and similar. */ -#include -#include -#include -#include -#include -#include #include #include -/* - * The generic vDSO implementation requires that gettimeofday.h - * provides: - * - __arch_get_vdso_data(): to get the vdso datapage. - * - __arch_get_hw_counter(): to get the hw counter based on the - * clock_mode. - * - gettimeofday_fallback(): fallback for gettimeofday. - * - clock_gettime_fallback(): fallback for clock_gettime. - * - clock_getres_fallback(): fallback for clock_getres. - */ -#ifdef ENABLE_COMPAT_VDSO -#include -#else -#include -#endif /* ENABLE_COMPAT_VDSO */ - #ifndef vdso_calc_delta /* * Default implementation which works for all sane clocksources. That -- cgit v1.2.3-70-g09d2 From a5d442f50a41d7c5a6a97b19c49d8a1ee0cf128b Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 20 Mar 2020 14:53:51 +0000 Subject: arm64: vdso32: Enable Clang Compilation Enable Clang Compilation for the vdso32 library. Signed-off-by: Vincenzo Frascino Signed-off-by: Thomas Gleixner Tested-by: Nathan Chancellor # build Tested-by: Stephen Boyd Reviewed-by: Nathan Chancellor Acked-by: Catalin Marinas Cc: Will Deacon Link: https://lkml.kernel.org/r/20200320145351.32292-27-vincenzo.frascino@arm.com --- arch/arm64/kernel/vdso32/Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile index 04df57b43cb1..3964738ebbde 100644 --- a/arch/arm64/kernel/vdso32/Makefile +++ b/arch/arm64/kernel/vdso32/Makefile @@ -10,7 +10,18 @@ include $(srctree)/lib/vdso/Makefile # Same as cc-*option, but using CC_COMPAT instead of CC ifeq ($(CONFIG_CC_IS_CLANG), y) +COMPAT_GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE_COMPAT)elfedit)) +COMPAT_GCC_TOOLCHAIN := $(realpath $(COMPAT_GCC_TOOLCHAIN_DIR)/..) + +CC_COMPAT_CLANG_FLAGS := --target=$(notdir $(CROSS_COMPILE_COMPAT:%-=%)) +CC_COMPAT_CLANG_FLAGS += --prefix=$(COMPAT_GCC_TOOLCHAIN_DIR) +CC_COMPAT_CLANG_FLAGS += -no-integrated-as -Qunused-arguments +ifneq ($(COMPAT_GCC_TOOLCHAIN),) +CC_COMPAT_CLANG_FLAGS += --gcc-toolchain=$(COMPAT_GCC_TOOLCHAIN) +endif + CC_COMPAT ?= $(CC) +CC_COMPAT += $(CC_COMPAT_CLANG_FLAGS) else CC_COMPAT ?= $(CROSS_COMPILE_COMPAT)gcc endif -- cgit v1.2.3-70-g09d2 From 1c1a18b00d7e25d1bed3507880de2da07be704a2 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Mon, 23 Mar 2020 12:41:09 +0000 Subject: um: Fix header inclusion User Mode Linux is a flavor of x86 that from the vDSO prospective always falls back on system calls. This implies that it does not require any of the unified vDSO definitions and their inclusion causes side effects like this: In file included from include/vdso/processor.h:10:0, from include/vdso/datapage.h:17, from arch/x86/include/asm/vgtod.h:7, from arch/x86/um/../kernel/sys_ia32.c:49: >> arch/x86/include/asm/vdso/processor.h:11:29: error: redefinition of 'rep_nop' static __always_inline void rep_nop(void) ^~~~~~~ In file included from include/linux/rcupdate.h:30:0, from include/linux/rculist.h:11, from include/linux/pid.h:5, from include/linux/sched.h:14, from arch/x86/um/../kernel/sys_ia32.c:25: arch/x86/um/asm/processor.h:24:20: note: previous definition of 'rep_nop' was here static inline void rep_nop(void) Make sure that the unnecessary headers are not included when um is built to address the problem. Fixes: abc22418db02 ("x86/vdso: Enable x86 to use common headers") Reported-by: kbuild test robot Signed-off-by: Vincenzo Frascino Signed-off-by: Borislav Petkov Link: https://lkml.kernel.org/r/20200323124109.7104-1-vincenzo.frascino@arm.com --- arch/x86/include/asm/vgtod.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h index fc8e4cd342cc..7aa38b2ad8a9 100644 --- a/arch/x86/include/asm/vgtod.h +++ b/arch/x86/include/asm/vgtod.h @@ -2,6 +2,11 @@ #ifndef _ASM_X86_VGTOD_H #define _ASM_X86_VGTOD_H +/* + * This check is required to prevent ARCH=um to include + * unwanted headers. + */ +#ifdef CONFIG_GENERIC_GETTIMEOFDAY #include #include #include @@ -14,5 +19,6 @@ typedef u64 gtod_long_t; #else typedef unsigned long gtod_long_t; #endif +#endif /* CONFIG_GENERIC_GETTIMEOFDAY */ #endif /* _ASM_X86_VGTOD_H */ -- cgit v1.2.3-70-g09d2 From ca214e2c1793058e3a1387f9e343cc5b1731db15 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Mon, 23 Mar 2020 13:39:20 +0000 Subject: vdso: Fix clocksource.h macro detection CONFIG_GENERIC_GETTIMEOFDAY is a sufficient condition to verify if an architecture implements asm/vdso/clocksource.h or not. The current implementation wrongly assumes that the same is true for the config option CONFIG_ARCH_CLOCKSOURCE_DATA. This results in a series of build errors on ia64/sparc/sparc64 like this: In file included from ./include/linux/clocksource.h:31, from ./include/linux/clockchips.h:14, from ./include/linux/tick.h:8, from fs/proc/stat.c:15: ./include/vdso/clocksource.h:9:10: fatal error: asm/vdso/clocksource.h: No such file or directory 9 | #include | ^~~~~~~~~~~~~~~~~~~~~~~~ Fix the issue removing the unneeded config condition. Fixes: 14ee2ac618e4 ("linux/clocksource.h: Extract common header for vDSO") Reported-by: Thomas Gleixner Signed-off-by: Vincenzo Frascino Signed-off-by: Borislav Petkov Link: https://lkml.kernel.org/r/20200323133920.46546-1-vincenzo.frascino@arm.com --- include/vdso/clocksource.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/vdso/clocksource.h b/include/vdso/clocksource.h index ab58330e4e5d..c682e7c60273 100644 --- a/include/vdso/clocksource.h +++ b/include/vdso/clocksource.h @@ -4,10 +4,9 @@ #include -#if defined(CONFIG_ARCH_CLOCKSOURCE_DATA) || \ - defined(CONFIG_GENERIC_GETTIMEOFDAY) +#ifdef CONFIG_GENERIC_GETTIMEOFDAY #include -#endif /* CONFIG_ARCH_CLOCKSOURCE_DATA || CONFIG_GENERIC_GETTIMEOFDAY */ +#endif /* CONFIG_GENERIC_GETTIMEOFDAY */ enum vdso_clock_mode { VDSO_CLOCKMODE_NONE, -- cgit v1.2.3-70-g09d2 From 4479730e9263befbb9ce9563a09563db2acb8f7c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 28 Mar 2020 11:20:36 +0100 Subject: Revert "clocksource/drivers/timer-probe: Avoid creating dead devices" This reverts commit 4f41fe386a94639cd9a1831298d4f85db5662f1e. The change breaks systems on which the DT node of a device is used by multiple drivers. The proposed workaround to clear OF_POPULATED is just a band aid and this needs to be cleaned up at the root of the problem. Revert this for now. Reported-by: Ionela Voinescu Reported-by: Jon Hunter Requested-by: Rob Herring Signed-off-by: Thomas Gleixner Cc: Saravana Kannan Cc: Daniel Lezcano Link: https://lore.kernel.org/r/20200324175955.GA16972@arm.com --- drivers/clocksource/timer-probe.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clocksource/timer-probe.c b/drivers/clocksource/timer-probe.c index a10f28d750a9..ee9574da53c0 100644 --- a/drivers/clocksource/timer-probe.c +++ b/drivers/clocksource/timer-probe.c @@ -27,10 +27,8 @@ void __init timer_probe(void) init_func_ret = match->data; - of_node_set_flag(np, OF_POPULATED); ret = init_func_ret(np); if (ret) { - of_node_clear_flag(np, OF_POPULATED); if (ret != -EPROBE_DEFER) pr_err("Failed to initialize '%pOF': %d\n", np, ret); -- cgit v1.2.3-70-g09d2