timer subsystem changes for v4.11
Subsystems (22)
Ingo Molnar
maintainerLinus,
Please pull the latest timers-core-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers-core-for-linus
# HEAD: 336a9cde10d641e70bac67d90ae91b3190c3edca hrtimer: Catch invalid clockids again
The main changes in this cycle were:
- Update clocksource drivers (Bhumika Goyal, Chris Brandt, David Engraf, Ding Tianhong, Linus Walleij, Daniel Lezcano)
- Make delay() work early during bootup and improve its documentation
(Jiri Slaby, Russell King)
- Remove the CONFIG_TIMER_STATS (/proc/timer_stats) debugging facility (Kees Cook)
- Detect invalid clockids (Marc Zyngier)
- Improve timer broadcast lock scalability (Waiman Long)
- ... plus various smaller fixes and cleanups.
Thanks,
Ingo
------------------>
Bhumika Goyal (1):
clocksource/drivers/arm_arch_timer:: Mark cyclecounter __ro_after_init
Chris Brandt (2):
clocksource/drivers/ostm: Document renesas-ostm timer DT bindings clocksource/drivers/ostm: Add renesas-ostm timer driver
Daniel Lezcano (1):
clockevents: Add a clkevt-of mechanism like clksrc-of
David Engraf (1):
clocksource/drivers/tcb_clksrc: Use 32 bit tcb as sched_clock
Ding Tianhong (4):
clocksource/drivers/arm_arch_timer: Add dt binding for hisilicon-161010101 erratum clocksource/drivers/arm_arch_timer: Remove fsl-a008585 parameter clocksource/drivers/arm_arch_timer: Introduce generic errata handling infrastructure clocksource/drivers/arm_arch_timer: Work around Hisilicon erratum 161010101
Geliang Tang (1):
timerqueue: Use rb_entry_safe() instead of open-coding it
Jiri Slaby (1):
x86/timer: Make delay() work during early bootup
Kees Cook (1):
time: Remove CONFIG_TIMER_STATS
Linus Walleij (2):
clocksource: add DT bindings for Cortina Gemini clocksource/drivers/gemini: Add driver for the Cortina Gemini
Marc Zyngier (1):
hrtimer: Catch invalid clockids again
Mars Cheng (1):
timer_list: Remove useless cast when printing
Nicolas Pitre (1):
timers: Omit POSIX timer stuff from task_struct when disabled
Peter Zijlstra (1):
math64, timers: Fix 32bit mul_u64_u32_shr() and friends
Russell King (1):
delay: Add explanation of udelay() inaccuracy
Stephen Boyd (1):
timekeeping: Remove unused timekeeping_{get,set}_tai_offset()
Sudip Mukherjee (1):
math64, tile: Fix build failure
Thomas Gleixner (1):
timerfd: Protect the might cancel mechanism proper
Waiman Long (1):
tick/broadcast: Reduce lock cacheline contention
Documentation/admin-guide/kernel-parameters.txt | 9 - .../devicetree/bindings/arm/arch_timer.txt | 6 + .../bindings/timer/cortina,gemini-timer.txt | 22 ++ .../devicetree/bindings/timer/renesas,ostm.txt | 30 ++ Documentation/timers/timer_stats.txt | 73 ---- arch/arm/mach-shmobile/Kconfig | 1 + arch/arm64/include/asm/arch_timer.h | 38 +- arch/tile/include/asm/Kbuild | 1 - arch/tile/include/asm/div64.h | 16 + arch/x86/include/asm/div64.h | 11 + arch/x86/lib/delay.c | 4 +- drivers/clocksource/Kconfig | 38 ++ drivers/clocksource/Makefile | 3 + drivers/clocksource/arm_arch_timer.c | 153 ++++++-- drivers/clocksource/clkevt-probe.c | 56 +++ drivers/clocksource/renesas-ostm.c | 265 +++++++++++++ drivers/clocksource/tcb_clksrc.c | 16 +- drivers/clocksource/timer-gemini.c | 277 ++++++++++++++ fs/proc/base.c | 4 +- fs/timerfd.c | 17 +- include/linux/clockchips.h | 9 + include/linux/cpumask.h | 7 +- include/linux/delay.h | 11 + include/linux/hrtimer.h | 11 - include/linux/init_task.h | 40 +- include/linux/math64.h | 26 +- include/linux/sched.h | 13 +- include/linux/timer.h | 45 --- kernel/fork.c | 10 +- kernel/kthread.c | 1 - kernel/sched/rt.c | 4 + kernel/sched/stats.h | 32 +- kernel/time/Makefile | 1 - kernel/time/hrtimer.c | 58 +-- kernel/time/tick-broadcast.c | 15 +- kernel/time/timekeeping.c | 39 +- kernel/time/timekeeping.h | 2 - kernel/time/timer.c | 48 +-- kernel/time/timer_list.c | 12 +- kernel/time/timer_stats.c | 425 --------------------- kernel/workqueue.c | 2 - lib/Kconfig.debug | 14 - lib/timerqueue.c | 3 +- 43 files changed, 1022 insertions(+), 846 deletions(-) create mode 100644 Documentation/devicetree/bindings/timer/cortina,gemini-timer.txt create mode 100644 Documentation/devicetree/bindings/timer/renesas,ostm.txt delete mode 100644 Documentation/timers/timer_stats.txt create mode 100644 arch/tile/include/asm/div64.h create mode 100644 drivers/clocksource/clkevt-probe.c create mode 100644 drivers/clocksource/renesas-ostm.c create mode 100644 drivers/clocksource/timer-gemini.c delete mode 100644 kernel/time/timer_stats.c
Documentation/admin-guide/kernel-parameters.txt +0 -9
@@ -549,15 +549,6 @@ loops can be debugged more effectively on production systems. - clocksource.arm_arch_timer.fsl-a008585= - [ARM64] - Format: <bool> - Enable/disable the workaround of Freescale/NXP - erratum A-008585. This can be useful for KVM - guests, if the guest device tree doesn't show the - erratum. If unspecified, the workaround is - enabled based on the device tree. - clearcpuid=BITNUM [X86] Disable CPUID feature X for the kernel. See arch/x86/include/asm/cpufeatures.h for the valid bit
Documentation/devicetree/bindings/arm/arch_timer.txt +6 -0
@@ -31,6 +31,12 @@ to deliver its interrupts via SPIs. This also affects writes to the tval register, due to the implicit counter read. +- hisilicon,erratum-161010101 : A boolean property. Indicates the + presence of Hisilicon erratum 161010101, which says that reading the + counters is unreliable in some cases, and reads may return a value 32 + beyond the correct value. This also affects writes to the tval + registers, due to the implicit counter read. + ** Optional properties: - arm,cpu-registers-not-fw-configured : Firmware does not initialize
Documentation/devicetree/bindings/timer/cortina,gemini-timer.txt new file +22 -0
@@ -0,0 +1,22 @@ +Cortina Systems Gemini timer + +This timer is embedded in the Cortina Systems Gemini SoCs. + +Required properties: + +- compatible : Must be "cortina,gemini-timer" +- reg : Should contain registers location and length +- interrupts : Should contain the three timer interrupts with + flags for rising edge +- syscon : a phandle to the global Gemini system controller + +Example: + +timer@43000000 { + compatible = "cortina,gemini-timer"; + reg = <0x43000000 0x1000>; + interrupts = <14 IRQ_TYPE_EDGE_RISING>, /* Timer 1 */ + <15 IRQ_TYPE_EDGE_RISING>, /* Timer 2 */ + <16 IRQ_TYPE_EDGE_RISING>; /* Timer 3 */ + syscon = <&syscon>; +};
Documentation/devicetree/bindings/timer/renesas,ostm.txt new file +30 -0
@@ -0,0 +1,30 @@ +* Renesas OS Timer (OSTM) + +The OSTM is a multi-channel 32-bit timer/counter with fixed clock +source that can operate in either interval count down timer or free-running +compare match mode. + +Channels are independent from each other. + +Required Properties: + + - compatible: must be one or more of the following: + - "renesas,r7s72100-ostm" for the r7s72100 OSTM + - "renesas,ostm" for any OSTM + This is a fallback for the above renesas,*-ostm entries + + - reg: base address and length of the register block for a timer channel. + + - interrupts: interrupt specifier for the timer channel. + + - clocks: clock specifier for the timer channel. + +Example: R7S72100 (RZ/A1H) OSTM node + + ostm0: timer@fcfec000 { + compatible = "renesas,r7s72100-ostm", "renesas,ostm"; + reg = <0xfcfec000 0x30>; + interrupts = <GIC_SPI 102 IRQ_TYPE_EDGE_RISING>; + clocks = <&mstp5_clks R7S72100_CLK_OSTM0>; + power-domains = <&cpg_clocks>; + };
Documentation/timers/timer_stats.txt deleted +0 -73
73 lines not on this page · raw message
arch/arm/mach-shmobile/Kconfig +1 -0
@@ -57,6 +57,7 @@ config ARCH_R7S72100 select PM select PM_GENERIC_DOMAINS select SYS_SUPPORTS_SH_MTU2 + select RENESAS_OSTM config ARCH_R8A73A4 bool "R-Mobile APE6 (R8A73A40)"
arch/arm64/include/asm/arch_timer.h +13 -25
@@ -29,41 +29,29 @@#include <clocksource/arm_arch_timer.h> -#if IS_ENABLED (CONFIG_FSL_ERRATUM_A008585 ) +#if IS_ENABLED (CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND )extern struct static_key_false arch_timer_read_ool_enabled; -#define needs_fsl_a008585_workaround () \ +#define needs_unstable_timer_counter_workaround () \ static_branch_unlikely(&arch_timer_read_ool_enabled)#else -#define needs_fsl_a008585_workaround () false +#define needs_unstable_timer_counter_workaround () false#endif -u32 __fsl_a008585_read_cntp_tval_el0 (void ); -u32 __fsl_a008585_read_cntv_tval_el0 (void ); -u64 __fsl_a008585_read_cntvct_el0 (void ); -/* -* The number of retries is an arbitrary value well beyond the highest number -* of iterations the loop has been observed to take. -*/ -#define __fsl_a008585_read_reg (reg) ({ \ - u64 _old, _new; \ - int _retries = 200; \ - \ - do { \ - _old = read_sysreg(reg); \ - _new = read_sysreg(reg); \ - _retries--; \ - } while (unlikely(_old != _new) && _retries); \ - \ - WARN_ON_ONCE(!_retries); \ - _new; \ -}) +struct arch_timer_erratum_workaround { +const char *id;/* Indicate the Erratum ID */ +u32 (*read_cntp_tval_el0)(void ); +u32 (*read_cntv_tval_el0)(void ); +u64 (*read_cntvct_el0)(void ); +}; + +extern const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround;#define arch_timer_reg_read_stable (reg) \ ({ \ u64 _val; \ - if (needs_fsl_a008585_workaround()) \ - _val = __fsl_a008585_read_##reg(); \ + if (needs_unstable_timer_counter_workaround()) \ + _val = timer_unstable_counter_workaround->read_##reg();\ else \ _val = read_sysreg(reg); \ _val; \
arch/tile/include/asm/Kbuild +0 -1
@@ -5,7 +5,6 @@ generic-y += bug.h generic-y += bugs.h generic-y += clkdev.h generic-y += cputime.h -generic-y += div64.h generic-y += emergency-restart.h generic-y += errno.h generic-y += exec.h
arch/tile/include/asm/div64.h new file +16 -0
@@ -0,0 +1,16 @@ +#ifndef _ASM_TILE_DIV64_H +#define _ASM_TILE_DIV64_H + +#include <linux/types.h> + +#ifdef __tilegx__ +static inline u64 mul_u32_u32 (u32 a,u32 b) +{ +return __insn_mul_lu_lu (a, b); +} +#define mul_u32_u32 mul_u32_u32 +#endif + +#include <asm-generic/div64.h> + +#endif /* _ASM_TILE_DIV64_H */
arch/x86/include/asm/div64.h +11 -0
@@ -59,6 +59,17 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) }#define div_u64_rem div_u64_rem +static inline u64 mul_u32_u32 (u32 a,u32 b) +{ +u32 high, low; + + asm ("mull %[b]" :"=a" (low),"=d" (high) + : [a]"a" (a), [b]"rm" (b) ); + +return low | ((u64 )high) <<32 ; +} +#define mul_u32_u32 mul_u32_u32 +#else # include <asm-generic/div64.h> #endif /* CONFIG_X86_32 */
arch/x86/lib/delay.c +2 -2
@@ -156,13 +156,13 @@ EXPORT_SYMBOL(__delay);inline void __const_udelay (unsigned long xloops) { +unsigned long lpj =this_cpu_read (cpu_info.loops_per_jiffy) ? : loops_per_jiffy;int d0; xloops *=4 ; asm("mull %%edx" :"=d" (xloops),"=&a" (d0) - :"1" (xloops),"0" - (this_cpu_read (cpu_info.loops_per_jiffy) * (HZ /4 ))); + :"1" (xloops),"0" (lpj * (HZ /4 )));__delay (++xloops); }
drivers/clocksource/Kconfig +38 -0
@@ -5,6 +5,10 @@ config CLKSRC_OF bool select CLKSRC_PROBE +config CLKEVT_OF + bool + select CLKEVT_PROBE + config CLKSRC_ACPI bool select CLKSRC_PROBE
@@ -12,6 +16,9 @@ config CLKSRC_ACPI config CLKSRC_PROBE bool +config CLKEVT_PROBE + bool + config CLKSRC_I8253 bool
@@ -60,6 +67,16 @@ config DW_APB_TIMER_OF select DW_APB_TIMER select CLKSRC_OF +config GEMINI_TIMER + bool "Cortina Gemini timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + depends on HAS_IOMEM + select CLKSRC_MMIO + select CLKSRC_OF + select MFD_SYSCON + help + Enables support for the Gemini timer + config ROCKCHIP_TIMER bool "Rockchip timer driver" if COMPILE_TEST depends on ARM || ARM64
@@ -325,16 +342,30 @@ config ARM_ARCH_TIMER_EVTSTREAM This must be disabled for hardware validation purposes to detect any hardware anomalies of missing events. +config ARM_ARCH_TIMER_OOL_WORKAROUND + bool + config FSL_ERRATUM_A008585 bool "Workaround for Freescale/NXP Erratum A-008585" default y depends on ARM_ARCH_TIMER && ARM64 + select ARM_ARCH_TIMER_OOL_WORKAROUND help This option enables a workaround for Freescale/NXP Erratum A-008585 ("ARM generic timer may contain an erroneous value"). The workaround will only be active if the fsl,erratum-a008585 property is found in the timer node. +config HISILICON_ERRATUM_161010101 + bool "Workaround for Hisilicon Erratum 161010101" + default y + select ARM_ARCH_TIMER_OOL_WORKAROUND + depends on ARM_ARCH_TIMER && ARM64 + help + This option enables a workaround for Hisilicon Erratum + 161010101. The workaround will be active if the hisilicon,erratum-161010101 + property is found in the timer node. + config ARM_GLOBAL_TIMER bool "Support for the ARM global timer" if COMPILE_TEST select CLKSRC_OF if OF
@@ -467,6 +498,13 @@ config SH_TIMER_MTU2 Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas. This hardware comes with 16 bit-timer registers. +config RENESAS_OSTM + bool "Renesas OSTM timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables the support for the Renesas OSTM. + config SH_TIMER_TMU bool "Renesas TMU timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS
drivers/clocksource/Makefile +3 -0
@@ -1,4 +1,5 @@ obj-$(CONFIG_CLKSRC_PROBE) += clksrc-probe.o +obj-$(CONFIG_CLKEVT_PROBE) += clkevt-probe.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
@@ -8,6 +9,7 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o +obj-$(CONFIG_RENESAS_OSTM) += renesas-ostm.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_EM_TIMER_STI) += em_sti.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o
@@ -15,6 +17,7 @@ obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o +obj-$(CONFIG_GEMINI_TIMER) += timer-gemini.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
drivers/clocksource/arm_arch_timer.c +111 -42
229 lines not on this page · raw message
drivers/clocksource/clkevt-probe.c new file +56 -0
56 lines not on this page · raw message
drivers/clocksource/renesas-ostm.c new file +265 -0
265 lines not on this page · raw message
drivers/clocksource/tcb_clksrc.c +15 -1
@@ -10,6 +10,7 @@#include <linux/io.h> #include <linux/platform_device.h> #include <linux/atmel_tc.h> +#include <linux/sched_clock.h> /*
@@ -56,11 +57,16 @@ static u64 tc_get_cycles(struct clocksource *cs)return (upper <<16 ) | lower; } -static u64 tc_get_cycles32 (struct clocksource *cs) +static u32 tc_get_cv32 (void ) {return __raw_readl (tcaddr +ATMEL_TC_REG (0 ,CV )); } +static u64 tc_get_cycles32 (struct clocksource *cs) +{ +return tc_get_cv32 (); +} +static struct clocksource clksrc = { .name ="tcb_clksrc" , .rating =200 ,
@@ -69,6 +75,11 @@ static struct clocksource clksrc = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; +static u64 notrace tc_read_sched_clock(void) +{ +return tc_get_cv32 (); +} +#ifdef CONFIG_GENERIC_CLOCKEVENTS struct tc_clkevt_device {
@@ -339,6 +350,9 @@ static int __init tcb_clksrc_init(void) clksrc.read = tc_get_cycles32;/* setup ony channel 0 */ tcb_setup_single_chan (tc, best_divisor_idx); + +/* register sched_clock on chips with single 32 bit counter */ +sched_clock_register (tc_read_sched_clock,32 , divided_rate); }else {/* tclib will give us three clocks no matter what the * underlying platform supports.
drivers/clocksource/timer-gemini.c new file +277 -0
277 lines not on this page · raw message
fs/proc/base.c +2 -2
@@ -2179,7 +2179,7 @@ static const struct file_operations proc_map_files_operations = { .llseek = generic_file_llseek, }; -#ifdef CONFIG_CHECKPOINT_RESTORE +#if defined(CONFIG_CHECKPOINT_RESTORE) && defined(CONFIG_POSIX_TIMERS) struct timers_private { struct pid *pid; struct task_struct *task;
@@ -2936,7 +2936,7 @@ static const struct pid_entry tgid_base_stuff[] = { REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations),#endif -#ifdef CONFIG_CHECKPOINT_RESTORE +#if defined(CONFIG_CHECKPOINT_RESTORE ) && defined(CONFIG_POSIX_TIMERS )REG ("timers" ,S_IRUGO , proc_timers_operations), #endif REG("timerslack_ns", S_IRUGO|S_IWUGO, proc_pid_set_timerslack_ns_operations),
fs/timerfd.c +14 -3
@@ -40,6 +40,7 @@ struct timerfd_ctx {short unsigned settime_flags;/* to show in fdinfo */ struct rcu_head rcu;struct list_head clist; +spinlock_t cancel_lock;bool might_cancel; };
@@ -112,7 +113,7 @@ void timerfd_clock_was_set(void)rcu_read_unlock (); } -static void timerfd_remove_cancel (struct timerfd_ctx *ctx) +static void __timerfd_remove_cancel (struct timerfd_ctx *ctx) {if (ctx->might_cancel) { ctx->might_cancel = false;
@@ -122,6 +123,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx) } } +static void timerfd_remove_cancel (struct timerfd_ctx *ctx) +{ +spin_lock (&ctx->cancel_lock); +__timerfd_remove_cancel (ctx); +spin_unlock (&ctx->cancel_lock); +} +static bool timerfd_canceled (struct timerfd_ctx *ctx) {if (!ctx->might_cancel || ctx->moffs !=KTIME_MAX )
@@ -132,6 +140,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx)static void timerfd_setup_cancel (struct timerfd_ctx *ctx,int flags) { +spin_lock (&ctx->cancel_lock);if ((ctx->clockid ==CLOCK_REALTIME || ctx->clockid ==CLOCK_REALTIME_ALARM ) && (flags &TFD_TIMER_ABSTIME ) && (flags &TFD_TIMER_CANCEL_ON_SET )) {
@@ -141,9 +150,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)list_add_rcu (&ctx->clist, &cancel_list);spin_unlock (&cancel_lock); } - }else if (ctx->might_cancel) { -timerfd_remove_cancel (ctx); + }else { +__timerfd_remove_cancel (ctx); } +spin_unlock (&ctx->cancel_lock); }static ktime_t timerfd_get_remaining (struct timerfd_ctx *ctx)
@@ -400,6 +410,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)return -ENOMEM ;init_waitqueue_head (&ctx->wqh); +spin_lock_init (&ctx->cancel_lock); ctx->clockid = clockid;if (isalarm (ctx))
include/linux/clockchips.h +9 -0
@@ -224,4 +224,13 @@ static inline void tick_setup_hrtimer_broadcast(void) { }#endif /* !CONFIG_GENERIC_CLOCKEVENTS */ +#define CLOCKEVENT_OF_DECLARE (name, compat, fn) \ + OF_DECLARE_1_RET(clkevt, name, compat, fn) + +#ifdef CONFIG_CLKEVT_PROBE +extern int clockevent_probe (void ); +#els +static inline int clockevent_probe (void ) {return 0 ; } +#endif +#endif /* _LINUX_CLOCKCHIPS_H */
include/linux/cpumask.h +6 -1
@@ -649,11 +649,15 @@ static inline size_t cpumask_size(void)* used. Please use this_cpu_cpumask_var_t in those cases. The direct use * of this_cpu_ptr() or this_cpu_read() will lead to failures when the * other type of cpumask_var_t implementation is configured. +* +* Please also note that __cpumask_var_read_mostly can be used to declare +* a cpumask_var_t variable itself (not its content) as read mostly. */ #ifdef CONFIG_CPUMASK_OFFSTACK typedef struct cpumask *cpumask_var_t ; -#define this_cpu_cpumask_var_ptr (x) this_cpu_read(x) +#define this_cpu_cpumask_var_ptr (x) this_cpu_read(x) +#define __cpumask_var_read_mostly __read_mostlybool alloc_cpumask_var_node (cpumask_var_t *mask,gfp_t flags,int node);bool alloc_cpumask_var (cpumask_var_t *mask,gfp_t flags);
@@ -667,6 +671,7 @@ void free_bootmem_cpumask_var(cpumask_var_t mask);typedef struct cpumask cpumask_var_t [1 ];#define this_cpu_cpumask_var_ptr (x) this_cpu_ptr(x) +#define __cpumask_var_read_mostlystatic inline bool alloc_cpumask_var (cpumask_var_t *mask,gfp_t flags) {
include/linux/delay.h +11 -0
@@ -5,6 +5,17 @@* Copyright (C) 1993 Linus Torvalds * * Delay routines, using a pre-computed "loops_per_jiffy" value. +* +* Please note that ndelay(), udelay() and mdelay() may return early for +* several reasons: +* 1. computed loops_per_jiffy too low (due to the time taken to +* execute the timer interrupt.) +* 2. cache behaviour affecting the time it takes to execute the +* loop function. +* 3. CPU clock rate changes. +* +* Please see this thread: +* http://lists.openwall.net/linux-kernel/2011/01/09/56 */ #include <linux/kernel.h>
include/linux/hrtimer.h +0 -11
@@ -88,12 +88,6 @@ enum hrtimer_restart {* @base: pointer to the timer base (per cpu and per clock) * @state: state information (See bit values above) * @is_rel: Set if the timer was armed relative -* @start_pid: timer statistics field to store the pid of the task which -* started the timer -* @start_site: timer statistics field to store the site where the timer -* was started -* @start_comm: timer statistics field to store the name of the process which -* started the timer * * The hrtimer structure must be initialized by hrtimer_init() */
@@ -104,11 +98,6 @@ struct hrtimer {struct hrtimer_clock_base *base;u8 state;u8 is_rel; -#ifdef CONFIG_TIMER_STATS -int start_pid; -void *start_site; -char start_comm[16 ]; -#endif };/**
include/linux/init_task.h +25 -15
@@ -42,6 +42,27 @@ extern struct fs_struct init_fs;#define INIT_PREV_CPUTIME (x)#endif +#ifdef CONFIG_POSIX_TIMERS +#define INIT_POSIX_TIMERS (s) \ + .posix_timers = LIST_HEAD_INIT(s.posix_timers), +#define INIT_CPU_TIMERS (s) \ + .cpu_timers = { \ + LIST_HEAD_INIT(s.cpu_timers[0]), \ + LIST_HEAD_INIT(s.cpu_timers[1]), \ + LIST_HEAD_INIT(s.cpu_timers[2]), \ + }, +#define INIT_CPUTIMER (s) \ + .cputimer = { \ + .cputime_atomic = INIT_CPUTIME_ATOMIC, \ + .running = false, \ + .checking_timer = false, \ + }, +#else +#define INIT_POSIX_TIMERS (s) +#define INIT_CPU_TIMERS (s) +#define INIT_CPUTIMER (s) +#endif +#define INIT_SIGNALS (sig) { \ .nr_threads = 1, \ .thread_head = LIST_HEAD_INIT(init_task.thread_node), \
@@ -49,14 +70,10 @@ extern struct fs_struct init_fs; .shared_pending = { \ .list = LIST_HEAD_INIT(sig.shared_pending.list), \ .signal = {{0}}}, \ - .posix_timers = LIST_HEAD_INIT(sig.posix_timers), \ - .cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \ + INIT_POSIX_TIMERS(sig) \ + INIT_CPU_TIMERS(sig) \ .rlim = INIT_RLIMITS, \ - .cputimer = { \ - .cputime_atomic = INIT_CPUTIME_ATOMIC, \ - .running = false, \ - .checking_timer = false, \ - }, \ + INIT_CPUTIMER(sig) \ INIT_PREV_CPUTIME(sig) \ .cred_guard_mutex = \ __MUTEX_INITIALIZER(sig.cred_guard_mutex), \
@@ -247,7 +264,7 @@ extern struct task_group root_task_group; .blocked = {{0}}, \ .alloc_lock = __SPIN_LOCK_UNLOCKED(tsk.alloc_lock), \ .journal_info =NULL , \ - .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ +INIT_CPU_TIMERS (tsk) \ .pi_lock =__RAW_SPIN_LOCK_UNLOCKED (tsk.pi_lock), \ .timer_slack_ns = 50000, /* 50 usec default slack */ \ .pids = { \
@@ -274,13 +291,6 @@ extern struct task_group root_task_group; } -#define INIT_CPU_TIMERS (cpu_timers) \ -{ \ - LIST_HEAD_INIT(cpu_timers[0]), \ - LIST_HEAD_INIT(cpu_timers[1]), \ - LIST_HEAD_INIT(cpu_timers[2]), \ -} -/* Attach to the init_task data structure for proper alignment */ #define __init_task_data __attribute__((__section__(".data..init_task")))
include/linux/math64.h +18 -8
@@ -133,6 +133,16 @@ __iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)return ret; } +#ifndef mul_u32_u32 +/* +* Many a GCC version messes this up and generates a 64x64 mult :-( +*/ +static inline u64 mul_u32_u32 (u32 a,u32 b) +{ +return (u64 )a * b; +} +#endif +#if defined(CONFIG_ARCH_SUPPORTS_INT128 ) && defined(__SIZEOF_INT128__)#ifndef mul_u64_u32_shr
@@ -160,9 +170,9 @@ static inline u64 mul_u64_u32_shr(u64 a, u32 mul, unsigned int shift) al = a; ah = a >>32 ; - ret = ((u64 )al * mul) >> shift; + ret =mul_u32_u32 (al, mul) >> shift;if (ah) - ret += ((u64 )ah * mul) << (32 - shift); + ret +=mul_u32_u32 (ah, mul) << (32 - shift);return ret; }
@@ -186,10 +196,10 @@ static inline u64 mul_u64_u64_shr(u64 a, u64 b, unsigned int shift) a0.ll = a; b0.ll = b; - rl.ll = (u64 )a0.l.low * b0.l.low; - rm.ll = (u64 )a0.l.low * b0.l.high; - rn.ll = (u64 )a0.l.high * b0.l.low; - rh.ll = (u64 )a0.l.high * b0.l.high; + rl.ll =mul_u32_u32 (a0.l.low, b0.l.low); + rm.ll =mul_u32_u32 (a0.l.low, b0.l.high); + rn.ll =mul_u32_u32 (a0.l.high, b0.l.low); + rh.ll =mul_u32_u32 (a0.l.high, b0.l.high);/* * Each of these lines computes a 64-bit intermediate result into "c",
@@ -229,8 +239,8 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) } u, rl, rh; u.ll = a; - rl.ll = (u64 )u.l.low * mul; - rh.ll = (u64 )u.l.high * mul + rl.l.high; + rl.ll =mul_u32_u32 (u.l.low, mul); + rh.ll =mul_u32_u32 (u.l.high, mul) + rl.l.high;/* Bits 32-63 of the result will be in rh.l.low. */ rl.l.high =do_div (rh.ll, divisor);
include/linux/sched.h +10 -3
@@ -734,13 +734,14 @@ struct signal_struct { unsigned int is_child_subreaper:1; unsigned int has_child_subreaper:1; +#ifdef CONFIG_POSIX_TIMERS +/* POSIX.1b Interval Timers */ int posix_timer_id;struct list_head posix_timers;/* ITIMER_REAL timer for the process */ struct hrtimer real_timer; -struct pid *leader_pid;ktime_t it_real_incr;/*
@@ -759,12 +760,16 @@ struct signal_struct {/* Earliest-expiration cache. */ struct task_cputime cputime_expires; +struct list_head cpu_timers[3 ]; + +#endif + +struct pid *leader_pid; +#ifdef CONFIG_NO_HZ_FULL atomic_t tick_dep_mask;#endif -struct list_head cpu_timers[3 ]; -struct pid *tty_old_pgrp;/* boolean value for session group leader */
@@ -1691,8 +1696,10 @@ struct task_struct {/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ unsigned long min_flt, maj_flt; +#ifdef CONFIG_POSIX_TIMERS struct task_cputime cputime_expires;struct list_head cpu_timers[3 ]; +#endif /* process credentials */ const struct cred __rcu *ptracer_cred;/* Tracer's credentials at attach */
include/linux/timer.h +0 -45
57 lines not on this page · raw message
kernel/fork.c +9 -1
@@ -1304,6 +1304,7 @@ void __cleanup_sighand(struct sighand_struct *sighand) } } +#ifdef CONFIG_POSIX_TIMERS /* * Initialize POSIX timer handling for a thread group. */
@@ -1322,6 +1323,9 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig)INIT_LIST_HEAD (&sig->cpu_timers[1 ]); INIT_LIST_HEAD(&sig->cpu_timers[2]); } +#else +static inline void posix_cpu_timers_init_group (struct signal_struct *sig) { } +#endif static int copy_signal (unsigned long clone_flags,struct task_struct *tsk) {
@@ -1346,11 +1350,11 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)init_waitqueue_head (&sig->wait_chldexit); sig->curr_target = tsk;init_sigpending (&sig->shared_pending); -INIT_LIST_HEAD (&sig->posix_timers);seqlock_init (&sig->stats_lock);prev_cputime_init (&sig->prev_cputime);#ifdef CONFIG_POSIX_TIMERS +INIT_LIST_HEAD (&sig->posix_timers);hrtimer_init (&sig->real_timer,CLOCK_MONOTONIC ,HRTIMER_MODE_REL ); sig->real_timer.function = it_real_fn;#endif
@@ -1425,6 +1429,7 @@ static void rt_mutex_init_task(struct task_struct *p)#endif } +#ifdef CONFIG_POSIX_TIMERS /* * Initialize POSIX timer handling for a single task. */
@@ -1437,6 +1442,9 @@ static void posix_cpu_timers_init(struct task_struct *tsk)INIT_LIST_HEAD (&tsk->cpu_timers[1 ]); INIT_LIST_HEAD(&tsk->cpu_timers[2]); } +#else +static inline void posix_cpu_timers_init (struct task_struct *tsk) { } +#endif static inline void init_task_pid (struct task_struct *task,enum pid_type type,struct pid *pid)
kernel/kthread.c +0 -1
@@ -850,7 +850,6 @@ void __kthread_queue_delayed_work(struct kthread_worker *worker,list_add (&work->node, &worker->delayed_work_list); work->worker = worker; -timer_stats_timer_set_start_info (&dwork->timer); timer->expires = jiffies + delay;add_timer (timer); }
kernel/sched/rt.c +4 -0
@@ -2246,6 +2246,7 @@ prio_changed_rt(struct rq *rq, struct task_struct *p, int oldprio) } } +#ifdef CONFIG_POSIX_TIMERS static void watchdog (struct rq *rq,struct task_struct *p) {unsigned long soft, hard;
@@ -2267,6 +2268,9 @@ static void watchdog(struct rq *rq, struct task_struct *p) p->cputime_expires.sched_exp = p->se.sum_exec_runtime; } } +#else +static inline void watchdog (struct rq *rq,struct task_struct *p) { } +#endif static void task_tick_rt (struct rq *rq,struct task_struct *p,int queued) {
kernel/sched/stats.h +20 -12
@@ -172,18 +172,19 @@ sched_info_switch(struct rq *rq,*/ /** -* cputimer_running - return true if cputimer is running +* get_running_cputimer - return &tsk->signal->cputimer if cputimer is running * * @tsk: Pointer to target task. */ -static inline bool cputimer_running (struct task_struct *tsk) - +#ifdef CONFIG_POSIX_TIMERS +static inline +struct thread_group_cputimer *get_running_cputimer (struct task_struct *tsk) {struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;/* Check if cputimer isn't running. This is accessed without locking. */ if (!READ_ONCE (cputimer->running)) -return false; +return NULL ;/* * After we flush the task's sum_exec_runtime to sig->sum_sched_runtime
@@ -200,10 +201,17 @@ static inline bool cputimer_running(struct task_struct *tsk)* clock delta is behind the expiring timer value. */ if (unlikely (!tsk->sighand)) -return false; +return NULL ; -return true; + return cputimer; +} +#else +static inline +struct thread_group_cputimer *get_running_cputimer (struct task_struct *tsk) +{ +return NULL ; } +#endif /** * account_group_user_time - Maintain utime for a thread group.
@@ -218,9 +226,9 @@ static inline bool cputimer_running(struct task_struct *tsk)static inline void account_group_user_time (struct task_struct *tsk,cputime_t cputime) { -struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; +struct thread_group_cputimer *cputimer =get_running_cputimer (tsk); -if (!cputimer_running (tsk)) +if (!cputimer)return ;atomic64_add (cputime, &cputimer->cputime_atomic.utime);
@@ -239,9 +247,9 @@ static inline void account_group_user_time(struct task_struct *tsk,static inline void account_group_system_time (struct task_struct *tsk,cputime_t cputime) { -struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; +struct thread_group_cputimer *cputimer =get_running_cputimer (tsk); -if (!cputimer_running (tsk)) +if (!cputimer)return ;atomic64_add (cputime, &cputimer->cputime_atomic.stime);
@@ -260,9 +268,9 @@ static inline void account_group_system_time(struct task_struct *tsk,static inline void account_group_exec_runtime (struct task_struct *tsk,unsigned long long ns) { -struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; +struct thread_group_cputimer *cputimer =get_running_cputimer (tsk); -if (!cputimer_running (tsk)) +if (!cputimer)return ;atomic64_add (ns, &cputimer->cputime_atomic.sum_exec_runtime);
kernel/time/Makefile +0 -1
@@ -15,6 +15,5 @@ ifeq ($(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST),y) endif obj-$(CONFIG_GENERIC_SCHED_CLOCK) += sched_clock.o obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o tick-sched.o -obj-$(CONFIG_TIMER_STATS) += timer_stats.o obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o obj-$(CONFIG_TEST_UDELAY) += test_udelay.o
kernel/time/hrtimer.c +15 -43
106 lines not on this page · raw message
kernel/time/tick-broadcast.c +8 -7
@@ -29,12 +29,13 @@*/ static struct tick_device tick_broadcast_device; -static cpumask_var_t tick_broadcast_mask; -static cpumask_var_t tick_broadcast_on; -static cpumask_var_t tmpmask; -static DEFINE_RAW_SPINLOCK (tick_broadcast_lock); +static cpumask_var_t tick_broadcast_mask __cpumask_var_read_mostly; +static cpumask_var_t tick_broadcast_on __cpumask_var_read_mostly; +static cpumask_var_t tmpmask __cpumask_var_read_mostly;static int tick_broadcast_forced; +static __cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK (tick_broadcast_lock ); +#ifdef CONFIG_TICK_ONESHOT static void tick_broadcast_clear_oneshot (int cpu);static void tick_resume_broadcast_oneshot (struct clock_event_device *bc);
@@ -517,9 +518,9 @@ void tick_resume_broadcast(void)#ifdef CONFIG_TICK_ONESHOT -static cpumask_var_t tick_broadcast_oneshot_mask; -static cpumask_var_t tick_broadcast_pending_mask; -static cpumask_var_t tick_broadcast_force_mask; +static cpumask_var_t tick_broadcast_oneshot_mask __cpumask_var_read_mostly; +static cpumask_var_t tick_broadcast_pending_mask __cpumask_var_read_mostly; +static cpumask_var_t tick_broadcast_force_mask __cpumask_var_read_mostly;/* * Exposed for debugging: see timer_list.c
kernel/time/timekeeping.c +1 -38
@@ -1275,27 +1275,8 @@ int timekeeping_inject_offset(struct timespec *ts) }EXPORT_SYMBOL (timekeeping_inject_offset); - -/** -* timekeeping_get_tai_offset - Returns current TAI offset from UTC -* -*/ -s32 timekeeping_get_tai_offset (void ) -{ -struct timekeeper *tk = &tk_core.timekeeper; -unsigned int seq; -s32 ret; - -do { - seq =read_seqcount_begin (&tk_core.seq); - ret = tk->tai_offset; - }while (read_seqcount_retry (&tk_core.seq, seq)); - -return ret; -} -/** -* __timekeeping_set_tai_offset - Lock free worker function +* __timekeeping_set_tai_offset - Sets the TAI offset from UTC and monotonic * */ static void __timekeeping_set_tai_offset (struct timekeeper *tk,s32 tai_offset)
@@ -1305,24 +1286,6 @@ static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) }/** -* timekeeping_set_tai_offset - Sets the current TAI offset from UTC -* -*/ -void timekeeping_set_tai_offset (s32 tai_offset) -{ -struct timekeeper *tk = &tk_core.timekeeper; -unsigned long flags; - -raw_spin_lock_irqsave (&timekeeper_lock, flags); -write_seqcount_begin (&tk_core.seq); -__timekeeping_set_tai_offset (tk, tai_offset); -timekeeping_update (tk,TK_MIRROR |TK_CLOCK_WAS_SET ); -write_seqcount_end (&tk_core.seq); -raw_spin_unlock_irqrestore (&timekeeper_lock, flags); -clock_was_set (); -} - -/** * change_clocksource - Swaps clocksources if a new one is available * * Accumulates current time interval and initializes new clocksource
kernel/time/timekeeping.h +0 -2
@@ -11,8 +11,6 @@ extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq,extern int timekeeping_valid_for_hres (void );extern u64 timekeeping_max_deferment (void );extern int timekeeping_inject_offset (struct timespec *ts); -extern s32 timekeeping_get_tai_offset (void ); -extern void timekeeping_set_tai_offset (s32 tai_offset);extern int timekeeping_suspend (void );extern void timekeeping_resume (void );
kernel/time/timer.c +2 -46
97 lines not on this page · raw message
kernel/time/timer_list.c +1 -11
@@ -62,21 +62,11 @@ static void print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer, int idx, u64 now) { -#ifdef CONFIG_TIMER_STATS - char tmp[TASK_COMM_LEN + 1]; -#endif SEQ_printf(m, " #%d: ", idx);print_name_offset (m, taddr);SEQ_printf (m,", " );print_name_offset (m, timer->function);SEQ_printf (m,", S:%02x" , timer->state); -#ifdef CONFIG_TIMER_STATS -SEQ_printf (m,", " ); -print_name_offset (m, timer->start_site); -memcpy (tmp, timer->start_comm,TASK_COMM_LEN ); - tmp[TASK_COMM_LEN ] =0 ; -SEQ_printf (m,", %s/%d" , tmp, timer->start_pid); -#endif SEQ_printf (m,"\n" ); SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs]\n", (unsigned long long)ktime_to_ns(hrtimer_get_softexpires(timer)),
@@ -127,7 +117,7 @@ print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)SEQ_printf (m," .base: %pK\n" , base);SEQ_printf (m," .index: %d\n" , base->index); -SEQ_printf (m," .resolution: %u nsecs\n" , (unsigned ) hrtimer_resolution); +SEQ_printf (m," .resolution: %u nsecs\n" , hrtimer_resolution);SEQ_printf (m," .get_time: " );print_name_offset (m, base->get_time);
kernel/time/timer_stats.c deleted +0 -425
425 lines not on this page · raw message
kernel/workqueue.c +0 -2
@@ -1523,8 +1523,6 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq,return ; } -timer_stats_timer_set_start_info (&dwork->timer); - dwork->wq = wq; dwork->cpu = cpu; timer->expires = jiffies + delay;
lib/Kconfig.debug +0 -14
@@ -980,20 +980,6 @@ config DEBUG_TIMEKEEPING If unsure, say N. -config TIMER_STATS - bool "Collect kernel timers statistics" - depends on DEBUG_KERNEL && PROC_FS - help - If you say Y here, additional code will be inserted into the - timer routines to collect statistics about kernel timers being - reprogrammed. The statistics can be read from /proc/timer_stats. - The statistics collection is started by writing 1 to /proc/timer_stats, - writing 0 stops it. This feature is useful to collect information - about timer usage patterns in kernel and userspace. This feature - is lightweight if enabled in the kernel config but not activated - (it defaults to deactivated on bootup and will only be activated - if some application like powertop activates it explicitly). - config DEBUG_PREEMPT bool "Debug preemptible kernel" depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
lib/timerqueue.c +1 -2
@@ -80,8 +80,7 @@ bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node)if (head->next == node) {struct rb_node *rbn =rb_next (&node->node); - head->next = rbn ? - rb_entry(rbn, struct timerqueue_node, node) : NULL; + head->next = rb_entry_safe(rbn, struct timerqueue_node, node); }rb_erase (&node->node, &head->head);RB_CLEAR_NODE (&node->node);