diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 16:14:51 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 16:14:51 -0700 |
commit | 1b044f1cfc65a7d90b209dfabd57e16d98b58c5b (patch) | |
tree | ad657c911b563f9176b17578c0b88a1ea9916a02 | |
parent | e0f3e8f14da868047c524a0cf11e08b95fd1b008 (diff) | |
parent | 2287d8664fe7345ead891017eccd879fc605305e (diff) | |
download | op-kernel-dev-1b044f1cfc65a7d90b209dfabd57e16d98b58c5b.zip op-kernel-dev-1b044f1cfc65a7d90b209dfabd57e16d98b58c5b.tar.gz |
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates from Thomas Gleixner:
"A rather large update for timers/timekeeping:
- compat syscall consolidation (Al Viro)
- Posix timer consolidation (Christoph Helwig / Thomas Gleixner)
- Cleanup of the device tree based initialization for clockevents and
clocksources (Daniel Lezcano)
- Consolidation of the FTTMR010 clocksource/event driver (Linus
Walleij)
- The usual set of small fixes and updates all over the place"
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (93 commits)
timers: Make the cpu base lock raw
clocksource/drivers/mips-gic-timer: Fix an error code in 'gic_clocksource_of_init()'
clocksource/drivers/fsl_ftm_timer: Unmap region obtained by of_iomap
clocksource/drivers/tcb_clksrc: Make IO endian agnostic
clocksource/drivers/sun4i: Switch to the timer-of common init
clocksource/drivers/timer-of: Fix invalid iomap check
Revert "ktime: Simplify ktime_compare implementation"
clocksource/drivers: Fix uninitialized variable use in timer_of_init
kselftests: timers: Add test for frequency step
kselftests: timers: Fix inconsistency-check to not ignore first timestamp
time: Add warning about imminent deprecation of CONFIG_GENERIC_TIME_VSYSCALL_OLD
time: Clean up CLOCK_MONOTONIC_RAW time handling
posix-cpu-timers: Make timespec to nsec conversion safe
itimer: Make timeval to nsec conversion range limited
timers: Fix parameter description of try_to_del_timer_sync()
ktime: Simplify ktime_compare implementation
clocksource/drivers/fttmr010: Factor out clock read code
clocksource/drivers/fttmr010: Implement delay timer
clocksource/drivers: Add timer-of common init routine
clocksource/drivers/tcb_clksrc: Save timer context on suspend/resume
...
175 files changed, 2498 insertions, 3166 deletions
diff --git a/Documentation/devicetree/bindings/timer/faraday,fttmr010.txt b/Documentation/devicetree/bindings/timer/faraday,fttmr010.txt index b73ca6c..1957922 100644 --- a/Documentation/devicetree/bindings/timer/faraday,fttmr010.txt +++ b/Documentation/devicetree/bindings/timer/faraday,fttmr010.txt @@ -7,7 +7,11 @@ Required properties: - compatible : Must be one of "faraday,fttmr010" - "cortina,gemini-timer" + "cortina,gemini-timer", "faraday,fttmr010" + "moxa,moxart-timer", "faraday,fttmr010" + "aspeed,ast2400-timer" + "aspeed,ast2500-timer" + - reg : Should contain registers location and length - interrupts : Should contain the three timer interrupts usually with flags for falling edge diff --git a/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt b/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt deleted file mode 100644 index e207c11..0000000 --- a/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt +++ /dev/null @@ -1,19 +0,0 @@ -MOXA ART timer - -Required properties: - -- compatible : Must be one of: - - "moxa,moxart-timer" - - "aspeed,ast2400-timer" -- reg : Should contain registers location and length -- interrupts : Should contain the timer interrupt number -- clocks : Should contain phandle for the clock that drives the counter - -Example: - - timer: timer@98400000 { - compatible = "moxa,moxart-timer"; - reg = <0x98400000 0x42>; - interrupts = <19 1>; - clocks = <&coreclk>; - }; diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild index 7bee4e4..3e74ca5 100644 --- a/arch/arc/include/asm/Kbuild +++ b/arch/arc/include/asm/Kbuild @@ -36,7 +36,6 @@ generic-y += preempt.h generic-y += resource.h generic-y += sembuf.h generic-y += shmbuf.h -generic-y += siginfo.h generic-y += socket.h generic-y += sockios.h generic-y += stat.h diff --git a/arch/arc/include/uapi/asm/Kbuild b/arch/arc/include/uapi/asm/Kbuild index b15bf6b..b55fc2a 100644 --- a/arch/arc/include/uapi/asm/Kbuild +++ b/arch/arc/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index fc8211f..666613f 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -470,7 +470,7 @@ void __init setup_arch(char **cmdline_p) void __init time_init(void) { of_clk_init(NULL); - clocksource_probe(); + timer_probe(); } static int __init customize_machine(void) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6491be5..6281c3e 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -337,7 +337,7 @@ config ARCH_MULTIPLATFORM select ARM_HAS_SG_CHAIN select ARM_PATCH_PHYS_VIRT select AUTO_ZRELADDR - select CLKSRC_OF + select TIMER_OF select COMMON_CLK select GENERIC_CLOCKEVENTS select MIGHT_HAVE_PCI @@ -351,7 +351,7 @@ config ARM_SINGLE_ARMV7M depends on !MMU select ARM_NVIC select AUTO_ZRELADDR - select CLKSRC_OF + select TIMER_OF select COMMON_CLK select CPU_V7M select GENERIC_CLOCKEVENTS @@ -532,7 +532,7 @@ config ARCH_PXA select CLKDEV_LOOKUP select CLKSRC_PXA select CLKSRC_MMIO - select CLKSRC_OF + select TIMER_OF select CPU_XSCALE if !CPU_XSC3 select GENERIC_CLOCKEVENTS select GPIO_PXA @@ -571,7 +571,7 @@ config ARCH_SA1100 select CLKDEV_LOOKUP select CLKSRC_MMIO select CLKSRC_PXA - select CLKSRC_OF if OF + select TIMER_OF if OF select CPU_FREQ select CPU_SA1100 select GENERIC_CLOCKEVENTS @@ -1357,7 +1357,7 @@ config HAVE_ARM_ARCH_TIMER config HAVE_ARM_TWD bool - select CLKSRC_OF if OF + select TIMER_OF if OF help This options enables support for the ARM timer and watchdog unit diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi index 8c6bc29..3e74929 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi @@ -893,6 +893,7 @@ //interrupts = <16 17 18 35 36 37 38 39>; interrupts = <16>; clocks = <&clk_apb>; + clock-names = "PCLK"; }; wdt1: wdt@1e785000 { diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index a0bea4a..1e6c701 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -1000,6 +1000,7 @@ //interrupts = <16 17 18 35 36 37 38 39>; interrupts = <16>; clocks = <&clk_apb>; + clock-names = "PCLK"; }; diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index 3a36d99..d836050 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -28,7 +28,6 @@ generic-y += segment.h generic-y += sembuf.h generic-y += serial.h generic-y += shmbuf.h -generic-y += siginfo.h generic-y += simd.h generic-y += sizes.h generic-y += socket.h diff --git a/arch/arm/include/uapi/asm/Kbuild b/arch/arm/include/uapi/asm/Kbuild index 607f702..e9b098d 100644 --- a/arch/arm/include/uapi/asm/Kbuild +++ b/arch/arm/include/uapi/asm/Kbuild @@ -4,3 +4,5 @@ include include/uapi/asm-generic/Kbuild.asm genhdr-y += unistd-common.h genhdr-y += unistd-oabi.h genhdr-y += unistd-eabi.h + +generic-y += siginfo.h diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 895ae51..b30eafe 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -403,7 +403,7 @@ out: WARN(err, "twd_local_timer_of_register failed (%d)\n", err); return err; } -CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); -CLOCKSOURCE_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); -CLOCKSOURCE_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); +TIMER_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); +TIMER_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); +TIMER_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); #endif diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 97b22fa..629f8e9 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -120,6 +120,6 @@ void __init time_init(void) #ifdef CONFIG_COMMON_CLK of_clk_init(NULL); #endif - clocksource_probe(); + timer_probe(); } } diff --git a/arch/arm/mach-aspeed/Kconfig b/arch/arm/mach-aspeed/Kconfig index f3f8c5c..2d5570e 100644 --- a/arch/arm/mach-aspeed/Kconfig +++ b/arch/arm/mach-aspeed/Kconfig @@ -4,7 +4,7 @@ menuconfig ARCH_ASPEED select SRAM select WATCHDOG select ASPEED_WATCHDOG - select MOXART_TIMER + select FTTMR010_TIMER select MFD_SYSCON select PINCTRL help diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index f9389c5..f23a239 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -150,7 +150,7 @@ config ARCH_BCM2835 select ARM_ERRATA_411920 if ARCH_MULTI_V6 select ARM_TIMER_SP804 select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 - select CLKSRC_OF + select TIMER_OF select BCM2835_TIMER select PINCTRL select PINCTRL_BCM2835 diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig index 61284b9..f385b1f 100644 --- a/arch/arm/mach-clps711x/Kconfig +++ b/arch/arm/mach-clps711x/Kconfig @@ -2,7 +2,7 @@ menuconfig ARCH_CLPS711X bool "Cirrus Logic EP721x/EP731x-based" depends on ARCH_MULTI_V4T select AUTO_ZRELADDR - select CLKSRC_OF + select TIMER_OF select CLPS711X_TIMER select COMMON_CLK select CPU_ARM720T diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c index a6e3c98..c3cf215 100644 --- a/arch/arm/mach-mediatek/mediatek.c +++ b/arch/arm/mach-mediatek/mediatek.c @@ -41,7 +41,7 @@ static void __init mediatek_timer_init(void) } of_clk_init(NULL); - clocksource_probe(); + timer_probe(); }; static const char * const mediatek_board_dt_compat[] = { diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig index 70db2ab..a4a91f9 100644 --- a/arch/arm/mach-moxart/Kconfig +++ b/arch/arm/mach-moxart/Kconfig @@ -4,7 +4,7 @@ menuconfig ARCH_MOXART select CPU_FA526 select ARM_DMA_MEM_BUFFERABLE select FARADAY_FTINTC010 - select MOXART_TIMER + select FTTMR010_TIMER select GPIOLIB select PHYLIB if NETDEVICES help diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 07dd692..ae4bb9f 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -497,7 +497,7 @@ void __init omap_init_time(void) __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon", 2, "timer_sys_ck", NULL, false); - clocksource_probe(); + timer_probe(); } #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX) @@ -506,7 +506,7 @@ void __init omap3_secure_sync32k_timer_init(void) __omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure", 2, "timer_sys_ck", NULL, false); - clocksource_probe(); + timer_probe(); } #endif /* CONFIG_ARCH_OMAP3 */ @@ -517,7 +517,7 @@ void __init omap3_gptimer_timer_init(void) __omap_sync32k_timer_init(2, "timer_sys_ck", NULL, 1, "timer_sys_ck", "ti,timer-alwon", true); if (of_have_populated_dt()) - clocksource_probe(); + timer_probe(); } #endif @@ -532,7 +532,7 @@ static void __init omap4_sync32k_timer_init(void) void __init omap4_local_timer_init(void) { omap4_sync32k_timer_init(); - clocksource_probe(); + timer_probe(); } #endif @@ -656,7 +656,7 @@ void __init omap5_realtime_timer_init(void) omap4_sync32k_timer_init(); realtime_counter_init(); - clocksource_probe(); + timer_probe(); } #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c index ef0500a..5ab834e 100644 --- a/arch/arm/mach-rockchip/rockchip.c +++ b/arch/arm/mach-rockchip/rockchip.c @@ -55,7 +55,7 @@ static void __init rockchip_timer_init(void) } of_clk_init(NULL); - clocksource_probe(); + timer_probe(); } static void __init rockchip_dt_init(void) diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig index 4b1690a..f07da82 100644 --- a/arch/arm/mach-s3c24xx/Kconfig +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -394,7 +394,7 @@ config MACH_SMDK2416 config MACH_S3C2416_DT bool "Samsung S3C2416 machine using devicetree" - select CLKSRC_OF + select TIMER_OF select USE_OF select PINCTRL select PINCTRL_S3C24XX diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 459214f..71a4934 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -336,7 +336,7 @@ config MACH_WLF_CRAGG_6410 config MACH_S3C64XX_DT bool "Samsung S3C6400/S3C6410 machine using Device Tree" - select CLKSRC_OF + select TIMER_OF select CPU_S3C6400 select CPU_S3C6410 select PINCTRL diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c index 52d466b..a6e74f4 100644 --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -113,7 +113,7 @@ void __init rcar_gen2_timer_init(void) #endif /* CONFIG_ARM_ARCH_TIMER */ of_clk_init(NULL); - clocksource_probe(); + timer_probe(); } struct memory_reserve_config { diff --git a/arch/arm/mach-spear/spear13xx.c b/arch/arm/mach-spear/spear13xx.c index ca2f6a8..31c43ca 100644 --- a/arch/arm/mach-spear/spear13xx.c +++ b/arch/arm/mach-spear/spear13xx.c @@ -124,5 +124,5 @@ void __init spear13xx_timer_init(void) clk_put(pclk); spear_setup_of_timer(); - clocksource_probe(); + timer_probe(); } diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c index f44e3ac..7ab353f 100644 --- a/arch/arm/mach-sunxi/sunxi.c +++ b/arch/arm/mach-sunxi/sunxi.c @@ -42,7 +42,7 @@ static void __init sun6i_timer_init(void) of_clk_init(NULL); if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) sun6i_reset_init(); - clocksource_probe(); + timer_probe(); } DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index a4910ea..048f15e 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -407,7 +407,7 @@ static const char * u300_board_compat[] = { DT_MACHINE_START(U300_DT, "U300 S335/B335 (Device Tree)") .map_io = u300_map_io, .init_irq = u300_init_irq_dt, - .init_time = clocksource_probe, + .init_time = timer_probe, .init_machine = u300_init_machine_dt, .restart = u300_restart, .dt_compat = u300_board_compat, diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index ed11864..6aba9eb 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -150,7 +150,7 @@ static void __init zynq_timer_init(void) { zynq_clock_init(); of_clk_init(NULL); - clocksource_probe(); + timer_probe(); } static struct map_desc zynq_cortex_a9_scu_map __initdata = { diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 73272f4..9ed0a65 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -18,7 +18,7 @@ config ARCH_ALPINE config ARCH_BCM2835 bool "Broadcom BCM2835 family" - select CLKSRC_OF + select TIMER_OF select GPIOLIB select PINCTRL select PINCTRL_BCM2835 @@ -178,7 +178,7 @@ config ARCH_TEGRA select ARCH_HAS_RESET_CONTROLLER select CLKDEV_LOOKUP select CLKSRC_MMIO - select CLKSRC_OF + select TIMER_OF select GENERIC_CLOCKEVENTS select GPIOLIB select PINCTRL diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index 5977969..da33c90 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -70,7 +70,7 @@ void __init time_init(void) u32 arch_timer_rate; of_clk_init(NULL); - clocksource_probe(); + timer_probe(); tick_setup_hrtimer_broadcast(); diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index d0cb007..7492d90 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -220,10 +220,8 @@ void update_vsyscall(struct timekeeper *tk) if (!use_syscall) { /* tkr_mono.cycle_last == tkr_raw.cycle_last */ vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; - vdso_data->raw_time_sec = tk->raw_time.tv_sec; - vdso_data->raw_time_nsec = (tk->raw_time.tv_nsec << - tk->tkr_raw.shift) + - tk->tkr_raw.xtime_nsec; + vdso_data->raw_time_sec = tk->raw_sec; + vdso_data->raw_time_nsec = tk->tkr_raw.xtime_nsec; vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; vdso_data->cs_mono_mult = tk->tkr_mono.mult; diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild index f0eaf047..a3c8d05 100644 --- a/arch/c6x/include/asm/Kbuild +++ b/arch/c6x/include/asm/Kbuild @@ -45,7 +45,6 @@ generic-y += sembuf.h generic-y += serial.h generic-y += shmbuf.h generic-y += shmparam.h -generic-y += siginfo.h generic-y += signal.h generic-y += socket.h generic-y += sockios.h diff --git a/arch/c6x/include/uapi/asm/Kbuild b/arch/c6x/include/uapi/asm/Kbuild index 13a97aa..1c44d3b 100644 --- a/arch/c6x/include/uapi/asm/Kbuild +++ b/arch/c6x/include/uapi/asm/Kbuild @@ -2,3 +2,4 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += kvm_para.h +generic-y += siginfo.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 2890099..acc5781 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -36,7 +36,6 @@ generic-y += resource.h generic-y += sections.h generic-y += sembuf.h generic-y += shmbuf.h -generic-y += siginfo.h generic-y += socket.h generic-y += sockios.h generic-y += statfs.h diff --git a/arch/cris/include/uapi/asm/Kbuild b/arch/cris/include/uapi/asm/Kbuild index b15bf6b..b55fc2a 100644 --- a/arch/cris/include/uapi/asm/Kbuild +++ b/arch/cris/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 3ae8525..6e3d36f 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -15,7 +15,7 @@ config H8300 select OF_IRQ select OF_EARLY_FLATTREE select HAVE_MEMBLOCK - select CLKSRC_OF + select TIMER_OF select H8300_TMR8 select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZO diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild index 757cdeb..99c8246 100644 --- a/arch/h8300/include/asm/Kbuild +++ b/arch/h8300/include/asm/Kbuild @@ -54,7 +54,6 @@ generic-y += serial.h generic-y += setup.h generic-y += shmbuf.h generic-y += shmparam.h -generic-y += siginfo.h generic-y += sizes.h generic-y += socket.h generic-y += sockios.h diff --git a/arch/h8300/include/uapi/asm/Kbuild b/arch/h8300/include/uapi/asm/Kbuild index b15bf6b..b55fc2a 100644 --- a/arch/h8300/include/uapi/asm/Kbuild +++ b/arch/h8300/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c index c8c25a4..6be15d6 100644 --- a/arch/h8300/kernel/setup.c +++ b/arch/h8300/kernel/setup.c @@ -246,5 +246,5 @@ void __init calibrate_delay(void) void __init time_init(void) { of_clk_init(NULL); - clocksource_probe(); + timer_probe(); } diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild index 6b45ef7..0fc9cb0 100644 --- a/arch/hexagon/include/asm/Kbuild +++ b/arch/hexagon/include/asm/Kbuild @@ -41,7 +41,6 @@ generic-y += sembuf.h generic-y += serial.h generic-y += shmbuf.h generic-y += shmparam.h -generic-y += siginfo.h generic-y += sizes.h generic-y += socket.h generic-y += sockios.h diff --git a/arch/hexagon/include/uapi/asm/Kbuild b/arch/hexagon/include/uapi/asm/Kbuild index b15bf6b..b55fc2a 100644 --- a/arch/hexagon/include/uapi/asm/Kbuild +++ b/arch/hexagon/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/ia64/include/asm/siginfo.h b/arch/ia64/include/asm/siginfo.h deleted file mode 100644 index 6f2e2dd..0000000 --- a/arch/ia64/include/asm/siginfo.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Based on <asm-i386/siginfo.h>. - * - * Modified 1998-2002 - * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co - */ -#ifndef _ASM_IA64_SIGINFO_H -#define _ASM_IA64_SIGINFO_H - -#include <linux/string.h> -#include <uapi/asm/siginfo.h> - -static inline void -copy_siginfo (siginfo_t *to, siginfo_t *from) -{ - if (from->si_code < 0) - memcpy(to, from, sizeof(siginfo_t)); - else - /* _sigchld is currently the largest know union member */ - memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld)); -} - -#endif /* _ASM_IA64_SIGINFO_H */ diff --git a/arch/ia64/include/uapi/asm/siginfo.h b/arch/ia64/include/uapi/asm/siginfo.h index f72bf01..4694c64 100644 --- a/arch/ia64/include/uapi/asm/siginfo.h +++ b/arch/ia64/include/uapi/asm/siginfo.h @@ -11,7 +11,6 @@ #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #define HAVE_ARCH_SIGINFO_T -#define HAVE_ARCH_COPY_SIGINFO #define HAVE_ARCH_COPY_SIGINFO_TO_USER #include <asm-generic/siginfo.h> diff --git a/arch/m32r/include/uapi/asm/Kbuild b/arch/m32r/include/uapi/asm/Kbuild index b15bf6b..c94ee54 100644 --- a/arch/m32r/include/uapi/asm/Kbuild +++ b/arch/m32r/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/m32r/include/uapi/asm/siginfo.h b/arch/m32r/include/uapi/asm/siginfo.h deleted file mode 100644 index 7d9cd9e..0000000 --- a/arch/m32r/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _M32R_SIGINFO_H -#define _M32R_SIGINFO_H - -#include <asm-generic/siginfo.h> - -#endif /* _M32R_SIGINFO_H */ diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild index 82005d2..5ecf4e4 100644 --- a/arch/m68k/include/asm/Kbuild +++ b/arch/m68k/include/asm/Kbuild @@ -25,7 +25,6 @@ generic-y += preempt.h generic-y += resource.h generic-y += sections.h generic-y += shmparam.h -generic-y += siginfo.h generic-y += spinlock.h generic-y += statfs.h generic-y += termios.h diff --git a/arch/m68k/include/uapi/asm/Kbuild b/arch/m68k/include/uapi/asm/Kbuild index 6436807..68b45cc 100644 --- a/arch/m68k/include/uapi/asm/Kbuild +++ b/arch/m68k/include/uapi/asm/Kbuild @@ -5,6 +5,7 @@ generic-y += auxvec.h generic-y += msgbuf.h generic-y += sembuf.h generic-y += shmbuf.h +generic-y += siginfo.h generic-y += socket.h generic-y += sockios.h generic-y += termbits.h diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 85885a5..8e47121 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -4,7 +4,7 @@ config MICROBLAZE select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_WANT_IPC_PARSE_VERSION select BUILDTIME_EXTABLE_SORT - select CLKSRC_OF + select TIMER_OF select CLONE_BACKWARDS3 select COMMON_CLK select GENERIC_ATOMIC64 diff --git a/arch/microblaze/include/uapi/asm/Kbuild b/arch/microblaze/include/uapi/asm/Kbuild index 2178c78..cb6784f 100644 --- a/arch/microblaze/include/uapi/asm/Kbuild +++ b/arch/microblaze/include/uapi/asm/Kbuild @@ -2,3 +2,4 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += types.h +generic-y += siginfo.h diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index f31ebb5..be98ffe 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -192,7 +192,7 @@ void __init time_init(void) { of_clk_init(NULL); setup_cpuinfo_clk(); - clocksource_probe(); + timer_probe(); } #ifdef CONFIG_DEBUG_FS diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 545ccd4..ea2d83f 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -335,5 +335,5 @@ static int __init xilinx_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", +TIMER_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", xilinx_timer_init); diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c index 4af6192..1231b5a 100644 --- a/arch/mips/generic/init.c +++ b/arch/mips/generic/init.c @@ -161,7 +161,7 @@ void __init plat_time_init(void) } } - clocksource_probe(); + timer_probe(); } void __init arch_init_irq(void) diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 289edcf..cea4ec9 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -265,7 +265,7 @@ void __init plat_time_init(void) (freq%1000000)*100/1000000); #ifdef CONFIG_CLKSRC_MIPS_GIC update_gic_frequency_dt(); - clocksource_probe(); + timer_probe(); #endif } #endif diff --git a/arch/mips/pic32/pic32mzda/time.c b/arch/mips/pic32/pic32mzda/time.c index 62a0a78..1894e50 100644 --- a/arch/mips/pic32/pic32mzda/time.c +++ b/arch/mips/pic32/pic32mzda/time.c @@ -64,5 +64,5 @@ void __init plat_time_init(void) pr_info("CPU Clock: %ldMHz\n", rate / 1000000); mips_hpt_frequency = rate / 2; - clocksource_probe(); + timer_probe(); } diff --git a/arch/mips/pistachio/time.c b/arch/mips/pistachio/time.c index 1022201..17a0f1d 100644 --- a/arch/mips/pistachio/time.c +++ b/arch/mips/pistachio/time.c @@ -39,7 +39,7 @@ void __init plat_time_init(void) struct clk *clk; of_clk_init(NULL); - clocksource_probe(); + timer_probe(); np = of_get_cpu_node(0, NULL); if (!np) { diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 9825dee..710b04c 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -4,7 +4,7 @@ config CLKEVT_RT3352 bool depends on SOC_RT305X || SOC_MT7620 default y - select CLKSRC_OF + select TIMER_OF select CLKSRC_MMIO config RALINK_ILL_ACC diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index b8a1376..92f284d 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -152,4 +152,4 @@ static int __init ralink_systick_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); +TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c index df79588..eb1c619 100644 --- a/arch/mips/ralink/clk.c +++ b/arch/mips/ralink/clk.c @@ -82,5 +82,5 @@ void __init plat_time_init(void) pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); mips_hpt_frequency = clk_get_rate(clk) / 2; clk_put(clk); - clocksource_probe(); + timer_probe(); } diff --git a/arch/mips/ralink/timer-gic.c b/arch/mips/ralink/timer-gic.c index 069771d..b5f07d2 100644 --- a/arch/mips/ralink/timer-gic.c +++ b/arch/mips/ralink/timer-gic.c @@ -20,5 +20,5 @@ void __init plat_time_init(void) ralink_of_remap(); of_clk_init(NULL); - clocksource_probe(); + timer_probe(); } diff --git a/arch/mips/xilfpga/time.c b/arch/mips/xilfpga/time.c index cbb3fca..36f3f18 100644 --- a/arch/mips/xilfpga/time.c +++ b/arch/mips/xilfpga/time.c @@ -22,7 +22,7 @@ void __init plat_time_init(void) struct clk *clk; of_clk_init(NULL); - clocksource_probe(); + timer_probe(); np = of_get_cpu_node(0, NULL); if (!np) { diff --git a/arch/mn10300/include/uapi/asm/Kbuild b/arch/mn10300/include/uapi/asm/Kbuild index b15bf6b..c94ee54 100644 --- a/arch/mn10300/include/uapi/asm/Kbuild +++ b/arch/mn10300/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/mn10300/include/uapi/asm/siginfo.h b/arch/mn10300/include/uapi/asm/siginfo.h deleted file mode 100644 index 0815d29..0000000 --- a/arch/mn10300/include/uapi/asm/siginfo.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/siginfo.h> diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig index a72d5f0..c587764 100644 --- a/arch/nios2/Kconfig +++ b/arch/nios2/Kconfig @@ -1,6 +1,6 @@ config NIOS2 def_bool y - select CLKSRC_OF + select TIMER_OF select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS select GENERIC_CPU_DEVICES diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild index 727dbb3..e1a843d 100644 --- a/arch/nios2/include/asm/Kbuild +++ b/arch/nios2/include/asm/Kbuild @@ -47,7 +47,6 @@ generic-y += segment.h generic-y += sembuf.h generic-y += serial.h generic-y += shmbuf.h -generic-y += siginfo.h generic-y += signal.h generic-y += socket.h generic-y += sockios.h diff --git a/arch/nios2/include/uapi/asm/Kbuild b/arch/nios2/include/uapi/asm/Kbuild index 374bd12..51eff5b 100644 --- a/arch/nios2/include/uapi/asm/Kbuild +++ b/arch/nios2/include/uapi/asm/Kbuild @@ -2,4 +2,5 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += setup.h +generic-y += siginfo.h generic-y += ucontext.h diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c index 6e2bdc9..645129a 100644 --- a/arch/nios2/kernel/time.c +++ b/arch/nios2/kernel/time.c @@ -350,7 +350,7 @@ void __init time_init(void) if (count < 2) panic("%d timer is found, it needs 2 timers in system\n", count); - clocksource_probe(); + timer_probe(); } -CLOCKSOURCE_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); +TIMER_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild index fdbcf0b..091585a 100644 --- a/arch/openrisc/include/asm/Kbuild +++ b/arch/openrisc/include/asm/Kbuild @@ -46,7 +46,6 @@ generic-y += sembuf.h generic-y += setup.h generic-y += shmbuf.h generic-y += shmparam.h -generic-y += siginfo.h generic-y += signal.h generic-y += socket.h generic-y += sockios.h diff --git a/arch/openrisc/include/uapi/asm/Kbuild b/arch/openrisc/include/uapi/asm/Kbuild index b15bf6b..b55fc2a 100644 --- a/arch/openrisc/include/uapi/asm/Kbuild +++ b/arch/openrisc/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/score/include/uapi/asm/Kbuild b/arch/score/include/uapi/asm/Kbuild index b15bf6b..c94ee54 100644 --- a/arch/score/include/uapi/asm/Kbuild +++ b/arch/score/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/score/include/uapi/asm/siginfo.h b/arch/score/include/uapi/asm/siginfo.h deleted file mode 100644 index 87ca356..0000000 --- a/arch/score/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_SCORE_SIGINFO_H -#define _ASM_SCORE_SIGINFO_H - -#include <asm-generic/siginfo.h> - -#endif /* _ASM_SCORE_SIGINFO_H */ diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index 4e21949..3554fca 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -10,7 +10,7 @@ config SH_DEVICE_TREE bool "Board Described by Device Tree" select OF select OF_EARLY_FLATTREE - select CLKSRC_OF + select TIMER_OF select COMMON_CLK select GENERIC_CALIBRATE_DELAY help diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c index 1fb6d57..4feb7c8 100644 --- a/arch/sh/boards/of-generic.c +++ b/arch/sh/boards/of-generic.c @@ -119,7 +119,7 @@ static void __init sh_of_mem_reserve(void) static void __init sh_of_time_init(void) { pr_info("SH generic board support: scanning for clocksource devices\n"); - clocksource_probe(); + timer_probe(); } static void __init sh_of_setup(char **cmdline_p) diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild index cf2a750..590c91a 100644 --- a/arch/sh/include/asm/Kbuild +++ b/arch/sh/include/asm/Kbuild @@ -29,7 +29,6 @@ generic-y += rwsem.h generic-y += sembuf.h generic-y += serial.h generic-y += shmbuf.h -generic-y += siginfo.h generic-y += sizes.h generic-y += socket.h generic-y += statfs.h diff --git a/arch/sh/include/uapi/asm/Kbuild b/arch/sh/include/uapi/asm/Kbuild index b15bf6b..b55fc2a 100644 --- a/arch/sh/include/uapi/asm/Kbuild +++ b/arch/sh/include/uapi/asm/Kbuild @@ -1,2 +1,4 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm + +generic-y += siginfo.h diff --git a/arch/sparc/include/asm/siginfo.h b/arch/sparc/include/asm/siginfo.h deleted file mode 100644 index 48c34c1..0000000 --- a/arch/sparc/include/asm/siginfo.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __SPARC_SIGINFO_H -#define __SPARC_SIGINFO_H - -#include <uapi/asm/siginfo.h> - - -#ifdef CONFIG_COMPAT - -struct compat_siginfo; - -#endif /* CONFIG_COMPAT */ - -#endif /* !(__SPARC_SIGINFO_H) */ diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild index e9ad511..7a53a55 100644 --- a/arch/unicore32/include/asm/Kbuild +++ b/arch/unicore32/include/asm/Kbuild @@ -44,7 +44,6 @@ generic-y += serial.h generic-y += setup.h generic-y += shmbuf.h generic-y += shmparam.h -generic-y += siginfo.h generic-y += signal.h generic-y += sizes.h generic-y += socket.h diff --git a/arch/unicore32/include/uapi/asm/Kbuild b/arch/unicore32/include/uapi/asm/Kbuild index 13a97aa..1c44d3b 100644 --- a/arch/unicore32/include/uapi/asm/Kbuild +++ b/arch/unicore32/include/uapi/asm/Kbuild @@ -2,3 +2,4 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += kvm_para.h +generic-y += siginfo.h diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild index cc23e9e..30f62901 100644 --- a/arch/xtensa/include/asm/Kbuild +++ b/arch/xtensa/include/asm/Kbuild @@ -25,7 +25,6 @@ generic-y += preempt.h generic-y += resource.h generic-y += rwsem.h generic-y += sections.h -generic-y += siginfo.h generic-y += statfs.h generic-y += termios.h generic-y += topology.h diff --git a/arch/xtensa/include/uapi/asm/Kbuild b/arch/xtensa/include/uapi/asm/Kbuild index b15bf6b..4cb0d2f 100644 --- a/arch/xtensa/include/uapi/asm/Kbuild +++ b/arch/xtensa/include/uapi/asm/Kbuild @@ -1,2 +1,3 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm +generic-y += siginfo.h diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 668c105..fd524a5 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c @@ -187,7 +187,7 @@ void __init time_init(void) local_timer_setup(0); setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction); sched_clock_register(ccount_sched_clock_read, 32, ccount_freq); - clocksource_probe(); + timer_probe(); } /* diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 31adbeb..2af7001 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -539,15 +539,6 @@ config HANGCHECK_TIMER out to lunch past a certain margin. It can reboot the system or merely print a warning. -config MMTIMER - tristate "MMTIMER Memory mapped RTC for SGI Altix" - depends on IA64_GENERIC || IA64_SGI_SN2 - depends on POSIX_TIMERS - default y - help - The mmtimer device allows direct userspace access to the - Altix system timer. - config UV_MMTIMER tristate "UV_MMTIMER Memory mapped RTC for SGI UV" depends on X86_UV diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 6e6c244..53e3372 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MSPEC) += mspec.o -obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o obj-$(CONFIG_IBM_BSR) += bsr.o obj-$(CONFIG_SGI_MBCS) += mbcs.o diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c deleted file mode 100644 index 0e7fcb0..0000000 --- a/drivers/char/mmtimer.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Timer device implementation for SGI SN platforms. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2001-2006 Silicon Graphics, Inc. All rights reserved. - * - * This driver exports an API that should be supportable by any HPET or IA-PC - * multimedia timer. The code below is currently specific to the SGI Altix - * SHub RTC, however. - * - * 11/01/01 - jbarnes - initial revision - * 9/10/04 - Christoph Lameter - remove interrupt support for kernel inclusion - * 10/1/04 - Christoph Lameter - provide posix clock CLOCK_SGI_CYCLE - * 10/13/04 - Christoph Lameter, Dimitri Sivanich - provide timer interrupt - * support via the posix timer interface - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/ioctl.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/fs.h> -#include <linux/mmtimer.h> -#include <linux/miscdevice.h> -#include <linux/posix-timers.h> -#include <linux/interrupt.h> -#include <linux/time.h> -#include <linux/math64.h> -#include <linux/mutex.h> -#include <linux/slab.h> - -#include <linux/uaccess.h> -#include <asm/sn/addrs.h> -#include <asm/sn/intr.h> -#include <asm/sn/shub_mmr.h> -#include <asm/sn/nodepda.h> -#include <asm/sn/shubio.h> - -MODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>"); -MODULE_DESCRIPTION("SGI Altix RTC Timer"); -MODULE_LICENSE("GPL"); - -/* name of the device, usually in /dev */ -#define MMTIMER_NAME "mmtimer" -#define MMTIMER_DESC "SGI Altix RTC Timer" -#define MMTIMER_VERSION "2.1" - -#define RTC_BITS 55 /* 55 bits for this implementation */ - -static struct k_clock sgi_clock; - -extern unsigned long sn_rtc_cycles_per_second; - -#define RTC_COUNTER_ADDR ((long *)LOCAL_MMR_ADDR(SH_RTC)) - -#define rtc_time() (*RTC_COUNTER_ADDR) - -static DEFINE_MUTEX(mmtimer_mutex); -static long mmtimer_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); -static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma); - -/* - * Period in femtoseconds (10^-15 s) - */ -static unsigned long mmtimer_femtoperiod = 0; - -static const struct file_operations mmtimer_fops = { - .owner = THIS_MODULE, - .mmap = mmtimer_mmap, - .unlocked_ioctl = mmtimer_ioctl, - .llseek = noop_llseek, -}; - -/* - * We only have comparison registers RTC1-4 currently available per - * node. RTC0 is used by SAL. - */ -/* Check for an RTC interrupt pending */ -static int mmtimer_int_pending(int comparator) -{ - if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) & - SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator) - return 1; - else - return 0; -} - -/* Clear the RTC interrupt pending bit */ -static void mmtimer_clr_int_pending(int comparator) -{ - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), - SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator); -} - -/* Setup timer on comparator RTC1 */ -static void mmtimer_setup_int_0(int cpu, u64 expires) -{ - u64 val; - - /* Disable interrupt */ - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), 0UL); - - /* Initialize comparator value */ - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPB), -1L); - - /* Clear pending bit */ - mmtimer_clr_int_pending(0); - - val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC1_INT_CONFIG_IDX_SHFT) | - ((u64)cpu_physical_id(cpu) << - SH_RTC1_INT_CONFIG_PID_SHFT); - - /* Set configuration */ - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_CONFIG), val); - - /* Enable RTC interrupts */ - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), 1UL); - - /* Initialize comparator value */ - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPB), expires); - - -} - -/* Setup timer on comparator RTC2 */ -static void mmtimer_setup_int_1(int cpu, u64 expires) -{ - u64 val; - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), 0UL); - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPC), -1L); - - mmtimer_clr_int_pending(1); - - val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC2_INT_CONFIG_IDX_SHFT) | - ((u64)cpu_physical_id(cpu) << - SH_RTC2_INT_CONFIG_PID_SHFT); - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_CONFIG), val); - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), 1UL); - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPC), expires); -} - -/* Setup timer on comparator RTC3 */ -static void mmtimer_setup_int_2(int cpu, u64 expires) -{ - u64 val; - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), 0UL); - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPD), -1L); - - mmtimer_clr_int_pending(2); - - val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC3_INT_CONFIG_IDX_SHFT) | - ((u64)cpu_physical_id(cpu) << - SH_RTC3_INT_CONFIG_PID_SHFT); - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_CONFIG), val); - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), 1UL); - - HUB_S((u64 *)LOCAL_MMR_ADDR(SH_INT_CMPD), expires); -} - -/* - * This function must be called with interrupts disabled and preemption off - * in order to insure that the setup succeeds in a deterministic time frame. - * It will check if the interrupt setup succeeded. - */ -static int mmtimer_setup(int cpu, int comparator, unsigned long expires, - u64 *set_completion_time) -{ - switch (comparator) { - case 0: - mmtimer_setup_int_0(cpu, expires); - break; - case 1: - mmtimer_setup_int_1(cpu, expires); - break; - case 2: - mmtimer_setup_int_2(cpu, expires); - break; - } - /* We might've missed our expiration time */ - *set_completion_time = rtc_time(); - if (*set_completion_time <= expires) - return 1; - - /* - * If an interrupt is already pending then its okay - * if not then we failed - */ - return mmtimer_int_pending(comparator); -} - -static int mmtimer_disable_int(long nasid, int comparator) -{ - switch (comparator) { - case 0: - nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC1_INT_ENABLE), - 0UL) : REMOTE_HUB_S(nasid, SH_RTC1_INT_ENABLE, 0UL); - break; - case 1: - nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_ENABLE), - 0UL) : REMOTE_HUB_S(nasid, SH_RTC2_INT_ENABLE, 0UL); - break; - case 2: - nasid == -1 ? HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_ENABLE), - 0UL) : REMOTE_HUB_S(nasid, SH_RTC3_INT_ENABLE, 0UL); - break; - default: - return -EFAULT; - } - return 0; -} - -#define COMPARATOR 1 /* The comparator to use */ - -#define TIMER_OFF 0xbadcabLL /* Timer is not setup */ -#define TIMER_SET 0 /* Comparator is set for this timer */ - -#define MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT 40 - -/* There is one of these for each timer */ -struct mmtimer { - struct rb_node list; - struct k_itimer *timer; - int cpu; -}; - -struct mmtimer_node { - spinlock_t lock ____cacheline_aligned; - struct rb_root timer_head; - struct rb_node *next; - struct tasklet_struct tasklet; -}; -static struct mmtimer_node *timers; - -static unsigned mmtimer_interval_retry_increment = - MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT; -module_param(mmtimer_interval_retry_increment, uint, 0644); -MODULE_PARM_DESC(mmtimer_interval_retry_increment, - "RTC ticks to add to expiration on interval retry (default 40)"); - -/* - * Add a new mmtimer struct to the node's mmtimer list. - * This function assumes the struct mmtimer_node is locked. - */ -static void mmtimer_add_list(struct mmtimer *n) -{ - int nodeid = n->timer->it.mmtimer.node; - unsigned long expires = n->timer->it.mmtimer.expires; - struct rb_node **link = &timers[nodeid].timer_head.rb_node; - struct rb_node *parent = NULL; - struct mmtimer *x; - - /* - * Find the right place in the rbtree: - */ - while (*link) { - parent = *link; - x = rb_entry(parent, struct mmtimer, list); - - if (expires < x->timer->it.mmtimer.expires) - link = &(*link)->rb_left; - else - link = &(*link)->rb_right; - } - - /* - * Insert the timer to the rbtree and check whether it - * replaces the first pending timer - */ - rb_link_node(&n->list, parent, link); - rb_insert_color(&n->list, &timers[nodeid].timer_head); - - if (!timers[nodeid].next || expires < rb_entry(timers[nodeid].next, - struct mmtimer, list)->timer->it.mmtimer.expires) - timers[nodeid].next = &n->list; -} - -/* - * Set the comparator for the next timer. - * This function assumes the struct mmtimer_node is locked. - */ -static void mmtimer_set_next_timer(int nodeid) -{ - struct mmtimer_node *n = &timers[nodeid]; - struct mmtimer *x; - struct k_itimer *t; - u64 expires, exp, set_completion_time; - int i; - -restart: - if (n->next == NULL) - return; - - x = rb_entry(n->next, struct mmtimer, list); - t = x->timer; - if (!t->it.mmtimer.incr) { - /* Not an interval timer */ - if (!mmtimer_setup(x->cpu, COMPARATOR, - t->it.mmtimer.expires, - &set_completion_time)) { - /* Late setup, fire now */ - tasklet_schedule(&n->tasklet); - } - return; - } - - /* Interval timer */ - i = 0; - expires = exp = t->it.mmtimer.expires; - while (!mmtimer_setup(x->cpu, COMPARATOR, expires, - &set_completion_time)) { - int to; - - i++; - expires = set_completion_time + - mmtimer_interval_retry_increment + (1 << i); - /* Calculate overruns as we go. */ - to = ((u64)(expires - exp) / t->it.mmtimer.incr); - if (to) { - t->it_overrun += to; - t->it.mmtimer.expires += t->it.mmtimer.incr * to; - exp = t->it.mmtimer.expires; - } - if (i > 20) { - printk(KERN_ALERT "mmtimer: cannot reschedule timer\n"); - t->it.mmtimer.clock = TIMER_OFF; - n->next = rb_next(&x->list); - rb_erase(&x->list, &n->timer_head); - kfree(x); - goto restart; - } - } -} - -/** - * mmtimer_ioctl - ioctl interface for /dev/mmtimer - * @file: file structure for the device - * @cmd: command to execute - * @arg: optional argument to command - * - * Executes the command specified by @cmd. Returns 0 for success, < 0 for - * failure. - * - * Valid commands: - * - * %MMTIMER_GETOFFSET - Should return the offset (relative to the start - * of the page where the registers are mapped) for the counter in question. - * - * %MMTIMER_GETRES - Returns the resolution of the clock in femto (10^-15) - * seconds - * - * %MMTIMER_GETFREQ - Copies the frequency of the clock in Hz to the address - * specified by @arg - * - * %MMTIMER_GETBITS - Returns the number of bits in the clock's counter - * - * %MMTIMER_MMAPAVAIL - Returns 1 if the registers can be mmap'd into userspace - * - * %MMTIMER_GETCOUNTER - Gets the current value in the counter and places it - * in the address specified by @arg. - */ -static long mmtimer_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret = 0; - - mutex_lock(&mmtimer_mutex); - - switch (cmd) { - case MMTIMER_GETOFFSET: /* offset of the counter */ - /* - * SN RTC registers are on their own 64k page - */ - if(PAGE_SIZE <= (1 << 16)) - ret = (((long)RTC_COUNTER_ADDR) & (PAGE_SIZE-1)) / 8; - else - ret = -ENOSYS; - break; - - case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */ - if(copy_to_user((unsigned long __user *)arg, - &mmtimer_femtoperiod, sizeof(unsigned long))) - ret = -EFAULT; - break; - - case MMTIMER_GETFREQ: /* frequency in Hz */ - if(copy_to_user((unsigned long __user *)arg, - &sn_rtc_cycles_per_second, - sizeof(unsigned long))) - ret = -EFAULT; - break; - - case MMTIMER_GETBITS: /* number of bits in the clock */ - ret = RTC_BITS; - break; - - case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */ - ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0; - break; - - case MMTIMER_GETCOUNTER: - if(copy_to_user((unsigned long __user *)arg, - RTC_COUNTER_ADDR, sizeof(unsigned long))) - ret = -EFAULT; - break; - default: - ret = -ENOTTY; - break; - } - mutex_unlock(&mmtimer_mutex); - return ret; -} - -/** - * mmtimer_mmap - maps the clock's registers into userspace - * @file: file structure for the device - * @vma: VMA to map the registers into - * - * Calls remap_pfn_range() to map the clock's registers into - * the calling process' address space. - */ -static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned long mmtimer_addr; - - if (vma->vm_end - vma->vm_start != PAGE_SIZE) - return -EINVAL; - - if (vma->vm_flags & VM_WRITE) - return -EPERM; - - if (PAGE_SIZE > (1 << 16)) - return -ENOSYS; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - mmtimer_addr = __pa(RTC_COUNTER_ADDR); - mmtimer_addr &= ~(PAGE_SIZE - 1); - mmtimer_addr &= 0xfffffffffffffffUL; - - if (remap_pfn_range(vma, vma->vm_start, mmtimer_addr >> PAGE_SHIFT, - PAGE_SIZE, vma->vm_page_prot)) { - printk(KERN_ERR "remap_pfn_range failed in mmtimer.c\n"); - return -EAGAIN; - } - - return 0; -} - -static struct miscdevice mmtimer_miscdev = { - .minor = SGI_MMTIMER, - .name = MMTIMER_NAME, - .fops = &mmtimer_fops -}; - -static struct timespec sgi_clock_offset; -static int sgi_clock_period; - -/* - * Posix Timer Interface - */ - -static struct timespec sgi_clock_offset; -static int sgi_clock_period; - -static int sgi_clock_get(clockid_t clockid, struct timespec64 *tp) -{ - u64 nsec; - - nsec = rtc_time() * sgi_clock_period - + sgi_clock_offset.tv_nsec; - *tp = ns_to_timespec64(nsec); - tp->tv_sec += sgi_clock_offset.tv_sec; - return 0; -}; - -static int sgi_clock_set(const clockid_t clockid, const struct timespec64 *tp) -{ - - u64 nsec; - u32 rem; - - nsec = rtc_time() * sgi_clock_period; - - sgi_clock_offset.tv_sec = tp->tv_sec - div_u64_rem(nsec, NSEC_PER_SEC, &rem); - - if (rem <= tp->tv_nsec) - sgi_clock_offset.tv_nsec = tp->tv_sec - rem; - else { - sgi_clock_offset.tv_nsec = tp->tv_sec + NSEC_PER_SEC - rem; - sgi_clock_offset.tv_sec--; - } - return 0; -} - -/** - * mmtimer_interrupt - timer interrupt handler - * @irq: irq received - * @dev_id: device the irq came from - * - * Called when one of the comarators matches the counter, This - * routine will send signals to processes that have requested - * them. - * - * This interrupt is run in an interrupt context - * by the SHUB. It is therefore safe to locally access SHub - * registers. - */ -static irqreturn_t -mmtimer_interrupt(int irq, void *dev_id) -{ - unsigned long expires = 0; - int result = IRQ_NONE; - unsigned indx = cpu_to_node(smp_processor_id()); - struct mmtimer *base; - - spin_lock(&timers[indx].lock); - base = rb_entry(timers[indx].next, struct mmtimer, list); - if (base == NULL) { - spin_unlock(&timers[indx].lock); - return result; - } - - if (base->cpu == smp_processor_id()) { - if (base->timer) - expires = base->timer->it.mmtimer.expires; - /* expires test won't work with shared irqs */ - if ((mmtimer_int_pending(COMPARATOR) > 0) || - (expires && (expires <= rtc_time()))) { - mmtimer_clr_int_pending(COMPARATOR); - tasklet_schedule(&timers[indx].tasklet); - result = IRQ_HANDLED; - } - } - spin_unlock(&timers[indx].lock); - return result; -} - -static void mmtimer_tasklet(unsigned long data) -{ - int nodeid = data; - struct mmtimer_node *mn = &timers[nodeid]; - struct mmtimer *x; - struct k_itimer *t; - unsigned long flags; - - /* Send signal and deal with periodic signals */ - spin_lock_irqsave(&mn->lock, flags); - if (!mn->next) - goto out; - - x = rb_entry(mn->next, struct mmtimer, list); - t = x->timer; - - if (t->it.mmtimer.clock == TIMER_OFF) - goto out; - - t->it_overrun = 0; - - mn->next = rb_next(&x->list); - rb_erase(&x->list, &mn->timer_head); - - if (posix_timer_event(t, 0) != 0) - t->it_overrun++; - - if(t->it.mmtimer.incr) { - t->it.mmtimer.expires += t->it.mmtimer.incr; - mmtimer_add_list(x); - } else { - /* Ensure we don't false trigger in mmtimer_interrupt */ - t->it.mmtimer.clock = TIMER_OFF; - t->it.mmtimer.expires = 0; - kfree(x); - } - /* Set comparator for next timer, if there is one */ - mmtimer_set_next_timer(nodeid); - - t->it_overrun_last = t->it_overrun; -out: - spin_unlock_irqrestore(&mn->lock, flags); -} - -static int sgi_timer_create(struct k_itimer *timer) -{ - /* Insure that a newly created timer is off */ - timer->it.mmtimer.clock = TIMER_OFF; - return 0; -} - -/* This does not really delete a timer. It just insures - * that the timer is not active - * - * Assumption: it_lock is already held with irq's disabled - */ -static int sgi_timer_del(struct k_itimer *timr) -{ - cnodeid_t nodeid = timr->it.mmtimer.node; - unsigned long irqflags; - - spin_lock_irqsave(&timers[nodeid].lock, irqflags); - if (timr->it.mmtimer.clock != TIMER_OFF) { - unsigned long expires = timr->it.mmtimer.expires; - struct rb_node *n = timers[nodeid].timer_head.rb_node; - struct mmtimer *uninitialized_var(t); - int r = 0; - - timr->it.mmtimer.clock = TIMER_OFF; - timr->it.mmtimer.expires = 0; - - while (n) { - t = rb_entry(n, struct mmtimer, list); - if (t->timer == timr) - break; - - if (expires < t->timer->it.mmtimer.expires) - n = n->rb_left; - else - n = n->rb_right; - } - - if (!n) { - spin_unlock_irqrestore(&timers[nodeid].lock, irqflags); - return 0; - } - - if (timers[nodeid].next == n) { - timers[nodeid].next = rb_next(n); - r = 1; - } - - rb_erase(n, &timers[nodeid].timer_head); - kfree(t); - - if (r) { - mmtimer_disable_int(cnodeid_to_nasid(nodeid), - COMPARATOR); - mmtimer_set_next_timer(nodeid); - } - } - spin_unlock_irqrestore(&timers[nodeid].lock, irqflags); - return 0; -} - -/* Assumption: it_lock is already held with irq's disabled */ -static void sgi_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) -{ - - if (timr->it.mmtimer.clock == TIMER_OFF) { - cur_setting->it_interval.tv_nsec = 0; - cur_setting->it_interval.tv_sec = 0; - cur_setting->it_value.tv_nsec = 0; - cur_setting->it_value.tv_sec =0; - return; - } - - cur_setting->it_interval = ns_to_timespec64(timr->it.mmtimer.incr * sgi_clock_period); - cur_setting->it_value = ns_to_timespec64((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period); -} - - -static int sgi_timer_set(struct k_itimer *timr, int flags, - struct itimerspec64 *new_setting, - struct itimerspec64 *old_setting) -{ - unsigned long when, period, irqflags; - int err = 0; - cnodeid_t nodeid; - struct mmtimer *base; - struct rb_node *n; - - if (old_setting) - sgi_timer_get(timr, old_setting); - - sgi_timer_del(timr); - when = timespec64_to_ns(&new_setting->it_value); - period = timespec64_to_ns(&new_setting->it_interval); - - if (when == 0) - /* Clear timer */ - return 0; - - base = kmalloc(sizeof(struct mmtimer), GFP_KERNEL); - if (base == NULL) - return -ENOMEM; - - if (flags & TIMER_ABSTIME) { - struct timespec64 n; - unsigned long now; - - getnstimeofday64(&n); - now = timespec64_to_ns(&n); - if (when > now) - when -= now; - else - /* Fire the timer immediately */ - when = 0; - } - - /* - * Convert to sgi clock period. Need to keep rtc_time() as near as possible - * to getnstimeofday() in order to be as faithful as possible to the time - * specified. - */ - when = (when + sgi_clock_period - 1) / sgi_clock_period + rtc_time(); - period = (period + sgi_clock_period - 1) / sgi_clock_period; - - /* - * We are allocating a local SHub comparator. If we would be moved to another - * cpu then another SHub may be local to us. Prohibit that by switching off - * preemption. - */ - preempt_disable(); - - nodeid = cpu_to_node(smp_processor_id()); - - /* Lock the node timer structure */ - spin_lock_irqsave(&timers[nodeid].lock, irqflags); - - base->timer = timr; - base->cpu = smp_processor_id(); - - timr->it.mmtimer.clock = TIMER_SET; - timr->it.mmtimer.node = nodeid; - timr->it.mmtimer.incr = period; - timr->it.mmtimer.expires = when; - - n = timers[nodeid].next; - - /* Add the new struct mmtimer to node's timer list */ - mmtimer_add_list(base); - - if (timers[nodeid].next == n) { - /* No need to reprogram comparator for now */ - spin_unlock_irqrestore(&timers[nodeid].lock, irqflags); - preempt_enable(); - return err; - } - - /* We need to reprogram the comparator */ - if (n) - mmtimer_disable_int(cnodeid_to_nasid(nodeid), COMPARATOR); - - mmtimer_set_next_timer(nodeid); - - /* Unlock the node timer structure */ - spin_unlock_irqrestore(&timers[nodeid].lock, irqflags); - - preempt_enable(); - - return err; -} - -static int sgi_clock_getres(const clockid_t which_clock, struct timespec64 *tp) -{ - tp->tv_sec = 0; - tp->tv_nsec = sgi_clock_period; - return 0; -} - -static struct k_clock sgi_clock = { - .clock_set = sgi_clock_set, - .clock_get = sgi_clock_get, - .clock_getres = sgi_clock_getres, - .timer_create = sgi_timer_create, - .timer_set = sgi_timer_set, - .timer_del = sgi_timer_del, - .timer_get = sgi_timer_get -}; - -/** - * mmtimer_init - device initialization routine - * - * Does initial setup for the mmtimer device. - */ -static int __init mmtimer_init(void) -{ - cnodeid_t node, maxn = -1; - - if (!ia64_platform_is("sn2")) - return 0; - - /* - * Sanity check the cycles/sec variable - */ - if (sn_rtc_cycles_per_second < 100000) { - printk(KERN_ERR "%s: unable to determine clock frequency\n", - MMTIMER_NAME); - goto out1; - } - - mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / - 2) / sn_rtc_cycles_per_second; - - if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, IRQF_PERCPU, MMTIMER_NAME, NULL)) { - printk(KERN_WARNING "%s: unable to allocate interrupt.", - MMTIMER_NAME); - goto out1; - } - - if (misc_register(&mmtimer_miscdev)) { - printk(KERN_ERR "%s: failed to register device\n", - MMTIMER_NAME); - goto out2; - } - - /* Get max numbered node, calculate slots needed */ - for_each_online_node(node) { - maxn = node; - } - maxn++; - - /* Allocate list of node ptrs to mmtimer_t's */ - timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL); - if (!timers) { - printk(KERN_ERR "%s: failed to allocate memory for device\n", - MMTIMER_NAME); - goto out3; - } - - /* Initialize struct mmtimer's for each online node */ - for_each_online_node(node) { - spin_lock_init(&timers[node].lock); - tasklet_init(&timers[node].tasklet, mmtimer_tasklet, - (unsigned long) node); - } - - sgi_clock_period = NSEC_PER_SEC / sn_rtc_cycles_per_second; - posix_timers_register_clock(CLOCK_SGI_CYCLE, &sgi_clock); - - printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION, - sn_rtc_cycles_per_second/(unsigned long)1E6); - - return 0; - -out3: - misc_deregister(&mmtimer_miscdev); -out2: - free_irq(SGI_MMTIMER_VECTOR, NULL); -out1: - return -1; -} - -module_init(mmtimer_init); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 545d541..88818a4 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -1,22 +1,16 @@ menu "Clock Source drivers" depends on !ARCH_USES_GETTIMEOFFSET -config CLKSRC_OF +config TIMER_OF bool - select CLKSRC_PROBE - -config CLKEVT_OF - bool - select CLKEVT_PROBE - -config CLKSRC_ACPI - bool - select CLKSRC_PROBE + depends on GENERIC_CLOCKEVENTS + select TIMER_PROBE -config CLKSRC_PROBE +config TIMER_ACPI bool + select TIMER_PROBE -config CLKEVT_PROBE +config TIMER_PROBE bool config CLKSRC_I8253 @@ -65,14 +59,14 @@ config DW_APB_TIMER config DW_APB_TIMER_OF bool select DW_APB_TIMER - select CLKSRC_OF + select TIMER_OF config FTTMR010_TIMER bool "Faraday Technology timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS depends on HAS_IOMEM select CLKSRC_MMIO - select CLKSRC_OF + select TIMER_OF select MFD_SYSCON help Enables support for the Faraday Technology timer block @@ -81,7 +75,7 @@ config FTTMR010_TIMER config ROCKCHIP_TIMER bool "Rockchip timer driver" if COMPILE_TEST depends on ARM || ARM64 - select CLKSRC_OF + select TIMER_OF select CLKSRC_MMIO help Enables the support for the rockchip timer driver. @@ -89,7 +83,7 @@ config ROCKCHIP_TIMER config ARMADA_370_XP_TIMER bool "Armada 370 and XP timer driver" if COMPILE_TEST depends on ARM - select CLKSRC_OF + select TIMER_OF select CLKSRC_MMIO help Enables the support for the Armada 370 and XP timer driver. @@ -104,7 +98,7 @@ config MESON6_TIMER config ORION_TIMER bool "Orion timer driver" if COMPILE_TEST depends on ARM - select CLKSRC_OF + select TIMER_OF select CLKSRC_MMIO help Enables the support for the Orion timer driver @@ -114,6 +108,7 @@ config SUN4I_TIMER depends on GENERIC_CLOCKEVENTS depends on HAS_IOMEM select CLKSRC_MMIO + select TIMER_OF help Enables support for the Sun4i timer. @@ -148,7 +143,7 @@ config ASM9260_TIMER bool "ASM9260 timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS select CLKSRC_MMIO - select CLKSRC_OF + select TIMER_OF help Enables support for the ASM9260 timer. @@ -188,13 +183,6 @@ config ATLAS7_TIMER help Enables support for the Atlas7 timer. -config MOXART_TIMER - bool "Moxart timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables support for the Moxart timer. - config MXS_TIMER bool "Mxs timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS @@ -261,21 +249,21 @@ config CLKSRC_LPC32XX depends on GENERIC_CLOCKEVENTS && HAS_IOMEM depends on ARM select CLKSRC_MMIO - select CLKSRC_OF + select TIMER_OF help Support for the LPC32XX clocksource. config CLKSRC_PISTACHIO bool "Clocksource for Pistachio SoC" if COMPILE_TEST depends on HAS_IOMEM - select CLKSRC_OF + select TIMER_OF help Enables the clocksource for the Pistachio SoC. config CLKSRC_TI_32K bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST depends on GENERIC_SCHED_CLOCK - select CLKSRC_OF if OF + select TIMER_OF if OF help This option enables support for Texas Instruments 32.768 Hz clocksource available on many OMAP-like platforms. @@ -284,7 +272,7 @@ config CLKSRC_NPS bool "NPS400 clocksource driver" if COMPILE_TEST depends on !PHYS_ADDR_T_64BIT select CLKSRC_MMIO - select CLKSRC_OF if OF + select TIMER_OF if OF help NPS400 clocksource support. Got 64 bit counter with update rate up to 1000MHz. @@ -299,12 +287,12 @@ config CLKSRC_MPS2 bool "Clocksource for MPS2 SoCs" if COMPILE_TEST depends on GENERIC_SCHED_CLOCK select CLKSRC_MMIO - select CLKSRC_OF + select TIMER_OF config ARC_TIMERS bool "Support for 32-bit TIMERn counters in ARC Cores" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS - select CLKSRC_OF + select TIMER_OF help These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores (ARC700 as well as ARC HS38). @@ -314,7 +302,7 @@ config ARC_TIMERS_64BIT bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS depends on ARC_TIMERS - select CLKSRC_OF + select TIMER_OF help This enables 2 different 64-bit timers: RTC (for UP) and GFRC (for SMP) RTC is implemented inside the core, while GFRC sits outside the core in @@ -323,8 +311,8 @@ config ARC_TIMERS_64BIT config ARM_ARCH_TIMER bool - select CLKSRC_OF if OF - select CLKSRC_ACPI if ACPI + select TIMER_OF if OF + select TIMER_ACPI if ACPI config ARM_ARCH_TIMER_EVTSTREAM bool "Enable ARM architected timer event stream generation by default" @@ -381,7 +369,7 @@ config ARM64_ERRATUM_858921 config ARM_GLOBAL_TIMER bool "Support for the ARM global timer" if COMPILE_TEST - select CLKSRC_OF if OF + select TIMER_OF if OF depends on ARM help This options enables support for the ARM global timer unit @@ -390,7 +378,7 @@ config ARM_TIMER_SP804 bool "Support for Dual Timer SP804 module" depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP select CLKSRC_MMIO - select CLKSRC_OF if OF + select TIMER_OF if OF config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK bool @@ -401,19 +389,19 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK config ARMV7M_SYSTICK bool "Support for the ARMv7M system time" if COMPILE_TEST - select CLKSRC_OF if OF + select TIMER_OF if OF select CLKSRC_MMIO help This options enables support for the ARMv7M system timer unit config ATMEL_PIT - select CLKSRC_OF if OF + select TIMER_OF if OF def_bool SOC_AT91SAM9 || SOC_SAMA5 config ATMEL_ST bool "Atmel ST timer support" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS - select CLKSRC_OF + select TIMER_OF select MFD_SYSCON help Support for the Atmel ST timer. @@ -456,7 +444,7 @@ config VF_PIT_TIMER config OXNAS_RPS_TIMER bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS - select CLKSRC_OF + select TIMER_OF select CLKSRC_MMIO help This enables support for the Oxford Semiconductor OXNAS RPS timers. @@ -467,7 +455,7 @@ config SYS_SUPPORTS_SH_CMT config MTK_TIMER bool "Mediatek timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS && HAS_IOMEM - select CLKSRC_OF + select TIMER_OF select CLKSRC_MMIO help Support for Mediatek timer driver. @@ -540,7 +528,7 @@ config EM_TIMER_STI config CLKSRC_QCOM bool "Qualcomm MSM timer" if COMPILE_TEST depends on ARM - select CLKSRC_OF + select TIMER_OF help This enables the clocksource and the per CPU clockevent driver for the Qualcomm SoCs. @@ -548,7 +536,7 @@ config CLKSRC_QCOM config CLKSRC_VERSATILE bool "ARM Versatile (Express) reference platforms clock source" if COMPILE_TEST depends on GENERIC_SCHED_CLOCK && !ARCH_USES_GETTIMEOFFSET - select CLKSRC_OF + select TIMER_OF default y if MFD_VEXPRESS_SYSREG help This option enables clock source based on free running @@ -559,12 +547,12 @@ config CLKSRC_VERSATILE config CLKSRC_MIPS_GIC bool depends on MIPS_GIC - select CLKSRC_OF + select TIMER_OF config CLKSRC_TANGO_XTAL bool "Clocksource for Tango SoC" if COMPILE_TEST depends on ARM - select CLKSRC_OF + select TIMER_OF select CLKSRC_MMIO help This enables the clocksource for Tango SoC @@ -605,7 +593,7 @@ config CLKSRC_IMX_GPT config CLKSRC_ST_LPC bool "Low power clocksource found in the LPC" if COMPILE_TEST - select CLKSRC_OF if OF + select TIMER_OF if OF depends on HAS_IOMEM select CLKSRC_MMIO help diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 2b5b56a..72bfd00 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -1,5 +1,5 @@ -obj-$(CONFIG_CLKSRC_PROBE) += clksrc-probe.o -obj-$(CONFIG_CLKEVT_PROBE) += clkevt-probe.o +obj-$(CONFIG_TIMER_OF) += timer-of.o +obj-$(CONFIG_TIMER_PROBE) += timer-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 @@ -26,7 +26,6 @@ obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o -obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o obj-$(CONFIG_MXS_TIMER) += mxs_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o diff --git a/drivers/clocksource/arc_timer.c b/drivers/clocksource/arc_timer.c index 2164973..4927355 100644 --- a/drivers/clocksource/arc_timer.c +++ b/drivers/clocksource/arc_timer.c @@ -99,7 +99,7 @@ static int __init arc_cs_setup_gfrc(struct device_node *node) return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); } -CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); +TIMER_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); #define AUX_RTC_CTRL 0x103 #define AUX_RTC_LOW 0x104 @@ -158,7 +158,7 @@ static int __init arc_cs_setup_rtc(struct device_node *node) return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); } -CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); +TIMER_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); #endif @@ -333,4 +333,4 @@ static int __init arc_of_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); +TIMER_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 8b5c300..aae87c4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1194,8 +1194,8 @@ static int __init arch_timer_of_init(struct device_node *np) return arch_timer_common_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); +TIMER_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); +TIMER_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); static u32 __init arch_timer_mem_frame_get_cntfrq(struct arch_timer_mem_frame *frame) @@ -1382,7 +1382,7 @@ out: kfree(timer_mem); return ret; } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", +TIMER_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_of_init); #ifdef CONFIG_ACPI_GTDT @@ -1516,5 +1516,5 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) return arch_timer_common_init(); } -CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init); +TIMER_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init); #endif diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index 123ed20..095bb96 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -339,5 +339,5 @@ out_unmap: } /* Only tested on r2p2 and r3p0 */ -CLOCKSOURCE_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer", +TIMER_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer", global_timer_of_register); diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c index a315491..ac046d6 100644 --- a/drivers/clocksource/armv7m_systick.c +++ b/drivers/clocksource/armv7m_systick.c @@ -82,5 +82,5 @@ out_unmap: return ret; } -CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick", +TIMER_OF_DECLARE(arm_systick, "arm,armv7m-systick", system_timer_of_register); diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c index c678083..38cd2fe 100644 --- a/drivers/clocksource/asm9260_timer.c +++ b/drivers/clocksource/asm9260_timer.c @@ -238,5 +238,5 @@ static int __init asm9260_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer", +TIMER_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer", asm9260_timer_init); diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index dce4430..82828d3 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -148,5 +148,5 @@ err_iounmap: iounmap(base); return ret; } -CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer", +TIMER_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer", bcm2835_timer_init); diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index fda5e147..5c40be9 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -198,9 +198,9 @@ static int __init kona_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init); +TIMER_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init); /* * bcm,kona-timer is deprecated by brcm,kona-timer * being kept here for driver compatibility */ -CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init); +TIMER_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init); diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 8e64b84..29d5175 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -540,4 +540,4 @@ static int __init ttc_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); +TIMER_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); diff --git a/drivers/clocksource/clkevt-probe.c b/drivers/clocksource/clkevt-probe.c deleted file mode 100644 index eb89b50..0000000 --- a/drivers/clocksource/clkevt-probe.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2016, Linaro Ltd. All rights reserved. - * Daniel Lezcano <daniel.lezcano@linaro.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <linux/init.h> -#include <linux/of.h> -#include <linux/clockchips.h> - -extern struct of_device_id __clkevt_of_table[]; - -static const struct of_device_id __clkevt_of_table_sentinel - __used __section(__clkevt_of_table_end); - -int __init clockevent_probe(void) -{ - struct device_node *np; - const struct of_device_id *match; - of_init_fn_1_ret init_func; - int ret, clockevents = 0; - - for_each_matching_node_and_match(np, __clkevt_of_table, &match) { - if (!of_device_is_available(np)) - continue; - - init_func = match->data; - - ret = init_func(np); - if (ret) { - pr_warn("Failed to initialize '%s' (%d)\n", - np->name, ret); - continue; - } - - clockevents++; - } - - if (!clockevents) { - pr_crit("%s: no matching clockevent found\n", __func__); - return -ENODEV; - } - - return 0; -} diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c index c69e277..c1b96dc 100644 --- a/drivers/clocksource/clksrc-dbx500-prcmu.c +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c @@ -86,5 +86,5 @@ static int __init clksrc_dbx500_prcmu_init(struct device_node *node) #endif return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K); } -CLOCKSOURCE_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4", +TIMER_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4", clksrc_dbx500_prcmu_init); diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c index 03cc492..a1d01eb 100644 --- a/drivers/clocksource/clksrc_st_lpc.c +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -132,4 +132,4 @@ static int __init st_clksrc_of_register(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); +TIMER_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c index 24db6d6..a8dd805 100644 --- a/drivers/clocksource/clps711x-timer.c +++ b/drivers/clocksource/clps711x-timer.c @@ -103,7 +103,7 @@ void __init clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base, BUG_ON(_clps711x_clkevt_init(tc2, tc2_base, irq)); } -#ifdef CONFIG_CLKSRC_OF +#ifdef CONFIG_TIMER_OF static int __init clps711x_timer_init(struct device_node *np) { unsigned int irq = irq_of_parse_and_map(np, 0); @@ -119,5 +119,5 @@ static int __init clps711x_timer_init(struct device_node *np) return -EINVAL; } } -CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,ep7209-timer", clps711x_timer_init); +TIMER_OF_DECLARE(clps711x, "cirrus,ep7209-timer", clps711x_timer_init); #endif diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index aee6c0d..69866cd 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -167,7 +167,7 @@ static int __init dw_apb_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); +TIMER_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); +TIMER_OF_DECLARE(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); +TIMER_OF_DECLARE(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); +TIMER_OF_DECLARE(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 670ff0f..7a244b6 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -610,5 +610,5 @@ static int __init mct_init_ppi(struct device_node *np) { return mct_init_dt(np, MCT_INT_PPI); } -CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi); -CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); +TIMER_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi); +TIMER_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 738515b..3ee7e6f 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -329,13 +329,13 @@ static int __init ftm_timer_init(struct device_node *np) priv->clkevt_base = of_iomap(np, 0); if (!priv->clkevt_base) { pr_err("ftm: unable to map event timer registers\n"); - goto err; + goto err_clkevt; } priv->clksrc_base = of_iomap(np, 1); if (!priv->clksrc_base) { pr_err("ftm: unable to map source timer registers\n"); - goto err; + goto err_clksrc; } ret = -EINVAL; @@ -366,7 +366,11 @@ static int __init ftm_timer_init(struct device_node *np) return 0; err: + iounmap(priv->clksrc_base); +err_clksrc: + iounmap(priv->clkevt_base); +err_clkevt: kfree(priv); return ret; } -CLOCKSOURCE_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init); +TIMER_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init); diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c index 5b27fb9..dfbd4f8 100644 --- a/drivers/clocksource/h8300_timer16.c +++ b/drivers/clocksource/h8300_timer16.c @@ -187,5 +187,5 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", +TIMER_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init); diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index 804c489..f6ffb0c 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -207,4 +207,4 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); +TIMER_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c index 72e1cf2..45a8d17 100644 --- a/drivers/clocksource/h8300_tpu.c +++ b/drivers/clocksource/h8300_tpu.c @@ -154,4 +154,4 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); +TIMER_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); diff --git a/drivers/clocksource/jcore-pit.c b/drivers/clocksource/jcore-pit.c index 7c61226..5d3d88e 100644 --- a/drivers/clocksource/jcore-pit.c +++ b/drivers/clocksource/jcore-pit.c @@ -246,4 +246,4 @@ static int __init jcore_pit_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(jcore_pit, "jcore,pit", jcore_pit_init); +TIMER_OF_DECLARE(jcore_pit, "jcore,pit", jcore_pit_init); diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c index 39d21f6..92f2099 100644 --- a/drivers/clocksource/meson6_timer.c +++ b/drivers/clocksource/meson6_timer.c @@ -174,5 +174,5 @@ static int __init meson6_timer_init(struct device_node *node) 1, 0xfffe); return 0; } -CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", +TIMER_OF_DECLARE(meson6, "amlogic,meson6-timer", meson6_timer_init); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 3f52ee2..17b861e 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -167,10 +167,11 @@ static int __init gic_clocksource_of_init(struct device_node *node) clk = of_clk_get(node, 0); if (!IS_ERR(clk)) { - if (clk_prepare_enable(clk) < 0) { + ret = clk_prepare_enable(clk); + if (ret < 0) { pr_err("GIC failed to enable clock\n"); clk_put(clk); - return PTR_ERR(clk); + return ret; } gic_frequency = clk_get_rate(clk); @@ -200,5 +201,5 @@ static int __init gic_clocksource_of_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", +TIMER_OF_DECLARE(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c deleted file mode 100644 index 7f34306..0000000 --- a/drivers/clocksource/moxart_timer.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * MOXA ART SoCs timer handling. - * - * Copyright (C) 2013 Jonas Jensen - * - * Jonas Jensen <jonas.jensen@gmail.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/clk.h> -#include <linux/clockchips.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/irqreturn.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/io.h> -#include <linux/clocksource.h> -#include <linux/bitops.h> -#include <linux/slab.h> - -#define TIMER1_BASE 0x00 -#define TIMER2_BASE 0x10 -#define TIMER3_BASE 0x20 - -#define REG_COUNT 0x0 /* writable */ -#define REG_LOAD 0x4 -#define REG_MATCH1 0x8 -#define REG_MATCH2 0xC - -#define TIMER_CR 0x30 -#define TIMER_INTR_STATE 0x34 -#define TIMER_INTR_MASK 0x38 - -/* - * Moxart TIMER_CR flags: - * - * MOXART_CR_*_CLOCK 0: PCLK, 1: EXT1CLK - * MOXART_CR_*_INT overflow interrupt enable bit - */ -#define MOXART_CR_1_ENABLE BIT(0) -#define MOXART_CR_1_CLOCK BIT(1) -#define MOXART_CR_1_INT BIT(2) -#define MOXART_CR_2_ENABLE BIT(3) -#define MOXART_CR_2_CLOCK BIT(4) -#define MOXART_CR_2_INT BIT(5) -#define MOXART_CR_3_ENABLE BIT(6) -#define MOXART_CR_3_CLOCK BIT(7) -#define MOXART_CR_3_INT BIT(8) -#define MOXART_CR_COUNT_UP BIT(9) - -#define MOXART_TIMER1_ENABLE (MOXART_CR_2_ENABLE | MOXART_CR_1_ENABLE) -#define MOXART_TIMER1_DISABLE (MOXART_CR_2_ENABLE) - -/* - * The ASpeed variant of the IP block has a different layout - * for the control register - */ -#define ASPEED_CR_1_ENABLE BIT(0) -#define ASPEED_CR_1_CLOCK BIT(1) -#define ASPEED_CR_1_INT BIT(2) -#define ASPEED_CR_2_ENABLE BIT(4) -#define ASPEED_CR_2_CLOCK BIT(5) -#define ASPEED_CR_2_INT BIT(6) -#define ASPEED_CR_3_ENABLE BIT(8) -#define ASPEED_CR_3_CLOCK BIT(9) -#define ASPEED_CR_3_INT BIT(10) - -#define ASPEED_TIMER1_ENABLE (ASPEED_CR_2_ENABLE | ASPEED_CR_1_ENABLE) -#define ASPEED_TIMER1_DISABLE (ASPEED_CR_2_ENABLE) - -struct moxart_timer { - void __iomem *base; - unsigned int t1_disable_val; - unsigned int t1_enable_val; - unsigned int count_per_tick; - struct clock_event_device clkevt; -}; - -static inline struct moxart_timer *to_moxart(struct clock_event_device *evt) -{ - return container_of(evt, struct moxart_timer, clkevt); -} - -static inline void moxart_disable(struct clock_event_device *evt) -{ - struct moxart_timer *timer = to_moxart(evt); - - writel(timer->t1_disable_val, timer->base + TIMER_CR); -} - -static inline void moxart_enable(struct clock_event_device *evt) -{ - struct moxart_timer *timer = to_moxart(evt); - - writel(timer->t1_enable_val, timer->base + TIMER_CR); -} - -static int moxart_shutdown(struct clock_event_device *evt) -{ - moxart_disable(evt); - return 0; -} - -static int moxart_set_oneshot(struct clock_event_device *evt) -{ - moxart_disable(evt); - writel(~0, to_moxart(evt)->base + TIMER1_BASE + REG_LOAD); - return 0; -} - -static int moxart_set_periodic(struct clock_event_device *evt) -{ - struct moxart_timer *timer = to_moxart(evt); - - moxart_disable(evt); - writel(timer->count_per_tick, timer->base + TIMER1_BASE + REG_LOAD); - writel(0, timer->base + TIMER1_BASE + REG_MATCH1); - moxart_enable(evt); - return 0; -} - -static int moxart_clkevt_next_event(unsigned long cycles, - struct clock_event_device *evt) -{ - struct moxart_timer *timer = to_moxart(evt); - u32 u; - - moxart_disable(evt); - - u = readl(timer->base + TIMER1_BASE + REG_COUNT) - cycles; - writel(u, timer->base + TIMER1_BASE + REG_MATCH1); - - moxart_enable(evt); - - return 0; -} - -static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - evt->event_handler(evt); - return IRQ_HANDLED; -} - -static int __init moxart_timer_init(struct device_node *node) -{ - int ret, irq; - unsigned long pclk; - struct clk *clk; - struct moxart_timer *timer; - - timer = kzalloc(sizeof(*timer), GFP_KERNEL); - if (!timer) - return -ENOMEM; - - timer->base = of_iomap(node, 0); - if (!timer->base) { - pr_err("%s: of_iomap failed\n", node->full_name); - ret = -ENXIO; - goto out_free; - } - - irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) { - pr_err("%s: irq_of_parse_and_map failed\n", node->full_name); - ret = -EINVAL; - goto out_unmap; - } - - clk = of_clk_get(node, 0); - if (IS_ERR(clk)) { - pr_err("%s: of_clk_get failed\n", node->full_name); - ret = PTR_ERR(clk); - goto out_unmap; - } - - pclk = clk_get_rate(clk); - - if (of_device_is_compatible(node, "moxa,moxart-timer")) { - timer->t1_enable_val = MOXART_TIMER1_ENABLE; - timer->t1_disable_val = MOXART_TIMER1_DISABLE; - } else if (of_device_is_compatible(node, "aspeed,ast2400-timer")) { - timer->t1_enable_val = ASPEED_TIMER1_ENABLE; - timer->t1_disable_val = ASPEED_TIMER1_DISABLE; - } else { - pr_err("%s: unknown platform\n", node->full_name); - ret = -EINVAL; - goto out_unmap; - } - - timer->count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ); - - timer->clkevt.name = node->name; - timer->clkevt.rating = 200; - timer->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT; - timer->clkevt.set_state_shutdown = moxart_shutdown; - timer->clkevt.set_state_periodic = moxart_set_periodic; - timer->clkevt.set_state_oneshot = moxart_set_oneshot; - timer->clkevt.tick_resume = moxart_set_oneshot; - timer->clkevt.set_next_event = moxart_clkevt_next_event; - timer->clkevt.cpumask = cpumask_of(0); - timer->clkevt.irq = irq; - - ret = clocksource_mmio_init(timer->base + TIMER2_BASE + REG_COUNT, - "moxart_timer", pclk, 200, 32, - clocksource_mmio_readl_down); - if (ret) { - pr_err("%s: clocksource_mmio_init failed\n", node->full_name); - goto out_unmap; - } - - ret = request_irq(irq, moxart_timer_interrupt, IRQF_TIMER, - node->name, &timer->clkevt); - if (ret) { - pr_err("%s: setup_irq failed\n", node->full_name); - goto out_unmap; - } - - /* Clear match registers */ - writel(0, timer->base + TIMER1_BASE + REG_MATCH1); - writel(0, timer->base + TIMER1_BASE + REG_MATCH2); - writel(0, timer->base + TIMER2_BASE + REG_MATCH1); - writel(0, timer->base + TIMER2_BASE + REG_MATCH2); - - /* - * Start timer 2 rolling as our main wall clock source, keep timer 1 - * disabled - */ - writel(0, timer->base + TIMER_CR); - writel(~0, timer->base + TIMER2_BASE + REG_LOAD); - writel(timer->t1_disable_val, timer->base + TIMER_CR); - - /* - * documentation is not publicly available: - * min_delta / max_delta obtained by trial-and-error, - * max_delta 0xfffffffe should be ok because count - * register size is u32 - */ - clockevents_config_and_register(&timer->clkevt, pclk, 0x4, 0xfffffffe); - - return 0; - -out_unmap: - iounmap(timer->base); -out_free: - kfree(timer); - return ret; -} -CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init); -CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", moxart_timer_init); diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c index 3e4431e..aa4d63af 100644 --- a/drivers/clocksource/mps2-timer.c +++ b/drivers/clocksource/mps2-timer.c @@ -274,4 +274,4 @@ static int __init mps2_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init); +TIMER_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init); diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index 9065949..f9b724f 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -265,4 +265,4 @@ err_kzalloc: return -EINVAL; } -CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); +TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index 99b77af..a03434e 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -293,4 +293,4 @@ static int __init mxs_timer_init(struct device_node *np) return setup_irq(irq, &mxs_timer_irq); } -CLOCKSOURCE_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init); +TIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init); diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 7d44de3..8e4ddb9 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -284,5 +284,5 @@ static int __init nmdk_timer_of_init(struct device_node *node) return nmdk_timer_init(base, irq, pclk, clk); } -CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "st,nomadik-mtu", +TIMER_OF_DECLARE(nomadik_mtu, "st,nomadik-mtu", nmdk_timer_of_init); diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index a10fa667..08cd6ea 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -216,7 +216,7 @@ static int __init pxa_timer_dt_init(struct device_node *np) return pxa_timer_common_init(irq, clk_get_rate(clk)); } -CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); +TIMER_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); /* * Legacy timer init for non device-tree boards. diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index ee358cd..89816f8 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -254,5 +254,5 @@ static int __init msm_dt_timer_init(struct device_node *np) return msm_timer_init(freq, 32, irq, !!percpu_offset); } -CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); -CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); +TIMER_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); +TIMER_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c index c76f576..6cffd7c 100644 --- a/drivers/clocksource/renesas-ostm.c +++ b/drivers/clocksource/renesas-ostm.c @@ -262,4 +262,4 @@ err: return 0; } -CLOCKSOURCE_OF_DECLARE(ostm, "renesas,ostm", ostm_init); +TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init); diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index 49c02be..c27f4c8 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -303,5 +303,5 @@ static int __init rk_timer_init(struct device_node *np) return -EINVAL; } -CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init); -CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init); +TIMER_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init); +TIMER_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init); diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index a68e653..6d5d126 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -418,7 +418,7 @@ void __init samsung_pwm_clocksource_init(void __iomem *base, _samsung_pwm_clocksource_init(); } -#ifdef CONFIG_CLKSRC_OF +#ifdef CONFIG_TIMER_OF static int __init samsung_pwm_alloc(struct device_node *np, const struct samsung_pwm_variant *variant) { @@ -466,7 +466,7 @@ static int __init s3c2410_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s3c24xx_variant); } -CLOCKSOURCE_OF_DECLARE(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init); +TIMER_OF_DECLARE(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init); static const struct samsung_pwm_variant s3c64xx_variant = { .bits = 32, @@ -479,7 +479,7 @@ static int __init s3c64xx_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s3c64xx_variant); } -CLOCKSOURCE_OF_DECLARE(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init); +TIMER_OF_DECLARE(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init); static const struct samsung_pwm_variant s5p64x0_variant = { .bits = 32, @@ -492,7 +492,7 @@ static int __init s5p64x0_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s5p64x0_variant); } -CLOCKSOURCE_OF_DECLARE(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init); +TIMER_OF_DECLARE(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init); static const struct samsung_pwm_variant s5p_variant = { .bits = 32, @@ -505,5 +505,5 @@ static int __init s5p_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s5p_variant); } -CLOCKSOURCE_OF_DECLARE(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); +TIMER_OF_DECLARE(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); #endif diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 4452d5c..6e0180a 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -24,6 +24,8 @@ #include <linux/of_address.h> #include <linux/of_irq.h> +#include "timer-of.h" + #define TIMER_IRQ_EN_REG 0x00 #define TIMER_IRQ_EN(val) BIT(val) #define TIMER_IRQ_ST_REG 0x04 @@ -39,38 +41,37 @@ #define TIMER_SYNC_TICKS 3 -static void __iomem *timer_base; -static u32 ticks_per_jiffy; - /* * When we disable a timer, we need to wait at least for 2 cycles of * the timer source clock. We will use for that the clocksource timer * that is already setup and runs at the same frequency than the other * timers, and we never will be disabled. */ -static void sun4i_clkevt_sync(void) +static void sun4i_clkevt_sync(void __iomem *base) { - u32 old = readl(timer_base + TIMER_CNTVAL_REG(1)); + u32 old = readl(base + TIMER_CNTVAL_REG(1)); - while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < TIMER_SYNC_TICKS) + while ((old - readl(base + TIMER_CNTVAL_REG(1))) < TIMER_SYNC_TICKS) cpu_relax(); } -static void sun4i_clkevt_time_stop(u8 timer) +static void sun4i_clkevt_time_stop(void __iomem *base, u8 timer) { - u32 val = readl(timer_base + TIMER_CTL_REG(timer)); - writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); - sun4i_clkevt_sync(); + u32 val = readl(base + TIMER_CTL_REG(timer)); + writel(val & ~TIMER_CTL_ENABLE, base + TIMER_CTL_REG(timer)); + sun4i_clkevt_sync(base); } -static void sun4i_clkevt_time_setup(u8 timer, unsigned long delay) +static void sun4i_clkevt_time_setup(void __iomem *base, u8 timer, + unsigned long delay) { - writel(delay, timer_base + TIMER_INTVAL_REG(timer)); + writel(delay, base + TIMER_INTVAL_REG(timer)); } -static void sun4i_clkevt_time_start(u8 timer, bool periodic) +static void sun4i_clkevt_time_start(void __iomem *base, u8 timer, + bool periodic) { - u32 val = readl(timer_base + TIMER_CTL_REG(timer)); + u32 val = readl(base + TIMER_CTL_REG(timer)); if (periodic) val &= ~TIMER_CTL_ONESHOT; @@ -78,115 +79,106 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic) val |= TIMER_CTL_ONESHOT; writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, - timer_base + TIMER_CTL_REG(timer)); + base + TIMER_CTL_REG(timer)); } static int sun4i_clkevt_shutdown(struct clock_event_device *evt) { - sun4i_clkevt_time_stop(0); + struct timer_of *to = to_timer_of(evt); + + sun4i_clkevt_time_stop(timer_of_base(to), 0); + return 0; } static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt) { - sun4i_clkevt_time_stop(0); - sun4i_clkevt_time_start(0, false); + struct timer_of *to = to_timer_of(evt); + + sun4i_clkevt_time_stop(timer_of_base(to), 0); + sun4i_clkevt_time_start(timer_of_base(to), 0, false); + return 0; } static int sun4i_clkevt_set_periodic(struct clock_event_device *evt) { - sun4i_clkevt_time_stop(0); - sun4i_clkevt_time_setup(0, ticks_per_jiffy); - sun4i_clkevt_time_start(0, true); + struct timer_of *to = to_timer_of(evt); + + sun4i_clkevt_time_stop(timer_of_base(to), 0); + sun4i_clkevt_time_setup(timer_of_base(to), 0, timer_of_period(to)); + sun4i_clkevt_time_start(timer_of_base(to), 0, true); + return 0; } static int sun4i_clkevt_next_event(unsigned long evt, - struct clock_event_device *unused) + struct clock_event_device *clkevt) { - sun4i_clkevt_time_stop(0); - sun4i_clkevt_time_setup(0, evt - TIMER_SYNC_TICKS); - sun4i_clkevt_time_start(0, false); + struct timer_of *to = to_timer_of(clkevt); + + sun4i_clkevt_time_stop(timer_of_base(to), 0); + sun4i_clkevt_time_setup(timer_of_base(to), 0, evt - TIMER_SYNC_TICKS); + sun4i_clkevt_time_start(timer_of_base(to), 0, false); return 0; } -static struct clock_event_device sun4i_clockevent = { - .name = "sun4i_tick", - .rating = 350, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_state_shutdown = sun4i_clkevt_shutdown, - .set_state_periodic = sun4i_clkevt_set_periodic, - .set_state_oneshot = sun4i_clkevt_set_oneshot, - .tick_resume = sun4i_clkevt_shutdown, - .set_next_event = sun4i_clkevt_next_event, -}; - -static void sun4i_timer_clear_interrupt(void) +static void sun4i_timer_clear_interrupt(void __iomem *base) { - writel(TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_ST_REG); + writel(TIMER_IRQ_EN(0), base + TIMER_IRQ_ST_REG); } static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = (struct clock_event_device *)dev_id; + struct timer_of *to = to_timer_of(evt); - sun4i_timer_clear_interrupt(); + sun4i_timer_clear_interrupt(timer_of_base(to)); evt->event_handler(evt); return IRQ_HANDLED; } -static struct irqaction sun4i_timer_irq = { - .name = "sun4i_timer0", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = sun4i_timer_interrupt, - .dev_id = &sun4i_clockevent, +static struct timer_of to = { + .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE, + + .clkevt = { + .name = "sun4i_tick", + .rating = 350, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = sun4i_clkevt_shutdown, + .set_state_periodic = sun4i_clkevt_set_periodic, + .set_state_oneshot = sun4i_clkevt_set_oneshot, + .tick_resume = sun4i_clkevt_shutdown, + .set_next_event = sun4i_clkevt_next_event, + .cpumask = cpu_possible_mask, + }, + + .of_irq = { + .handler = sun4i_timer_interrupt, + .flags = IRQF_TIMER | IRQF_IRQPOLL, + }, }; static u64 notrace sun4i_timer_sched_read(void) { - return ~readl(timer_base + TIMER_CNTVAL_REG(1)); + return ~readl(timer_of_base(&to) + TIMER_CNTVAL_REG(1)); } static int __init sun4i_timer_init(struct device_node *node) { - unsigned long rate = 0; - struct clk *clk; - int ret, irq; + int ret; u32 val; - timer_base = of_iomap(node, 0); - if (!timer_base) { - pr_crit("Can't map registers\n"); - return -ENXIO; - } - - irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) { - pr_crit("Can't parse IRQ\n"); - return -EINVAL; - } - - clk = of_clk_get(node, 0); - if (IS_ERR(clk)) { - pr_crit("Can't get timer clock\n"); - return PTR_ERR(clk); - } - - ret = clk_prepare_enable(clk); - if (ret) { - pr_err("Failed to prepare clock\n"); + ret = timer_of_init(node, &to); + if (ret) return ret; - } - - rate = clk_get_rate(clk); - writel(~0, timer_base + TIMER_INTVAL_REG(1)); + writel(~0, timer_of_base(&to) + TIMER_INTVAL_REG(1)); writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD | TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), - timer_base + TIMER_CTL_REG(1)); + timer_of_base(&to) + TIMER_CTL_REG(1)); /* * sched_clock_register does not have priorities, and on sun6i and @@ -195,43 +187,34 @@ static int __init sun4i_timer_init(struct device_node *node) if (of_machine_is_compatible("allwinner,sun4i-a10") || of_machine_is_compatible("allwinner,sun5i-a13") || of_machine_is_compatible("allwinner,sun5i-a10s")) - sched_clock_register(sun4i_timer_sched_read, 32, rate); + sched_clock_register(sun4i_timer_sched_read, 32, + timer_of_rate(&to)); - ret = clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, - rate, 350, 32, clocksource_mmio_readl_down); + ret = clocksource_mmio_init(timer_of_base(&to) + TIMER_CNTVAL_REG(1), + node->name, timer_of_rate(&to), 350, 32, + clocksource_mmio_readl_down); if (ret) { pr_err("Failed to register clocksource\n"); return ret; } - ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); - writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), - timer_base + TIMER_CTL_REG(0)); + timer_of_base(&to) + TIMER_CTL_REG(0)); /* Make sure timer is stopped before playing with interrupts */ - sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_stop(timer_of_base(&to), 0); /* clear timer0 interrupt */ - sun4i_timer_clear_interrupt(); - - sun4i_clockevent.cpumask = cpu_possible_mask; - sun4i_clockevent.irq = irq; + sun4i_timer_clear_interrupt(timer_of_base(&to)); - clockevents_config_and_register(&sun4i_clockevent, rate, + clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), TIMER_SYNC_TICKS, 0xffffffff); - ret = setup_irq(irq, &sun4i_timer_irq); - if (ret) { - pr_err("failed to setup irq %d\n", irq); - return ret; - } - /* Enable timer0 interrupt */ - val = readl(timer_base + TIMER_IRQ_EN_REG); - writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); + val = readl(timer_of_base(&to) + TIMER_IRQ_EN_REG); + writel(val | TIMER_IRQ_EN(0), timer_of_base(&to) + TIMER_IRQ_EN_REG); return ret; } -CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", +TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", sun4i_timer_init); diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c index 12fcef8..c4e1c2e 100644 --- a/drivers/clocksource/tango_xtal.c +++ b/drivers/clocksource/tango_xtal.c @@ -53,4 +53,4 @@ static int __init tango_clocksource_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init); +TIMER_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init); diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index d4ca996..59e8aee 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -9,6 +9,7 @@ #include <linux/ioport.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/syscore_ops.h> #include <linux/atmel_tc.h> @@ -40,6 +41,14 @@ */ static void __iomem *tcaddr; +static struct +{ + u32 cmr; + u32 imr; + u32 rc; + bool clken; +} tcb_cache[3]; +static u32 bmr_cache; static u64 tc_get_cycles(struct clocksource *cs) { @@ -48,9 +57,9 @@ static u64 tc_get_cycles(struct clocksource *cs) raw_local_irq_save(flags); do { - upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)); - lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV)); - } while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV))); + upper = readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV)); + lower = readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV)); + } while (upper != readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV))); raw_local_irq_restore(flags); return (upper << 16) | lower; @@ -58,7 +67,47 @@ static u64 tc_get_cycles(struct clocksource *cs) static u64 tc_get_cycles32(struct clocksource *cs) { - return __raw_readl(tcaddr + ATMEL_TC_REG(0, CV)); + return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV)); +} + +void tc_clksrc_suspend(struct clocksource *cs) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) { + tcb_cache[i].cmr = readl(tcaddr + ATMEL_TC_REG(i, CMR)); + tcb_cache[i].imr = readl(tcaddr + ATMEL_TC_REG(i, IMR)); + tcb_cache[i].rc = readl(tcaddr + ATMEL_TC_REG(i, RC)); + tcb_cache[i].clken = !!(readl(tcaddr + ATMEL_TC_REG(i, SR)) & + ATMEL_TC_CLKSTA); + } + + bmr_cache = readl(tcaddr + ATMEL_TC_BMR); +} + +void tc_clksrc_resume(struct clocksource *cs) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) { + /* Restore registers for the channel, RA and RB are not used */ + writel(tcb_cache[i].cmr, tcaddr + ATMEL_TC_REG(i, CMR)); + writel(tcb_cache[i].rc, tcaddr + ATMEL_TC_REG(i, RC)); + writel(0, tcaddr + ATMEL_TC_REG(i, RA)); + writel(0, tcaddr + ATMEL_TC_REG(i, RB)); + /* Disable all the interrupts */ + writel(0xff, tcaddr + ATMEL_TC_REG(i, IDR)); + /* Reenable interrupts that were enabled before suspending */ + writel(tcb_cache[i].imr, tcaddr + ATMEL_TC_REG(i, IER)); + /* Start the clock if it was used */ + if (tcb_cache[i].clken) + writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(i, CCR)); + } + + /* Dual channel, chain channels */ + writel(bmr_cache, tcaddr + ATMEL_TC_BMR); + /* Finally, trigger all the channels*/ + writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); } static struct clocksource clksrc = { @@ -67,6 +116,8 @@ static struct clocksource clksrc = { .read = tc_get_cycles, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .suspend = tc_clksrc_suspend, + .resume = tc_clksrc_resume, }; #ifdef CONFIG_GENERIC_CLOCKEVENTS @@ -96,8 +147,8 @@ static int tc_shutdown(struct clock_event_device *d) struct tc_clkevt_device *tcd = to_tc_clkevt(d); void __iomem *regs = tcd->regs; - __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); - __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); + writel(0xff, regs + ATMEL_TC_REG(2, IDR)); + writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); if (!clockevent_state_detached(d)) clk_disable(tcd->clk); @@ -115,9 +166,9 @@ static int tc_set_oneshot(struct clock_event_device *d) clk_enable(tcd->clk); /* slow clock, count up to RC, then irq and stop */ - __raw_writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE | + writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR)); - __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); + writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); /* set_next_event() configures and starts the timer */ return 0; @@ -137,25 +188,25 @@ static int tc_set_periodic(struct clock_event_device *d) clk_enable(tcd->clk); /* slow clock, count up to RC, then irq and restart */ - __raw_writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, + writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR)); - __raw_writel((32768 + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); + writel((32768 + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); /* Enable clock and interrupts on RC compare */ - __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); + writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); /* go go gadget! */ - __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs + + writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs + ATMEL_TC_REG(2, CCR)); return 0; } static int tc_next_event(unsigned long delta, struct clock_event_device *d) { - __raw_writel(delta, tcaddr + ATMEL_TC_REG(2, RC)); + writel_relaxed(delta, tcaddr + ATMEL_TC_REG(2, RC)); /* go go gadget! */ - __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, + writel_relaxed(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, tcaddr + ATMEL_TC_REG(2, CCR)); return 0; } @@ -179,7 +230,7 @@ static irqreturn_t ch2_irq(int irq, void *handle) struct tc_clkevt_device *dev = handle; unsigned int sr; - sr = __raw_readl(dev->regs + ATMEL_TC_REG(2, SR)); + sr = readl_relaxed(dev->regs + ATMEL_TC_REG(2, SR)); if (sr & ATMEL_TC_CPCS) { dev->clkevt.event_handler(&dev->clkevt); return IRQ_HANDLED; @@ -239,43 +290,43 @@ static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx) { /* channel 0: waveform mode, input mclk/8, clock TIOA0 on overflow */ - __raw_writel(mck_divisor_idx /* likely divide-by-8 */ + writel(mck_divisor_idx /* likely divide-by-8 */ | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP /* free-run */ | ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */ | ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */ tcaddr + ATMEL_TC_REG(0, CMR)); - __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA)); - __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC)); - __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ - __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); + writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA)); + writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC)); + writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ + writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); /* channel 1: waveform mode, input TIOA0 */ - __raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */ + writel(ATMEL_TC_XC1 /* input: TIOA0 */ | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP, /* free-run */ tcaddr + ATMEL_TC_REG(1, CMR)); - __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */ - __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR)); + writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */ + writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR)); /* chain channel 0 to channel 1*/ - __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR); + writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR); /* then reset all the timers */ - __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); + writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); } static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx) { /* channel 0: waveform mode, input mclk/8 */ - __raw_writel(mck_divisor_idx /* likely divide-by-8 */ + writel(mck_divisor_idx /* likely divide-by-8 */ | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP, /* free-run */ tcaddr + ATMEL_TC_REG(0, CMR)); - __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ - __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); + writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ + writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); /* then reset all the timers */ - __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); + writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); } static int __init tcb_clksrc_init(void) diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index b9990b9..c337a81 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -237,7 +237,7 @@ static int __init tegra20_init_timer(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); +TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); static int __init tegra20_init_rtc(struct device_node *np) { @@ -261,4 +261,4 @@ static int __init tegra20_init_rtc(struct device_node *np) return register_persistent_clock(NULL, tegra_read_persistent_clock64); } -CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); +TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index aea4380..edf1a46 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -351,7 +351,7 @@ static int __init armada_xp_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", +TIMER_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", armada_xp_timer_init); static int __init armada_375_timer_init(struct device_node *np) @@ -389,7 +389,7 @@ static int __init armada_375_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE(armada_375, "marvell,armada-375-timer", +TIMER_OF_DECLARE(armada_375, "marvell,armada-375-timer", armada_375_timer_init); static int __init armada_370_timer_init(struct device_node *np) @@ -412,5 +412,5 @@ static int __init armada_370_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", +TIMER_OF_DECLARE(armada_370, "marvell,armada-370-timer", armada_370_timer_init); diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/time-efm32.c index ce0f97b..257e810 100644 --- a/drivers/clocksource/time-efm32.c +++ b/drivers/clocksource/time-efm32.c @@ -283,5 +283,5 @@ static int __init efm32_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init); -CLOCKSOURCE_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init); +TIMER_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init); +TIMER_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init); diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c index 9649cfd..d51a62a 100644 --- a/drivers/clocksource/time-lpc32xx.c +++ b/drivers/clocksource/time-lpc32xx.c @@ -311,4 +311,4 @@ static int __init lpc32xx_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); +TIMER_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index b9b97f6..1220206 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c @@ -189,4 +189,4 @@ static int __init orion_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init); +TIMER_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init); diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c index 3710e4d..a2dd85d 100644 --- a/drivers/clocksource/time-pistachio.c +++ b/drivers/clocksource/time-pistachio.c @@ -214,5 +214,5 @@ static int __init pistachio_clksrc_of_init(struct device_node *node) sched_clock_register(pistachio_read_sched_clock, 32, rate); return clocksource_register_hz(&pcs_gpt.cs, rate); } -CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", +TIMER_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", pistachio_clksrc_of_init); diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c index 50300ee..62c4bbc 100644 --- a/drivers/clocksource/timer-atlas7.c +++ b/drivers/clocksource/timer-atlas7.c @@ -283,4 +283,4 @@ static int __init sirfsoc_of_timer_init(struct device_node *np) return sirfsoc_atlas7_timer_init(np); } -CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); +TIMER_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index cc11235..ec8a437 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -255,5 +255,5 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit", +TIMER_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit", at91sam926x_pit_dt_init); diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c index be4ac76..d2e660f 100644 --- a/drivers/clocksource/timer-atmel-st.c +++ b/drivers/clocksource/timer-atmel-st.c @@ -260,5 +260,5 @@ static int __init atmel_st_timer_init(struct device_node *node) /* register clocksource */ return clocksource_register_hz(&clk32k, sclk_rate); } -CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st", +TIMER_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st", atmel_st_timer_init); diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c index 94a161e..1e984a4 100644 --- a/drivers/clocksource/timer-digicolor.c +++ b/drivers/clocksource/timer-digicolor.c @@ -203,5 +203,5 @@ static int __init digicolor_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer", +TIMER_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer", digicolor_timer_init); diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c index b4a6f1e..66dd909 100644 --- a/drivers/clocksource/timer-fttmr010.c +++ b/drivers/clocksource/timer-fttmr010.c @@ -11,12 +11,13 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/mfd/syscon.h> -#include <linux/regmap.h> #include <linux/clockchips.h> #include <linux/clocksource.h> #include <linux/sched_clock.h> #include <linux/clk.h> +#include <linux/slab.h> +#include <linux/bitops.h> +#include <linux/delay.h> /* * Register definitions for the timers @@ -37,267 +38,368 @@ #define TIMER_INTR_STATE (0x34) #define TIMER_INTR_MASK (0x38) -#define TIMER_1_CR_ENABLE (1 << 0) -#define TIMER_1_CR_CLOCK (1 << 1) -#define TIMER_1_CR_INT (1 << 2) -#define TIMER_2_CR_ENABLE (1 << 3) -#define TIMER_2_CR_CLOCK (1 << 4) -#define TIMER_2_CR_INT (1 << 5) -#define TIMER_3_CR_ENABLE (1 << 6) -#define TIMER_3_CR_CLOCK (1 << 7) -#define TIMER_3_CR_INT (1 << 8) -#define TIMER_1_CR_UPDOWN (1 << 9) -#define TIMER_2_CR_UPDOWN (1 << 10) -#define TIMER_3_CR_UPDOWN (1 << 11) -#define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \ - TIMER_3_CR_ENABLE | \ - TIMER_3_CR_UPDOWN) - -#define TIMER_1_INT_MATCH1 (1 << 0) -#define TIMER_1_INT_MATCH2 (1 << 1) -#define TIMER_1_INT_OVERFLOW (1 << 2) -#define TIMER_2_INT_MATCH1 (1 << 3) -#define TIMER_2_INT_MATCH2 (1 << 4) -#define TIMER_2_INT_OVERFLOW (1 << 5) -#define TIMER_3_INT_MATCH1 (1 << 6) -#define TIMER_3_INT_MATCH2 (1 << 7) -#define TIMER_3_INT_OVERFLOW (1 << 8) +#define TIMER_1_CR_ENABLE BIT(0) +#define TIMER_1_CR_CLOCK BIT(1) +#define TIMER_1_CR_INT BIT(2) +#define TIMER_2_CR_ENABLE BIT(3) +#define TIMER_2_CR_CLOCK BIT(4) +#define TIMER_2_CR_INT BIT(5) +#define TIMER_3_CR_ENABLE BIT(6) +#define TIMER_3_CR_CLOCK BIT(7) +#define TIMER_3_CR_INT BIT(8) +#define TIMER_1_CR_UPDOWN BIT(9) +#define TIMER_2_CR_UPDOWN BIT(10) +#define TIMER_3_CR_UPDOWN BIT(11) + +/* + * The Aspeed AST2400 moves bits around in the control register + * and lacks bits for setting the timer to count upwards. + */ +#define TIMER_1_CR_ASPEED_ENABLE BIT(0) +#define TIMER_1_CR_ASPEED_CLOCK BIT(1) +#define TIMER_1_CR_ASPEED_INT BIT(2) +#define TIMER_2_CR_ASPEED_ENABLE BIT(4) +#define TIMER_2_CR_ASPEED_CLOCK BIT(5) +#define TIMER_2_CR_ASPEED_INT BIT(6) +#define TIMER_3_CR_ASPEED_ENABLE BIT(8) +#define TIMER_3_CR_ASPEED_CLOCK BIT(9) +#define TIMER_3_CR_ASPEED_INT BIT(10) + +#define TIMER_1_INT_MATCH1 BIT(0) +#define TIMER_1_INT_MATCH2 BIT(1) +#define TIMER_1_INT_OVERFLOW BIT(2) +#define TIMER_2_INT_MATCH1 BIT(3) +#define TIMER_2_INT_MATCH2 BIT(4) +#define TIMER_2_INT_OVERFLOW BIT(5) +#define TIMER_3_INT_MATCH1 BIT(6) +#define TIMER_3_INT_MATCH2 BIT(7) +#define TIMER_3_INT_OVERFLOW BIT(8) #define TIMER_INT_ALL_MASK 0x1ff -static unsigned int tick_rate; -static void __iomem *base; +struct fttmr010 { + void __iomem *base; + unsigned int tick_rate; + bool count_down; + u32 t1_enable_val; + struct clock_event_device clkevt; +#ifdef CONFIG_ARM + struct delay_timer delay_timer; +#endif +}; + +/* + * A local singleton used by sched_clock and delay timer reads, which are + * fast and stateless + */ +static struct fttmr010 *local_fttmr; + +static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt) +{ + return container_of(evt, struct fttmr010, clkevt); +} + +static unsigned long fttmr010_read_current_timer_up(void) +{ + return readl(local_fttmr->base + TIMER2_COUNT); +} + +static unsigned long fttmr010_read_current_timer_down(void) +{ + return ~readl(local_fttmr->base + TIMER2_COUNT); +} + +static u64 notrace fttmr010_read_sched_clock_up(void) +{ + return fttmr010_read_current_timer_up(); +} -static u64 notrace fttmr010_read_sched_clock(void) +static u64 notrace fttmr010_read_sched_clock_down(void) { - return readl(base + TIMER3_COUNT); + return fttmr010_read_current_timer_down(); } static int fttmr010_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { + struct fttmr010 *fttmr010 = to_fttmr010(evt); u32 cr; - /* Setup the match register */ - cr = readl(base + TIMER1_COUNT); - writel(cr + cycles, base + TIMER1_MATCH1); - if (readl(base + TIMER1_COUNT) - cr > cycles) - return -ETIME; + /* Stop */ + cr = readl(fttmr010->base + TIMER_CR); + cr &= ~fttmr010->t1_enable_val; + writel(cr, fttmr010->base + TIMER_CR); + + /* Setup the match register forward/backward in time */ + cr = readl(fttmr010->base + TIMER1_COUNT); + if (fttmr010->count_down) + cr -= cycles; + else + cr += cycles; + writel(cr, fttmr010->base + TIMER1_MATCH1); + + /* Start */ + cr = readl(fttmr010->base + TIMER_CR); + cr |= fttmr010->t1_enable_val; + writel(cr, fttmr010->base + TIMER_CR); return 0; } static int fttmr010_timer_shutdown(struct clock_event_device *evt) { + struct fttmr010 *fttmr010 = to_fttmr010(evt); u32 cr; - /* - * Disable also for oneshot: the set_next() call will arm the timer - * instead. - */ - /* Stop timer and interrupt. */ - cr = readl(base + TIMER_CR); - cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); - writel(cr, base + TIMER_CR); + /* Stop */ + cr = readl(fttmr010->base + TIMER_CR); + cr &= ~fttmr010->t1_enable_val; + writel(cr, fttmr010->base + TIMER_CR); + + return 0; +} + +static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) +{ + struct fttmr010 *fttmr010 = to_fttmr010(evt); + u32 cr; + + /* Stop */ + cr = readl(fttmr010->base + TIMER_CR); + cr &= ~fttmr010->t1_enable_val; + writel(cr, fttmr010->base + TIMER_CR); - /* Setup counter start from 0 */ - writel(0, base + TIMER1_COUNT); - writel(0, base + TIMER1_LOAD); + /* Setup counter start from 0 or ~0 */ + writel(0, fttmr010->base + TIMER1_COUNT); + if (fttmr010->count_down) + writel(~0, fttmr010->base + TIMER1_LOAD); + else + writel(0, fttmr010->base + TIMER1_LOAD); - /* enable interrupt */ - cr = readl(base + TIMER_INTR_MASK); + /* Enable interrupt */ + cr = readl(fttmr010->base + TIMER_INTR_MASK); cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); cr |= TIMER_1_INT_MATCH1; - writel(cr, base + TIMER_INTR_MASK); - - /* start the timer */ - cr = readl(base + TIMER_CR); - cr |= TIMER_1_CR_ENABLE; - writel(cr, base + TIMER_CR); + writel(cr, fttmr010->base + TIMER_INTR_MASK); return 0; } static int fttmr010_timer_set_periodic(struct clock_event_device *evt) { - u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ); + struct fttmr010 *fttmr010 = to_fttmr010(evt); + u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); u32 cr; - /* Stop timer and interrupt */ - cr = readl(base + TIMER_CR); - cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); - writel(cr, base + TIMER_CR); - - /* Setup timer to fire at 1/HT intervals. */ - cr = 0xffffffff - (period - 1); - writel(cr, base + TIMER1_COUNT); - writel(cr, base + TIMER1_LOAD); - - /* enable interrupt on overflow */ - cr = readl(base + TIMER_INTR_MASK); - cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); - cr |= TIMER_1_INT_OVERFLOW; - writel(cr, base + TIMER_INTR_MASK); + /* Stop */ + cr = readl(fttmr010->base + TIMER_CR); + cr &= ~fttmr010->t1_enable_val; + writel(cr, fttmr010->base + TIMER_CR); + + /* Setup timer to fire at 1/HZ intervals. */ + if (fttmr010->count_down) { + writel(period, fttmr010->base + TIMER1_LOAD); + writel(0, fttmr010->base + TIMER1_MATCH1); + } else { + cr = 0xffffffff - (period - 1); + writel(cr, fttmr010->base + TIMER1_COUNT); + writel(cr, fttmr010->base + TIMER1_LOAD); + + /* Enable interrupt on overflow */ + cr = readl(fttmr010->base + TIMER_INTR_MASK); + cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); + cr |= TIMER_1_INT_OVERFLOW; + writel(cr, fttmr010->base + TIMER_INTR_MASK); + } /* Start the timer */ - cr = readl(base + TIMER_CR); - cr |= TIMER_1_CR_ENABLE; - cr |= TIMER_1_CR_INT; - writel(cr, base + TIMER_CR); + cr = readl(fttmr010->base + TIMER_CR); + cr |= fttmr010->t1_enable_val; + writel(cr, fttmr010->base + TIMER_CR); return 0; } -/* Use TIMER1 as clock event */ -static struct clock_event_device fttmr010_clockevent = { - .name = "TIMER1", - /* Reasonably fast and accurate clock event */ - .rating = 300, - .shift = 32, - .features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = fttmr010_timer_set_next_event, - .set_state_shutdown = fttmr010_timer_shutdown, - .set_state_periodic = fttmr010_timer_set_periodic, - .set_state_oneshot = fttmr010_timer_shutdown, - .tick_resume = fttmr010_timer_shutdown, -}; - /* * IRQ handler for the timer */ static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) { - struct clock_event_device *evt = &fttmr010_clockevent; + struct clock_event_device *evt = dev_id; evt->event_handler(evt); return IRQ_HANDLED; } -static struct irqaction fttmr010_timer_irq = { - .name = "Faraday FTTMR010 Timer Tick", - .flags = IRQF_TIMER, - .handler = fttmr010_timer_interrupt, -}; - -static int __init fttmr010_timer_common_init(struct device_node *np) +static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed) { + struct fttmr010 *fttmr010; int irq; + struct clk *clk; + int ret; + u32 val; + + /* + * These implementations require a clock reference. + * FIXME: we currently only support clocking using PCLK + * and using EXTCLK is not supported in the driver. + */ + clk = of_clk_get_by_name(np, "PCLK"); + if (IS_ERR(clk)) { + pr_err("could not get PCLK\n"); + return PTR_ERR(clk); + } + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("failed to enable PCLK\n"); + return ret; + } - base = of_iomap(np, 0); - if (!base) { + fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL); + if (!fttmr010) { + ret = -ENOMEM; + goto out_disable_clock; + } + fttmr010->tick_rate = clk_get_rate(clk); + + fttmr010->base = of_iomap(np, 0); + if (!fttmr010->base) { pr_err("Can't remap registers"); - return -ENXIO; + ret = -ENXIO; + goto out_free; } /* IRQ for timer 1 */ irq = irq_of_parse_and_map(np, 0); if (irq <= 0) { pr_err("Can't parse IRQ"); - return -EINVAL; + ret = -EINVAL; + goto out_unmap; + } + + /* + * The Aspeed AST2400 moves bits around in the control register, + * otherwise it works the same. + */ + if (is_aspeed) { + fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE | + TIMER_1_CR_ASPEED_INT; + /* Downward not available */ + fttmr010->count_down = true; + } else { + fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT; } /* * Reset the interrupt mask and status */ - writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK); - writel(0, base + TIMER_INTR_STATE); - writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR); + writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); + writel(0, fttmr010->base + TIMER_INTR_STATE); + + /* + * Enable timer 1 count up, timer 2 count up, except on Aspeed, + * where everything just counts down. + */ + if (is_aspeed) + val = TIMER_2_CR_ASPEED_ENABLE; + else { + val = TIMER_2_CR_ENABLE; + if (!fttmr010->count_down) + val |= TIMER_1_CR_UPDOWN | TIMER_2_CR_UPDOWN; + } + writel(val, fttmr010->base + TIMER_CR); /* * Setup free-running clocksource timer (interrupts * disabled.) */ - writel(0, base + TIMER3_COUNT); - writel(0, base + TIMER3_LOAD); - writel(0, base + TIMER3_MATCH1); - writel(0, base + TIMER3_MATCH2); - clocksource_mmio_init(base + TIMER3_COUNT, - "fttmr010_clocksource", tick_rate, - 300, 32, clocksource_mmio_readl_up); - sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate); + local_fttmr = fttmr010; + writel(0, fttmr010->base + TIMER2_COUNT); + writel(0, fttmr010->base + TIMER2_MATCH1); + writel(0, fttmr010->base + TIMER2_MATCH2); + + if (fttmr010->count_down) { + writel(~0, fttmr010->base + TIMER2_LOAD); + clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, + "FTTMR010-TIMER2", + fttmr010->tick_rate, + 300, 32, clocksource_mmio_readl_down); + sched_clock_register(fttmr010_read_sched_clock_down, 32, + fttmr010->tick_rate); + } else { + writel(0, fttmr010->base + TIMER2_LOAD); + clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, + "FTTMR010-TIMER2", + fttmr010->tick_rate, + 300, 32, clocksource_mmio_readl_up); + sched_clock_register(fttmr010_read_sched_clock_up, 32, + fttmr010->tick_rate); + } /* - * Setup clockevent timer (interrupt-driven.) + * Setup clockevent timer (interrupt-driven) on timer 1. */ - writel(0, base + TIMER1_COUNT); - writel(0, base + TIMER1_LOAD); - writel(0, base + TIMER1_MATCH1); - writel(0, base + TIMER1_MATCH2); - setup_irq(irq, &fttmr010_timer_irq); - fttmr010_clockevent.cpumask = cpumask_of(0); - clockevents_config_and_register(&fttmr010_clockevent, tick_rate, + writel(0, fttmr010->base + TIMER1_COUNT); + 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, + "FTTMR010-TIMER1", &fttmr010->clkevt); + if (ret) { + pr_err("FTTMR010-TIMER1 no IRQ\n"); + goto out_unmap; + } + + fttmr010->clkevt.name = "FTTMR010-TIMER1"; + /* Reasonably fast and accurate clock event */ + fttmr010->clkevt.rating = 300; + 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_periodic = fttmr010_timer_set_periodic; + fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot; + fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown; + fttmr010->clkevt.cpumask = cpumask_of(0); + fttmr010->clkevt.irq = irq; + clockevents_config_and_register(&fttmr010->clkevt, + fttmr010->tick_rate, 1, 0xffffffff); - return 0; -} +#ifdef CONFIG_ARM + /* Also use this timer for delays */ + if (fttmr010->count_down) + fttmr010->delay_timer.read_current_timer = + fttmr010_read_current_timer_down; + else + fttmr010->delay_timer.read_current_timer = + fttmr010_read_current_timer_up; + fttmr010->delay_timer.freq = fttmr010->tick_rate; + register_current_timer_delay(&fttmr010->delay_timer); +#endif -static int __init fttmr010_timer_of_init(struct device_node *np) -{ - /* - * These implementations require a clock reference. - * FIXME: we currently only support clocking using PCLK - * and using EXTCLK is not supported in the driver. - */ - struct clk *clk; + return 0; - clk = of_clk_get_by_name(np, "PCLK"); - if (IS_ERR(clk)) { - pr_err("could not get PCLK"); - return PTR_ERR(clk); - } - tick_rate = clk_get_rate(clk); +out_unmap: + iounmap(fttmr010->base); +out_free: + kfree(fttmr010); +out_disable_clock: + clk_disable_unprepare(clk); - return fttmr010_timer_common_init(np); + return ret; } -CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_of_init); -/* - * Gemini-specific: relevant registers in the global syscon - */ -#define GLOBAL_STATUS 0x04 -#define CPU_AHB_RATIO_MASK (0x3 << 18) -#define CPU_AHB_1_1 (0x0 << 18) -#define CPU_AHB_3_2 (0x1 << 18) -#define CPU_AHB_24_13 (0x2 << 18) -#define CPU_AHB_2_1 (0x3 << 18) -#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130) - -static int __init gemini_timer_of_init(struct device_node *np) +static __init int aspeed_timer_init(struct device_node *np) { - static struct regmap *map; - int ret; - u32 val; - - map = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(map)) { - pr_err("Can't get regmap for syscon handle\n"); - return -ENODEV; - } - ret = regmap_read(map, GLOBAL_STATUS, &val); - if (ret) { - pr_err("Can't read syscon status register\n"); - return -ENXIO; - } - - tick_rate = REG_TO_AHB_SPEED(val) * 1000000; - pr_info("Bus: %dMHz ", tick_rate / 1000000); - - tick_rate /= 6; /* APB bus run AHB*(1/6) */ - - switch (val & CPU_AHB_RATIO_MASK) { - case CPU_AHB_1_1: - pr_cont("(1/1)\n"); - break; - case CPU_AHB_3_2: - pr_cont("(3/2)\n"); - break; - case CPU_AHB_24_13: - pr_cont("(24/13)\n"); - break; - case CPU_AHB_2_1: - pr_cont("(2/1)\n"); - break; - } + return fttmr010_common_init(np, true); +} - return fttmr010_timer_common_init(np); +static __init int fttmr010_timer_init(struct device_node *np) +{ + return fttmr010_common_init(np, false); } -CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", gemini_timer_of_init); + +TIMER_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); +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); diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index f595460..6ec6d79 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -545,15 +545,15 @@ static int __init imx6dl_timer_init_dt(struct device_node *np) return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); } -CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); +TIMER_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); +TIMER_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); +TIMER_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); +TIMER_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); +TIMER_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); +TIMER_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); +TIMER_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); +TIMER_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); +TIMER_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); +TIMER_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); +TIMER_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); +TIMER_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index 04ad306..2ff64d9 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -232,5 +232,5 @@ static int __init integrator_ap_timer_init_of(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", +TIMER_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", integrator_ap_timer_init_of); diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c index ab68a47..0eee032 100644 --- a/drivers/clocksource/timer-keystone.c +++ b/drivers/clocksource/timer-keystone.c @@ -226,5 +226,5 @@ err: return error; } -CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer", +TIMER_OF_DECLARE(keystone_timer, "ti,keystone-timer", keystone_timer_init); diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c index e74ea17..7b6bb0d 100644 --- a/drivers/clocksource/timer-nps.c +++ b/drivers/clocksource/timer-nps.c @@ -110,9 +110,9 @@ static int __init nps_setup_clocksource(struct device_node *node) return ret; } -CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", +TIMER_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", nps_setup_clocksource); -CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clk_src, "ezchip,nps400-timer1", +TIMER_OF_DECLARE(ezchip_nps400_clk_src, "ezchip,nps400-timer1", nps_setup_clocksource); #ifdef CONFIG_EZNPS_MTM_EXT @@ -279,6 +279,6 @@ static int __init nps_setup_clockevent(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clk_evt, "ezchip,nps400-timer0", +TIMER_OF_DECLARE(ezchip_nps400_clk_evt, "ezchip,nps400-timer0", nps_setup_clockevent); #endif /* CONFIG_EZNPS_MTM_EXT */ diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c new file mode 100644 index 0000000..f6e7491 --- /dev/null +++ b/drivers/clocksource/timer-of.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2017, Linaro Ltd. All rights reserved. + * + * Author: Daniel Lezcano <daniel.lezcano@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> + +#include "timer-of.h" + +static __init void timer_irq_exit(struct of_timer_irq *of_irq) +{ + struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); + + struct clock_event_device *clkevt = &to->clkevt; + + of_irq->percpu ? free_percpu_irq(of_irq->irq, clkevt) : + free_irq(of_irq->irq, clkevt); +} + +static __init int timer_irq_init(struct device_node *np, + struct of_timer_irq *of_irq) +{ + int ret; + struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); + struct clock_event_device *clkevt = &to->clkevt; + + of_irq->irq = of_irq->name ? of_irq_get_byname(np, of_irq->name): + irq_of_parse_and_map(np, of_irq->index); + if (!of_irq->irq) { + pr_err("Failed to map interrupt for %s\n", np->full_name); + return -EINVAL; + } + + ret = of_irq->percpu ? + request_percpu_irq(of_irq->irq, of_irq->handler, + np->full_name, clkevt) : + request_irq(of_irq->irq, of_irq->handler, + of_irq->flags ? of_irq->flags : IRQF_TIMER, + np->full_name, clkevt); + if (ret) { + pr_err("Failed to request irq %d for %s\n", of_irq->irq, + np->full_name); + return ret; + } + + clkevt->irq = of_irq->irq; + + return 0; +} + +static __init void timer_clk_exit(struct of_timer_clk *of_clk) +{ + of_clk->rate = 0; + clk_disable_unprepare(of_clk->clk); + clk_put(of_clk->clk); +} + +static __init int timer_clk_init(struct device_node *np, + struct of_timer_clk *of_clk) +{ + int ret; + + of_clk->clk = of_clk->name ? of_clk_get_by_name(np, of_clk->name) : + of_clk_get(np, of_clk->index); + if (IS_ERR(of_clk->clk)) { + pr_err("Failed to get clock for %s\n", np->full_name); + return PTR_ERR(of_clk->clk); + } + + ret = clk_prepare_enable(of_clk->clk); + if (ret) { + pr_err("Failed for enable clock for %s\n", np->full_name); + goto out_clk_put; + } + + of_clk->rate = clk_get_rate(of_clk->clk); + if (!of_clk->rate) { + ret = -EINVAL; + pr_err("Failed to get clock rate for %s\n", np->full_name); + goto out_clk_disable; + } + + of_clk->period = DIV_ROUND_UP(of_clk->rate, HZ); +out: + return ret; + +out_clk_disable: + clk_disable_unprepare(of_clk->clk); +out_clk_put: + clk_put(of_clk->clk); + + goto out; +} + +static __init void timer_base_exit(struct of_timer_base *of_base) +{ + iounmap(of_base->base); +} + +static __init int timer_base_init(struct device_node *np, + struct of_timer_base *of_base) +{ + const char *name = of_base->name ? of_base->name : np->full_name; + + of_base->base = of_io_request_and_map(np, of_base->index, name); + if (!of_base->base) { + pr_err("Failed to iomap (%s)\n", name); + return -ENXIO; + } + + return 0; +} + +int __init timer_of_init(struct device_node *np, struct timer_of *to) +{ + int ret = -EINVAL; + int flags = 0; + + if (to->flags & TIMER_OF_BASE) { + ret = timer_base_init(np, &to->of_base); + if (ret) + goto out_fail; + flags |= TIMER_OF_BASE; + } + + if (to->flags & TIMER_OF_CLOCK) { + ret = timer_clk_init(np, &to->of_clk); + if (ret) + goto out_fail; + flags |= TIMER_OF_CLOCK; + } + + if (to->flags & TIMER_OF_IRQ) { + ret = timer_irq_init(np, &to->of_irq); + if (ret) + goto out_fail; + flags |= TIMER_OF_IRQ; + } + + if (!to->clkevt.name) + to->clkevt.name = np->name; + return ret; + +out_fail: + if (flags & TIMER_OF_IRQ) + timer_irq_exit(&to->of_irq); + + if (flags & TIMER_OF_CLOCK) + timer_clk_exit(&to->of_clk); + + if (flags & TIMER_OF_BASE) + timer_base_exit(&to->of_base); + return ret; +} diff --git a/drivers/clocksource/timer-of.h b/drivers/clocksource/timer-of.h new file mode 100644 index 0000000..e0d7272 --- /dev/null +++ b/drivers/clocksource/timer-of.h @@ -0,0 +1,69 @@ +#ifndef __TIMER_OF_H__ +#define __TIMER_OF_H__ + +#include <linux/clockchips.h> + +#define TIMER_OF_BASE 0x1 +#define TIMER_OF_CLOCK 0x2 +#define TIMER_OF_IRQ 0x4 + +struct of_timer_irq { + int irq; + int index; + int percpu; + const char *name; + unsigned long flags; + irq_handler_t handler; +}; + +struct of_timer_base { + void __iomem *base; + const char *name; + int index; +}; + +struct of_timer_clk { + struct clk *clk; + const char *name; + int index; + unsigned long rate; + unsigned long period; +}; + +struct timer_of { + unsigned int flags; + struct clock_event_device clkevt; + struct of_timer_base of_base; + struct of_timer_irq of_irq; + struct of_timer_clk of_clk; + void *private_data; +}; + +static inline struct timer_of *to_timer_of(struct clock_event_device *clkevt) +{ + return container_of(clkevt, struct timer_of, clkevt); +} + +static inline void __iomem *timer_of_base(struct timer_of *to) +{ + return to->of_base.base; +} + +static inline int timer_of_irq(struct timer_of *to) +{ + return to->of_irq.irq; +} + +static inline unsigned long timer_of_rate(struct timer_of *to) +{ + return to->of_clk.rate; +} + +static inline unsigned long timer_of_period(struct timer_of *to) +{ + return to->of_clk.period; +} + +extern int __init timer_of_init(struct device_node *np, + struct timer_of *to); +#endif diff --git a/drivers/clocksource/timer-oxnas-rps.c b/drivers/clocksource/timer-oxnas-rps.c index d630bf4..eed6fef 100644 --- a/drivers/clocksource/timer-oxnas-rps.c +++ b/drivers/clocksource/timer-oxnas-rps.c @@ -293,7 +293,7 @@ err_alloc: return ret; } -CLOCKSOURCE_OF_DECLARE(ox810se_rps, +TIMER_OF_DECLARE(ox810se_rps, "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); -CLOCKSOURCE_OF_DECLARE(ox820_rps, +TIMER_OF_DECLARE(ox820_rps, "oxsemi,ox820se-rps-timer", oxnas_rps_timer_init); diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index b4122ed..20ff33b 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -245,5 +245,5 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(sirfsoc_prima2_timer, +TIMER_OF_DECLARE(sirfsoc_prima2_timer, "sirf,prima2-tick", sirfsoc_prima2_timer_init); diff --git a/drivers/clocksource/clksrc-probe.c b/drivers/clocksource/timer-probe.c index ac701ff..da81e5d 100644 --- a/drivers/clocksource/clksrc-probe.c +++ b/drivers/clocksource/timer-probe.c @@ -19,20 +19,20 @@ #include <linux/of.h> #include <linux/clocksource.h> -extern struct of_device_id __clksrc_of_table[]; +extern struct of_device_id __timer_of_table[]; -static const struct of_device_id __clksrc_of_table_sentinel - __used __section(__clksrc_of_table_end); +static const struct of_device_id __timer_of_table_sentinel + __used __section(__timer_of_table_end); -void __init clocksource_probe(void) +void __init timer_probe(void) { struct device_node *np; const struct of_device_id *match; of_init_fn_1_ret init_func_ret; - unsigned clocksources = 0; + unsigned timers = 0; int ret; - for_each_matching_node_and_match(np, __clksrc_of_table, &match) { + for_each_matching_node_and_match(np, __timer_of_table, &match) { if (!of_device_is_available(np)) continue; @@ -45,11 +45,11 @@ void __init clocksource_probe(void) continue; } - clocksources++; + timers++; } - clocksources += acpi_probe_device_table(clksrc); + timers += acpi_probe_device_table(timer); - if (!clocksources) - pr_crit("%s: no matching clocksources found\n", __func__); + if (!timers) + pr_crit("%s: no matching timers found\n", __func__); } diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index 2d575a8c..3ac9dec 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -287,7 +287,7 @@ err: iounmap(base); return ret; } -CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); +TIMER_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); static int __init integrator_cp_of_init(struct device_node *np) { @@ -335,4 +335,4 @@ err: iounmap(base); return ret; } -CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); +TIMER_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index 1b2574c..174d1243 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -187,4 +187,4 @@ err_clk_get: return ret; } -CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init); +TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init); diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index c4656c4..2a3fe83 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -359,7 +359,7 @@ static int __init sun5i_timer_init(struct device_node *node) return sun5i_setup_clockevent(node, timer_base, clk, irq); } -CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer", +TIMER_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer", sun5i_timer_init); -CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", +TIMER_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", sun5i_timer_init); diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c index 6240677..880a861 100644 --- a/drivers/clocksource/timer-ti-32k.c +++ b/drivers/clocksource/timer-ti-32k.c @@ -124,5 +124,5 @@ static int __init ti_32k_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k", +TIMER_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k", ti_32k_timer_init); diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c index 704e40c..be34b11 100644 --- a/drivers/clocksource/timer-u300.c +++ b/drivers/clocksource/timer-u300.c @@ -458,5 +458,5 @@ static int __init u300_timer_init_of(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(u300_timer, "stericsson,u300-apptimer", +TIMER_OF_DECLARE(u300_timer, "stericsson,u300-apptimer", u300_timer_init_of); diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c index 220b490..39725d3 100644 --- a/drivers/clocksource/versatile.c +++ b/drivers/clocksource/versatile.c @@ -38,7 +38,7 @@ static int __init versatile_sched_clock_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg", +TIMER_OF_DECLARE(vexpress, "arm,vexpress-sysreg", versatile_sched_clock_init); -CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg", +TIMER_OF_DECLARE(versatile, "arm,versatile-sysreg", versatile_sched_clock_init); diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c index e0849e2..0f92089 100644 --- a/drivers/clocksource/vf_pit_timer.c +++ b/drivers/clocksource/vf_pit_timer.c @@ -201,4 +201,4 @@ static int __init pit_timer_init(struct device_node *np) return pit_clockevent_init(clk_rate, irq); } -CLOCKSOURCE_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); +TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index d02b510..e0f7489 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -165,4 +165,4 @@ static int __init vt8500_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); +TIMER_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c index 9a53f5e..a6a0338 100644 --- a/drivers/clocksource/zevio-timer.c +++ b/drivers/clocksource/zevio-timer.c @@ -215,4 +215,4 @@ static int __init zevio_timer_init(struct device_node *node) return zevio_timer_add(node); } -CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_init); +TIMER_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_init); diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h deleted file mode 100644 index a2508a8..0000000 --- a/include/asm-generic/siginfo.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _ASM_GENERIC_SIGINFO_H -#define _ASM_GENERIC_SIGINFO_H - -#include <uapi/asm-generic/siginfo.h> - -#define __SI_MASK 0xffff0000u -#define __SI_KILL (0 << 16) -#define __SI_TIMER (1 << 16) -#define __SI_POLL (2 << 16) -#define __SI_FAULT (3 << 16) -#define __SI_CHLD (4 << 16) -#define __SI_RT (5 << 16) -#define __SI_MESGQ (6 << 16) -#define __SI_SYS (7 << 16) -#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) - -struct siginfo; -void do_schedule_next_timer(struct siginfo *info); - -extern int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); - -#endif diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 314a0b9..0d64658 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -172,8 +172,7 @@ KEEP(*(__##name##_of_table)) \ KEEP(*(__##name##_of_table_end)) -#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) -#define CLKEVT_OF_TABLES() OF_TABLE(CONFIG_CLKEVT_OF, clkevt) +#define TIMER_OF_TABLES() OF_TABLE(CONFIG_TIMER_OF, timer) #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) #define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) #define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) @@ -557,15 +556,15 @@ MEM_DISCARD(init.rodata) \ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ - CLKSRC_OF_TABLES() \ - CLKEVT_OF_TABLES() \ + TIMER_OF_TABLES() \ IOMMU_OF_TABLES() \ CPU_METHOD_OF_TABLES() \ CPUIDLE_METHOD_OF_TABLES() \ KERNEL_DTB() \ IRQCHIP_OF_MATCH_TABLE() \ ACPI_PROBE_TABLE(irqchip) \ - ACPI_PROBE_TABLE(clksrc) \ + ACPI_PROBE_TABLE(timer) \ + ACPI_PROBE_TABLE(iort) \ EARLYCON_TABLE() #define INIT_TEXT \ diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index acc9ce0..a116926 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -223,13 +223,4 @@ 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); -#else -static inline int clockevent_probe(void) { return 0; } -#endif - #endif /* _LINUX_CLOCKCHIPS_H */ diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 8149045..a78cb18 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -250,16 +250,19 @@ extern int clocksource_mmio_init(void __iomem *, const char *, extern int clocksource_i8253_init(void); +#define TIMER_OF_DECLARE(name, compat, fn) \ + OF_DECLARE_1_RET(timer, name, compat, fn) + #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ - OF_DECLARE_1_RET(clksrc, name, compat, fn) + TIMER_OF_DECLARE(name, compat, fn) -#ifdef CONFIG_CLKSRC_PROBE -extern void clocksource_probe(void); +#ifdef CONFIG_TIMER_PROBE +extern void timer_probe(void); #else -static inline void clocksource_probe(void) {} +static inline void timer_probe(void) {} #endif -#define CLOCKSOURCE_ACPI_DECLARE(name, table_id, fn) \ - ACPI_DECLARE_PROBE_ENTRY(clksrc, name, table_id, 0, NULL, 0, fn) +#define TIMER_ACPI_DECLARE(name, table_id, fn) \ + ACPI_DECLARE_PROBE_ENTRY(timer, name, table_id, 0, NULL, 0, fn) #endif /* _LINUX_CLOCKSOURCE_H */ diff --git a/include/linux/compat.h b/include/linux/compat.h index 1c5f315..425563c 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -94,6 +94,10 @@ struct compat_itimerval { struct compat_timeval it_value; }; +struct itimerval; +int get_compat_itimerval(struct itimerval *, const struct compat_itimerval __user *); +int put_compat_itimerval(struct compat_itimerval __user *, const struct itimerval *); + struct compat_tms { compat_clock_t tms_utime; compat_clock_t tms_stime; @@ -128,6 +132,10 @@ struct compat_timex { compat_int_t:32; compat_int_t:32; compat_int_t:32; }; +struct timex; +int compat_get_timex(struct timex *, const struct compat_timex __user *); +int compat_put_timex(struct compat_timex __user *, const struct timex *); + #define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW) typedef struct { diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 8c5b10e..255edd5 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -452,11 +452,11 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer, } /* Precise sleep: */ -extern long hrtimer_nanosleep(struct timespec64 *rqtp, - struct timespec __user *rmtp, + +extern int nanosleep_copyout(struct restart_block *, struct timespec *); +extern long hrtimer_nanosleep(const struct timespec64 *rqtp, const enum hrtimer_mode mode, const clockid_t clockid); -extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *tsk); diff --git a/include/linux/posix-clock.h b/include/linux/posix-clock.h index 83b22ae..38d8225 100644 --- a/include/linux/posix-clock.h +++ b/include/linux/posix-clock.h @@ -42,12 +42,6 @@ struct posix_clock; * @clock_gettime: Read the current time * @clock_getres: Get the clock resolution * @clock_settime: Set the current time value - * @timer_create: Create a new timer - * @timer_delete: Remove a previously created timer - * @timer_gettime: Get remaining time and interval of a timer - * @timer_settime: Set a timer's initial expiration and interval - * @fasync: Optional character device fasync method - * @mmap: Optional character device mmap method * @open: Optional character device open method * @release: Optional character device release method * @ioctl: Optional character device ioctl method @@ -66,28 +60,12 @@ struct posix_clock_operations { int (*clock_settime)(struct posix_clock *pc, const struct timespec64 *ts); - int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit); - - int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit); - - void (*timer_gettime)(struct posix_clock *pc, - struct k_itimer *kit, struct itimerspec64 *tsp); - - int (*timer_settime)(struct posix_clock *pc, - struct k_itimer *kit, int flags, - struct itimerspec64 *tsp, struct itimerspec64 *old); /* * Optional character device methods: */ - int (*fasync) (struct posix_clock *pc, - int fd, struct file *file, int on); - long (*ioctl) (struct posix_clock *pc, unsigned int cmd, unsigned long arg); - int (*mmap) (struct posix_clock *pc, - struct vm_area_struct *vma); - int (*open) (struct posix_clock *pc, fmode_t f_mode); uint (*poll) (struct posix_clock *pc, diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 8c1e43a..29f1b7f 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -7,6 +7,7 @@ #include <linux/timex.h> #include <linux/alarmtimer.h> +struct siginfo; struct cpu_timer_list { struct list_head entry; @@ -48,81 +49,69 @@ struct cpu_timer_list { #define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) #define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3)) -/* POSIX.1b interval timer structure. */ -struct k_itimer { - struct list_head list; /* free/ allocate list */ - struct hlist_node t_hash; - spinlock_t it_lock; - clockid_t it_clock; /* which timer type */ - timer_t it_id; /* timer id */ - int it_overrun; /* overrun on pending signal */ - int it_overrun_last; /* overrun on last delivered signal */ - int it_requeue_pending; /* waiting to requeue this timer */ #define REQUEUE_PENDING 1 - int it_sigev_notify; /* notify word of sigevent struct */ - struct signal_struct *it_signal; + +/** + * struct k_itimer - POSIX.1b interval timer structure. + * @list: List head for binding the timer to signals->posix_timers + * @t_hash: Entry in the posix timer hash table + * @it_lock: Lock protecting the timer + * @kclock: Pointer to the k_clock struct handling this timer + * @it_clock: The posix timer clock id + * @it_id: The posix timer id for identifying the timer + * @it_active: Marker that timer is active + * @it_overrun: The overrun counter for pending signals + * @it_overrun_last: The overrun at the time of the last delivered signal + * @it_requeue_pending: Indicator that timer waits for being requeued on + * signal delivery + * @it_sigev_notify: The notify word of sigevent struct for signal delivery + * @it_interval: The interval for periodic timers + * @it_signal: Pointer to the creators signal struct + * @it_pid: The pid of the process/task targeted by the signal + * @it_process: The task to wakeup on clock_nanosleep (CPU timers) + * @sigq: Pointer to preallocated sigqueue + * @it: Union representing the various posix timer type + * internals. Also used for rcu freeing the timer. + */ +struct k_itimer { + struct list_head list; + struct hlist_node t_hash; + spinlock_t it_lock; + const struct k_clock *kclock; + clockid_t it_clock; + timer_t it_id; + int it_active; + int it_overrun; + int it_overrun_last; + int it_requeue_pending; + int it_sigev_notify; + ktime_t it_interval; + struct signal_struct *it_signal; union { - struct pid *it_pid; /* pid of process to send signal to */ - struct task_struct *it_process; /* for clock_nanosleep */ + struct pid *it_pid; + struct task_struct *it_process; }; - struct sigqueue *sigq; /* signal queue entry. */ + struct sigqueue *sigq; union { struct { - struct hrtimer timer; - ktime_t interval; + struct hrtimer timer; } real; - struct cpu_timer_list cpu; + struct cpu_timer_list cpu; struct { - unsigned int clock; - unsigned int node; - unsigned long incr; - unsigned long expires; - } mmtimer; - struct { - struct alarm alarmtimer; - ktime_t interval; + struct alarm alarmtimer; } alarm; - struct rcu_head rcu; + struct rcu_head rcu; } it; }; -struct k_clock { - int (*clock_getres) (const clockid_t which_clock, struct timespec64 *tp); - int (*clock_set) (const clockid_t which_clock, - const struct timespec64 *tp); - int (*clock_get) (const clockid_t which_clock, struct timespec64 *tp); - int (*clock_adj) (const clockid_t which_clock, struct timex *tx); - int (*timer_create) (struct k_itimer *timer); - int (*nsleep) (const clockid_t which_clock, int flags, - struct timespec64 *, struct timespec __user *); - long (*nsleep_restart) (struct restart_block *restart_block); - int (*timer_set) (struct k_itimer *timr, int flags, - struct itimerspec64 *new_setting, - struct itimerspec64 *old_setting); - int (*timer_del) (struct k_itimer *timr); -#define TIMER_RETRY 1 - void (*timer_get) (struct k_itimer *timr, - struct itimerspec64 *cur_setting); -}; - -extern struct k_clock clock_posix_cpu; -extern struct k_clock clock_posix_dynamic; - -void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock); - -/* function to call to trigger timer event */ -int posix_timer_event(struct k_itimer *timr, int si_private); - -void posix_cpu_timer_schedule(struct k_itimer *timer); - void run_posix_cpu_timers(struct task_struct *task); void posix_cpu_timers_exit(struct task_struct *task); void posix_cpu_timers_exit_group(struct task_struct *task); void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, u64 *newval, u64 *oldval); -long clock_nanosleep_restart(struct restart_block *restart_block); - void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new); +void posixtimer_rearm(struct siginfo *info); + #endif diff --git a/include/linux/restart_block.h b/include/linux/restart_block.h index 0d905d8..19df8422 100644 --- a/include/linux/restart_block.h +++ b/include/linux/restart_block.h @@ -11,6 +11,14 @@ struct timespec; struct compat_timespec; struct pollfd; +enum timespec_type { + TT_NONE = 0, + TT_NATIVE = 1, +#ifdef CONFIG_COMPAT + TT_COMPAT = 2, +#endif +}; + /* * System call restart block. */ @@ -29,10 +37,13 @@ struct restart_block { /* For nanosleep */ struct { clockid_t clockid; - struct timespec __user *rmtp; + enum timespec_type type; + union { + struct timespec __user *rmtp; #ifdef CONFIG_COMPAT - struct compat_timespec __user *compat_rmtp; + struct compat_timespec __user *compat_rmtp; #endif + }; u64 expires; } nanosleep; /* For poll */ diff --git a/include/linux/signal.h b/include/linux/signal.h index 1f5a166..a39fedd 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -3,16 +3,13 @@ #include <linux/bug.h> #include <linux/signal_types.h> +#include <linux/string.h> struct task_struct; /* for sysctl */ extern int print_fatal_signals; -#ifndef HAVE_ARCH_COPY_SIGINFO - -#include <linux/string.h> - static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) { if (from->si_code < 0) @@ -22,7 +19,7 @@ static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld)); } -#endif +int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); /* * Define some primitives to manipulate sigset_t. diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index f7043cc..0a0a53d 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -51,7 +51,7 @@ struct tk_read_base { * @clock_was_set_seq: The sequence number of clock was set events * @cs_was_changed_seq: The sequence number of clocksource change events * @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second - * @raw_time: Monotonic raw base time in timespec64 format + * @raw_sec: CLOCK_MONOTONIC_RAW time in seconds * @cycle_interval: Number of clock cycles in one NTP interval * @xtime_interval: Number of clock shifted nano seconds in one NTP * interval. @@ -93,7 +93,7 @@ struct timekeeper { unsigned int clock_was_set_seq; u8 cs_was_changed_seq; ktime_t next_leap_ktime; - struct timespec64 raw_time; + u64 raw_sec; /* The following members are for timekeeping internal use */ u64 cycle_interval; diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h index 1abaf62..9c4eca6 100644 --- a/include/uapi/asm-generic/siginfo.h +++ b/include/uapi/asm-generic/siginfo.h @@ -151,7 +151,18 @@ typedef struct siginfo { #define si_arch _sifields._sigsys._arch #endif -#ifndef __KERNEL__ +#ifdef __KERNEL__ +#define __SI_MASK 0xffff0000u +#define __SI_KILL (0 << 16) +#define __SI_TIMER (1 << 16) +#define __SI_POLL (2 << 16) +#define __SI_FAULT (3 << 16) +#define __SI_CHLD (4 << 16) +#define __SI_RT (5 << 16) +#define __SI_MESGQ (6 << 16) +#define __SI_SYS (7 << 16) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) +#else /* __KERNEL__ */ #define __SI_KILL 0 #define __SI_TIMER 0 #define __SI_POLL 0 @@ -161,7 +172,7 @@ typedef struct siginfo { #define __SI_MESGQ 0 #define __SI_SYS 0 #define __SI_CODE(T,N) (N) -#endif +#endif /* __KERNEL__ */ /* * si_code values diff --git a/include/uapi/linux/time.h b/include/uapi/linux/time.h index e75e1b6..09299fc 100644 --- a/include/uapi/linux/time.h +++ b/include/uapi/linux/time.h @@ -54,7 +54,11 @@ struct itimerval { #define CLOCK_BOOTTIME 7 #define CLOCK_REALTIME_ALARM 8 #define CLOCK_BOOTTIME_ALARM 9 -#define CLOCK_SGI_CYCLE 10 /* Hardware specific */ +/* + * The driver implementing this got removed. The clock ID is kept as a + * place holder. Do not reuse! + */ +#define CLOCK_SGI_CYCLE 10 #define CLOCK_TAI 11 #define MAX_CLOCKS 16 diff --git a/kernel/compat.c b/kernel/compat.c index 933bcb3..ebd8bdc 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -30,100 +30,66 @@ #include <linux/uaccess.h> -static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp) +int compat_get_timex(struct timex *txc, const struct compat_timex __user *utp) { - memset(txc, 0, sizeof(struct timex)); - - if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) || - __get_user(txc->modes, &utp->modes) || - __get_user(txc->offset, &utp->offset) || - __get_user(txc->freq, &utp->freq) || - __get_user(txc->maxerror, &utp->maxerror) || - __get_user(txc->esterror, &utp->esterror) || - __get_user(txc->status, &utp->status) || - __get_user(txc->constant, &utp->constant) || - __get_user(txc->precision, &utp->precision) || - __get_user(txc->tolerance, &utp->tolerance) || - __get_user(txc->time.tv_sec, &utp->time.tv_sec) || - __get_user(txc->time.tv_usec, &utp->time.tv_usec) || - __get_user(txc->tick, &utp->tick) || - __get_user(txc->ppsfreq, &utp->ppsfreq) || - __get_user(txc->jitter, &utp->jitter) || - __get_user(txc->shift, &utp->shift) || - __get_user(txc->stabil, &utp->stabil) || - __get_user(txc->jitcnt, &utp->jitcnt) || - __get_user(txc->calcnt, &utp->calcnt) || - __get_user(txc->errcnt, &utp->errcnt) || - __get_user(txc->stbcnt, &utp->stbcnt)) - return -EFAULT; + struct compat_timex tx32; - return 0; -} - -static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc) -{ - if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) || - __put_user(txc->modes, &utp->modes) || - __put_user(txc->offset, &utp->offset) || - __put_user(txc->freq, &utp->freq) || - __put_user(txc->maxerror, &utp->maxerror) || - __put_user(txc->esterror, &utp->esterror) || - __put_user(txc->status, &utp->status) || - __put_user(txc->constant, &utp->constant) || - __put_user(txc->precision, &utp->precision) || - __put_user(txc->tolerance, &utp->tolerance) || - __put_user(txc->time.tv_sec, &utp->time.tv_sec) || - __put_user(txc->time.tv_usec, &utp->time.tv_usec) || - __put_user(txc->tick, &utp->tick) || - __put_user(txc->ppsfreq, &utp->ppsfreq) || - __put_user(txc->jitter, &utp->jitter) || - __put_user(txc->shift, &utp->shift) || - __put_user(txc->stabil, &utp->stabil) || - __put_user(txc->jitcnt, &utp->jitcnt) || - __put_user(txc->calcnt, &utp->calcnt) || - __put_user(txc->errcnt, &utp->errcnt) || - __put_user(txc->stbcnt, &utp->stbcnt) || - __put_user(txc->tai, &utp->tai)) + if (copy_from_user(&tx32, utp, sizeof(struct compat_timex))) return -EFAULT; - return 0; -} -COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv, - struct timezone __user *, tz) -{ - if (tv) { - struct timeval ktv; - do_gettimeofday(&ktv); - if (compat_put_timeval(&ktv, tv)) - return -EFAULT; - } - if (tz) { - if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) - return -EFAULT; - } + txc->modes = tx32.modes; + txc->offset = tx32.offset; + txc->freq = tx32.freq; + txc->maxerror = tx32.maxerror; + txc->esterror = tx32.esterror; + txc->status = tx32.status; + txc->constant = tx32.constant; + txc->precision = tx32.precision; + txc->tolerance = tx32.tolerance; + txc->time.tv_sec = tx32.time.tv_sec; + txc->time.tv_usec = tx32.time.tv_usec; + txc->tick = tx32.tick; + txc->ppsfreq = tx32.ppsfreq; + txc->jitter = tx32.jitter; + txc->shift = tx32.shift; + txc->stabil = tx32.stabil; + txc->jitcnt = tx32.jitcnt; + txc->calcnt = tx32.calcnt; + txc->errcnt = tx32.errcnt; + txc->stbcnt = tx32.stbcnt; return 0; } -COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv, - struct timezone __user *, tz) -{ - struct timespec64 new_ts; - struct timeval user_tv; - struct timezone new_tz; - - if (tv) { - if (compat_get_timeval(&user_tv, tv)) - return -EFAULT; - new_ts.tv_sec = user_tv.tv_sec; - new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC; - } - if (tz) { - if (copy_from_user(&new_tz, tz, sizeof(*tz))) - return -EFAULT; - } - - return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL); +int compat_put_timex(struct compat_timex __user *utp, const struct timex *txc) +{ + struct compat_timex tx32; + + memset(&tx32, 0, sizeof(struct compat_timex)); + tx32.modes = txc->modes; + tx32.offset = txc->offset; + tx32.freq = txc->freq; + tx32.maxerror = txc->maxerror; + tx32.esterror = txc->esterror; + tx32.status = txc->status; + tx32.constant = txc->constant; + tx32.precision = txc->precision; + tx32.tolerance = txc->tolerance; + tx32.time.tv_sec = txc->time.tv_sec; + tx32.time.tv_usec = txc->time.tv_usec; + tx32.tick = txc->tick; + tx32.ppsfreq = txc->ppsfreq; + tx32.jitter = txc->jitter; + tx32.shift = txc->shift; + tx32.stabil = txc->stabil; + tx32.jitcnt = txc->jitcnt; + tx32.calcnt = txc->calcnt; + tx32.errcnt = txc->errcnt; + tx32.stbcnt = txc->stbcnt; + tx32.tai = txc->tai; + if (copy_to_user(utp, &tx32, sizeof(struct compat_timex))) + return -EFAULT; + return 0; } static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv) @@ -213,141 +179,28 @@ int compat_convert_timespec(struct timespec __user **kts, return 0; } -static long compat_nanosleep_restart(struct restart_block *restart) -{ - struct compat_timespec __user *rmtp; - struct timespec rmt; - mm_segment_t oldfs; - long ret; - - restart->nanosleep.rmtp = (struct timespec __user *) &rmt; - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = hrtimer_nanosleep_restart(restart); - set_fs(oldfs); - - if (ret == -ERESTART_RESTARTBLOCK) { - rmtp = restart->nanosleep.compat_rmtp; - - if (rmtp && compat_put_timespec(&rmt, rmtp)) - return -EFAULT; - } - - return ret; -} - -COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, - struct compat_timespec __user *, rmtp) +int get_compat_itimerval(struct itimerval *o, const struct compat_itimerval __user *i) { - struct timespec tu, rmt; - struct timespec64 tu64; - mm_segment_t oldfs; - long ret; + struct compat_itimerval v32; - if (compat_get_timespec(&tu, rqtp)) + if (copy_from_user(&v32, i, sizeof(struct compat_itimerval))) return -EFAULT; - - tu64 = timespec_to_timespec64(tu); - if (!timespec64_valid(&tu64)) - return -EINVAL; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = hrtimer_nanosleep(&tu64, - rmtp ? (struct timespec __user *)&rmt : NULL, - HRTIMER_MODE_REL, CLOCK_MONOTONIC); - set_fs(oldfs); - - /* - * hrtimer_nanosleep() can only return 0 or - * -ERESTART_RESTARTBLOCK here because: - * - * - we call it with HRTIMER_MODE_REL and therefor exclude the - * -ERESTARTNOHAND return path. - * - * - we supply the rmtp argument from the task stack (due to - * the necessary compat conversion. So the update cannot - * fail, which excludes the -EFAULT return path as well. If - * it fails nevertheless we have a bigger problem and wont - * reach this place anymore. - * - * - if the return value is 0, we do not have to update rmtp - * because there is no remaining time. - * - * We check for -ERESTART_RESTARTBLOCK nevertheless if the - * core implementation decides to return random nonsense. - */ - if (ret == -ERESTART_RESTARTBLOCK) { - struct restart_block *restart = ¤t->restart_block; - - restart->fn = compat_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - - if (rmtp && compat_put_timespec(&rmt, rmtp)) - return -EFAULT; - } - return ret; -} - -static inline long get_compat_itimerval(struct itimerval *o, - struct compat_itimerval __user *i) -{ - return (!access_ok(VERIFY_READ, i, sizeof(*i)) || - (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | - __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | - __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | - __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); -} - -static inline long put_compat_itimerval(struct compat_itimerval __user *o, - struct itimerval *i) -{ - return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || - (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | - __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | - __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | - __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); -} - -asmlinkage long sys_ni_posix_timers(void); - -COMPAT_SYSCALL_DEFINE2(getitimer, int, which, - struct compat_itimerval __user *, it) -{ - struct itimerval kit; - int error; - - if (!IS_ENABLED(CONFIG_POSIX_TIMERS)) - return sys_ni_posix_timers(); - - error = do_getitimer(which, &kit); - if (!error && put_compat_itimerval(it, &kit)) - error = -EFAULT; - return error; + o->it_interval.tv_sec = v32.it_interval.tv_sec; + o->it_interval.tv_usec = v32.it_interval.tv_usec; + o->it_value.tv_sec = v32.it_value.tv_sec; + o->it_value.tv_usec = v32.it_value.tv_usec; + return 0; } -COMPAT_SYSCALL_DEFINE3(setitimer, int, which, - struct compat_itimerval __user *, in, - struct compat_itimerval __user *, out) +int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerval *i) { - struct itimerval kin, kout; - int error; - - if (!IS_ENABLED(CONFIG_POSIX_TIMERS)) - return sys_ni_posix_timers(); + struct compat_itimerval v32; - if (in) { - if (get_compat_itimerval(&kin, in)) - return -EFAULT; - } else - memset(&kin, 0, sizeof(kin)); - - error = do_setitimer(which, &kin, out ? &kout : NULL); - if (error || !out) - return error; - if (put_compat_itimerval(out, &kout)) - return -EFAULT; - return 0; + v32.it_interval.tv_sec = i->it_interval.tv_sec; + v32.it_interval.tv_usec = i->it_interval.tv_usec; + v32.it_value.tv_sec = i->it_value.tv_sec; + v32.it_value.tv_usec = i->it_value.tv_usec; + return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0; } static compat_clock_t clock_t_to_compat_clock_t(clock_t x) @@ -689,193 +542,6 @@ int put_compat_itimerspec(struct compat_itimerspec __user *dst, return 0; } -COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock, - struct compat_sigevent __user *, timer_event_spec, - timer_t __user *, created_timer_id) -{ - struct sigevent __user *event = NULL; - - if (timer_event_spec) { - struct sigevent kevent; - - event = compat_alloc_user_space(sizeof(*event)); - if (get_compat_sigevent(&kevent, timer_event_spec) || - copy_to_user(event, &kevent, sizeof(*event))) - return -EFAULT; - } - - return sys_timer_create(which_clock, event, created_timer_id); -} - -COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, - struct compat_itimerspec __user *, new, - struct compat_itimerspec __user *, old) -{ - long err; - mm_segment_t oldfs; - struct itimerspec newts, oldts; - - if (!new) - return -EINVAL; - if (get_compat_itimerspec(&newts, new)) - return -EFAULT; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_timer_settime(timer_id, flags, - (struct itimerspec __user *) &newts, - (struct itimerspec __user *) &oldts); - set_fs(oldfs); - if (!err && old && put_compat_itimerspec(old, &oldts)) - return -EFAULT; - return err; -} - -COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, - struct compat_itimerspec __user *, setting) -{ - long err; - mm_segment_t oldfs; - struct itimerspec ts; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_timer_gettime(timer_id, - (struct itimerspec __user *) &ts); - set_fs(oldfs); - if (!err && put_compat_itimerspec(setting, &ts)) - return -EFAULT; - return err; -} - -COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock, - struct compat_timespec __user *, tp) -{ - long err; - mm_segment_t oldfs; - struct timespec ts; - - if (compat_get_timespec(&ts, tp)) - return -EFAULT; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_settime(which_clock, - (struct timespec __user *) &ts); - set_fs(oldfs); - return err; -} - -COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, - struct compat_timespec __user *, tp) -{ - long err; - mm_segment_t oldfs; - struct timespec ts; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_gettime(which_clock, - (struct timespec __user *) &ts); - set_fs(oldfs); - if (!err && compat_put_timespec(&ts, tp)) - return -EFAULT; - return err; -} - -COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, - struct compat_timex __user *, utp) -{ - struct timex txc; - mm_segment_t oldfs; - int err, ret; - - err = compat_get_timex(&txc, utp); - if (err) - return err; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc); - set_fs(oldfs); - - err = compat_put_timex(utp, &txc); - if (err) - return err; - - return ret; -} - -COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, - struct compat_timespec __user *, tp) -{ - long err; - mm_segment_t oldfs; - struct timespec ts; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_getres(which_clock, - (struct timespec __user *) &ts); - set_fs(oldfs); - if (!err && tp && compat_put_timespec(&ts, tp)) - return -EFAULT; - return err; -} - -static long compat_clock_nanosleep_restart(struct restart_block *restart) -{ - long err; - mm_segment_t oldfs; - struct timespec tu; - struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; - - restart->nanosleep.rmtp = (struct timespec __user *) &tu; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = clock_nanosleep_restart(restart); - set_fs(oldfs); - - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&tu, rmtp)) - return -EFAULT; - - if (err == -ERESTART_RESTARTBLOCK) { - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; -} - -COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, - struct compat_timespec __user *, rqtp, - struct compat_timespec __user *, rmtp) -{ - long err; - mm_segment_t oldfs; - struct timespec in, out; - struct restart_block *restart; - - if (compat_get_timespec(&in, rqtp)) - return -EFAULT; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_nanosleep(which_clock, flags, - (struct timespec __user *) &in, - (struct timespec __user *) &out); - set_fs(oldfs); - - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&out, rmtp)) - return -EFAULT; - - if (err == -ERESTART_RESTARTBLOCK) { - restart = ¤t->restart_block; - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; -} - /* * We currently only need the following fields from the sigevent * structure: sigev_value, sigev_signo, sig_notify and (sometimes @@ -1035,64 +701,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, return ret; } -#ifdef __ARCH_WANT_COMPAT_SYS_TIME - -/* compat_time_t is a 32 bit "long" and needs to get converted. */ - -COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc) -{ - compat_time_t i; - struct timeval tv; - - do_gettimeofday(&tv); - i = tv.tv_sec; - - if (tloc) { - if (put_user(i,tloc)) - return -EFAULT; - } - force_successful_syscall_return(); - return i; -} - -COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr) -{ - struct timespec tv; - int err; - - if (get_user(tv.tv_sec, tptr)) - return -EFAULT; - - tv.tv_nsec = 0; - - err = security_settime(&tv, NULL); - if (err) - return err; - - do_settimeofday(&tv); - return 0; -} - -#endif /* __ARCH_WANT_COMPAT_SYS_TIME */ - -COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp) -{ - struct timex txc; - int err, ret; - - err = compat_get_timex(&txc, utp); - if (err) - return err; - - ret = do_adjtimex(&txc); - - err = compat_put_timex(utp, &txc); - if (err) - return err; - - return ret; -} - #ifdef CONFIG_NUMA COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages, compat_uptr_t __user *, pages32, diff --git a/kernel/signal.c b/kernel/signal.c index 9b28954..35a570f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -39,6 +39,7 @@ #include <linux/compat.h> #include <linux/cn_proc.h> #include <linux/compiler.h> +#include <linux/posix-timers.h> #define CREATE_TRACE_POINTS #include <trace/events/signal.h> @@ -637,7 +638,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) * about to disable them again anyway. */ spin_unlock(&tsk->sighand->siglock); - do_schedule_next_timer(info); + posixtimer_rearm(info); spin_lock(&tsk->sighand->siglock); } #endif diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index ee2f420..c991cf2 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -27,6 +27,9 @@ #include <linux/posix-timers.h> #include <linux/workqueue.h> #include <linux/freezer.h> +#include <linux/compat.h> + +#include "posix-timers.h" #define CREATE_TRACE_POINTS #include <trace/events/alarmtimer.h> @@ -45,11 +48,13 @@ static struct alarm_base { clockid_t base_clockid; } alarm_bases[ALARM_NUMTYPE]; +#if defined(CONFIG_POSIX_TIMERS) || defined(CONFIG_RTC_CLASS) /* freezer information to handle clock_nanosleep triggered wakeups */ static enum alarmtimer_type freezer_alarmtype; static ktime_t freezer_expires; static ktime_t freezer_delta; static DEFINE_SPINLOCK(freezer_delta_lock); +#endif static struct wakeup_source *ws; @@ -307,38 +312,6 @@ static int alarmtimer_resume(struct device *dev) } #endif -static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type) -{ - struct alarm_base *base; - unsigned long flags; - ktime_t delta; - - switch(type) { - case ALARM_REALTIME: - base = &alarm_bases[ALARM_REALTIME]; - type = ALARM_REALTIME_FREEZER; - break; - case ALARM_BOOTTIME: - base = &alarm_bases[ALARM_BOOTTIME]; - type = ALARM_BOOTTIME_FREEZER; - break; - default: - WARN_ONCE(1, "Invalid alarm type: %d\n", type); - return; - } - - delta = ktime_sub(absexp, base->gettime()); - - spin_lock_irqsave(&freezer_delta_lock, flags); - if (!freezer_delta || (delta < freezer_delta)) { - freezer_delta = delta; - freezer_expires = absexp; - freezer_alarmtype = type; - } - spin_unlock_irqrestore(&freezer_delta_lock, flags); -} - - /** * alarm_init - Initialize an alarm structure * @alarm: ptr to alarm to be initialized @@ -488,6 +461,38 @@ u64 alarm_forward_now(struct alarm *alarm, ktime_t interval) } EXPORT_SYMBOL_GPL(alarm_forward_now); +#ifdef CONFIG_POSIX_TIMERS + +static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type) +{ + struct alarm_base *base; + unsigned long flags; + ktime_t delta; + + switch(type) { + case ALARM_REALTIME: + base = &alarm_bases[ALARM_REALTIME]; + type = ALARM_REALTIME_FREEZER; + break; + case ALARM_BOOTTIME: + base = &alarm_bases[ALARM_BOOTTIME]; + type = ALARM_BOOTTIME_FREEZER; + break; + default: + WARN_ONCE(1, "Invalid alarm type: %d\n", type); + return; + } + + delta = ktime_sub(absexp, base->gettime()); + + spin_lock_irqsave(&freezer_delta_lock, flags); + if (!freezer_delta || (delta < freezer_delta)) { + freezer_delta = delta; + freezer_expires = absexp; + freezer_alarmtype = type; + } + spin_unlock_irqrestore(&freezer_delta_lock, flags); +} /** * clock2alarm - helper that converts from clockid to alarmtypes @@ -511,22 +516,26 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid) static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, ktime_t now) { - unsigned long flags; struct k_itimer *ptr = container_of(alarm, struct k_itimer, - it.alarm.alarmtimer); + it.alarm.alarmtimer); enum alarmtimer_restart result = ALARMTIMER_NORESTART; + unsigned long flags; + int si_private = 0; spin_lock_irqsave(&ptr->it_lock, flags); - if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) { - if (IS_ENABLED(CONFIG_POSIX_TIMERS) && - posix_timer_event(ptr, 0) != 0) - ptr->it_overrun++; - } - /* Re-add periodic timers */ - if (ptr->it.alarm.interval) { - ptr->it_overrun += alarm_forward(alarm, now, - ptr->it.alarm.interval); + ptr->it_active = 0; + if (ptr->it_interval) + si_private = ++ptr->it_requeue_pending; + + if (posix_timer_event(ptr, si_private) && ptr->it_interval) { + /* + * Handle ignored signals and rearm the timer. This will go + * away once we handle ignored signals proper. + */ + ptr->it_overrun += alarm_forward_now(alarm, ptr->it_interval); + ++ptr->it_requeue_pending; + ptr->it_active = 1; result = ALARMTIMER_RESTART; } spin_unlock_irqrestore(&ptr->it_lock, flags); @@ -535,6 +544,72 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, } /** + * alarm_timer_rearm - Posix timer callback for rearming timer + * @timr: Pointer to the posixtimer data struct + */ +static void alarm_timer_rearm(struct k_itimer *timr) +{ + struct alarm *alarm = &timr->it.alarm.alarmtimer; + + timr->it_overrun += alarm_forward_now(alarm, timr->it_interval); + alarm_start(alarm, alarm->node.expires); +} + +/** + * alarm_timer_forward - Posix timer callback for forwarding timer + * @timr: Pointer to the posixtimer data struct + * @now: Current time to forward the timer against + */ +static int alarm_timer_forward(struct k_itimer *timr, ktime_t now) +{ + struct alarm *alarm = &timr->it.alarm.alarmtimer; + + return (int) alarm_forward(alarm, timr->it_interval, now); +} + +/** + * alarm_timer_remaining - Posix timer callback to retrieve remaining time + * @timr: Pointer to the posixtimer data struct + * @now: Current time to calculate against + */ +static ktime_t alarm_timer_remaining(struct k_itimer *timr, ktime_t now) +{ + struct alarm *alarm = &timr->it.alarm.alarmtimer; + + return ktime_sub(now, alarm->node.expires); +} + +/** + * alarm_timer_try_to_cancel - Posix timer callback to cancel a timer + * @timr: Pointer to the posixtimer data struct + */ +static int alarm_timer_try_to_cancel(struct k_itimer *timr) +{ + return alarm_try_to_cancel(&timr->it.alarm.alarmtimer); +} + +/** + * alarm_timer_arm - Posix timer callback to arm a timer + * @timr: Pointer to the posixtimer data struct + * @expires: The new expiry time + * @absolute: Expiry value is absolute time + * @sigev_none: Posix timer does not deliver signals + */ +static void alarm_timer_arm(struct k_itimer *timr, ktime_t expires, + bool absolute, bool sigev_none) +{ + struct alarm *alarm = &timr->it.alarm.alarmtimer; + struct alarm_base *base = &alarm_bases[alarm->type]; + + if (!absolute) + expires = ktime_add_safe(expires, base->gettime()); + if (sigev_none) + alarm->node.expires = expires; + else + alarm_start(&timr->it.alarm.alarmtimer, expires); +} + +/** * alarm_clock_getres - posix getres interface * @which_clock: clockid * @tp: timespec to fill @@ -591,97 +666,6 @@ static int alarm_timer_create(struct k_itimer *new_timer) } /** - * alarm_timer_get - posix timer_get interface - * @new_timer: k_itimer pointer - * @cur_setting: itimerspec data to fill - * - * Copies out the current itimerspec data - */ -static void alarm_timer_get(struct k_itimer *timr, - struct itimerspec64 *cur_setting) -{ - ktime_t relative_expiry_time = - alarm_expires_remaining(&(timr->it.alarm.alarmtimer)); - - if (ktime_to_ns(relative_expiry_time) > 0) { - cur_setting->it_value = ktime_to_timespec64(relative_expiry_time); - } else { - cur_setting->it_value.tv_sec = 0; - cur_setting->it_value.tv_nsec = 0; - } - - cur_setting->it_interval = ktime_to_timespec64(timr->it.alarm.interval); -} - -/** - * alarm_timer_del - posix timer_del interface - * @timr: k_itimer pointer to be deleted - * - * Cancels any programmed alarms for the given timer. - */ -static int alarm_timer_del(struct k_itimer *timr) -{ - if (!rtcdev) - return -ENOTSUPP; - - if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0) - return TIMER_RETRY; - - return 0; -} - -/** - * alarm_timer_set - posix timer_set interface - * @timr: k_itimer pointer to be deleted - * @flags: timer flags - * @new_setting: itimerspec to be used - * @old_setting: itimerspec being replaced - * - * Sets the timer to new_setting, and starts the timer. - */ -static int alarm_timer_set(struct k_itimer *timr, int flags, - struct itimerspec64 *new_setting, - struct itimerspec64 *old_setting) -{ - ktime_t exp; - - if (!rtcdev) - return -ENOTSUPP; - - if (flags & ~TIMER_ABSTIME) - return -EINVAL; - - if (old_setting) - alarm_timer_get(timr, old_setting); - - /* If the timer was already set, cancel it */ - if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0) - return TIMER_RETRY; - - /* start the timer */ - timr->it.alarm.interval = timespec64_to_ktime(new_setting->it_interval); - - /* - * Rate limit to the tick as a hot fix to prevent DOS. Will be - * mopped up later. - */ - if (timr->it.alarm.interval < TICK_NSEC) - timr->it.alarm.interval = TICK_NSEC; - - exp = timespec64_to_ktime(new_setting->it_value); - /* Convert (if necessary) to absolute time */ - if (flags != TIMER_ABSTIME) { - ktime_t now; - - now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime(); - exp = ktime_add_safe(now, exp); - } - - alarm_start(&timr->it.alarm.alarmtimer, exp); - return 0; -} - -/** * alarmtimer_nsleep_wakeup - Wakeup function for alarm_timer_nsleep * @alarm: ptr to alarm that fired * @@ -705,8 +689,10 @@ static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm, * * Sets the alarm timer and sleeps until it is fired or interrupted. */ -static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) +static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp, + enum alarmtimer_type type) { + struct restart_block *restart; alarm->data = (void *)current; do { set_current_state(TASK_INTERRUPTIBLE); @@ -719,36 +705,25 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) __set_current_state(TASK_RUNNING); - return (alarm->data == NULL); -} - - -/** - * update_rmtp - Update remaining timespec value - * @exp: expiration time - * @type: timer type - * @rmtp: user pointer to remaining timepsec value - * - * Helper function that fills in rmtp value with time between - * now and the exp value - */ -static int update_rmtp(ktime_t exp, enum alarmtimer_type type, - struct timespec __user *rmtp) -{ - struct timespec rmt; - ktime_t rem; - - rem = ktime_sub(exp, alarm_bases[type].gettime()); - - if (rem <= 0) + if (!alarm->data) return 0; - rmt = ktime_to_timespec(rem); - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; + if (freezing(current)) + alarmtimer_freezerset(absexp, type); + restart = ¤t->restart_block; + if (restart->nanosleep.type != TT_NONE) { + struct timespec rmt; + ktime_t rem; + + rem = ktime_sub(absexp, alarm_bases[type].gettime()); - return 1; + if (rem <= 0) + return 0; + rmt = ktime_to_timespec(rem); + return nanosleep_copyout(restart, &rmt); + } + return -ERESTART_RESTARTBLOCK; } /** @@ -760,32 +735,12 @@ static int update_rmtp(ktime_t exp, enum alarmtimer_type type, static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) { enum alarmtimer_type type = restart->nanosleep.clockid; - ktime_t exp; - struct timespec __user *rmtp; + ktime_t exp = restart->nanosleep.expires; struct alarm alarm; - int ret = 0; - exp = restart->nanosleep.expires; alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); - if (alarmtimer_do_nsleep(&alarm, exp)) - goto out; - - if (freezing(current)) - alarmtimer_freezerset(exp, type); - - rmtp = restart->nanosleep.rmtp; - if (rmtp) { - ret = update_rmtp(exp, type, rmtp); - if (ret <= 0) - goto out; - } - - - /* The other values in restart are already filled in */ - ret = -ERESTART_RESTARTBLOCK; -out: - return ret; + return alarmtimer_do_nsleep(&alarm, exp, type); } /** @@ -798,11 +753,10 @@ out: * Handles clock_nanosleep calls against _ALARM clockids */ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, - struct timespec64 *tsreq, - struct timespec __user *rmtp) + const struct timespec64 *tsreq) { enum alarmtimer_type type = clock2alarm(which_clock); - struct restart_block *restart; + struct restart_block *restart = ¤t->restart_block; struct alarm alarm; ktime_t exp; int ret = 0; @@ -825,35 +779,36 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, exp = ktime_add(now, exp); } - if (alarmtimer_do_nsleep(&alarm, exp)) - goto out; - - if (freezing(current)) - alarmtimer_freezerset(exp, type); + ret = alarmtimer_do_nsleep(&alarm, exp, type); + if (ret != -ERESTART_RESTARTBLOCK) + return ret; /* abs timers don't set remaining time or restart */ - if (flags == TIMER_ABSTIME) { - ret = -ERESTARTNOHAND; - goto out; - } + if (flags == TIMER_ABSTIME) + return -ERESTARTNOHAND; - if (rmtp) { - ret = update_rmtp(exp, type, rmtp); - if (ret <= 0) - goto out; - } - - restart = ¤t->restart_block; restart->fn = alarm_timer_nsleep_restart; restart->nanosleep.clockid = type; restart->nanosleep.expires = exp; - restart->nanosleep.rmtp = rmtp; - ret = -ERESTART_RESTARTBLOCK; - -out: return ret; } +const struct k_clock alarm_clock = { + .clock_getres = alarm_clock_getres, + .clock_get = alarm_clock_get, + .timer_create = alarm_timer_create, + .timer_set = common_timer_set, + .timer_del = common_timer_del, + .timer_get = common_timer_get, + .timer_arm = alarm_timer_arm, + .timer_rearm = alarm_timer_rearm, + .timer_forward = alarm_timer_forward, + .timer_remaining = alarm_timer_remaining, + .timer_try_to_cancel = alarm_timer_try_to_cancel, + .nsleep = alarm_timer_nsleep, +}; +#endif /* CONFIG_POSIX_TIMERS */ + /* Suspend hook structures */ static const struct dev_pm_ops alarmtimer_pm_ops = { @@ -879,23 +834,9 @@ static int __init alarmtimer_init(void) struct platform_device *pdev; int error = 0; int i; - struct k_clock alarm_clock = { - .clock_getres = alarm_clock_getres, - .clock_get = alarm_clock_get, - .timer_create = alarm_timer_create, - .timer_set = alarm_timer_set, - .timer_del = alarm_timer_del, - .timer_get = alarm_timer_get, - .nsleep = alarm_timer_nsleep, - }; alarmtimer_rtc_timer_init(); - if (IS_ENABLED(CONFIG_POSIX_TIMERS)) { - posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock); - posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock); - } - /* Initialize alarm bases */ alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME; alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real; diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index ac053bb..81da124 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -51,6 +51,7 @@ #include <linux/sched/debug.h> #include <linux/timer.h> #include <linux/freezer.h> +#include <linux/compat.h> #include <linux/uaccess.h> @@ -1439,8 +1440,29 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) } EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); +int nanosleep_copyout(struct restart_block *restart, struct timespec *ts) +{ + switch(restart->nanosleep.type) { +#ifdef CONFIG_COMPAT + case TT_COMPAT: + if (compat_put_timespec(ts, restart->nanosleep.compat_rmtp)) + return -EFAULT; + break; +#endif + case TT_NATIVE: + if (copy_to_user(restart->nanosleep.rmtp, ts, sizeof(struct timespec))) + return -EFAULT; + break; + default: + BUG(); + } + return -ERESTART_RESTARTBLOCK; +} + static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) { + struct restart_block *restart; + hrtimer_init_sleeper(t, current); do { @@ -1457,53 +1479,38 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod __set_current_state(TASK_RUNNING); - return t->task == NULL; -} - -static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp) -{ - struct timespec rmt; - ktime_t rem; - - rem = hrtimer_expires_remaining(timer); - if (rem <= 0) + if (!t->task) return 0; - rmt = ktime_to_timespec(rem); - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; + restart = ¤t->restart_block; + if (restart->nanosleep.type != TT_NONE) { + ktime_t rem = hrtimer_expires_remaining(&t->timer); + struct timespec rmt; - return 1; + if (rem <= 0) + return 0; + rmt = ktime_to_timespec(rem); + + return nanosleep_copyout(restart, &rmt); + } + return -ERESTART_RESTARTBLOCK; } -long __sched hrtimer_nanosleep_restart(struct restart_block *restart) +static long __sched hrtimer_nanosleep_restart(struct restart_block *restart) { struct hrtimer_sleeper t; - struct timespec __user *rmtp; - int ret = 0; + int ret; hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid, HRTIMER_MODE_ABS); hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires); - if (do_nanosleep(&t, HRTIMER_MODE_ABS)) - goto out; - - rmtp = restart->nanosleep.rmtp; - if (rmtp) { - ret = update_rmtp(&t.timer, rmtp); - if (ret <= 0) - goto out; - } - - /* The other values in restart are already filled in */ - ret = -ERESTART_RESTARTBLOCK; -out: + ret = do_nanosleep(&t, HRTIMER_MODE_ABS); destroy_hrtimer_on_stack(&t.timer); return ret; } -long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, +long hrtimer_nanosleep(const struct timespec64 *rqtp, const enum hrtimer_mode mode, const clockid_t clockid) { struct restart_block *restart; @@ -1517,7 +1524,8 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, hrtimer_init_on_stack(&t.timer, clockid, mode); hrtimer_set_expires_range_ns(&t.timer, timespec64_to_ktime(*rqtp), slack); - if (do_nanosleep(&t, mode)) + ret = do_nanosleep(&t, mode); + if (ret != -ERESTART_RESTARTBLOCK) goto out; /* Absolute timers do not update the rmtp value and restart: */ @@ -1526,19 +1534,10 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, goto out; } - if (rmtp) { - ret = update_rmtp(&t.timer, rmtp); - if (ret <= 0) - goto out; - } - restart = ¤t->restart_block; restart->fn = hrtimer_nanosleep_restart; restart->nanosleep.clockid = t.timer.base->clockid; - restart->nanosleep.rmtp = rmtp; restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer); - - ret = -ERESTART_RESTARTBLOCK; out: destroy_hrtimer_on_stack(&t.timer); return ret; @@ -1557,8 +1556,31 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, if (!timespec64_valid(&tu64)) return -EINVAL; - return hrtimer_nanosleep(&tu64, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); + current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; + current->restart_block.nanosleep.rmtp = rmtp; + return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC); +} + +#ifdef CONFIG_COMPAT + +COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, + struct compat_timespec __user *, rmtp) +{ + struct timespec64 tu64; + struct timespec tu; + + if (compat_get_timespec(&tu, rqtp)) + return -EFAULT; + + tu64 = timespec_to_timespec64(tu); + if (!timespec64_valid(&tu64)) + return -EINVAL; + + current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; + current->restart_block.nanosleep.compat_rmtp = rmtp; + return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC); } +#endif /* * Functions related to boot-time initialization: diff --git a/kernel/time/itimer.c b/kernel/time/itimer.c index 087d6a1..2ef98a0 100644 --- a/kernel/time/itimer.c +++ b/kernel/time/itimer.c @@ -15,6 +15,7 @@ #include <linux/posix-timers.h> #include <linux/hrtimer.h> #include <trace/events/timer.h> +#include <linux/compat.h> #include <linux/uaccess.h> @@ -116,6 +117,19 @@ SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value) return error; } +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE2(getitimer, int, which, + struct compat_itimerval __user *, it) +{ + struct itimerval kit; + int error = do_getitimer(which, &kit); + + if (!error && put_compat_itimerval(it, &kit)) + error = -EFAULT; + return error; +} +#endif + /* * The timer is automagically restarted, when interval != 0 @@ -138,8 +152,12 @@ static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id, u64 oval, nval, ointerval, ninterval; struct cpu_itimer *it = &tsk->signal->it[clock_id]; - nval = timeval_to_ns(&value->it_value); - ninterval = timeval_to_ns(&value->it_interval); + /* + * Use the to_ktime conversion because that clamps the maximum + * value to KTIME_MAX and avoid multiplication overflows. + */ + nval = ktime_to_ns(timeval_to_ktime(value->it_value)); + ninterval = ktime_to_ns(timeval_to_ktime(value->it_interval)); spin_lock_irq(&tsk->sighand->siglock); @@ -294,3 +312,27 @@ SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value, return -EFAULT; return 0; } + +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE3(setitimer, int, which, + struct compat_itimerval __user *, in, + struct compat_itimerval __user *, out) +{ + struct itimerval kin, kout; + int error; + + if (in) { + if (get_compat_itimerval(&kin, in)) + return -EFAULT; + } else { + memset(&kin, 0, sizeof(kin)); + } + + error = do_setitimer(which, &kin, out ? &kout : NULL); + if (error || !out) + return error; + if (put_compat_itimerval(out, &kout)) + return -EFAULT; + return 0; +} +#endif diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c index 31d588d..17cdc55 100644 --- a/kernel/time/posix-clock.c +++ b/kernel/time/posix-clock.c @@ -25,6 +25,8 @@ #include <linux/syscalls.h> #include <linux/uaccess.h> +#include "posix-timers.h" + static void delete_clock(struct kref *kref); /* @@ -82,38 +84,6 @@ static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) return result; } -static int posix_clock_fasync(int fd, struct file *fp, int on) -{ - struct posix_clock *clk = get_posix_clock(fp); - int err = 0; - - if (!clk) - return -ENODEV; - - if (clk->ops.fasync) - err = clk->ops.fasync(clk, fd, fp, on); - - put_posix_clock(clk); - - return err; -} - -static int posix_clock_mmap(struct file *fp, struct vm_area_struct *vma) -{ - struct posix_clock *clk = get_posix_clock(fp); - int err = -ENODEV; - - if (!clk) - return -ENODEV; - - if (clk->ops.mmap) - err = clk->ops.mmap(clk, vma); - - put_posix_clock(clk); - - return err; -} - static long posix_clock_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { @@ -199,8 +169,6 @@ static const struct file_operations posix_clock_file_operations = { .unlocked_ioctl = posix_clock_ioctl, .open = posix_clock_open, .release = posix_clock_release, - .fasync = posix_clock_fasync, - .mmap = posix_clock_mmap, #ifdef CONFIG_COMPAT .compat_ioctl = posix_clock_compat_ioctl, #endif @@ -359,88 +327,9 @@ out: return err; } -static int pc_timer_create(struct k_itimer *kit) -{ - clockid_t id = kit->it_clock; - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if (cd.clk->ops.timer_create) - err = cd.clk->ops.timer_create(cd.clk, kit); - else - err = -EOPNOTSUPP; - - put_clock_desc(&cd); - - return err; -} - -static int pc_timer_delete(struct k_itimer *kit) -{ - clockid_t id = kit->it_clock; - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if (cd.clk->ops.timer_delete) - err = cd.clk->ops.timer_delete(cd.clk, kit); - else - err = -EOPNOTSUPP; - - put_clock_desc(&cd); - - return err; -} - -static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec64 *ts) -{ - clockid_t id = kit->it_clock; - struct posix_clock_desc cd; - - if (get_clock_desc(id, &cd)) - return; - - if (cd.clk->ops.timer_gettime) - cd.clk->ops.timer_gettime(cd.clk, kit, ts); - - put_clock_desc(&cd); -} - -static int pc_timer_settime(struct k_itimer *kit, int flags, - struct itimerspec64 *ts, struct itimerspec64 *old) -{ - clockid_t id = kit->it_clock; - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if (cd.clk->ops.timer_settime) - err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old); - else - err = -EOPNOTSUPP; - - put_clock_desc(&cd); - - return err; -} - -struct k_clock clock_posix_dynamic = { +const struct k_clock clock_posix_dynamic = { .clock_getres = pc_clock_getres, .clock_set = pc_clock_settime, .clock_get = pc_clock_gettime, .clock_adj = pc_clock_adjtime, - .timer_create = pc_timer_create, - .timer_set = pc_timer_settime, - .timer_del = pc_timer_delete, - .timer_get = pc_timer_gettime, }; diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index d2a1e6d..60cb24a 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -12,6 +12,11 @@ #include <trace/events/timer.h> #include <linux/tick.h> #include <linux/workqueue.h> +#include <linux/compat.h> + +#include "posix-timers.h" + +static void posix_cpu_timer_rearm(struct k_itimer *timer); /* * Called after updating RLIMIT_CPU to run cpu timer and update @@ -322,6 +327,8 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer) if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX) return -EINVAL; + new_timer->kclock = &clock_posix_cpu; + INIT_LIST_HEAD(&new_timer->it.cpu.entry); rcu_read_lock(); @@ -524,7 +531,8 @@ static void cpu_timer_fire(struct k_itimer *timer) * reload the timer. But we need to keep it * ticking in case the signal is deliverable next time. */ - posix_cpu_timer_schedule(timer); + posix_cpu_timer_rearm(timer); + ++timer->it_requeue_pending; } } @@ -572,7 +580,11 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, WARN_ON_ONCE(p == NULL); - new_expires = timespec64_to_ns(&new->it_value); + /* + * Use the to_ktime conversion because that clamps the maximum + * value to KTIME_MAX and avoid multiplication overflows. + */ + new_expires = ktime_to_ns(timespec64_to_ktime(new->it_value)); /* * Protect against sighand release/switch in exit/exec and p->cpu_timers @@ -712,10 +724,8 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp */ itp->it_interval = ns_to_timespec64(timer->it.cpu.incr); - if (timer->it.cpu.expires == 0) { /* Timer not armed at all. */ - itp->it_value.tv_sec = itp->it_value.tv_nsec = 0; + if (!timer->it.cpu.expires) return; - } /* * Sample the clock to take the difference with the expiry time. @@ -739,7 +749,6 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp * Call the timer disarmed, nothing else to do. */ timer->it.cpu.expires = 0; - itp->it_value = ns_to_timespec64(timer->it.cpu.expires); return; } else { cpu_timer_sample_group(timer->it_clock, p, &now); @@ -976,10 +985,10 @@ static void check_process_timers(struct task_struct *tsk, } /* - * This is called from the signal code (via do_schedule_next_timer) + * This is called from the signal code (via posixtimer_rearm) * when the last timer signal was delivered and we have to reload the timer. */ -void posix_cpu_timer_schedule(struct k_itimer *timer) +static void posix_cpu_timer_rearm(struct k_itimer *timer) { struct sighand_struct *sighand; unsigned long flags; @@ -995,12 +1004,12 @@ void posix_cpu_timer_schedule(struct k_itimer *timer) cpu_clock_sample(timer->it_clock, p, &now); bump_cpu_timer(timer, now); if (unlikely(p->exit_state)) - goto out; + return; /* Protect timer list r/w in arm_timer() */ sighand = lock_task_sighand(p, &flags); if (!sighand) - goto out; + return; } else { /* * Protect arm_timer() and timer sampling in case of call to @@ -1013,11 +1022,10 @@ void posix_cpu_timer_schedule(struct k_itimer *timer) * We can't even collect a sample any more. */ timer->it.cpu.expires = 0; - goto out; + return; } else if (unlikely(p->exit_state) && thread_group_empty(p)) { - unlock_task_sighand(p, &flags); - /* Optimizations: if the process is dying, no need to rearm */ - goto out; + /* If the process is dying, no need to rearm */ + goto unlock; } cpu_timer_sample_group(timer->it_clock, p, &now); bump_cpu_timer(timer, now); @@ -1029,12 +1037,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer) */ WARN_ON_ONCE(!irqs_disabled()); arm_timer(timer); +unlock: unlock_task_sighand(p, &flags); - -out: - timer->it_overrun_last = timer->it_overrun; - timer->it_overrun = -1; - ++timer->it_requeue_pending; } /** @@ -1227,9 +1231,11 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, } static int do_cpu_nanosleep(const clockid_t which_clock, int flags, - struct timespec64 *rqtp, struct itimerspec64 *it) + const struct timespec64 *rqtp) { + struct itimerspec64 it; struct k_itimer timer; + u64 expires; int error; /* @@ -1243,12 +1249,13 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, timer.it_process = current; if (!error) { static struct itimerspec64 zero_it; + struct restart_block *restart; - memset(it, 0, sizeof *it); - it->it_value = *rqtp; + memset(&it, 0, sizeof(it)); + it.it_value = *rqtp; spin_lock_irq(&timer.it_lock); - error = posix_cpu_timer_set(&timer, flags, it, NULL); + error = posix_cpu_timer_set(&timer, flags, &it, NULL); if (error) { spin_unlock_irq(&timer.it_lock); return error; @@ -1277,8 +1284,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, /* * We were interrupted by a signal. */ - *rqtp = ns_to_timespec64(timer.it.cpu.expires); - error = posix_cpu_timer_set(&timer, 0, &zero_it, it); + expires = timer.it.cpu.expires; + error = posix_cpu_timer_set(&timer, 0, &zero_it, &it); if (!error) { /* * Timer is now unarmed, deletion can not fail. @@ -1298,7 +1305,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, spin_unlock_irq(&timer.it_lock); } - if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { + if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) { /* * It actually did fire already. */ @@ -1306,6 +1313,17 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, } error = -ERESTART_RESTARTBLOCK; + /* + * Report back to the user the time still remaining. + */ + restart = ¤t->restart_block; + restart->nanosleep.expires = expires; + if (restart->nanosleep.type != TT_NONE) { + struct timespec ts; + + ts = timespec64_to_timespec(it.it_value); + error = nanosleep_copyout(restart, &ts); + } } return error; @@ -1314,11 +1332,9 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, static long posix_cpu_nsleep_restart(struct restart_block *restart_block); static int posix_cpu_nsleep(const clockid_t which_clock, int flags, - struct timespec64 *rqtp, struct timespec __user *rmtp) + const struct timespec64 *rqtp) { struct restart_block *restart_block = ¤t->restart_block; - struct itimerspec64 it; - struct timespec ts; int error; /* @@ -1329,23 +1345,15 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, CPUCLOCK_PID(which_clock) == task_pid_vnr(current))) return -EINVAL; - error = do_cpu_nanosleep(which_clock, flags, rqtp, &it); + error = do_cpu_nanosleep(which_clock, flags, rqtp); if (error == -ERESTART_RESTARTBLOCK) { if (flags & TIMER_ABSTIME) return -ERESTARTNOHAND; - /* - * Report back to the user the time still remaining. - */ - ts = timespec64_to_timespec(it.it_value); - if (rmtp && copy_to_user(rmtp, &ts, sizeof(*rmtp))) - return -EFAULT; restart_block->fn = posix_cpu_nsleep_restart; restart_block->nanosleep.clockid = which_clock; - restart_block->nanosleep.rmtp = rmtp; - restart_block->nanosleep.expires = timespec64_to_ns(rqtp); } return error; } @@ -1353,28 +1361,11 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, static long posix_cpu_nsleep_restart(struct restart_block *restart_block) { clockid_t which_clock = restart_block->nanosleep.clockid; - struct itimerspec64 it; struct timespec64 t; - struct timespec tmp; - int error; t = ns_to_timespec64(restart_block->nanosleep.expires); - error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it); - - if (error == -ERESTART_RESTARTBLOCK) { - struct timespec __user *rmtp = restart_block->nanosleep.rmtp; - /* - * Report back to the user the time still remaining. - */ - tmp = timespec64_to_timespec(it.it_value); - if (rmtp && copy_to_user(rmtp, &tmp, sizeof(*rmtp))) - return -EFAULT; - - restart_block->nanosleep.expires = timespec64_to_ns(&t); - } - return error; - + return do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t); } #define PROCESS_CLOCK MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED) @@ -1396,14 +1387,9 @@ static int process_cpu_timer_create(struct k_itimer *timer) return posix_cpu_timer_create(timer); } static int process_cpu_nsleep(const clockid_t which_clock, int flags, - struct timespec64 *rqtp, - struct timespec __user *rmtp) -{ - return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); -} -static long process_cpu_nsleep_restart(struct restart_block *restart_block) + const struct timespec64 *rqtp) { - return -EINVAL; + return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp); } static int thread_cpu_clock_getres(const clockid_t which_clock, struct timespec64 *tp) @@ -1421,36 +1407,27 @@ static int thread_cpu_timer_create(struct k_itimer *timer) return posix_cpu_timer_create(timer); } -struct k_clock clock_posix_cpu = { +const struct k_clock clock_posix_cpu = { .clock_getres = posix_cpu_clock_getres, .clock_set = posix_cpu_clock_set, .clock_get = posix_cpu_clock_get, .timer_create = posix_cpu_timer_create, .nsleep = posix_cpu_nsleep, - .nsleep_restart = posix_cpu_nsleep_restart, .timer_set = posix_cpu_timer_set, .timer_del = posix_cpu_timer_del, .timer_get = posix_cpu_timer_get, + .timer_rearm = posix_cpu_timer_rearm, }; -static __init int init_posix_cpu_timers(void) -{ - struct k_clock process = { - .clock_getres = process_cpu_clock_getres, - .clock_get = process_cpu_clock_get, - .timer_create = process_cpu_timer_create, - .nsleep = process_cpu_nsleep, - .nsleep_restart = process_cpu_nsleep_restart, - }; - struct k_clock thread = { - .clock_getres = thread_cpu_clock_getres, - .clock_get = thread_cpu_clock_get, - .timer_create = thread_cpu_timer_create, - }; - - posix_timers_register_clock(CLOCK_PROCESS_CPUTIME_ID, &process); - posix_timers_register_clock(CLOCK_THREAD_CPUTIME_ID, &thread); +const struct k_clock clock_process = { + .clock_getres = process_cpu_clock_getres, + .clock_get = process_cpu_clock_get, + .timer_create = process_cpu_timer_create, + .nsleep = process_cpu_nsleep, +}; - return 0; -} -__initcall(init_posix_cpu_timers); +const struct k_clock clock_thread = { + .clock_getres = thread_cpu_clock_getres, + .clock_get = thread_cpu_clock_get, + .timer_create = thread_cpu_timer_create, +}; diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c index c0cd53e..38f3b20 100644 --- a/kernel/time/posix-stubs.c +++ b/kernel/time/posix-stubs.c @@ -17,6 +17,7 @@ #include <linux/ktime.h> #include <linux/timekeeping.h> #include <linux/posix-timers.h> +#include <linux/compat.h> asmlinkage long sys_ni_posix_timers(void) { @@ -27,6 +28,7 @@ asmlinkage long sys_ni_posix_timers(void) } #define SYS_NI(name) SYSCALL_ALIAS(sys_##name, sys_ni_posix_timers) +#define COMPAT_SYS_NI(name) SYSCALL_ALIAS(compat_sys_##name, sys_ni_posix_timers) SYS_NI(timer_create); SYS_NI(timer_gettime); @@ -39,6 +41,12 @@ SYS_NI(setitimer); #ifdef __ARCH_WANT_SYS_ALARM SYS_NI(alarm); #endif +COMPAT_SYS_NI(timer_create); +COMPAT_SYS_NI(clock_adjtime); +COMPAT_SYS_NI(timer_settime); +COMPAT_SYS_NI(timer_gettime); +COMPAT_SYS_NI(getitimer); +COMPAT_SYS_NI(setitimer); /* * We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC @@ -110,22 +118,106 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, case CLOCK_REALTIME: case CLOCK_MONOTONIC: case CLOCK_BOOTTIME: - if (copy_from_user(&t, rqtp, sizeof (struct timespec))) - return -EFAULT; - t64 = timespec_to_timespec64(t); - if (!timespec64_valid(&t64)) - return -EINVAL; - return hrtimer_nanosleep(&t64, rmtp, flags & TIMER_ABSTIME ? - HRTIMER_MODE_ABS : HRTIMER_MODE_REL, - which_clock); + break; default: return -EINVAL; } + + if (copy_from_user(&t, rqtp, sizeof (struct timespec))) + return -EFAULT; + t64 = timespec_to_timespec64(t); + if (!timespec64_valid(&t64)) + return -EINVAL; + if (flags & TIMER_ABSTIME) + rmtp = NULL; + current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; + current->restart_block.nanosleep.rmtp = rmtp; + return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ? + HRTIMER_MODE_ABS : HRTIMER_MODE_REL, + which_clock); } #ifdef CONFIG_COMPAT -long clock_nanosleep_restart(struct restart_block *restart_block) +COMPAT_SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, + struct compat_timespec __user *, tp) +{ + struct timespec64 new_tp64; + struct timespec new_tp; + + if (which_clock != CLOCK_REALTIME) + return -EINVAL; + if (compat_get_timespec(&new_tp, tp)) + return -EFAULT; + + new_tp64 = timespec_to_timespec64(new_tp); + return do_sys_settimeofday64(&new_tp64, NULL); +} + +COMPAT_SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, + struct compat_timespec __user *,tp) { - return hrtimer_nanosleep_restart(restart_block); + struct timespec64 kernel_tp64; + struct timespec kernel_tp; + + switch (which_clock) { + case CLOCK_REALTIME: ktime_get_real_ts64(&kernel_tp64); break; + case CLOCK_MONOTONIC: ktime_get_ts64(&kernel_tp64); break; + case CLOCK_BOOTTIME: get_monotonic_boottime64(&kernel_tp64); break; + default: return -EINVAL; + } + + kernel_tp = timespec64_to_timespec(kernel_tp64); + if (compat_put_timespec(&kernel_tp, tp)) + return -EFAULT; + return 0; +} + +COMPAT_SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, + struct compat_timespec __user *, tp) +{ + struct timespec rtn_tp = { + .tv_sec = 0, + .tv_nsec = hrtimer_resolution, + }; + + switch (which_clock) { + case CLOCK_REALTIME: + case CLOCK_MONOTONIC: + case CLOCK_BOOTTIME: + if (compat_put_timespec(&rtn_tp, tp)) + return -EFAULT; + return 0; + default: + return -EINVAL; + } +} +COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, + struct compat_timespec __user *, rqtp, + struct compat_timespec __user *, rmtp) +{ + struct timespec64 t64; + struct timespec t; + + switch (which_clock) { + case CLOCK_REALTIME: + case CLOCK_MONOTONIC: + case CLOCK_BOOTTIME: + break; + default: + return -EINVAL; + } + + if (compat_get_timespec(&t, rqtp)) + return -EFAULT; + t64 = timespec_to_timespec64(t); + if (!timespec64_valid(&t64)) + return -EINVAL; + if (flags & TIMER_ABSTIME) + rmtp = NULL; + current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; + current->restart_block.nanosleep.compat_rmtp = rmtp; + return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ? + HRTIMER_MODE_ABS : HRTIMER_MODE_REL, + which_clock); } #endif diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 4d7b2ce..82d67be 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -49,8 +49,10 @@ #include <linux/workqueue.h> #include <linux/export.h> #include <linux/hashtable.h> +#include <linux/compat.h> #include "timekeeping.h" +#include "posix-timers.h" /* * Management arrays for POSIX timers. Timers are now kept in static hash table @@ -69,6 +71,10 @@ static struct kmem_cache *posix_timers_cache; static DEFINE_HASHTABLE(posix_timers_hashtable, 9); static DEFINE_SPINLOCK(hash_lock); +static const struct k_clock * const posix_clocks[]; +static const struct k_clock *clockid_to_kclock(const clockid_t id); +static const struct k_clock clock_realtime, clock_monotonic; + /* * we assume that the new SIGEV_THREAD_ID shares no bits with the other * SIGEV values. Here we put out an error if this assumption fails. @@ -124,22 +130,6 @@ static DEFINE_SPINLOCK(hash_lock); * have is CLOCK_REALTIME and its high res counter part, both of * which we beg off on and pass to do_sys_settimeofday(). */ - -static struct k_clock posix_clocks[MAX_CLOCKS]; - -/* - * These ones are defined below. - */ -static int common_nsleep(const clockid_t, int flags, struct timespec64 *t, - struct timespec __user *rmtp); -static int common_timer_create(struct k_itimer *new_timer); -static void common_timer_get(struct k_itimer *, struct itimerspec64 *); -static int common_timer_set(struct k_itimer *, int, - struct itimerspec64 *, struct itimerspec64 *); -static int common_timer_del(struct k_itimer *timer); - -static enum hrtimer_restart posix_timer_fn(struct hrtimer *data); - static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags); #define lock_timer(tid, flags) \ @@ -285,91 +275,23 @@ static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp) */ static __init int init_posix_timers(void) { - struct k_clock clock_realtime = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_clock_realtime_get, - .clock_set = posix_clock_realtime_set, - .clock_adj = posix_clock_realtime_adj, - .nsleep = common_nsleep, - .nsleep_restart = hrtimer_nanosleep_restart, - .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, - .timer_del = common_timer_del, - }; - struct k_clock clock_monotonic = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_ktime_get_ts, - .nsleep = common_nsleep, - .nsleep_restart = hrtimer_nanosleep_restart, - .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, - .timer_del = common_timer_del, - }; - struct k_clock clock_monotonic_raw = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_get_monotonic_raw, - }; - struct k_clock clock_realtime_coarse = { - .clock_getres = posix_get_coarse_res, - .clock_get = posix_get_realtime_coarse, - }; - struct k_clock clock_monotonic_coarse = { - .clock_getres = posix_get_coarse_res, - .clock_get = posix_get_monotonic_coarse, - }; - struct k_clock clock_tai = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_get_tai, - .nsleep = common_nsleep, - .nsleep_restart = hrtimer_nanosleep_restart, - .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, - .timer_del = common_timer_del, - }; - struct k_clock clock_boottime = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_get_boottime, - .nsleep = common_nsleep, - .nsleep_restart = hrtimer_nanosleep_restart, - .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, - .timer_del = common_timer_del, - }; - - posix_timers_register_clock(CLOCK_REALTIME, &clock_realtime); - posix_timers_register_clock(CLOCK_MONOTONIC, &clock_monotonic); - posix_timers_register_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw); - posix_timers_register_clock(CLOCK_REALTIME_COARSE, &clock_realtime_coarse); - posix_timers_register_clock(CLOCK_MONOTONIC_COARSE, &clock_monotonic_coarse); - posix_timers_register_clock(CLOCK_BOOTTIME, &clock_boottime); - posix_timers_register_clock(CLOCK_TAI, &clock_tai); - posix_timers_cache = kmem_cache_create("posix_timers_cache", sizeof (struct k_itimer), 0, SLAB_PANIC, NULL); return 0; } - __initcall(init_posix_timers); -static void schedule_next_timer(struct k_itimer *timr) +static void common_hrtimer_rearm(struct k_itimer *timr) { struct hrtimer *timer = &timr->it.real.timer; - if (timr->it.real.interval == 0) + if (!timr->it_interval) return; timr->it_overrun += (unsigned int) hrtimer_forward(timer, timer->base->get_time(), - timr->it.real.interval); - - timr->it_overrun_last = timr->it_overrun; - timr->it_overrun = -1; - ++timr->it_requeue_pending; + timr->it_interval); hrtimer_restart(timer); } @@ -384,24 +306,27 @@ static void schedule_next_timer(struct k_itimer *timr) * To protect against the timer going away while the interrupt is queued, * we require that the it_requeue_pending flag be set. */ -void do_schedule_next_timer(struct siginfo *info) +void posixtimer_rearm(struct siginfo *info) { struct k_itimer *timr; unsigned long flags; timr = lock_timer(info->si_tid, &flags); + if (!timr) + return; - if (timr && timr->it_requeue_pending == info->si_sys_private) { - if (timr->it_clock < 0) - posix_cpu_timer_schedule(timr); - else - schedule_next_timer(timr); + if (timr->it_requeue_pending == info->si_sys_private) { + timr->kclock->timer_rearm(timr); + + timr->it_active = 1; + timr->it_overrun_last = timr->it_overrun; + timr->it_overrun = -1; + ++timr->it_requeue_pending; info->si_overrun += timr->it_overrun_last; } - if (timr) - unlock_timer(timr, flags); + unlock_timer(timr, flags); } int posix_timer_event(struct k_itimer *timr, int si_private) @@ -410,12 +335,12 @@ int posix_timer_event(struct k_itimer *timr, int si_private) int shared, ret = -1; /* * FIXME: if ->sigq is queued we can race with - * dequeue_signal()->do_schedule_next_timer(). + * dequeue_signal()->posixtimer_rearm(). * * If dequeue_signal() sees the "right" value of - * si_sys_private it calls do_schedule_next_timer(). + * si_sys_private it calls posixtimer_rearm(). * We re-queue ->sigq and drop ->it_lock(). - * do_schedule_next_timer() locks the timer + * posixtimer_rearm() locks the timer * and re-schedules it while ->sigq is pending. * Not really bad, but not that we want. */ @@ -431,7 +356,6 @@ int posix_timer_event(struct k_itimer *timr, int si_private) /* If we failed to send the signal the timer stops. */ return ret > 0; } -EXPORT_SYMBOL_GPL(posix_timer_event); /* * This function gets called when a POSIX.1b interval timer expires. It @@ -450,7 +374,8 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) timr = container_of(timer, struct k_itimer, it.real.timer); spin_lock_irqsave(&timr->it_lock, flags); - if (timr->it.real.interval != 0) + timr->it_active = 0; + if (timr->it_interval != 0) si_private = ++timr->it_requeue_pending; if (posix_timer_event(timr, si_private)) { @@ -459,7 +384,7 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) * we will not get a call back to restart it AND * it should be restarted. */ - if (timr->it.real.interval != 0) { + if (timr->it_interval != 0) { ktime_t now = hrtimer_cb_get_time(timer); /* @@ -488,15 +413,16 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) { ktime_t kj = NSEC_PER_SEC / HZ; - if (timr->it.real.interval < kj) + if (timr->it_interval < kj) now = ktime_add(now, kj); } #endif timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, - timr->it.real.interval); + timr->it_interval); ret = HRTIMER_RESTART; ++timr->it_requeue_pending; + timr->it_active = 1; } } @@ -521,30 +447,6 @@ static struct pid *good_sigevent(sigevent_t * event) return task_pid(rtn); } -void posix_timers_register_clock(const clockid_t clock_id, - struct k_clock *new_clock) -{ - if ((unsigned) clock_id >= MAX_CLOCKS) { - printk(KERN_WARNING "POSIX clock register failed for clock_id %d\n", - clock_id); - return; - } - - if (!new_clock->clock_get) { - printk(KERN_WARNING "POSIX clock id %d lacks clock_get()\n", - clock_id); - return; - } - if (!new_clock->clock_getres) { - printk(KERN_WARNING "POSIX clock id %d lacks clock_getres()\n", - clock_id); - return; - } - - posix_clocks[clock_id] = *new_clock; -} -EXPORT_SYMBOL_GPL(posix_timers_register_clock); - static struct k_itimer * alloc_posix_timer(void) { struct k_itimer *tmr; @@ -581,17 +483,6 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set) call_rcu(&tmr->it.rcu, k_itimer_rcu_free); } -static struct k_clock *clockid_to_kclock(const clockid_t id) -{ - if (id < 0) - return (id & CLOCKFD_MASK) == CLOCKFD ? - &clock_posix_dynamic : &clock_posix_cpu; - - if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres) - return NULL; - return &posix_clocks[id]; -} - static int common_timer_create(struct k_itimer *new_timer) { hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0); @@ -599,15 +490,12 @@ static int common_timer_create(struct k_itimer *new_timer) } /* Create a POSIX.1b interval timer. */ - -SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, - struct sigevent __user *, timer_event_spec, - timer_t __user *, created_timer_id) +static int do_timer_create(clockid_t which_clock, struct sigevent *event, + timer_t __user *created_timer_id) { - struct k_clock *kc = clockid_to_kclock(which_clock); + const struct k_clock *kc = clockid_to_kclock(which_clock); struct k_itimer *new_timer; int error, new_timer_id; - sigevent_t event; int it_id_set = IT_ID_NOT_SET; if (!kc) @@ -629,31 +517,28 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, it_id_set = IT_ID_SET; new_timer->it_id = (timer_t) new_timer_id; new_timer->it_clock = which_clock; + new_timer->kclock = kc; new_timer->it_overrun = -1; - if (timer_event_spec) { - if (copy_from_user(&event, timer_event_spec, sizeof (event))) { - error = -EFAULT; - goto out; - } + if (event) { rcu_read_lock(); - new_timer->it_pid = get_pid(good_sigevent(&event)); + new_timer->it_pid = get_pid(good_sigevent(event)); rcu_read_unlock(); if (!new_timer->it_pid) { error = -EINVAL; goto out; } + new_timer->it_sigev_notify = event->sigev_notify; + new_timer->sigq->info.si_signo = event->sigev_signo; + new_timer->sigq->info.si_value = event->sigev_value; } else { - memset(&event.sigev_value, 0, sizeof(event.sigev_value)); - event.sigev_notify = SIGEV_SIGNAL; - event.sigev_signo = SIGALRM; - event.sigev_value.sival_int = new_timer->it_id; + new_timer->it_sigev_notify = SIGEV_SIGNAL; + new_timer->sigq->info.si_signo = SIGALRM; + memset(&new_timer->sigq->info.si_value, 0, sizeof(sigval_t)); + new_timer->sigq->info.si_value.sival_int = new_timer->it_id; new_timer->it_pid = get_pid(task_tgid(current)); } - new_timer->it_sigev_notify = event.sigev_notify; - new_timer->sigq->info.si_signo = event.sigev_signo; - new_timer->sigq->info.si_value = event.sigev_value; new_timer->sigq->info.si_tid = new_timer->it_id; new_timer->sigq->info.si_code = SI_TIMER; @@ -684,6 +569,36 @@ out: return error; } +SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, + struct sigevent __user *, timer_event_spec, + timer_t __user *, created_timer_id) +{ + if (timer_event_spec) { + sigevent_t event; + + if (copy_from_user(&event, timer_event_spec, sizeof (event))) + return -EFAULT; + return do_timer_create(which_clock, &event, created_timer_id); + } + return do_timer_create(which_clock, NULL, created_timer_id); +} + +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock, + struct compat_sigevent __user *, timer_event_spec, + timer_t __user *, created_timer_id) +{ + if (timer_event_spec) { + sigevent_t event; + + if (get_compat_sigevent(&event, timer_event_spec)) + return -EFAULT; + return do_timer_create(which_clock, &event, created_timer_id); + } + return do_timer_create(which_clock, NULL, created_timer_id); +} +#endif + /* * Locking issues: We need to protect the result of the id look up until * we get the timer locked down so it is not deleted under us. The @@ -717,6 +632,20 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags) return NULL; } +static ktime_t common_hrtimer_remaining(struct k_itimer *timr, ktime_t now) +{ + struct hrtimer *timer = &timr->it.real.timer; + + return __hrtimer_expires_remaining_adjusted(timer, now); +} + +static int common_hrtimer_forward(struct k_itimer *timr, ktime_t now) +{ + struct hrtimer *timer = &timr->it.real.timer; + + return (int)hrtimer_forward(timer, now, timr->it_interval); +} + /* * Get the time remaining on a POSIX.1b interval timer. This function * is ALWAYS called with spin_lock_irq on the timer, thus it must not @@ -733,55 +662,61 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags) * it is the same as a requeue pending timer WRT to what we should * report. */ -static void -common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) +void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) { + const struct k_clock *kc = timr->kclock; ktime_t now, remaining, iv; - struct hrtimer *timer = &timr->it.real.timer; + struct timespec64 ts64; + bool sig_none; - memset(cur_setting, 0, sizeof(*cur_setting)); - - iv = timr->it.real.interval; + sig_none = (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE; + iv = timr->it_interval; /* interval timer ? */ - if (iv) + if (iv) { cur_setting->it_interval = ktime_to_timespec64(iv); - else if (!hrtimer_active(timer) && - (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) - return; + } else if (!timr->it_active) { + /* + * SIGEV_NONE oneshot timers are never queued. Check them + * below. + */ + if (!sig_none) + return; + } - now = timer->base->get_time(); + /* + * The timespec64 based conversion is suboptimal, but it's not + * worth to implement yet another callback. + */ + kc->clock_get(timr->it_clock, &ts64); + now = timespec64_to_ktime(ts64); /* - * When a requeue is pending or this is a SIGEV_NONE - * timer move the expiry time forward by intervals, so - * expiry is > now. + * When a requeue is pending or this is a SIGEV_NONE timer move the + * expiry time forward by intervals, so expiry is > now. */ - if (iv && (timr->it_requeue_pending & REQUEUE_PENDING || - (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) - timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv); + if (iv && (timr->it_requeue_pending & REQUEUE_PENDING || sig_none)) + timr->it_overrun += kc->timer_forward(timr, now); - remaining = __hrtimer_expires_remaining_adjusted(timer, now); + remaining = kc->timer_remaining(timr, now); /* Return 0 only, when the timer is expired and not pending */ if (remaining <= 0) { /* * A single shot SIGEV_NONE timer must return 0, when * it is expired ! */ - if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) + if (!sig_none) cur_setting->it_value.tv_nsec = 1; - } else + } else { cur_setting->it_value = ktime_to_timespec64(remaining); + } } /* Get the time remaining on a POSIX.1b interval timer. */ -SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, - struct itimerspec __user *, setting) +static int do_timer_gettime(timer_t timer_id, struct itimerspec64 *setting) { - struct itimerspec64 cur_setting64; - struct itimerspec cur_setting; struct k_itimer *timr; - struct k_clock *kc; + const struct k_clock *kc; unsigned long flags; int ret = 0; @@ -789,20 +724,49 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, if (!timr) return -EINVAL; - kc = clockid_to_kclock(timr->it_clock); + memset(setting, 0, sizeof(*setting)); + kc = timr->kclock; if (WARN_ON_ONCE(!kc || !kc->timer_get)) ret = -EINVAL; else - kc->timer_get(timr, &cur_setting64); + kc->timer_get(timr, setting); unlock_timer(timr, flags); + return ret; +} - cur_setting = itimerspec64_to_itimerspec(&cur_setting64); - if (!ret && copy_to_user(setting, &cur_setting, sizeof (cur_setting))) - return -EFAULT; +/* Get the time remaining on a POSIX.1b interval timer. */ +SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, + struct itimerspec __user *, setting) +{ + struct itimerspec64 cur_setting64; + int ret = do_timer_gettime(timer_id, &cur_setting64); + if (!ret) { + struct itimerspec cur_setting; + cur_setting = itimerspec64_to_itimerspec(&cur_setting64); + if (copy_to_user(setting, &cur_setting, sizeof (cur_setting))) + ret = -EFAULT; + } + return ret; +} + +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, + struct compat_itimerspec __user *, setting) +{ + struct itimerspec64 cur_setting64; + + int ret = do_timer_gettime(timer_id, &cur_setting64); + if (!ret) { + struct itimerspec cur_setting; + cur_setting = itimerspec64_to_itimerspec(&cur_setting64); + if (put_compat_itimerspec(setting, &cur_setting)) + ret = -EFAULT; + } return ret; } +#endif /* * Get the number of overruns of a POSIX.1b interval timer. This is to @@ -810,7 +774,7 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, * accumulating overruns on the next timer. The overrun is frozen when * the signal is delivered, either at the notify time (if the info block * is not queued) or at the actual delivery time (as we are informed by - * the call back to do_schedule_next_timer(). So all we need to do is + * the call back to posixtimer_rearm(). So all we need to do is * to pick up the frozen overrun. */ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) @@ -829,117 +793,183 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) return overrun; } -/* Set a POSIX.1b interval timer. */ -/* timr->it_lock is taken. */ -static int -common_timer_set(struct k_itimer *timr, int flags, - struct itimerspec64 *new_setting, struct itimerspec64 *old_setting) +static void common_hrtimer_arm(struct k_itimer *timr, ktime_t expires, + bool absolute, bool sigev_none) { struct hrtimer *timer = &timr->it.real.timer; enum hrtimer_mode mode; + mode = absolute ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; + /* + * Posix magic: Relative CLOCK_REALTIME timers are not affected by + * clock modifications, so they become CLOCK_MONOTONIC based under the + * hood. See hrtimer_init(). Update timr->kclock, so the generic + * functions which use timr->kclock->clock_get() work. + * + * Note: it_clock stays unmodified, because the next timer_set() might + * use ABSTIME, so it needs to switch back. + */ + if (timr->it_clock == CLOCK_REALTIME) + timr->kclock = absolute ? &clock_realtime : &clock_monotonic; + + hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); + timr->it.real.timer.function = posix_timer_fn; + + if (!absolute) + expires = ktime_add_safe(expires, timer->base->get_time()); + hrtimer_set_expires(timer, expires); + + if (!sigev_none) + hrtimer_start_expires(timer, HRTIMER_MODE_ABS); +} + +static int common_hrtimer_try_to_cancel(struct k_itimer *timr) +{ + return hrtimer_try_to_cancel(&timr->it.real.timer); +} + +/* Set a POSIX.1b interval timer. */ +int common_timer_set(struct k_itimer *timr, int flags, + struct itimerspec64 *new_setting, + struct itimerspec64 *old_setting) +{ + const struct k_clock *kc = timr->kclock; + bool sigev_none; + ktime_t expires; + if (old_setting) common_timer_get(timr, old_setting); - /* disable the timer */ - timr->it.real.interval = 0; + /* Prevent rearming by clearing the interval */ + timr->it_interval = 0; /* - * careful here. If smp we could be in the "fire" routine which will - * be spinning as we hold the lock. But this is ONLY an SMP issue. + * Careful here. On SMP systems the timer expiry function could be + * active and spinning on timr->it_lock. */ - if (hrtimer_try_to_cancel(timer) < 0) + if (kc->timer_try_to_cancel(timr) < 0) return TIMER_RETRY; - timr->it_requeue_pending = (timr->it_requeue_pending + 2) & + timr->it_active = 0; + timr->it_requeue_pending = (timr->it_requeue_pending + 2) & ~REQUEUE_PENDING; timr->it_overrun_last = 0; - /* switch off the timer when it_value is zero */ + /* Switch off the timer when it_value is zero */ if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec) return 0; - mode = flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; - hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); - timr->it.real.timer.function = posix_timer_fn; - - hrtimer_set_expires(timer, timespec64_to_ktime(new_setting->it_value)); - - /* Convert interval */ - timr->it.real.interval = timespec64_to_ktime(new_setting->it_interval); - - /* SIGEV_NONE timers are not queued ! See common_timer_get */ - if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { - /* Setup correct expiry time for relative timers */ - if (mode == HRTIMER_MODE_REL) { - hrtimer_add_expires(timer, timer->base->get_time()); - } - return 0; - } + timr->it_interval = timespec64_to_ktime(new_setting->it_interval); + expires = timespec64_to_ktime(new_setting->it_value); + sigev_none = (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE; - hrtimer_start_expires(timer, mode); + kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none); + timr->it_active = !sigev_none; return 0; } -/* Set a POSIX.1b interval timer */ -SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, - const struct itimerspec __user *, new_setting, - struct itimerspec __user *, old_setting) +static int do_timer_settime(timer_t timer_id, int flags, + struct itimerspec64 *new_spec64, + struct itimerspec64 *old_spec64) { - struct itimerspec64 new_spec64, old_spec64; - struct itimerspec64 *rtn = old_setting ? &old_spec64 : NULL; - struct itimerspec new_spec, old_spec; + const struct k_clock *kc; struct k_itimer *timr; unsigned long flag; - struct k_clock *kc; int error = 0; - if (!new_setting) + if (!timespec64_valid(&new_spec64->it_interval) || + !timespec64_valid(&new_spec64->it_value)) return -EINVAL; - if (copy_from_user(&new_spec, new_setting, sizeof (new_spec))) - return -EFAULT; - new_spec64 = itimerspec_to_itimerspec64(&new_spec); - - if (!timespec64_valid(&new_spec64.it_interval) || - !timespec64_valid(&new_spec64.it_value)) - return -EINVAL; + if (old_spec64) + memset(old_spec64, 0, sizeof(*old_spec64)); retry: timr = lock_timer(timer_id, &flag); if (!timr) return -EINVAL; - kc = clockid_to_kclock(timr->it_clock); + kc = timr->kclock; if (WARN_ON_ONCE(!kc || !kc->timer_set)) error = -EINVAL; else - error = kc->timer_set(timr, flags, &new_spec64, rtn); + error = kc->timer_set(timr, flags, new_spec64, old_spec64); unlock_timer(timr, flag); if (error == TIMER_RETRY) { - rtn = NULL; // We already got the old time... + old_spec64 = NULL; // We already got the old time... goto retry; } - old_spec = itimerspec64_to_itimerspec(&old_spec64); - if (old_setting && !error && - copy_to_user(old_setting, &old_spec, sizeof (old_spec))) - error = -EFAULT; + return error; +} + +/* Set a POSIX.1b interval timer */ +SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, + const struct itimerspec __user *, new_setting, + struct itimerspec __user *, old_setting) +{ + struct itimerspec64 new_spec64, old_spec64; + struct itimerspec64 *rtn = old_setting ? &old_spec64 : NULL; + struct itimerspec new_spec; + int error = 0; + + if (!new_setting) + return -EINVAL; + + if (copy_from_user(&new_spec, new_setting, sizeof (new_spec))) + return -EFAULT; + new_spec64 = itimerspec_to_itimerspec64(&new_spec); + + error = do_timer_settime(timer_id, flags, &new_spec64, rtn); + if (!error && old_setting) { + struct itimerspec old_spec; + old_spec = itimerspec64_to_itimerspec(&old_spec64); + if (copy_to_user(old_setting, &old_spec, sizeof (old_spec))) + error = -EFAULT; + } + return error; +} + +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, + struct compat_itimerspec __user *, new, + struct compat_itimerspec __user *, old) +{ + struct itimerspec64 new_spec64, old_spec64; + struct itimerspec64 *rtn = old ? &old_spec64 : NULL; + struct itimerspec new_spec; + int error = 0; + + if (!new) + return -EINVAL; + if (get_compat_itimerspec(&new_spec, new)) + return -EFAULT; + new_spec64 = itimerspec_to_itimerspec64(&new_spec); + error = do_timer_settime(timer_id, flags, &new_spec64, rtn); + if (!error && old) { + struct itimerspec old_spec; + old_spec = itimerspec64_to_itimerspec(&old_spec64); + if (put_compat_itimerspec(old, &old_spec)) + error = -EFAULT; + } return error; } +#endif -static int common_timer_del(struct k_itimer *timer) +int common_timer_del(struct k_itimer *timer) { - timer->it.real.interval = 0; + const struct k_clock *kc = timer->kclock; - if (hrtimer_try_to_cancel(&timer->it.real.timer) < 0) + timer->it_interval = 0; + if (kc->timer_try_to_cancel(timer) < 0) return TIMER_RETRY; + timer->it_active = 0; return 0; } static inline int timer_delete_hook(struct k_itimer *timer) { - struct k_clock *kc = clockid_to_kclock(timer->it_clock); + const struct k_clock *kc = timer->kclock; if (WARN_ON_ONCE(!kc || !kc->timer_del)) return -EINVAL; @@ -1018,7 +1048,7 @@ void exit_itimers(struct signal_struct *sig) SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, const struct timespec __user *, tp) { - struct k_clock *kc = clockid_to_kclock(which_clock); + const struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec64 new_tp64; struct timespec new_tp; @@ -1035,7 +1065,7 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, struct timespec __user *,tp) { - struct k_clock *kc = clockid_to_kclock(which_clock); + const struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec64 kernel_tp64; struct timespec kernel_tp; int error; @@ -1055,7 +1085,7 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, struct timex __user *, utx) { - struct k_clock *kc = clockid_to_kclock(which_clock); + const struct k_clock *kc = clockid_to_kclock(which_clock); struct timex ktx; int err; @@ -1078,7 +1108,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __user *, tp) { - struct k_clock *kc = clockid_to_kclock(which_clock); + const struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec64 rtn_tp64; struct timespec rtn_tp; int error; @@ -1095,13 +1125,98 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, return error; } +#ifdef CONFIG_COMPAT + +COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock, + struct compat_timespec __user *, tp) +{ + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 new_tp64; + struct timespec new_tp; + + if (!kc || !kc->clock_set) + return -EINVAL; + + if (compat_get_timespec(&new_tp, tp)) + return -EFAULT; + + new_tp64 = timespec_to_timespec64(new_tp); + + return kc->clock_set(which_clock, &new_tp64); +} + +COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, + struct compat_timespec __user *, tp) +{ + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 kernel_tp64; + struct timespec kernel_tp; + int error; + + if (!kc) + return -EINVAL; + + error = kc->clock_get(which_clock, &kernel_tp64); + kernel_tp = timespec64_to_timespec(kernel_tp64); + + if (!error && compat_put_timespec(&kernel_tp, tp)) + error = -EFAULT; + + return error; +} + +COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, + struct compat_timex __user *, utp) +{ + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timex ktx; + int err; + + if (!kc) + return -EINVAL; + if (!kc->clock_adj) + return -EOPNOTSUPP; + + err = compat_get_timex(&ktx, utp); + if (err) + return err; + + err = kc->clock_adj(which_clock, &ktx); + + if (err >= 0) + err = compat_put_timex(utp, &ktx); + + return err; +} + +COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, + struct compat_timespec __user *, tp) +{ + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 rtn_tp64; + struct timespec rtn_tp; + int error; + + if (!kc) + return -EINVAL; + + error = kc->clock_getres(which_clock, &rtn_tp64); + rtn_tp = timespec64_to_timespec(rtn_tp64); + + if (!error && tp && compat_put_timespec(&rtn_tp, tp)) + error = -EFAULT; + + return error; +} +#endif + /* * nanosleep for monotonic and realtime clocks */ static int common_nsleep(const clockid_t which_clock, int flags, - struct timespec64 *tsave, struct timespec __user *rmtp) + const struct timespec64 *rqtp) { - return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? + return hrtimer_nanosleep(rqtp, flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL, which_clock); } @@ -1110,7 +1225,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, const struct timespec __user *, rqtp, struct timespec __user *, rmtp) { - struct k_clock *kc = clockid_to_kclock(which_clock); + const struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec64 t64; struct timespec t; @@ -1125,21 +1240,141 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, t64 = timespec_to_timespec64(t); if (!timespec64_valid(&t64)) return -EINVAL; + if (flags & TIMER_ABSTIME) + rmtp = NULL; + current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; + current->restart_block.nanosleep.rmtp = rmtp; - return kc->nsleep(which_clock, flags, &t64, rmtp); + return kc->nsleep(which_clock, flags, &t64); } -/* - * This will restart clock_nanosleep. This is required only by - * compat_clock_nanosleep_restart for now. - */ -long clock_nanosleep_restart(struct restart_block *restart_block) +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, + struct compat_timespec __user *, rqtp, + struct compat_timespec __user *, rmtp) { - clockid_t which_clock = restart_block->nanosleep.clockid; - struct k_clock *kc = clockid_to_kclock(which_clock); + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 t64; + struct timespec t; - if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) + if (!kc) return -EINVAL; + if (!kc->nsleep) + return -ENANOSLEEP_NOTSUP; - return kc->nsleep_restart(restart_block); + if (compat_get_timespec(&t, rqtp)) + return -EFAULT; + + t64 = timespec_to_timespec64(t); + if (!timespec64_valid(&t64)) + return -EINVAL; + if (flags & TIMER_ABSTIME) + rmtp = NULL; + current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; + current->restart_block.nanosleep.compat_rmtp = rmtp; + + return kc->nsleep(which_clock, flags, &t64); +} +#endif + +static const struct k_clock clock_realtime = { + .clock_getres = posix_get_hrtimer_res, + .clock_get = posix_clock_realtime_get, + .clock_set = posix_clock_realtime_set, + .clock_adj = posix_clock_realtime_adj, + .nsleep = common_nsleep, + .timer_create = common_timer_create, + .timer_set = common_timer_set, + .timer_get = common_timer_get, + .timer_del = common_timer_del, + .timer_rearm = common_hrtimer_rearm, + .timer_forward = common_hrtimer_forward, + .timer_remaining = common_hrtimer_remaining, + .timer_try_to_cancel = common_hrtimer_try_to_cancel, + .timer_arm = common_hrtimer_arm, +}; + +static const struct k_clock clock_monotonic = { + .clock_getres = posix_get_hrtimer_res, + .clock_get = posix_ktime_get_ts, + .nsleep = common_nsleep, + .timer_create = common_timer_create, + .timer_set = common_timer_set, + .timer_get = common_timer_get, + .timer_del = common_timer_del, + .timer_rearm = common_hrtimer_rearm, + .timer_forward = common_hrtimer_forward, + .timer_remaining = common_hrtimer_remaining, + .timer_try_to_cancel = common_hrtimer_try_to_cancel, + .timer_arm = common_hrtimer_arm, +}; + +static const struct k_clock clock_monotonic_raw = { + .clock_getres = posix_get_hrtimer_res, + .clock_get = posix_get_monotonic_raw, +}; + +static const struct k_clock clock_realtime_coarse = { + .clock_getres = posix_get_coarse_res, + .clock_get = posix_get_realtime_coarse, +}; + +static const struct k_clock clock_monotonic_coarse = { + .clock_getres = posix_get_coarse_res, + .clock_get = posix_get_monotonic_coarse, +}; + +static const struct k_clock clock_tai = { + .clock_getres = posix_get_hrtimer_res, + .clock_get = posix_get_tai, + .nsleep = common_nsleep, + .timer_create = common_timer_create, + .timer_set = common_timer_set, + .timer_get = common_timer_get, + .timer_del = common_timer_del, + .timer_rearm = common_hrtimer_rearm, + .timer_forward = common_hrtimer_forward, + .timer_remaining = common_hrtimer_remaining, + .timer_try_to_cancel = common_hrtimer_try_to_cancel, + .timer_arm = common_hrtimer_arm, +}; + +static const struct k_clock clock_boottime = { + .clock_getres = posix_get_hrtimer_res, + .clock_get = posix_get_boottime, + .nsleep = common_nsleep, + .timer_create = common_timer_create, + .timer_set = common_timer_set, + .timer_get = common_timer_get, + .timer_del = common_timer_del, + .timer_rearm = common_hrtimer_rearm, + .timer_forward = common_hrtimer_forward, + .timer_remaining = common_hrtimer_remaining, + .timer_try_to_cancel = common_hrtimer_try_to_cancel, + .timer_arm = common_hrtimer_arm, +}; + +static const struct k_clock * const posix_clocks[] = { + [CLOCK_REALTIME] = &clock_realtime, + [CLOCK_MONOTONIC] = &clock_monotonic, + [CLOCK_PROCESS_CPUTIME_ID] = &clock_process, + [CLOCK_THREAD_CPUTIME_ID] = &clock_thread, + [CLOCK_MONOTONIC_RAW] = &clock_monotonic_raw, + [CLOCK_REALTIME_COARSE] = &clock_realtime_coarse, + [CLOCK_MONOTONIC_COARSE] = &clock_monotonic_coarse, + [CLOCK_BOOTTIME] = &clock_boottime, + [CLOCK_REALTIME_ALARM] = &alarm_clock, + [CLOCK_BOOTTIME_ALARM] = &alarm_clock, + [CLOCK_TAI] = &clock_tai, +}; + +static const struct k_clock *clockid_to_kclock(const clockid_t id) +{ + if (id < 0) + return (id & CLOCKFD_MASK) == CLOCKFD ? + &clock_posix_dynamic : &clock_posix_cpu; + + if (id >= ARRAY_SIZE(posix_clocks) || !posix_clocks[id]) + return NULL; + return posix_clocks[id]; } diff --git a/kernel/time/posix-timers.h b/kernel/time/posix-timers.h new file mode 100644 index 0000000..fb303c3 --- /dev/null +++ b/kernel/time/posix-timers.h @@ -0,0 +1,40 @@ +#define TIMER_RETRY 1 + +struct k_clock { + int (*clock_getres)(const clockid_t which_clock, + struct timespec64 *tp); + int (*clock_set)(const clockid_t which_clock, + const struct timespec64 *tp); + int (*clock_get)(const clockid_t which_clock, + struct timespec64 *tp); + int (*clock_adj)(const clockid_t which_clock, struct timex *tx); + int (*timer_create)(struct k_itimer *timer); + int (*nsleep)(const clockid_t which_clock, int flags, + const struct timespec64 *); + int (*timer_set)(struct k_itimer *timr, int flags, + struct itimerspec64 *new_setting, + struct itimerspec64 *old_setting); + int (*timer_del)(struct k_itimer *timr); + void (*timer_get)(struct k_itimer *timr, + struct itimerspec64 *cur_setting); + void (*timer_rearm)(struct k_itimer *timr); + int (*timer_forward)(struct k_itimer *timr, ktime_t now); + ktime_t (*timer_remaining)(struct k_itimer *timr, ktime_t now); + int (*timer_try_to_cancel)(struct k_itimer *timr); + void (*timer_arm)(struct k_itimer *timr, ktime_t expires, + bool absolute, bool sigev_none); +}; + +extern const struct k_clock clock_posix_cpu; +extern const struct k_clock clock_posix_dynamic; +extern const struct k_clock clock_process; +extern const struct k_clock clock_thread; +extern const struct k_clock alarm_clock; + +int posix_timer_event(struct k_itimer *timr, int si_private); + +void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting); +int common_timer_set(struct k_itimer *timr, int flags, + struct itimerspec64 *new_setting, + struct itimerspec64 *old_setting); +int common_timer_del(struct k_itimer *timer); diff --git a/kernel/time/time.c b/kernel/time/time.c index 49c73c6..7c89e43 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -39,6 +39,7 @@ #include <linux/ptrace.h> #include <linux/uaccess.h> +#include <linux/compat.h> #include <asm/unistd.h> #include <generated/timeconst.h> @@ -99,6 +100,47 @@ SYSCALL_DEFINE1(stime, time_t __user *, tptr) #endif /* __ARCH_WANT_SYS_TIME */ +#ifdef CONFIG_COMPAT +#ifdef __ARCH_WANT_COMPAT_SYS_TIME + +/* compat_time_t is a 32 bit "long" and needs to get converted. */ +COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc) +{ + struct timeval tv; + compat_time_t i; + + do_gettimeofday(&tv); + i = tv.tv_sec; + + if (tloc) { + if (put_user(i,tloc)) + return -EFAULT; + } + force_successful_syscall_return(); + return i; +} + +COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr) +{ + struct timespec tv; + int err; + + if (get_user(tv.tv_sec, tptr)) + return -EFAULT; + + tv.tv_nsec = 0; + + err = security_settime(&tv, NULL); + if (err) + return err; + + do_settimeofday(&tv); + return 0; +} + +#endif /* __ARCH_WANT_COMPAT_SYS_TIME */ +#endif + SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv, struct timezone __user *, tz) { @@ -215,6 +257,47 @@ SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv, return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL); } +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv, + struct timezone __user *, tz) +{ + if (tv) { + struct timeval ktv; + + do_gettimeofday(&ktv); + if (compat_put_timeval(&ktv, tv)) + return -EFAULT; + } + if (tz) { + if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) + return -EFAULT; + } + + return 0; +} + +COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv, + struct timezone __user *, tz) +{ + struct timespec64 new_ts; + struct timeval user_tv; + struct timezone new_tz; + + if (tv) { + if (compat_get_timeval(&user_tv, tv)) + return -EFAULT; + new_ts.tv_sec = user_tv.tv_sec; + new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC; + } + if (tz) { + if (copy_from_user(&new_tz, tz, sizeof(*tz))) + return -EFAULT; + } + + return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL); +} +#endif + SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p) { struct timex txc; /* Local copy of parameter */ @@ -224,12 +307,33 @@ SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p) * structure. But bear in mind that the structures * may change */ - if(copy_from_user(&txc, txc_p, sizeof(struct timex))) + if (copy_from_user(&txc, txc_p, sizeof(struct timex))) return -EFAULT; ret = do_adjtimex(&txc); return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret; } +#ifdef CONFIG_COMPAT + +COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp) +{ + struct timex txc; + int err, ret; + + err = compat_get_timex(&txc, utp); + if (err) + return err; + + ret = do_adjtimex(&txc); + + err = compat_put_timex(utp, &txc); + if (err) + return err; + + return ret; +} +#endif + /* * Convert jiffies to milliseconds and back. * diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index b602c48..cedafa0 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -72,6 +72,10 @@ static inline void tk_normalize_xtime(struct timekeeper *tk) tk->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift; tk->xtime_sec++; } + while (tk->tkr_raw.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_raw.shift)) { + tk->tkr_raw.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_raw.shift; + tk->raw_sec++; + } } static inline struct timespec64 tk_xtime(struct timekeeper *tk) @@ -285,12 +289,14 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock) /* if changing clocks, convert xtime_nsec shift units */ if (old_clock) { int shift_change = clock->shift - old_clock->shift; - if (shift_change < 0) + if (shift_change < 0) { tk->tkr_mono.xtime_nsec >>= -shift_change; - else + tk->tkr_raw.xtime_nsec >>= -shift_change; + } else { tk->tkr_mono.xtime_nsec <<= shift_change; + tk->tkr_raw.xtime_nsec <<= shift_change; + } } - tk->tkr_raw.xtime_nsec = 0; tk->tkr_mono.shift = clock->shift; tk->tkr_raw.shift = clock->shift; @@ -510,6 +516,7 @@ static void halt_fast_timekeeper(struct timekeeper *tk) } #ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD +#warning Please contact your maintainers, as GENERIC_TIME_VSYSCALL_OLD compatibity will disappear soon. static inline void update_vsyscall(struct timekeeper *tk) { @@ -619,9 +626,6 @@ static inline void tk_update_ktime_data(struct timekeeper *tk) nsec = (u32) tk->wall_to_monotonic.tv_nsec; tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); - /* Update the monotonic raw base */ - tk->tkr_raw.base = timespec64_to_ktime(tk->raw_time); - /* * The sum of the nanoseconds portions of xtime and * wall_to_monotonic can be greater/equal one second. Take @@ -631,6 +635,11 @@ static inline void tk_update_ktime_data(struct timekeeper *tk) if (nsec >= NSEC_PER_SEC) seconds++; tk->ktime_sec = seconds; + + /* Update the monotonic raw base */ + seconds = tk->raw_sec; + nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift); + tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); } /* must hold timekeeper_lock */ @@ -672,7 +681,6 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) static void timekeeping_forward_now(struct timekeeper *tk) { u64 cycle_now, delta; - u64 nsec; cycle_now = tk_clock_read(&tk->tkr_mono); delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask); @@ -684,10 +692,13 @@ static void timekeeping_forward_now(struct timekeeper *tk) /* If arch requires, add in get_arch_timeoffset() */ tk->tkr_mono.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_mono.shift; - tk_normalize_xtime(tk); - nsec = clocksource_cyc2ns(delta, tk->tkr_raw.mult, tk->tkr_raw.shift); - timespec64_add_ns(&tk->raw_time, nsec); + tk->tkr_raw.xtime_nsec += delta * tk->tkr_raw.mult; + + /* If arch requires, add in get_arch_timeoffset() */ + tk->tkr_raw.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_raw.shift; + + tk_normalize_xtime(tk); } /** @@ -1373,19 +1384,18 @@ int timekeeping_notify(struct clocksource *clock) void getrawmonotonic64(struct timespec64 *ts) { struct timekeeper *tk = &tk_core.timekeeper; - struct timespec64 ts64; unsigned long seq; u64 nsecs; do { seq = read_seqcount_begin(&tk_core.seq); + ts->tv_sec = tk->raw_sec; nsecs = timekeeping_get_ns(&tk->tkr_raw); - ts64 = tk->raw_time; } while (read_seqcount_retry(&tk_core.seq, seq)); - timespec64_add_ns(&ts64, nsecs); - *ts = ts64; + ts->tv_nsec = 0; + timespec64_add_ns(ts, nsecs); } EXPORT_SYMBOL(getrawmonotonic64); @@ -1509,8 +1519,7 @@ void __init timekeeping_init(void) tk_setup_internals(tk, clock); tk_set_xtime(tk, &now); - tk->raw_time.tv_sec = 0; - tk->raw_time.tv_nsec = 0; + tk->raw_sec = 0; if (boot.tv_sec == 0 && boot.tv_nsec == 0) boot = tk_xtime(tk); @@ -2011,15 +2020,12 @@ static u64 logarithmic_accumulation(struct timekeeper *tk, u64 offset, *clock_set |= accumulate_nsecs_to_secs(tk); /* Accumulate raw time */ - tk->tkr_raw.xtime_nsec += (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift; tk->tkr_raw.xtime_nsec += tk->raw_interval << shift; snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift; while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) { tk->tkr_raw.xtime_nsec -= snsec_per_sec; - tk->raw_time.tv_sec++; + tk->raw_sec++; } - tk->raw_time.tv_nsec = tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift; - tk->tkr_raw.xtime_nsec -= (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift; /* Accumulate error between NTP and clock interval */ tk->ntp_error += tk->ntp_tick << shift; diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 152a706..71ce3f4 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -195,7 +195,7 @@ EXPORT_SYMBOL(jiffies_64); #endif struct timer_base { - spinlock_t lock; + raw_spinlock_t lock; struct timer_list *running_timer; unsigned long clk; unsigned long next_expiry; @@ -913,10 +913,10 @@ static struct timer_base *lock_timer_base(struct timer_list *timer, if (!(tf & TIMER_MIGRATING)) { base = get_timer_base(tf); - spin_lock_irqsave(&base->lock, *flags); + raw_spin_lock_irqsave(&base->lock, *flags); if (timer->flags == tf) return base; - spin_unlock_irqrestore(&base->lock, *flags); + raw_spin_unlock_irqrestore(&base->lock, *flags); } cpu_relax(); } @@ -986,9 +986,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) /* See the comment in lock_timer_base() */ timer->flags |= TIMER_MIGRATING; - spin_unlock(&base->lock); + raw_spin_unlock(&base->lock); base = new_base; - spin_lock(&base->lock); + raw_spin_lock(&base->lock); WRITE_ONCE(timer->flags, (timer->flags & ~TIMER_BASEMASK) | base->cpu); } @@ -1013,7 +1013,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) } out_unlock: - spin_unlock_irqrestore(&base->lock, flags); + raw_spin_unlock_irqrestore(&base->lock, flags); return ret; } @@ -1106,16 +1106,16 @@ void add_timer_on(struct timer_list *timer, int cpu) if (base != new_base) { timer->flags |= TIMER_MIGRATING; - spin_unlock(&base->lock); + raw_spin_unlock(&base->lock); base = new_base; - spin_lock(&base->lock); + raw_spin_lock(&base->lock); WRITE_ONCE(timer->flags, (timer->flags & ~TIMER_BASEMASK) | cpu); } debug_activate(timer, timer->expires); internal_add_timer(base, timer); - spin_unlock_irqrestore(&base->lock, flags); + raw_spin_unlock_irqrestore(&base->lock, flags); } EXPORT_SYMBOL_GPL(add_timer_on); @@ -1141,7 +1141,7 @@ int del_timer(struct timer_list *timer) if (timer_pending(timer)) { base = lock_timer_base(timer, &flags); ret = detach_if_pending(timer, base, true); - spin_unlock_irqrestore(&base->lock, flags); + raw_spin_unlock_irqrestore(&base->lock, flags); } return ret; @@ -1150,7 +1150,7 @@ EXPORT_SYMBOL(del_timer); /** * try_to_del_timer_sync - Try to deactivate a timer - * @timer: timer do del + * @timer: timer to delete * * This function tries to deactivate a timer. Upon successful (ret >= 0) * exit the timer is not queued and the handler is not running on any CPU. @@ -1168,7 +1168,7 @@ int try_to_del_timer_sync(struct timer_list *timer) if (base->running_timer != timer) ret = detach_if_pending(timer, base, true); - spin_unlock_irqrestore(&base->lock, flags); + raw_spin_unlock_irqrestore(&base->lock, flags); return ret; } @@ -1299,13 +1299,13 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head) data = timer->data; if (timer->flags & TIMER_IRQSAFE) { - spin_unlock(&base->lock); + raw_spin_unlock(&base->lock); call_timer_fn(timer, fn, data); - spin_lock(&base->lock); + raw_spin_lock(&base->lock); } else { - spin_unlock_irq(&base->lock); + raw_spin_unlock_irq(&base->lock); call_timer_fn(timer, fn, data); - spin_lock_irq(&base->lock); + raw_spin_lock_irq(&base->lock); } } } @@ -1474,7 +1474,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) if (cpu_is_offline(smp_processor_id())) return expires; - spin_lock(&base->lock); + raw_spin_lock(&base->lock); nextevt = __next_timer_interrupt(base); is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA); base->next_expiry = nextevt; @@ -1502,7 +1502,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) if ((expires - basem) > TICK_NSEC) base->is_idle = true; } - spin_unlock(&base->lock); + raw_spin_unlock(&base->lock); return cmp_next_hrtimer_event(basem, expires); } @@ -1590,7 +1590,7 @@ static inline void __run_timers(struct timer_base *base) if (!time_after_eq(jiffies, base->clk)) return; - spin_lock_irq(&base->lock); + raw_spin_lock_irq(&base->lock); while (time_after_eq(jiffies, base->clk)) { @@ -1601,7 +1601,7 @@ static inline void __run_timers(struct timer_base *base) expire_timers(base, heads + levels); } base->running_timer = NULL; - spin_unlock_irq(&base->lock); + raw_spin_unlock_irq(&base->lock); } /* @@ -1786,16 +1786,16 @@ int timers_dead_cpu(unsigned int cpu) * The caller is globally serialized and nobody else * takes two locks at once, deadlock is not possible. */ - spin_lock_irq(&new_base->lock); - spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); + raw_spin_lock_irq(&new_base->lock); + raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); BUG_ON(old_base->running_timer); for (i = 0; i < WHEEL_SIZE; i++) migrate_timer_list(new_base, old_base->vectors + i); - spin_unlock(&old_base->lock); - spin_unlock_irq(&new_base->lock); + raw_spin_unlock(&old_base->lock); + raw_spin_unlock_irq(&new_base->lock); put_cpu_ptr(&timer_bases); } return 0; @@ -1811,7 +1811,7 @@ static void __init init_timer_cpu(int cpu) for (i = 0; i < NR_BASES; i++) { base = per_cpu_ptr(&timer_bases[i], cpu); base->cpu = cpu; - spin_lock_init(&base->lock); + raw_spin_lock_init(&base->lock); base->clk = jiffies; } } diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile index 5fa1d7e9..5801bbe 100644 --- a/tools/testing/selftests/timers/Makefile +++ b/tools/testing/selftests/timers/Makefile @@ -1,6 +1,6 @@ BUILD_FLAGS = -DKTEST CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS) -LDFLAGS += -lrt -lpthread +LDFLAGS += -lrt -lpthread -lm # these are all "safe" tests that don't modify # system time or require escalated privileges @@ -8,7 +8,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ inconsistency-check raw_skew threadtest rtctest TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ - skew_consistency clocksource-switch leap-a-day \ + skew_consistency clocksource-switch freq-step leap-a-day \ leapcrash set-tai set-2038 set-tz @@ -24,6 +24,7 @@ run_destructive_tests: run_tests ./change_skew ./skew_consistency ./clocksource-switch + ./freq-step ./leap-a-day -s -i 10 ./leapcrash ./set-tz diff --git a/tools/testing/selftests/timers/freq-step.c b/tools/testing/selftests/timers/freq-step.c new file mode 100644 index 0000000..e8c6183 --- /dev/null +++ b/tools/testing/selftests/timers/freq-step.c @@ -0,0 +1,268 @@ +/* + * This test checks the response of the system clock to frequency + * steps made with adjtimex(). The frequency error and stability of + * the CLOCK_MONOTONIC clock relative to the CLOCK_MONOTONIC_RAW clock + * is measured in two intervals following the step. The test fails if + * values from the second interval exceed specified limits. + * + * Copyright (C) Miroslav Lichvar <mlichvar@redhat.com> 2017 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <math.h> +#include <stdio.h> +#include <sys/timex.h> +#include <time.h> +#include <unistd.h> + +#include "../kselftest.h" + +#define SAMPLES 100 +#define SAMPLE_READINGS 10 +#define MEAN_SAMPLE_INTERVAL 0.1 +#define STEP_INTERVAL 1.0 +#define MAX_PRECISION 100e-9 +#define MAX_FREQ_ERROR 10e-6 +#define MAX_STDDEV 1000e-9 + +struct sample { + double offset; + double time; +}; + +static time_t mono_raw_base; +static time_t mono_base; +static long user_hz; +static double precision; +static double mono_freq_offset; + +static double diff_timespec(struct timespec *ts1, struct timespec *ts2) +{ + return ts1->tv_sec - ts2->tv_sec + (ts1->tv_nsec - ts2->tv_nsec) / 1e9; +} + +static double get_sample(struct sample *sample) +{ + double delay, mindelay = 0.0; + struct timespec ts1, ts2, ts3; + int i; + + for (i = 0; i < SAMPLE_READINGS; i++) { + clock_gettime(CLOCK_MONOTONIC_RAW, &ts1); + clock_gettime(CLOCK_MONOTONIC, &ts2); + clock_gettime(CLOCK_MONOTONIC_RAW, &ts3); + + ts1.tv_sec -= mono_raw_base; + ts2.tv_sec -= mono_base; + ts3.tv_sec -= mono_raw_base; + + delay = diff_timespec(&ts3, &ts1); + if (delay <= 1e-9) { + i--; + continue; + } + + if (!i || delay < mindelay) { + sample->offset = diff_timespec(&ts2, &ts1); + sample->offset -= delay / 2.0; + sample->time = ts1.tv_sec + ts1.tv_nsec / 1e9; + mindelay = delay; + } + } + + return mindelay; +} + +static void reset_ntp_error(void) +{ + struct timex txc; + + txc.modes = ADJ_SETOFFSET; + txc.time.tv_sec = 0; + txc.time.tv_usec = 0; + + if (adjtimex(&txc) < 0) { + perror("[FAIL] adjtimex"); + ksft_exit_fail(); + } +} + +static void set_frequency(double freq) +{ + struct timex txc; + int tick_offset; + + tick_offset = 1e6 * freq / user_hz; + + txc.modes = ADJ_TICK | ADJ_FREQUENCY; + txc.tick = 1000000 / user_hz + tick_offset; + txc.freq = (1e6 * freq - user_hz * tick_offset) * (1 << 16); + + if (adjtimex(&txc) < 0) { + perror("[FAIL] adjtimex"); + ksft_exit_fail(); + } +} + +static void regress(struct sample *samples, int n, double *intercept, + double *slope, double *r_stddev, double *r_max) +{ + double x, y, r, x_sum, y_sum, xy_sum, x2_sum, r2_sum; + int i; + + x_sum = 0.0, y_sum = 0.0, xy_sum = 0.0, x2_sum = 0.0; + + for (i = 0; i < n; i++) { + x = samples[i].time; + y = samples[i].offset; + + x_sum += x; + y_sum += y; + xy_sum += x * y; + x2_sum += x * x; + } + + *slope = (xy_sum - x_sum * y_sum / n) / (x2_sum - x_sum * x_sum / n); + *intercept = (y_sum - *slope * x_sum) / n; + + *r_max = 0.0, r2_sum = 0.0; + + for (i = 0; i < n; i++) { + x = samples[i].time; + y = samples[i].offset; + r = fabs(x * *slope + *intercept - y); + if (*r_max < r) + *r_max = r; + r2_sum += r * r; + } + + *r_stddev = sqrt(r2_sum / n); +} + +static int run_test(int calibration, double freq_base, double freq_step) +{ + struct sample samples[SAMPLES]; + double intercept, slope, stddev1, max1, stddev2, max2; + double freq_error1, freq_error2; + int i; + + set_frequency(freq_base); + + for (i = 0; i < 10; i++) + usleep(1e6 * MEAN_SAMPLE_INTERVAL / 10); + + reset_ntp_error(); + + set_frequency(freq_base + freq_step); + + for (i = 0; i < 10; i++) + usleep(rand() % 2000000 * STEP_INTERVAL / 10); + + set_frequency(freq_base); + + for (i = 0; i < SAMPLES; i++) { + usleep(rand() % 2000000 * MEAN_SAMPLE_INTERVAL); + get_sample(&samples[i]); + } + + if (calibration) { + regress(samples, SAMPLES, &intercept, &slope, &stddev1, &max1); + mono_freq_offset = slope; + printf("CLOCK_MONOTONIC_RAW frequency offset: %11.3f ppm\n", + 1e6 * mono_freq_offset); + return 0; + } + + regress(samples, SAMPLES / 2, &intercept, &slope, &stddev1, &max1); + freq_error1 = slope * (1.0 - mono_freq_offset) - mono_freq_offset - + freq_base; + + regress(samples + SAMPLES / 2, SAMPLES / 2, &intercept, &slope, + &stddev2, &max2); + freq_error2 = slope * (1.0 - mono_freq_offset) - mono_freq_offset - + freq_base; + + printf("%6.0f %+10.3f %6.0f %7.0f %+10.3f %6.0f %7.0f\t", + 1e6 * freq_step, + 1e6 * freq_error1, 1e9 * stddev1, 1e9 * max1, + 1e6 * freq_error2, 1e9 * stddev2, 1e9 * max2); + + if (fabs(freq_error2) > MAX_FREQ_ERROR || stddev2 > MAX_STDDEV) { + printf("[FAIL]\n"); + return 1; + } + + printf("[OK]\n"); + return 0; +} + +static void init_test(void) +{ + struct timespec ts; + struct sample sample; + + if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts)) { + perror("[FAIL] clock_gettime(CLOCK_MONOTONIC_RAW)"); + ksft_exit_fail(); + } + + mono_raw_base = ts.tv_sec; + + if (clock_gettime(CLOCK_MONOTONIC, &ts)) { + perror("[FAIL] clock_gettime(CLOCK_MONOTONIC)"); + ksft_exit_fail(); + } + + mono_base = ts.tv_sec; + + user_hz = sysconf(_SC_CLK_TCK); + + precision = get_sample(&sample) / 2.0; + printf("CLOCK_MONOTONIC_RAW+CLOCK_MONOTONIC precision: %.0f ns\t\t", + 1e9 * precision); + + if (precision > MAX_PRECISION) { + printf("[SKIP]\n"); + ksft_exit_skip(); + } + + printf("[OK]\n"); + srand(ts.tv_sec ^ ts.tv_nsec); + + run_test(1, 0.0, 0.0); +} + +int main(int argc, char **argv) +{ + double freq_base, freq_step; + int i, j, fails = 0; + + init_test(); + + printf("Checking response to frequency step:\n"); + printf(" Step 1st interval 2nd interval\n"); + printf(" Freq Dev Max Freq Dev Max\n"); + + for (i = 2; i >= 0; i--) { + for (j = 0; j < 5; j++) { + freq_base = (rand() % (1 << 24) - (1 << 23)) / 65536e6; + freq_step = 10e-6 * (1 << (6 * i)); + fails += run_test(0, freq_base, freq_step); + } + } + + set_frequency(0.0); + + if (fails) + ksft_exit_fail(); + + ksft_exit_pass(); +} diff --git a/tools/testing/selftests/timers/inconsistency-check.c b/tools/testing/selftests/timers/inconsistency-check.c index caf1bc9..74c60e8 100644 --- a/tools/testing/selftests/timers/inconsistency-check.c +++ b/tools/testing/selftests/timers/inconsistency-check.c @@ -118,7 +118,7 @@ int consistency_test(int clock_type, unsigned long seconds) start_str = ctime(&t); while (seconds == -1 || now - then < seconds) { - inconsistent = 0; + inconsistent = -1; /* Fill list */ for (i = 0; i < CALLS_PER_LOOP; i++) @@ -130,7 +130,7 @@ int consistency_test(int clock_type, unsigned long seconds) inconsistent = i; /* display inconsistency */ - if (inconsistent) { + if (inconsistent >= 0) { unsigned long long delta; printf("\%s\n", start_str); |