提交 1b044f1c 编写于 作者: L Linus Torvalds

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
  ...
...@@ -7,7 +7,11 @@ Required properties: ...@@ -7,7 +7,11 @@ Required properties:
- compatible : Must be one of - compatible : Must be one of
"faraday,fttmr010" "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 - reg : Should contain registers location and length
- interrupts : Should contain the three timer interrupts usually with - interrupts : Should contain the three timer interrupts usually with
flags for falling edge flags for falling edge
......
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>;
};
...@@ -36,7 +36,6 @@ generic-y += preempt.h ...@@ -36,7 +36,6 @@ generic-y += preempt.h
generic-y += resource.h generic-y += resource.h
generic-y += sembuf.h generic-y += sembuf.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += siginfo.h
generic-y += socket.h generic-y += socket.h
generic-y += sockios.h generic-y += sockios.h
generic-y += stat.h generic-y += stat.h
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
...@@ -470,7 +470,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -470,7 +470,7 @@ void __init setup_arch(char **cmdline_p)
void __init time_init(void) void __init time_init(void)
{ {
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
} }
static int __init customize_machine(void) static int __init customize_machine(void)
......
...@@ -337,7 +337,7 @@ config ARCH_MULTIPLATFORM ...@@ -337,7 +337,7 @@ config ARCH_MULTIPLATFORM
select ARM_HAS_SG_CHAIN select ARM_HAS_SG_CHAIN
select ARM_PATCH_PHYS_VIRT select ARM_PATCH_PHYS_VIRT
select AUTO_ZRELADDR select AUTO_ZRELADDR
select CLKSRC_OF select TIMER_OF
select COMMON_CLK select COMMON_CLK
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select MIGHT_HAVE_PCI select MIGHT_HAVE_PCI
...@@ -351,7 +351,7 @@ config ARM_SINGLE_ARMV7M ...@@ -351,7 +351,7 @@ config ARM_SINGLE_ARMV7M
depends on !MMU depends on !MMU
select ARM_NVIC select ARM_NVIC
select AUTO_ZRELADDR select AUTO_ZRELADDR
select CLKSRC_OF select TIMER_OF
select COMMON_CLK select COMMON_CLK
select CPU_V7M select CPU_V7M
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
...@@ -532,7 +532,7 @@ config ARCH_PXA ...@@ -532,7 +532,7 @@ config ARCH_PXA
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select CLKSRC_PXA select CLKSRC_PXA
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF select TIMER_OF
select CPU_XSCALE if !CPU_XSC3 select CPU_XSCALE if !CPU_XSC3
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GPIO_PXA select GPIO_PXA
...@@ -571,7 +571,7 @@ config ARCH_SA1100 ...@@ -571,7 +571,7 @@ config ARCH_SA1100
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_PXA select CLKSRC_PXA
select CLKSRC_OF if OF select TIMER_OF if OF
select CPU_FREQ select CPU_FREQ
select CPU_SA1100 select CPU_SA1100
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
...@@ -1357,7 +1357,7 @@ config HAVE_ARM_ARCH_TIMER ...@@ -1357,7 +1357,7 @@ config HAVE_ARM_ARCH_TIMER
config HAVE_ARM_TWD config HAVE_ARM_TWD
bool bool
select CLKSRC_OF if OF select TIMER_OF if OF
help help
This options enables support for the ARM timer and watchdog unit This options enables support for the ARM timer and watchdog unit
......
...@@ -893,6 +893,7 @@ ...@@ -893,6 +893,7 @@
//interrupts = <16 17 18 35 36 37 38 39>; //interrupts = <16 17 18 35 36 37 38 39>;
interrupts = <16>; interrupts = <16>;
clocks = <&clk_apb>; clocks = <&clk_apb>;
clock-names = "PCLK";
}; };
wdt1: wdt@1e785000 { wdt1: wdt@1e785000 {
......
...@@ -1000,6 +1000,7 @@ ...@@ -1000,6 +1000,7 @@
//interrupts = <16 17 18 35 36 37 38 39>; //interrupts = <16 17 18 35 36 37 38 39>;
interrupts = <16>; interrupts = <16>;
clocks = <&clk_apb>; clocks = <&clk_apb>;
clock-names = "PCLK";
}; };
......
...@@ -28,7 +28,6 @@ generic-y += segment.h ...@@ -28,7 +28,6 @@ generic-y += segment.h
generic-y += sembuf.h generic-y += sembuf.h
generic-y += serial.h generic-y += serial.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += siginfo.h
generic-y += simd.h generic-y += simd.h
generic-y += sizes.h generic-y += sizes.h
generic-y += socket.h generic-y += socket.h
......
...@@ -4,3 +4,5 @@ include include/uapi/asm-generic/Kbuild.asm ...@@ -4,3 +4,5 @@ include include/uapi/asm-generic/Kbuild.asm
genhdr-y += unistd-common.h genhdr-y += unistd-common.h
genhdr-y += unistd-oabi.h genhdr-y += unistd-oabi.h
genhdr-y += unistd-eabi.h genhdr-y += unistd-eabi.h
generic-y += siginfo.h
...@@ -403,7 +403,7 @@ static int __init twd_local_timer_of_register(struct device_node *np) ...@@ -403,7 +403,7 @@ static int __init twd_local_timer_of_register(struct device_node *np)
WARN(err, "twd_local_timer_of_register failed (%d)\n", err); WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
return err; return err;
} }
CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); TIMER_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); TIMER_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_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register);
#endif #endif
...@@ -120,6 +120,6 @@ void __init time_init(void) ...@@ -120,6 +120,6 @@ void __init time_init(void)
#ifdef CONFIG_COMMON_CLK #ifdef CONFIG_COMMON_CLK
of_clk_init(NULL); of_clk_init(NULL);
#endif #endif
clocksource_probe(); timer_probe();
} }
} }
...@@ -4,7 +4,7 @@ menuconfig ARCH_ASPEED ...@@ -4,7 +4,7 @@ menuconfig ARCH_ASPEED
select SRAM select SRAM
select WATCHDOG select WATCHDOG
select ASPEED_WATCHDOG select ASPEED_WATCHDOG
select MOXART_TIMER select FTTMR010_TIMER
select MFD_SYSCON select MFD_SYSCON
select PINCTRL select PINCTRL
help help
......
...@@ -150,7 +150,7 @@ config ARCH_BCM2835 ...@@ -150,7 +150,7 @@ config ARCH_BCM2835
select ARM_ERRATA_411920 if ARCH_MULTI_V6 select ARM_ERRATA_411920 if ARCH_MULTI_V6
select ARM_TIMER_SP804 select ARM_TIMER_SP804
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
select CLKSRC_OF select TIMER_OF
select BCM2835_TIMER select BCM2835_TIMER
select PINCTRL select PINCTRL
select PINCTRL_BCM2835 select PINCTRL_BCM2835
......
...@@ -2,7 +2,7 @@ menuconfig ARCH_CLPS711X ...@@ -2,7 +2,7 @@ menuconfig ARCH_CLPS711X
bool "Cirrus Logic EP721x/EP731x-based" bool "Cirrus Logic EP721x/EP731x-based"
depends on ARCH_MULTI_V4T depends on ARCH_MULTI_V4T
select AUTO_ZRELADDR select AUTO_ZRELADDR
select CLKSRC_OF select TIMER_OF
select CLPS711X_TIMER select CLPS711X_TIMER
select COMMON_CLK select COMMON_CLK
select CPU_ARM720T select CPU_ARM720T
......
...@@ -41,7 +41,7 @@ static void __init mediatek_timer_init(void) ...@@ -41,7 +41,7 @@ static void __init mediatek_timer_init(void)
} }
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
}; };
static const char * const mediatek_board_dt_compat[] = { static const char * const mediatek_board_dt_compat[] = {
......
...@@ -4,7 +4,7 @@ menuconfig ARCH_MOXART ...@@ -4,7 +4,7 @@ menuconfig ARCH_MOXART
select CPU_FA526 select CPU_FA526
select ARM_DMA_MEM_BUFFERABLE select ARM_DMA_MEM_BUFFERABLE
select FARADAY_FTINTC010 select FARADAY_FTINTC010
select MOXART_TIMER select FTTMR010_TIMER
select GPIOLIB select GPIOLIB
select PHYLIB if NETDEVICES select PHYLIB if NETDEVICES
help help
......
...@@ -497,7 +497,7 @@ void __init omap_init_time(void) ...@@ -497,7 +497,7 @@ void __init omap_init_time(void)
__omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon", __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon",
2, "timer_sys_ck", NULL, false); 2, "timer_sys_ck", NULL, false);
clocksource_probe(); timer_probe();
} }
#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX) #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX)
...@@ -506,7 +506,7 @@ void __init omap3_secure_sync32k_timer_init(void) ...@@ -506,7 +506,7 @@ void __init omap3_secure_sync32k_timer_init(void)
__omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure", __omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure",
2, "timer_sys_ck", NULL, false); 2, "timer_sys_ck", NULL, false);
clocksource_probe(); timer_probe();
} }
#endif /* CONFIG_ARCH_OMAP3 */ #endif /* CONFIG_ARCH_OMAP3 */
...@@ -517,7 +517,7 @@ void __init omap3_gptimer_timer_init(void) ...@@ -517,7 +517,7 @@ void __init omap3_gptimer_timer_init(void)
__omap_sync32k_timer_init(2, "timer_sys_ck", NULL, __omap_sync32k_timer_init(2, "timer_sys_ck", NULL,
1, "timer_sys_ck", "ti,timer-alwon", true); 1, "timer_sys_ck", "ti,timer-alwon", true);
if (of_have_populated_dt()) if (of_have_populated_dt())
clocksource_probe(); timer_probe();
} }
#endif #endif
...@@ -532,7 +532,7 @@ static void __init omap4_sync32k_timer_init(void) ...@@ -532,7 +532,7 @@ static void __init omap4_sync32k_timer_init(void)
void __init omap4_local_timer_init(void) void __init omap4_local_timer_init(void)
{ {
omap4_sync32k_timer_init(); omap4_sync32k_timer_init();
clocksource_probe(); timer_probe();
} }
#endif #endif
...@@ -656,7 +656,7 @@ void __init omap5_realtime_timer_init(void) ...@@ -656,7 +656,7 @@ void __init omap5_realtime_timer_init(void)
omap4_sync32k_timer_init(); omap4_sync32k_timer_init();
realtime_counter_init(); realtime_counter_init();
clocksource_probe(); timer_probe();
} }
#endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */
......
...@@ -55,7 +55,7 @@ static void __init rockchip_timer_init(void) ...@@ -55,7 +55,7 @@ static void __init rockchip_timer_init(void)
} }
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
} }
static void __init rockchip_dt_init(void) static void __init rockchip_dt_init(void)
......
...@@ -394,7 +394,7 @@ config MACH_SMDK2416 ...@@ -394,7 +394,7 @@ config MACH_SMDK2416
config MACH_S3C2416_DT config MACH_S3C2416_DT
bool "Samsung S3C2416 machine using devicetree" bool "Samsung S3C2416 machine using devicetree"
select CLKSRC_OF select TIMER_OF
select USE_OF select USE_OF
select PINCTRL select PINCTRL
select PINCTRL_S3C24XX select PINCTRL_S3C24XX
......
...@@ -336,7 +336,7 @@ config MACH_WLF_CRAGG_6410 ...@@ -336,7 +336,7 @@ config MACH_WLF_CRAGG_6410
config MACH_S3C64XX_DT config MACH_S3C64XX_DT
bool "Samsung S3C6400/S3C6410 machine using Device Tree" bool "Samsung S3C6400/S3C6410 machine using Device Tree"
select CLKSRC_OF select TIMER_OF
select CPU_S3C6400 select CPU_S3C6400
select CPU_S3C6410 select CPU_S3C6410
select PINCTRL select PINCTRL
......
...@@ -113,7 +113,7 @@ void __init rcar_gen2_timer_init(void) ...@@ -113,7 +113,7 @@ void __init rcar_gen2_timer_init(void)
#endif /* CONFIG_ARM_ARCH_TIMER */ #endif /* CONFIG_ARM_ARCH_TIMER */
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
} }
struct memory_reserve_config { struct memory_reserve_config {
......
...@@ -124,5 +124,5 @@ void __init spear13xx_timer_init(void) ...@@ -124,5 +124,5 @@ void __init spear13xx_timer_init(void)
clk_put(pclk); clk_put(pclk);
spear_setup_of_timer(); spear_setup_of_timer();
clocksource_probe(); timer_probe();
} }
...@@ -42,7 +42,7 @@ static void __init sun6i_timer_init(void) ...@@ -42,7 +42,7 @@ static void __init sun6i_timer_init(void)
of_clk_init(NULL); of_clk_init(NULL);
if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
sun6i_reset_init(); sun6i_reset_init();
clocksource_probe(); timer_probe();
} }
DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family")
......
...@@ -407,7 +407,7 @@ static const char * u300_board_compat[] = { ...@@ -407,7 +407,7 @@ static const char * u300_board_compat[] = {
DT_MACHINE_START(U300_DT, "U300 S335/B335 (Device Tree)") DT_MACHINE_START(U300_DT, "U300 S335/B335 (Device Tree)")
.map_io = u300_map_io, .map_io = u300_map_io,
.init_irq = u300_init_irq_dt, .init_irq = u300_init_irq_dt,
.init_time = clocksource_probe, .init_time = timer_probe,
.init_machine = u300_init_machine_dt, .init_machine = u300_init_machine_dt,
.restart = u300_restart, .restart = u300_restart,
.dt_compat = u300_board_compat, .dt_compat = u300_board_compat,
......
...@@ -150,7 +150,7 @@ static void __init zynq_timer_init(void) ...@@ -150,7 +150,7 @@ static void __init zynq_timer_init(void)
{ {
zynq_clock_init(); zynq_clock_init();
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
} }
static struct map_desc zynq_cortex_a9_scu_map __initdata = { static struct map_desc zynq_cortex_a9_scu_map __initdata = {
......
...@@ -18,7 +18,7 @@ config ARCH_ALPINE ...@@ -18,7 +18,7 @@ config ARCH_ALPINE
config ARCH_BCM2835 config ARCH_BCM2835
bool "Broadcom BCM2835 family" bool "Broadcom BCM2835 family"
select CLKSRC_OF select TIMER_OF
select GPIOLIB select GPIOLIB
select PINCTRL select PINCTRL
select PINCTRL_BCM2835 select PINCTRL_BCM2835
...@@ -178,7 +178,7 @@ config ARCH_TEGRA ...@@ -178,7 +178,7 @@ config ARCH_TEGRA
select ARCH_HAS_RESET_CONTROLLER select ARCH_HAS_RESET_CONTROLLER
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF select TIMER_OF
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GPIOLIB select GPIOLIB
select PINCTRL select PINCTRL
......
...@@ -70,7 +70,7 @@ void __init time_init(void) ...@@ -70,7 +70,7 @@ void __init time_init(void)
u32 arch_timer_rate; u32 arch_timer_rate;
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
tick_setup_hrtimer_broadcast(); tick_setup_hrtimer_broadcast();
......
...@@ -220,10 +220,8 @@ void update_vsyscall(struct timekeeper *tk) ...@@ -220,10 +220,8 @@ void update_vsyscall(struct timekeeper *tk)
if (!use_syscall) { if (!use_syscall) {
/* tkr_mono.cycle_last == tkr_raw.cycle_last */ /* tkr_mono.cycle_last == tkr_raw.cycle_last */
vdso_data->cs_cycle_last = tk->tkr_mono.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_sec = tk->raw_sec;
vdso_data->raw_time_nsec = (tk->raw_time.tv_nsec << vdso_data->raw_time_nsec = tk->tkr_raw.xtime_nsec;
tk->tkr_raw.shift) +
tk->tkr_raw.xtime_nsec;
vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_sec = tk->xtime_sec;
vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec;
vdso_data->cs_mono_mult = tk->tkr_mono.mult; vdso_data->cs_mono_mult = tk->tkr_mono.mult;
......
...@@ -45,7 +45,6 @@ generic-y += sembuf.h ...@@ -45,7 +45,6 @@ generic-y += sembuf.h
generic-y += serial.h generic-y += serial.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += shmparam.h generic-y += shmparam.h
generic-y += siginfo.h
generic-y += signal.h generic-y += signal.h
generic-y += socket.h generic-y += socket.h
generic-y += sockios.h generic-y += sockios.h
......
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += kvm_para.h generic-y += kvm_para.h
generic-y += siginfo.h
...@@ -36,7 +36,6 @@ generic-y += resource.h ...@@ -36,7 +36,6 @@ generic-y += resource.h
generic-y += sections.h generic-y += sections.h
generic-y += sembuf.h generic-y += sembuf.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += siginfo.h
generic-y += socket.h generic-y += socket.h
generic-y += sockios.h generic-y += sockios.h
generic-y += statfs.h generic-y += statfs.h
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
...@@ -15,7 +15,7 @@ config H8300 ...@@ -15,7 +15,7 @@ config H8300
select OF_IRQ select OF_IRQ
select OF_EARLY_FLATTREE select OF_EARLY_FLATTREE
select HAVE_MEMBLOCK select HAVE_MEMBLOCK
select CLKSRC_OF select TIMER_OF
select H8300_TMR8 select H8300_TMR8
select HAVE_KERNEL_GZIP select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZO select HAVE_KERNEL_LZO
......
...@@ -54,7 +54,6 @@ generic-y += serial.h ...@@ -54,7 +54,6 @@ generic-y += serial.h
generic-y += setup.h generic-y += setup.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += shmparam.h generic-y += shmparam.h
generic-y += siginfo.h
generic-y += sizes.h generic-y += sizes.h
generic-y += socket.h generic-y += socket.h
generic-y += sockios.h generic-y += sockios.h
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
...@@ -246,5 +246,5 @@ void __init calibrate_delay(void) ...@@ -246,5 +246,5 @@ void __init calibrate_delay(void)
void __init time_init(void) void __init time_init(void)
{ {
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
} }
...@@ -41,7 +41,6 @@ generic-y += sembuf.h ...@@ -41,7 +41,6 @@ generic-y += sembuf.h
generic-y += serial.h generic-y += serial.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += shmparam.h generic-y += shmparam.h
generic-y += siginfo.h
generic-y += sizes.h generic-y += sizes.h
generic-y += socket.h generic-y += socket.h
generic-y += sockios.h generic-y += sockios.h
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
/*
* 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 */
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
#define HAVE_ARCH_SIGINFO_T #define HAVE_ARCH_SIGINFO_T
#define HAVE_ARCH_COPY_SIGINFO
#define HAVE_ARCH_COPY_SIGINFO_TO_USER #define HAVE_ARCH_COPY_SIGINFO_TO_USER
#include <asm-generic/siginfo.h> #include <asm-generic/siginfo.h>
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
#ifndef _M32R_SIGINFO_H
#define _M32R_SIGINFO_H
#include <asm-generic/siginfo.h>
#endif /* _M32R_SIGINFO_H */
...@@ -25,7 +25,6 @@ generic-y += preempt.h ...@@ -25,7 +25,6 @@ generic-y += preempt.h
generic-y += resource.h generic-y += resource.h
generic-y += sections.h generic-y += sections.h
generic-y += shmparam.h generic-y += shmparam.h
generic-y += siginfo.h
generic-y += spinlock.h generic-y += spinlock.h
generic-y += statfs.h generic-y += statfs.h
generic-y += termios.h generic-y += termios.h
......
...@@ -5,6 +5,7 @@ generic-y += auxvec.h ...@@ -5,6 +5,7 @@ generic-y += auxvec.h
generic-y += msgbuf.h generic-y += msgbuf.h
generic-y += sembuf.h generic-y += sembuf.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += siginfo.h
generic-y += socket.h generic-y += socket.h
generic-y += sockios.h generic-y += sockios.h
generic-y += termbits.h generic-y += termbits.h
......
...@@ -4,7 +4,7 @@ config MICROBLAZE ...@@ -4,7 +4,7 @@ config MICROBLAZE
select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WANT_IPC_PARSE_VERSION
select BUILDTIME_EXTABLE_SORT select BUILDTIME_EXTABLE_SORT
select CLKSRC_OF select TIMER_OF
select CLONE_BACKWARDS3 select CLONE_BACKWARDS3
select COMMON_CLK select COMMON_CLK
select GENERIC_ATOMIC64 select GENERIC_ATOMIC64
......
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += types.h generic-y += types.h
generic-y += siginfo.h
...@@ -192,7 +192,7 @@ void __init time_init(void) ...@@ -192,7 +192,7 @@ void __init time_init(void)
{ {
of_clk_init(NULL); of_clk_init(NULL);
setup_cpuinfo_clk(); setup_cpuinfo_clk();
clocksource_probe(); timer_probe();
} }
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
......
...@@ -335,5 +335,5 @@ static int __init xilinx_timer_init(struct device_node *timer) ...@@ -335,5 +335,5 @@ static int __init xilinx_timer_init(struct device_node *timer)
return 0; 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); xilinx_timer_init);
...@@ -161,7 +161,7 @@ void __init plat_time_init(void) ...@@ -161,7 +161,7 @@ void __init plat_time_init(void)
} }
} }
clocksource_probe(); timer_probe();
} }
void __init arch_init_irq(void) void __init arch_init_irq(void)
......
...@@ -265,7 +265,7 @@ void __init plat_time_init(void) ...@@ -265,7 +265,7 @@ void __init plat_time_init(void)
(freq%1000000)*100/1000000); (freq%1000000)*100/1000000);
#ifdef CONFIG_CLKSRC_MIPS_GIC #ifdef CONFIG_CLKSRC_MIPS_GIC
update_gic_frequency_dt(); update_gic_frequency_dt();
clocksource_probe(); timer_probe();
#endif #endif
} }
#endif #endif
......
...@@ -64,5 +64,5 @@ void __init plat_time_init(void) ...@@ -64,5 +64,5 @@ void __init plat_time_init(void)
pr_info("CPU Clock: %ldMHz\n", rate / 1000000); pr_info("CPU Clock: %ldMHz\n", rate / 1000000);
mips_hpt_frequency = rate / 2; mips_hpt_frequency = rate / 2;
clocksource_probe(); timer_probe();
} }
...@@ -39,7 +39,7 @@ void __init plat_time_init(void) ...@@ -39,7 +39,7 @@ void __init plat_time_init(void)
struct clk *clk; struct clk *clk;
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
np = of_get_cpu_node(0, NULL); np = of_get_cpu_node(0, NULL);
if (!np) { if (!np) {
......
...@@ -4,7 +4,7 @@ config CLKEVT_RT3352 ...@@ -4,7 +4,7 @@ config CLKEVT_RT3352
bool bool
depends on SOC_RT305X || SOC_MT7620 depends on SOC_RT305X || SOC_MT7620
default y default y
select CLKSRC_OF select TIMER_OF
select CLKSRC_MMIO select CLKSRC_MMIO
config RALINK_ILL_ACC config RALINK_ILL_ACC
......
...@@ -152,4 +152,4 @@ static int __init ralink_systick_init(struct device_node *np) ...@@ -152,4 +152,4 @@ static int __init ralink_systick_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
...@@ -82,5 +82,5 @@ void __init plat_time_init(void) ...@@ -82,5 +82,5 @@ void __init plat_time_init(void)
pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
mips_hpt_frequency = clk_get_rate(clk) / 2; mips_hpt_frequency = clk_get_rate(clk) / 2;
clk_put(clk); clk_put(clk);
clocksource_probe(); timer_probe();
} }
...@@ -20,5 +20,5 @@ void __init plat_time_init(void) ...@@ -20,5 +20,5 @@ void __init plat_time_init(void)
ralink_of_remap(); ralink_of_remap();
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
} }
...@@ -22,7 +22,7 @@ void __init plat_time_init(void) ...@@ -22,7 +22,7 @@ void __init plat_time_init(void)
struct clk *clk; struct clk *clk;
of_clk_init(NULL); of_clk_init(NULL);
clocksource_probe(); timer_probe();
np = of_get_cpu_node(0, NULL); np = of_get_cpu_node(0, NULL);
if (!np) { if (!np) {
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
config NIOS2 config NIOS2
def_bool y def_bool y
select CLKSRC_OF select TIMER_OF
select GENERIC_ATOMIC64 select GENERIC_ATOMIC64
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GENERIC_CPU_DEVICES select GENERIC_CPU_DEVICES
......
...@@ -47,7 +47,6 @@ generic-y += segment.h ...@@ -47,7 +47,6 @@ generic-y += segment.h
generic-y += sembuf.h generic-y += sembuf.h
generic-y += serial.h generic-y += serial.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += siginfo.h
generic-y += signal.h generic-y += signal.h
generic-y += socket.h generic-y += socket.h
generic-y += sockios.h generic-y += sockios.h
......
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += setup.h generic-y += setup.h
generic-y += siginfo.h
generic-y += ucontext.h generic-y += ucontext.h
...@@ -350,7 +350,7 @@ void __init time_init(void) ...@@ -350,7 +350,7 @@ void __init time_init(void)
if (count < 2) if (count < 2)
panic("%d timer is found, it needs 2 timers in system\n", count); 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);
...@@ -46,7 +46,6 @@ generic-y += sembuf.h ...@@ -46,7 +46,6 @@ generic-y += sembuf.h
generic-y += setup.h generic-y += setup.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += shmparam.h generic-y += shmparam.h
generic-y += siginfo.h
generic-y += signal.h generic-y += signal.h
generic-y += socket.h generic-y += socket.h
generic-y += sockios.h generic-y += sockios.h
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
#ifndef _ASM_SCORE_SIGINFO_H
#define _ASM_SCORE_SIGINFO_H
#include <asm-generic/siginfo.h>
#endif /* _ASM_SCORE_SIGINFO_H */
...@@ -10,7 +10,7 @@ config SH_DEVICE_TREE ...@@ -10,7 +10,7 @@ config SH_DEVICE_TREE
bool "Board Described by Device Tree" bool "Board Described by Device Tree"
select OF select OF
select OF_EARLY_FLATTREE select OF_EARLY_FLATTREE
select CLKSRC_OF select TIMER_OF
select COMMON_CLK select COMMON_CLK
select GENERIC_CALIBRATE_DELAY select GENERIC_CALIBRATE_DELAY
help help
......
...@@ -119,7 +119,7 @@ static void __init sh_of_mem_reserve(void) ...@@ -119,7 +119,7 @@ static void __init sh_of_mem_reserve(void)
static void __init sh_of_time_init(void) static void __init sh_of_time_init(void)
{ {
pr_info("SH generic board support: scanning for clocksource devices\n"); pr_info("SH generic board support: scanning for clocksource devices\n");
clocksource_probe(); timer_probe();
} }
static void __init sh_of_setup(char **cmdline_p) static void __init sh_of_setup(char **cmdline_p)
......
...@@ -29,7 +29,6 @@ generic-y += rwsem.h ...@@ -29,7 +29,6 @@ generic-y += rwsem.h
generic-y += sembuf.h generic-y += sembuf.h
generic-y += serial.h generic-y += serial.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += siginfo.h
generic-y += sizes.h generic-y += sizes.h
generic-y += socket.h generic-y += socket.h
generic-y += statfs.h generic-y += statfs.h
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
#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) */
...@@ -44,7 +44,6 @@ generic-y += serial.h ...@@ -44,7 +44,6 @@ generic-y += serial.h
generic-y += setup.h generic-y += setup.h
generic-y += shmbuf.h generic-y += shmbuf.h
generic-y += shmparam.h generic-y += shmparam.h
generic-y += siginfo.h
generic-y += signal.h generic-y += signal.h
generic-y += sizes.h generic-y += sizes.h
generic-y += socket.h generic-y += socket.h
......
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += kvm_para.h generic-y += kvm_para.h
generic-y += siginfo.h
...@@ -25,7 +25,6 @@ generic-y += preempt.h ...@@ -25,7 +25,6 @@ generic-y += preempt.h
generic-y += resource.h generic-y += resource.h
generic-y += rwsem.h generic-y += rwsem.h
generic-y += sections.h generic-y += sections.h
generic-y += siginfo.h
generic-y += statfs.h generic-y += statfs.h
generic-y += termios.h generic-y += termios.h
generic-y += topology.h generic-y += topology.h
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
generic-y += siginfo.h
...@@ -187,7 +187,7 @@ void __init time_init(void) ...@@ -187,7 +187,7 @@ void __init time_init(void)
local_timer_setup(0); local_timer_setup(0);
setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction); setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction);
sched_clock_register(ccount_sched_clock_read, 32, ccount_freq); sched_clock_register(ccount_sched_clock_read, 32, ccount_freq);
clocksource_probe(); timer_probe();
} }
/* /*
......
...@@ -539,15 +539,6 @@ config HANGCHECK_TIMER ...@@ -539,15 +539,6 @@ config HANGCHECK_TIMER
out to lunch past a certain margin. It can reboot the system out to lunch past a certain margin. It can reboot the system
or merely print a warning. 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 config UV_MMTIMER
tristate "UV_MMTIMER Memory mapped RTC for SGI UV" tristate "UV_MMTIMER Memory mapped RTC for SGI UV"
depends on X86_UV depends on X86_UV
......
...@@ -10,7 +10,6 @@ obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o ...@@ -10,7 +10,6 @@ obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
obj-$(CONFIG_IBM_BSR) += bsr.o obj-$(CONFIG_IBM_BSR) += bsr.o
obj-$(CONFIG_SGI_MBCS) += mbcs.o obj-$(CONFIG_SGI_MBCS) += mbcs.o
......
/*
* 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);
menu "Clock Source drivers" menu "Clock Source drivers"
depends on !ARCH_USES_GETTIMEOFFSET depends on !ARCH_USES_GETTIMEOFFSET
config CLKSRC_OF config TIMER_OF
bool bool
select CLKSRC_PROBE depends on GENERIC_CLOCKEVENTS
select TIMER_PROBE
config CLKEVT_OF
bool
select CLKEVT_PROBE
config CLKSRC_ACPI
bool
select CLKSRC_PROBE
config CLKSRC_PROBE config TIMER_ACPI
bool bool
select TIMER_PROBE
config CLKEVT_PROBE config TIMER_PROBE
bool bool
config CLKSRC_I8253 config CLKSRC_I8253
...@@ -65,14 +59,14 @@ config DW_APB_TIMER ...@@ -65,14 +59,14 @@ config DW_APB_TIMER
config DW_APB_TIMER_OF config DW_APB_TIMER_OF
bool bool
select DW_APB_TIMER select DW_APB_TIMER
select CLKSRC_OF select TIMER_OF
config FTTMR010_TIMER config FTTMR010_TIMER
bool "Faraday Technology timer driver" if COMPILE_TEST bool "Faraday Technology timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
depends on HAS_IOMEM depends on HAS_IOMEM
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF select TIMER_OF
select MFD_SYSCON select MFD_SYSCON
help help
Enables support for the Faraday Technology timer block Enables support for the Faraday Technology timer block
...@@ -81,7 +75,7 @@ config FTTMR010_TIMER ...@@ -81,7 +75,7 @@ config FTTMR010_TIMER
config ROCKCHIP_TIMER config ROCKCHIP_TIMER
bool "Rockchip timer driver" if COMPILE_TEST bool "Rockchip timer driver" if COMPILE_TEST
depends on ARM || ARM64 depends on ARM || ARM64
select CLKSRC_OF select TIMER_OF
select CLKSRC_MMIO select CLKSRC_MMIO
help help
Enables the support for the rockchip timer driver. Enables the support for the rockchip timer driver.
...@@ -89,7 +83,7 @@ config ROCKCHIP_TIMER ...@@ -89,7 +83,7 @@ config ROCKCHIP_TIMER
config ARMADA_370_XP_TIMER config ARMADA_370_XP_TIMER
bool "Armada 370 and XP timer driver" if COMPILE_TEST bool "Armada 370 and XP timer driver" if COMPILE_TEST
depends on ARM depends on ARM
select CLKSRC_OF select TIMER_OF
select CLKSRC_MMIO select CLKSRC_MMIO
help help
Enables the support for the Armada 370 and XP timer driver. Enables the support for the Armada 370 and XP timer driver.
...@@ -104,7 +98,7 @@ config MESON6_TIMER ...@@ -104,7 +98,7 @@ config MESON6_TIMER
config ORION_TIMER config ORION_TIMER
bool "Orion timer driver" if COMPILE_TEST bool "Orion timer driver" if COMPILE_TEST
depends on ARM depends on ARM
select CLKSRC_OF select TIMER_OF
select CLKSRC_MMIO select CLKSRC_MMIO
help help
Enables the support for the Orion timer driver Enables the support for the Orion timer driver
...@@ -114,6 +108,7 @@ config SUN4I_TIMER ...@@ -114,6 +108,7 @@ config SUN4I_TIMER
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
depends on HAS_IOMEM depends on HAS_IOMEM
select CLKSRC_MMIO select CLKSRC_MMIO
select TIMER_OF
help help
Enables support for the Sun4i timer. Enables support for the Sun4i timer.
...@@ -148,7 +143,7 @@ config ASM9260_TIMER ...@@ -148,7 +143,7 @@ config ASM9260_TIMER
bool "ASM9260 timer driver" if COMPILE_TEST bool "ASM9260 timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF select TIMER_OF
help help
Enables support for the ASM9260 timer. Enables support for the ASM9260 timer.
...@@ -188,13 +183,6 @@ config ATLAS7_TIMER ...@@ -188,13 +183,6 @@ config ATLAS7_TIMER
help help
Enables support for the Atlas7 timer. 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 config MXS_TIMER
bool "Mxs timer driver" if COMPILE_TEST bool "Mxs timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
...@@ -261,21 +249,21 @@ config CLKSRC_LPC32XX ...@@ -261,21 +249,21 @@ config CLKSRC_LPC32XX
depends on GENERIC_CLOCKEVENTS && HAS_IOMEM depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
depends on ARM depends on ARM
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF select TIMER_OF
help help
Support for the LPC32XX clocksource. Support for the LPC32XX clocksource.
config CLKSRC_PISTACHIO config CLKSRC_PISTACHIO
bool "Clocksource for Pistachio SoC" if COMPILE_TEST bool "Clocksource for Pistachio SoC" if COMPILE_TEST
depends on HAS_IOMEM depends on HAS_IOMEM
select CLKSRC_OF select TIMER_OF
help help
Enables the clocksource for the Pistachio SoC. Enables the clocksource for the Pistachio SoC.
config CLKSRC_TI_32K config CLKSRC_TI_32K
bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK depends on GENERIC_SCHED_CLOCK
select CLKSRC_OF if OF select TIMER_OF if OF
help help
This option enables support for Texas Instruments 32.768 Hz clocksource This option enables support for Texas Instruments 32.768 Hz clocksource
available on many OMAP-like platforms. available on many OMAP-like platforms.
...@@ -284,7 +272,7 @@ config CLKSRC_NPS ...@@ -284,7 +272,7 @@ config CLKSRC_NPS
bool "NPS400 clocksource driver" if COMPILE_TEST bool "NPS400 clocksource driver" if COMPILE_TEST
depends on !PHYS_ADDR_T_64BIT depends on !PHYS_ADDR_T_64BIT
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF if OF select TIMER_OF if OF
help help
NPS400 clocksource support. NPS400 clocksource support.
Got 64 bit counter with update rate up to 1000MHz. Got 64 bit counter with update rate up to 1000MHz.
...@@ -299,12 +287,12 @@ config CLKSRC_MPS2 ...@@ -299,12 +287,12 @@ config CLKSRC_MPS2
bool "Clocksource for MPS2 SoCs" if COMPILE_TEST bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK depends on GENERIC_SCHED_CLOCK
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF select TIMER_OF
config ARC_TIMERS config ARC_TIMERS
bool "Support for 32-bit TIMERn counters in ARC Cores" if COMPILE_TEST bool "Support for 32-bit TIMERn counters in ARC Cores" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
select CLKSRC_OF select TIMER_OF
help help
These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores
(ARC700 as well as ARC HS38). (ARC700 as well as ARC HS38).
...@@ -314,7 +302,7 @@ config ARC_TIMERS_64BIT ...@@ -314,7 +302,7 @@ config ARC_TIMERS_64BIT
bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
depends on ARC_TIMERS depends on ARC_TIMERS
select CLKSRC_OF select TIMER_OF
help help
This enables 2 different 64-bit timers: RTC (for UP) and GFRC (for SMP) 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 RTC is implemented inside the core, while GFRC sits outside the core in
...@@ -323,8 +311,8 @@ config ARC_TIMERS_64BIT ...@@ -323,8 +311,8 @@ config ARC_TIMERS_64BIT
config ARM_ARCH_TIMER config ARM_ARCH_TIMER
bool bool
select CLKSRC_OF if OF select TIMER_OF if OF
select CLKSRC_ACPI if ACPI select TIMER_ACPI if ACPI
config ARM_ARCH_TIMER_EVTSTREAM config ARM_ARCH_TIMER_EVTSTREAM
bool "Enable ARM architected timer event stream generation by default" bool "Enable ARM architected timer event stream generation by default"
...@@ -381,7 +369,7 @@ config ARM64_ERRATUM_858921 ...@@ -381,7 +369,7 @@ config ARM64_ERRATUM_858921
config ARM_GLOBAL_TIMER config ARM_GLOBAL_TIMER
bool "Support for the ARM global timer" if COMPILE_TEST bool "Support for the ARM global timer" if COMPILE_TEST
select CLKSRC_OF if OF select TIMER_OF if OF
depends on ARM depends on ARM
help help
This options enables support for the ARM global timer unit This options enables support for the ARM global timer unit
...@@ -390,7 +378,7 @@ config ARM_TIMER_SP804 ...@@ -390,7 +378,7 @@ config ARM_TIMER_SP804
bool "Support for Dual Timer SP804 module" bool "Support for Dual Timer SP804 module"
depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF if OF select TIMER_OF if OF
config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
bool bool
...@@ -401,19 +389,19 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK ...@@ -401,19 +389,19 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
config ARMV7M_SYSTICK config ARMV7M_SYSTICK
bool "Support for the ARMv7M system time" if COMPILE_TEST bool "Support for the ARMv7M system time" if COMPILE_TEST
select CLKSRC_OF if OF select TIMER_OF if OF
select CLKSRC_MMIO select CLKSRC_MMIO
help help
This options enables support for the ARMv7M system timer unit This options enables support for the ARMv7M system timer unit
config ATMEL_PIT config ATMEL_PIT
select CLKSRC_OF if OF select TIMER_OF if OF
def_bool SOC_AT91SAM9 || SOC_SAMA5 def_bool SOC_AT91SAM9 || SOC_SAMA5
config ATMEL_ST config ATMEL_ST
bool "Atmel ST timer support" if COMPILE_TEST bool "Atmel ST timer support" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
select CLKSRC_OF select TIMER_OF
select MFD_SYSCON select MFD_SYSCON
help help
Support for the Atmel ST timer. Support for the Atmel ST timer.
...@@ -456,7 +444,7 @@ config VF_PIT_TIMER ...@@ -456,7 +444,7 @@ config VF_PIT_TIMER
config OXNAS_RPS_TIMER config OXNAS_RPS_TIMER
bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
select CLKSRC_OF select TIMER_OF
select CLKSRC_MMIO select CLKSRC_MMIO
help help
This enables support for the Oxford Semiconductor OXNAS RPS timers. This enables support for the Oxford Semiconductor OXNAS RPS timers.
...@@ -467,7 +455,7 @@ config SYS_SUPPORTS_SH_CMT ...@@ -467,7 +455,7 @@ config SYS_SUPPORTS_SH_CMT
config MTK_TIMER config MTK_TIMER
bool "Mediatek timer driver" if COMPILE_TEST bool "Mediatek timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS && HAS_IOMEM depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
select CLKSRC_OF select TIMER_OF
select CLKSRC_MMIO select CLKSRC_MMIO
help help
Support for Mediatek timer driver. Support for Mediatek timer driver.
...@@ -540,7 +528,7 @@ config EM_TIMER_STI ...@@ -540,7 +528,7 @@ config EM_TIMER_STI
config CLKSRC_QCOM config CLKSRC_QCOM
bool "Qualcomm MSM timer" if COMPILE_TEST bool "Qualcomm MSM timer" if COMPILE_TEST
depends on ARM depends on ARM
select CLKSRC_OF select TIMER_OF
help help
This enables the clocksource and the per CPU clockevent driver for the This enables the clocksource and the per CPU clockevent driver for the
Qualcomm SoCs. Qualcomm SoCs.
...@@ -548,7 +536,7 @@ config CLKSRC_QCOM ...@@ -548,7 +536,7 @@ config CLKSRC_QCOM
config CLKSRC_VERSATILE config CLKSRC_VERSATILE
bool "ARM Versatile (Express) reference platforms clock source" if COMPILE_TEST bool "ARM Versatile (Express) reference platforms clock source" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK && !ARCH_USES_GETTIMEOFFSET depends on GENERIC_SCHED_CLOCK && !ARCH_USES_GETTIMEOFFSET
select CLKSRC_OF select TIMER_OF
default y if MFD_VEXPRESS_SYSREG default y if MFD_VEXPRESS_SYSREG
help help
This option enables clock source based on free running This option enables clock source based on free running
...@@ -559,12 +547,12 @@ config CLKSRC_VERSATILE ...@@ -559,12 +547,12 @@ config CLKSRC_VERSATILE
config CLKSRC_MIPS_GIC config CLKSRC_MIPS_GIC
bool bool
depends on MIPS_GIC depends on MIPS_GIC
select CLKSRC_OF select TIMER_OF
config CLKSRC_TANGO_XTAL config CLKSRC_TANGO_XTAL
bool "Clocksource for Tango SoC" if COMPILE_TEST bool "Clocksource for Tango SoC" if COMPILE_TEST
depends on ARM depends on ARM
select CLKSRC_OF select TIMER_OF
select CLKSRC_MMIO select CLKSRC_MMIO
help help
This enables the clocksource for Tango SoC This enables the clocksource for Tango SoC
...@@ -605,7 +593,7 @@ config CLKSRC_IMX_GPT ...@@ -605,7 +593,7 @@ config CLKSRC_IMX_GPT
config CLKSRC_ST_LPC config CLKSRC_ST_LPC
bool "Low power clocksource found in the LPC" if COMPILE_TEST 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 depends on HAS_IOMEM
select CLKSRC_MMIO select CLKSRC_MMIO
help help
......
obj-$(CONFIG_CLKSRC_PROBE) += clksrc-probe.o obj-$(CONFIG_TIMER_OF) += timer-of.o
obj-$(CONFIG_CLKEVT_PROBE) += clkevt-probe.o obj-$(CONFIG_TIMER_PROBE) += timer-probe.o
obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o
obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o
obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
...@@ -26,7 +26,6 @@ obj-$(CONFIG_ORION_TIMER) += time-orion.o ...@@ -26,7 +26,6 @@ obj-$(CONFIG_ORION_TIMER) += time-orion.o
obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o
obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o
obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o
obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o
obj-$(CONFIG_MXS_TIMER) += mxs_timer.o obj-$(CONFIG_MXS_TIMER) += mxs_timer.o
obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o
obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o
......
...@@ -99,7 +99,7 @@ static int __init arc_cs_setup_gfrc(struct device_node *node) ...@@ -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); 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_CTRL 0x103
#define AUX_RTC_LOW 0x104 #define AUX_RTC_LOW 0x104
...@@ -158,7 +158,7 @@ static int __init arc_cs_setup_rtc(struct device_node *node) ...@@ -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); 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 #endif
...@@ -333,4 +333,4 @@ static int __init arc_of_timer_init(struct device_node *np) ...@@ -333,4 +333,4 @@ static int __init arc_of_timer_init(struct device_node *np)
return ret; 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);
...@@ -1194,8 +1194,8 @@ static int __init arch_timer_of_init(struct device_node *np) ...@@ -1194,8 +1194,8 @@ static int __init arch_timer_of_init(struct device_node *np)
return arch_timer_common_init(); return arch_timer_common_init();
} }
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); TIMER_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(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
static u32 __init static u32 __init
arch_timer_mem_frame_get_cntfrq(struct arch_timer_mem_frame *frame) arch_timer_mem_frame_get_cntfrq(struct arch_timer_mem_frame *frame)
...@@ -1382,7 +1382,7 @@ static int __init arch_timer_mem_of_init(struct device_node *np) ...@@ -1382,7 +1382,7 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
kfree(timer_mem); kfree(timer_mem);
return ret; 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); arch_timer_mem_of_init);
#ifdef CONFIG_ACPI_GTDT #ifdef CONFIG_ACPI_GTDT
...@@ -1516,5 +1516,5 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) ...@@ -1516,5 +1516,5 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
return arch_timer_common_init(); 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 #endif
...@@ -339,5 +339,5 @@ static int __init global_timer_of_register(struct device_node *np) ...@@ -339,5 +339,5 @@ static int __init global_timer_of_register(struct device_node *np)
} }
/* Only tested on r2p2 and r3p0 */ /* 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); global_timer_of_register);
...@@ -82,5 +82,5 @@ static int __init system_timer_of_register(struct device_node *np) ...@@ -82,5 +82,5 @@ static int __init system_timer_of_register(struct device_node *np)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick", TIMER_OF_DECLARE(arm_systick, "arm,armv7m-systick",
system_timer_of_register); system_timer_of_register);
...@@ -238,5 +238,5 @@ static int __init asm9260_timer_init(struct device_node *np) ...@@ -238,5 +238,5 @@ static int __init asm9260_timer_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer", TIMER_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer",
asm9260_timer_init); asm9260_timer_init);
...@@ -148,5 +148,5 @@ static int __init bcm2835_timer_init(struct device_node *node) ...@@ -148,5 +148,5 @@ static int __init bcm2835_timer_init(struct device_node *node)
iounmap(base); iounmap(base);
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer", TIMER_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer",
bcm2835_timer_init); bcm2835_timer_init);
...@@ -198,9 +198,9 @@ static int __init kona_timer_init(struct device_node *node) ...@@ -198,9 +198,9 @@ static int __init kona_timer_init(struct device_node *node)
return 0; 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 * bcm,kona-timer is deprecated by brcm,kona-timer
* being kept here for driver compatibility * 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);
...@@ -540,4 +540,4 @@ static int __init ttc_timer_init(struct device_node *timer) ...@@ -540,4 +540,4 @@ static int __init ttc_timer_init(struct device_node *timer)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); TIMER_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init);
/*
* 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;
}
...@@ -86,5 +86,5 @@ static int __init clksrc_dbx500_prcmu_init(struct device_node *node) ...@@ -86,5 +86,5 @@ static int __init clksrc_dbx500_prcmu_init(struct device_node *node)
#endif #endif
return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K); 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); clksrc_dbx500_prcmu_init);
...@@ -132,4 +132,4 @@ static int __init st_clksrc_of_register(struct device_node *np) ...@@ -132,4 +132,4 @@ static int __init st_clksrc_of_register(struct device_node *np)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); TIMER_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register);
...@@ -103,7 +103,7 @@ void __init clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base, ...@@ -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)); 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) static int __init clps711x_timer_init(struct device_node *np)
{ {
unsigned int irq = irq_of_parse_and_map(np, 0); unsigned int irq = irq_of_parse_and_map(np, 0);
...@@ -119,5 +119,5 @@ static int __init clps711x_timer_init(struct device_node *np) ...@@ -119,5 +119,5 @@ static int __init clps711x_timer_init(struct device_node *np)
return -EINVAL; return -EINVAL;
} }
} }
CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,ep7209-timer", clps711x_timer_init); TIMER_OF_DECLARE(clps711x, "cirrus,ep7209-timer", clps711x_timer_init);
#endif #endif
...@@ -167,7 +167,7 @@ static int __init dw_apb_timer_init(struct device_node *timer) ...@@ -167,7 +167,7 @@ static int __init dw_apb_timer_init(struct device_node *timer)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); TIMER_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); TIMER_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); TIMER_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(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init);
...@@ -610,5 +610,5 @@ static int __init mct_init_ppi(struct device_node *np) ...@@ -610,5 +610,5 @@ static int __init mct_init_ppi(struct device_node *np)
{ {
return mct_init_dt(np, MCT_INT_PPI); return mct_init_dt(np, MCT_INT_PPI);
} }
CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi); TIMER_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi);
CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); TIMER_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi);
...@@ -329,13 +329,13 @@ static int __init ftm_timer_init(struct device_node *np) ...@@ -329,13 +329,13 @@ static int __init ftm_timer_init(struct device_node *np)
priv->clkevt_base = of_iomap(np, 0); priv->clkevt_base = of_iomap(np, 0);
if (!priv->clkevt_base) { if (!priv->clkevt_base) {
pr_err("ftm: unable to map event timer registers\n"); pr_err("ftm: unable to map event timer registers\n");
goto err; goto err_clkevt;
} }
priv->clksrc_base = of_iomap(np, 1); priv->clksrc_base = of_iomap(np, 1);
if (!priv->clksrc_base) { if (!priv->clksrc_base) {
pr_err("ftm: unable to map source timer registers\n"); pr_err("ftm: unable to map source timer registers\n");
goto err; goto err_clksrc;
} }
ret = -EINVAL; ret = -EINVAL;
...@@ -366,7 +366,11 @@ static int __init ftm_timer_init(struct device_node *np) ...@@ -366,7 +366,11 @@ static int __init ftm_timer_init(struct device_node *np)
return 0; return 0;
err: err:
iounmap(priv->clksrc_base);
err_clksrc:
iounmap(priv->clkevt_base);
err_clkevt:
kfree(priv); kfree(priv);
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init); TIMER_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init);
...@@ -187,5 +187,5 @@ static int __init h8300_16timer_init(struct device_node *node) ...@@ -187,5 +187,5 @@ static int __init h8300_16timer_init(struct device_node *node)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", TIMER_OF_DECLARE(h8300_16bit, "renesas,16bit-timer",
h8300_16timer_init); h8300_16timer_init);
...@@ -207,4 +207,4 @@ static int __init h8300_8timer_init(struct device_node *node) ...@@ -207,4 +207,4 @@ static int __init h8300_8timer_init(struct device_node *node)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); TIMER_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);
...@@ -154,4 +154,4 @@ static int __init h8300_tpu_init(struct device_node *node) ...@@ -154,4 +154,4 @@ static int __init h8300_tpu_init(struct device_node *node)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); TIMER_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init);
...@@ -246,4 +246,4 @@ static int __init jcore_pit_init(struct device_node *node) ...@@ -246,4 +246,4 @@ static int __init jcore_pit_init(struct device_node *node)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(jcore_pit, "jcore,pit", jcore_pit_init); TIMER_OF_DECLARE(jcore_pit, "jcore,pit", jcore_pit_init);
...@@ -174,5 +174,5 @@ static int __init meson6_timer_init(struct device_node *node) ...@@ -174,5 +174,5 @@ static int __init meson6_timer_init(struct device_node *node)
1, 0xfffe); 1, 0xfffe);
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", TIMER_OF_DECLARE(meson6, "amlogic,meson6-timer",
meson6_timer_init); meson6_timer_init);
...@@ -167,10 +167,11 @@ static int __init gic_clocksource_of_init(struct device_node *node) ...@@ -167,10 +167,11 @@ static int __init gic_clocksource_of_init(struct device_node *node)
clk = of_clk_get(node, 0); clk = of_clk_get(node, 0);
if (!IS_ERR(clk)) { 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"); pr_err("GIC failed to enable clock\n");
clk_put(clk); clk_put(clk);
return PTR_ERR(clk); return ret;
} }
gic_frequency = clk_get_rate(clk); gic_frequency = clk_get_rate(clk);
...@@ -200,5 +201,5 @@ static int __init gic_clocksource_of_init(struct device_node *node) ...@@ -200,5 +201,5 @@ static int __init gic_clocksource_of_init(struct device_node *node)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", TIMER_OF_DECLARE(mips_gic_timer, "mti,gic-timer",
gic_clocksource_of_init); gic_clocksource_of_init);
/*
* 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);
...@@ -274,4 +274,4 @@ static int __init mps2_timer_init(struct device_node *np) ...@@ -274,4 +274,4 @@ static int __init mps2_timer_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init); TIMER_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
...@@ -265,4 +265,4 @@ static int __init mtk_timer_init(struct device_node *node) ...@@ -265,4 +265,4 @@ static int __init mtk_timer_init(struct device_node *node)
return -EINVAL; return -EINVAL;
} }
CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);
...@@ -293,4 +293,4 @@ static int __init mxs_timer_init(struct device_node *np) ...@@ -293,4 +293,4 @@ static int __init mxs_timer_init(struct device_node *np)
return setup_irq(irq, &mxs_timer_irq); 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);
...@@ -284,5 +284,5 @@ static int __init nmdk_timer_of_init(struct device_node *node) ...@@ -284,5 +284,5 @@ static int __init nmdk_timer_of_init(struct device_node *node)
return nmdk_timer_init(base, irq, pclk, clk); 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); nmdk_timer_of_init);
...@@ -216,7 +216,7 @@ static int __init pxa_timer_dt_init(struct device_node *np) ...@@ -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)); 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. * Legacy timer init for non device-tree boards.
......
...@@ -254,5 +254,5 @@ static int __init msm_dt_timer_init(struct device_node *np) ...@@ -254,5 +254,5 @@ static int __init msm_dt_timer_init(struct device_node *np)
return msm_timer_init(freq, 32, irq, !!percpu_offset); return msm_timer_init(freq, 32, irq, !!percpu_offset);
} }
CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); TIMER_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(scss_timer, "qcom,scss-timer", msm_dt_timer_init);
...@@ -262,4 +262,4 @@ static int __init ostm_init(struct device_node *np) ...@@ -262,4 +262,4 @@ static int __init ostm_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(ostm, "renesas,ostm", ostm_init); TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init);
...@@ -303,5 +303,5 @@ static int __init rk_timer_init(struct device_node *np) ...@@ -303,5 +303,5 @@ static int __init rk_timer_init(struct device_node *np)
return -EINVAL; return -EINVAL;
} }
CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init); TIMER_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init);
CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init); TIMER_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init);
...@@ -418,7 +418,7 @@ void __init samsung_pwm_clocksource_init(void __iomem *base, ...@@ -418,7 +418,7 @@ void __init samsung_pwm_clocksource_init(void __iomem *base,
_samsung_pwm_clocksource_init(); _samsung_pwm_clocksource_init();
} }
#ifdef CONFIG_CLKSRC_OF #ifdef CONFIG_TIMER_OF
static int __init samsung_pwm_alloc(struct device_node *np, static int __init samsung_pwm_alloc(struct device_node *np,
const struct samsung_pwm_variant *variant) const struct samsung_pwm_variant *variant)
{ {
...@@ -466,7 +466,7 @@ static int __init s3c2410_pwm_clocksource_init(struct device_node *np) ...@@ -466,7 +466,7 @@ static int __init s3c2410_pwm_clocksource_init(struct device_node *np)
{ {
return samsung_pwm_alloc(np, &s3c24xx_variant); 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 = { static const struct samsung_pwm_variant s3c64xx_variant = {
.bits = 32, .bits = 32,
...@@ -479,7 +479,7 @@ static int __init s3c64xx_pwm_clocksource_init(struct device_node *np) ...@@ -479,7 +479,7 @@ static int __init s3c64xx_pwm_clocksource_init(struct device_node *np)
{ {
return samsung_pwm_alloc(np, &s3c64xx_variant); 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 = { static const struct samsung_pwm_variant s5p64x0_variant = {
.bits = 32, .bits = 32,
...@@ -492,7 +492,7 @@ static int __init s5p64x0_pwm_clocksource_init(struct device_node *np) ...@@ -492,7 +492,7 @@ static int __init s5p64x0_pwm_clocksource_init(struct device_node *np)
{ {
return samsung_pwm_alloc(np, &s5p64x0_variant); 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 = { static const struct samsung_pwm_variant s5p_variant = {
.bits = 32, .bits = 32,
...@@ -505,5 +505,5 @@ static int __init s5p_pwm_clocksource_init(struct device_node *np) ...@@ -505,5 +505,5 @@ static int __init s5p_pwm_clocksource_init(struct device_node *np)
{ {
return samsung_pwm_alloc(np, &s5p_variant); 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 #endif
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include "timer-of.h"
#define TIMER_IRQ_EN_REG 0x00 #define TIMER_IRQ_EN_REG 0x00
#define TIMER_IRQ_EN(val) BIT(val) #define TIMER_IRQ_EN(val) BIT(val)
#define TIMER_IRQ_ST_REG 0x04 #define TIMER_IRQ_ST_REG 0x04
...@@ -39,38 +41,37 @@ ...@@ -39,38 +41,37 @@
#define TIMER_SYNC_TICKS 3 #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 * 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 * 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 * that is already setup and runs at the same frequency than the other
* timers, and we never will be disabled. * 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(); 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)); u32 val = readl(base + TIMER_CTL_REG(timer));
writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); writel(val & ~TIMER_CTL_ENABLE, base + TIMER_CTL_REG(timer));
sun4i_clkevt_sync(); 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) if (periodic)
val &= ~TIMER_CTL_ONESHOT; val &= ~TIMER_CTL_ONESHOT;
...@@ -78,115 +79,106 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic) ...@@ -78,115 +79,106 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic)
val |= TIMER_CTL_ONESHOT; val |= TIMER_CTL_ONESHOT;
writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, 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) 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; return 0;
} }
static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt) static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt)
{ {
sun4i_clkevt_time_stop(0); struct timer_of *to = to_timer_of(evt);
sun4i_clkevt_time_start(0, false);
sun4i_clkevt_time_stop(timer_of_base(to), 0);
sun4i_clkevt_time_start(timer_of_base(to), 0, false);
return 0; return 0;
} }
static int sun4i_clkevt_set_periodic(struct clock_event_device *evt) static int sun4i_clkevt_set_periodic(struct clock_event_device *evt)
{ {
sun4i_clkevt_time_stop(0); struct timer_of *to = to_timer_of(evt);
sun4i_clkevt_time_setup(0, ticks_per_jiffy);
sun4i_clkevt_time_start(0, true); 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; return 0;
} }
static int sun4i_clkevt_next_event(unsigned long evt, static int sun4i_clkevt_next_event(unsigned long evt,
struct clock_event_device *unused) struct clock_event_device *clkevt)
{ {
sun4i_clkevt_time_stop(0); struct timer_of *to = to_timer_of(clkevt);
sun4i_clkevt_time_setup(0, evt - TIMER_SYNC_TICKS);
sun4i_clkevt_time_start(0, false); 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; return 0;
} }
static struct clock_event_device sun4i_clockevent = { static void sun4i_timer_clear_interrupt(void __iomem *base)
.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)
{ {
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) static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
{ {
struct clock_event_device *evt = (struct clock_event_device *)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); evt->event_handler(evt);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static struct irqaction sun4i_timer_irq = { static struct timer_of to = {
.name = "sun4i_timer0", .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE,
.flags = IRQF_TIMER | IRQF_IRQPOLL,
.handler = sun4i_timer_interrupt, .clkevt = {
.dev_id = &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,
.cpumask = cpu_possible_mask,
},
.of_irq = {
.handler = sun4i_timer_interrupt,
.flags = IRQF_TIMER | IRQF_IRQPOLL,
},
}; };
static u64 notrace sun4i_timer_sched_read(void) 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) static int __init sun4i_timer_init(struct device_node *node)
{ {
unsigned long rate = 0; int ret;
struct clk *clk;
int ret, irq;
u32 val; u32 val;
timer_base = of_iomap(node, 0); ret = timer_of_init(node, &to);
if (!timer_base) { if (ret)
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");
return 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 | writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD |
TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), 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 * 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) ...@@ -195,43 +187,34 @@ static int __init sun4i_timer_init(struct device_node *node)
if (of_machine_is_compatible("allwinner,sun4i-a10") || if (of_machine_is_compatible("allwinner,sun4i-a10") ||
of_machine_is_compatible("allwinner,sun5i-a13") || of_machine_is_compatible("allwinner,sun5i-a13") ||
of_machine_is_compatible("allwinner,sun5i-a10s")) 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, ret = clocksource_mmio_init(timer_of_base(&to) + TIMER_CNTVAL_REG(1),
rate, 350, 32, clocksource_mmio_readl_down); node->name, timer_of_rate(&to), 350, 32,
clocksource_mmio_readl_down);
if (ret) { if (ret) {
pr_err("Failed to register clocksource\n"); pr_err("Failed to register clocksource\n");
return ret; return ret;
} }
ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), 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 */ /* 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 */ /* clear timer0 interrupt */
sun4i_timer_clear_interrupt(); sun4i_timer_clear_interrupt(timer_of_base(&to));
sun4i_clockevent.cpumask = cpu_possible_mask;
sun4i_clockevent.irq = irq;
clockevents_config_and_register(&sun4i_clockevent, rate, clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
TIMER_SYNC_TICKS, 0xffffffff); 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 */ /* Enable timer0 interrupt */
val = readl(timer_base + TIMER_IRQ_EN_REG); val = readl(timer_of_base(&to) + TIMER_IRQ_EN_REG);
writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); writel(val | TIMER_IRQ_EN(0), timer_of_base(&to) + TIMER_IRQ_EN_REG);
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
sun4i_timer_init); sun4i_timer_init);
...@@ -53,4 +53,4 @@ static int __init tango_clocksource_init(struct device_node *np) ...@@ -53,4 +53,4 @@ static int __init tango_clocksource_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init); TIMER_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init);
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <linux/atmel_tc.h> #include <linux/atmel_tc.h>
...@@ -40,6 +41,14 @@ ...@@ -40,6 +41,14 @@
*/ */
static void __iomem *tcaddr; 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) static u64 tc_get_cycles(struct clocksource *cs)
{ {
...@@ -48,9 +57,9 @@ 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); raw_local_irq_save(flags);
do { do {
upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)); upper = readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV));
lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV)); lower = readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));
} while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV))); } while (upper != readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV)));
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
return (upper << 16) | lower; return (upper << 16) | lower;
...@@ -58,7 +67,47 @@ static u64 tc_get_cycles(struct clocksource *cs) ...@@ -58,7 +67,47 @@ static u64 tc_get_cycles(struct clocksource *cs)
static u64 tc_get_cycles32(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 = { static struct clocksource clksrc = {
...@@ -67,6 +116,8 @@ static struct clocksource clksrc = { ...@@ -67,6 +116,8 @@ static struct clocksource clksrc = {
.read = tc_get_cycles, .read = tc_get_cycles,
.mask = CLOCKSOURCE_MASK(32), .mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
.suspend = tc_clksrc_suspend,
.resume = tc_clksrc_resume,
}; };
#ifdef CONFIG_GENERIC_CLOCKEVENTS #ifdef CONFIG_GENERIC_CLOCKEVENTS
...@@ -96,8 +147,8 @@ static int tc_shutdown(struct clock_event_device *d) ...@@ -96,8 +147,8 @@ static int tc_shutdown(struct clock_event_device *d)
struct tc_clkevt_device *tcd = to_tc_clkevt(d); struct tc_clkevt_device *tcd = to_tc_clkevt(d);
void __iomem *regs = tcd->regs; void __iomem *regs = tcd->regs;
__raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); writel(0xff, regs + ATMEL_TC_REG(2, IDR));
__raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
if (!clockevent_state_detached(d)) if (!clockevent_state_detached(d))
clk_disable(tcd->clk); clk_disable(tcd->clk);
...@@ -115,9 +166,9 @@ static int tc_set_oneshot(struct clock_event_device *d) ...@@ -115,9 +166,9 @@ static int tc_set_oneshot(struct clock_event_device *d)
clk_enable(tcd->clk); clk_enable(tcd->clk);
/* slow clock, count up to RC, then irq and stop */ /* 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)); 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 */ /* set_next_event() configures and starts the timer */
return 0; return 0;
...@@ -137,25 +188,25 @@ static int tc_set_periodic(struct clock_event_device *d) ...@@ -137,25 +188,25 @@ static int tc_set_periodic(struct clock_event_device *d)
clk_enable(tcd->clk); clk_enable(tcd->clk);
/* slow clock, count up to RC, then irq and restart */ /* 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)); 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 */ /* 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! */ /* 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)); ATMEL_TC_REG(2, CCR));
return 0; return 0;
} }
static int tc_next_event(unsigned long delta, struct clock_event_device *d) 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! */ /* 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)); tcaddr + ATMEL_TC_REG(2, CCR));
return 0; return 0;
} }
...@@ -179,7 +230,7 @@ static irqreturn_t ch2_irq(int irq, void *handle) ...@@ -179,7 +230,7 @@ static irqreturn_t ch2_irq(int irq, void *handle)
struct tc_clkevt_device *dev = handle; struct tc_clkevt_device *dev = handle;
unsigned int sr; 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) { if (sr & ATMEL_TC_CPCS) {
dev->clkevt.event_handler(&dev->clkevt); dev->clkevt.event_handler(&dev->clkevt);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -239,43 +290,43 @@ static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) ...@@ -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) 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 */ /* 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_WAVE
| ATMEL_TC_WAVESEL_UP /* free-run */ | ATMEL_TC_WAVESEL_UP /* free-run */
| ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */ | ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */
| ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */ | ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */
tcaddr + ATMEL_TC_REG(0, CMR)); tcaddr + ATMEL_TC_REG(0, CMR));
__raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA)); writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
__raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC)); writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
/* channel 1: waveform mode, input TIOA0 */ /* channel 1: waveform mode, input TIOA0 */
__raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */ writel(ATMEL_TC_XC1 /* input: TIOA0 */
| ATMEL_TC_WAVE | ATMEL_TC_WAVE
| ATMEL_TC_WAVESEL_UP, /* free-run */ | ATMEL_TC_WAVESEL_UP, /* free-run */
tcaddr + ATMEL_TC_REG(1, CMR)); tcaddr + ATMEL_TC_REG(1, CMR));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */ writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR)); writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
/* chain channel 0 to channel 1*/ /* 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 */ /* 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) static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx)
{ {
/* channel 0: waveform mode, input mclk/8 */ /* 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_WAVE
| ATMEL_TC_WAVESEL_UP, /* free-run */ | ATMEL_TC_WAVESEL_UP, /* free-run */
tcaddr + ATMEL_TC_REG(0, CMR)); tcaddr + ATMEL_TC_REG(0, CMR));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
/* then reset all the timers */ /* 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) static int __init tcb_clksrc_init(void)
......
...@@ -237,7 +237,7 @@ static int __init tegra20_init_timer(struct device_node *np) ...@@ -237,7 +237,7 @@ static int __init tegra20_init_timer(struct device_node *np)
return 0; 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) static int __init tegra20_init_rtc(struct device_node *np)
{ {
...@@ -261,4 +261,4 @@ 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); 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);
...@@ -351,7 +351,7 @@ static int __init armada_xp_timer_init(struct device_node *np) ...@@ -351,7 +351,7 @@ static int __init armada_xp_timer_init(struct device_node *np)
return armada_370_xp_timer_common_init(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); armada_xp_timer_init);
static int __init armada_375_timer_init(struct device_node *np) 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) ...@@ -389,7 +389,7 @@ static int __init armada_375_timer_init(struct device_node *np)
return armada_370_xp_timer_common_init(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); armada_375_timer_init);
static int __init armada_370_timer_init(struct device_node *np) 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) ...@@ -412,5 +412,5 @@ static int __init armada_370_timer_init(struct device_node *np)
return armada_370_xp_timer_common_init(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); armada_370_timer_init);
...@@ -283,5 +283,5 @@ static int __init efm32_timer_init(struct device_node *np) ...@@ -283,5 +283,5 @@ static int __init efm32_timer_init(struct device_node *np)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init); TIMER_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init);
CLOCKSOURCE_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init); TIMER_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init);
...@@ -311,4 +311,4 @@ static int __init lpc32xx_timer_init(struct device_node *np) ...@@ -311,4 +311,4 @@ static int __init lpc32xx_timer_init(struct device_node *np)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); TIMER_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init);
...@@ -189,4 +189,4 @@ static int __init orion_timer_init(struct device_node *np) ...@@ -189,4 +189,4 @@ static int __init orion_timer_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init); TIMER_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
...@@ -214,5 +214,5 @@ static int __init pistachio_clksrc_of_init(struct device_node *node) ...@@ -214,5 +214,5 @@ static int __init pistachio_clksrc_of_init(struct device_node *node)
sched_clock_register(pistachio_read_sched_clock, 32, rate); sched_clock_register(pistachio_read_sched_clock, 32, rate);
return clocksource_register_hz(&pcs_gpt.cs, 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); pistachio_clksrc_of_init);
...@@ -283,4 +283,4 @@ static int __init sirfsoc_of_timer_init(struct device_node *np) ...@@ -283,4 +283,4 @@ static int __init sirfsoc_of_timer_init(struct device_node *np)
return sirfsoc_atlas7_timer_init(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);
...@@ -255,5 +255,5 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) ...@@ -255,5 +255,5 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit", TIMER_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit",
at91sam926x_pit_dt_init); at91sam926x_pit_dt_init);
...@@ -260,5 +260,5 @@ static int __init atmel_st_timer_init(struct device_node *node) ...@@ -260,5 +260,5 @@ static int __init atmel_st_timer_init(struct device_node *node)
/* register clocksource */ /* register clocksource */
return clocksource_register_hz(&clk32k, sclk_rate); 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); atmel_st_timer_init);
...@@ -203,5 +203,5 @@ static int __init digicolor_timer_init(struct device_node *node) ...@@ -203,5 +203,5 @@ static int __init digicolor_timer_init(struct device_node *node)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer", TIMER_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer",
digicolor_timer_init); digicolor_timer_init);
...@@ -11,12 +11,13 @@ ...@@ -11,12 +11,13 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/sched_clock.h> #include <linux/sched_clock.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/delay.h>
/* /*
* Register definitions for the timers * Register definitions for the timers
...@@ -37,267 +38,368 @@ ...@@ -37,267 +38,368 @@
#define TIMER_INTR_STATE (0x34) #define TIMER_INTR_STATE (0x34)
#define TIMER_INTR_MASK (0x38) #define TIMER_INTR_MASK (0x38)
#define TIMER_1_CR_ENABLE (1 << 0) #define TIMER_1_CR_ENABLE BIT(0)
#define TIMER_1_CR_CLOCK (1 << 1) #define TIMER_1_CR_CLOCK BIT(1)
#define TIMER_1_CR_INT (1 << 2) #define TIMER_1_CR_INT BIT(2)
#define TIMER_2_CR_ENABLE (1 << 3) #define TIMER_2_CR_ENABLE BIT(3)
#define TIMER_2_CR_CLOCK (1 << 4) #define TIMER_2_CR_CLOCK BIT(4)
#define TIMER_2_CR_INT (1 << 5) #define TIMER_2_CR_INT BIT(5)
#define TIMER_3_CR_ENABLE (1 << 6) #define TIMER_3_CR_ENABLE BIT(6)
#define TIMER_3_CR_CLOCK (1 << 7) #define TIMER_3_CR_CLOCK BIT(7)
#define TIMER_3_CR_INT (1 << 8) #define TIMER_3_CR_INT BIT(8)
#define TIMER_1_CR_UPDOWN (1 << 9) #define TIMER_1_CR_UPDOWN BIT(9)
#define TIMER_2_CR_UPDOWN (1 << 10) #define TIMER_2_CR_UPDOWN BIT(10)
#define TIMER_3_CR_UPDOWN (1 << 11) #define TIMER_3_CR_UPDOWN BIT(11)
#define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \
TIMER_3_CR_ENABLE | \ /*
TIMER_3_CR_UPDOWN) * The Aspeed AST2400 moves bits around in the control register
* and lacks bits for setting the timer to count upwards.
#define TIMER_1_INT_MATCH1 (1 << 0) */
#define TIMER_1_INT_MATCH2 (1 << 1) #define TIMER_1_CR_ASPEED_ENABLE BIT(0)
#define TIMER_1_INT_OVERFLOW (1 << 2) #define TIMER_1_CR_ASPEED_CLOCK BIT(1)
#define TIMER_2_INT_MATCH1 (1 << 3) #define TIMER_1_CR_ASPEED_INT BIT(2)
#define TIMER_2_INT_MATCH2 (1 << 4) #define TIMER_2_CR_ASPEED_ENABLE BIT(4)
#define TIMER_2_INT_OVERFLOW (1 << 5) #define TIMER_2_CR_ASPEED_CLOCK BIT(5)
#define TIMER_3_INT_MATCH1 (1 << 6) #define TIMER_2_CR_ASPEED_INT BIT(6)
#define TIMER_3_INT_MATCH2 (1 << 7) #define TIMER_3_CR_ASPEED_ENABLE BIT(8)
#define TIMER_3_INT_OVERFLOW (1 << 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 #define TIMER_INT_ALL_MASK 0x1ff
static unsigned int tick_rate; struct fttmr010 {
static void __iomem *base; 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, static int fttmr010_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
struct fttmr010 *fttmr010 = to_fttmr010(evt);
u32 cr; u32 cr;
/* Setup the match register */ /* Stop */
cr = readl(base + TIMER1_COUNT); cr = readl(fttmr010->base + TIMER_CR);
writel(cr + cycles, base + TIMER1_MATCH1); cr &= ~fttmr010->t1_enable_val;
if (readl(base + TIMER1_COUNT) - cr > cycles) writel(cr, fttmr010->base + TIMER_CR);
return -ETIME;
/* 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; return 0;
} }
static int fttmr010_timer_shutdown(struct clock_event_device *evt) static int fttmr010_timer_shutdown(struct clock_event_device *evt)
{ {
struct fttmr010 *fttmr010 = to_fttmr010(evt);
u32 cr; u32 cr;
/* /* Stop */
* Disable also for oneshot: the set_next() call will arm the timer cr = readl(fttmr010->base + TIMER_CR);
* instead. cr &= ~fttmr010->t1_enable_val;
*/ writel(cr, fttmr010->base + TIMER_CR);
/* Stop timer and interrupt. */
cr = readl(base + TIMER_CR); return 0;
cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); }
writel(cr, base + TIMER_CR);
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 */ /* Setup counter start from 0 or ~0 */
writel(0, base + TIMER1_COUNT); writel(0, fttmr010->base + TIMER1_COUNT);
writel(0, base + TIMER1_LOAD); if (fttmr010->count_down)
writel(~0, fttmr010->base + TIMER1_LOAD);
else
writel(0, fttmr010->base + TIMER1_LOAD);
/* enable interrupt */ /* Enable interrupt */
cr = readl(base + TIMER_INTR_MASK); cr = readl(fttmr010->base + TIMER_INTR_MASK);
cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
cr |= TIMER_1_INT_MATCH1; cr |= TIMER_1_INT_MATCH1;
writel(cr, base + TIMER_INTR_MASK); writel(cr, fttmr010->base + TIMER_INTR_MASK);
/* start the timer */
cr = readl(base + TIMER_CR);
cr |= TIMER_1_CR_ENABLE;
writel(cr, base + TIMER_CR);
return 0; return 0;
} }
static int fttmr010_timer_set_periodic(struct clock_event_device *evt) 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; u32 cr;
/* Stop timer and interrupt */ /* Stop */
cr = readl(base + TIMER_CR); cr = readl(fttmr010->base + TIMER_CR);
cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); cr &= ~fttmr010->t1_enable_val;
writel(cr, base + TIMER_CR); writel(cr, fttmr010->base + TIMER_CR);
/* Setup timer to fire at 1/HT intervals. */ /* Setup timer to fire at 1/HZ intervals. */
cr = 0xffffffff - (period - 1); if (fttmr010->count_down) {
writel(cr, base + TIMER1_COUNT); writel(period, fttmr010->base + TIMER1_LOAD);
writel(cr, base + TIMER1_LOAD); writel(0, fttmr010->base + TIMER1_MATCH1);
} else {
/* enable interrupt on overflow */ cr = 0xffffffff - (period - 1);
cr = readl(base + TIMER_INTR_MASK); writel(cr, fttmr010->base + TIMER1_COUNT);
cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); writel(cr, fttmr010->base + TIMER1_LOAD);
cr |= TIMER_1_INT_OVERFLOW;
writel(cr, base + TIMER_INTR_MASK); /* 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 */ /* Start the timer */
cr = readl(base + TIMER_CR); cr = readl(fttmr010->base + TIMER_CR);
cr |= TIMER_1_CR_ENABLE; cr |= fttmr010->t1_enable_val;
cr |= TIMER_1_CR_INT; writel(cr, fttmr010->base + TIMER_CR);
writel(cr, base + TIMER_CR);
return 0; 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 * IRQ handler for the timer
*/ */
static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) 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); evt->event_handler(evt);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static struct irqaction fttmr010_timer_irq = { static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
.name = "Faraday FTTMR010 Timer Tick",
.flags = IRQF_TIMER,
.handler = fttmr010_timer_interrupt,
};
static int __init fttmr010_timer_common_init(struct device_node *np)
{ {
struct fttmr010 *fttmr010;
int irq; 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); fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL);
if (!base) { 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"); pr_err("Can't remap registers");
return -ENXIO; ret = -ENXIO;
goto out_free;
} }
/* IRQ for timer 1 */ /* IRQ for timer 1 */
irq = irq_of_parse_and_map(np, 0); irq = irq_of_parse_and_map(np, 0);
if (irq <= 0) { if (irq <= 0) {
pr_err("Can't parse IRQ"); 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 * Reset the interrupt mask and status
*/ */
writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK); writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK);
writel(0, base + TIMER_INTR_STATE); writel(0, fttmr010->base + TIMER_INTR_STATE);
writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR);
/*
* 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 * Setup free-running clocksource timer (interrupts
* disabled.) * disabled.)
*/ */
writel(0, base + TIMER3_COUNT); local_fttmr = fttmr010;
writel(0, base + TIMER3_LOAD); writel(0, fttmr010->base + TIMER2_COUNT);
writel(0, base + TIMER3_MATCH1); writel(0, fttmr010->base + TIMER2_MATCH1);
writel(0, base + TIMER3_MATCH2); writel(0, fttmr010->base + TIMER2_MATCH2);
clocksource_mmio_init(base + TIMER3_COUNT,
"fttmr010_clocksource", tick_rate, if (fttmr010->count_down) {
300, 32, clocksource_mmio_readl_up); writel(~0, fttmr010->base + TIMER2_LOAD);
sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate); 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, fttmr010->base + TIMER1_COUNT);
writel(0, base + TIMER1_LOAD); writel(0, fttmr010->base + TIMER1_LOAD);
writel(0, base + TIMER1_MATCH1); writel(0, fttmr010->base + TIMER1_MATCH1);
writel(0, base + TIMER1_MATCH2); writel(0, fttmr010->base + TIMER1_MATCH2);
setup_irq(irq, &fttmr010_timer_irq); ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER,
fttmr010_clockevent.cpumask = cpumask_of(0); "FTTMR010-TIMER1", &fttmr010->clkevt);
clockevents_config_and_register(&fttmr010_clockevent, tick_rate, 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); 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) return 0;
{
/*
* 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;
clk = of_clk_get_by_name(np, "PCLK"); out_unmap:
if (IS_ERR(clk)) { iounmap(fttmr010->base);
pr_err("could not get PCLK"); out_free:
return PTR_ERR(clk); kfree(fttmr010);
} out_disable_clock:
tick_rate = clk_get_rate(clk); clk_disable_unprepare(clk);
return fttmr010_timer_common_init(np); return ret;
} }
CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_of_init);
/* static __init int aspeed_timer_init(struct device_node *np)
* 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 struct regmap *map; return fttmr010_common_init(np, true);
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_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);
...@@ -545,15 +545,15 @@ static int __init imx6dl_timer_init_dt(struct device_node *np) ...@@ -545,15 +545,15 @@ static int __init imx6dl_timer_init_dt(struct device_node *np)
return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL);
} }
CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); TIMER_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); TIMER_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); TIMER_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); TIMER_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); TIMER_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); TIMER_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); TIMER_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); TIMER_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); TIMER_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); TIMER_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); TIMER_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(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
...@@ -232,5 +232,5 @@ static int __init integrator_ap_timer_init_of(struct device_node *node) ...@@ -232,5 +232,5 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
return 0; 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); integrator_ap_timer_init_of);
...@@ -226,5 +226,5 @@ static int __init keystone_timer_init(struct device_node *np) ...@@ -226,5 +226,5 @@ static int __init keystone_timer_init(struct device_node *np)
return error; return error;
} }
CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer", TIMER_OF_DECLARE(keystone_timer, "ti,keystone-timer",
keystone_timer_init); keystone_timer_init);
...@@ -110,9 +110,9 @@ static int __init nps_setup_clocksource(struct device_node *node) ...@@ -110,9 +110,9 @@ static int __init nps_setup_clocksource(struct device_node *node)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", TIMER_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer",
nps_setup_clocksource); 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); nps_setup_clocksource);
#ifdef CONFIG_EZNPS_MTM_EXT #ifdef CONFIG_EZNPS_MTM_EXT
...@@ -279,6 +279,6 @@ static int __init nps_setup_clockevent(struct device_node *node) ...@@ -279,6 +279,6 @@ static int __init nps_setup_clockevent(struct device_node *node)
return 0; 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); nps_setup_clockevent);
#endif /* CONFIG_EZNPS_MTM_EXT */ #endif /* CONFIG_EZNPS_MTM_EXT */
/*
* 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;
}
#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
...@@ -293,7 +293,7 @@ static int __init oxnas_rps_timer_init(struct device_node *np) ...@@ -293,7 +293,7 @@ static int __init oxnas_rps_timer_init(struct device_node *np)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(ox810se_rps, TIMER_OF_DECLARE(ox810se_rps,
"oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); "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); "oxsemi,ox820se-rps-timer", oxnas_rps_timer_init);
...@@ -245,5 +245,5 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np) ...@@ -245,5 +245,5 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(sirfsoc_prima2_timer, TIMER_OF_DECLARE(sirfsoc_prima2_timer,
"sirf,prima2-tick", sirfsoc_prima2_timer_init); "sirf,prima2-tick", sirfsoc_prima2_timer_init);
...@@ -19,20 +19,20 @@ ...@@ -19,20 +19,20 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/clocksource.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 static const struct of_device_id __timer_of_table_sentinel
__used __section(__clksrc_of_table_end); __used __section(__timer_of_table_end);
void __init clocksource_probe(void) void __init timer_probe(void)
{ {
struct device_node *np; struct device_node *np;
const struct of_device_id *match; const struct of_device_id *match;
of_init_fn_1_ret init_func_ret; of_init_fn_1_ret init_func_ret;
unsigned clocksources = 0; unsigned timers = 0;
int ret; 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)) if (!of_device_is_available(np))
continue; continue;
...@@ -45,11 +45,11 @@ void __init clocksource_probe(void) ...@@ -45,11 +45,11 @@ void __init clocksource_probe(void)
continue; continue;
} }
clocksources++; timers++;
} }
clocksources += acpi_probe_device_table(clksrc); timers += acpi_probe_device_table(timer);
if (!clocksources) if (!timers)
pr_crit("%s: no matching clocksources found\n", __func__); pr_crit("%s: no matching timers found\n", __func__);
} }
...@@ -287,7 +287,7 @@ static int __init sp804_of_init(struct device_node *np) ...@@ -287,7 +287,7 @@ static int __init sp804_of_init(struct device_node *np)
iounmap(base); iounmap(base);
return ret; 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) static int __init integrator_cp_of_init(struct device_node *np)
{ {
...@@ -335,4 +335,4 @@ static int __init integrator_cp_of_init(struct device_node *np) ...@@ -335,4 +335,4 @@ static int __init integrator_cp_of_init(struct device_node *np)
iounmap(base); iounmap(base);
return ret; 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);
...@@ -187,4 +187,4 @@ static int __init stm32_clockevent_init(struct device_node *np) ...@@ -187,4 +187,4 @@ static int __init stm32_clockevent_init(struct device_node *np)
return ret; return ret;
} }
CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init); TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
...@@ -359,7 +359,7 @@ static int __init sun5i_timer_init(struct device_node *node) ...@@ -359,7 +359,7 @@ static int __init sun5i_timer_init(struct device_node *node)
return sun5i_setup_clockevent(node, timer_base, clk, irq); 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); sun5i_timer_init);
CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", TIMER_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer",
sun5i_timer_init); sun5i_timer_init);
...@@ -124,5 +124,5 @@ static int __init ti_32k_timer_init(struct device_node *np) ...@@ -124,5 +124,5 @@ static int __init ti_32k_timer_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k", TIMER_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k",
ti_32k_timer_init); ti_32k_timer_init);
...@@ -458,5 +458,5 @@ static int __init u300_timer_init_of(struct device_node *np) ...@@ -458,5 +458,5 @@ static int __init u300_timer_init_of(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(u300_timer, "stericsson,u300-apptimer", TIMER_OF_DECLARE(u300_timer, "stericsson,u300-apptimer",
u300_timer_init_of); u300_timer_init_of);
...@@ -38,7 +38,7 @@ static int __init versatile_sched_clock_init(struct device_node *node) ...@@ -38,7 +38,7 @@ static int __init versatile_sched_clock_init(struct device_node *node)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg", TIMER_OF_DECLARE(vexpress, "arm,vexpress-sysreg",
versatile_sched_clock_init); versatile_sched_clock_init);
CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg", TIMER_OF_DECLARE(versatile, "arm,versatile-sysreg",
versatile_sched_clock_init); versatile_sched_clock_init);
...@@ -201,4 +201,4 @@ static int __init pit_timer_init(struct device_node *np) ...@@ -201,4 +201,4 @@ static int __init pit_timer_init(struct device_node *np)
return pit_clockevent_init(clk_rate, irq); 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);
...@@ -165,4 +165,4 @@ static int __init vt8500_timer_init(struct device_node *np) ...@@ -165,4 +165,4 @@ static int __init vt8500_timer_init(struct device_node *np)
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); TIMER_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);
...@@ -215,4 +215,4 @@ static int __init zevio_timer_init(struct device_node *node) ...@@ -215,4 +215,4 @@ static int __init zevio_timer_init(struct device_node *node)
return zevio_timer_add(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);
#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
...@@ -172,8 +172,7 @@ ...@@ -172,8 +172,7 @@
KEEP(*(__##name##_of_table)) \ KEEP(*(__##name##_of_table)) \
KEEP(*(__##name##_of_table_end)) KEEP(*(__##name##_of_table_end))
#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) #define TIMER_OF_TABLES() OF_TABLE(CONFIG_TIMER_OF, timer)
#define CLKEVT_OF_TABLES() OF_TABLE(CONFIG_CLKEVT_OF, clkevt)
#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
#define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) #define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk)
#define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) #define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu)
...@@ -557,15 +556,15 @@ ...@@ -557,15 +556,15 @@
MEM_DISCARD(init.rodata) \ MEM_DISCARD(init.rodata) \
CLK_OF_TABLES() \ CLK_OF_TABLES() \
RESERVEDMEM_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \
CLKSRC_OF_TABLES() \ TIMER_OF_TABLES() \
CLKEVT_OF_TABLES() \
IOMMU_OF_TABLES() \ IOMMU_OF_TABLES() \
CPU_METHOD_OF_TABLES() \ CPU_METHOD_OF_TABLES() \
CPUIDLE_METHOD_OF_TABLES() \ CPUIDLE_METHOD_OF_TABLES() \
KERNEL_DTB() \ KERNEL_DTB() \
IRQCHIP_OF_MATCH_TABLE() \ IRQCHIP_OF_MATCH_TABLE() \
ACPI_PROBE_TABLE(irqchip) \ ACPI_PROBE_TABLE(irqchip) \
ACPI_PROBE_TABLE(clksrc) \ ACPI_PROBE_TABLE(timer) \
ACPI_PROBE_TABLE(iort) \
EARLYCON_TABLE() EARLYCON_TABLE()
#define INIT_TEXT \ #define INIT_TEXT \
......
...@@ -223,13 +223,4 @@ static inline void tick_setup_hrtimer_broadcast(void) { } ...@@ -223,13 +223,4 @@ static inline void tick_setup_hrtimer_broadcast(void) { }
#endif /* !CONFIG_GENERIC_CLOCKEVENTS */ #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 */ #endif /* _LINUX_CLOCKCHIPS_H */
...@@ -250,16 +250,19 @@ extern int clocksource_mmio_init(void __iomem *, const char *, ...@@ -250,16 +250,19 @@ extern int clocksource_mmio_init(void __iomem *, const char *,
extern int clocksource_i8253_init(void); 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) \ #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 #ifdef CONFIG_TIMER_PROBE
extern void clocksource_probe(void); extern void timer_probe(void);
#else #else
static inline void clocksource_probe(void) {} static inline void timer_probe(void) {}
#endif #endif
#define CLOCKSOURCE_ACPI_DECLARE(name, table_id, fn) \ #define TIMER_ACPI_DECLARE(name, table_id, fn) \
ACPI_DECLARE_PROBE_ENTRY(clksrc, name, table_id, 0, NULL, 0, fn) ACPI_DECLARE_PROBE_ENTRY(timer, name, table_id, 0, NULL, 0, fn)
#endif /* _LINUX_CLOCKSOURCE_H */ #endif /* _LINUX_CLOCKSOURCE_H */
...@@ -94,6 +94,10 @@ struct compat_itimerval { ...@@ -94,6 +94,10 @@ struct compat_itimerval {
struct compat_timeval it_value; 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 { struct compat_tms {
compat_clock_t tms_utime; compat_clock_t tms_utime;
compat_clock_t tms_stime; compat_clock_t tms_stime;
...@@ -128,6 +132,10 @@ struct compat_timex { ...@@ -128,6 +132,10 @@ struct compat_timex {
compat_int_t:32; compat_int_t:32; compat_int_t:32; 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) #define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
typedef struct { typedef struct {
......
...@@ -452,11 +452,11 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer, ...@@ -452,11 +452,11 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer,
} }
/* Precise sleep: */ /* 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 enum hrtimer_mode mode,
const clockid_t clockid); const clockid_t clockid);
extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
struct task_struct *tsk); struct task_struct *tsk);
......
...@@ -42,12 +42,6 @@ struct posix_clock; ...@@ -42,12 +42,6 @@ struct posix_clock;
* @clock_gettime: Read the current time * @clock_gettime: Read the current time
* @clock_getres: Get the clock resolution * @clock_getres: Get the clock resolution
* @clock_settime: Set the current time value * @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 * @open: Optional character device open method
* @release: Optional character device release method * @release: Optional character device release method
* @ioctl: Optional character device ioctl method * @ioctl: Optional character device ioctl method
...@@ -66,28 +60,12 @@ struct posix_clock_operations { ...@@ -66,28 +60,12 @@ struct posix_clock_operations {
int (*clock_settime)(struct posix_clock *pc, int (*clock_settime)(struct posix_clock *pc,
const struct timespec64 *ts); 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: * Optional character device methods:
*/ */
int (*fasync) (struct posix_clock *pc,
int fd, struct file *file, int on);
long (*ioctl) (struct posix_clock *pc, long (*ioctl) (struct posix_clock *pc,
unsigned int cmd, unsigned long arg); 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); int (*open) (struct posix_clock *pc, fmode_t f_mode);
uint (*poll) (struct posix_clock *pc, uint (*poll) (struct posix_clock *pc,
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/alarmtimer.h> #include <linux/alarmtimer.h>
struct siginfo;
struct cpu_timer_list { struct cpu_timer_list {
struct list_head entry; struct list_head entry;
...@@ -48,81 +49,69 @@ struct cpu_timer_list { ...@@ -48,81 +49,69 @@ struct cpu_timer_list {
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) #define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
#define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3)) #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 #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 { union {
struct pid *it_pid; /* pid of process to send signal to */ struct pid *it_pid;
struct task_struct *it_process; /* for clock_nanosleep */ struct task_struct *it_process;
}; };
struct sigqueue *sigq; /* signal queue entry. */ struct sigqueue *sigq;
union { union {
struct { struct {
struct hrtimer timer; struct hrtimer timer;
ktime_t interval;
} real; } real;
struct cpu_timer_list cpu; struct cpu_timer_list cpu;
struct { struct {
unsigned int clock; struct alarm alarmtimer;
unsigned int node;
unsigned long incr;
unsigned long expires;
} mmtimer;
struct {
struct alarm alarmtimer;
ktime_t interval;
} alarm; } alarm;
struct rcu_head rcu; struct rcu_head rcu;
} it; } 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 run_posix_cpu_timers(struct task_struct *task);
void posix_cpu_timers_exit(struct task_struct *task); void posix_cpu_timers_exit(struct task_struct *task);
void posix_cpu_timers_exit_group(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, void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
u64 *newval, u64 *oldval); 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 update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
void posixtimer_rearm(struct siginfo *info);
#endif #endif
...@@ -11,6 +11,14 @@ struct timespec; ...@@ -11,6 +11,14 @@ struct timespec;
struct compat_timespec; struct compat_timespec;
struct pollfd; struct pollfd;
enum timespec_type {
TT_NONE = 0,
TT_NATIVE = 1,
#ifdef CONFIG_COMPAT
TT_COMPAT = 2,
#endif
};
/* /*
* System call restart block. * System call restart block.
*/ */
...@@ -29,10 +37,13 @@ struct restart_block { ...@@ -29,10 +37,13 @@ struct restart_block {
/* For nanosleep */ /* For nanosleep */
struct { struct {
clockid_t clockid; clockid_t clockid;
struct timespec __user *rmtp; enum timespec_type type;
union {
struct timespec __user *rmtp;
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
struct compat_timespec __user *compat_rmtp; struct compat_timespec __user *compat_rmtp;
#endif #endif
};
u64 expires; u64 expires;
} nanosleep; } nanosleep;
/* For poll */ /* For poll */
......
...@@ -3,16 +3,13 @@ ...@@ -3,16 +3,13 @@
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/signal_types.h> #include <linux/signal_types.h>
#include <linux/string.h>
struct task_struct; struct task_struct;
/* for sysctl */ /* for sysctl */
extern int print_fatal_signals; 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) static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
{ {
if (from->si_code < 0) if (from->si_code < 0)
...@@ -22,7 +19,7 @@ static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) ...@@ -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)); 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. * Define some primitives to manipulate sigset_t.
......
...@@ -51,7 +51,7 @@ struct tk_read_base { ...@@ -51,7 +51,7 @@ struct tk_read_base {
* @clock_was_set_seq: The sequence number of clock was set events * @clock_was_set_seq: The sequence number of clock was set events
* @cs_was_changed_seq: The sequence number of clocksource change events * @cs_was_changed_seq: The sequence number of clocksource change events
* @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second * @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 * @cycle_interval: Number of clock cycles in one NTP interval
* @xtime_interval: Number of clock shifted nano seconds in one NTP * @xtime_interval: Number of clock shifted nano seconds in one NTP
* interval. * interval.
...@@ -93,7 +93,7 @@ struct timekeeper { ...@@ -93,7 +93,7 @@ struct timekeeper {
unsigned int clock_was_set_seq; unsigned int clock_was_set_seq;
u8 cs_was_changed_seq; u8 cs_was_changed_seq;
ktime_t next_leap_ktime; ktime_t next_leap_ktime;
struct timespec64 raw_time; u64 raw_sec;
/* The following members are for timekeeping internal use */ /* The following members are for timekeeping internal use */
u64 cycle_interval; u64 cycle_interval;
......
...@@ -151,7 +151,18 @@ typedef struct siginfo { ...@@ -151,7 +151,18 @@ typedef struct siginfo {
#define si_arch _sifields._sigsys._arch #define si_arch _sifields._sigsys._arch
#endif #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_KILL 0
#define __SI_TIMER 0 #define __SI_TIMER 0
#define __SI_POLL 0 #define __SI_POLL 0
...@@ -161,7 +172,7 @@ typedef struct siginfo { ...@@ -161,7 +172,7 @@ typedef struct siginfo {
#define __SI_MESGQ 0 #define __SI_MESGQ 0
#define __SI_SYS 0 #define __SI_SYS 0
#define __SI_CODE(T,N) (N) #define __SI_CODE(T,N) (N)
#endif #endif /* __KERNEL__ */
/* /*
* si_code values * si_code values
......
...@@ -54,7 +54,11 @@ struct itimerval { ...@@ -54,7 +54,11 @@ struct itimerval {
#define CLOCK_BOOTTIME 7 #define CLOCK_BOOTTIME 7
#define CLOCK_REALTIME_ALARM 8 #define CLOCK_REALTIME_ALARM 8
#define CLOCK_BOOTTIME_ALARM 9 #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 CLOCK_TAI 11
#define MAX_CLOCKS 16 #define MAX_CLOCKS 16
......
...@@ -30,100 +30,66 @@ ...@@ -30,100 +30,66 @@
#include <linux/uaccess.h> #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)); struct compat_timex tx32;
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;
return 0; if (copy_from_user(&tx32, utp, sizeof(struct compat_timex)))
}
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))
return -EFAULT; return -EFAULT;
return 0;
}
COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv, txc->modes = tx32.modes;
struct timezone __user *, tz) txc->offset = tx32.offset;
{ txc->freq = tx32.freq;
if (tv) { txc->maxerror = tx32.maxerror;
struct timeval ktv; txc->esterror = tx32.esterror;
do_gettimeofday(&ktv); txc->status = tx32.status;
if (compat_put_timeval(&ktv, tv)) txc->constant = tx32.constant;
return -EFAULT; txc->precision = tx32.precision;
} txc->tolerance = tx32.tolerance;
if (tz) { txc->time.tv_sec = tx32.time.tv_sec;
if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) txc->time.tv_usec = tx32.time.tv_usec;
return -EFAULT; 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; return 0;
} }
COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv, int compat_put_timex(struct compat_timex __user *utp, const struct timex *txc)
struct timezone __user *, tz) {
{ struct compat_timex tx32;
struct timespec64 new_ts;
struct timeval user_tv; memset(&tx32, 0, sizeof(struct compat_timex));
struct timezone new_tz; tx32.modes = txc->modes;
tx32.offset = txc->offset;
if (tv) { tx32.freq = txc->freq;
if (compat_get_timeval(&user_tv, tv)) tx32.maxerror = txc->maxerror;
return -EFAULT; tx32.esterror = txc->esterror;
new_ts.tv_sec = user_tv.tv_sec; tx32.status = txc->status;
new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC; tx32.constant = txc->constant;
} tx32.precision = txc->precision;
if (tz) { tx32.tolerance = txc->tolerance;
if (copy_from_user(&new_tz, tz, sizeof(*tz))) tx32.time.tv_sec = txc->time.tv_sec;
return -EFAULT; tx32.time.tv_usec = txc->time.tv_usec;
} tx32.tick = txc->tick;
tx32.ppsfreq = txc->ppsfreq;
return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL); 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) 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, ...@@ -213,141 +179,28 @@ int compat_convert_timespec(struct timespec __user **kts,
return 0; return 0;
} }
static long compat_nanosleep_restart(struct restart_block *restart) int get_compat_itimerval(struct itimerval *o, const struct compat_itimerval __user *i)
{
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)
{ {
struct timespec tu, rmt; struct compat_itimerval v32;
struct timespec64 tu64;
mm_segment_t oldfs;
long ret;
if (compat_get_timespec(&tu, rqtp)) if (copy_from_user(&v32, i, sizeof(struct compat_itimerval)))
return -EFAULT; return -EFAULT;
o->it_interval.tv_sec = v32.it_interval.tv_sec;
tu64 = timespec_to_timespec64(tu); o->it_interval.tv_usec = v32.it_interval.tv_usec;
if (!timespec64_valid(&tu64)) o->it_value.tv_sec = v32.it_value.tv_sec;
return -EINVAL; o->it_value.tv_usec = v32.it_value.tv_usec;
return 0;
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 = &current->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;
} }
COMPAT_SYSCALL_DEFINE3(setitimer, int, which, int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerval *i)
struct compat_itimerval __user *, in,
struct compat_itimerval __user *, out)
{ {
struct itimerval kin, kout; struct compat_itimerval v32;
int error;
if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
return sys_ni_posix_timers();
if (in) { v32.it_interval.tv_sec = i->it_interval.tv_sec;
if (get_compat_itimerval(&kin, in)) v32.it_interval.tv_usec = i->it_interval.tv_usec;
return -EFAULT; v32.it_value.tv_sec = i->it_value.tv_sec;
} else v32.it_value.tv_usec = i->it_value.tv_usec;
memset(&kin, 0, sizeof(kin)); return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0;
error = do_setitimer(which, &kin, out ? &kout : NULL);
if (error || !out)
return error;
if (put_compat_itimerval(out, &kout))
return -EFAULT;
return 0;
} }
static compat_clock_t clock_t_to_compat_clock_t(clock_t x) 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, ...@@ -689,193 +542,6 @@ int put_compat_itimerspec(struct compat_itimerspec __user *dst,
return 0; 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 = &current->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 * We currently only need the following fields from the sigevent
* structure: sigev_value, sigev_signo, sig_notify and (sometimes * structure: sigev_value, sigev_signo, sig_notify and (sometimes
...@@ -1035,64 +701,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, ...@@ -1035,64 +701,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
return ret; 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 #ifdef CONFIG_NUMA
COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages, COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
compat_uptr_t __user *, pages32, compat_uptr_t __user *, pages32,
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/cn_proc.h> #include <linux/cn_proc.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/posix-timers.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/signal.h> #include <trace/events/signal.h>
...@@ -637,7 +638,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) ...@@ -637,7 +638,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
* about to disable them again anyway. * about to disable them again anyway.
*/ */
spin_unlock(&tsk->sighand->siglock); spin_unlock(&tsk->sighand->siglock);
do_schedule_next_timer(info); posixtimer_rearm(info);
spin_lock(&tsk->sighand->siglock); spin_lock(&tsk->sighand->siglock);
} }
#endif #endif
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#include <linux/posix-timers.h> #include <linux/posix-timers.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/compat.h>
#include "posix-timers.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/alarmtimer.h> #include <trace/events/alarmtimer.h>
...@@ -45,11 +48,13 @@ static struct alarm_base { ...@@ -45,11 +48,13 @@ static struct alarm_base {
clockid_t base_clockid; clockid_t base_clockid;
} alarm_bases[ALARM_NUMTYPE]; } alarm_bases[ALARM_NUMTYPE];
#if defined(CONFIG_POSIX_TIMERS) || defined(CONFIG_RTC_CLASS)
/* freezer information to handle clock_nanosleep triggered wakeups */ /* freezer information to handle clock_nanosleep triggered wakeups */
static enum alarmtimer_type freezer_alarmtype; static enum alarmtimer_type freezer_alarmtype;
static ktime_t freezer_expires; static ktime_t freezer_expires;
static ktime_t freezer_delta; static ktime_t freezer_delta;
static DEFINE_SPINLOCK(freezer_delta_lock); static DEFINE_SPINLOCK(freezer_delta_lock);
#endif
static struct wakeup_source *ws; static struct wakeup_source *ws;
...@@ -307,38 +312,6 @@ static int alarmtimer_resume(struct device *dev) ...@@ -307,38 +312,6 @@ static int alarmtimer_resume(struct device *dev)
} }
#endif #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_init - Initialize an alarm structure
* @alarm: ptr to alarm to be initialized * @alarm: ptr to alarm to be initialized
...@@ -488,6 +461,38 @@ u64 alarm_forward_now(struct alarm *alarm, ktime_t interval) ...@@ -488,6 +461,38 @@ u64 alarm_forward_now(struct alarm *alarm, ktime_t interval)
} }
EXPORT_SYMBOL_GPL(alarm_forward_now); 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 * clock2alarm - helper that converts from clockid to alarmtypes
...@@ -511,22 +516,26 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid) ...@@ -511,22 +516,26 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid)
static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
ktime_t now) ktime_t now)
{ {
unsigned long flags;
struct k_itimer *ptr = container_of(alarm, struct k_itimer, struct k_itimer *ptr = container_of(alarm, struct k_itimer,
it.alarm.alarmtimer); it.alarm.alarmtimer);
enum alarmtimer_restart result = ALARMTIMER_NORESTART; enum alarmtimer_restart result = ALARMTIMER_NORESTART;
unsigned long flags;
int si_private = 0;
spin_lock_irqsave(&ptr->it_lock, flags); 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 */ ptr->it_active = 0;
if (ptr->it.alarm.interval) { if (ptr->it_interval)
ptr->it_overrun += alarm_forward(alarm, now, si_private = ++ptr->it_requeue_pending;
ptr->it.alarm.interval);
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; result = ALARMTIMER_RESTART;
} }
spin_unlock_irqrestore(&ptr->it_lock, flags); spin_unlock_irqrestore(&ptr->it_lock, flags);
...@@ -534,6 +543,72 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, ...@@ -534,6 +543,72 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
return result; return result;
} }
/**
* 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 * alarm_clock_getres - posix getres interface
* @which_clock: clockid * @which_clock: clockid
...@@ -590,97 +665,6 @@ static int alarm_timer_create(struct k_itimer *new_timer) ...@@ -590,97 +665,6 @@ static int alarm_timer_create(struct k_itimer *new_timer)
return 0; return 0;
} }
/**
* 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 * alarmtimer_nsleep_wakeup - Wakeup function for alarm_timer_nsleep
* @alarm: ptr to alarm that fired * @alarm: ptr to alarm that fired
...@@ -705,8 +689,10 @@ static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm, ...@@ -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. * 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; alarm->data = (void *)current;
do { do {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
...@@ -719,36 +705,25 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) ...@@ -719,36 +705,25 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp)
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
return (alarm->data == NULL); if (!alarm->data)
}
/**
* 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)
return 0; return 0;
rmt = ktime_to_timespec(rem);
if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) if (freezing(current))
return -EFAULT; alarmtimer_freezerset(absexp, type);
restart = &current->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, ...@@ -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) static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
{ {
enum alarmtimer_type type = restart->nanosleep.clockid; enum alarmtimer_type type = restart->nanosleep.clockid;
ktime_t exp; ktime_t exp = restart->nanosleep.expires;
struct timespec __user *rmtp;
struct alarm alarm; struct alarm alarm;
int ret = 0;
exp = restart->nanosleep.expires;
alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
if (alarmtimer_do_nsleep(&alarm, exp)) return alarmtimer_do_nsleep(&alarm, exp, type);
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;
} }
/** /**
...@@ -798,11 +753,10 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) ...@@ -798,11 +753,10 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
* Handles clock_nanosleep calls against _ALARM clockids * Handles clock_nanosleep calls against _ALARM clockids
*/ */
static int alarm_timer_nsleep(const clockid_t which_clock, int flags, static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
struct timespec64 *tsreq, const struct timespec64 *tsreq)
struct timespec __user *rmtp)
{ {
enum alarmtimer_type type = clock2alarm(which_clock); enum alarmtimer_type type = clock2alarm(which_clock);
struct restart_block *restart; struct restart_block *restart = &current->restart_block;
struct alarm alarm; struct alarm alarm;
ktime_t exp; ktime_t exp;
int ret = 0; int ret = 0;
...@@ -825,35 +779,36 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, ...@@ -825,35 +779,36 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
exp = ktime_add(now, exp); exp = ktime_add(now, exp);
} }
if (alarmtimer_do_nsleep(&alarm, exp)) ret = alarmtimer_do_nsleep(&alarm, exp, type);
goto out; if (ret != -ERESTART_RESTARTBLOCK)
return ret;
if (freezing(current))
alarmtimer_freezerset(exp, type);
/* abs timers don't set remaining time or restart */ /* abs timers don't set remaining time or restart */
if (flags == TIMER_ABSTIME) { if (flags == TIMER_ABSTIME)
ret = -ERESTARTNOHAND; return -ERESTARTNOHAND;
goto out;
}
if (rmtp) {
ret = update_rmtp(exp, type, rmtp);
if (ret <= 0)
goto out;
}
restart = &current->restart_block;
restart->fn = alarm_timer_nsleep_restart; restart->fn = alarm_timer_nsleep_restart;
restart->nanosleep.clockid = type; restart->nanosleep.clockid = type;
restart->nanosleep.expires = exp; restart->nanosleep.expires = exp;
restart->nanosleep.rmtp = rmtp;
ret = -ERESTART_RESTARTBLOCK;
out:
return ret; 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 */ /* Suspend hook structures */
static const struct dev_pm_ops alarmtimer_pm_ops = { static const struct dev_pm_ops alarmtimer_pm_ops = {
...@@ -879,23 +834,9 @@ static int __init alarmtimer_init(void) ...@@ -879,23 +834,9 @@ static int __init alarmtimer_init(void)
struct platform_device *pdev; struct platform_device *pdev;
int error = 0; int error = 0;
int i; 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(); 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 */ /* Initialize alarm bases */
alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME; alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME;
alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real; alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real;
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <linux/sched/debug.h> #include <linux/sched/debug.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/compat.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -1439,8 +1440,29 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) ...@@ -1439,8 +1440,29 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
} }
EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); 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) static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
{ {
struct restart_block *restart;
hrtimer_init_sleeper(t, current); hrtimer_init_sleeper(t, current);
do { do {
...@@ -1457,53 +1479,38 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod ...@@ -1457,53 +1479,38 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
return t->task == NULL; if (!t->task)
}
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)
return 0; return 0;
rmt = ktime_to_timespec(rem);
if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) restart = &current->restart_block;
return -EFAULT; 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 hrtimer_sleeper t;
struct timespec __user *rmtp; int ret;
int ret = 0;
hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid, hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid,
HRTIMER_MODE_ABS); HRTIMER_MODE_ABS);
hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires); hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires);
if (do_nanosleep(&t, HRTIMER_MODE_ABS)) ret = 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:
destroy_hrtimer_on_stack(&t.timer); destroy_hrtimer_on_stack(&t.timer);
return ret; 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) const enum hrtimer_mode mode, const clockid_t clockid)
{ {
struct restart_block *restart; struct restart_block *restart;
...@@ -1517,7 +1524,8 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, ...@@ -1517,7 +1524,8 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp,
hrtimer_init_on_stack(&t.timer, clockid, mode); hrtimer_init_on_stack(&t.timer, clockid, mode);
hrtimer_set_expires_range_ns(&t.timer, timespec64_to_ktime(*rqtp), slack); 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; goto out;
/* Absolute timers do not update the rmtp value and restart: */ /* Absolute timers do not update the rmtp value and restart: */
...@@ -1526,19 +1534,10 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, ...@@ -1526,19 +1534,10 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp,
goto out; goto out;
} }
if (rmtp) {
ret = update_rmtp(&t.timer, rmtp);
if (ret <= 0)
goto out;
}
restart = &current->restart_block; restart = &current->restart_block;
restart->fn = hrtimer_nanosleep_restart; restart->fn = hrtimer_nanosleep_restart;
restart->nanosleep.clockid = t.timer.base->clockid; restart->nanosleep.clockid = t.timer.base->clockid;
restart->nanosleep.rmtp = rmtp;
restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer); restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer);
ret = -ERESTART_RESTARTBLOCK;
out: out:
destroy_hrtimer_on_stack(&t.timer); destroy_hrtimer_on_stack(&t.timer);
return ret; return ret;
...@@ -1557,8 +1556,31 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, ...@@ -1557,8 +1556,31 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
if (!timespec64_valid(&tu64)) if (!timespec64_valid(&tu64))
return -EINVAL; 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: * Functions related to boot-time initialization:
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/posix-timers.h> #include <linux/posix-timers.h>
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <trace/events/timer.h> #include <trace/events/timer.h>
#include <linux/compat.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -116,6 +117,19 @@ SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value) ...@@ -116,6 +117,19 @@ SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value)
return error; 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 * 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, ...@@ -138,8 +152,12 @@ static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
u64 oval, nval, ointerval, ninterval; u64 oval, nval, ointerval, ninterval;
struct cpu_itimer *it = &tsk->signal->it[clock_id]; 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); spin_lock_irq(&tsk->sighand->siglock);
...@@ -294,3 +312,27 @@ SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value, ...@@ -294,3 +312,27 @@ SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,
return -EFAULT; return -EFAULT;
return 0; 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
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include "posix-timers.h"
static void delete_clock(struct kref *kref); static void delete_clock(struct kref *kref);
/* /*
...@@ -82,38 +84,6 @@ static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) ...@@ -82,38 +84,6 @@ static unsigned int posix_clock_poll(struct file *fp, poll_table *wait)
return result; 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, static long posix_clock_ioctl(struct file *fp,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
...@@ -199,8 +169,6 @@ static const struct file_operations posix_clock_file_operations = { ...@@ -199,8 +169,6 @@ static const struct file_operations posix_clock_file_operations = {
.unlocked_ioctl = posix_clock_ioctl, .unlocked_ioctl = posix_clock_ioctl,
.open = posix_clock_open, .open = posix_clock_open,
.release = posix_clock_release, .release = posix_clock_release,
.fasync = posix_clock_fasync,
.mmap = posix_clock_mmap,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = posix_clock_compat_ioctl, .compat_ioctl = posix_clock_compat_ioctl,
#endif #endif
...@@ -359,88 +327,9 @@ static int pc_clock_settime(clockid_t id, const struct timespec64 *ts) ...@@ -359,88 +327,9 @@ static int pc_clock_settime(clockid_t id, const struct timespec64 *ts)
return err; return err;
} }
static int pc_timer_create(struct k_itimer *kit) const struct k_clock clock_posix_dynamic = {
{
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 = {
.clock_getres = pc_clock_getres, .clock_getres = pc_clock_getres,
.clock_set = pc_clock_settime, .clock_set = pc_clock_settime,
.clock_get = pc_clock_gettime, .clock_get = pc_clock_gettime,
.clock_adj = pc_clock_adjtime, .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,
}; };
...@@ -12,6 +12,11 @@ ...@@ -12,6 +12,11 @@
#include <trace/events/timer.h> #include <trace/events/timer.h>
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/workqueue.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 * 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) ...@@ -322,6 +327,8 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer)
if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX) if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX)
return -EINVAL; return -EINVAL;
new_timer->kclock = &clock_posix_cpu;
INIT_LIST_HEAD(&new_timer->it.cpu.entry); INIT_LIST_HEAD(&new_timer->it.cpu.entry);
rcu_read_lock(); rcu_read_lock();
...@@ -524,7 +531,8 @@ static void cpu_timer_fire(struct k_itimer *timer) ...@@ -524,7 +531,8 @@ static void cpu_timer_fire(struct k_itimer *timer)
* reload the timer. But we need to keep it * reload the timer. But we need to keep it
* ticking in case the signal is deliverable next time. * 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, ...@@ -572,7 +580,11 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
WARN_ON_ONCE(p == NULL); 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 * 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 ...@@ -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); itp->it_interval = ns_to_timespec64(timer->it.cpu.incr);
if (timer->it.cpu.expires == 0) { /* Timer not armed at all. */ if (!timer->it.cpu.expires)
itp->it_value.tv_sec = itp->it_value.tv_nsec = 0;
return; return;
}
/* /*
* Sample the clock to take the difference with the expiry time. * 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 ...@@ -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. * Call the timer disarmed, nothing else to do.
*/ */
timer->it.cpu.expires = 0; timer->it.cpu.expires = 0;
itp->it_value = ns_to_timespec64(timer->it.cpu.expires);
return; return;
} else { } else {
cpu_timer_sample_group(timer->it_clock, p, &now); cpu_timer_sample_group(timer->it_clock, p, &now);
...@@ -976,10 +985,10 @@ static void check_process_timers(struct task_struct *tsk, ...@@ -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. * 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; struct sighand_struct *sighand;
unsigned long flags; unsigned long flags;
...@@ -995,12 +1004,12 @@ void posix_cpu_timer_schedule(struct k_itimer *timer) ...@@ -995,12 +1004,12 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
cpu_clock_sample(timer->it_clock, p, &now); cpu_clock_sample(timer->it_clock, p, &now);
bump_cpu_timer(timer, now); bump_cpu_timer(timer, now);
if (unlikely(p->exit_state)) if (unlikely(p->exit_state))
goto out; return;
/* Protect timer list r/w in arm_timer() */ /* Protect timer list r/w in arm_timer() */
sighand = lock_task_sighand(p, &flags); sighand = lock_task_sighand(p, &flags);
if (!sighand) if (!sighand)
goto out; return;
} else { } else {
/* /*
* Protect arm_timer() and timer sampling in case of call to * Protect arm_timer() and timer sampling in case of call to
...@@ -1013,11 +1022,10 @@ void posix_cpu_timer_schedule(struct k_itimer *timer) ...@@ -1013,11 +1022,10 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
* We can't even collect a sample any more. * We can't even collect a sample any more.
*/ */
timer->it.cpu.expires = 0; timer->it.cpu.expires = 0;
goto out; return;
} else if (unlikely(p->exit_state) && thread_group_empty(p)) { } else if (unlikely(p->exit_state) && thread_group_empty(p)) {
unlock_task_sighand(p, &flags); /* If the process is dying, no need to rearm */
/* Optimizations: if the process is dying, no need to rearm */ goto unlock;
goto out;
} }
cpu_timer_sample_group(timer->it_clock, p, &now); cpu_timer_sample_group(timer->it_clock, p, &now);
bump_cpu_timer(timer, now); bump_cpu_timer(timer, now);
...@@ -1029,12 +1037,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer) ...@@ -1029,12 +1037,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
*/ */
WARN_ON_ONCE(!irqs_disabled()); WARN_ON_ONCE(!irqs_disabled());
arm_timer(timer); arm_timer(timer);
unlock:
unlock_task_sighand(p, &flags); 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, ...@@ -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, 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; struct k_itimer timer;
u64 expires;
int error; int error;
/* /*
...@@ -1243,12 +1249,13 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1243,12 +1249,13 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
timer.it_process = current; timer.it_process = current;
if (!error) { if (!error) {
static struct itimerspec64 zero_it; static struct itimerspec64 zero_it;
struct restart_block *restart;
memset(it, 0, sizeof *it); memset(&it, 0, sizeof(it));
it->it_value = *rqtp; it.it_value = *rqtp;
spin_lock_irq(&timer.it_lock); 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) { if (error) {
spin_unlock_irq(&timer.it_lock); spin_unlock_irq(&timer.it_lock);
return error; return error;
...@@ -1277,8 +1284,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1277,8 +1284,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
/* /*
* We were interrupted by a signal. * We were interrupted by a signal.
*/ */
*rqtp = ns_to_timespec64(timer.it.cpu.expires); expires = timer.it.cpu.expires;
error = posix_cpu_timer_set(&timer, 0, &zero_it, it); error = posix_cpu_timer_set(&timer, 0, &zero_it, &it);
if (!error) { if (!error) {
/* /*
* Timer is now unarmed, deletion can not fail. * Timer is now unarmed, deletion can not fail.
...@@ -1298,7 +1305,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1298,7 +1305,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
spin_unlock_irq(&timer.it_lock); 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. * It actually did fire already.
*/ */
...@@ -1306,6 +1313,17 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1306,6 +1313,17 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
} }
error = -ERESTART_RESTARTBLOCK; error = -ERESTART_RESTARTBLOCK;
/*
* Report back to the user the time still remaining.
*/
restart = &current->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; return error;
...@@ -1314,11 +1332,9 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -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 long posix_cpu_nsleep_restart(struct restart_block *restart_block);
static int posix_cpu_nsleep(const clockid_t which_clock, int flags, 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 = &current->restart_block; struct restart_block *restart_block = &current->restart_block;
struct itimerspec64 it;
struct timespec ts;
int error; int error;
/* /*
...@@ -1329,23 +1345,15 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -1329,23 +1345,15 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
CPUCLOCK_PID(which_clock) == task_pid_vnr(current))) CPUCLOCK_PID(which_clock) == task_pid_vnr(current)))
return -EINVAL; return -EINVAL;
error = do_cpu_nanosleep(which_clock, flags, rqtp, &it); error = do_cpu_nanosleep(which_clock, flags, rqtp);
if (error == -ERESTART_RESTARTBLOCK) { if (error == -ERESTART_RESTARTBLOCK) {
if (flags & TIMER_ABSTIME) if (flags & TIMER_ABSTIME)
return -ERESTARTNOHAND; 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->fn = posix_cpu_nsleep_restart;
restart_block->nanosleep.clockid = which_clock; restart_block->nanosleep.clockid = which_clock;
restart_block->nanosleep.rmtp = rmtp;
restart_block->nanosleep.expires = timespec64_to_ns(rqtp);
} }
return error; return error;
} }
...@@ -1353,28 +1361,11 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -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) static long posix_cpu_nsleep_restart(struct restart_block *restart_block)
{ {
clockid_t which_clock = restart_block->nanosleep.clockid; clockid_t which_clock = restart_block->nanosleep.clockid;
struct itimerspec64 it;
struct timespec64 t; struct timespec64 t;
struct timespec tmp;
int error;
t = ns_to_timespec64(restart_block->nanosleep.expires); t = ns_to_timespec64(restart_block->nanosleep.expires);
error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it); return do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t);
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;
} }
#define PROCESS_CLOCK MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED) #define PROCESS_CLOCK MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED)
...@@ -1396,14 +1387,9 @@ static int process_cpu_timer_create(struct k_itimer *timer) ...@@ -1396,14 +1387,9 @@ static int process_cpu_timer_create(struct k_itimer *timer)
return posix_cpu_timer_create(timer); return posix_cpu_timer_create(timer);
} }
static int process_cpu_nsleep(const clockid_t which_clock, int flags, static int process_cpu_nsleep(const clockid_t which_clock, int flags,
struct timespec64 *rqtp, const 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)
{ {
return -EINVAL; return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp);
} }
static int thread_cpu_clock_getres(const clockid_t which_clock, static int thread_cpu_clock_getres(const clockid_t which_clock,
struct timespec64 *tp) struct timespec64 *tp)
...@@ -1421,36 +1407,27 @@ static int thread_cpu_timer_create(struct k_itimer *timer) ...@@ -1421,36 +1407,27 @@ static int thread_cpu_timer_create(struct k_itimer *timer)
return posix_cpu_timer_create(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_getres = posix_cpu_clock_getres,
.clock_set = posix_cpu_clock_set, .clock_set = posix_cpu_clock_set,
.clock_get = posix_cpu_clock_get, .clock_get = posix_cpu_clock_get,
.timer_create = posix_cpu_timer_create, .timer_create = posix_cpu_timer_create,
.nsleep = posix_cpu_nsleep, .nsleep = posix_cpu_nsleep,
.nsleep_restart = posix_cpu_nsleep_restart,
.timer_set = posix_cpu_timer_set, .timer_set = posix_cpu_timer_set,
.timer_del = posix_cpu_timer_del, .timer_del = posix_cpu_timer_del,
.timer_get = posix_cpu_timer_get, .timer_get = posix_cpu_timer_get,
.timer_rearm = posix_cpu_timer_rearm,
}; };
static __init int init_posix_cpu_timers(void) const struct k_clock clock_process = {
{ .clock_getres = process_cpu_clock_getres,
struct k_clock process = { .clock_get = process_cpu_clock_get,
.clock_getres = process_cpu_clock_getres, .timer_create = process_cpu_timer_create,
.clock_get = process_cpu_clock_get, .nsleep = process_cpu_nsleep,
.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);
return 0; const struct k_clock clock_thread = {
} .clock_getres = thread_cpu_clock_getres,
__initcall(init_posix_cpu_timers); .clock_get = thread_cpu_clock_get,
.timer_create = thread_cpu_timer_create,
};
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/timekeeping.h> #include <linux/timekeeping.h>
#include <linux/posix-timers.h> #include <linux/posix-timers.h>
#include <linux/compat.h>
asmlinkage long sys_ni_posix_timers(void) asmlinkage long sys_ni_posix_timers(void)
{ {
...@@ -27,6 +28,7 @@ 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 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_create);
SYS_NI(timer_gettime); SYS_NI(timer_gettime);
...@@ -39,6 +41,12 @@ SYS_NI(setitimer); ...@@ -39,6 +41,12 @@ SYS_NI(setitimer);
#ifdef __ARCH_WANT_SYS_ALARM #ifdef __ARCH_WANT_SYS_ALARM
SYS_NI(alarm); SYS_NI(alarm);
#endif #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 * 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, ...@@ -110,22 +118,106 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
case CLOCK_REALTIME: case CLOCK_REALTIME:
case CLOCK_MONOTONIC: case CLOCK_MONOTONIC:
case CLOCK_BOOTTIME: case CLOCK_BOOTTIME:
if (copy_from_user(&t, rqtp, sizeof (struct timespec))) break;
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);
default: default:
return -EINVAL; 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 #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 #endif
...@@ -49,8 +49,10 @@ ...@@ -49,8 +49,10 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/compat.h>
#include "timekeeping.h" #include "timekeeping.h"
#include "posix-timers.h"
/* /*
* Management arrays for POSIX timers. Timers are now kept in static hash table * Management arrays for POSIX timers. Timers are now kept in static hash table
...@@ -69,6 +71,10 @@ static struct kmem_cache *posix_timers_cache; ...@@ -69,6 +71,10 @@ static struct kmem_cache *posix_timers_cache;
static DEFINE_HASHTABLE(posix_timers_hashtable, 9); static DEFINE_HASHTABLE(posix_timers_hashtable, 9);
static DEFINE_SPINLOCK(hash_lock); 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 * 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. * SIGEV values. Here we put out an error if this assumption fails.
...@@ -124,22 +130,6 @@ static DEFINE_SPINLOCK(hash_lock); ...@@ -124,22 +130,6 @@ static DEFINE_SPINLOCK(hash_lock);
* have is CLOCK_REALTIME and its high res counter part, both of * have is CLOCK_REALTIME and its high res counter part, both of
* which we beg off on and pass to do_sys_settimeofday(). * 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); static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags);
#define lock_timer(tid, flags) \ #define lock_timer(tid, flags) \
...@@ -285,91 +275,23 @@ static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp) ...@@ -285,91 +275,23 @@ static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp)
*/ */
static __init int init_posix_timers(void) 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", posix_timers_cache = kmem_cache_create("posix_timers_cache",
sizeof (struct k_itimer), 0, SLAB_PANIC, sizeof (struct k_itimer), 0, SLAB_PANIC,
NULL); NULL);
return 0; return 0;
} }
__initcall(init_posix_timers); __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; struct hrtimer *timer = &timr->it.real.timer;
if (timr->it.real.interval == 0) if (!timr->it_interval)
return; return;
timr->it_overrun += (unsigned int) hrtimer_forward(timer, timr->it_overrun += (unsigned int) hrtimer_forward(timer,
timer->base->get_time(), timer->base->get_time(),
timr->it.real.interval); timr->it_interval);
timr->it_overrun_last = timr->it_overrun;
timr->it_overrun = -1;
++timr->it_requeue_pending;
hrtimer_restart(timer); hrtimer_restart(timer);
} }
...@@ -384,24 +306,27 @@ static void schedule_next_timer(struct k_itimer *timr) ...@@ -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, * To protect against the timer going away while the interrupt is queued,
* we require that the it_requeue_pending flag be set. * 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; struct k_itimer *timr;
unsigned long flags; unsigned long flags;
timr = lock_timer(info->si_tid, &flags); timr = lock_timer(info->si_tid, &flags);
if (!timr)
return;
if (timr && timr->it_requeue_pending == info->si_sys_private) { if (timr->it_requeue_pending == info->si_sys_private) {
if (timr->it_clock < 0) timr->kclock->timer_rearm(timr);
posix_cpu_timer_schedule(timr);
else timr->it_active = 1;
schedule_next_timer(timr); timr->it_overrun_last = timr->it_overrun;
timr->it_overrun = -1;
++timr->it_requeue_pending;
info->si_overrun += timr->it_overrun_last; 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) 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) ...@@ -410,12 +335,12 @@ int posix_timer_event(struct k_itimer *timr, int si_private)
int shared, ret = -1; int shared, ret = -1;
/* /*
* FIXME: if ->sigq is queued we can race with * 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 * 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(). * 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. * and re-schedules it while ->sigq is pending.
* Not really bad, but not that we want. * Not really bad, but not that we want.
*/ */
...@@ -431,7 +356,6 @@ int posix_timer_event(struct k_itimer *timr, int si_private) ...@@ -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. */ /* If we failed to send the signal the timer stops. */
return ret > 0; return ret > 0;
} }
EXPORT_SYMBOL_GPL(posix_timer_event);
/* /*
* This function gets called when a POSIX.1b interval timer expires. It * 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) ...@@ -450,7 +374,8 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
timr = container_of(timer, struct k_itimer, it.real.timer); timr = container_of(timer, struct k_itimer, it.real.timer);
spin_lock_irqsave(&timr->it_lock, flags); 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; si_private = ++timr->it_requeue_pending;
if (posix_timer_event(timr, si_private)) { if (posix_timer_event(timr, si_private)) {
...@@ -459,7 +384,7 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) ...@@ -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 * we will not get a call back to restart it AND
* it should be restarted. * it should be restarted.
*/ */
if (timr->it.real.interval != 0) { if (timr->it_interval != 0) {
ktime_t now = hrtimer_cb_get_time(timer); ktime_t now = hrtimer_cb_get_time(timer);
/* /*
...@@ -488,15 +413,16 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) ...@@ -488,15 +413,16 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
{ {
ktime_t kj = NSEC_PER_SEC / HZ; ktime_t kj = NSEC_PER_SEC / HZ;
if (timr->it.real.interval < kj) if (timr->it_interval < kj)
now = ktime_add(now, kj); now = ktime_add(now, kj);
} }
#endif #endif
timr->it_overrun += (unsigned int) timr->it_overrun += (unsigned int)
hrtimer_forward(timer, now, hrtimer_forward(timer, now,
timr->it.real.interval); timr->it_interval);
ret = HRTIMER_RESTART; ret = HRTIMER_RESTART;
++timr->it_requeue_pending; ++timr->it_requeue_pending;
timr->it_active = 1;
} }
} }
...@@ -521,30 +447,6 @@ static struct pid *good_sigevent(sigevent_t * event) ...@@ -521,30 +447,6 @@ static struct pid *good_sigevent(sigevent_t * event)
return task_pid(rtn); 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) static struct k_itimer * alloc_posix_timer(void)
{ {
struct k_itimer *tmr; struct k_itimer *tmr;
...@@ -581,17 +483,6 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set) ...@@ -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); 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) static int common_timer_create(struct k_itimer *new_timer)
{ {
hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0); 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) ...@@ -599,15 +490,12 @@ static int common_timer_create(struct k_itimer *new_timer)
} }
/* Create a POSIX.1b interval timer. */ /* Create a POSIX.1b interval timer. */
static int do_timer_create(clockid_t which_clock, struct sigevent *event,
SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, timer_t __user *created_timer_id)
struct sigevent __user *, timer_event_spec,
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; struct k_itimer *new_timer;
int error, new_timer_id; int error, new_timer_id;
sigevent_t event;
int it_id_set = IT_ID_NOT_SET; int it_id_set = IT_ID_NOT_SET;
if (!kc) if (!kc)
...@@ -629,31 +517,28 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, ...@@ -629,31 +517,28 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
it_id_set = IT_ID_SET; it_id_set = IT_ID_SET;
new_timer->it_id = (timer_t) new_timer_id; new_timer->it_id = (timer_t) new_timer_id;
new_timer->it_clock = which_clock; new_timer->it_clock = which_clock;
new_timer->kclock = kc;
new_timer->it_overrun = -1; new_timer->it_overrun = -1;
if (timer_event_spec) { if (event) {
if (copy_from_user(&event, timer_event_spec, sizeof (event))) {
error = -EFAULT;
goto out;
}
rcu_read_lock(); rcu_read_lock();
new_timer->it_pid = get_pid(good_sigevent(&event)); new_timer->it_pid = get_pid(good_sigevent(event));
rcu_read_unlock(); rcu_read_unlock();
if (!new_timer->it_pid) { if (!new_timer->it_pid) {
error = -EINVAL; error = -EINVAL;
goto out; 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 { } else {
memset(&event.sigev_value, 0, sizeof(event.sigev_value)); new_timer->it_sigev_notify = SIGEV_SIGNAL;
event.sigev_notify = SIGEV_SIGNAL; new_timer->sigq->info.si_signo = SIGALRM;
event.sigev_signo = SIGALRM; memset(&new_timer->sigq->info.si_value, 0, sizeof(sigval_t));
event.sigev_value.sival_int = new_timer->it_id; new_timer->sigq->info.si_value.sival_int = new_timer->it_id;
new_timer->it_pid = get_pid(task_tgid(current)); 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_tid = new_timer->it_id;
new_timer->sigq->info.si_code = SI_TIMER; new_timer->sigq->info.si_code = SI_TIMER;
...@@ -684,6 +569,36 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, ...@@ -684,6 +569,36 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
return error; 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 * 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 * 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) ...@@ -717,6 +632,20 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)
return NULL; 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 * 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 * 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) ...@@ -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 * it is the same as a requeue pending timer WRT to what we should
* report. * report.
*/ */
static void void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
{ {
const struct k_clock *kc = timr->kclock;
ktime_t now, remaining, iv; 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)); sig_none = (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE;
iv = timr->it_interval;
iv = timr->it.real.interval;
/* interval timer ? */ /* interval timer ? */
if (iv) if (iv) {
cur_setting->it_interval = ktime_to_timespec64(iv); cur_setting->it_interval = ktime_to_timespec64(iv);
else if (!hrtimer_active(timer) && } else if (!timr->it_active) {
(timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) /*
return; * 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 * When a requeue is pending or this is a SIGEV_NONE timer move the
* timer move the expiry time forward by intervals, so * expiry time forward by intervals, so expiry is > now.
* expiry is > now.
*/ */
if (iv && (timr->it_requeue_pending & REQUEUE_PENDING || if (iv && (timr->it_requeue_pending & REQUEUE_PENDING || sig_none))
(timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) timr->it_overrun += kc->timer_forward(timr, now);
timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
remaining = __hrtimer_expires_remaining_adjusted(timer, now); remaining = kc->timer_remaining(timr, now);
/* Return 0 only, when the timer is expired and not pending */ /* Return 0 only, when the timer is expired and not pending */
if (remaining <= 0) { if (remaining <= 0) {
/* /*
* A single shot SIGEV_NONE timer must return 0, when * A single shot SIGEV_NONE timer must return 0, when
* it is expired ! * it is expired !
*/ */
if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) if (!sig_none)
cur_setting->it_value.tv_nsec = 1; cur_setting->it_value.tv_nsec = 1;
} else } else {
cur_setting->it_value = ktime_to_timespec64(remaining); cur_setting->it_value = ktime_to_timespec64(remaining);
}
} }
/* Get the time remaining on a POSIX.1b interval timer. */ /* Get the time remaining on a POSIX.1b interval timer. */
SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, static int do_timer_gettime(timer_t timer_id, struct itimerspec64 *setting)
struct itimerspec __user *, setting)
{ {
struct itimerspec64 cur_setting64;
struct itimerspec cur_setting;
struct k_itimer *timr; struct k_itimer *timr;
struct k_clock *kc; const struct k_clock *kc;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
...@@ -789,20 +724,49 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, ...@@ -789,20 +724,49 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
if (!timr) if (!timr)
return -EINVAL; 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)) if (WARN_ON_ONCE(!kc || !kc->timer_get))
ret = -EINVAL; ret = -EINVAL;
else else
kc->timer_get(timr, &cur_setting64); kc->timer_get(timr, setting);
unlock_timer(timr, flags); unlock_timer(timr, flags);
return ret;
}
cur_setting = itimerspec64_to_itimerspec(&cur_setting64); /* Get the time remaining on a POSIX.1b interval timer. */
if (!ret && copy_to_user(setting, &cur_setting, sizeof (cur_setting))) SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
return -EFAULT; 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; return ret;
} }
#endif
/* /*
* Get the number of overruns of a POSIX.1b interval timer. This is to * 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, ...@@ -810,7 +774,7 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
* accumulating overruns on the next timer. The overrun is frozen when * accumulating overruns on the next timer. The overrun is frozen when
* the signal is delivered, either at the notify time (if the info block * 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 * 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. * to pick up the frozen overrun.
*/ */
SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id)
...@@ -829,117 +793,183 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) ...@@ -829,117 +793,183 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id)
return overrun; return overrun;
} }
/* Set a POSIX.1b interval timer. */ static void common_hrtimer_arm(struct k_itimer *timr, ktime_t expires,
/* timr->it_lock is taken. */ bool absolute, bool sigev_none)
static int
common_timer_set(struct k_itimer *timr, int flags,
struct itimerspec64 *new_setting, struct itimerspec64 *old_setting)
{ {
struct hrtimer *timer = &timr->it.real.timer; struct hrtimer *timer = &timr->it.real.timer;
enum hrtimer_mode mode; 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) if (old_setting)
common_timer_get(timr, old_setting); common_timer_get(timr, old_setting);
/* disable the timer */ /* Prevent rearming by clearing the interval */
timr->it.real.interval = 0; timr->it_interval = 0;
/* /*
* careful here. If smp we could be in the "fire" routine which will * Careful here. On SMP systems the timer expiry function could be
* be spinning as we hold the lock. But this is ONLY an SMP issue. * 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; 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; ~REQUEUE_PENDING;
timr->it_overrun_last = 0; 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) if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec)
return 0; return 0;
mode = flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; timr->it_interval = timespec64_to_ktime(new_setting->it_interval);
hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); expires = timespec64_to_ktime(new_setting->it_value);
timr->it.real.timer.function = posix_timer_fn; sigev_none = (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE;
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;
}
hrtimer_start_expires(timer, mode); kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none);
timr->it_active = !sigev_none;
return 0; return 0;
} }
/* Set a POSIX.1b interval timer */ static int do_timer_settime(timer_t timer_id, int flags,
SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, struct itimerspec64 *new_spec64,
const struct itimerspec __user *, new_setting, struct itimerspec64 *old_spec64)
struct itimerspec __user *, old_setting)
{ {
struct itimerspec64 new_spec64, old_spec64; const struct k_clock *kc;
struct itimerspec64 *rtn = old_setting ? &old_spec64 : NULL;
struct itimerspec new_spec, old_spec;
struct k_itimer *timr; struct k_itimer *timr;
unsigned long flag; unsigned long flag;
struct k_clock *kc;
int error = 0; int error = 0;
if (!new_setting) if (!timespec64_valid(&new_spec64->it_interval) ||
!timespec64_valid(&new_spec64->it_value))
return -EINVAL; return -EINVAL;
if (copy_from_user(&new_spec, new_setting, sizeof (new_spec))) if (old_spec64)
return -EFAULT; memset(old_spec64, 0, sizeof(*old_spec64));
new_spec64 = itimerspec_to_itimerspec64(&new_spec);
if (!timespec64_valid(&new_spec64.it_interval) ||
!timespec64_valid(&new_spec64.it_value))
return -EINVAL;
retry: retry:
timr = lock_timer(timer_id, &flag); timr = lock_timer(timer_id, &flag);
if (!timr) if (!timr)
return -EINVAL; return -EINVAL;
kc = clockid_to_kclock(timr->it_clock); kc = timr->kclock;
if (WARN_ON_ONCE(!kc || !kc->timer_set)) if (WARN_ON_ONCE(!kc || !kc->timer_set))
error = -EINVAL; error = -EINVAL;
else else
error = kc->timer_set(timr, flags, &new_spec64, rtn); error = kc->timer_set(timr, flags, new_spec64, old_spec64);
unlock_timer(timr, flag); unlock_timer(timr, flag);
if (error == TIMER_RETRY) { if (error == TIMER_RETRY) {
rtn = NULL; // We already got the old time... old_spec64 = NULL; // We already got the old time...
goto retry; goto retry;
} }
old_spec = itimerspec64_to_itimerspec(&old_spec64); return error;
if (old_setting && !error && }
copy_to_user(old_setting, &old_spec, sizeof (old_spec)))
error = -EFAULT; /* 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; 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; return TIMER_RETRY;
timer->it_active = 0;
return 0; return 0;
} }
static inline int timer_delete_hook(struct k_itimer *timer) 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)) if (WARN_ON_ONCE(!kc || !kc->timer_del))
return -EINVAL; return -EINVAL;
...@@ -1018,7 +1048,7 @@ void exit_itimers(struct signal_struct *sig) ...@@ -1018,7 +1048,7 @@ void exit_itimers(struct signal_struct *sig)
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
const struct timespec __user *, tp) 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 timespec64 new_tp64;
struct timespec new_tp; struct timespec new_tp;
...@@ -1035,7 +1065,7 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, ...@@ -1035,7 +1065,7 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
struct timespec __user *,tp) 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 timespec64 kernel_tp64;
struct timespec kernel_tp; struct timespec kernel_tp;
int error; int error;
...@@ -1055,7 +1085,7 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, ...@@ -1055,7 +1085,7 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
struct timex __user *, utx) 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; struct timex ktx;
int err; int err;
...@@ -1078,7 +1108,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, ...@@ -1078,7 +1108,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
struct timespec __user *, tp) 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 timespec64 rtn_tp64;
struct timespec rtn_tp; struct timespec rtn_tp;
int error; int error;
...@@ -1095,13 +1125,98 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, ...@@ -1095,13 +1125,98 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
return error; 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 * nanosleep for monotonic and realtime clocks
*/ */
static int common_nsleep(const clockid_t which_clock, int flags, 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, HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
which_clock); which_clock);
} }
...@@ -1110,7 +1225,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, ...@@ -1110,7 +1225,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
const struct timespec __user *, rqtp, const struct timespec __user *, rqtp,
struct timespec __user *, rmtp) 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 timespec64 t64;
struct timespec t; struct timespec t;
...@@ -1125,21 +1240,141 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, ...@@ -1125,21 +1240,141 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
t64 = timespec_to_timespec64(t); t64 = timespec_to_timespec64(t);
if (!timespec64_valid(&t64)) if (!timespec64_valid(&t64))
return -EINVAL; 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);
} }
/* #ifdef CONFIG_COMPAT
* This will restart clock_nanosleep. This is required only by COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
* compat_clock_nanosleep_restart for now. struct compat_timespec __user *, rqtp,
*/ struct compat_timespec __user *, rmtp)
long clock_nanosleep_restart(struct restart_block *restart_block)
{ {
clockid_t which_clock = restart_block->nanosleep.clockid; const struct k_clock *kc = clockid_to_kclock(which_clock);
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; 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];
} }
#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);
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/compat.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <generated/timeconst.h> #include <generated/timeconst.h>
...@@ -99,6 +100,47 @@ SYSCALL_DEFINE1(stime, time_t __user *, tptr) ...@@ -99,6 +100,47 @@ SYSCALL_DEFINE1(stime, time_t __user *, tptr)
#endif /* __ARCH_WANT_SYS_TIME */ #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, SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
struct timezone __user *, tz) struct timezone __user *, tz)
{ {
...@@ -215,6 +257,47 @@ SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv, ...@@ -215,6 +257,47 @@ SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv,
return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL); 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) SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p)
{ {
struct timex txc; /* Local copy of parameter */ struct timex txc; /* Local copy of parameter */
...@@ -224,12 +307,33 @@ SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p) ...@@ -224,12 +307,33 @@ SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p)
* structure. But bear in mind that the structures * structure. But bear in mind that the structures
* may change * may change
*/ */
if(copy_from_user(&txc, txc_p, sizeof(struct timex))) if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
return -EFAULT; return -EFAULT;
ret = do_adjtimex(&txc); ret = do_adjtimex(&txc);
return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret; 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. * Convert jiffies to milliseconds and back.
* *
......
...@@ -72,6 +72,10 @@ static inline void tk_normalize_xtime(struct timekeeper *tk) ...@@ -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->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift;
tk->xtime_sec++; 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) static inline struct timespec64 tk_xtime(struct timekeeper *tk)
...@@ -285,12 +289,14 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock) ...@@ -285,12 +289,14 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
/* if changing clocks, convert xtime_nsec shift units */ /* if changing clocks, convert xtime_nsec shift units */
if (old_clock) { if (old_clock) {
int shift_change = clock->shift - old_clock->shift; int shift_change = clock->shift - old_clock->shift;
if (shift_change < 0) if (shift_change < 0) {
tk->tkr_mono.xtime_nsec >>= -shift_change; 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_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_mono.shift = clock->shift;
tk->tkr_raw.shift = clock->shift; tk->tkr_raw.shift = clock->shift;
...@@ -510,6 +516,7 @@ static void halt_fast_timekeeper(struct timekeeper *tk) ...@@ -510,6 +516,7 @@ static void halt_fast_timekeeper(struct timekeeper *tk)
} }
#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD #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) static inline void update_vsyscall(struct timekeeper *tk)
{ {
...@@ -619,9 +626,6 @@ static inline void tk_update_ktime_data(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; nsec = (u32) tk->wall_to_monotonic.tv_nsec;
tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + 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 * The sum of the nanoseconds portions of xtime and
* wall_to_monotonic can be greater/equal one second. Take * wall_to_monotonic can be greater/equal one second. Take
...@@ -631,6 +635,11 @@ static inline void tk_update_ktime_data(struct timekeeper *tk) ...@@ -631,6 +635,11 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
if (nsec >= NSEC_PER_SEC) if (nsec >= NSEC_PER_SEC)
seconds++; seconds++;
tk->ktime_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 */ /* must hold timekeeper_lock */
...@@ -672,7 +681,6 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) ...@@ -672,7 +681,6 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
static void timekeeping_forward_now(struct timekeeper *tk) static void timekeeping_forward_now(struct timekeeper *tk)
{ {
u64 cycle_now, delta; u64 cycle_now, delta;
u64 nsec;
cycle_now = tk_clock_read(&tk->tkr_mono); cycle_now = tk_clock_read(&tk->tkr_mono);
delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask); 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) ...@@ -684,10 +692,13 @@ static void timekeeping_forward_now(struct timekeeper *tk)
/* If arch requires, add in get_arch_timeoffset() */ /* If arch requires, add in get_arch_timeoffset() */
tk->tkr_mono.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_mono.shift; 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); tk->tkr_raw.xtime_nsec += delta * tk->tkr_raw.mult;
timespec64_add_ns(&tk->raw_time, nsec);
/* 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) ...@@ -1373,19 +1384,18 @@ int timekeeping_notify(struct clocksource *clock)
void getrawmonotonic64(struct timespec64 *ts) void getrawmonotonic64(struct timespec64 *ts)
{ {
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 ts64;
unsigned long seq; unsigned long seq;
u64 nsecs; u64 nsecs;
do { do {
seq = read_seqcount_begin(&tk_core.seq); seq = read_seqcount_begin(&tk_core.seq);
ts->tv_sec = tk->raw_sec;
nsecs = timekeeping_get_ns(&tk->tkr_raw); nsecs = timekeeping_get_ns(&tk->tkr_raw);
ts64 = tk->raw_time;
} while (read_seqcount_retry(&tk_core.seq, seq)); } while (read_seqcount_retry(&tk_core.seq, seq));
timespec64_add_ns(&ts64, nsecs); ts->tv_nsec = 0;
*ts = ts64; timespec64_add_ns(ts, nsecs);
} }
EXPORT_SYMBOL(getrawmonotonic64); EXPORT_SYMBOL(getrawmonotonic64);
...@@ -1509,8 +1519,7 @@ void __init timekeeping_init(void) ...@@ -1509,8 +1519,7 @@ void __init timekeeping_init(void)
tk_setup_internals(tk, clock); tk_setup_internals(tk, clock);
tk_set_xtime(tk, &now); tk_set_xtime(tk, &now);
tk->raw_time.tv_sec = 0; tk->raw_sec = 0;
tk->raw_time.tv_nsec = 0;
if (boot.tv_sec == 0 && boot.tv_nsec == 0) if (boot.tv_sec == 0 && boot.tv_nsec == 0)
boot = tk_xtime(tk); boot = tk_xtime(tk);
...@@ -2011,15 +2020,12 @@ static u64 logarithmic_accumulation(struct timekeeper *tk, u64 offset, ...@@ -2011,15 +2020,12 @@ static u64 logarithmic_accumulation(struct timekeeper *tk, u64 offset,
*clock_set |= accumulate_nsecs_to_secs(tk); *clock_set |= accumulate_nsecs_to_secs(tk);
/* Accumulate raw time */ /* 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; tk->tkr_raw.xtime_nsec += tk->raw_interval << shift;
snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift; snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift;
while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) { while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) {
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 */ /* Accumulate error between NTP and clock interval */
tk->ntp_error += tk->ntp_tick << shift; tk->ntp_error += tk->ntp_tick << shift;
......
...@@ -195,7 +195,7 @@ EXPORT_SYMBOL(jiffies_64); ...@@ -195,7 +195,7 @@ EXPORT_SYMBOL(jiffies_64);
#endif #endif
struct timer_base { struct timer_base {
spinlock_t lock; raw_spinlock_t lock;
struct timer_list *running_timer; struct timer_list *running_timer;
unsigned long clk; unsigned long clk;
unsigned long next_expiry; unsigned long next_expiry;
...@@ -913,10 +913,10 @@ static struct timer_base *lock_timer_base(struct timer_list *timer, ...@@ -913,10 +913,10 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
if (!(tf & TIMER_MIGRATING)) { if (!(tf & TIMER_MIGRATING)) {
base = get_timer_base(tf); base = get_timer_base(tf);
spin_lock_irqsave(&base->lock, *flags); raw_spin_lock_irqsave(&base->lock, *flags);
if (timer->flags == tf) if (timer->flags == tf)
return base; return base;
spin_unlock_irqrestore(&base->lock, *flags); raw_spin_unlock_irqrestore(&base->lock, *flags);
} }
cpu_relax(); cpu_relax();
} }
...@@ -986,9 +986,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) ...@@ -986,9 +986,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
/* See the comment in lock_timer_base() */ /* See the comment in lock_timer_base() */
timer->flags |= TIMER_MIGRATING; timer->flags |= TIMER_MIGRATING;
spin_unlock(&base->lock); raw_spin_unlock(&base->lock);
base = new_base; base = new_base;
spin_lock(&base->lock); raw_spin_lock(&base->lock);
WRITE_ONCE(timer->flags, WRITE_ONCE(timer->flags,
(timer->flags & ~TIMER_BASEMASK) | base->cpu); (timer->flags & ~TIMER_BASEMASK) | base->cpu);
} }
...@@ -1013,7 +1013,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) ...@@ -1013,7 +1013,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
} }
out_unlock: out_unlock:
spin_unlock_irqrestore(&base->lock, flags); raw_spin_unlock_irqrestore(&base->lock, flags);
return ret; return ret;
} }
...@@ -1106,16 +1106,16 @@ void add_timer_on(struct timer_list *timer, int cpu) ...@@ -1106,16 +1106,16 @@ void add_timer_on(struct timer_list *timer, int cpu)
if (base != new_base) { if (base != new_base) {
timer->flags |= TIMER_MIGRATING; timer->flags |= TIMER_MIGRATING;
spin_unlock(&base->lock); raw_spin_unlock(&base->lock);
base = new_base; base = new_base;
spin_lock(&base->lock); raw_spin_lock(&base->lock);
WRITE_ONCE(timer->flags, WRITE_ONCE(timer->flags,
(timer->flags & ~TIMER_BASEMASK) | cpu); (timer->flags & ~TIMER_BASEMASK) | cpu);
} }
debug_activate(timer, timer->expires); debug_activate(timer, timer->expires);
internal_add_timer(base, timer); internal_add_timer(base, timer);
spin_unlock_irqrestore(&base->lock, flags); raw_spin_unlock_irqrestore(&base->lock, flags);
} }
EXPORT_SYMBOL_GPL(add_timer_on); EXPORT_SYMBOL_GPL(add_timer_on);
...@@ -1141,7 +1141,7 @@ int del_timer(struct timer_list *timer) ...@@ -1141,7 +1141,7 @@ int del_timer(struct timer_list *timer)
if (timer_pending(timer)) { if (timer_pending(timer)) {
base = lock_timer_base(timer, &flags); base = lock_timer_base(timer, &flags);
ret = detach_if_pending(timer, base, true); ret = detach_if_pending(timer, base, true);
spin_unlock_irqrestore(&base->lock, flags); raw_spin_unlock_irqrestore(&base->lock, flags);
} }
return ret; return ret;
...@@ -1150,7 +1150,7 @@ EXPORT_SYMBOL(del_timer); ...@@ -1150,7 +1150,7 @@ EXPORT_SYMBOL(del_timer);
/** /**
* try_to_del_timer_sync - Try to deactivate a 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) * 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. * 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) ...@@ -1168,7 +1168,7 @@ int try_to_del_timer_sync(struct timer_list *timer)
if (base->running_timer != timer) if (base->running_timer != timer)
ret = detach_if_pending(timer, base, true); ret = detach_if_pending(timer, base, true);
spin_unlock_irqrestore(&base->lock, flags); raw_spin_unlock_irqrestore(&base->lock, flags);
return ret; return ret;
} }
...@@ -1299,13 +1299,13 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head) ...@@ -1299,13 +1299,13 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head)
data = timer->data; data = timer->data;
if (timer->flags & TIMER_IRQSAFE) { if (timer->flags & TIMER_IRQSAFE) {
spin_unlock(&base->lock); raw_spin_unlock(&base->lock);
call_timer_fn(timer, fn, data); call_timer_fn(timer, fn, data);
spin_lock(&base->lock); raw_spin_lock(&base->lock);
} else { } else {
spin_unlock_irq(&base->lock); raw_spin_unlock_irq(&base->lock);
call_timer_fn(timer, fn, data); 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) ...@@ -1474,7 +1474,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
if (cpu_is_offline(smp_processor_id())) if (cpu_is_offline(smp_processor_id()))
return expires; return expires;
spin_lock(&base->lock); raw_spin_lock(&base->lock);
nextevt = __next_timer_interrupt(base); nextevt = __next_timer_interrupt(base);
is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA); is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA);
base->next_expiry = nextevt; base->next_expiry = nextevt;
...@@ -1502,7 +1502,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) ...@@ -1502,7 +1502,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
if ((expires - basem) > TICK_NSEC) if ((expires - basem) > TICK_NSEC)
base->is_idle = true; base->is_idle = true;
} }
spin_unlock(&base->lock); raw_spin_unlock(&base->lock);
return cmp_next_hrtimer_event(basem, expires); return cmp_next_hrtimer_event(basem, expires);
} }
...@@ -1590,7 +1590,7 @@ static inline void __run_timers(struct timer_base *base) ...@@ -1590,7 +1590,7 @@ static inline void __run_timers(struct timer_base *base)
if (!time_after_eq(jiffies, base->clk)) if (!time_after_eq(jiffies, base->clk))
return; return;
spin_lock_irq(&base->lock); raw_spin_lock_irq(&base->lock);
while (time_after_eq(jiffies, base->clk)) { while (time_after_eq(jiffies, base->clk)) {
...@@ -1601,7 +1601,7 @@ static inline void __run_timers(struct timer_base *base) ...@@ -1601,7 +1601,7 @@ static inline void __run_timers(struct timer_base *base)
expire_timers(base, heads + levels); expire_timers(base, heads + levels);
} }
base->running_timer = NULL; 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) ...@@ -1786,16 +1786,16 @@ int timers_dead_cpu(unsigned int cpu)
* The caller is globally serialized and nobody else * The caller is globally serialized and nobody else
* takes two locks at once, deadlock is not possible. * takes two locks at once, deadlock is not possible.
*/ */
spin_lock_irq(&new_base->lock); raw_spin_lock_irq(&new_base->lock);
spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
BUG_ON(old_base->running_timer); BUG_ON(old_base->running_timer);
for (i = 0; i < WHEEL_SIZE; i++) for (i = 0; i < WHEEL_SIZE; i++)
migrate_timer_list(new_base, old_base->vectors + i); migrate_timer_list(new_base, old_base->vectors + i);
spin_unlock(&old_base->lock); raw_spin_unlock(&old_base->lock);
spin_unlock_irq(&new_base->lock); raw_spin_unlock_irq(&new_base->lock);
put_cpu_ptr(&timer_bases); put_cpu_ptr(&timer_bases);
} }
return 0; return 0;
...@@ -1811,7 +1811,7 @@ static void __init init_timer_cpu(int cpu) ...@@ -1811,7 +1811,7 @@ static void __init init_timer_cpu(int cpu)
for (i = 0; i < NR_BASES; i++) { for (i = 0; i < NR_BASES; i++) {
base = per_cpu_ptr(&timer_bases[i], cpu); base = per_cpu_ptr(&timer_bases[i], cpu);
base->cpu = cpu; base->cpu = cpu;
spin_lock_init(&base->lock); raw_spin_lock_init(&base->lock);
base->clk = jiffies; base->clk = jiffies;
} }
} }
......
BUILD_FLAGS = -DKTEST BUILD_FLAGS = -DKTEST
CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS) 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 # these are all "safe" tests that don't modify
# system time or require escalated privileges # system time or require escalated privileges
...@@ -8,7 +8,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ ...@@ -8,7 +8,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \
inconsistency-check raw_skew threadtest rtctest inconsistency-check raw_skew threadtest rtctest
TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ 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 leapcrash set-tai set-2038 set-tz
...@@ -24,6 +24,7 @@ run_destructive_tests: run_tests ...@@ -24,6 +24,7 @@ run_destructive_tests: run_tests
./change_skew ./change_skew
./skew_consistency ./skew_consistency
./clocksource-switch ./clocksource-switch
./freq-step
./leap-a-day -s -i 10 ./leap-a-day -s -i 10
./leapcrash ./leapcrash
./set-tz ./set-tz
......
/*
* 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();
}
...@@ -118,7 +118,7 @@ int consistency_test(int clock_type, unsigned long seconds) ...@@ -118,7 +118,7 @@ int consistency_test(int clock_type, unsigned long seconds)
start_str = ctime(&t); start_str = ctime(&t);
while (seconds == -1 || now - then < seconds) { while (seconds == -1 || now - then < seconds) {
inconsistent = 0; inconsistent = -1;
/* Fill list */ /* Fill list */
for (i = 0; i < CALLS_PER_LOOP; i++) for (i = 0; i < CALLS_PER_LOOP; i++)
...@@ -130,7 +130,7 @@ int consistency_test(int clock_type, unsigned long seconds) ...@@ -130,7 +130,7 @@ int consistency_test(int clock_type, unsigned long seconds)
inconsistent = i; inconsistent = i;
/* display inconsistency */ /* display inconsistency */
if (inconsistent) { if (inconsistent >= 0) {
unsigned long long delta; unsigned long long delta;
printf("\%s\n", start_str); printf("\%s\n", start_str);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册