diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index cc63f30de166..6e06ebdbe0c7 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -54,7 +54,7 @@ !Ikernel/sched/cpupri.c !Ikernel/sched/fair.c !Iinclude/linux/completion.h -!Ekernel/timer.c +!Ekernel/time/timer.c Wait queues and Wake events !Iinclude/linux/wait.h @@ -63,7 +63,7 @@ High-resolution timers !Iinclude/linux/ktime.h !Iinclude/linux/hrtimer.h -!Ekernel/hrtimer.c +!Ekernel/time/hrtimer.c Workqueues and Kevents !Ekernel/workqueue.c diff --git a/Documentation/devicetree/bindings/timer/cirrus,clps711x-timer.txt b/Documentation/devicetree/bindings/timer/cirrus,clps711x-timer.txt new file mode 100644 index 000000000000..cd55b52548e4 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/cirrus,clps711x-timer.txt @@ -0,0 +1,29 @@ +* Cirrus Logic CLPS711X Timer Counter + +Required properties: +- compatible: Shall contain "cirrus,clps711x-timer". +- reg : Address and length of the register set. +- interrupts: The interrupt number of the timer. +- clocks : phandle of timer reference clock. + +Note: Each timer should have an alias correctly numbered in "aliases" node. + +Example: + aliases { + timer0 = &timer1; + timer1 = &timer2; + }; + + timer1: timer@80000300 { + compatible = "cirrus,ep7312-timer", "cirrus,clps711x-timer"; + reg = <0x80000300 0x4>; + interrupts = <8>; + clocks = <&clks 5>; + }; + + timer2: timer@80000340 { + compatible = "cirrus,ep7312-timer", "cirrus,clps711x-timer"; + reg = <0x80000340 0x4>; + interrupts = <9>; + clocks = <&clks 6>; + }; diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt new file mode 100644 index 000000000000..7c4408ff4b83 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt @@ -0,0 +1,17 @@ +Mediatek MT6577, MT6572 and MT6589 Timers +--------------------------------------- + +Required properties: +- compatible: Should be "mediatek,mt6577-timer" +- reg: Should contain location and length for timers register. +- clocks: Clocks driving the timer hardware. This list should include two + clocks. The order is system clock and as second clock the RTC clock. + +Examples: + + timer@10008000 { + compatible = "mediatek,mt6577-timer"; + reg = <0x10008000 0x80>; + interrupts = ; + clocks = <&system_clk>, <&rtc_clk>; + }; diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.txt b/Documentation/devicetree/bindings/timer/renesas,cmt.txt new file mode 100644 index 000000000000..a17418b0ece3 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/renesas,cmt.txt @@ -0,0 +1,47 @@ +* Renesas R-Car Compare Match Timer (CMT) + +The CMT is a multi-channel 16/32/48-bit timer/counter with configurable clock +inputs and programmable compare match. + +Channels share hardware resources but their counter and compare match value +are independent. A particular CMT instance can implement only a subset of the +channels supported by the CMT model. Channel indices represent the hardware +position of the channel in the CMT and don't match the channel numbers in the +datasheets. + +Required Properties: + + - compatible: must contain one of the following. + - "renesas,cmt-32" for the 32-bit CMT + (CMT0 on sh7372, sh73a0 and r8a7740) + - "renesas,cmt-32-fast" for the 32-bit CMT with fast clock support + (CMT[234] on sh7372, sh73a0 and r8a7740) + - "renesas,cmt-48" for the 48-bit CMT + (CMT1 on sh7372, sh73a0 and r8a7740) + - "renesas,cmt-48-gen2" for the second generation 48-bit CMT + (CMT[01] on r8a73a4, r8a7790 and r8a7791) + + - reg: base address and length of the registers block for the timer module. + - interrupts: interrupt-specifier for the timer, one per channel. + - clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. + - clock-names: must contain "fck" for the functional clock. + + - renesas,channels-mask: bitmask of the available channels. + + +Example: R8A7790 (R-Car H2) CMT0 node + + CMT0 on R8A7790 implements hardware channels 5 and 6 only and names + them channels 0 and 1 in the documentation. + + cmt0: timer@ffca0000 { + compatible = "renesas,cmt-48-gen2"; + reg = <0 0xffca0000 0 0x1004>; + interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>, + <0 142 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_CMT0>; + clock-names = "fck"; + + renesas,channels-mask = <0x60>; + }; diff --git a/Documentation/devicetree/bindings/timer/renesas,mtu2.txt b/Documentation/devicetree/bindings/timer/renesas,mtu2.txt new file mode 100644 index 000000000000..917453f826bc --- /dev/null +++ b/Documentation/devicetree/bindings/timer/renesas,mtu2.txt @@ -0,0 +1,39 @@ +* Renesas R-Car Multi-Function Timer Pulse Unit 2 (MTU2) + +The MTU2 is a multi-purpose, multi-channel timer/counter with configurable +clock inputs and programmable compare match. + +Channels share hardware resources but their counter and compare match value +are independent. The MTU2 hardware supports five channels indexed from 0 to 4. + +Required Properties: + + - compatible: must contain "renesas,mtu2" + + - reg: base address and length of the registers block for the timer module. + + - interrupts: interrupt specifiers for the timer, one for each entry in + interrupt-names. + - interrupt-names: must contain one entry named "tgi?a" for each enabled + channel, where "?" is the channel index expressed as one digit from "0" to + "4". + + - clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. + - clock-names: must contain "fck" for the functional clock. + + +Example: R7S72100 (RZ/A1H) MTU2 node + + mtu2: timer@fcff0000 { + compatible = "renesas,mtu2"; + reg = <0xfcff0000 0x400>; + interrupts = <0 139 IRQ_TYPE_LEVEL_HIGH>, + <0 146 IRQ_TYPE_LEVEL_HIGH>, + <0 150 IRQ_TYPE_LEVEL_HIGH>, + <0 154 IRQ_TYPE_LEVEL_HIGH>, + <0 159 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tgi0a", "tgi1a", "tgi2a", "tgi3a", "tgi4a"; + clocks = <&mstp3_clks R7S72100_CLK_MTU2>; + clock-names = "fck"; + }; diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.txt b/Documentation/devicetree/bindings/timer/renesas,tmu.txt new file mode 100644 index 000000000000..425d0c5f4aee --- /dev/null +++ b/Documentation/devicetree/bindings/timer/renesas,tmu.txt @@ -0,0 +1,39 @@ +* Renesas R-Car Timer Unit (TMU) + +The TMU is a 32-bit timer/counter with configurable clock inputs and +programmable compare match. + +Channels share hardware resources but their counter and compare match value +are independent. The TMU hardware supports up to three channels. + +Required Properties: + + - compatible: must contain "renesas,tmu" + + - reg: base address and length of the registers block for the timer module. + + - interrupts: interrupt-specifier for the timer, one per channel. + + - clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. + - clock-names: must contain "fck" for the functional clock. + +Optional Properties: + + - #renesas,channels: number of channels implemented by the timer, must be 2 + or 3 (if not specified the value defaults to 3). + + +Example: R8A7779 (R-Car H1) TMU0 node + + tmu0: timer@ffd80000 { + compatible = "renesas,tmu"; + reg = <0xffd80000 0x30>; + interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>, + <0 33 IRQ_TYPE_LEVEL_HIGH>, + <0 34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp0_clks R8A7779_CLK_TMU0>; + clock-names = "fck"; + + #renesas,channels = <3>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 46a311e728a8..dd5bce848cef 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -77,6 +77,7 @@ lsi LSI Corp. (LSI Logic) lltc Linear Technology Corporation marvell Marvell Technology Group Ltd. maxim Maxim Integrated Products +mediatek MediaTek Inc. micrel Micrel Inc. microchip Microchip Technology Inc. mosaixtech Mosaix Technologies, Inc. diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index ddc531a74d04..eb8a10e22f7c 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1743,6 +1743,25 @@ pair provide additional information particular to the objects they represent. While the first three lines are mandatory and always printed, the rest is optional and may be omitted if no marks created yet. + Timerfd files + ~~~~~~~~~~~~~ + + pos: 0 + flags: 02 + mnt_id: 9 + clockid: 0 + ticks: 0 + settime flags: 01 + it_value: (0, 49406829) + it_interval: (1, 0) + + where 'clockid' is the clock type and 'ticks' is the number of the timer expirations + that have occurred [see timerfd_create(2) for details]. 'settime flags' are + flags in octal form been used to setup the timer [see timerfd_settime(2) for + details]. 'it_value' is remaining time until the timer exiration. + 'it_interval' is the interval for the timer. Note the timer might be set up + with TIMER_ABSTIME option which will be shown in 'settime flags', but 'it_value' + still exhibits timer's remaining time. ------------------------------------------------------------------------------ Configuring procfs diff --git a/MAINTAINERS b/MAINTAINERS index c2066f4c3286..117945edf26c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4204,7 +4204,7 @@ L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Maintained F: Documentation/timers/ -F: kernel/hrtimer.c +F: kernel/time/hrtimer.c F: kernel/time/clockevents.c F: kernel/time/tick*.* F: kernel/time/timer_*.c @@ -7026,10 +7026,10 @@ POSIX CLOCKS and TIMERS M: Thomas Gleixner L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core -S: Supported +S: Maintained F: fs/timerfd.c F: include/linux/timer* -F: kernel/*timer* +F: kernel/time/*timer* POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS M: Dmitry Eremin-Solenikov diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 290f02ee0157..5f38033f7a9f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -65,7 +65,6 @@ config ARM select HAVE_UID16 select HAVE_VIRT_CPU_ACCOUNTING_GEN select IRQ_FORCED_THREADING - select KTIME_SCALAR select MODULES_USE_ELF_REL select NO_BOOTMEM select OLD_SIGACTION @@ -635,6 +634,7 @@ config ARCH_PXA select AUTO_ZRELADDR select CLKDEV_LOOKUP select CLKSRC_MMIO + select CLKSRC_OF select GENERIC_CLOCKEVENTS select GPIO_PXA select HAVE_IDE diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 648867a8caa8..2fe1824c6dcb 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -4,7 +4,7 @@ # Common support (must be linked before board specific support) obj-y += clock.o devices.o generic.o irq.o \ - time.o reset.o + reset.o obj-$(CONFIG_PM) += pm.o sleep.o standby.o # Generic drivers that other drivers may depend upon diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 42254175fcf4..6f38e1af45af 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -25,11 +25,13 @@ #include #include +#include #include #include #include #include "generic.h" +#include void clear_reset_status(unsigned int mask) { @@ -56,6 +58,15 @@ unsigned long get_clock_tick_rate(void) } EXPORT_SYMBOL(get_clock_tick_rate); +/* + * For non device-tree builds, keep legacy timer init + */ +void pxa_timer_init(void) +{ + pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x40a00000), + get_clock_tick_rate()); +} + /* * Get the clock frequency as reflected by CCCR and the turbo flag. * We assume these values have been applied via a fcs. diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c deleted file mode 100644 index fca174e3865d..000000000000 --- a/arch/arm/mach-pxa/time.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * arch/arm/mach-pxa/time.c - * - * PXA clocksource, clockevents, and OST interrupt handlers. - * Copyright (c) 2007 by Bill Gatliff . - * - * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001 - * by MontaVista Software, Inc. (Nico, your code rocks!) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * This is PXA's sched_clock implementation. This has a resolution - * of at least 308 ns and a maximum value of 208 days. - * - * The return value is guaranteed to be monotonic in that range as - * long as there is always less than 582 seconds between successive - * calls to sched_clock() which should always be the case in practice. - */ - -static u64 notrace pxa_read_sched_clock(void) -{ - return readl_relaxed(OSCR); -} - - -#define MIN_OSCR_DELTA 16 - -static irqreturn_t -pxa_ost0_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *c = dev_id; - - /* Disarm the compare/match, signal the event. */ - writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); - writel_relaxed(OSSR_M0, OSSR); - c->event_handler(c); - - return IRQ_HANDLED; -} - -static int -pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) -{ - unsigned long next, oscr; - - writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER); - next = readl_relaxed(OSCR) + delta; - writel_relaxed(next, OSMR0); - oscr = readl_relaxed(OSCR); - - return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; -} - -static void -pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) -{ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); - writel_relaxed(OSSR_M0, OSSR); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - /* initializing, released, or preparing for suspend */ - writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); - writel_relaxed(OSSR_M0, OSSR); - break; - - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - } -} - -#ifdef CONFIG_PM -static unsigned long osmr[4], oier, oscr; - -static void pxa_timer_suspend(struct clock_event_device *cedev) -{ - osmr[0] = readl_relaxed(OSMR0); - osmr[1] = readl_relaxed(OSMR1); - osmr[2] = readl_relaxed(OSMR2); - osmr[3] = readl_relaxed(OSMR3); - oier = readl_relaxed(OIER); - oscr = readl_relaxed(OSCR); -} - -static void pxa_timer_resume(struct clock_event_device *cedev) -{ - /* - * Ensure that we have at least MIN_OSCR_DELTA between match - * register 0 and the OSCR, to guarantee that we will receive - * the one-shot timer interrupt. We adjust OSMR0 in preference - * to OSCR to guarantee that OSCR is monotonically incrementing. - */ - if (osmr[0] - oscr < MIN_OSCR_DELTA) - osmr[0] += MIN_OSCR_DELTA; - - writel_relaxed(osmr[0], OSMR0); - writel_relaxed(osmr[1], OSMR1); - writel_relaxed(osmr[2], OSMR2); - writel_relaxed(osmr[3], OSMR3); - writel_relaxed(oier, OIER); - writel_relaxed(oscr, OSCR); -} -#else -#define pxa_timer_suspend NULL -#define pxa_timer_resume NULL -#endif - -static struct clock_event_device ckevt_pxa_osmr0 = { - .name = "osmr0", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = pxa_osmr0_set_next_event, - .set_mode = pxa_osmr0_set_mode, - .suspend = pxa_timer_suspend, - .resume = pxa_timer_resume, -}; - -static struct irqaction pxa_ost0_irq = { - .name = "ost0", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = pxa_ost0_interrupt, - .dev_id = &ckevt_pxa_osmr0, -}; - -void __init pxa_timer_init(void) -{ - unsigned long clock_tick_rate = get_clock_tick_rate(); - - writel_relaxed(0, OIER); - writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); - - sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate); - - ckevt_pxa_osmr0.cpumask = cpumask_of(0); - - setup_irq(IRQ_OST0, &pxa_ost0_irq); - - clocksource_mmio_init(OSCR, "oscr0", clock_tick_rate, 200, 32, - clocksource_mmio_readl_up); - clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate, - MIN_OSCR_DELTA * 2, 0x7fffffff); -} diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig index 0fd6138f6203..4dc89d1f9c48 100644 --- a/arch/hexagon/Kconfig +++ b/arch/hexagon/Kconfig @@ -23,7 +23,6 @@ config HEXAGON select GENERIC_IOMAP select GENERIC_SMP_IDLE_THREAD select STACKTRACE_SUPPORT - select KTIME_SCALAR select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS_BROADCAST select MODULES_USE_ELF_RELA diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index bb63499fc5d3..1afc7a686702 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -137,7 +137,6 @@ config S390 select HAVE_SYSCALL_TRACEPOINTS select HAVE_UID16 if 32BIT select HAVE_VIRT_CPU_ACCOUNTING - select KTIME_SCALAR if 32BIT select MODULES_USE_ELF_RELA select NO_BOOTMEM select OLD_SIGACTION diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c index 462dcd0c1700..ae70155c2f16 100644 --- a/arch/tile/kernel/time.c +++ b/arch/tile/kernel/time.c @@ -260,7 +260,6 @@ void update_vsyscall_tz(void) void update_vsyscall(struct timekeeper *tk) { - struct timespec wall_time = tk_xtime(tk); struct timespec *wtm = &tk->wall_to_monotonic; struct clocksource *clock = tk->clock; @@ -271,12 +270,12 @@ void update_vsyscall(struct timekeeper *tk) ++vdso_data->tb_update_count; smp_wmb(); vdso_data->xtime_tod_stamp = clock->cycle_last; - vdso_data->xtime_clock_sec = wall_time.tv_sec; - vdso_data->xtime_clock_nsec = wall_time.tv_nsec; + vdso_data->xtime_clock_sec = tk->xtime_sec; + vdso_data->xtime_clock_nsec = tk->xtime_nsec; vdso_data->wtom_clock_sec = wtm->tv_sec; vdso_data->wtom_clock_nsec = wtm->tv_nsec; - vdso_data->mult = clock->mult; - vdso_data->shift = clock->shift; + vdso_data->mult = tk->mult; + vdso_data->shift = tk->shift; smp_wmb(); ++vdso_data->tb_update_count; } diff --git a/arch/tile/kernel/vdso/vgettimeofday.c b/arch/tile/kernel/vdso/vgettimeofday.c index 51ec8e46f5f9..e933fb9fbf5c 100644 --- a/arch/tile/kernel/vdso/vgettimeofday.c +++ b/arch/tile/kernel/vdso/vgettimeofday.c @@ -83,10 +83,11 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) if (count & 1) continue; - cycles = (get_cycles() - vdso_data->xtime_tod_stamp); - ns = (cycles * vdso_data->mult) >> vdso_data->shift; sec = vdso_data->xtime_clock_sec; - ns += vdso_data->xtime_clock_nsec; + cycles = get_cycles() - vdso_data->xtime_tod_stamp; + ns = (cycles * vdso_data->mult) + vdso_data->xtime_clock_nsec; + ns >>= vdso_data->shift; + if (ns >= NSEC_PER_SEC) { ns -= NSEC_PER_SEC; sec += 1; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d24887b645dc..5b2acad59622 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -111,7 +111,6 @@ config X86 select ARCH_CLOCKSOURCE_DATA select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) select GENERIC_TIME_VSYSCALL - select KTIME_SCALAR if X86_32 select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select HAVE_CONTEXT_TRACKING if X86_64 diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 065131cbfcc0..cfd6519df661 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -1,3 +1,5 @@ +menu "Clock Source drivers" + config CLKSRC_OF bool @@ -125,6 +127,7 @@ config CLKSRC_METAG_GENERIC config CLKSRC_EXYNOS_MCT def_bool y if ARCH_EXYNOS + depends on !ARM64 help Support for Multi Core Timer controller on Exynos SoCs. @@ -149,6 +152,11 @@ config VF_PIT_TIMER config SYS_SUPPORTS_SH_CMT bool +config MTK_TIMER + select CLKSRC_OF + select CLKSRC_MMIO + bool + config SYS_SUPPORTS_SH_MTU2 bool @@ -173,7 +181,7 @@ config SH_TIMER_MTU2 default SYS_SUPPORTS_SH_MTU2 help This enables build of a clockevent driver for the Multi-Function - Timer Pulse Unit 2 (TMU2) hardware available on SoCs from Renesas. + Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas. This hardware comes with 16 bit-timer registers. config SH_TIMER_TMU @@ -187,7 +195,7 @@ config SH_TIMER_TMU config EM_TIMER_STI bool "Renesas STI timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS + depends on GENERIC_CLOCKEVENTS && HAS_IOMEM default SYS_SUPPORTS_EM_STI help This enables build of a clocksource and clockevent driver for @@ -207,3 +215,5 @@ config CLKSRC_VERSATILE counter available in the "System Registers" block of ARM Versatile, RealView and Versatile Express reference platforms. + +endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 800b1303c236..7fd9fd1dff42 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -16,9 +16,11 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o +obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o +obj-$(CONFIG_ARCH_PXA) += pxa_timer.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o @@ -34,6 +36,7 @@ obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o +obj-$(CONFIG_MTK_TIMER) += mtk_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c new file mode 100644 index 000000000000..d83ec1f2fddc --- /dev/null +++ b/drivers/clocksource/clps711x-timer.c @@ -0,0 +1,131 @@ +/* + * Cirrus Logic CLPS711X clocksource driver + * + * Copyright (C) 2014 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + CLPS711X_CLKSRC_CLOCKSOURCE, + CLPS711X_CLKSRC_CLOCKEVENT, +}; + +static void __iomem *tcd; + +static u64 notrace clps711x_sched_clock_read(void) +{ + return ~readw(tcd); +} + +static int __init _clps711x_clksrc_init(struct clk *clock, void __iomem *base) +{ + unsigned long rate; + + if (!base) + return -ENOMEM; + if (IS_ERR(clock)) + return PTR_ERR(clock); + + rate = clk_get_rate(clock); + + tcd = base; + + clocksource_mmio_init(tcd, "clps711x-clocksource", rate, 300, 16, + clocksource_mmio_readw_down); + + sched_clock_register(clps711x_sched_clock_read, 16, rate); + + return 0; +} + +static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void clps711x_clockevent_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ +} + +static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, + unsigned int irq) +{ + struct clock_event_device *clkevt; + unsigned long rate; + + if (!irq) + return -EINVAL; + if (!base) + return -ENOMEM; + if (IS_ERR(clock)) + return PTR_ERR(clock); + + clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); + if (!clkevt) + return -ENOMEM; + + rate = clk_get_rate(clock); + + /* Set Timer prescaler */ + writew(DIV_ROUND_CLOSEST(rate, HZ), base); + + clkevt->name = "clps711x-clockevent"; + clkevt->rating = 300; + clkevt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_C3STOP; + clkevt->set_mode = clps711x_clockevent_set_mode; + clkevt->cpumask = cpumask_of(0); + clockevents_config_and_register(clkevt, HZ, 0, 0); + + return request_irq(irq, clps711x_timer_interrupt, IRQF_TIMER, + "clps711x-timer", clkevt); +} + +void __init clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base, + unsigned int irq) +{ + struct clk *tc1 = clk_get_sys("clps711x-timer.0", NULL); + struct clk *tc2 = clk_get_sys("clps711x-timer.1", NULL); + + BUG_ON(_clps711x_clksrc_init(tc1, tc1_base)); + BUG_ON(_clps711x_clkevt_init(tc2, tc2_base, irq)); +} + +#ifdef CONFIG_CLKSRC_OF +static void __init clps711x_timer_init(struct device_node *np) +{ + unsigned int irq = irq_of_parse_and_map(np, 0); + struct clk *clock = of_clk_get(np, 0); + void __iomem *base = of_iomap(np, 0); + + switch (of_alias_get_id(np, "timer")) { + case CLPS711X_CLKSRC_CLOCKSOURCE: + BUG_ON(_clps711x_clksrc_init(clock, base)); + break; + case CLPS711X_CLKSRC_CLOCKEVENT: + BUG_ON(_clps711x_clkevt_init(clock, base, irq)); + break; + default: + break; + } +} +CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); +#endif diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index ab51bf20a3ed..9403061a2acc 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -94,7 +94,7 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset) u32 mask; u32 i; - __raw_writel(value, reg_base + offset); + writel_relaxed(value, reg_base + offset); if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) { stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; @@ -144,8 +144,8 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset) /* Wait maximum 1 ms until written values are applied */ for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++) - if (__raw_readl(reg_base + stat_addr) & mask) { - __raw_writel(mask, reg_base + stat_addr); + if (readl_relaxed(reg_base + stat_addr) & mask) { + writel_relaxed(mask, reg_base + stat_addr); return; } @@ -157,28 +157,51 @@ static void exynos4_mct_frc_start(void) { u32 reg; - reg = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); + reg = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); reg |= MCT_G_TCON_START; exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON); } -static cycle_t notrace _exynos4_frc_read(void) +/** + * exynos4_read_count_64 - Read all 64-bits of the global counter + * + * This will read all 64-bits of the global counter taking care to make sure + * that the upper and lower half match. Note that reading the MCT can be quite + * slow (hundreds of nanoseconds) so you should use the 32-bit (lower half + * only) version when possible. + * + * Returns the number of cycles in the global counter. + */ +static u64 exynos4_read_count_64(void) { unsigned int lo, hi; - u32 hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); + u32 hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U); do { hi = hi2; - lo = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_L); - hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); + lo = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L); + hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U); } while (hi != hi2); return ((cycle_t)hi << 32) | lo; } +/** + * exynos4_read_count_32 - Read the lower 32-bits of the global counter + * + * This will read just the lower 32-bits of the global counter. This is marked + * as notrace so it can be used by the scheduler clock. + * + * Returns the number of cycles in the global counter (lower 32 bits). + */ +static u32 notrace exynos4_read_count_32(void) +{ + return readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L); +} + static cycle_t exynos4_frc_read(struct clocksource *cs) { - return _exynos4_frc_read(); + return exynos4_read_count_32(); } static void exynos4_frc_resume(struct clocksource *cs) @@ -190,21 +213,23 @@ struct clocksource mct_frc = { .name = "mct-frc", .rating = 400, .read = exynos4_frc_read, - .mask = CLOCKSOURCE_MASK(64), + .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, .resume = exynos4_frc_resume, }; static u64 notrace exynos4_read_sched_clock(void) { - return _exynos4_frc_read(); + return exynos4_read_count_32(); } static struct delay_timer exynos4_delay_timer; static cycles_t exynos4_read_current_timer(void) { - return _exynos4_frc_read(); + BUILD_BUG_ON_MSG(sizeof(cycles_t) != sizeof(u32), + "cycles_t needs to move to 32-bit for ARM64 usage"); + return exynos4_read_count_32(); } static void __init exynos4_clocksource_init(void) @@ -218,14 +243,14 @@ static void __init exynos4_clocksource_init(void) if (clocksource_register_hz(&mct_frc, clk_rate)) panic("%s: can't register clocksource\n", mct_frc.name); - sched_clock_register(exynos4_read_sched_clock, 64, clk_rate); + sched_clock_register(exynos4_read_sched_clock, 32, clk_rate); } static void exynos4_mct_comp0_stop(void) { unsigned int tcon; - tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); + tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC); exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON); @@ -238,14 +263,14 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode, unsigned int tcon; cycle_t comp_cycle; - tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); + tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); if (mode == CLOCK_EVT_MODE_PERIODIC) { tcon |= MCT_G_TCON_COMP0_AUTO_INC; exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR); } - comp_cycle = exynos4_frc_read(&mct_frc) + cycles; + comp_cycle = exynos4_read_count_64() + cycles; exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L); exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U); @@ -327,7 +352,7 @@ static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt) unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START; unsigned long offset = mevt->base + MCT_L_TCON_OFFSET; - tmp = __raw_readl(reg_base + offset); + tmp = readl_relaxed(reg_base + offset); if (tmp & mask) { tmp &= ~mask; exynos4_mct_write(tmp, offset); @@ -349,7 +374,7 @@ static void exynos4_mct_tick_start(unsigned long cycles, /* enable MCT tick interrupt */ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET); - tmp = __raw_readl(reg_base + mevt->base + MCT_L_TCON_OFFSET); + tmp = readl_relaxed(reg_base + mevt->base + MCT_L_TCON_OFFSET); tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START | MCT_L_TCON_INTERVAL_MODE; exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); @@ -401,7 +426,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) exynos4_mct_tick_stop(mevt); /* Clear the MCT tick interrupt */ - if (__raw_readl(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { + if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); return 1; } else { diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c new file mode 100644 index 000000000000..32a3d25795d3 --- /dev/null +++ b/drivers/clocksource/mtk_timer.c @@ -0,0 +1,261 @@ +/* + * Mediatek SoCs General-Purpose Timer handling. + * + * Copyright (C) 2014 Matthias Brugger + * + * Matthias Brugger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPT_IRQ_EN_REG 0x00 +#define GPT_IRQ_ENABLE(val) BIT((val) - 1) +#define GPT_IRQ_ACK_REG 0x08 +#define GPT_IRQ_ACK(val) BIT((val) - 1) + +#define TIMER_CTRL_REG(val) (0x10 * (val)) +#define TIMER_CTRL_OP(val) (((val) & 0x3) << 4) +#define TIMER_CTRL_OP_ONESHOT (0) +#define TIMER_CTRL_OP_REPEAT (1) +#define TIMER_CTRL_OP_FREERUN (3) +#define TIMER_CTRL_CLEAR (2) +#define TIMER_CTRL_ENABLE (1) +#define TIMER_CTRL_DISABLE (0) + +#define TIMER_CLK_REG(val) (0x04 + (0x10 * (val))) +#define TIMER_CLK_SRC(val) (((val) & 0x1) << 4) +#define TIMER_CLK_SRC_SYS13M (0) +#define TIMER_CLK_SRC_RTC32K (1) +#define TIMER_CLK_DIV1 (0x0) +#define TIMER_CLK_DIV2 (0x1) + +#define TIMER_CNT_REG(val) (0x08 + (0x10 * (val))) +#define TIMER_CMP_REG(val) (0x0C + (0x10 * (val))) + +#define GPT_CLK_EVT 1 +#define GPT_CLK_SRC 2 + +struct mtk_clock_event_device { + void __iomem *gpt_base; + u32 ticks_per_jiffy; + struct clock_event_device dev; +}; + +static inline struct mtk_clock_event_device *to_mtk_clk( + struct clock_event_device *c) +{ + return container_of(c, struct mtk_clock_event_device, dev); +} + +static void mtk_clkevt_time_stop(struct mtk_clock_event_device *evt, u8 timer) +{ + u32 val; + + val = readl(evt->gpt_base + TIMER_CTRL_REG(timer)); + writel(val & ~TIMER_CTRL_ENABLE, evt->gpt_base + + TIMER_CTRL_REG(timer)); +} + +static void mtk_clkevt_time_setup(struct mtk_clock_event_device *evt, + unsigned long delay, u8 timer) +{ + writel(delay, evt->gpt_base + TIMER_CMP_REG(timer)); +} + +static void mtk_clkevt_time_start(struct mtk_clock_event_device *evt, + bool periodic, u8 timer) +{ + u32 val; + + /* Acknowledge interrupt */ + writel(GPT_IRQ_ACK(timer), evt->gpt_base + GPT_IRQ_ACK_REG); + + val = readl(evt->gpt_base + TIMER_CTRL_REG(timer)); + + /* Clear 2 bit timer operation mode field */ + val &= ~TIMER_CTRL_OP(0x3); + + if (periodic) + val |= TIMER_CTRL_OP(TIMER_CTRL_OP_REPEAT); + else + val |= TIMER_CTRL_OP(TIMER_CTRL_OP_ONESHOT); + + writel(val | TIMER_CTRL_ENABLE | TIMER_CTRL_CLEAR, + evt->gpt_base + TIMER_CTRL_REG(timer)); +} + +static void mtk_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + struct mtk_clock_event_device *evt = to_mtk_clk(clk); + + mtk_clkevt_time_stop(evt, GPT_CLK_EVT); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT); + mtk_clkevt_time_start(evt, true, GPT_CLK_EVT); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Timer is enabled in set_next_event */ + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + /* No more interrupts will occur as source is disabled */ + break; + } +} + +static int mtk_clkevt_next_event(unsigned long event, + struct clock_event_device *clk) +{ + struct mtk_clock_event_device *evt = to_mtk_clk(clk); + + mtk_clkevt_time_stop(evt, GPT_CLK_EVT); + mtk_clkevt_time_setup(evt, event, GPT_CLK_EVT); + mtk_clkevt_time_start(evt, false, GPT_CLK_EVT); + + return 0; +} + +static irqreturn_t mtk_timer_interrupt(int irq, void *dev_id) +{ + struct mtk_clock_event_device *evt = dev_id; + + /* Acknowledge timer0 irq */ + writel(GPT_IRQ_ACK(GPT_CLK_EVT), evt->gpt_base + GPT_IRQ_ACK_REG); + evt->dev.event_handler(&evt->dev); + + return IRQ_HANDLED; +} + +static void mtk_timer_global_reset(struct mtk_clock_event_device *evt) +{ + /* Disable all interrupts */ + writel(0x0, evt->gpt_base + GPT_IRQ_EN_REG); + /* Acknowledge all interrupts */ + writel(0x3f, evt->gpt_base + GPT_IRQ_ACK_REG); +} + +static void +mtk_timer_setup(struct mtk_clock_event_device *evt, u8 timer, u8 option) +{ + writel(TIMER_CTRL_CLEAR | TIMER_CTRL_DISABLE, + evt->gpt_base + TIMER_CTRL_REG(timer)); + + writel(TIMER_CLK_SRC(TIMER_CLK_SRC_SYS13M) | TIMER_CLK_DIV1, + evt->gpt_base + TIMER_CLK_REG(timer)); + + writel(0x0, evt->gpt_base + TIMER_CMP_REG(timer)); + + writel(TIMER_CTRL_OP(option) | TIMER_CTRL_ENABLE, + evt->gpt_base + TIMER_CTRL_REG(timer)); +} + +static void mtk_timer_enable_irq(struct mtk_clock_event_device *evt, u8 timer) +{ + u32 val; + + val = readl(evt->gpt_base + GPT_IRQ_EN_REG); + writel(val | GPT_IRQ_ENABLE(timer), + evt->gpt_base + GPT_IRQ_EN_REG); +} + +static void __init mtk_timer_init(struct device_node *node) +{ + struct mtk_clock_event_device *evt; + struct resource res; + unsigned long rate = 0; + struct clk *clk; + + evt = kzalloc(sizeof(*evt), GFP_KERNEL); + if (!evt) { + pr_warn("Can't allocate mtk clock event driver struct"); + return; + } + + evt->dev.name = "mtk_tick"; + evt->dev.rating = 300; + evt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + evt->dev.set_mode = mtk_clkevt_mode; + evt->dev.set_next_event = mtk_clkevt_next_event; + evt->dev.cpumask = cpu_possible_mask; + + evt->gpt_base = of_io_request_and_map(node, 0, "mtk-timer"); + if (IS_ERR(evt->gpt_base)) { + pr_warn("Can't get resource\n"); + return; + } + + evt->dev.irq = irq_of_parse_and_map(node, 0); + if (evt->dev.irq <= 0) { + pr_warn("Can't parse IRQ"); + goto err_mem; + } + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_warn("Can't get timer clock"); + goto err_irq; + } + + if (clk_prepare_enable(clk)) { + pr_warn("Can't prepare clock"); + goto err_clk_put; + } + rate = clk_get_rate(clk); + + if (request_irq(evt->dev.irq, mtk_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) { + pr_warn("failed to setup irq %d\n", evt->dev.irq); + goto err_clk_disable; + } + + evt->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); + + mtk_timer_global_reset(evt); + + /* Configure clock source */ + mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN); + clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC), + node->name, rate, 300, 32, clocksource_mmio_readl_up); + + /* Configure clock event */ + mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT); + mtk_timer_enable_irq(evt, GPT_CLK_EVT); + + clockevents_config_and_register(&evt->dev, rate, 0x3, + 0xffffffff); + return; + +err_clk_disable: + clk_disable_unprepare(clk); +err_clk_put: + clk_put(clk); +err_irq: + irq_dispose_mapping(evt->dev.irq); +err_mem: + iounmap(evt->gpt_base); + of_address_to_resource(node, 0, &res); + release_mem_region(res.start, resource_size(&res)); +} +CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c new file mode 100644 index 000000000000..941f3f344e08 --- /dev/null +++ b/drivers/clocksource/pxa_timer.c @@ -0,0 +1,227 @@ +/* + * arch/arm/mach-pxa/time.c + * + * PXA clocksource, clockevents, and OST interrupt handlers. + * Copyright (c) 2007 by Bill Gatliff . + * + * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001 + * by MontaVista Software, Inc. (Nico, your code rocks!) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define OSMR0 0x00 /* OS Timer 0 Match Register */ +#define OSMR1 0x04 /* OS Timer 1 Match Register */ +#define OSMR2 0x08 /* OS Timer 2 Match Register */ +#define OSMR3 0x0C /* OS Timer 3 Match Register */ + +#define OSCR 0x10 /* OS Timer Counter Register */ +#define OSSR 0x14 /* OS Timer Status Register */ +#define OWER 0x18 /* OS Timer Watchdog Enable Register */ +#define OIER 0x1C /* OS Timer Interrupt Enable Register */ + +#define OSSR_M3 (1 << 3) /* Match status channel 3 */ +#define OSSR_M2 (1 << 2) /* Match status channel 2 */ +#define OSSR_M1 (1 << 1) /* Match status channel 1 */ +#define OSSR_M0 (1 << 0) /* Match status channel 0 */ + +#define OIER_E0 (1 << 0) /* Interrupt enable channel 0 */ + +/* + * This is PXA's sched_clock implementation. This has a resolution + * of at least 308 ns and a maximum value of 208 days. + * + * The return value is guaranteed to be monotonic in that range as + * long as there is always less than 582 seconds between successive + * calls to sched_clock() which should always be the case in practice. + */ + +#define timer_readl(reg) readl_relaxed(timer_base + (reg)) +#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg)) + +static void __iomem *timer_base; + +static u64 notrace pxa_read_sched_clock(void) +{ + return timer_readl(OSCR); +} + + +#define MIN_OSCR_DELTA 16 + +static irqreturn_t +pxa_ost0_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *c = dev_id; + + /* Disarm the compare/match, signal the event. */ + timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); + timer_writel(OSSR_M0, OSSR); + c->event_handler(c); + + return IRQ_HANDLED; +} + +static int +pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) +{ + unsigned long next, oscr; + + timer_writel(timer_readl(OIER) | OIER_E0, OIER); + next = timer_readl(OSCR) + delta; + timer_writel(next, OSMR0); + oscr = timer_readl(OSCR); + + return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; +} + +static void +pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) +{ + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); + timer_writel(OSSR_M0, OSSR); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + /* initializing, released, or preparing for suspend */ + timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); + timer_writel(OSSR_M0, OSSR); + break; + + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_PERIODIC: + break; + } +} + +#ifdef CONFIG_PM +static unsigned long osmr[4], oier, oscr; + +static void pxa_timer_suspend(struct clock_event_device *cedev) +{ + osmr[0] = timer_readl(OSMR0); + osmr[1] = timer_readl(OSMR1); + osmr[2] = timer_readl(OSMR2); + osmr[3] = timer_readl(OSMR3); + oier = timer_readl(OIER); + oscr = timer_readl(OSCR); +} + +static void pxa_timer_resume(struct clock_event_device *cedev) +{ + /* + * Ensure that we have at least MIN_OSCR_DELTA between match + * register 0 and the OSCR, to guarantee that we will receive + * the one-shot timer interrupt. We adjust OSMR0 in preference + * to OSCR to guarantee that OSCR is monotonically incrementing. + */ + if (osmr[0] - oscr < MIN_OSCR_DELTA) + osmr[0] += MIN_OSCR_DELTA; + + timer_writel(osmr[0], OSMR0); + timer_writel(osmr[1], OSMR1); + timer_writel(osmr[2], OSMR2); + timer_writel(osmr[3], OSMR3); + timer_writel(oier, OIER); + timer_writel(oscr, OSCR); +} +#else +#define pxa_timer_suspend NULL +#define pxa_timer_resume NULL +#endif + +static struct clock_event_device ckevt_pxa_osmr0 = { + .name = "osmr0", + .features = CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = pxa_osmr0_set_next_event, + .set_mode = pxa_osmr0_set_mode, + .suspend = pxa_timer_suspend, + .resume = pxa_timer_resume, +}; + +static struct irqaction pxa_ost0_irq = { + .name = "ost0", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = pxa_ost0_interrupt, + .dev_id = &ckevt_pxa_osmr0, +}; + +static void pxa_timer_common_init(int irq, unsigned long clock_tick_rate) +{ + timer_writel(0, OIER); + timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); + + sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate); + + ckevt_pxa_osmr0.cpumask = cpumask_of(0); + + setup_irq(irq, &pxa_ost0_irq); + + clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200, + 32, clocksource_mmio_readl_up); + clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate, + MIN_OSCR_DELTA * 2, 0x7fffffff); +} + +static void __init pxa_timer_dt_init(struct device_node *np) +{ + struct clk *clk; + int irq; + + /* timer registers are shared with watchdog timer */ + timer_base = of_iomap(np, 0); + if (!timer_base) + panic("%s: unable to map resource\n", np->name); + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_crit("%s: unable to get clk\n", np->name); + return; + } + clk_prepare_enable(clk); + + /* we are only interested in OS-timer0 irq */ + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + pr_crit("%s: unable to parse OS-timer0 irq\n", np->name); + return; + } + + pxa_timer_common_init(irq, clk_get_rate(clk)); +} +CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); + +/* + * Legacy timer init for non device-tree boards. + */ +void __init pxa_timer_nodt_init(int irq, void __iomem *base, + unsigned long clock_tick_rate) +{ + struct clk *clk; + + timer_base = base; + clk = clk_get(NULL, "OSTIMER0"); + if (clk && !IS_ERR(clk)) + clk_prepare_enable(clk); + else + pr_crit("%s: unable to get clk\n", __func__); + + pxa_timer_common_init(irq, clock_tick_rate); +} diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index dfa780396b91..2bd13b53b727 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -114,14 +115,15 @@ struct sh_cmt_device { struct platform_device *pdev; const struct sh_cmt_info *info; - bool legacy; - void __iomem *mapbase_ch; void __iomem *mapbase; struct clk *clk; + raw_spinlock_t lock; /* Protect the shared start/stop register */ + struct sh_cmt_channel *channels; unsigned int num_channels; + unsigned int hw_channels; bool has_clockevent; bool has_clocksource; @@ -301,14 +303,12 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, return v2; } -static DEFINE_RAW_SPINLOCK(sh_cmt_lock); - static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) { unsigned long flags, value; /* start stop register shared by multiple timer channels */ - raw_spin_lock_irqsave(&sh_cmt_lock, flags); + raw_spin_lock_irqsave(&ch->cmt->lock, flags); value = sh_cmt_read_cmstr(ch); if (start) @@ -317,7 +317,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) value &= ~(1 << ch->timer_bit); sh_cmt_write_cmstr(ch, value); - raw_spin_unlock_irqrestore(&sh_cmt_lock, flags); + raw_spin_unlock_irqrestore(&ch->cmt->lock, flags); } static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate) @@ -792,7 +792,7 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch, int irq; int ret; - irq = platform_get_irq(ch->cmt->pdev, ch->cmt->legacy ? 0 : ch->index); + irq = platform_get_irq(ch->cmt->pdev, ch->index); if (irq < 0) { dev_err(&ch->cmt->pdev->dev, "ch%u: failed to get irq\n", ch->index); @@ -863,33 +863,26 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, * Compute the address of the channel control register block. For the * timers with a per-channel start/stop register, compute its address * as well. - * - * For legacy configuration the address has been mapped explicitly. */ - if (cmt->legacy) { - ch->ioctrl = cmt->mapbase_ch; - } else { - switch (cmt->info->model) { - case SH_CMT_16BIT: - ch->ioctrl = cmt->mapbase + 2 + ch->hwidx * 6; - break; - case SH_CMT_32BIT: - case SH_CMT_48BIT: - ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10; - break; - case SH_CMT_32BIT_FAST: - /* - * The 32-bit "fast" timer has a single channel at hwidx - * 5 but is located at offset 0x40 instead of 0x60 for - * some reason. - */ - ch->ioctrl = cmt->mapbase + 0x40; - break; - case SH_CMT_48BIT_GEN2: - ch->iostart = cmt->mapbase + ch->hwidx * 0x100; - ch->ioctrl = ch->iostart + 0x10; - break; - } + switch (cmt->info->model) { + case SH_CMT_16BIT: + ch->ioctrl = cmt->mapbase + 2 + ch->hwidx * 6; + break; + case SH_CMT_32BIT: + case SH_CMT_48BIT: + ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10; + break; + case SH_CMT_32BIT_FAST: + /* + * The 32-bit "fast" timer has a single channel at hwidx 5 but + * is located at offset 0x40 instead of 0x60 for some reason. + */ + ch->ioctrl = cmt->mapbase + 0x40; + break; + case SH_CMT_48BIT_GEN2: + ch->iostart = cmt->mapbase + ch->hwidx * 0x100; + ch->ioctrl = ch->iostart + 0x10; + break; } if (cmt->info->width == (sizeof(ch->max_match_value) * 8)) @@ -900,12 +893,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, ch->match_value = ch->max_match_value; raw_spin_lock_init(&ch->lock); - if (cmt->legacy) { - ch->timer_bit = ch->hwidx; - } else { - ch->timer_bit = cmt->info->model == SH_CMT_48BIT_GEN2 - ? 0 : ch->hwidx; - } + ch->timer_bit = cmt->info->model == SH_CMT_48BIT_GEN2 ? 0 : ch->hwidx; ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev), clockevent, clocksource); @@ -938,75 +926,65 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt) return 0; } -static int sh_cmt_map_memory_legacy(struct sh_cmt_device *cmt) +static const struct platform_device_id sh_cmt_id_table[] = { + { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, + { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, + { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, + { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, + { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, + { } +}; +MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); + +static const struct of_device_id sh_cmt_of_table[] __maybe_unused = { + { .compatible = "renesas,cmt-32", .data = &sh_cmt_info[SH_CMT_32BIT] }, + { .compatible = "renesas,cmt-32-fast", .data = &sh_cmt_info[SH_CMT_32BIT_FAST] }, + { .compatible = "renesas,cmt-48", .data = &sh_cmt_info[SH_CMT_48BIT] }, + { .compatible = "renesas,cmt-48-gen2", .data = &sh_cmt_info[SH_CMT_48BIT_GEN2] }, + { } +}; +MODULE_DEVICE_TABLE(of, sh_cmt_of_table); + +static int sh_cmt_parse_dt(struct sh_cmt_device *cmt) { - struct sh_timer_config *cfg = cmt->pdev->dev.platform_data; - struct resource *res, *res2; + struct device_node *np = cmt->pdev->dev.of_node; - /* map memory, let mapbase_ch point to our channel */ - res = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&cmt->pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; - } - - cmt->mapbase_ch = ioremap_nocache(res->start, resource_size(res)); - if (cmt->mapbase_ch == NULL) { - dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n"); - return -ENXIO; - } - - /* optional resource for the shared timer start/stop register */ - res2 = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 1); - - /* map second resource for CMSTR */ - cmt->mapbase = ioremap_nocache(res2 ? res2->start : - res->start - cfg->channel_offset, - res2 ? resource_size(res2) : 2); - if (cmt->mapbase == NULL) { - dev_err(&cmt->pdev->dev, "failed to remap I/O second memory\n"); - iounmap(cmt->mapbase_ch); - return -ENXIO; - } - - /* identify the model based on the resources */ - if (resource_size(res) == 6) - cmt->info = &sh_cmt_info[SH_CMT_16BIT]; - else if (res2 && (resource_size(res2) == 4)) - cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2]; - else - cmt->info = &sh_cmt_info[SH_CMT_32BIT]; - - return 0; -} - -static void sh_cmt_unmap_memory(struct sh_cmt_device *cmt) -{ - iounmap(cmt->mapbase); - if (cmt->mapbase_ch) - iounmap(cmt->mapbase_ch); + return of_property_read_u32(np, "renesas,channels-mask", + &cmt->hw_channels); } static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) { - struct sh_timer_config *cfg = pdev->dev.platform_data; - const struct platform_device_id *id = pdev->id_entry; - unsigned int hw_channels; + unsigned int mask; + unsigned int i; int ret; memset(cmt, 0, sizeof(*cmt)); cmt->pdev = pdev; + raw_spin_lock_init(&cmt->lock); - if (!cfg) { + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + const struct of_device_id *id; + + id = of_match_node(sh_cmt_of_table, pdev->dev.of_node); + cmt->info = id->data; + + ret = sh_cmt_parse_dt(cmt); + if (ret < 0) + return ret; + } else if (pdev->dev.platform_data) { + struct sh_timer_config *cfg = pdev->dev.platform_data; + const struct platform_device_id *id = pdev->id_entry; + + cmt->info = (const struct sh_cmt_info *)id->driver_data; + cmt->hw_channels = cfg->channels_mask; + } else { dev_err(&cmt->pdev->dev, "missing platform data\n"); return -ENXIO; } - cmt->info = (const struct sh_cmt_info *)id->driver_data; - cmt->legacy = cmt->info ? false : true; - /* Get hold of clock. */ - cmt->clk = clk_get(&cmt->pdev->dev, cmt->legacy ? "cmt_fck" : "fck"); + cmt->clk = clk_get(&cmt->pdev->dev, "fck"); if (IS_ERR(cmt->clk)) { dev_err(&cmt->pdev->dev, "cannot get clock\n"); return PTR_ERR(cmt->clk); @@ -1016,28 +994,13 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) if (ret < 0) goto err_clk_put; - /* - * Map the memory resource(s). We need to support both the legacy - * platform device configuration (with one device per channel) and the - * new version (with multiple channels per device). - */ - if (cmt->legacy) - ret = sh_cmt_map_memory_legacy(cmt); - else - ret = sh_cmt_map_memory(cmt); - + /* Map the memory resource(s). */ + ret = sh_cmt_map_memory(cmt); if (ret < 0) goto err_clk_unprepare; /* Allocate and setup the channels. */ - if (cmt->legacy) { - cmt->num_channels = 1; - hw_channels = 0; - } else { - cmt->num_channels = hweight8(cfg->channels_mask); - hw_channels = cfg->channels_mask; - } - + cmt->num_channels = hweight8(cmt->hw_channels); cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels), GFP_KERNEL); if (cmt->channels == NULL) { @@ -1045,35 +1008,21 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) goto err_unmap; } - if (cmt->legacy) { - ret = sh_cmt_setup_channel(&cmt->channels[0], - cfg->timer_bit, cfg->timer_bit, - cfg->clockevent_rating != 0, - cfg->clocksource_rating != 0, cmt); + /* + * Use the first channel as a clock event device and the second channel + * as a clock source. If only one channel is available use it for both. + */ + for (i = 0, mask = cmt->hw_channels; i < cmt->num_channels; ++i) { + unsigned int hwidx = ffs(mask) - 1; + bool clocksource = i == 1 || cmt->num_channels == 1; + bool clockevent = i == 0; + + ret = sh_cmt_setup_channel(&cmt->channels[i], i, hwidx, + clockevent, clocksource, cmt); if (ret < 0) goto err_unmap; - } else { - unsigned int mask = hw_channels; - unsigned int i; - /* - * Use the first channel as a clock event device and the second - * channel as a clock source. If only one channel is available - * use it for both. - */ - for (i = 0; i < cmt->num_channels; ++i) { - unsigned int hwidx = ffs(mask) - 1; - bool clocksource = i == 1 || cmt->num_channels == 1; - bool clockevent = i == 0; - - ret = sh_cmt_setup_channel(&cmt->channels[i], i, hwidx, - clockevent, clocksource, - cmt); - if (ret < 0) - goto err_unmap; - - mask &= ~(1 << hwidx); - } + mask &= ~(1 << hwidx); } platform_set_drvdata(pdev, cmt); @@ -1082,7 +1031,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) err_unmap: kfree(cmt->channels); - sh_cmt_unmap_memory(cmt); + iounmap(cmt->mapbase); err_clk_unprepare: clk_unprepare(cmt->clk); err_clk_put: @@ -1132,22 +1081,12 @@ static int sh_cmt_remove(struct platform_device *pdev) return -EBUSY; /* cannot unregister clockevent and clocksource */ } -static const struct platform_device_id sh_cmt_id_table[] = { - { "sh_cmt", 0 }, - { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, - { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, - { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, - { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, - { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, - { } -}; -MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); - static struct platform_driver sh_cmt_device_driver = { .probe = sh_cmt_probe, .remove = sh_cmt_remove, .driver = { .name = "sh_cmt", + .of_match_table = of_match_ptr(sh_cmt_of_table), }, .id_table = sh_cmt_id_table, }; diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 188d4e092efc..3d88698cf2b8 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ struct sh_mtu2_channel { unsigned int index; void __iomem *base; - int irq; struct clock_event_device ced; }; @@ -48,15 +48,14 @@ struct sh_mtu2_device { void __iomem *mapbase; struct clk *clk; + raw_spinlock_t lock; /* Protect the shared registers */ + struct sh_mtu2_channel *channels; unsigned int num_channels; - bool legacy; bool has_clockevent; }; -static DEFINE_RAW_SPINLOCK(sh_mtu2_lock); - #define TSTR -1 /* shared register */ #define TCR 0 /* channel register */ #define TMDR 1 /* channel register */ @@ -162,12 +161,8 @@ static inline unsigned long sh_mtu2_read(struct sh_mtu2_channel *ch, int reg_nr) { unsigned long offs; - if (reg_nr == TSTR) { - if (ch->mtu->legacy) - return ioread8(ch->mtu->mapbase); - else - return ioread8(ch->mtu->mapbase + 0x280); - } + if (reg_nr == TSTR) + return ioread8(ch->mtu->mapbase + 0x280); offs = mtu2_reg_offs[reg_nr]; @@ -182,12 +177,8 @@ static inline void sh_mtu2_write(struct sh_mtu2_channel *ch, int reg_nr, { unsigned long offs; - if (reg_nr == TSTR) { - if (ch->mtu->legacy) - return iowrite8(value, ch->mtu->mapbase); - else - return iowrite8(value, ch->mtu->mapbase + 0x280); - } + if (reg_nr == TSTR) + return iowrite8(value, ch->mtu->mapbase + 0x280); offs = mtu2_reg_offs[reg_nr]; @@ -202,7 +193,7 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start) unsigned long flags, value; /* start stop register shared by multiple timer channels */ - raw_spin_lock_irqsave(&sh_mtu2_lock, flags); + raw_spin_lock_irqsave(&ch->mtu->lock, flags); value = sh_mtu2_read(ch, TSTR); if (start) @@ -211,7 +202,7 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start) value &= ~(1 << ch->index); sh_mtu2_write(ch, TSTR, value); - raw_spin_unlock_irqrestore(&sh_mtu2_lock, flags); + raw_spin_unlock_irqrestore(&ch->mtu->lock, flags); } static int sh_mtu2_enable(struct sh_mtu2_channel *ch) @@ -331,7 +322,6 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, const char *name) { struct clock_event_device *ced = &ch->ced; - int ret; ced->name = name; ced->features = CLOCK_EVT_FEAT_PERIODIC; @@ -344,24 +334,12 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, dev_info(&ch->mtu->pdev->dev, "ch%u: used for clock events\n", ch->index); clockevents_register_device(ced); - - ret = request_irq(ch->irq, sh_mtu2_interrupt, - IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, - dev_name(&ch->mtu->pdev->dev), ch); - if (ret) { - dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n", - ch->index, ch->irq); - return; - } } -static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name, - bool clockevent) +static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name) { - if (clockevent) { - ch->mtu->has_clockevent = true; - sh_mtu2_register_clockevent(ch, name); - } + ch->mtu->has_clockevent = true; + sh_mtu2_register_clockevent(ch, name); return 0; } @@ -372,40 +350,32 @@ static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, unsigned int index, static const unsigned int channel_offsets[] = { 0x300, 0x380, 0x000, }; - bool clockevent; + char name[6]; + int irq; + int ret; ch->mtu = mtu; - if (mtu->legacy) { - struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; - - clockevent = cfg->clockevent_rating != 0; - - ch->irq = platform_get_irq(mtu->pdev, 0); - ch->base = mtu->mapbase - cfg->channel_offset; - ch->index = cfg->timer_bit; - } else { - char name[6]; - - clockevent = true; - - sprintf(name, "tgi%ua", index); - ch->irq = platform_get_irq_byname(mtu->pdev, name); - ch->base = mtu->mapbase + channel_offsets[index]; - ch->index = index; - } - - if (ch->irq < 0) { + sprintf(name, "tgi%ua", index); + irq = platform_get_irq_byname(mtu->pdev, name); + if (irq < 0) { /* Skip channels with no declared interrupt. */ - if (!mtu->legacy) - return 0; - - dev_err(&mtu->pdev->dev, "ch%u: failed to get irq\n", - ch->index); - return ch->irq; + return 0; } - return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev), clockevent); + ret = request_irq(irq, sh_mtu2_interrupt, + IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, + dev_name(&ch->mtu->pdev->dev), ch); + if (ret) { + dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n", + index, irq); + return ret; + } + + ch->base = mtu->mapbase + channel_offsets[index]; + ch->index = index; + + return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev)); } static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu) @@ -422,46 +392,21 @@ static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu) if (mtu->mapbase == NULL) return -ENXIO; - /* - * In legacy platform device configuration (with one device per channel) - * the resource points to the channel base address. - */ - if (mtu->legacy) { - struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; - mtu->mapbase += cfg->channel_offset; - } - return 0; } -static void sh_mtu2_unmap_memory(struct sh_mtu2_device *mtu) -{ - if (mtu->legacy) { - struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; - mtu->mapbase -= cfg->channel_offset; - } - - iounmap(mtu->mapbase); -} - static int sh_mtu2_setup(struct sh_mtu2_device *mtu, struct platform_device *pdev) { - struct sh_timer_config *cfg = pdev->dev.platform_data; - const struct platform_device_id *id = pdev->id_entry; unsigned int i; int ret; mtu->pdev = pdev; - mtu->legacy = id->driver_data; - if (mtu->legacy && !cfg) { - dev_err(&mtu->pdev->dev, "missing platform data\n"); - return -ENXIO; - } + raw_spin_lock_init(&mtu->lock); /* Get hold of clock. */ - mtu->clk = clk_get(&mtu->pdev->dev, mtu->legacy ? "mtu2_fck" : "fck"); + mtu->clk = clk_get(&mtu->pdev->dev, "fck"); if (IS_ERR(mtu->clk)) { dev_err(&mtu->pdev->dev, "cannot get clock\n"); return PTR_ERR(mtu->clk); @@ -479,10 +424,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, } /* Allocate and setup the channels. */ - if (mtu->legacy) - mtu->num_channels = 1; - else - mtu->num_channels = 3; + mtu->num_channels = 3; mtu->channels = kzalloc(sizeof(*mtu->channels) * mtu->num_channels, GFP_KERNEL); @@ -491,16 +433,10 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, goto err_unmap; } - if (mtu->legacy) { - ret = sh_mtu2_setup_channel(&mtu->channels[0], 0, mtu); + for (i = 0; i < mtu->num_channels; ++i) { + ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu); if (ret < 0) goto err_unmap; - } else { - for (i = 0; i < mtu->num_channels; ++i) { - ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu); - if (ret < 0) - goto err_unmap; - } } platform_set_drvdata(pdev, mtu); @@ -509,7 +445,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, err_unmap: kfree(mtu->channels); - sh_mtu2_unmap_memory(mtu); + iounmap(mtu->mapbase); err_clk_unprepare: clk_unprepare(mtu->clk); err_clk_put: @@ -560,17 +496,23 @@ static int sh_mtu2_remove(struct platform_device *pdev) } static const struct platform_device_id sh_mtu2_id_table[] = { - { "sh_mtu2", 1 }, { "sh-mtu2", 0 }, { }, }; MODULE_DEVICE_TABLE(platform, sh_mtu2_id_table); +static const struct of_device_id sh_mtu2_of_table[] __maybe_unused = { + { .compatible = "renesas,mtu2" }, + { } +}; +MODULE_DEVICE_TABLE(of, sh_mtu2_of_table); + static struct platform_driver sh_mtu2_device_driver = { .probe = sh_mtu2_probe, .remove = sh_mtu2_remove, .driver = { .name = "sh_mtu2", + .of_match_table = of_match_ptr(sh_mtu2_of_table), }, .id_table = sh_mtu2_id_table, }; diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 6bd17a8f3dd4..0f665b8f2461 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,6 @@ #include enum sh_tmu_model { - SH_TMU_LEGACY, SH_TMU, SH_TMU_SH3, }; @@ -62,6 +62,8 @@ struct sh_tmu_device { enum sh_tmu_model model; + raw_spinlock_t lock; /* Protect the shared start/stop register */ + struct sh_tmu_channel *channels; unsigned int num_channels; @@ -69,8 +71,6 @@ struct sh_tmu_device { bool has_clocksource; }; -static DEFINE_RAW_SPINLOCK(sh_tmu_lock); - #define TSTR -1 /* shared register */ #define TCOR 0 /* channel register */ #define TCNT 1 /* channel register */ @@ -91,8 +91,6 @@ static inline unsigned long sh_tmu_read(struct sh_tmu_channel *ch, int reg_nr) if (reg_nr == TSTR) { switch (ch->tmu->model) { - case SH_TMU_LEGACY: - return ioread8(ch->tmu->mapbase); case SH_TMU_SH3: return ioread8(ch->tmu->mapbase + 2); case SH_TMU: @@ -115,8 +113,6 @@ static inline void sh_tmu_write(struct sh_tmu_channel *ch, int reg_nr, if (reg_nr == TSTR) { switch (ch->tmu->model) { - case SH_TMU_LEGACY: - return iowrite8(value, ch->tmu->mapbase); case SH_TMU_SH3: return iowrite8(value, ch->tmu->mapbase + 2); case SH_TMU: @@ -137,7 +133,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start) unsigned long flags, value; /* start stop register shared by multiple timer channels */ - raw_spin_lock_irqsave(&sh_tmu_lock, flags); + raw_spin_lock_irqsave(&ch->tmu->lock, flags); value = sh_tmu_read(ch, TSTR); if (start) @@ -146,7 +142,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start) value &= ~(1 << ch->index); sh_tmu_write(ch, TSTR, value); - raw_spin_unlock_irqrestore(&sh_tmu_lock, flags); + raw_spin_unlock_irqrestore(&ch->tmu->lock, flags); } static int __sh_tmu_enable(struct sh_tmu_channel *ch) @@ -476,27 +472,12 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, unsigned int index, return 0; ch->tmu = tmu; + ch->index = index; - if (tmu->model == SH_TMU_LEGACY) { - struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; - - /* - * The SH3 variant (SH770x, SH7705, SH7710 and SH7720) maps - * channel registers blocks at base + 2 + 12 * index, while all - * other variants map them at base + 4 + 12 * index. We can - * compute the index by just dividing by 12, the 2 bytes or 4 - * bytes offset being hidden by the integer division. - */ - ch->index = cfg->channel_offset / 12; - ch->base = tmu->mapbase + cfg->channel_offset; - } else { - ch->index = index; - - if (tmu->model == SH_TMU_SH3) - ch->base = tmu->mapbase + 4 + ch->index * 12; - else - ch->base = tmu->mapbase + 8 + ch->index * 12; - } + if (tmu->model == SH_TMU_SH3) + ch->base = tmu->mapbase + 4 + ch->index * 12; + else + ch->base = tmu->mapbase + 8 + ch->index * 12; ch->irq = platform_get_irq(tmu->pdev, index); if (ch->irq < 0) { @@ -526,46 +507,53 @@ static int sh_tmu_map_memory(struct sh_tmu_device *tmu) if (tmu->mapbase == NULL) return -ENXIO; - /* - * In legacy platform device configuration (with one device per channel) - * the resource points to the channel base address. - */ - if (tmu->model == SH_TMU_LEGACY) { - struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; - tmu->mapbase -= cfg->channel_offset; + return 0; +} + +static int sh_tmu_parse_dt(struct sh_tmu_device *tmu) +{ + struct device_node *np = tmu->pdev->dev.of_node; + + tmu->model = SH_TMU; + tmu->num_channels = 3; + + of_property_read_u32(np, "#renesas,channels", &tmu->num_channels); + + if (tmu->num_channels != 2 && tmu->num_channels != 3) { + dev_err(&tmu->pdev->dev, "invalid number of channels %u\n", + tmu->num_channels); + return -EINVAL; } return 0; } -static void sh_tmu_unmap_memory(struct sh_tmu_device *tmu) -{ - if (tmu->model == SH_TMU_LEGACY) { - struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; - tmu->mapbase += cfg->channel_offset; - } - - iounmap(tmu->mapbase); -} - static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) { - struct sh_timer_config *cfg = pdev->dev.platform_data; - const struct platform_device_id *id = pdev->id_entry; unsigned int i; int ret; - if (!cfg) { + tmu->pdev = pdev; + + raw_spin_lock_init(&tmu->lock); + + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + ret = sh_tmu_parse_dt(tmu); + if (ret < 0) + return ret; + } else if (pdev->dev.platform_data) { + const struct platform_device_id *id = pdev->id_entry; + struct sh_timer_config *cfg = pdev->dev.platform_data; + + tmu->model = id->driver_data; + tmu->num_channels = hweight8(cfg->channels_mask); + } else { dev_err(&tmu->pdev->dev, "missing platform data\n"); return -ENXIO; } - tmu->pdev = pdev; - tmu->model = id->driver_data; - /* Get hold of clock. */ - tmu->clk = clk_get(&tmu->pdev->dev, - tmu->model == SH_TMU_LEGACY ? "tmu_fck" : "fck"); + tmu->clk = clk_get(&tmu->pdev->dev, "fck"); if (IS_ERR(tmu->clk)) { dev_err(&tmu->pdev->dev, "cannot get clock\n"); return PTR_ERR(tmu->clk); @@ -583,11 +571,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) } /* Allocate and setup the channels. */ - if (tmu->model == SH_TMU_LEGACY) - tmu->num_channels = 1; - else - tmu->num_channels = hweight8(cfg->channels_mask); - tmu->channels = kzalloc(sizeof(*tmu->channels) * tmu->num_channels, GFP_KERNEL); if (tmu->channels == NULL) { @@ -595,23 +578,15 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) goto err_unmap; } - if (tmu->model == SH_TMU_LEGACY) { - ret = sh_tmu_channel_setup(&tmu->channels[0], 0, - cfg->clockevent_rating != 0, - cfg->clocksource_rating != 0, tmu); + /* + * Use the first channel as a clock event device and the second channel + * as a clock source. + */ + for (i = 0; i < tmu->num_channels; ++i) { + ret = sh_tmu_channel_setup(&tmu->channels[i], i, + i == 0, i == 1, tmu); if (ret < 0) goto err_unmap; - } else { - /* - * Use the first channel as a clock event device and the second - * channel as a clock source. - */ - for (i = 0; i < tmu->num_channels; ++i) { - ret = sh_tmu_channel_setup(&tmu->channels[i], i, - i == 0, i == 1, tmu); - if (ret < 0) - goto err_unmap; - } } platform_set_drvdata(pdev, tmu); @@ -620,7 +595,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) err_unmap: kfree(tmu->channels); - sh_tmu_unmap_memory(tmu); + iounmap(tmu->mapbase); err_clk_unprepare: clk_unprepare(tmu->clk); err_clk_put: @@ -671,18 +646,24 @@ static int sh_tmu_remove(struct platform_device *pdev) } static const struct platform_device_id sh_tmu_id_table[] = { - { "sh_tmu", SH_TMU_LEGACY }, { "sh-tmu", SH_TMU }, { "sh-tmu-sh3", SH_TMU_SH3 }, { } }; MODULE_DEVICE_TABLE(platform, sh_tmu_id_table); +static const struct of_device_id sh_tmu_of_table[] __maybe_unused = { + { .compatible = "renesas,tmu" }, + { } +}; +MODULE_DEVICE_TABLE(of, sh_tmu_of_table); + static struct platform_driver sh_tmu_device_driver = { .probe = sh_tmu_probe, .remove = sh_tmu_remove, .driver = { .name = "sh_tmu", + .of_match_table = of_match_ptr(sh_tmu_of_table), }, .id_table = sh_tmu_id_table, }; diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index dbd30398222a..330e93064692 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c @@ -260,6 +260,9 @@ static void __init sirfsoc_marco_timer_init(struct device_node *np) clk = of_clk_get(np, 0); BUG_ON(IS_ERR(clk)); + + BUG_ON(clk_prepare_enable(clk)); + rate = clk_get_rate(clk); BUG_ON(rate < MARCO_CLOCK_FREQ); diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index a722aac7ac02..ce18d570e1cd 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -200,6 +200,9 @@ static void __init sirfsoc_prima2_timer_init(struct device_node *np) clk = of_clk_get(np, 0); BUG_ON(IS_ERR(clk)); + + BUG_ON(clk_prepare_enable(clk)); + rate = clk_get_rate(clk); BUG_ON(rate < PRIMA2_CLOCK_FREQ); diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index d7d5c8af92b9..5d997a33907e 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -1214,9 +1214,9 @@ static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg) cycle_time = card->driver->read_csr(card, CSR_CYCLE_TIME); switch (a->clk_id) { - case CLOCK_REALTIME: getnstimeofday(&ts); break; - case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break; - case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; + case CLOCK_REALTIME: getnstimeofday(&ts); break; + case CLOCK_MONOTONIC: ktime_get_ts(&ts); break; + case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; default: ret = -EINVAL; } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 0de123afdb34..08ba1209228e 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -542,8 +542,8 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, const struct drm_crtc *refcrtc, const struct drm_display_mode *mode) { - ktime_t stime, etime, mono_time_offset; struct timeval tv_etime; + ktime_t stime, etime; int vbl_status; int vpos, hpos, i; int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; @@ -588,13 +588,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos, &hpos, &stime, &etime); - /* - * Get correction for CLOCK_MONOTONIC -> CLOCK_REALTIME if - * CLOCK_REALTIME is requested. - */ - if (!drm_timestamp_monotonic) - mono_time_offset = ktime_get_monotonic_offset(); - /* Return as no-op if scanout query unsupported or failed. */ if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n", @@ -633,7 +626,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, delta_ns = vpos * linedur_ns + hpos * pixeldur_ns; if (!drm_timestamp_monotonic) - etime = ktime_sub(etime, mono_time_offset); + etime = ktime_mono_to_real(etime); /* save this only for debugging purposes */ tv_etime = ktime_to_timeval(etime); @@ -664,10 +657,7 @@ static struct timeval get_drm_timestamp(void) { ktime_t now; - now = ktime_get(); - if (!drm_timestamp_monotonic) - now = ktime_sub(now, ktime_get_monotonic_offset()); - + now = drm_timestamp_monotonic ? ktime_get() : ktime_get_real(); return ktime_to_timeval(now); } diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index fd325ec9f064..de055451d1af 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -108,9 +108,8 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) struct input_event ev; ktime_t time; - time = ktime_get(); - if (client->clkid != CLOCK_MONOTONIC) - time = ktime_sub(time, ktime_get_monotonic_offset()); + time = (client->clkid == CLOCK_MONOTONIC) ? + ktime_get() : ktime_get_real(); ev.time = ktime_to_timeval(time); ev.type = EV_SYN; @@ -202,7 +201,7 @@ static void evdev_events(struct input_handle *handle, ktime_t time_mono, time_real; time_mono = ktime_get(); - time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); + time_real = ktime_mono_to_real(time_mono); rcu_read_lock(); diff --git a/drivers/of/address.c b/drivers/of/address.c index 5edfcb0da37d..e3718250d66e 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -702,6 +702,42 @@ void __iomem *of_iomap(struct device_node *np, int index) } EXPORT_SYMBOL(of_iomap); +/* + * of_io_request_and_map - Requests a resource and maps the memory mapped IO + * for a given device_node + * @device: the device whose io range will be mapped + * @index: index of the io range + * @name: name of the resource + * + * Returns a pointer to the requested and mapped memory or an ERR_PTR() encoded + * error code on failure. Usage example: + * + * base = of_io_request_and_map(node, 0, "foo"); + * if (IS_ERR(base)) + * return PTR_ERR(base); + */ +void __iomem *of_io_request_and_map(struct device_node *np, int index, + char *name) +{ + struct resource res; + void __iomem *mem; + + if (of_address_to_resource(np, index, &res)) + return IOMEM_ERR_PTR(-EINVAL); + + if (!request_mem_region(res.start, resource_size(&res), name)) + return IOMEM_ERR_PTR(-EBUSY); + + mem = ioremap(res.start, resource_size(&res)); + if (!mem) { + release_mem_region(res.start, resource_size(&res)); + return IOMEM_ERR_PTR(-ENOMEM); + } + + return mem; +} +EXPORT_SYMBOL(of_io_request_and_map); + /** * of_dma_get_range - Get DMA range info * @np: device node to get DMA range info diff --git a/fs/proc/array.c b/fs/proc/array.c index 64db2bceac59..d7f9199217bb 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -473,13 +473,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, priority = task_prio(task); nice = task_nice(task); - /* Temporary variable needed for gcc-2.96 */ - /* convert timespec -> nsec*/ - start_time = - (unsigned long long)task->real_start_time.tv_sec * NSEC_PER_SEC - + task->real_start_time.tv_nsec; /* convert nsec -> ticks */ - start_time = nsec_to_clock_t(start_time); + start_time = nsec_to_clock_t(task->real_start_time); seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state); seq_put_decimal_ll(m, ' ', ppid); diff --git a/fs/timerfd.c b/fs/timerfd.c index 0013142c0475..80c350216ea8 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -35,8 +35,9 @@ struct timerfd_ctx { ktime_t moffs; wait_queue_head_t wqh; u64 ticks; - int expired; int clockid; + short unsigned expired; + short unsigned settime_flags; /* to show in fdinfo */ struct rcu_head rcu; struct list_head clist; bool might_cancel; @@ -92,7 +93,7 @@ static enum alarmtimer_restart timerfd_alarmproc(struct alarm *alarm, */ void timerfd_clock_was_set(void) { - ktime_t moffs = ktime_get_monotonic_offset(); + ktime_t moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 }); struct timerfd_ctx *ctx; unsigned long flags; @@ -125,7 +126,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx) { if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX) return false; - ctx->moffs = ktime_get_monotonic_offset(); + ctx->moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 }); return true; } @@ -196,6 +197,8 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int flags, if (timerfd_canceled(ctx)) return -ECANCELED; } + + ctx->settime_flags = flags & TFD_SETTIME_FLAGS; return 0; } @@ -284,11 +287,77 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, return res; } +#ifdef CONFIG_PROC_FS +static int timerfd_show(struct seq_file *m, struct file *file) +{ + struct timerfd_ctx *ctx = file->private_data; + struct itimerspec t; + + spin_lock_irq(&ctx->wqh.lock); + t.it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); + t.it_interval = ktime_to_timespec(ctx->tintv); + spin_unlock_irq(&ctx->wqh.lock); + + return seq_printf(m, + "clockid: %d\n" + "ticks: %llu\n" + "settime flags: 0%o\n" + "it_value: (%llu, %llu)\n" + "it_interval: (%llu, %llu)\n", + ctx->clockid, (unsigned long long)ctx->ticks, + ctx->settime_flags, + (unsigned long long)t.it_value.tv_sec, + (unsigned long long)t.it_value.tv_nsec, + (unsigned long long)t.it_interval.tv_sec, + (unsigned long long)t.it_interval.tv_nsec); +} +#else +#define timerfd_show NULL +#endif + +#ifdef CONFIG_CHECKPOINT_RESTORE +static long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct timerfd_ctx *ctx = file->private_data; + int ret = 0; + + switch (cmd) { + case TFD_IOC_SET_TICKS: { + u64 ticks; + + if (copy_from_user(&ticks, (u64 __user *)arg, sizeof(ticks))) + return -EFAULT; + if (!ticks) + return -EINVAL; + + spin_lock_irq(&ctx->wqh.lock); + if (!timerfd_canceled(ctx)) { + ctx->ticks = ticks; + if (ticks) + wake_up_locked(&ctx->wqh); + } else + ret = -ECANCELED; + spin_unlock_irq(&ctx->wqh.lock); + break; + } + default: + ret = -ENOTTY; + break; + } + + return ret; +} +#else +#define timerfd_ioctl NULL +#endif + static const struct file_operations timerfd_fops = { .release = timerfd_release, .poll = timerfd_poll, .read = timerfd_read, .llseek = noop_llseek, + .show_fdinfo = timerfd_show, + .unlocked_ioctl = timerfd_ioctl, }; static int timerfd_fget(int fd, struct fd *p) @@ -336,7 +405,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) else hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS); - ctx->moffs = ktime_get_monotonic_offset(); + ctx->moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 }); ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx, O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS)); diff --git a/include/clocksource/pxa.h b/include/clocksource/pxa.h new file mode 100644 index 000000000000..1efbe5a66958 --- /dev/null +++ b/include/clocksource/pxa.h @@ -0,0 +1,18 @@ +/* + * PXA clocksource, clockevents, and OST interrupt handlers. + * + * Copyright (C) 2014 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + */ + +#ifndef _CLOCKSOURCE_PXA_H +#define _CLOCKSOURCE_PXA_H + +extern void pxa_timer_nodt_init(int irq, void __iomem *base, + unsigned long clock_tick_rate); + +#endif diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index e7a8d3fa91d5..a036d058a249 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -165,6 +165,7 @@ enum hrtimer_base_type { * struct hrtimer_cpu_base - the per cpu clock bases * @lock: lock protecting the base and associated clock bases * and timers + * @cpu: cpu number * @active_bases: Bitfield to mark bases with active timers * @clock_was_set: Indicates that clock was set from irq context. * @expires_next: absolute time of the next event which was scheduled @@ -179,6 +180,7 @@ enum hrtimer_base_type { */ struct hrtimer_cpu_base { raw_spinlock_t lock; + unsigned int cpu; unsigned int active_bases; unsigned int clock_was_set; #ifdef CONFIG_HIGH_RES_TIMERS @@ -324,14 +326,6 @@ static inline void timerfd_clock_was_set(void) { } #endif extern void hrtimers_resume(void); -extern ktime_t ktime_get(void); -extern ktime_t ktime_get_real(void); -extern ktime_t ktime_get_boottime(void); -extern ktime_t ktime_get_monotonic_offset(void); -extern ktime_t ktime_get_clocktai(void); -extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot, - ktime_t *offs_tai); - DECLARE_PER_CPU(struct tick_device, tick_cpu_device); @@ -452,12 +446,6 @@ extern void hrtimer_run_pending(void); /* Bootup initialization: */ extern void __init hrtimers_init(void); -#if BITS_PER_LONG < 64 -extern u64 ktime_divns(const ktime_t kt, s64 div); -#else /* BITS_PER_LONG < 64 */ -# define ktime_divns(kt, div) (u64)((kt).tv64 / (div)) -#endif - /* Show pending timers: */ extern void sysrq_timer_list_show(void); diff --git a/include/linux/io.h b/include/linux/io.h index b76e6e545806..d5fc9b8d8b03 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -58,6 +58,8 @@ static inline void devm_ioport_unmap(struct device *dev, void __iomem *addr) } #endif +#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err) + void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, unsigned long size); void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset, diff --git a/include/linux/ktime.h b/include/linux/ktime.h index de9e46e6bcc9..c9d645ad98ff 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -27,43 +27,19 @@ /* * ktime_t: * - * On 64-bit CPUs a single 64-bit variable is used to store the hrtimers + * A single 64-bit variable is used to store the hrtimers * internal representation of time values in scalar nanoseconds. The * design plays out best on 64-bit CPUs, where most conversions are * NOPs and most arithmetic ktime_t operations are plain arithmetic * operations. * - * On 32-bit CPUs an optimized representation of the timespec structure - * is used to avoid expensive conversions from and to timespecs. The - * endian-aware order of the tv struct members is chosen to allow - * mathematical operations on the tv64 member of the union too, which - * for certain operations produces better code. - * - * For architectures with efficient support for 64/32-bit conversions the - * plain scalar nanosecond based representation can be selected by the - * config switch CONFIG_KTIME_SCALAR. */ union ktime { s64 tv64; -#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR) - struct { -# ifdef __BIG_ENDIAN - s32 sec, nsec; -# else - s32 nsec, sec; -# endif - } tv; -#endif }; typedef union ktime ktime_t; /* Kill this */ -/* - * ktime_t definitions when using the 64-bit scalar representation: - */ - -#if (BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR) - /** * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value * @secs: seconds to set @@ -71,13 +47,12 @@ typedef union ktime ktime_t; /* Kill this */ * * Return: The ktime_t representation of the value. */ -static inline ktime_t ktime_set(const long secs, const unsigned long nsecs) +static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs) { -#if (BITS_PER_LONG == 64) if (unlikely(secs >= KTIME_SEC_MAX)) return (ktime_t){ .tv64 = KTIME_MAX }; -#endif - return (ktime_t) { .tv64 = (s64)secs * NSEC_PER_SEC + (s64)nsecs }; + + return (ktime_t) { .tv64 = secs * NSEC_PER_SEC + (s64)nsecs }; } /* Subtract two ktime_t variables. rem = lhs -rhs: */ @@ -108,6 +83,12 @@ static inline ktime_t timespec_to_ktime(struct timespec ts) return ktime_set(ts.tv_sec, ts.tv_nsec); } +/* convert a timespec64 to ktime_t format: */ +static inline ktime_t timespec64_to_ktime(struct timespec64 ts) +{ + return ktime_set(ts.tv_sec, ts.tv_nsec); +} + /* convert a timeval to ktime_t format: */ static inline ktime_t timeval_to_ktime(struct timeval tv) { @@ -117,159 +98,15 @@ static inline ktime_t timeval_to_ktime(struct timeval tv) /* Map the ktime_t to timespec conversion to ns_to_timespec function */ #define ktime_to_timespec(kt) ns_to_timespec((kt).tv64) +/* Map the ktime_t to timespec conversion to ns_to_timespec function */ +#define ktime_to_timespec64(kt) ns_to_timespec64((kt).tv64) + /* Map the ktime_t to timeval conversion to ns_to_timeval function */ #define ktime_to_timeval(kt) ns_to_timeval((kt).tv64) /* Convert ktime_t to nanoseconds - NOP in the scalar storage format: */ #define ktime_to_ns(kt) ((kt).tv64) -#else /* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */ - -/* - * Helper macros/inlines to get the ktime_t math right in the timespec - * representation. The macros are sometimes ugly - their actual use is - * pretty okay-ish, given the circumstances. We do all this for - * performance reasons. The pure scalar nsec_t based code was nice and - * simple, but created too many 64-bit / 32-bit conversions and divisions. - * - * Be especially aware that negative values are represented in a way - * that the tv.sec field is negative and the tv.nsec field is greater - * or equal to zero but less than nanoseconds per second. This is the - * same representation which is used by timespecs. - * - * tv.sec < 0 and 0 >= tv.nsec < NSEC_PER_SEC - */ - -/* Set a ktime_t variable to a value in sec/nsec representation: */ -static inline ktime_t ktime_set(const long secs, const unsigned long nsecs) -{ - return (ktime_t) { .tv = { .sec = secs, .nsec = nsecs } }; -} - -/** - * ktime_sub - subtract two ktime_t variables - * @lhs: minuend - * @rhs: subtrahend - * - * Return: The remainder of the subtraction. - */ -static inline ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs) -{ - ktime_t res; - - res.tv64 = lhs.tv64 - rhs.tv64; - if (res.tv.nsec < 0) - res.tv.nsec += NSEC_PER_SEC; - - return res; -} - -/** - * ktime_add - add two ktime_t variables - * @add1: addend1 - * @add2: addend2 - * - * Return: The sum of @add1 and @add2. - */ -static inline ktime_t ktime_add(const ktime_t add1, const ktime_t add2) -{ - ktime_t res; - - res.tv64 = add1.tv64 + add2.tv64; - /* - * performance trick: the (u32) -NSEC gives 0x00000000Fxxxxxxx - * so we subtract NSEC_PER_SEC and add 1 to the upper 32 bit. - * - * it's equivalent to: - * tv.nsec -= NSEC_PER_SEC - * tv.sec ++; - */ - if (res.tv.nsec >= NSEC_PER_SEC) - res.tv64 += (u32)-NSEC_PER_SEC; - - return res; -} - -/** - * ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable - * @kt: addend - * @nsec: the scalar nsec value to add - * - * Return: The sum of @kt and @nsec in ktime_t format. - */ -extern ktime_t ktime_add_ns(const ktime_t kt, u64 nsec); - -/** - * ktime_sub_ns - Subtract a scalar nanoseconds value from a ktime_t variable - * @kt: minuend - * @nsec: the scalar nsec value to subtract - * - * Return: The subtraction of @nsec from @kt in ktime_t format. - */ -extern ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec); - -/** - * timespec_to_ktime - convert a timespec to ktime_t format - * @ts: the timespec variable to convert - * - * Return: A ktime_t variable with the converted timespec value. - */ -static inline ktime_t timespec_to_ktime(const struct timespec ts) -{ - return (ktime_t) { .tv = { .sec = (s32)ts.tv_sec, - .nsec = (s32)ts.tv_nsec } }; -} - -/** - * timeval_to_ktime - convert a timeval to ktime_t format - * @tv: the timeval variable to convert - * - * Return: A ktime_t variable with the converted timeval value. - */ -static inline ktime_t timeval_to_ktime(const struct timeval tv) -{ - return (ktime_t) { .tv = { .sec = (s32)tv.tv_sec, - .nsec = (s32)(tv.tv_usec * - NSEC_PER_USEC) } }; -} - -/** - * ktime_to_timespec - convert a ktime_t variable to timespec format - * @kt: the ktime_t variable to convert - * - * Return: The timespec representation of the ktime value. - */ -static inline struct timespec ktime_to_timespec(const ktime_t kt) -{ - return (struct timespec) { .tv_sec = (time_t) kt.tv.sec, - .tv_nsec = (long) kt.tv.nsec }; -} - -/** - * ktime_to_timeval - convert a ktime_t variable to timeval format - * @kt: the ktime_t variable to convert - * - * Return: The timeval representation of the ktime value. - */ -static inline struct timeval ktime_to_timeval(const ktime_t kt) -{ - return (struct timeval) { - .tv_sec = (time_t) kt.tv.sec, - .tv_usec = (suseconds_t) (kt.tv.nsec / NSEC_PER_USEC) }; -} - -/** - * ktime_to_ns - convert a ktime_t variable to scalar nanoseconds - * @kt: the ktime_t variable to convert - * - * Return: The scalar nanoseconds representation of @kt. - */ -static inline s64 ktime_to_ns(const ktime_t kt) -{ - return (s64) kt.tv.sec * NSEC_PER_SEC + kt.tv.nsec; -} - -#endif /* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */ /** * ktime_equal - Compares two ktime_t variables to see if they are equal @@ -328,16 +165,20 @@ static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2) return ktime_compare(cmp1, cmp2) < 0; } +#if BITS_PER_LONG < 64 +extern u64 ktime_divns(const ktime_t kt, s64 div); +#else /* BITS_PER_LONG < 64 */ +# define ktime_divns(kt, div) (u64)((kt).tv64 / (div)) +#endif + static inline s64 ktime_to_us(const ktime_t kt) { - struct timeval tv = ktime_to_timeval(kt); - return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec; + return ktime_divns(kt, NSEC_PER_USEC); } static inline s64 ktime_to_ms(const ktime_t kt) { - struct timeval tv = ktime_to_timeval(kt); - return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC; + return ktime_divns(kt, NSEC_PER_MSEC); } static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier) @@ -381,6 +222,25 @@ static inline __must_check bool ktime_to_timespec_cond(const ktime_t kt, } } +/** + * ktime_to_timespec64_cond - convert a ktime_t variable to timespec64 + * format only if the variable contains data + * @kt: the ktime_t variable to convert + * @ts: the timespec variable to store the result in + * + * Return: %true if there was a successful conversion, %false if kt was 0. + */ +static inline __must_check bool ktime_to_timespec64_cond(const ktime_t kt, + struct timespec64 *ts) +{ + if (kt.tv64) { + *ts = ktime_to_timespec64(kt); + return true; + } else { + return false; + } +} + /* * The resolution of the clocks. The resolution value is returned in * the clock_getres() system call to give application programmers an @@ -390,12 +250,6 @@ static inline __must_check bool ktime_to_timespec_cond(const ktime_t kt, #define LOW_RES_NSEC TICK_NSEC #define KTIME_LOW_RES (ktime_t){ .tv64 = LOW_RES_NSEC } -/* Get the monotonic time in timespec format: */ -extern void ktime_get_ts(struct timespec *ts); - -/* Get the real (wall-) time in timespec format: */ -#define ktime_get_real_ts(ts) getnstimeofday(ts) - static inline ktime_t ns_to_ktime(u64 ns) { static const ktime_t ktime_zero = { .tv64 = 0 }; @@ -410,4 +264,6 @@ static inline ktime_t ms_to_ktime(u64 ms) return ktime_add_ms(ktime_zero, ms); } +# include + #endif diff --git a/include/linux/of_address.h b/include/linux/of_address.h index c13b8782a4eb..fb7b7221e063 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -109,7 +109,12 @@ static inline bool of_dma_is_coherent(struct device_node *np) extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); void __iomem *of_iomap(struct device_node *node, int index); +void __iomem *of_io_request_and_map(struct device_node *device, + int index, char *name); #else + +#include + static inline int of_address_to_resource(struct device_node *dev, int index, struct resource *r) { @@ -120,6 +125,12 @@ static inline void __iomem *of_iomap(struct device_node *device, int index) { return NULL; } + +static inline void __iomem *of_io_request_and_map(struct device_node *device, + int index, char *name) +{ + return IOMEM_ERR_PTR(-EINVAL); +} #endif #if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI) diff --git a/include/linux/sched.h b/include/linux/sched.h index 0376b054a0d0..b1ce2aceaf49 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1367,8 +1367,8 @@ struct task_struct { } vtime_snap_whence; #endif unsigned long nvcsw, nivcsw; /* context switch counts */ - struct timespec start_time; /* monotonic time */ - struct timespec real_start_time; /* boot based time */ + u64 start_time; /* monotonic time in nsec */ + u64 real_start_time; /* boot based time in nsec */ /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ unsigned long min_flt, maj_flt; diff --git a/include/linux/sh_timer.h b/include/linux/sh_timer.h index 8e1e036d6d45..64638b058076 100644 --- a/include/linux/sh_timer.h +++ b/include/linux/sh_timer.h @@ -2,11 +2,6 @@ #define __SH_TIMER_H__ struct sh_timer_config { - char *name; - long channel_offset; - int timer_bit; - unsigned long clockevent_rating; - unsigned long clocksource_rating; unsigned int channels_mask; }; diff --git a/include/linux/time.h b/include/linux/time.h index d5d229b2e5af..8c42cf8d2444 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -4,19 +4,10 @@ # include # include # include -#include +# include extern struct timezone sys_tz; -/* Parameters used to convert the timespec values: */ -#define MSEC_PER_SEC 1000L -#define USEC_PER_MSEC 1000L -#define NSEC_PER_USEC 1000L -#define NSEC_PER_MSEC 1000000L -#define USEC_PER_SEC 1000000L -#define NSEC_PER_SEC 1000000000L -#define FSEC_PER_SEC 1000000000000000LL - #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) static inline int timespec_equal(const struct timespec *a, @@ -84,13 +75,6 @@ static inline struct timespec timespec_sub(struct timespec lhs, return ts_delta; } -#define KTIME_MAX ((s64)~((u64)1 << 63)) -#if (BITS_PER_LONG == 64) -# define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) -#else -# define KTIME_SEC_MAX LONG_MAX -#endif - /* * Returns true if the timespec is norm, false if denorm: */ @@ -115,27 +99,7 @@ static inline bool timespec_valid_strict(const struct timespec *ts) return true; } -extern bool persistent_clock_exist; - -static inline bool has_persistent_clock(void) -{ - return persistent_clock_exist; -} - -extern void read_persistent_clock(struct timespec *ts); -extern void read_boot_clock(struct timespec *ts); -extern int persistent_clock_is_local; -extern int update_persistent_clock(struct timespec now); -void timekeeping_init(void); -extern int timekeeping_suspended; - -unsigned long get_seconds(void); -struct timespec current_kernel_time(void); -struct timespec __current_kernel_time(void); /* does not take xtime_lock */ -struct timespec get_monotonic_coarse(void); -void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, - struct timespec *wtom, struct timespec *sleep); -void timekeeping_inject_sleeptime(struct timespec *delta); +extern struct timespec timespec_trunc(struct timespec t, unsigned gran); #define CURRENT_TIME (current_kernel_time()) #define CURRENT_TIME_SEC ((struct timespec) { get_seconds(), 0 }) @@ -153,33 +117,14 @@ void timekeeping_inject_sleeptime(struct timespec *delta); extern u32 (*arch_gettimeoffset)(void); #endif -extern void do_gettimeofday(struct timeval *tv); -extern int do_settimeofday(const struct timespec *tv); -extern int do_sys_settimeofday(const struct timespec *tv, - const struct timezone *tz); -#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts) -extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags); struct itimerval; extern int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue); -extern unsigned int alarm_setitimer(unsigned int seconds); extern int do_getitimer(int which, struct itimerval *value); -extern int __getnstimeofday(struct timespec *tv); -extern void getnstimeofday(struct timespec *tv); -extern void getrawmonotonic(struct timespec *ts); -extern void getnstime_raw_and_real(struct timespec *ts_raw, - struct timespec *ts_real); -extern void getboottime(struct timespec *ts); -extern void monotonic_to_bootbased(struct timespec *ts); -extern void get_monotonic_boottime(struct timespec *ts); -extern struct timespec timespec_trunc(struct timespec t, unsigned gran); -extern int timekeeping_valid_for_hres(void); -extern u64 timekeeping_max_deferment(void); -extern int timekeeping_inject_offset(struct timespec *ts); -extern s32 timekeeping_get_tai_offset(void); -extern void timekeeping_set_tai_offset(s32 tai_offset); -extern void timekeeping_clocktai(struct timespec *ts); +extern unsigned int alarm_setitimer(unsigned int seconds); + +extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags); struct tms; extern void do_sys_times(struct tms *); diff --git a/include/linux/time64.h b/include/linux/time64.h new file mode 100644 index 000000000000..a3831478d9cf --- /dev/null +++ b/include/linux/time64.h @@ -0,0 +1,190 @@ +#ifndef _LINUX_TIME64_H +#define _LINUX_TIME64_H + +#include + +typedef __s64 time64_t; + +/* + * This wants to go into uapi/linux/time.h once we agreed about the + * userspace interfaces. + */ +#if __BITS_PER_LONG == 64 +# define timespec64 timespec +#else +struct timespec64 { + time64_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; +#endif + +/* Parameters used to convert the timespec values: */ +#define MSEC_PER_SEC 1000L +#define USEC_PER_MSEC 1000L +#define NSEC_PER_USEC 1000L +#define NSEC_PER_MSEC 1000000L +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000L +#define FSEC_PER_SEC 1000000000000000LL + +/* Located here for timespec[64]_valid_strict */ +#define KTIME_MAX ((s64)~((u64)1 << 63)) +#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) + +#if __BITS_PER_LONG == 64 + +static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64) +{ + return ts64; +} + +static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) +{ + return ts; +} + +# define timespec64_equal timespec_equal +# define timespec64_compare timespec_compare +# define set_normalized_timespec64 set_normalized_timespec +# define timespec64_add_safe timespec_add_safe +# define timespec64_add timespec_add +# define timespec64_sub timespec_sub +# define timespec64_valid timespec_valid +# define timespec64_valid_strict timespec_valid_strict +# define timespec64_to_ns timespec_to_ns +# define ns_to_timespec64 ns_to_timespec +# define timespec64_add_ns timespec_add_ns + +#else + +static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64) +{ + struct timespec ret; + + ret.tv_sec = (time_t)ts64.tv_sec; + ret.tv_nsec = ts64.tv_nsec; + return ret; +} + +static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) +{ + struct timespec64 ret; + + ret.tv_sec = ts.tv_sec; + ret.tv_nsec = ts.tv_nsec; + return ret; +} + +static inline int timespec64_equal(const struct timespec64 *a, + const struct timespec64 *b) +{ + return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec); +} + +/* + * lhs < rhs: return <0 + * lhs == rhs: return 0 + * lhs > rhs: return >0 + */ +static inline int timespec64_compare(const struct timespec64 *lhs, const struct timespec64 *rhs) +{ + if (lhs->tv_sec < rhs->tv_sec) + return -1; + if (lhs->tv_sec > rhs->tv_sec) + return 1; + return lhs->tv_nsec - rhs->tv_nsec; +} + +extern void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec); + +/* + * timespec64_add_safe assumes both values are positive and checks for + * overflow. It will return TIME_T_MAX if the returned value would be + * smaller then either of the arguments. + */ +extern struct timespec64 timespec64_add_safe(const struct timespec64 lhs, + const struct timespec64 rhs); + + +static inline struct timespec64 timespec64_add(struct timespec64 lhs, + struct timespec64 rhs) +{ + struct timespec64 ts_delta; + set_normalized_timespec64(&ts_delta, lhs.tv_sec + rhs.tv_sec, + lhs.tv_nsec + rhs.tv_nsec); + return ts_delta; +} + +/* + * sub = lhs - rhs, in normalized form + */ +static inline struct timespec64 timespec64_sub(struct timespec64 lhs, + struct timespec64 rhs) +{ + struct timespec64 ts_delta; + set_normalized_timespec64(&ts_delta, lhs.tv_sec - rhs.tv_sec, + lhs.tv_nsec - rhs.tv_nsec); + return ts_delta; +} + +/* + * Returns true if the timespec64 is norm, false if denorm: + */ +static inline bool timespec64_valid(const struct timespec64 *ts) +{ + /* Dates before 1970 are bogus */ + if (ts->tv_sec < 0) + return false; + /* Can't have more nanoseconds then a second */ + if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) + return false; + return true; +} + +static inline bool timespec64_valid_strict(const struct timespec64 *ts) +{ + if (!timespec64_valid(ts)) + return false; + /* Disallow values that could overflow ktime_t */ + if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) + return false; + return true; +} + +/** + * timespec64_to_ns - Convert timespec64 to nanoseconds + * @ts: pointer to the timespec64 variable to be converted + * + * Returns the scalar nanosecond representation of the timespec64 + * parameter. + */ +static inline s64 timespec64_to_ns(const struct timespec64 *ts) +{ + return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec; +} + +/** + * ns_to_timespec64 - Convert nanoseconds to timespec64 + * @nsec: the nanoseconds value to be converted + * + * Returns the timespec64 representation of the nsec parameter. + */ +extern struct timespec64 ns_to_timespec64(const s64 nsec); + +/** + * timespec64_add_ns - Adds nanoseconds to a timespec64 + * @a: pointer to timespec64 to be incremented + * @ns: unsigned nanoseconds value to be added + * + * This must always be inlined because its used from the x86-64 vdso, + * which cannot call other kernel functions. + */ +static __always_inline void timespec64_add_ns(struct timespec64 *a, u64 ns) +{ + a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); + a->tv_nsec = ns; +} + +#endif + +#endif /* _LINUX_TIME64_H */ diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index c1825eb436ed..87e0992564f2 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -10,7 +10,22 @@ #include #include -/* Structure holding internal timekeeping values. */ +/* + * Structure holding internal timekeeping values. + * + * Note: wall_to_monotonic is what we need to add to xtime (or xtime + * corrected for sub jiffie times) to get to monotonic time. + * Monotonic is pegged at zero at system boot time, so + * wall_to_monotonic will be negative, however, we will ALWAYS keep + * the tv_nsec part positive so we can use the usual normalization. + * + * wall_to_monotonic is moved after resume from suspend for the + * monotonic time not to jump. We need to add total_sleep_time to + * wall_to_monotonic to get the real boot based time offset. + * + * - wall_to_monotonic is no longer the boot time, getboottime must be + * used instead. + */ struct timekeeper { /* Current clocksource used for timekeeping. */ struct clocksource *clock; @@ -18,6 +33,32 @@ struct timekeeper { u32 mult; /* The shift value of the current clocksource. */ u32 shift; + /* Clock shifted nano seconds */ + u64 xtime_nsec; + + /* Monotonic base time */ + ktime_t base_mono; + + /* Current CLOCK_REALTIME time in seconds */ + u64 xtime_sec; + /* CLOCK_REALTIME to CLOCK_MONOTONIC offset */ + struct timespec64 wall_to_monotonic; + + /* Offset clock monotonic -> clock realtime */ + ktime_t offs_real; + /* Offset clock monotonic -> clock boottime */ + ktime_t offs_boot; + /* Offset clock monotonic -> clock tai */ + ktime_t offs_tai; + + /* time spent in suspend */ + struct timespec64 total_sleep_time; + /* The current UTC to TAI offset in seconds */ + s32 tai_offset; + + /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ + struct timespec64 raw_time; + /* Number of clock cycles in one NTP interval. */ cycle_t cycle_interval; /* Last cycle value (also stored in clock->cycle_last) */ @@ -29,58 +70,18 @@ struct timekeeper { /* Raw nano seconds accumulated per NTP interval. */ u32 raw_interval; - /* Current CLOCK_REALTIME time in seconds */ - u64 xtime_sec; - /* Clock shifted nano seconds */ - u64 xtime_nsec; - - /* Difference between accumulated time and NTP time in ntp - * shifted nano seconds. */ - s64 ntp_error; - /* Shift conversion between clock shifted nano seconds and - * ntp shifted nano seconds. */ - u32 ntp_error_shift; - /* - * wall_to_monotonic is what we need to add to xtime (or xtime corrected - * for sub jiffie times) to get to monotonic time. Monotonic is pegged - * at zero at system boot time, so wall_to_monotonic will be negative, - * however, we will ALWAYS keep the tv_nsec part positive so we can use - * the usual normalization. - * - * wall_to_monotonic is moved after resume from suspend for the - * monotonic time not to jump. We need to add total_sleep_time to - * wall_to_monotonic to get the real boot based time offset. - * - * - wall_to_monotonic is no longer the boot time, getboottime must be - * used instead. + * Difference between accumulated time and NTP time in ntp + * shifted nano seconds. */ - struct timespec wall_to_monotonic; - /* Offset clock monotonic -> clock realtime */ - ktime_t offs_real; - /* time spent in suspend */ - struct timespec total_sleep_time; - /* Offset clock monotonic -> clock boottime */ - ktime_t offs_boot; - /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ - struct timespec raw_time; - /* The current UTC to TAI offset in seconds */ - s32 tai_offset; - /* Offset clock monotonic -> clock tai */ - ktime_t offs_tai; - + s64 ntp_error; + /* + * Shift conversion between clock shifted nano seconds and + * ntp shifted nano seconds. + */ + u32 ntp_error_shift; }; -static inline struct timespec tk_xtime(struct timekeeper *tk) -{ - struct timespec ts; - - ts.tv_sec = tk->xtime_sec; - ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); - return ts; -} - - #ifdef CONFIG_GENERIC_TIME_VSYSCALL extern void update_vsyscall(struct timekeeper *tk); @@ -92,14 +93,6 @@ extern void update_vsyscall_old(struct timespec *ts, struct timespec *wtm, struct clocksource *c, u32 mult); extern void update_vsyscall_tz(void); -static inline void update_vsyscall(struct timekeeper *tk) -{ - struct timespec xt; - - xt = tk_xtime(tk); - update_vsyscall_old(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult); -} - #else static inline void update_vsyscall(struct timekeeper *tk) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h new file mode 100644 index 000000000000..903ecc10fcff --- /dev/null +++ b/include/linux/timekeeping.h @@ -0,0 +1,190 @@ +#ifndef _LINUX_TIMEKEEPING_H +#define _LINUX_TIMEKEEPING_H + +/* Included from linux/ktime.h */ + +void timekeeping_init(void); +extern int timekeeping_suspended; + +/* + * Get and set timeofday + */ +extern void do_gettimeofday(struct timeval *tv); +extern int do_settimeofday(const struct timespec *tv); +extern int do_sys_settimeofday(const struct timespec *tv, + const struct timezone *tz); + +/* + * Kernel time accessors + */ +unsigned long get_seconds(void); +struct timespec current_kernel_time(void); +/* does not take xtime_lock */ +struct timespec __current_kernel_time(void); + +/* + * timespec based interfaces + */ +struct timespec get_monotonic_coarse(void); +extern void getrawmonotonic(struct timespec *ts); +extern void monotonic_to_bootbased(struct timespec *ts); +extern void get_monotonic_boottime(struct timespec *ts); +extern void ktime_get_ts64(struct timespec64 *ts); + +extern int __getnstimeofday64(struct timespec64 *tv); +extern void getnstimeofday64(struct timespec64 *tv); + +#if BITS_PER_LONG == 64 +static inline int __getnstimeofday(struct timespec *ts) +{ + return __getnstimeofday64(ts); +} + +static inline void getnstimeofday(struct timespec *ts) +{ + getnstimeofday64(ts); +} + +static inline void ktime_get_ts(struct timespec *ts) +{ + ktime_get_ts64(ts); +} + +static inline void ktime_get_real_ts(struct timespec *ts) +{ + getnstimeofday64(ts); +} + +#else +static inline int __getnstimeofday(struct timespec *ts) +{ + struct timespec64 ts64; + int ret = __getnstimeofday64(&ts64); + + *ts = timespec64_to_timespec(ts64); + return ret; +} + +static inline void getnstimeofday(struct timespec *ts) +{ + struct timespec64 ts64; + + getnstimeofday64(&ts64); + *ts = timespec64_to_timespec(ts64); +} + +static inline void ktime_get_ts(struct timespec *ts) +{ + struct timespec64 ts64; + + ktime_get_ts64(&ts64); + *ts = timespec64_to_timespec(ts64); +} + +static inline void ktime_get_real_ts(struct timespec *ts) +{ + struct timespec64 ts64; + + getnstimeofday64(&ts64); + *ts = timespec64_to_timespec(ts64); +} +#endif + +extern void getboottime(struct timespec *ts); + +#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts) +#define ktime_get_real_ts64(ts) getnstimeofday64(ts) + +/* + * ktime_t based interfaces + */ + +enum tk_offsets { + TK_OFFS_REAL, + TK_OFFS_BOOT, + TK_OFFS_TAI, + TK_OFFS_MAX, +}; + +extern ktime_t ktime_get(void); +extern ktime_t ktime_get_with_offset(enum tk_offsets offs); +extern ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs); + +/** + * ktime_get_real - get the real (wall-) time in ktime_t format + */ +static inline ktime_t ktime_get_real(void) +{ + return ktime_get_with_offset(TK_OFFS_REAL); +} + +/** + * ktime_get_boottime - Returns monotonic time since boot in ktime_t format + * + * This is similar to CLOCK_MONTONIC/ktime_get, but also includes the + * time spent in suspend. + */ +static inline ktime_t ktime_get_boottime(void) +{ + return ktime_get_with_offset(TK_OFFS_BOOT); +} + +/** + * ktime_get_clocktai - Returns the TAI time of day in ktime_t format + */ +static inline ktime_t ktime_get_clocktai(void) +{ + return ktime_get_with_offset(TK_OFFS_TAI); +} + +/** + * ktime_mono_to_real - Convert monotonic time to clock realtime + */ +static inline ktime_t ktime_mono_to_real(ktime_t mono) +{ + return ktime_mono_to_any(mono, TK_OFFS_REAL); +} + +static inline u64 ktime_get_ns(void) +{ + return ktime_to_ns(ktime_get()); +} + +static inline u64 ktime_get_real_ns(void) +{ + return ktime_to_ns(ktime_get_real()); +} + +static inline u64 ktime_get_boot_ns(void) +{ + return ktime_to_ns(ktime_get_boottime()); +} + +/* + * RTC specific + */ +extern void timekeeping_inject_sleeptime(struct timespec *delta); + +/* + * PPS accessor + */ +extern void getnstime_raw_and_real(struct timespec *ts_raw, + struct timespec *ts_real); + +/* + * Persistent clock related interfaces + */ +extern bool persistent_clock_exist; +extern int persistent_clock_is_local; + +static inline bool has_persistent_clock(void) +{ + return persistent_clock_exist; +} + +extern void read_persistent_clock(struct timespec *ts); +extern void read_boot_clock(struct timespec *ts); +extern int update_persistent_clock(struct timespec now); + + +#endif diff --git a/include/linux/timerfd.h b/include/linux/timerfd.h index d3b57fa12225..bd36ce431e32 100644 --- a/include/linux/timerfd.h +++ b/include/linux/timerfd.h @@ -11,6 +11,9 @@ /* For O_CLOEXEC and O_NONBLOCK */ #include +/* For _IO helpers */ +#include + /* * CAREFUL: Check include/asm-generic/fcntl.h when defining * new flags, since they might collide with O_* ones. We want @@ -29,4 +32,6 @@ /* Flags for timerfd_settime. */ #define TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET) +#define TFD_IOC_SET_TICKS _IOW('T', 0, u64) + #endif /* _LINUX_TIMERFD_H */ diff --git a/kernel/Makefile b/kernel/Makefile index f2a8b6246ce9..973a40cf8068 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,12 +3,11 @@ # obj-y = fork.o exec_domain.o panic.o \ - cpu.o exit.o itimer.o time.o softirq.o resource.o \ - sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \ + cpu.o exit.o softirq.o resource.o \ + sysctl.o sysctl_binary.o capability.o ptrace.o user.o \ signal.o sys.o kmod.o workqueue.o pid.o task_work.o \ - extable.o params.o posix-timers.o \ - kthread.o sys_ni.o posix-cpu-timers.o \ - hrtimer.o nsproxy.o \ + extable.o params.o \ + kthread.o sys_ni.o nsproxy.o \ notifier.o ksysfs.o cred.o reboot.o \ async.o range.o groups.o smpboot.o @@ -110,22 +109,6 @@ targets += config_data.h $(obj)/config_data.h: $(obj)/config_data.gz FORCE $(call filechk,ikconfiggz) -$(obj)/time.o: $(obj)/timeconst.h - -quiet_cmd_hzfile = HZFILE $@ - cmd_hzfile = echo "hz=$(CONFIG_HZ)" > $@ - -targets += hz.bc -$(obj)/hz.bc: $(objtree)/include/config/hz.h FORCE - $(call if_changed,hzfile) - -quiet_cmd_bc = BC $@ - cmd_bc = bc -q $(filter-out FORCE,$^) > $@ - -targets += timeconst.h -$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE - $(call if_changed,bc) - ############################################################################### # # Roll all the X.509 certificates that we can find together and pull them into diff --git a/kernel/acct.c b/kernel/acct.c index 808a86ff229d..a1844f14c6d6 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -458,9 +458,7 @@ static void do_acct_process(struct bsd_acct_struct *acct, acct_t ac; mm_segment_t fs; unsigned long flim; - u64 elapsed; - u64 run_time; - struct timespec uptime; + u64 elapsed, run_time; struct tty_struct *tty; const struct cred *orig_cred; @@ -484,10 +482,8 @@ static void do_acct_process(struct bsd_acct_struct *acct, strlcpy(ac.ac_comm, current->comm, sizeof(ac.ac_comm)); /* calculate run_time in nsec*/ - do_posix_clock_monotonic_gettime(&uptime); - run_time = (u64)uptime.tv_sec*NSEC_PER_SEC + uptime.tv_nsec; - run_time -= (u64)current->group_leader->start_time.tv_sec * NSEC_PER_SEC - + current->group_leader->start_time.tv_nsec; + run_time = ktime_get_ns(); + run_time -= current->group_leader->start_time; /* convert nsec -> AHZ */ elapsed = nsec_to_AHZ(run_time); #if ACCT_VERSION==3 diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 2f7c760305ca..379650b984f8 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -2472,7 +2472,7 @@ static void kdb_gmtime(struct timespec *tv, struct kdb_tm *tm) static void kdb_sysinfo(struct sysinfo *val) { struct timespec uptime; - do_posix_clock_monotonic_gettime(&uptime); + ktime_get_ts(&uptime); memset(val, 0, sizeof(*val)); val->uptime = uptime.tv_sec; val->loads[0] = avenrun[0]; diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 54996b71e66d..de699f42f9bc 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -45,16 +45,6 @@ void __delayacct_tsk_init(struct task_struct *tsk) spin_lock_init(&tsk->delays->lock); } -/* - * Start accounting for a delay statistic using - * its starting timestamp (@start) - */ - -static inline void delayacct_start(struct timespec *start) -{ - do_posix_clock_monotonic_gettime(start); -} - /* * Finish delay accounting for a statistic using * its timestamps (@start, @end), accumalator (@total) and @count @@ -67,7 +57,7 @@ static void delayacct_end(struct timespec *start, struct timespec *end, s64 ns; unsigned long flags; - do_posix_clock_monotonic_gettime(end); + ktime_get_ts(end); ts = timespec_sub(*end, *start); ns = timespec_to_ns(&ts); if (ns < 0) @@ -81,7 +71,7 @@ static void delayacct_end(struct timespec *start, struct timespec *end, void __delayacct_blkio_start(void) { - delayacct_start(¤t->delays->blkio_start); + ktime_get_ts(¤t->delays->blkio_start); } void __delayacct_blkio_end(void) @@ -169,7 +159,7 @@ __u64 __delayacct_blkio_ticks(struct task_struct *tsk) void __delayacct_freepages_start(void) { - delayacct_start(¤t->delays->freepages_start); + ktime_get_ts(¤t->delays->freepages_start); } void __delayacct_freepages_end(void) diff --git a/kernel/fork.c b/kernel/fork.c index 6a13c46cd87d..627b7f80afb0 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1262,9 +1262,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, posix_cpu_timers_init(p); - do_posix_clock_monotonic_gettime(&p->start_time); - p->real_start_time = p->start_time; - monotonic_to_bootbased(&p->real_start_time); + p->start_time = ktime_get_ns(); + p->real_start_time = ktime_get_boot_ns(); p->io_context = NULL; p->audit_context = NULL; if (clone_flags & CLONE_THREAD) diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index f448513a45ed..feccfd888732 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig @@ -20,10 +20,6 @@ config GENERIC_TIME_VSYSCALL config GENERIC_TIME_VSYSCALL_OLD bool -# ktime_t scalar 64bit nsec representation -config KTIME_SCALAR - bool - # Old style timekeeping config ARCH_USES_GETTIMEOFFSET bool diff --git a/kernel/time/Makefile b/kernel/time/Makefile index 57a413fd0ebf..7347426fa68d 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -1,3 +1,4 @@ +obj-y += time.o timer.o hrtimer.o itimer.o posix-timers.o posix-cpu-timers.o obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o obj-y += timeconv.o posix-clock.o alarmtimer.o @@ -12,3 +13,21 @@ obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o obj-$(CONFIG_TIMER_STATS) += timer_stats.o obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o +obj-$(CONFIG_TEST_UDELAY) += udelay_test.o + +$(obj)/time.o: $(obj)/timeconst.h + +quiet_cmd_hzfile = HZFILE $@ + cmd_hzfile = echo "hz=$(CONFIG_HZ)" > $@ + +targets += hz.bc +$(obj)/hz.bc: $(objtree)/include/config/hz.h FORCE + $(call if_changed,hzfile) + +quiet_cmd_bc = BC $@ + cmd_bc = bc -q $(filter-out FORCE,$^) > $@ + +targets += timeconst.h +$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE + $(call if_changed,bc) + diff --git a/kernel/hrtimer.c b/kernel/time/hrtimer.c similarity index 94% rename from kernel/hrtimer.c rename to kernel/time/hrtimer.c index 3ab28993f6e0..1c2fe7de2842 100644 --- a/kernel/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -54,6 +54,8 @@ #include +#include "timekeeping.h" + /* * The timer bases: * @@ -114,21 +116,18 @@ static inline int hrtimer_clockid_to_base(clockid_t clock_id) */ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base) { - ktime_t xtim, mono, boot; - struct timespec xts, tom, slp; - s32 tai_offset; + ktime_t xtim, mono, boot, tai; + ktime_t off_real, off_boot, off_tai; - get_xtime_and_monotonic_and_sleep_offset(&xts, &tom, &slp); - tai_offset = timekeeping_get_tai_offset(); + mono = ktime_get_update_offsets_tick(&off_real, &off_boot, &off_tai); + boot = ktime_add(mono, off_boot); + xtim = ktime_add(mono, off_real); + tai = ktime_add(xtim, off_tai); - xtim = timespec_to_ktime(xts); - mono = ktime_add(xtim, timespec_to_ktime(tom)); - boot = ktime_add(mono, timespec_to_ktime(slp)); base->clock_base[HRTIMER_BASE_REALTIME].softirq_time = xtim; base->clock_base[HRTIMER_BASE_MONOTONIC].softirq_time = mono; base->clock_base[HRTIMER_BASE_BOOTTIME].softirq_time = boot; - base->clock_base[HRTIMER_BASE_TAI].softirq_time = - ktime_add(xtim, ktime_set(tai_offset, 0)); + base->clock_base[HRTIMER_BASE_TAI].softirq_time = tai; } /* @@ -264,60 +263,6 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) * too large for inlining: */ #if BITS_PER_LONG < 64 -# ifndef CONFIG_KTIME_SCALAR -/** - * ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable - * @kt: addend - * @nsec: the scalar nsec value to add - * - * Returns the sum of kt and nsec in ktime_t format - */ -ktime_t ktime_add_ns(const ktime_t kt, u64 nsec) -{ - ktime_t tmp; - - if (likely(nsec < NSEC_PER_SEC)) { - tmp.tv64 = nsec; - } else { - unsigned long rem = do_div(nsec, NSEC_PER_SEC); - - /* Make sure nsec fits into long */ - if (unlikely(nsec > KTIME_SEC_MAX)) - return (ktime_t){ .tv64 = KTIME_MAX }; - - tmp = ktime_set((long)nsec, rem); - } - - return ktime_add(kt, tmp); -} - -EXPORT_SYMBOL_GPL(ktime_add_ns); - -/** - * ktime_sub_ns - Subtract a scalar nanoseconds value from a ktime_t variable - * @kt: minuend - * @nsec: the scalar nsec value to subtract - * - * Returns the subtraction of @nsec from @kt in ktime_t format - */ -ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec) -{ - ktime_t tmp; - - if (likely(nsec < NSEC_PER_SEC)) { - tmp.tv64 = nsec; - } else { - unsigned long rem = do_div(nsec, NSEC_PER_SEC); - - tmp = ktime_set((long)nsec, rem); - } - - return ktime_sub(kt, tmp); -} - -EXPORT_SYMBOL_GPL(ktime_sub_ns); -# endif /* !CONFIG_KTIME_SCALAR */ - /* * Divide a ktime value by a nanosecond value */ @@ -337,6 +282,7 @@ u64 ktime_divns(const ktime_t kt, s64 div) return dclc; } +EXPORT_SYMBOL_GPL(ktime_divns); #endif /* BITS_PER_LONG >= 64 */ /* @@ -602,6 +548,11 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal) * timers, we have to check, whether it expires earlier than the timer for * which the clock event device was armed. * + * Note, that in case the state has HRTIMER_STATE_CALLBACK set, no reprogramming + * and no expiry check happens. The timer gets enqueued into the rbtree. The + * reprogramming and expiry check is done in the hrtimer_interrupt or in the + * softirq. + * * Called with interrupts disabled and base->cpu_base.lock held */ static int hrtimer_reprogram(struct hrtimer *timer, @@ -662,25 +613,13 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) base->hres_active = 0; } -/* - * When High resolution timers are active, try to reprogram. Note, that in case - * the state has HRTIMER_STATE_CALLBACK set, no reprogramming and no expiry - * check happens. The timer gets enqueued into the rbtree. The reprogramming - * and expiry check is done in the hrtimer_interrupt or in the softirq. - */ -static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base) -{ - return base->cpu_base->hres_active && hrtimer_reprogram(timer, base); -} - static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) { ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset; ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset; ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset; - return ktime_get_update_offsets(offs_real, offs_boot, offs_tai); + return ktime_get_update_offsets_now(offs_real, offs_boot, offs_tai); } /* @@ -755,8 +694,8 @@ static inline int hrtimer_is_hres_enabled(void) { return 0; } static inline int hrtimer_switch_to_hres(void) { return 0; } static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } -static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base) +static inline int hrtimer_reprogram(struct hrtimer *timer, + struct hrtimer_clock_base *base) { return 0; } @@ -1013,14 +952,25 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, leftmost = enqueue_hrtimer(timer, new_base); - /* - * Only allow reprogramming if the new base is on this CPU. - * (it might still be on another CPU if the timer was pending) - * - * XXX send_remote_softirq() ? - */ - if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases) - && hrtimer_enqueue_reprogram(timer, new_base)) { + if (!leftmost) { + unlock_hrtimer_base(timer, &flags); + return ret; + } + + if (!hrtimer_is_hres_active(timer)) { + /* + * Kick to reschedule the next tick to handle the new timer + * on dynticks target. + */ + wake_up_nohz_cpu(new_base->cpu_base->cpu); + } else if (new_base->cpu_base == &__get_cpu_var(hrtimer_bases) && + hrtimer_reprogram(timer, new_base)) { + /* + * Only allow reprogramming if the new base is on this CPU. + * (it might still be on another CPU if the timer was pending) + * + * XXX send_remote_softirq() ? + */ if (wakeup) { /* * We need to drop cpu_base->lock to avoid a @@ -1680,6 +1630,7 @@ static void init_hrtimers_cpu(int cpu) timerqueue_init_head(&cpu_base->clock_base[i].active); } + cpu_base->cpu = cpu; hrtimer_init_hres(cpu_base); } diff --git a/kernel/itimer.c b/kernel/time/itimer.c similarity index 100% rename from kernel/itimer.c rename to kernel/time/itimer.c diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 33db43a39515..87a346fd6d61 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -466,7 +466,8 @@ static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); static void sync_cmos_clock(struct work_struct *work) { - struct timespec now, next; + struct timespec64 now; + struct timespec next; int fail = 1; /* @@ -485,9 +486,9 @@ static void sync_cmos_clock(struct work_struct *work) return; } - getnstimeofday(&now); + getnstimeofday64(&now); if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec * 5) { - struct timespec adjust = now; + struct timespec adjust = timespec64_to_timespec(now); fail = -ENODEV; if (persistent_clock_is_local) @@ -531,7 +532,7 @@ void ntp_notify_cmos_timer(void) { } /* * Propagate a new txc->status value into the NTP state: */ -static inline void process_adj_status(struct timex *txc, struct timespec *ts) +static inline void process_adj_status(struct timex *txc, struct timespec64 *ts) { if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) { time_state = TIME_OK; @@ -554,7 +555,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts) static inline void process_adjtimex_modes(struct timex *txc, - struct timespec *ts, + struct timespec64 *ts, s32 *time_tai) { if (txc->modes & ADJ_STATUS) @@ -640,7 +641,7 @@ int ntp_validate_timex(struct timex *txc) * adjtimex mainly allows reading (and writing, if superuser) of * kernel time-keeping variables. used by xntpd. */ -int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai) +int __do_adjtimex(struct timex *txc, struct timespec64 *ts, s32 *time_tai) { int result; @@ -684,7 +685,7 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai) /* fill PPS status fields */ pps_fill_timex(txc); - txc->time.tv_sec = ts->tv_sec; + txc->time.tv_sec = (time_t)ts->tv_sec; txc->time.tv_usec = ts->tv_nsec; if (!(time_status & STA_NANO)) txc->time.tv_usec /= NSEC_PER_USEC; diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h index 1950cb4ca2a4..bbd102ad9df7 100644 --- a/kernel/time/ntp_internal.h +++ b/kernel/time/ntp_internal.h @@ -7,6 +7,6 @@ extern void ntp_clear(void); extern u64 ntp_tick_length(void); extern int second_overflow(unsigned long secs); extern int ntp_validate_timex(struct timex *); -extern int __do_adjtimex(struct timex *, struct timespec *, s32 *); +extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *); extern void __hardpps(const struct timespec *, const struct timespec *); #endif /* _LINUX_NTP_INTERNAL_H */ diff --git a/kernel/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c similarity index 100% rename from kernel/posix-cpu-timers.c rename to kernel/time/posix-cpu-timers.c diff --git a/kernel/posix-timers.c b/kernel/time/posix-timers.c similarity index 99% rename from kernel/posix-timers.c rename to kernel/time/posix-timers.c index 424c2d4265c9..42b463ad90f2 100644 --- a/kernel/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -49,6 +49,8 @@ #include #include +#include "timekeeping.h" + /* * Management arrays for POSIX timers. Timers are now kept in static hash table * with 512 entries. diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 7ab92b19965a..c19c1d84b6f3 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h @@ -4,6 +4,8 @@ #include #include +#include "timekeeping.h" + extern seqlock_t jiffies_lock; #define CS_NAME_LEN 32 diff --git a/kernel/time.c b/kernel/time/time.c similarity index 92% rename from kernel/time.c rename to kernel/time/time.c index 7c7964c33ae7..f0294ba14634 100644 --- a/kernel/time.c +++ b/kernel/time/time.c @@ -42,6 +42,7 @@ #include #include "timeconst.h" +#include "timekeeping.h" /* * The timezone where the local system is located. Used as a default by some @@ -420,6 +421,68 @@ struct timeval ns_to_timeval(const s64 nsec) } EXPORT_SYMBOL(ns_to_timeval); +#if BITS_PER_LONG == 32 +/** + * set_normalized_timespec - set timespec sec and nsec parts and normalize + * + * @ts: pointer to timespec variable to be set + * @sec: seconds to set + * @nsec: nanoseconds to set + * + * Set seconds and nanoseconds field of a timespec variable and + * normalize to the timespec storage format + * + * Note: The tv_nsec part is always in the range of + * 0 <= tv_nsec < NSEC_PER_SEC + * For negative values only the tv_sec field is negative ! + */ +void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec) +{ + while (nsec >= NSEC_PER_SEC) { + /* + * The following asm() prevents the compiler from + * optimising this loop into a modulo operation. See + * also __iter_div_u64_rem() in include/linux/time.h + */ + asm("" : "+rm"(nsec)); + nsec -= NSEC_PER_SEC; + ++sec; + } + while (nsec < 0) { + asm("" : "+rm"(nsec)); + nsec += NSEC_PER_SEC; + --sec; + } + ts->tv_sec = sec; + ts->tv_nsec = nsec; +} +EXPORT_SYMBOL(set_normalized_timespec64); + +/** + * ns_to_timespec64 - Convert nanoseconds to timespec64 + * @nsec: the nanoseconds value to be converted + * + * Returns the timespec64 representation of the nsec parameter. + */ +struct timespec64 ns_to_timespec64(const s64 nsec) +{ + struct timespec64 ts; + s32 rem; + + if (!nsec) + return (struct timespec64) {0, 0}; + + ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem); + if (unlikely(rem < 0)) { + ts.tv_sec--; + rem += NSEC_PER_SEC; + } + ts.tv_nsec = rem; + + return ts; +} +EXPORT_SYMBOL(ns_to_timespec64); +#endif /* * When we convert to jiffies then we interpret incoming values * the following way: @@ -694,6 +757,7 @@ unsigned long nsecs_to_jiffies(u64 n) { return (unsigned long)nsecs_to_jiffies64(n); } +EXPORT_SYMBOL_GPL(nsecs_to_jiffies); /* * Add two timespec values and do a safety check for overflow. diff --git a/kernel/timeconst.bc b/kernel/time/timeconst.bc similarity index 100% rename from kernel/timeconst.bc rename to kernel/time/timeconst.bc diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 32d8d6aaedb8..f7378eaebe67 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -32,9 +32,16 @@ #define TK_MIRROR (1 << 1) #define TK_CLOCK_WAS_SET (1 << 2) -static struct timekeeper timekeeper; +/* + * The most important data for readout fits into a single 64 byte + * cache line. + */ +static struct { + seqcount_t seq; + struct timekeeper timekeeper; +} tk_core ____cacheline_aligned; + static DEFINE_RAW_SPINLOCK(timekeeper_lock); -static seqcount_t timekeeper_seq; static struct timekeeper shadow_timekeeper; /* flag for if timekeeping is suspended */ @@ -51,43 +58,52 @@ static inline void tk_normalize_xtime(struct timekeeper *tk) } } -static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts) +static inline struct timespec64 tk_xtime(struct timekeeper *tk) +{ + struct timespec64 ts; + + ts.tv_sec = tk->xtime_sec; + ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); + return ts; +} + +static void tk_set_xtime(struct timekeeper *tk, const struct timespec64 *ts) { tk->xtime_sec = ts->tv_sec; tk->xtime_nsec = (u64)ts->tv_nsec << tk->shift; } -static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts) +static void tk_xtime_add(struct timekeeper *tk, const struct timespec64 *ts) { tk->xtime_sec += ts->tv_sec; tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift; tk_normalize_xtime(tk); } -static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) +static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm) { - struct timespec tmp; + struct timespec64 tmp; /* * Verify consistency of: offset_real = -wall_to_monotonic * before modifying anything */ - set_normalized_timespec(&tmp, -tk->wall_to_monotonic.tv_sec, + set_normalized_timespec64(&tmp, -tk->wall_to_monotonic.tv_sec, -tk->wall_to_monotonic.tv_nsec); - WARN_ON_ONCE(tk->offs_real.tv64 != timespec_to_ktime(tmp).tv64); + WARN_ON_ONCE(tk->offs_real.tv64 != timespec64_to_ktime(tmp).tv64); tk->wall_to_monotonic = wtm; - set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec); - tk->offs_real = timespec_to_ktime(tmp); + set_normalized_timespec64(&tmp, -wtm.tv_sec, -wtm.tv_nsec); + tk->offs_real = timespec64_to_ktime(tmp); tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tk->tai_offset, 0)); } -static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) +static void tk_set_sleep_time(struct timekeeper *tk, struct timespec64 t) { /* Verify consistency before modifying */ - WARN_ON_ONCE(tk->offs_boot.tv64 != timespec_to_ktime(tk->total_sleep_time).tv64); + WARN_ON_ONCE(tk->offs_boot.tv64 != timespec64_to_ktime(tk->total_sleep_time).tv64); tk->total_sleep_time = t; - tk->offs_boot = timespec_to_ktime(t); + tk->offs_boot = timespec64_to_ktime(t); } /** @@ -153,16 +169,10 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock) /* Timekeeper helper functions. */ #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET -u32 (*arch_gettimeoffset)(void); - -u32 get_arch_timeoffset(void) -{ - if (likely(arch_gettimeoffset)) - return arch_gettimeoffset(); - return 0; -} +static u32 default_arch_gettimeoffset(void) { return 0; } +u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset; #else -static inline u32 get_arch_timeoffset(void) { return 0; } +static inline u32 arch_gettimeoffset(void) { return 0; } #endif static inline s64 timekeeping_get_ns(struct timekeeper *tk) @@ -182,7 +192,7 @@ static inline s64 timekeeping_get_ns(struct timekeeper *tk) nsec >>= tk->shift; /* If arch requires, add in get_arch_timeoffset() */ - return nsec + get_arch_timeoffset(); + return nsec + arch_gettimeoffset(); } static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) @@ -202,9 +212,43 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift); /* If arch requires, add in get_arch_timeoffset() */ - return nsec + get_arch_timeoffset(); + return nsec + arch_gettimeoffset(); } +#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD + +static inline void update_vsyscall(struct timekeeper *tk) +{ + struct timespec xt; + + xt = tk_xtime(tk); + update_vsyscall_old(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult); +} + +static inline void old_vsyscall_fixup(struct timekeeper *tk) +{ + s64 remainder; + + /* + * Store only full nanoseconds into xtime_nsec after rounding + * it up and add the remainder to the error difference. + * XXX - This is necessary to avoid small 1ns inconsistnecies caused + * by truncating the remainder in vsyscalls. However, it causes + * additional work to be done in timekeeping_adjust(). Once + * the vsyscall implementations are converted to use xtime_nsec + * (shifted nanoseconds), and CONFIG_GENERIC_TIME_VSYSCALL_OLD + * users are removed, this can be killed. + */ + remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); + tk->xtime_nsec -= remainder; + tk->xtime_nsec += 1ULL << tk->shift; + tk->ntp_error += remainder << tk->ntp_error_shift; + tk->ntp_error -= (1ULL << tk->shift) << tk->ntp_error_shift; +} +#else +#define old_vsyscall_fixup(tk) +#endif + static RAW_NOTIFIER_HEAD(pvclock_gtod_chain); static void update_pvclock_gtod(struct timekeeper *tk, bool was_set) @@ -217,7 +261,7 @@ static void update_pvclock_gtod(struct timekeeper *tk, bool was_set) */ int pvclock_gtod_register_notifier(struct notifier_block *nb) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long flags; int ret; @@ -247,6 +291,26 @@ int pvclock_gtod_unregister_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); +/* + * Update the ktime_t based scalar nsec members of the timekeeper + */ +static inline void tk_update_ktime_data(struct timekeeper *tk) +{ + s64 nsec; + + /* + * The xtime based monotonic readout is: + * nsec = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec + now(); + * The ktime based monotonic readout is: + * nsec = base_mono + now(); + * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec + */ + nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); + nsec *= NSEC_PER_SEC; + nsec += tk->wall_to_monotonic.tv_nsec; + tk->base_mono = ns_to_ktime(nsec); +} + /* must hold timekeeper_lock */ static void timekeeping_update(struct timekeeper *tk, unsigned int action) { @@ -257,8 +321,11 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) update_vsyscall(tk); update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET); + tk_update_ktime_data(tk); + if (action & TK_MIRROR) - memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); + memcpy(&shadow_timekeeper, &tk_core.timekeeper, + sizeof(tk_core.timekeeper)); } /** @@ -282,37 +349,37 @@ static void timekeeping_forward_now(struct timekeeper *tk) tk->xtime_nsec += cycle_delta * tk->mult; /* If arch requires, add in get_arch_timeoffset() */ - tk->xtime_nsec += (u64)get_arch_timeoffset() << tk->shift; + tk->xtime_nsec += (u64)arch_gettimeoffset() << tk->shift; tk_normalize_xtime(tk); nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift); - timespec_add_ns(&tk->raw_time, nsec); + timespec64_add_ns(&tk->raw_time, nsec); } /** - * __getnstimeofday - Returns the time of day in a timespec. + * __getnstimeofday64 - Returns the time of day in a timespec64. * @ts: pointer to the timespec to be set * * Updates the time of day in the timespec. * Returns 0 on success, or -ve when suspended (timespec will be undefined). */ -int __getnstimeofday(struct timespec *ts) +int __getnstimeofday64(struct timespec64 *ts) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long seq; s64 nsecs = 0; do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); ts->tv_sec = tk->xtime_sec; nsecs = timekeeping_get_ns(tk); - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); ts->tv_nsec = 0; - timespec_add_ns(ts, nsecs); + timespec64_add_ns(ts, nsecs); /* * Do not bail out early, in case there were callers still using @@ -322,72 +389,117 @@ int __getnstimeofday(struct timespec *ts) return -EAGAIN; return 0; } -EXPORT_SYMBOL(__getnstimeofday); +EXPORT_SYMBOL(__getnstimeofday64); /** - * getnstimeofday - Returns the time of day in a timespec. + * getnstimeofday64 - Returns the time of day in a timespec64. * @ts: pointer to the timespec to be set * * Returns the time of day in a timespec (WARN if suspended). */ -void getnstimeofday(struct timespec *ts) +void getnstimeofday64(struct timespec64 *ts) { - WARN_ON(__getnstimeofday(ts)); + WARN_ON(__getnstimeofday64(ts)); } -EXPORT_SYMBOL(getnstimeofday); +EXPORT_SYMBOL(getnstimeofday64); ktime_t ktime_get(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned int seq; - s64 secs, nsecs; + ktime_t base; + s64 nsecs; WARN_ON(timekeeping_suspended); do { - seq = read_seqcount_begin(&timekeeper_seq); - secs = tk->xtime_sec + tk->wall_to_monotonic.tv_sec; - nsecs = timekeeping_get_ns(tk) + tk->wall_to_monotonic.tv_nsec; + seq = read_seqcount_begin(&tk_core.seq); + base = tk->base_mono; + nsecs = timekeeping_get_ns(tk); - } while (read_seqcount_retry(&timekeeper_seq, seq)); - /* - * Use ktime_set/ktime_add_ns to create a proper ktime on - * 32-bit architectures without CONFIG_KTIME_SCALAR. - */ - return ktime_add_ns(ktime_set(secs, 0), nsecs); + } while (read_seqcount_retry(&tk_core.seq, seq)); + + return ktime_add_ns(base, nsecs); } EXPORT_SYMBOL_GPL(ktime_get); +static ktime_t *offsets[TK_OFFS_MAX] = { + [TK_OFFS_REAL] = &tk_core.timekeeper.offs_real, + [TK_OFFS_BOOT] = &tk_core.timekeeper.offs_boot, + [TK_OFFS_TAI] = &tk_core.timekeeper.offs_tai, +}; + +ktime_t ktime_get_with_offset(enum tk_offsets offs) +{ + struct timekeeper *tk = &tk_core.timekeeper; + unsigned int seq; + ktime_t base, *offset = offsets[offs]; + s64 nsecs; + + WARN_ON(timekeeping_suspended); + + do { + seq = read_seqcount_begin(&tk_core.seq); + base = ktime_add(tk->base_mono, *offset); + nsecs = timekeeping_get_ns(tk); + + } while (read_seqcount_retry(&tk_core.seq, seq)); + + return ktime_add_ns(base, nsecs); + +} +EXPORT_SYMBOL_GPL(ktime_get_with_offset); + /** - * ktime_get_ts - get the monotonic clock in timespec format + * ktime_mono_to_any() - convert mononotic time to any other time + * @tmono: time to convert. + * @offs: which offset to use + */ +ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs) +{ + ktime_t *offset = offsets[offs]; + unsigned long seq; + ktime_t tconv; + + do { + seq = read_seqcount_begin(&tk_core.seq); + tconv = ktime_add(tmono, *offset); + } while (read_seqcount_retry(&tk_core.seq, seq)); + + return tconv; +} +EXPORT_SYMBOL_GPL(ktime_mono_to_any); + +/** + * ktime_get_ts64 - get the monotonic clock in timespec64 format * @ts: pointer to timespec variable * * The function calculates the monotonic clock from the realtime * clock and the wall_to_monotonic offset and stores the result * in normalized timespec format in the variable pointed to by @ts. */ -void ktime_get_ts(struct timespec *ts) +void ktime_get_ts64(struct timespec64 *ts) { - struct timekeeper *tk = &timekeeper; - struct timespec tomono; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 tomono; s64 nsec; unsigned int seq; WARN_ON(timekeeping_suspended); do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); ts->tv_sec = tk->xtime_sec; nsec = timekeeping_get_ns(tk); tomono = tk->wall_to_monotonic; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); ts->tv_sec += tomono.tv_sec; ts->tv_nsec = 0; - timespec_add_ns(ts, nsec + tomono.tv_nsec); + timespec64_add_ns(ts, nsec + tomono.tv_nsec); } -EXPORT_SYMBOL_GPL(ktime_get_ts); +EXPORT_SYMBOL_GPL(ktime_get_ts64); /** @@ -398,41 +510,28 @@ EXPORT_SYMBOL_GPL(ktime_get_ts); */ void timekeeping_clocktai(struct timespec *ts) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 ts64; unsigned long seq; u64 nsecs; WARN_ON(timekeeping_suspended); do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); - ts->tv_sec = tk->xtime_sec + tk->tai_offset; + ts64.tv_sec = tk->xtime_sec + tk->tai_offset; nsecs = timekeeping_get_ns(tk); - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); - ts->tv_nsec = 0; - timespec_add_ns(ts, nsecs); + ts64.tv_nsec = 0; + timespec64_add_ns(&ts64, nsecs); + *ts = timespec64_to_timespec(ts64); } EXPORT_SYMBOL(timekeeping_clocktai); - -/** - * ktime_get_clocktai - Returns the TAI time of day in a ktime - * - * Returns the time of day in a ktime. - */ -ktime_t ktime_get_clocktai(void) -{ - struct timespec ts; - - timekeeping_clocktai(&ts); - return timespec_to_ktime(ts); -} -EXPORT_SYMBOL(ktime_get_clocktai); - #ifdef CONFIG_NTP_PPS /** @@ -446,23 +545,23 @@ EXPORT_SYMBOL(ktime_get_clocktai); */ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long seq; s64 nsecs_raw, nsecs_real; WARN_ON_ONCE(timekeeping_suspended); do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); - *ts_raw = tk->raw_time; + *ts_raw = timespec64_to_timespec(tk->raw_time); ts_real->tv_sec = tk->xtime_sec; ts_real->tv_nsec = 0; nsecs_raw = timekeeping_get_ns_raw(tk); nsecs_real = timekeeping_get_ns(tk); - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); timespec_add_ns(ts_raw, nsecs_raw); timespec_add_ns(ts_real, nsecs_real); @@ -479,9 +578,9 @@ EXPORT_SYMBOL(getnstime_raw_and_real); */ void do_gettimeofday(struct timeval *tv) { - struct timespec now; + struct timespec64 now; - getnstimeofday(&now); + getnstimeofday64(&now); tv->tv_sec = now.tv_sec; tv->tv_usec = now.tv_nsec/1000; } @@ -495,15 +594,15 @@ EXPORT_SYMBOL(do_gettimeofday); */ int do_settimeofday(const struct timespec *tv) { - struct timekeeper *tk = &timekeeper; - struct timespec ts_delta, xt; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 ts_delta, xt, tmp; unsigned long flags; if (!timespec_valid_strict(tv)) return -EINVAL; raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); timekeeping_forward_now(tk); @@ -511,13 +610,14 @@ int do_settimeofday(const struct timespec *tv) ts_delta.tv_sec = tv->tv_sec - xt.tv_sec; ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec; - tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, ts_delta)); + tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta)); - tk_set_xtime(tk, tv); + tmp = timespec_to_timespec64(*tv); + tk_set_xtime(tk, &tmp); timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); /* signal hrtimers about time change */ @@ -535,33 +635,35 @@ EXPORT_SYMBOL(do_settimeofday); */ int timekeeping_inject_offset(struct timespec *ts) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long flags; - struct timespec tmp; + struct timespec64 ts64, tmp; int ret = 0; if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) return -EINVAL; + ts64 = timespec_to_timespec64(*ts); + raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); timekeeping_forward_now(tk); /* Make sure the proposed value is valid */ - tmp = timespec_add(tk_xtime(tk), *ts); - if (!timespec_valid_strict(&tmp)) { + tmp = timespec64_add(tk_xtime(tk), ts64); + if (!timespec64_valid_strict(&tmp)) { ret = -EINVAL; goto error; } - tk_xtime_add(tk, ts); - tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); + tk_xtime_add(tk, &ts64); + tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts64)); error: /* even if we error out, we forwarded the time, so call update */ timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); /* signal hrtimers about time change */ @@ -578,14 +680,14 @@ EXPORT_SYMBOL(timekeeping_inject_offset); */ s32 timekeeping_get_tai_offset(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned int seq; s32 ret; do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); ret = tk->tai_offset; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); return ret; } @@ -606,14 +708,14 @@ static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) */ void timekeeping_set_tai_offset(s32 tai_offset) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long flags; raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); __timekeeping_set_tai_offset(tk, tai_offset); timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); clock_was_set(); } @@ -625,14 +727,14 @@ void timekeeping_set_tai_offset(s32 tai_offset) */ static int change_clocksource(void *data) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; struct clocksource *new, *old; unsigned long flags; new = (struct clocksource *) data; raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); timekeeping_forward_now(tk); /* @@ -652,7 +754,7 @@ static int change_clocksource(void *data) } timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); return 0; @@ -667,7 +769,7 @@ static int change_clocksource(void *data) */ int timekeeping_notify(struct clocksource *clock) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; if (tk->clock == clock) return 0; @@ -676,21 +778,6 @@ int timekeeping_notify(struct clocksource *clock) return tk->clock == clock ? 0 : -1; } -/** - * ktime_get_real - get the real (wall-) time in ktime_t format - * - * returns the time in ktime_t format - */ -ktime_t ktime_get_real(void) -{ - struct timespec now; - - getnstimeofday(&now); - - return timespec_to_ktime(now); -} -EXPORT_SYMBOL_GPL(ktime_get_real); - /** * getrawmonotonic - Returns the raw monotonic time in a timespec * @ts: pointer to the timespec to be set @@ -699,18 +786,20 @@ EXPORT_SYMBOL_GPL(ktime_get_real); */ void getrawmonotonic(struct timespec *ts) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 ts64; unsigned long seq; s64 nsecs; do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); nsecs = timekeeping_get_ns_raw(tk); - *ts = tk->raw_time; + ts64 = tk->raw_time; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); - timespec_add_ns(ts, nsecs); + timespec64_add_ns(&ts64, nsecs); + *ts = timespec64_to_timespec(ts64); } EXPORT_SYMBOL(getrawmonotonic); @@ -719,16 +808,16 @@ EXPORT_SYMBOL(getrawmonotonic); */ int timekeeping_valid_for_hres(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long seq; int ret; do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); ret = tk->clock->flags & CLOCK_SOURCE_VALID_FOR_HRES; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); return ret; } @@ -738,16 +827,16 @@ int timekeeping_valid_for_hres(void) */ u64 timekeeping_max_deferment(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long seq; u64 ret; do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); ret = tk->clock->max_idle_ns; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); return ret; } @@ -787,14 +876,15 @@ void __weak read_boot_clock(struct timespec *ts) */ void __init timekeeping_init(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; struct clocksource *clock; unsigned long flags; - struct timespec now, boot, tmp; + struct timespec64 now, boot, tmp; + struct timespec ts; - read_persistent_clock(&now); - - if (!timespec_valid_strict(&now)) { + read_persistent_clock(&ts); + now = timespec_to_timespec64(ts); + if (!timespec64_valid_strict(&now)) { pr_warn("WARNING: Persistent clock returned invalid value!\n" " Check your CMOS/BIOS settings.\n"); now.tv_sec = 0; @@ -802,8 +892,9 @@ void __init timekeeping_init(void) } else if (now.tv_sec || now.tv_nsec) persistent_clock_exist = true; - read_boot_clock(&boot); - if (!timespec_valid_strict(&boot)) { + read_boot_clock(&ts); + boot = timespec_to_timespec64(ts); + if (!timespec64_valid_strict(&boot)) { pr_warn("WARNING: Boot clock returned invalid value!\n" " Check your CMOS/BIOS settings.\n"); boot.tv_sec = 0; @@ -811,7 +902,7 @@ void __init timekeeping_init(void) } raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); ntp_init(); clock = clocksource_default_clock(); @@ -825,21 +916,21 @@ void __init timekeeping_init(void) if (boot.tv_sec == 0 && boot.tv_nsec == 0) boot = tk_xtime(tk); - set_normalized_timespec(&tmp, -boot.tv_sec, -boot.tv_nsec); + set_normalized_timespec64(&tmp, -boot.tv_sec, -boot.tv_nsec); tk_set_wall_to_mono(tk, tmp); tmp.tv_sec = 0; tmp.tv_nsec = 0; tk_set_sleep_time(tk, tmp); - memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); + timekeeping_update(tk, TK_MIRROR); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); } /* time in seconds when suspend began */ -static struct timespec timekeeping_suspend_time; +static struct timespec64 timekeeping_suspend_time; /** * __timekeeping_inject_sleeptime - Internal function to add sleep interval @@ -849,17 +940,17 @@ static struct timespec timekeeping_suspend_time; * adds the sleep offset to the timekeeping variables. */ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, - struct timespec *delta) + struct timespec64 *delta) { - if (!timespec_valid_strict(delta)) { + if (!timespec64_valid_strict(delta)) { printk_deferred(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid " "sleep delta value!\n"); return; } tk_xtime_add(tk, delta); - tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *delta)); - tk_set_sleep_time(tk, timespec_add(tk->total_sleep_time, *delta)); + tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, *delta)); + tk_set_sleep_time(tk, timespec64_add(tk->total_sleep_time, *delta)); tk_debug_account_sleep_time(delta); } @@ -875,7 +966,8 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, */ void timekeeping_inject_sleeptime(struct timespec *delta) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 tmp; unsigned long flags; /* @@ -886,15 +978,16 @@ void timekeeping_inject_sleeptime(struct timespec *delta) return; raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); timekeeping_forward_now(tk); - __timekeeping_inject_sleeptime(tk, delta); + tmp = timespec_to_timespec64(*delta); + __timekeeping_inject_sleeptime(tk, &tmp); timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); /* signal hrtimers about time change */ @@ -910,20 +1003,22 @@ void timekeeping_inject_sleeptime(struct timespec *delta) */ static void timekeeping_resume(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; struct clocksource *clock = tk->clock; unsigned long flags; - struct timespec ts_new, ts_delta; + struct timespec64 ts_new, ts_delta; + struct timespec tmp; cycle_t cycle_now, cycle_delta; bool suspendtime_found = false; - read_persistent_clock(&ts_new); + read_persistent_clock(&tmp); + ts_new = timespec_to_timespec64(tmp); clockevents_resume(); clocksource_resume(); raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); /* * After system resumes, we need to calculate the suspended time and @@ -960,10 +1055,10 @@ static void timekeeping_resume(void) } nsec += ((u64) cycle_delta * mult) >> shift; - ts_delta = ns_to_timespec(nsec); + ts_delta = ns_to_timespec64(nsec); suspendtime_found = true; - } else if (timespec_compare(&ts_new, &timekeeping_suspend_time) > 0) { - ts_delta = timespec_sub(ts_new, timekeeping_suspend_time); + } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) { + ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time); suspendtime_found = true; } @@ -975,7 +1070,7 @@ static void timekeeping_resume(void) tk->ntp_error = 0; timekeeping_suspended = 0; timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); touch_softlockup_watchdog(); @@ -988,12 +1083,14 @@ static void timekeeping_resume(void) static int timekeeping_suspend(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long flags; - struct timespec delta, delta_delta; - static struct timespec old_delta; + struct timespec64 delta, delta_delta; + static struct timespec64 old_delta; + struct timespec tmp; - read_persistent_clock(&timekeeping_suspend_time); + read_persistent_clock(&tmp); + timekeeping_suspend_time = timespec_to_timespec64(tmp); /* * On some systems the persistent_clock can not be detected at @@ -1004,7 +1101,7 @@ static int timekeeping_suspend(void) persistent_clock_exist = true; raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); timekeeping_forward_now(tk); timekeeping_suspended = 1; @@ -1014,8 +1111,8 @@ static int timekeeping_suspend(void) * try to compensate so the difference in system time * and persistent_clock time stays close to constant. */ - delta = timespec_sub(tk_xtime(tk), timekeeping_suspend_time); - delta_delta = timespec_sub(delta, old_delta); + delta = timespec64_sub(tk_xtime(tk), timekeeping_suspend_time); + delta_delta = timespec64_sub(delta, old_delta); if (abs(delta_delta.tv_sec) >= 2) { /* * if delta_delta is too large, assume time correction @@ -1025,11 +1122,11 @@ static int timekeeping_suspend(void) } else { /* Otherwise try to adjust old_system to compensate */ timekeeping_suspend_time = - timespec_add(timekeeping_suspend_time, delta_delta); + timespec64_add(timekeeping_suspend_time, delta_delta); } timekeeping_update(tk, TK_MIRROR); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL); @@ -1262,14 +1359,14 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) /* Figure out if its a leap sec and apply if needed */ leap = second_overflow(tk->xtime_sec); if (unlikely(leap)) { - struct timespec ts; + struct timespec64 ts; tk->xtime_sec += leap; ts.tv_sec = leap; ts.tv_nsec = 0; tk_set_wall_to_mono(tk, - timespec_sub(tk->wall_to_monotonic, ts)); + timespec64_sub(tk->wall_to_monotonic, ts)); __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); @@ -1324,33 +1421,6 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, return offset; } -#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD -static inline void old_vsyscall_fixup(struct timekeeper *tk) -{ - s64 remainder; - - /* - * Store only full nanoseconds into xtime_nsec after rounding - * it up and add the remainder to the error difference. - * XXX - This is necessary to avoid small 1ns inconsistnecies caused - * by truncating the remainder in vsyscalls. However, it causes - * additional work to be done in timekeeping_adjust(). Once - * the vsyscall implementations are converted to use xtime_nsec - * (shifted nanoseconds), and CONFIG_GENERIC_TIME_VSYSCALL_OLD - * users are removed, this can be killed. - */ - remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); - tk->xtime_nsec -= remainder; - tk->xtime_nsec += 1ULL << tk->shift; - tk->ntp_error += remainder << tk->ntp_error_shift; - tk->ntp_error -= (1ULL << tk->shift) << tk->ntp_error_shift; -} -#else -#define old_vsyscall_fixup(tk) -#endif - - - /** * update_wall_time - Uses the current clocksource to increment the wall time * @@ -1358,7 +1428,7 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk) void update_wall_time(void) { struct clocksource *clock; - struct timekeeper *real_tk = &timekeeper; + struct timekeeper *real_tk = &tk_core.timekeeper; struct timekeeper *tk = &shadow_timekeeper; cycle_t offset; int shift = 0, maxshift; @@ -1418,7 +1488,7 @@ void update_wall_time(void) */ clock_set |= accumulate_nsecs_to_secs(tk); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); /* Update clock->cycle_last with the new value */ clock->cycle_last = tk->cycle_last; /* @@ -1428,12 +1498,12 @@ void update_wall_time(void) * requires changes to all other timekeeper usage sites as * well, i.e. move the timekeeper pointer getter into the * spinlocked/seqcount protected sections. And we trade this - * memcpy under the timekeeper_seq against one before we start + * memcpy under the tk_core.seq against one before we start * updating. */ memcpy(real_tk, tk, sizeof(*tk)); timekeeping_update(real_tk, clock_set); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); out: raw_spin_unlock_irqrestore(&timekeeper_lock, flags); if (clock_set) @@ -1454,7 +1524,7 @@ out: */ void getboottime(struct timespec *ts) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; struct timespec boottime = { .tv_sec = tk->wall_to_monotonic.tv_sec + tk->total_sleep_time.tv_sec, @@ -1477,60 +1547,47 @@ EXPORT_SYMBOL_GPL(getboottime); */ void get_monotonic_boottime(struct timespec *ts) { - struct timekeeper *tk = &timekeeper; - struct timespec tomono, sleep; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 tomono, sleep, ret; s64 nsec; unsigned int seq; WARN_ON(timekeeping_suspended); do { - seq = read_seqcount_begin(&timekeeper_seq); - ts->tv_sec = tk->xtime_sec; + seq = read_seqcount_begin(&tk_core.seq); + ret.tv_sec = tk->xtime_sec; nsec = timekeeping_get_ns(tk); tomono = tk->wall_to_monotonic; sleep = tk->total_sleep_time; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); - ts->tv_sec += tomono.tv_sec + sleep.tv_sec; - ts->tv_nsec = 0; - timespec_add_ns(ts, nsec + tomono.tv_nsec + sleep.tv_nsec); + ret.tv_sec += tomono.tv_sec + sleep.tv_sec; + ret.tv_nsec = 0; + timespec64_add_ns(&ret, nsec + tomono.tv_nsec + sleep.tv_nsec); + *ts = timespec64_to_timespec(ret); } EXPORT_SYMBOL_GPL(get_monotonic_boottime); -/** - * ktime_get_boottime - Returns monotonic time since boot in a ktime - * - * Returns the monotonic time since boot in a ktime - * - * This is similar to CLOCK_MONTONIC/ktime_get, but also - * includes the time spent in suspend. - */ -ktime_t ktime_get_boottime(void) -{ - struct timespec ts; - - get_monotonic_boottime(&ts); - return timespec_to_ktime(ts); -} -EXPORT_SYMBOL_GPL(ktime_get_boottime); - /** * monotonic_to_bootbased - Convert the monotonic time to boot based. * @ts: pointer to the timespec to be converted */ void monotonic_to_bootbased(struct timespec *ts) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 ts64; - *ts = timespec_add(*ts, tk->total_sleep_time); + ts64 = timespec_to_timespec64(*ts); + ts64 = timespec64_add(ts64, tk->total_sleep_time); + *ts = timespec64_to_timespec(ts64); } EXPORT_SYMBOL_GPL(monotonic_to_bootbased); unsigned long get_seconds(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; return tk->xtime_sec; } @@ -1538,43 +1595,44 @@ EXPORT_SYMBOL(get_seconds); struct timespec __current_kernel_time(void) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; - return tk_xtime(tk); + return timespec64_to_timespec(tk_xtime(tk)); } struct timespec current_kernel_time(void) { - struct timekeeper *tk = &timekeeper; - struct timespec now; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 now; unsigned long seq; do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); now = tk_xtime(tk); - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); - return now; + return timespec64_to_timespec(now); } EXPORT_SYMBOL(current_kernel_time); struct timespec get_monotonic_coarse(void) { - struct timekeeper *tk = &timekeeper; - struct timespec now, mono; + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 now, mono; unsigned long seq; do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); now = tk_xtime(tk); mono = tk->wall_to_monotonic; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); - set_normalized_timespec(&now, now.tv_sec + mono.tv_sec, + set_normalized_timespec64(&now, now.tv_sec + mono.tv_sec, now.tv_nsec + mono.tv_nsec); - return now; + + return timespec64_to_timespec(now); } /* @@ -1587,29 +1645,38 @@ void do_timer(unsigned long ticks) } /** - * get_xtime_and_monotonic_and_sleep_offset() - get xtime, wall_to_monotonic, - * and sleep offsets. - * @xtim: pointer to timespec to be set with xtime - * @wtom: pointer to timespec to be set with wall_to_monotonic - * @sleep: pointer to timespec to be set with time in suspend + * ktime_get_update_offsets_tick - hrtimer helper + * @offs_real: pointer to storage for monotonic -> realtime offset + * @offs_boot: pointer to storage for monotonic -> boottime offset + * @offs_tai: pointer to storage for monotonic -> clock tai offset + * + * Returns monotonic time at last tick and various offsets */ -void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, - struct timespec *wtom, struct timespec *sleep) +ktime_t ktime_get_update_offsets_tick(ktime_t *offs_real, ktime_t *offs_boot, + ktime_t *offs_tai) { - struct timekeeper *tk = &timekeeper; - unsigned long seq; + struct timekeeper *tk = &tk_core.timekeeper; + unsigned int seq; + ktime_t base; + u64 nsecs; do { - seq = read_seqcount_begin(&timekeeper_seq); - *xtim = tk_xtime(tk); - *wtom = tk->wall_to_monotonic; - *sleep = tk->total_sleep_time; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + seq = read_seqcount_begin(&tk_core.seq); + + base = tk->base_mono; + nsecs = tk->xtime_nsec >> tk->shift; + + *offs_real = tk->offs_real; + *offs_boot = tk->offs_boot; + *offs_tai = tk->offs_tai; + } while (read_seqcount_retry(&tk_core.seq, seq)); + + return ktime_add_ns(base, nsecs); } #ifdef CONFIG_HIGH_RES_TIMERS /** - * ktime_get_update_offsets - hrtimer helper + * ktime_get_update_offsets_now - hrtimer helper * @offs_real: pointer to storage for monotonic -> realtime offset * @offs_boot: pointer to storage for monotonic -> boottime offset * @offs_tai: pointer to storage for monotonic -> clock tai offset @@ -1617,57 +1684,37 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, * Returns current monotonic time and updates the offsets * Called from hrtimer_interrupt() or retrigger_next_event() */ -ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot, +ktime_t ktime_get_update_offsets_now(ktime_t *offs_real, ktime_t *offs_boot, ktime_t *offs_tai) { - struct timekeeper *tk = &timekeeper; - ktime_t now; + struct timekeeper *tk = &tk_core.timekeeper; unsigned int seq; - u64 secs, nsecs; + ktime_t base; + u64 nsecs; do { - seq = read_seqcount_begin(&timekeeper_seq); + seq = read_seqcount_begin(&tk_core.seq); - secs = tk->xtime_sec; + base = tk->base_mono; nsecs = timekeeping_get_ns(tk); *offs_real = tk->offs_real; *offs_boot = tk->offs_boot; *offs_tai = tk->offs_tai; - } while (read_seqcount_retry(&timekeeper_seq, seq)); + } while (read_seqcount_retry(&tk_core.seq, seq)); - now = ktime_add_ns(ktime_set(secs, 0), nsecs); - now = ktime_sub(now, *offs_real); - return now; + return ktime_add_ns(base, nsecs); } #endif -/** - * ktime_get_monotonic_offset() - get wall_to_monotonic in ktime_t format - */ -ktime_t ktime_get_monotonic_offset(void) -{ - struct timekeeper *tk = &timekeeper; - unsigned long seq; - struct timespec wtom; - - do { - seq = read_seqcount_begin(&timekeeper_seq); - wtom = tk->wall_to_monotonic; - } while (read_seqcount_retry(&timekeeper_seq, seq)); - - return timespec_to_ktime(wtom); -} -EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset); - /** * do_adjtimex() - Accessor function to NTP __do_adjtimex function */ int do_adjtimex(struct timex *txc) { - struct timekeeper *tk = &timekeeper; + struct timekeeper *tk = &tk_core.timekeeper; unsigned long flags; - struct timespec ts; + struct timespec64 ts; s32 orig_tai, tai; int ret; @@ -1687,10 +1734,10 @@ int do_adjtimex(struct timex *txc) return ret; } - getnstimeofday(&ts); + getnstimeofday64(&ts); raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); orig_tai = tai = tk->tai_offset; ret = __do_adjtimex(txc, &ts, &tai); @@ -1699,7 +1746,7 @@ int do_adjtimex(struct timex *txc) __timekeeping_set_tai_offset(tk, tai); timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); } - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); if (tai != orig_tai) @@ -1719,11 +1766,11 @@ void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts) unsigned long flags; raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&timekeeper_seq); + write_seqcount_begin(&tk_core.seq); __hardpps(phase_ts, raw_ts); - write_seqcount_end(&timekeeper_seq); + write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); } EXPORT_SYMBOL(hardpps); diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h new file mode 100644 index 000000000000..adc1fc98bde3 --- /dev/null +++ b/kernel/time/timekeeping.h @@ -0,0 +1,20 @@ +#ifndef _KERNEL_TIME_TIMEKEEPING_H +#define _KERNEL_TIME_TIMEKEEPING_H +/* + * Internal interfaces for kernel/time/ + */ +extern ktime_t ktime_get_update_offsets_tick(ktime_t *offs_real, + ktime_t *offs_boot, + ktime_t *offs_tai); +extern ktime_t ktime_get_update_offsets_now(ktime_t *offs_real, + ktime_t *offs_boot, + ktime_t *offs_tai); + +extern int timekeeping_valid_for_hres(void); +extern u64 timekeeping_max_deferment(void); +extern int timekeeping_inject_offset(struct timespec *ts); +extern s32 timekeeping_get_tai_offset(void); +extern void timekeeping_set_tai_offset(s32 tai_offset); +extern void timekeeping_clocktai(struct timespec *ts); + +#endif diff --git a/kernel/time/timekeeping_debug.c b/kernel/time/timekeeping_debug.c index 4d54f97558df..f6bd65236712 100644 --- a/kernel/time/timekeeping_debug.c +++ b/kernel/time/timekeeping_debug.c @@ -67,7 +67,7 @@ static int __init tk_debug_sleep_time_init(void) } late_initcall(tk_debug_sleep_time_init); -void tk_debug_account_sleep_time(struct timespec *t) +void tk_debug_account_sleep_time(struct timespec64 *t) { sleep_time_bin[fls(t->tv_sec)]++; } diff --git a/kernel/time/timekeeping_internal.h b/kernel/time/timekeeping_internal.h index 13323ea08ffa..e3d28ad236f9 100644 --- a/kernel/time/timekeeping_internal.h +++ b/kernel/time/timekeeping_internal.h @@ -6,7 +6,7 @@ #include #ifdef CONFIG_DEBUG_FS -extern void tk_debug_account_sleep_time(struct timespec *t); +extern void tk_debug_account_sleep_time(struct timespec64 *t); #else #define tk_debug_account_sleep_time(x) #endif diff --git a/kernel/timer.c b/kernel/time/timer.c similarity index 99% rename from kernel/timer.c rename to kernel/time/timer.c index 3bb01a323b2a..aca5dfe2fa3d 100644 --- a/kernel/timer.c +++ b/kernel/time/timer.c @@ -82,6 +82,7 @@ struct tvec_base { unsigned long next_timer; unsigned long active_timers; unsigned long all_timers; + int cpu; struct tvec_root tv1; struct tvec tv2; struct tvec tv3; @@ -409,6 +410,22 @@ static void internal_add_timer(struct tvec_base *base, struct timer_list *timer) base->next_timer = timer->expires; } base->all_timers++; + + /* + * Check whether the other CPU is in dynticks mode and needs + * to be triggered to reevaluate the timer wheel. + * We are protected against the other CPU fiddling + * with the timer by holding the timer base lock. This also + * makes sure that a CPU on the way to stop its tick can not + * evaluate the timer wheel. + * + * Spare the IPI for deferrable timers on idle targets though. + * The next busy ticks will take care of it. Except full dynticks + * require special care against races with idle_cpu(), lets deal + * with that later. + */ + if (!tbase_get_deferrable(base) || tick_nohz_full_cpu(base->cpu)) + wake_up_nohz_cpu(base->cpu); } #ifdef CONFIG_TIMER_STATS @@ -948,22 +965,6 @@ void add_timer_on(struct timer_list *timer, int cpu) timer_set_base(timer, base); debug_activate(timer, timer->expires); internal_add_timer(base, timer); - /* - * Check whether the other CPU is in dynticks mode and needs - * to be triggered to reevaluate the timer wheel. - * We are protected against the other CPU fiddling - * with the timer by holding the timer base lock. This also - * makes sure that a CPU on the way to stop its tick can not - * evaluate the timer wheel. - * - * Spare the IPI for deferrable timers on idle targets though. - * The next busy ticks will take care of it. Except full dynticks - * require special care against races with idle_cpu(), lets deal - * with that later. - */ - if (!tbase_get_deferrable(timer->base) || tick_nohz_full_cpu(cpu)) - wake_up_nohz_cpu(cpu); - spin_unlock_irqrestore(&base->lock, flags); } EXPORT_SYMBOL_GPL(add_timer_on); @@ -1568,6 +1569,7 @@ static int init_timers_cpu(int cpu) } spin_lock_init(&base->lock); tvec_base_done[cpu] = 1; + base->cpu = cpu; } else { base = per_cpu(tvec_bases, cpu); } diff --git a/kernel/time/udelay_test.c b/kernel/time/udelay_test.c new file mode 100644 index 000000000000..e622ba365a13 --- /dev/null +++ b/kernel/time/udelay_test.c @@ -0,0 +1,168 @@ +/* + * udelay() test kernel module + * + * Test is executed by writing and reading to /sys/kernel/debug/udelay_test + * Tests are configured by writing: USECS ITERATIONS + * Tests are executed by reading from the same file. + * Specifying usecs of 0 or negative values will run multiples tests. + * + * Copyright (C) 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include +#include +#include + +#define DEFAULT_ITERATIONS 100 + +#define DEBUGFS_FILENAME "udelay_test" + +static DEFINE_MUTEX(udelay_test_lock); +static struct dentry *udelay_test_debugfs_file; +static int udelay_test_usecs; +static int udelay_test_iterations = DEFAULT_ITERATIONS; + +static int udelay_test_single(struct seq_file *s, int usecs, uint32_t iters) +{ + int min = 0, max = 0, fail_count = 0; + uint64_t sum = 0; + uint64_t avg; + int i; + /* Allow udelay to be up to 0.5% fast */ + int allowed_error_ns = usecs * 5; + + for (i = 0; i < iters; ++i) { + struct timespec ts1, ts2; + int time_passed; + + ktime_get_ts(&ts1); + udelay(usecs); + ktime_get_ts(&ts2); + time_passed = timespec_to_ns(&ts2) - timespec_to_ns(&ts1); + + if (i == 0 || time_passed < min) + min = time_passed; + if (i == 0 || time_passed > max) + max = time_passed; + if ((time_passed + allowed_error_ns) / 1000 < usecs) + ++fail_count; + WARN_ON(time_passed < 0); + sum += time_passed; + } + + avg = sum; + do_div(avg, iters); + seq_printf(s, "%d usecs x %d: exp=%d allowed=%d min=%d avg=%lld max=%d", + usecs, iters, usecs * 1000, + (usecs * 1000) - allowed_error_ns, min, avg, max); + if (fail_count) + seq_printf(s, " FAIL=%d", fail_count); + seq_puts(s, "\n"); + + return 0; +} + +static int udelay_test_show(struct seq_file *s, void *v) +{ + int usecs; + int iters; + int ret = 0; + + mutex_lock(&udelay_test_lock); + usecs = udelay_test_usecs; + iters = udelay_test_iterations; + mutex_unlock(&udelay_test_lock); + + if (usecs > 0 && iters > 0) { + return udelay_test_single(s, usecs, iters); + } else if (usecs == 0) { + struct timespec ts; + + ktime_get_ts(&ts); + seq_printf(s, "udelay() test (lpj=%ld kt=%ld.%09ld)\n", + loops_per_jiffy, ts.tv_sec, ts.tv_nsec); + seq_puts(s, "usage:\n"); + seq_puts(s, "echo USECS [ITERS] > " DEBUGFS_FILENAME "\n"); + seq_puts(s, "cat " DEBUGFS_FILENAME "\n"); + } + + return ret; +} + +static int udelay_test_open(struct inode *inode, struct file *file) +{ + return single_open(file, udelay_test_show, inode->i_private); +} + +static ssize_t udelay_test_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + char lbuf[32]; + int ret; + int usecs; + int iters; + + if (count >= sizeof(lbuf)) + return -EINVAL; + + if (copy_from_user(lbuf, buf, count)) + return -EFAULT; + lbuf[count] = '\0'; + + ret = sscanf(lbuf, "%d %d", &usecs, &iters); + if (ret < 1) + return -EINVAL; + else if (ret < 2) + iters = DEFAULT_ITERATIONS; + + mutex_lock(&udelay_test_lock); + udelay_test_usecs = usecs; + udelay_test_iterations = iters; + mutex_unlock(&udelay_test_lock); + + return count; +} + +static const struct file_operations udelay_test_debugfs_ops = { + .owner = THIS_MODULE, + .open = udelay_test_open, + .read = seq_read, + .write = udelay_test_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init udelay_test_init(void) +{ + mutex_lock(&udelay_test_lock); + udelay_test_debugfs_file = debugfs_create_file(DEBUGFS_FILENAME, + S_IRUSR, NULL, NULL, &udelay_test_debugfs_ops); + mutex_unlock(&udelay_test_lock); + + return 0; +} + +module_init(udelay_test_init); + +static void __exit udelay_test_exit(void) +{ + mutex_lock(&udelay_test_lock); + debugfs_remove(udelay_test_debugfs_file); + mutex_unlock(&udelay_test_lock); +} + +module_exit(udelay_test_exit); + +MODULE_AUTHOR("David Riley "); +MODULE_LICENSE("GPL"); diff --git a/kernel/tsacct.c b/kernel/tsacct.c index a1dd9a1b1327..975cb49e32bf 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c @@ -31,20 +31,19 @@ void bacct_add_tsk(struct user_namespace *user_ns, struct taskstats *stats, struct task_struct *tsk) { const struct cred *tcred; - struct timespec uptime, ts; cputime_t utime, stime, utimescaled, stimescaled; - u64 ac_etime; + u64 delta; BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN); - /* calculate task elapsed time in timespec */ - do_posix_clock_monotonic_gettime(&uptime); - ts = timespec_sub(uptime, tsk->start_time); - /* rebase elapsed time to usec (should never be negative) */ - ac_etime = timespec_to_ns(&ts); - do_div(ac_etime, NSEC_PER_USEC); - stats->ac_etime = ac_etime; - stats->ac_btime = get_seconds() - ts.tv_sec; + /* calculate task elapsed time in nsec */ + delta = ktime_get_ns() - tsk->start_time; + /* Convert to micro seconds */ + do_div(delta, NSEC_PER_USEC); + stats->ac_etime = delta; + /* Convert to seconds for btime */ + do_div(delta, USEC_PER_SEC); + stats->ac_btime = get_seconds() - delta; if (thread_group_leader(tsk)) { stats->ac_exitcode = tsk->exit_code; if (tsk->flags & PF_FORKNOEXEC) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 7a638aa3545b..24a26ad5c99d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1649,6 +1649,15 @@ config TEST_BPF If unsure, say N. +config TEST_UDELAY + tristate "udelay test driver" + default n + help + This builds the "udelay_test" module that helps to make sure + that udelay() is working properly. + + If unsure, say N. + source "samples/Kconfig" source "lib/Kconfig.kgdb" diff --git a/lib/devres.c b/lib/devres.c index f562bf6ff71d..bb632484a860 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -86,8 +86,6 @@ void devm_iounmap(struct device *dev, void __iomem *addr) } EXPORT_SYMBOL(devm_iounmap); -#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err) - /** * devm_ioremap_resource() - check, request region, and ioremap resource * @dev: generic device to handle the resource for diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index c1b00375c9ad..3ffa4f5509d8 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c @@ -155,11 +155,9 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) u8 i; if (!buffer) return NULL; - { - struct timeval tv; - do_gettimeofday(&tv); - tomoyo_convert_time(tv.tv_sec, &stamp); - } + + tomoyo_convert_time(get_seconds(), &stamp); + pos = snprintf(buffer, tomoyo_buffer_len - 1, "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " "granted=%s (global-pid=%u) task={ pid=%u ppid=%u " diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 283862aebdc8..e0fb75052550 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -2267,13 +2267,11 @@ static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT]; */ void tomoyo_update_stat(const u8 index) { - struct timeval tv; - do_gettimeofday(&tv); /* * I don't use atomic operations because race condition is not fatal. */ tomoyo_stat_updated[index]++; - tomoyo_stat_modified[index] = tv.tv_sec; + tomoyo_stat_modified[index] = get_seconds(); } /** diff --git a/tools/time/udelay_test.sh b/tools/time/udelay_test.sh new file mode 100755 index 000000000000..12d46b926917 --- /dev/null +++ b/tools/time/udelay_test.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# udelay() test script +# +# Test is executed by writing and reading to /sys/kernel/debug/udelay_test +# and exercises a variety of delays to ensure that udelay() is delaying +# at least as long as requested (as compared to ktime). +# +# Copyright (C) 2014 Google, Inc. +# +# This software is licensed under the terms of the GNU General Public +# License version 2, as published by the Free Software Foundation, and +# may be copied, distributed, and modified under those terms. +# +# 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. + +MODULE_NAME=udelay_test +UDELAY_PATH=/sys/kernel/debug/udelay_test + +setup() +{ + /sbin/modprobe -q $MODULE_NAME + tmp_file=`mktemp` +} + +test_one() +{ + delay=$1 + echo $delay > $UDELAY_PATH + tee -a $tmp_file < $UDELAY_PATH +} + +cleanup() +{ + if [ -f $tmp_file ]; then + rm $tmp_file + fi + /sbin/modprobe -q -r $MODULE_NAME +} + +trap cleanup EXIT +setup + +# Delay for a variety of times. +# 1..200, 200..500 (by 10), 500..2000 (by 100) +for (( delay = 1; delay < 200; delay += 1 )); do + test_one $delay +done +for (( delay = 200; delay < 500; delay += 10 )); do + test_one $delay +done +for (( delay = 500; delay <= 2000; delay += 100 )); do + test_one $delay +done + +# Search for failures +count=`grep -c FAIL $tmp_file` +if [ $? -eq "0" ]; then + echo "ERROR: $count delays failed to delay long enough" + retcode=1 +fi + +exit $retcode