Merge branches 'timers-core-for-linus' and 'timers-urgent-for-linus' of git://git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Jan 2016 02:06:43 +0000 (18:06 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Jan 2016 02:06:43 +0000 (18:06 -0800)
Pull timer updates - and a leftover fix - from Thomas Gleixner:
 "A rather large (commit wise) update from the timer side:

   - A bulk update to make compile tests work in the clocksource drivers

   - An overhaul of the h8300 timers

   - Some more Y2038 work

   - A few overflow prevention checks in the timekeeping/ntp code

   - The usual pile of fixes and improvements to the various
     clocksource/clockevent drivers and core code"

Also:
 "A single fix for the posix-clock poll code which did not make it into
  4.4"

* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (84 commits)
  clocksource/drivers/acpi_pm: Convert to pr_* macros
  clocksource: Make clocksource validation work for all clocksources
  timekeeping: Cap adjustments so they don't exceed the maxadj value
  ntp: Fix second_overflow's input parameter type to be 64bits
  ntp: Change time_reftime to time64_t and utilize 64bit __ktime_get_real_seconds
  timekeeping: Provide internal function __ktime_get_real_seconds
  clocksource/drivers/h8300: Use ioread / iowrite
  clocksource/drivers/h8300: Initializer cleanup.
  clocksource/drivers/h8300: Simplify delta handling
  clocksource/drivers/h8300: Fix timer not overflow case
  clocksource/drivers/h8300: Change to overflow interrupt
  clocksource/drivers/lpc32: Correct pr_err() output format
  clocksource/drivers/arm_global_timer: Fix suspend resume
  clocksource/drivers/pistachio: Fix wrong calculated clocksource read value
  clockevents/drivers/arm_global_timer: Use writel_relaxed in gt_compare_set
  clocksource/drivers/dw_apb_timer: Inline apbt_readl and apbt_writel
  clocksource/drivers/dw_apb_timer: Use {readl|writel}_relaxed in critical path
  clocksource/drivers/dw_apb_timer: Fix apbt_readl return types
  clocksource/drivers/tango-xtal: Replace code by clocksource_mmio_init
  clocksource/drivers/h8300: Increase the compilation test coverage
  ...

* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  posix-clock: Fix return code on the poll method's error path

38 files changed:
MAINTAINERS
arch/arm/Kconfig
arch/arm/mach-exynos/Kconfig
arch/arm/mach-sti/Kconfig
arch/arm/mach-ux500/Kconfig
arch/h8300/Kconfig
arch/h8300/include/asm/io.h
arch/h8300/kernel/setup.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/acpi_pm.c
drivers/clocksource/arm_global_timer.c
drivers/clocksource/dw_apb_timer.c
drivers/clocksource/dw_apb_timer_of.c
drivers/clocksource/h8300_timer16.c
drivers/clocksource/h8300_timer8.c
drivers/clocksource/h8300_tpu.c
drivers/clocksource/mtk_timer.c
drivers/clocksource/rockchip_timer.c
drivers/clocksource/tango_xtal.c
drivers/clocksource/tegra20_timer.c
drivers/clocksource/time-lpc32xx.c
drivers/clocksource/time-pistachio.c
drivers/clocksource/timer-sun5i.c
drivers/clocksource/vt8500_timer.c
drivers/irqchip/irq-renesas-h8300h.c
include/linux/clocksource.h
include/linux/sched_clock.h
include/linux/time.h
kernel/time/alarmtimer.c
kernel/time/clocksource.c
kernel/time/ntp.c
kernel/time/ntp_internal.h
kernel/time/posix-clock.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/time/timekeeping_internal.h
tools/testing/selftests/timers/clocksource-switch.c

index 026cea8..3cbad0f 100644 (file)
@@ -9364,7 +9364,7 @@ M:        Andreas Noever <andreas.noever@gmail.com>
 S:     Maintained
 F:     drivers/thunderbolt/
 
-TIMEKEEPING, CLOCKSOURCE CORE, NTP
+TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
 M:     John Stultz <john.stultz@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
@@ -9377,6 +9377,7 @@ F:        include/uapi/linux/time.h
 F:     include/uapi/linux/timex.h
 F:     kernel/time/clocksource.c
 F:     kernel/time/time*.c
+F:     kernel/time/alarmtimer.c
 F:     kernel/time/ntp.c
 F:     tools/testing/selftests/timers/
 
index 34e1569..688dc7b 100644 (file)
@@ -611,6 +611,7 @@ config ARCH_PXA
        select AUTO_ZRELADDR
        select COMMON_CLK
        select CLKDEV_LOOKUP
+       select CLKSRC_PXA
        select CLKSRC_MMIO
        select CLKSRC_OF
        select GENERIC_CLOCKEVENTS
@@ -650,6 +651,8 @@ config ARCH_SA1100
        select ARCH_SPARSEMEM_ENABLE
        select CLKDEV_LOOKUP
        select CLKSRC_MMIO
+       select CLKSRC_PXA
+       select CLKSRC_OF if OF
        select CPU_FREQ
        select CPU_SA1100
        select GENERIC_CLOCKEVENTS
index 3a10f1a..ff10539 100644 (file)
@@ -27,6 +27,7 @@ menuconfig ARCH_EXYNOS
        select SRAM
        select THERMAL
        select MFD_SYSCON
+       select CLKSRC_EXYNOS_MCT
        help
          Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
 
index 125865d..12dd1dc 100644 (file)
@@ -3,6 +3,7 @@ menuconfig ARCH_STI
        select ARM_GIC
        select ST_IRQCHIP
        select ARM_GLOBAL_TIMER
+       select CLKSRC_ST_LPC
        select PINCTRL
        select PINCTRL_ST
        select MFD_SYSCON
index c9ac19b..5eacdd6 100644 (file)
@@ -32,6 +32,7 @@ config UX500_SOC_DB8500
        select PINCTRL_AB8540
        select REGULATOR
        select REGULATOR_DB8500_PRCMU
+       select CLKSRC_DBX500_PRCMU
        select PM_GENERIC_DOMAINS if PM
 
 config MACH_MOP500
index dd3ac75..2e20333 100644 (file)
@@ -17,6 +17,7 @@ config H8300
        select HAVE_MEMBLOCK
        select HAVE_DMA_ATTRS
        select CLKSRC_OF
+       select H8300_TMR8
 
 config RWSEM_GENERIC_SPINLOCK
        def_bool y
index bb837cd..f0e14f3 100644 (file)
@@ -3,40 +3,45 @@
 
 #ifdef __KERNEL__
 
-#include <asm-generic/io.h>
-
 /* H8/300 internal I/O functions */
-static inline unsigned char ctrl_inb(unsigned long addr)
+
+#define __raw_readb __raw_readb
+static inline u8 __raw_readb(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned char *)addr;
+       return *(volatile u8 *)addr;
 }
 
-static inline unsigned short ctrl_inw(unsigned long addr)
+#define __raw_readw __raw_readw
+static inline u16 __raw_readw(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned short *)addr;
+       return *(volatile u16 *)addr;
 }
 
-static inline unsigned long ctrl_inl(unsigned long addr)
+#define __raw_readl __raw_readl
+static inline u32  __raw_readl(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned long *)addr;
+       return *(volatile u32 *)addr;
 }
 
-static inline void ctrl_outb(unsigned char b, unsigned long addr)
+#define __raw_writeb __raw_writeb
+static inline void __raw_writeb(u8 b, const volatile void __iomem *addr)
 {
-       *(volatile unsigned char *)addr = b;
+       *(volatile u8 *)addr = b;
 }
 
-static inline void ctrl_outw(unsigned short b, unsigned long addr)
+#define __raw_writew __raw_writew
+static inline void __raw_writew(u16 b, const volatile void __iomem *addr)
 {
-       *(volatile unsigned short *)addr = b;
+       *(volatile u16 *)addr = b;
 }
 
-static inline void ctrl_outl(unsigned long b, unsigned long addr)
+#define __raw_writel __raw_writel
+static inline void __raw_writel(u32 b, const volatile void __iomem *addr)
 {
-       *(volatile unsigned long *)addr = b;
+       *(volatile u32 *)addr = b;
 }
 
-static inline void ctrl_bclr(int b, unsigned char *addr)
+static inline void ctrl_bclr(int b, void __iomem *addr)
 {
        if (__builtin_constant_p(b))
                __asm__("bclr %1,%0" : "+WU"(*addr): "i"(b));
@@ -44,7 +49,7 @@ static inline void ctrl_bclr(int b, unsigned char *addr)
                __asm__("bclr %w1,%0" : "+WU"(*addr): "r"(b));
 }
 
-static inline void ctrl_bset(int b, unsigned char *addr)
+static inline void ctrl_bset(int b, void __iomem *addr)
 {
        if (__builtin_constant_p(b))
                __asm__("bset %1,%0" : "+WU"(*addr): "i"(b));
@@ -52,6 +57,8 @@ static inline void ctrl_bset(int b, unsigned char *addr)
                __asm__("bset %w1,%0" : "+WU"(*addr): "r"(b));
 }
 
+#include <asm-generic/io.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* _H8300_IO_H */
index c772abe..e4985df 100644 (file)
@@ -207,14 +207,14 @@ device_initcall(device_probe);
 #define get_wait(base, addr) ({                \
        int baddr;                      \
        baddr = ((addr) / 0x200000 * 2);                             \
-       w *= (ctrl_inw((unsigned long)(base) + 2) & (3 << baddr)) + 1;  \
+       w *= (readw((base) + 2) & (3 << baddr)) + 1;                 \
        })
 #endif
 #if defined(CONFIG_CPU_H8S)
 #define get_wait(base, addr) ({                \
        int baddr;                      \
        baddr = ((addr) / 0x200000 * 16);                            \
-       w *= (ctrl_inl((unsigned long)(base) + 2) & (7 << baddr)) + 1;  \
+       w *= (readl((base) + 2) & (7 << baddr)) + 1;    \
        })
 #endif
 
@@ -228,8 +228,8 @@ static __init int access_timing(void)
 
        bsc = of_find_compatible_node(NULL, NULL, "renesas,h8300-bsc");
        base = of_iomap(bsc, 0);
-       w = (ctrl_inb((unsigned long)base + 0) & bit)?2:1;
-       if (ctrl_inb((unsigned long)base + 1) & bit)
+       w = (readb(base + 0) & bit)?2:1;
+       if (readb(base + 1) & bit)
                w *= get_wait(base, addr);
        else
                w *= 2;
index 2eb5f0e..b251013 100644 (file)
@@ -28,10 +28,16 @@ config CLKSRC_MMIO
        bool
 
 config DIGICOLOR_TIMER
-       bool
+       bool "Digicolor timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       help
+         Enables the support for the digicolor timer driver.
 
 config DW_APB_TIMER
-       bool
+       bool "DW APB timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       help
+         Enables the support for the dw_apb timer.
 
 config DW_APB_TIMER_OF
        bool
@@ -39,47 +45,77 @@ config DW_APB_TIMER_OF
        select CLKSRC_OF
 
 config ROCKCHIP_TIMER
-       bool
+       bool "Rockchip timer driver" if COMPILE_TEST
+       depends on ARM || ARM64
        select CLKSRC_OF
+       help
+         Enables the support for the rockchip timer driver.
 
 config ARMADA_370_XP_TIMER
-       bool
+       bool "Armada 370 and XP timer driver" if COMPILE_TEST
+       depends on ARM
        select CLKSRC_OF
+       help
+         Enables the support for the Armada 370 and XP timer driver.
 
 config MESON6_TIMER
-       bool
+       bool "Meson6 timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
+       help
+         Enables the support for the Meson6 timer driver.
 
 config ORION_TIMER
+       bool "Orion timer driver" if COMPILE_TEST
+       depends on ARM
        select CLKSRC_OF
        select CLKSRC_MMIO
-       bool
+       help
+         Enables the support for the Orion timer driver
 
 config SUN4I_TIMER
+       bool "Sun4i timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
-       bool
+       help
+         Enables support for the Sun4i timer.
 
 config SUN5I_HSTIMER
+       bool "Sun5i timer driver" if COMPILE_TEST
        select CLKSRC_MMIO
-       bool
+       depends on COMMON_CLK
+       help
+         Enables support the Sun5i timer.
 
 config TEGRA_TIMER
-       bool
+       bool "Tegra timer driver" if COMPILE_TEST
+       depends on ARM
+       help
+         Enables support for the Tegra driver.
 
 config VT8500_TIMER
-       bool
+       bool "VT8500 timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       help
+         Enables support for the VT8500 driver.
 
 config CADENCE_TTC_TIMER
-       bool
+       bool "Cadence TTC timer driver" if COMPILE_TEST
+       depends on COMMON_CLK
+       help
+         Enables support for the cadence ttc driver.
 
 config ASM9260_TIMER
-       bool
+       bool "ASM9260 timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        select CLKSRC_OF
+       help
+         Enables support for the ASM9260 timer.
 
 config CLKSRC_NOMADIK_MTU
-       bool
-       depends on (ARCH_NOMADIK || ARCH_U8500)
+       bool "Nomakdik clocksource driver" if COMPILE_TEST
+       depends on ARM
        select CLKSRC_MMIO
        help
          Support for Multi Timer Unit. MTU provides access
@@ -93,9 +129,8 @@ config CLKSRC_NOMADIK_MTU_SCHED_CLOCK
          Use the Multi Timer Unit as the sched_clock.
 
 config CLKSRC_DBX500_PRCMU
-       bool "Clocksource PRCMU Timer"
-       depends on UX500_SOC_DB8500
-       default y
+       bool "Clocksource PRCMU Timer" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        help
          Use the always on PRCMU Timer as clocksource
 
@@ -116,13 +151,18 @@ config CLKSRC_EFM32
          event device.
 
 config CLKSRC_LPC32XX
-       bool
+       bool "Clocksource for LPC32XX" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        select CLKSRC_OF
+       help
+         Support for the LPC32XX clocksource.
 
 config CLKSRC_PISTACHIO
-       bool
+       bool "Clocksource for Pistachio SoC" if COMPILE_TEST
        select CLKSRC_OF
+       help
+         Enables the clocksource for the Pistachio SoC.
 
 config CLKSRC_TI_32K
        bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST
@@ -199,13 +239,14 @@ config CLKSRC_METAG_GENERIC
          This option enables support for the Meta per-thread timers.
 
 config CLKSRC_EXYNOS_MCT
-       def_bool y if ARCH_EXYNOS
-       depends on !ARM64
+       bool "Exynos multi core timer driver" if COMPILE_TEST
+       depends on ARM
        help
          Support for Multi Core Timer controller on Exynos SoCs.
 
 config CLKSRC_SAMSUNG_PWM
-       bool
+       bool "PWM timer drvier for Samsung S3C, S5P" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        help
          This is a new clocksource driver for the PWM timer found in
          Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver
@@ -213,7 +254,8 @@ config CLKSRC_SAMSUNG_PWM
          needed only on systems that do not have the Exynos MCT available.
 
 config FSL_FTM_TIMER
-       bool
+       bool "Freescale FlexTimer Module driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        help
          Support for Freescale FlexTimer Module (FTM) timer.
 
@@ -226,9 +268,12 @@ config SYS_SUPPORTS_SH_CMT
         bool
 
 config MTK_TIMER
+       bool "Mediatek timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_OF
        select CLKSRC_MMIO
-       bool
+       help
+         Support for Mediatek timer driver.
 
 config SYS_SUPPORTS_SH_MTU2
         bool
@@ -279,7 +324,12 @@ config EM_TIMER_STI
          such as EMEV2 from former NEC Electronics.
 
 config CLKSRC_QCOM
-       bool
+       bool "Qualcomm MSM timer" if COMPILE_TEST
+       depends on ARM
+       select CLKSRC_OF
+       help
+         This enables the clocksource and the per CPU clockevent driver for the
+         Qualcomm SoCs.
 
 config CLKSRC_VERSATILE
        bool "ARM Versatile (Express) reference platforms clock source"
@@ -298,21 +348,40 @@ config CLKSRC_MIPS_GIC
        select CLKSRC_OF
 
 config CLKSRC_TANGO_XTAL
-       bool
+       bool "Clocksource for Tango SoC" if COMPILE_TEST
+       depends on ARM
        select CLKSRC_OF
+       select CLKSRC_MMIO
+       help
+         This enables the clocksource for Tango SoC
 
 config CLKSRC_PXA
-       def_bool y if ARCH_PXA || ARCH_SA1100
-       select CLKSRC_OF if OF
+       bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       select CLKSRC_MMIO
        help
          This enables OST0 support available on PXA and SA-11x0
          platforms.
 
+config H8300_TMR8
+        bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
+        depends on GENERIC_CLOCKEVENTS
+       help
+         This enables the 8 bits timer for the H8300 platform.
+
 config H8300_TMR16
-        bool
+        bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
+        depends on GENERIC_CLOCKEVENTS
+       help
+         This enables the 16 bits timer for the H8300 platform with the
+         H83069 cpu.
 
 config H8300_TPU
-        bool
+        bool "Clocksource for the H8300 platform" if COMPILE_TEST
+        depends on GENERIC_CLOCKEVENTS
+       help
+         This enables the clocksource for the H8300 platform with the
+         H8S2678 cpu.
 
 config CLKSRC_IMX_GPT
        bool "Clocksource using i.MX GPT" if COMPILE_TEST
@@ -320,8 +389,7 @@ config CLKSRC_IMX_GPT
        select CLKSRC_MMIO
 
 config CLKSRC_ST_LPC
-       bool
-       depends on ARCH_STI
+       bool "Low power clocksource found in the LPC" if COMPILE_TEST
        select CLKSRC_OF if OF
        help
          Enable this option to use the Low Power controller timer
index 56bd16e..dc2b899 100644 (file)
@@ -60,7 +60,7 @@ obj-$(CONFIG_CLKSRC_MIPS_GIC)         += mips-gic-timer.o
 obj-$(CONFIG_CLKSRC_TANGO_XTAL)                += tango_xtal.o
 obj-$(CONFIG_CLKSRC_IMX_GPT)           += timer-imx-gpt.o
 obj-$(CONFIG_ASM9260_TIMER)            += asm9260_timer.o
-obj-$(CONFIG_H8300)                    += h8300_timer8.o
+obj-$(CONFIG_H8300_TMR8)               += h8300_timer8.o
 obj-$(CONFIG_H8300_TMR16)              += h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)                        += h8300_tpu.o
 obj-$(CONFIG_CLKSRC_ST_LPC)            += clksrc_st_lpc.o
index 6eab889..28037d0 100644 (file)
@@ -109,10 +109,8 @@ static void acpi_pm_check_blacklist(struct pci_dev *dev)
 
        /* the bug has been fixed in PIIX4M */
        if (dev->revision < 3) {
-               printk(KERN_WARNING "* Found PM-Timer Bug on the chipset."
-                      " Due to workarounds for a bug,\n"
-                      "* this clock source is slow. Consider trying"
-                      " other clock sources\n");
+               pr_warn("* Found PM-Timer Bug on the chipset. Due to workarounds for a bug,\n"
+                       "* this clock source is slow. Consider trying other clock sources\n");
 
                acpi_pm_need_workaround();
        }
@@ -125,12 +123,9 @@ static void acpi_pm_check_graylist(struct pci_dev *dev)
        if (acpi_pm_good)
                return;
 
-       printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to"
-              " workarounds for a bug,\n"
-              "* this clock source is slow. If you are sure your timer"
-              " does not have\n"
-              "* this bug, please use \"acpi_pm_good\" to disable the"
-              " workaround\n");
+       pr_warn("* The chipset may have PM-Timer Bug. Due to workarounds for a bug,\n"
+               "* this clock source is slow. If you are sure your timer does not have\n"
+               "* this bug, please use \"acpi_pm_good\" to disable the workaround\n");
 
        acpi_pm_need_workaround();
 }
@@ -162,8 +157,7 @@ static int verify_pmtmr_rate(void)
        /* Check that the PMTMR delta is within 5% of what we expect */
        if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
            delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
-               printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% "
-                       "of normal - aborting.\n",
+               pr_info("PM-Timer running at invalid rate: %lu%% of normal - aborting.\n",
                        100UL * delta / PMTMR_EXPECTED_RATE);
                return -1;
        }
@@ -199,15 +193,14 @@ static int __init init_acpi_pm_clocksource(void)
                                break;
                        if ((value2 < value1) && ((value2) < 0xFFF))
                                break;
-                       printk(KERN_INFO "PM-Timer had inconsistent results:"
-                              " %#llx, %#llx - aborting.\n",
-                              value1, value2);
+                       pr_info("PM-Timer had inconsistent results: %#llx, %#llx - aborting.\n",
+                               value1, value2);
                        pmtmr_ioport = 0;
                        return -EINVAL;
                }
                if (i == ACPI_PM_READ_CHECKS) {
-                       printk(KERN_INFO "PM-Timer failed consistency check "
-                              " (%#llx) - aborting.\n", value1);
+                       pr_info("PM-Timer failed consistency check  (%#llx) - aborting.\n",
+                               value1);
                        pmtmr_ioport = 0;
                        return -ENODEV;
                }
index a2cb6fa..d189d8c 100644 (file)
@@ -99,17 +99,17 @@ static void gt_compare_set(unsigned long delta, int periodic)
 
        counter += delta;
        ctrl = GT_CONTROL_TIMER_ENABLE;
-       writel(ctrl, gt_base + GT_CONTROL);
-       writel(lower_32_bits(counter), gt_base + GT_COMP0);
-       writel(upper_32_bits(counter), gt_base + GT_COMP1);
+       writel_relaxed(ctrl, gt_base + GT_CONTROL);
+       writel_relaxed(lower_32_bits(counter), gt_base + GT_COMP0);
+       writel_relaxed(upper_32_bits(counter), gt_base + GT_COMP1);
 
        if (periodic) {
-               writel(delta, gt_base + GT_AUTO_INC);
+               writel_relaxed(delta, gt_base + GT_AUTO_INC);
                ctrl |= GT_CONTROL_AUTO_INC;
        }
 
        ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
-       writel(ctrl, gt_base + GT_CONTROL);
+       writel_relaxed(ctrl, gt_base + GT_CONTROL);
 }
 
 static int gt_clockevent_shutdown(struct clock_event_device *evt)
@@ -195,12 +195,23 @@ static cycle_t gt_clocksource_read(struct clocksource *cs)
        return gt_counter_read();
 }
 
+static void gt_resume(struct clocksource *cs)
+{
+       unsigned long ctrl;
+
+       ctrl = readl(gt_base + GT_CONTROL);
+       if (!(ctrl & GT_CONTROL_TIMER_ENABLE))
+               /* re-enable timer on resume */
+               writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+}
+
 static struct clocksource gt_clocksource = {
        .name   = "arm_global_timer",
        .rating = 300,
        .read   = gt_clocksource_read,
        .mask   = CLOCKSOURCE_MASK(64),
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .resume = gt_resume,
 };
 
 #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
index c76c750..6334526 100644 (file)
@@ -49,20 +49,31 @@ clocksource_to_dw_apb_clocksource(struct clocksource *cs)
        return container_of(cs, struct dw_apb_clocksource, cs);
 }
 
-static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
+static inline u32 apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
 {
        return readl(timer->base + offs);
 }
 
-static void apbt_writel(struct dw_apb_timer *timer, unsigned long val,
-                unsigned long offs)
+static inline void apbt_writel(struct dw_apb_timer *timer, u32 val,
+                       unsigned long offs)
 {
        writel(val, timer->base + offs);
 }
 
+static inline u32 apbt_readl_relaxed(struct dw_apb_timer *timer, unsigned long offs)
+{
+       return readl_relaxed(timer->base + offs);
+}
+
+static inline void apbt_writel_relaxed(struct dw_apb_timer *timer, u32 val,
+                       unsigned long offs)
+{
+       writel_relaxed(val, timer->base + offs);
+}
+
 static void apbt_disable_int(struct dw_apb_timer *timer)
 {
-       unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
+       u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
 
        ctrl |= APBTMR_CONTROL_INT;
        apbt_writel(timer, ctrl, APBTMR_N_CONTROL);
@@ -81,7 +92,7 @@ void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced)
 
 static void apbt_eoi(struct dw_apb_timer *timer)
 {
-       apbt_readl(timer, APBTMR_N_EOI);
+       apbt_readl_relaxed(timer, APBTMR_N_EOI);
 }
 
 static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
@@ -103,7 +114,7 @@ static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
 
 static void apbt_enable_int(struct dw_apb_timer *timer)
 {
-       unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
+       u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
        /* clear pending intr */
        apbt_readl(timer, APBTMR_N_EOI);
        ctrl &= ~APBTMR_CONTROL_INT;
@@ -113,7 +124,7 @@ static void apbt_enable_int(struct dw_apb_timer *timer)
 static int apbt_shutdown(struct clock_event_device *evt)
 {
        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
-       unsigned long ctrl;
+       u32 ctrl;
 
        pr_debug("%s CPU %d state=shutdown\n", __func__,
                 cpumask_first(evt->cpumask));
@@ -127,7 +138,7 @@ static int apbt_shutdown(struct clock_event_device *evt)
 static int apbt_set_oneshot(struct clock_event_device *evt)
 {
        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
-       unsigned long ctrl;
+       u32 ctrl;
 
        pr_debug("%s CPU %d state=oneshot\n", __func__,
                 cpumask_first(evt->cpumask));
@@ -160,7 +171,7 @@ static int apbt_set_periodic(struct clock_event_device *evt)
 {
        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
        unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ);
-       unsigned long ctrl;
+       u32 ctrl;
 
        pr_debug("%s CPU %d state=periodic\n", __func__,
                 cpumask_first(evt->cpumask));
@@ -196,17 +207,17 @@ static int apbt_resume(struct clock_event_device *evt)
 static int apbt_next_event(unsigned long delta,
                           struct clock_event_device *evt)
 {
-       unsigned long ctrl;
+       u32 ctrl;
        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
 
        /* Disable timer */
-       ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
+       ctrl = apbt_readl_relaxed(&dw_ced->timer, APBTMR_N_CONTROL);
        ctrl &= ~APBTMR_CONTROL_ENABLE;
-       apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
+       apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
        /* write new count */
-       apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT);
+       apbt_writel_relaxed(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT);
        ctrl |= APBTMR_CONTROL_ENABLE;
-       apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
+       apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 
        return 0;
 }
@@ -323,7 +334,7 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs)
         * start count down from 0xffff_ffff. this is done by toggling the
         * enable bit then load initial load count to ~0.
         */
-       unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL);
+       u32 ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL);
 
        ctrl &= ~APBTMR_CONTROL_ENABLE;
        apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL);
@@ -338,11 +349,12 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs)
 
 static cycle_t __apbt_read_clocksource(struct clocksource *cs)
 {
-       unsigned long current_count;
+       u32 current_count;
        struct dw_apb_clocksource *dw_cs =
                clocksource_to_dw_apb_clocksource(cs);
 
-       current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE);
+       current_count = apbt_readl_relaxed(&dw_cs->timer,
+                                       APBTMR_N_CURRENT_VALUE);
 
        return (cycle_t)~current_count;
 }
index a19a3f6..860843c 100644 (file)
@@ -16,6 +16,7 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+#include <linux/delay.h>
 #include <linux/dw_apb_timer.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -130,6 +131,17 @@ static void __init init_sched_clock(void)
        sched_clock_register(read_sched_clock, 32, sched_rate);
 }
 
+#ifdef CONFIG_ARM
+static unsigned long dw_apb_delay_timer_read(void)
+{
+       return ~readl_relaxed(sched_io_base);
+}
+
+static struct delay_timer dw_apb_delay_timer = {
+       .read_current_timer     = dw_apb_delay_timer_read,
+};
+#endif
+
 static int num_called;
 static void __init dw_apb_timer_init(struct device_node *timer)
 {
@@ -142,6 +154,10 @@ static void __init dw_apb_timer_init(struct device_node *timer)
                pr_debug("%s: found clocksource timer\n", __func__);
                add_clocksource(timer);
                init_sched_clock();
+#ifdef CONFIG_ARM
+               dw_apb_delay_timer.freq = sched_rate;
+               register_current_timer_delay(&dw_apb_delay_timer);
+#endif
                break;
        default:
                break;
index 0e076c6..75c4407 100644 (file)
@@ -4,85 +4,56 @@
  *  Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
  */
 
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/platform_device.h>
 #include <linux/clocksource.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of.h>
-
-#include <asm/segment.h>
-#include <asm/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #define TSTR   0
-#define TSNC   1
-#define TMDR   2
-#define TOLR   3
-#define TISRA  4
-#define TISRB  5
 #define TISRC  6
 
 #define TCR    0
-#define TIOR   1
 #define TCNT   2
-#define GRA    4
-#define GRB    6
-
-#define FLAG_REPROGRAM (1 << 0)
-#define FLAG_SKIPEVENT (1 << 1)
-#define FLAG_IRQCONTEXT (1 << 2)
-#define FLAG_STARTED (1 << 3)
 
-#define ONESHOT  0
-#define PERIODIC 1
-
-#define RELATIVE 0
-#define ABSOLUTE 1
+#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
+#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
 
 struct timer16_priv {
-       struct platform_device *pdev;
        struct clocksource cs;
-       struct irqaction irqaction;
        unsigned long total_cycles;
-       unsigned long mapbase;
-       unsigned long mapcommon;
-       unsigned long flags;
-       unsigned short gra;
+       void __iomem *mapbase;
+       void __iomem *mapcommon;
        unsigned short cs_enabled;
        unsigned char enb;
-       unsigned char imfa;
-       unsigned char imiea;
        unsigned char ovf;
-       raw_spinlock_t lock;
-       struct clk *clk;
+       unsigned char ovie;
 };
 
 static unsigned long timer16_get_counter(struct timer16_priv *p)
 {
-       unsigned long v1, v2, v3;
-       int o1, o2;
+       unsigned short v1, v2, v3;
+       unsigned char  o1, o2;
 
-       o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
+       o1 = ioread8(p->mapcommon + TISRC) & p->ovf;
 
        /* Make sure the timer value is stable. Stolen from acpi_pm.c */
        do {
                o2 = o1;
-               v1 = ctrl_inw(p->mapbase + TCNT);
-               v2 = ctrl_inw(p->mapbase + TCNT);
-               v3 = ctrl_inw(p->mapbase + TCNT);
-               o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
+               v1 = ioread16be(p->mapbase + TCNT);
+               v2 = ioread16be(p->mapbase + TCNT);
+               v3 = ioread16be(p->mapbase + TCNT);
+               o1 = ioread8(p->mapcommon + TISRC) & p->ovf;
        } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
                          || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
 
-       v2 |= 0x10000;
-       return v2;
+       if (likely(!o1))
+               return v2;
+       else
+               return v2 + 0x10000;
 }
 
 
@@ -90,8 +61,7 @@ static irqreturn_t timer16_interrupt(int irq, void *dev_id)
 {
        struct timer16_priv *p = (struct timer16_priv *)dev_id;
 
-       ctrl_outb(ctrl_inb(p->mapcommon + TISRA) & ~p->imfa,
-                 p->mapcommon + TISRA);
+       bclr(p->ovf, p->mapcommon + TISRC);
        p->total_cycles += 0x10000;
 
        return IRQ_HANDLED;
@@ -105,13 +75,10 @@ static inline struct timer16_priv *cs_to_priv(struct clocksource *cs)
 static cycle_t timer16_clocksource_read(struct clocksource *cs)
 {
        struct timer16_priv *p = cs_to_priv(cs);
-       unsigned long flags, raw;
-       unsigned long value;
+       unsigned long raw, value;
 
-       raw_spin_lock_irqsave(&p->lock, flags);
        value = p->total_cycles;
        raw = timer16_get_counter(p);
-       raw_spin_unlock_irqrestore(&p->lock, flags);
 
        return value + raw;
 }
@@ -123,10 +90,10 @@ static int timer16_enable(struct clocksource *cs)
        WARN_ON(p->cs_enabled);
 
        p->total_cycles = 0;
-       ctrl_outw(0x0000, p->mapbase + TCNT);
-       ctrl_outb(0x83, p->mapbase + TCR);
-       ctrl_outb(ctrl_inb(p->mapcommon + TSTR) | p->enb,
-                 p->mapcommon + TSTR);
+       iowrite16be(0x0000, p->mapbase + TCNT);
+       iowrite8(0x83, p->mapbase + TCR);
+       bset(p->ovie, p->mapcommon + TISRC);
+       bset(p->enb, p->mapcommon + TSTR);
 
        p->cs_enabled = true;
        return 0;
@@ -138,116 +105,83 @@ static void timer16_disable(struct clocksource *cs)
 
        WARN_ON(!p->cs_enabled);
 
-       ctrl_outb(ctrl_inb(p->mapcommon + TSTR) & ~p->enb,
-                 p->mapcommon + TSTR);
+       bclr(p->ovie, p->mapcommon + TISRC);
+       bclr(p->enb, p->mapcommon + TSTR);
 
        p->cs_enabled = false;
 }
 
+static struct timer16_priv timer16_priv = {
+       .cs = {
+               .name = "h8300_16timer",
+               .rating = 200,
+               .read = timer16_clocksource_read,
+               .enable = timer16_enable,
+               .disable = timer16_disable,
+               .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8),
+               .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+       },
+};
+
 #define REG_CH   0
 #define REG_COMM 1
 
-static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev)
+static void __init h8300_16timer_init(struct device_node *node)
 {
-       struct resource *res[2];
+       void __iomem *base[2];
        int ret, irq;
        unsigned int ch;
+       struct clk *clk;
 
-       p->pdev = pdev;
-
-       res[REG_CH] = platform_get_resource(p->pdev,
-                                           IORESOURCE_MEM, REG_CH);
-       res[REG_COMM] = platform_get_resource(p->pdev,
-                                             IORESOURCE_MEM, REG_COMM);
-       if (!res[REG_CH] || !res[REG_COMM]) {
-               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
-               return -ENXIO;
-       }
-       irq = platform_get_irq(p->pdev, 0);
-       if (irq < 0) {
-               dev_err(&p->pdev->dev, "failed to get irq\n");
-               return irq;
+       clk = of_clk_get(node, 0);
+       if (IS_ERR(clk)) {
+               pr_err("failed to get clock for clocksource\n");
+               return;
        }
 
-       p->clk = clk_get(&p->pdev->dev, "fck");
-       if (IS_ERR(p->clk)) {
-               dev_err(&p->pdev->dev, "can't get clk\n");
-               return PTR_ERR(p->clk);
+       base[REG_CH] = of_iomap(node, 0);
+       if (!base[REG_CH]) {
+               pr_err("failed to map registers for clocksource\n");
+               goto free_clk;
        }
-       of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch);
-
-       p->pdev = pdev;
-       p->mapbase = res[REG_CH]->start;
-       p->mapcommon = res[REG_COMM]->start;
-       p->enb = 1 << ch;
-       p->imfa = 1 << ch;
-       p->imiea = 1 << (4 + ch);
-       p->cs.name = pdev->name;
-       p->cs.rating = 200;
-       p->cs.read = timer16_clocksource_read;
-       p->cs.enable = timer16_enable;
-       p->cs.disable = timer16_disable;
-       p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
-       p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
 
-       ret = request_irq(irq, timer16_interrupt,
-                         IRQF_TIMER, pdev->name, p);
-       if (ret < 0) {
-               dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
-               return ret;
+       base[REG_COMM] = of_iomap(node, 1);
+       if (!base[REG_COMM]) {
+               pr_err("failed to map registers for clocksource\n");
+               goto unmap_ch;
        }
 
-       clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8);
-
-       return 0;
-}
-
-static int timer16_probe(struct platform_device *pdev)
-{
-       struct timer16_priv *p = platform_get_drvdata(pdev);
-
-       if (p) {
-               dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+       irq = irq_of_parse_and_map(node, 0);
+       if (!irq) {
+               pr_err("failed to get irq for clockevent\n");
+               goto unmap_comm;
        }
 
-       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
+       of_property_read_u32(node, "renesas,channel", &ch);
 
-       return timer16_setup(p, pdev);
-}
-
-static int timer16_remove(struct platform_device *pdev)
-{
-       return -EBUSY;
-}
+       timer16_priv.mapbase = base[REG_CH];
+       timer16_priv.mapcommon = base[REG_COMM];
+       timer16_priv.enb = ch;
+       timer16_priv.ovf = ch;
+       timer16_priv.ovie = 4 + ch;
 
-static const struct of_device_id timer16_of_table[] = {
-       { .compatible = "renesas,16bit-timer" },
-       { }
-};
-static struct platform_driver timer16_driver = {
-       .probe          = timer16_probe,
-       .remove         = timer16_remove,
-       .driver         = {
-               .name   = "h8300h-16timer",
-               .of_match_table = of_match_ptr(timer16_of_table),
+       ret = request_irq(irq, timer16_interrupt,
+                         IRQF_TIMER, timer16_priv.cs.name, &timer16_priv);
+       if (ret < 0) {
+               pr_err("failed to request irq %d of clocksource\n", irq);
+               goto unmap_comm;
        }
-};
 
-static int __init timer16_init(void)
-{
-       return platform_driver_register(&timer16_driver);
-}
+       clocksource_register_hz(&timer16_priv.cs,
+                               clk_get_rate(clk) / 8);
+       return;
 
-static void __exit timer16_exit(void)
-{
-       platform_driver_unregister(&timer16_driver);
+unmap_comm:
+       iounmap(base[REG_COMM]);
+unmap_ch:
+       iounmap(base[REG_CH]);
+free_clk:
+       clk_put(clk);
 }
 
-subsys_initcall(timer16_init);
-module_exit(timer16_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8/300H 16bit Timer Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init);
index 44375d8..c151941 100644 (file)
@@ -8,19 +8,15 @@
  */
 
 #include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/clockchips.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of.h>
-
-#include <asm/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #define _8TCR  0
 #define _8TCSR 2
 #define TCORB  6
 #define _8TCNT 8
 
-#define FLAG_REPROGRAM (1 << 0)
-#define FLAG_SKIPEVENT (1 << 1)
-#define FLAG_IRQCONTEXT (1 << 2)
+#define CMIEA  6
+#define CMFA   6
+
 #define FLAG_STARTED (1 << 3)
 
-#define ONESHOT  0
-#define PERIODIC 1
+#define SCALE 64
 
-#define RELATIVE 0
-#define ABSOLUTE 1
+#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
+#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
 
 struct timer8_priv {
-       struct platform_device *pdev;
        struct clock_event_device ced;
-       struct irqaction irqaction;
-       unsigned long mapbase;
-       raw_spinlock_t lock;
+       void __iomem *mapbase;
        unsigned long flags;
        unsigned int rate;
-       unsigned int tcora;
-       struct clk *pclk;
 };
 
-static unsigned long timer8_get_counter(struct timer8_priv *p)
-{
-       unsigned long v1, v2, v3;
-       int o1, o2;
-
-       o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
-
-       /* Make sure the timer value is stable. Stolen from acpi_pm.c */
-       do {
-               o2 = o1;
-               v1 = ctrl_inw(p->mapbase + _8TCNT);
-               v2 = ctrl_inw(p->mapbase + _8TCNT);
-               v3 = ctrl_inw(p->mapbase + _8TCNT);
-               o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
-       } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
-                         || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
-
-       v2 |= o1 << 10;
-       return v2;
-}
-
 static irqreturn_t timer8_interrupt(int irq, void *dev_id)
 {
        struct timer8_priv *p = dev_id;
 
-       ctrl_outb(ctrl_inb(p->mapbase + _8TCSR) & ~0x40,
-                 p->mapbase + _8TCSR);
-       p->flags |= FLAG_IRQCONTEXT;
-       ctrl_outw(p->tcora, p->mapbase + TCORA);
-       if (!(p->flags & FLAG_SKIPEVENT)) {
-               if (clockevent_state_oneshot(&p->ced))
-                       ctrl_outw(0x0000, p->mapbase + _8TCR);
-               p->ced.event_handler(&p->ced);
-       }
-       p->flags &= ~(FLAG_SKIPEVENT | FLAG_IRQCONTEXT);
+       if (clockevent_state_oneshot(&p->ced))
+               iowrite16be(0x0000, p->mapbase + _8TCR);
+
+       p->ced.event_handler(&p->ced);
+
+       bclr(CMFA, p->mapbase + _8TCSR);
 
        return IRQ_HANDLED;
 }
 
 static void timer8_set_next(struct timer8_priv *p, unsigned long delta)
 {
-       unsigned long flags;
-       unsigned long now;
-
-       raw_spin_lock_irqsave(&p->lock, flags);
        if (delta >= 0x10000)
-               dev_warn(&p->pdev->dev, "delta out of range\n");
-       now = timer8_get_counter(p);
-       p->tcora = delta;
-       ctrl_outb(ctrl_inb(p->mapbase + _8TCR) | 0x40, p->mapbase + _8TCR);
-       if (delta > now)
-               ctrl_outw(delta, p->mapbase + TCORA);
-       else
-               ctrl_outw(now + 1, p->mapbase + TCORA);
-
-       raw_spin_unlock_irqrestore(&p->lock, flags);
+               pr_warn("delta out of range\n");
+       bclr(CMIEA, p->mapbase + _8TCR);
+       iowrite16be(delta, p->mapbase + TCORA);
+       iowrite16be(0x0000, p->mapbase + _8TCNT);
+       bclr(CMFA, p->mapbase + _8TCSR);
+       bset(CMIEA, p->mapbase + _8TCR);
 }
 
 static int timer8_enable(struct timer8_priv *p)
 {
-       p->rate = clk_get_rate(p->pclk) / 64;
-       ctrl_outw(0xffff, p->mapbase + TCORA);
-       ctrl_outw(0x0000, p->mapbase + _8TCNT);
-       ctrl_outw(0x0c02, p->mapbase + _8TCR);
+       iowrite16be(0xffff, p->mapbase + TCORA);
+       iowrite16be(0x0000, p->mapbase + _8TCNT);
+       iowrite16be(0x0c02, p->mapbase + _8TCR);
 
        return 0;
 }
 
 static int timer8_start(struct timer8_priv *p)
 {
-       int ret = 0;
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&p->lock, flags);
-
-       if (!(p->flags & FLAG_STARTED))
-               ret = timer8_enable(p);
+       int ret;
 
-       if (ret)
-               goto out;
-       p->flags |= FLAG_STARTED;
+       if ((p->flags & FLAG_STARTED))
+               return 0;
 
- out:
-       raw_spin_unlock_irqrestore(&p->lock, flags);
+       ret = timer8_enable(p);
+       if (!ret)
+               p->flags |= FLAG_STARTED;
 
        return ret;
 }
 
 static void timer8_stop(struct timer8_priv *p)
 {
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&p->lock, flags);
-
-       ctrl_outw(0x0000, p->mapbase + _8TCR);
-
-       raw_spin_unlock_irqrestore(&p->lock, flags);
+       iowrite16be(0x0000, p->mapbase + _8TCR);
 }
 
 static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
@@ -155,7 +99,7 @@ static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
        return container_of(ced, struct timer8_priv, ced);
 }
 
-static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
+static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
 {
        struct clock_event_device *ced = &p->ced;
 
@@ -166,7 +110,7 @@ static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
        ced->max_delta_ns = clockevent_delta2ns(0xffff, ced);
        ced->min_delta_ns = clockevent_delta2ns(0x0001, ced);
 
-       timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000);
+       timer8_set_next(p, delta);
 }
 
 static int timer8_clock_event_shutdown(struct clock_event_device *ced)
@@ -179,9 +123,9 @@ static int timer8_clock_event_periodic(struct clock_event_device *ced)
 {
        struct timer8_priv *p = ced_to_priv(ced);
 
-       dev_info(&p->pdev->dev, "used for periodic clock events\n");
+       pr_info("%s: used for periodic clock events\n", ced->name);
        timer8_stop(p);
-       timer8_clock_event_start(p, PERIODIC);
+       timer8_clock_event_start(p, (p->rate + HZ/2) / HZ);
 
        return 0;
 }
@@ -190,9 +134,9 @@ static int timer8_clock_event_oneshot(struct clock_event_device *ced)
 {
        struct timer8_priv *p = ced_to_priv(ced);
 
-       dev_info(&p->pdev->dev, "used for oneshot clock events\n");
+       pr_info("%s: used for oneshot clock events\n", ced->name);
        timer8_stop(p);
-       timer8_clock_event_start(p, ONESHOT);
+       timer8_clock_event_start(p, 0x10000);
 
        return 0;
 }
@@ -208,110 +152,64 @@ static int timer8_clock_event_next(unsigned long delta,
        return 0;
 }
 
-static int timer8_setup(struct timer8_priv *p,
-                       struct platform_device *pdev)
+static struct timer8_priv timer8_priv = {
+       .ced = {
+               .name = "h8300_8timer",
+               .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+               .rating = 200,
+               .set_next_event = timer8_clock_event_next,
+               .set_state_shutdown = timer8_clock_event_shutdown,
+               .set_state_periodic = timer8_clock_event_periodic,
+               .set_state_oneshot = timer8_clock_event_oneshot,
+       },
+};
+
+static void __init h8300_8timer_init(struct device_node *node)
 {
-       struct resource *res;
+       void __iomem *base;
        int irq;
-       int ret;
+       struct clk *clk;
 
-       p->pdev = pdev;
-
-       res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
-               return -ENXIO;
+       clk = of_clk_get(node, 0);
+       if (IS_ERR(clk)) {
+               pr_err("failed to get clock for clockevent\n");
+               return;
        }
 
-       irq = platform_get_irq(p->pdev, 0);
-       if (irq < 0) {
-               dev_err(&p->pdev->dev, "failed to get irq\n");
-               return -ENXIO;
+       base = of_iomap(node, 0);
+       if (!base) {
+               pr_err("failed to map registers for clockevent\n");
+               goto free_clk;
        }
 
-       p->mapbase = res->start;
-
-       p->irqaction.name = dev_name(&p->pdev->dev);
-       p->irqaction.handler = timer8_interrupt;
-       p->irqaction.dev_id = p;
-       p->irqaction.flags = IRQF_TIMER;
-
-       p->pclk = clk_get(&p->pdev->dev, "fck");
-       if (IS_ERR(p->pclk)) {
-               dev_err(&p->pdev->dev, "can't get clk\n");
-               return PTR_ERR(p->pclk);
+       irq = irq_of_parse_and_map(node, 0);
+       if (!irq) {
+               pr_err("failed to get irq for clockevent\n");
+               goto unmap_reg;
        }
 
-       p->ced.name = pdev->name;
-       p->ced.features = CLOCK_EVT_FEAT_PERIODIC |
-               CLOCK_EVT_FEAT_ONESHOT;
-       p->ced.rating = 200;
-       p->ced.cpumask = cpumask_of(0);
-       p->ced.set_next_event = timer8_clock_event_next;
-       p->ced.set_state_shutdown = timer8_clock_event_shutdown;
-       p->ced.set_state_periodic = timer8_clock_event_periodic;
-       p->ced.set_state_oneshot = timer8_clock_event_oneshot;
-
-       ret = setup_irq(irq, &p->irqaction);
-       if (ret < 0) {
-               dev_err(&p->pdev->dev,
-                       "failed to request irq %d\n", irq);
-               return ret;
-       }
-       clockevents_register_device(&p->ced);
-       platform_set_drvdata(pdev, p);
+       timer8_priv.mapbase = base;
 
-       return 0;
-}
-
-static int timer8_probe(struct platform_device *pdev)
-{
-       struct timer8_priv *p = platform_get_drvdata(pdev);
-
-       if (p) {
-               dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+       timer8_priv.rate = clk_get_rate(clk) / SCALE;
+       if (!timer8_priv.rate) {
+               pr_err("Failed to get rate for the clocksource\n");
+               goto unmap_reg;
        }
 
-       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       return timer8_setup(p, pdev);
-}
-
-static int timer8_remove(struct platform_device *pdev)
-{
-       return -EBUSY;
-}
-
-static const struct of_device_id timer8_of_table[] __maybe_unused = {
-       { .compatible = "renesas,8bit-timer" },
-       { }
-};
-
-MODULE_DEVICE_TABLE(of, timer8_of_table);
-static struct platform_driver timer8_driver = {
-       .probe          = timer8_probe,
-       .remove         = timer8_remove,
-       .driver         = {
-               .name   = "h8300-8timer",
-               .of_match_table = of_match_ptr(timer8_of_table),
+       if (request_irq(irq, timer8_interrupt, IRQF_TIMER,
+                       timer8_priv.ced.name, &timer8_priv) < 0) {
+               pr_err("failed to request irq %d for clockevent\n", irq);
+               goto unmap_reg;
        }
-};
 
-static int __init timer8_init(void)
-{
-       return platform_driver_register(&timer8_driver);
-}
+       clockevents_config_and_register(&timer8_priv.ced,
+                                       timer8_priv.rate, 1, 0x0000ffff);
 
-static void __exit timer8_exit(void)
-{
-       platform_driver_unregister(&timer8_driver);
+       return;
+unmap_reg:
+       iounmap(base);
+free_clk:
+       clk_put(clk);
 }
 
-subsys_initcall(timer8_init);
-module_exit(timer8_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8/300 8bit Timer Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);
index 5487410..d4c1a28 100644 (file)
@@ -1,42 +1,30 @@
 /*
- *  H8/300 TPU Driver
+ *  H8S TPU Driver
  *
  *  Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
  *
  */
 
 #include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/clocksource.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
-#include <asm/irq.h>
+#define TCR    0x0
+#define TSR    0x5
+#define TCNT   0x6
 
-#define TCR    0
-#define TMDR   1
-#define TIOR   2
-#define TER    4
-#define TSR    5
-#define TCNT   6
-#define TGRA   8
-#define TGRB   10
-#define TGRC   12
-#define TGRD   14
+#define TCFV   0x10
 
 struct tpu_priv {
-       struct platform_device *pdev;
        struct clocksource cs;
-       struct clk *clk;
-       unsigned long mapbase1;
-       unsigned long mapbase2;
+       void __iomem *mapbase1;
+       void __iomem *mapbase2;
        raw_spinlock_t lock;
        unsigned int cs_enabled;
 };
@@ -45,8 +33,8 @@ static inline unsigned long read_tcnt32(struct tpu_priv *p)
 {
        unsigned long tcnt;
 
-       tcnt = ctrl_inw(p->mapbase1 + TCNT) << 16;
-       tcnt |= ctrl_inw(p->mapbase2 + TCNT);
+       tcnt = ioread16be(p->mapbase1 + TCNT) << 16;
+       tcnt |= ioread16be(p->mapbase2 + TCNT);
        return tcnt;
 }
 
@@ -55,7 +43,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
        unsigned long v1, v2, v3;
        int o1, o2;
 
-       o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
+       o1 = ioread8(p->mapbase1 + TSR) & TCFV;
 
        /* Make sure the timer value is stable. Stolen from acpi_pm.c */
        do {
@@ -63,7 +51,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
                v1 = read_tcnt32(p);
                v2 = read_tcnt32(p);
                v3 = read_tcnt32(p);
-               o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
+               o1 = ioread8(p->mapbase1 + TSR) & TCFV;
        } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
                          || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
 
@@ -96,10 +84,10 @@ static int tpu_clocksource_enable(struct clocksource *cs)
 
        WARN_ON(p->cs_enabled);
 
-       ctrl_outw(0, p->mapbase1 + TCNT);
-       ctrl_outw(0, p->mapbase2 + TCNT);
-       ctrl_outb(0x0f, p->mapbase1 + TCR);
-       ctrl_outb(0x03, p->mapbase2 + TCR);
+       iowrite16be(0, p->mapbase1 + TCNT);
+       iowrite16be(0, p->mapbase2 + TCNT);
+       iowrite8(0x0f, p->mapbase1 + TCR);
+       iowrite8(0x03, p->mapbase2 + TCR);
 
        p->cs_enabled = true;
        return 0;
@@ -111,96 +99,59 @@ static void tpu_clocksource_disable(struct clocksource *cs)
 
        WARN_ON(!p->cs_enabled);
 
-       ctrl_outb(0, p->mapbase1 + TCR);
-       ctrl_outb(0, p->mapbase2 + TCR);
+       iowrite8(0, p->mapbase1 + TCR);
+       iowrite8(0, p->mapbase2 + TCR);
        p->cs_enabled = false;
 }
 
+static struct tpu_priv tpu_priv = {
+       .cs = {
+               .name = "H8S_TPU",
+               .rating = 200,
+               .read = tpu_clocksource_read,
+               .enable = tpu_clocksource_enable,
+               .disable = tpu_clocksource_disable,
+               .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8),
+               .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+       },
+};
+
 #define CH_L 0
 #define CH_H 1
 
-static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev)
+static void __init h8300_tpu_init(struct device_node *node)
 {
-       struct resource *res[2];
-
-       p->pdev = pdev;
+       void __iomem *base[2];
+       struct clk *clk;
 
-       res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L);
-       res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H);
-       if (!res[CH_L] || !res[CH_H]) {
-               dev_err(&p->pdev->dev, "failed to get I/O memory\n");
-               return -ENXIO;
+       clk = of_clk_get(node, 0);
+       if (IS_ERR(clk)) {
+               pr_err("failed to get clock for clocksource\n");
+               return;
        }
 
-       p->clk = clk_get(&p->pdev->dev, "fck");
-       if (IS_ERR(p->clk)) {
-               dev_err(&p->pdev->dev, "can't get clk\n");
-               return PTR_ERR(p->clk);
+       base[CH_L] = of_iomap(node, CH_L);
+       if (!base[CH_L]) {
+               pr_err("failed to map registers for clocksource\n");
+               goto free_clk;
        }
-
-       p->mapbase1 = res[CH_L]->start;
-       p->mapbase2 = res[CH_H]->start;
-
-       p->cs.name = pdev->name;
-       p->cs.rating = 200;
-       p->cs.read = tpu_clocksource_read;
-       p->cs.enable = tpu_clocksource_enable;
-       p->cs.disable = tpu_clocksource_disable;
-       p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
-       p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-       clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 64);
-       platform_set_drvdata(pdev, p);
-
-       return 0;
-}
-
-static int tpu_probe(struct platform_device *pdev)
-{
-       struct tpu_priv *p = platform_get_drvdata(pdev);
-
-       if (p) {
-               dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+       base[CH_H] = of_iomap(node, CH_H);
+       if (!base[CH_H]) {
+               pr_err("failed to map registers for clocksource\n");
+               goto unmap_L;
        }
 
-       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
+       tpu_priv.mapbase1 = base[CH_L];
+       tpu_priv.mapbase2 = base[CH_H];
 
-       return tpu_setup(p, pdev);
-}
-
-static int tpu_remove(struct platform_device *pdev)
-{
-       return -EBUSY;
-}
-
-static const struct of_device_id tpu_of_table[] = {
-       { .compatible = "renesas,tpu" },
-       { }
-};
+       clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64);
 
-static struct platform_driver tpu_driver = {
-       .probe          = tpu_probe,
-       .remove         = tpu_remove,
-       .driver         = {
-               .name   = "h8s-tpu",
-               .of_match_table = of_match_ptr(tpu_of_table),
-       }
-};
-
-static int __init tpu_init(void)
-{
-       return platform_driver_register(&tpu_driver);
-}
+       return;
 
-static void __exit tpu_exit(void)
-{
-       platform_driver_unregister(&tpu_driver);
+unmap_L:
+       iounmap(base[CH_H]);
+free_clk:
+       clk_put(clk);
 }
 
-subsys_initcall(tpu_init);
-module_exit(tpu_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8S Timer Pulse Unit Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init);
index fbfc746..d67bc35 100644 (file)
@@ -16,6 +16,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/clk.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
@@ -187,10 +189,8 @@ static void __init mtk_timer_init(struct device_node *node)
        struct clk *clk;
 
        evt = kzalloc(sizeof(*evt), GFP_KERNEL);
-       if (!evt) {
-               pr_warn("Can't allocate mtk clock event driver struct");
+       if (!evt)
                return;
-       }
 
        evt->dev.name = "mtk_tick";
        evt->dev.rating = 300;
@@ -204,31 +204,31 @@ static void __init mtk_timer_init(struct device_node *node)
 
        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;
+               pr_err("Can't get resource\n");
+               goto err_kzalloc;
        }
 
        evt->dev.irq = irq_of_parse_and_map(node, 0);
        if (evt->dev.irq <= 0) {
-               pr_warn("Can't parse IRQ");
+               pr_err("Can't parse IRQ\n");
                goto err_mem;
        }
 
        clk = of_clk_get(node, 0);
        if (IS_ERR(clk)) {
-               pr_warn("Can't get timer clock");
+               pr_err("Can't get timer clock\n");
                goto err_irq;
        }
 
        if (clk_prepare_enable(clk)) {
-               pr_warn("Can't prepare clock");
+               pr_err("Can't prepare clock\n");
                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);
+               pr_err("failed to setup irq %d\n", evt->dev.irq);
                goto err_clk_disable;
        }
 
@@ -260,5 +260,7 @@ err_mem:
        iounmap(evt->gpt_base);
        of_address_to_resource(node, 0, &res);
        release_mem_region(res.start, resource_size(&res));
+err_kzalloc:
+       kfree(evt);
 }
 CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);
index d3c1742..8c77a52 100644 (file)
 
 #define TIMER_NAME "rk_timer"
 
-#define TIMER_LOAD_COUNT0 0x00
-#define TIMER_LOAD_COUNT1 0x04
-#define TIMER_CONTROL_REG 0x10
-#define TIMER_INT_STATUS 0x18
+#define TIMER_LOAD_COUNT0      0x00
+#define TIMER_LOAD_COUNT1      0x04
+#define TIMER_CONTROL_REG      0x10
+#define TIMER_INT_STATUS       0x18
 
-#define TIMER_DISABLE 0x0
-#define TIMER_ENABLE 0x1
-#define TIMER_MODE_FREE_RUNNING (0 << 1)
-#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
-#define TIMER_INT_UNMASK (1 << 2)
+#define TIMER_DISABLE          0x0
+#define TIMER_ENABLE           0x1
+#define TIMER_MODE_FREE_RUNNING                        (0 << 1)
+#define TIMER_MODE_USER_DEFINED_COUNT          (1 << 1)
+#define TIMER_INT_UNMASK                       (1 << 2)
 
 struct bc_timer {
        struct clock_event_device ce;
@@ -49,14 +49,12 @@ static inline void __iomem *rk_base(struct clock_event_device *ce)
 static inline void rk_timer_disable(struct clock_event_device *ce)
 {
        writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
-       dsb();
 }
 
 static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
 {
        writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
                       rk_base(ce) + TIMER_CONTROL_REG);
-       dsb();
 }
 
 static void rk_timer_update_counter(unsigned long cycles,
@@ -64,13 +62,11 @@ static void rk_timer_update_counter(unsigned long cycles,
 {
        writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
        writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
-       dsb();
 }
 
 static void rk_timer_interrupt_clear(struct clock_event_device *ce)
 {
        writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
-       dsb();
 }
 
 static inline int rk_timer_set_next_event(unsigned long cycles,
@@ -173,4 +169,5 @@ static void __init rk_timer_init(struct device_node *np)
 
        clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
 }
+
 CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
index d297b30..2bcecaf 100644 (file)
@@ -19,19 +19,6 @@ static u64 notrace read_sched_clock(void)
        return read_xtal_counter();
 }
 
-static cycle_t read_clocksource(struct clocksource *cs)
-{
-       return read_xtal_counter();
-}
-
-static struct clocksource tango_xtal = {
-       .name   = "tango-xtal",
-       .rating = 350,
-       .read   = read_clocksource,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
 static void __init tango_clocksource_init(struct device_node *np)
 {
        struct clk *clk;
@@ -53,8 +40,9 @@ static void __init tango_clocksource_init(struct device_node *np)
        delay_timer.freq = xtal_freq;
        delay_timer.read_current_timer = read_xtal_counter;
 
-       ret = clocksource_register_hz(&tango_xtal, xtal_freq);
-       if (ret != 0) {
+       ret = clocksource_mmio_init(xtal_in_cnt, "tango-xtal", xtal_freq, 350,
+                                   32, clocksource_mmio_readl_up);
+       if (!ret) {
                pr_err("%s: registration failed\n", np->full_name);
                return;
        }
index 6ebda11..38333ab 100644 (file)
@@ -96,7 +96,8 @@ static struct clock_event_device tegra_clockevent = {
        .name                   = "timer0",
        .rating                 = 300,
        .features               = CLOCK_EVT_FEAT_ONESHOT |
-                                 CLOCK_EVT_FEAT_PERIODIC,
+                                 CLOCK_EVT_FEAT_PERIODIC |
+                                 CLOCK_EVT_FEAT_DYNIRQ,
        .set_next_event         = tegra_timer_set_next_event,
        .set_state_shutdown     = tegra_timer_shutdown,
        .set_state_periodic     = tegra_timer_set_periodic,
index a1c06a2..1316876 100644 (file)
@@ -125,7 +125,7 @@ static int __init lpc32xx_clocksource_init(struct device_node *np)
 
        clk = of_clk_get_by_name(np, "timerclk");
        if (IS_ERR(clk)) {
-               pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
+               pr_err("clock get failed (%ld)\n", PTR_ERR(clk));
                return PTR_ERR(clk);
        }
 
@@ -184,7 +184,7 @@ static int __init lpc32xx_clockevent_init(struct device_node *np)
 
        clk = of_clk_get_by_name(np, "timerclk");
        if (IS_ERR(clk)) {
-               pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
+               pr_err("clock get failed (%ld)\n", PTR_ERR(clk));
                return PTR_ERR(clk);
        }
 
index bba6799..3269d9e 100644 (file)
@@ -84,7 +84,7 @@ pistachio_clocksource_read_cycles(struct clocksource *cs)
        counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0);
        raw_spin_unlock_irqrestore(&pcs->lock, flags);
 
-       return ~(cycle_t)counter;
+       return (cycle_t)~counter;
 }
 
 static u64 notrace pistachio_read_sched_clock(void)
index bca9573..24c83f9 100644 (file)
@@ -152,13 +152,6 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static cycle_t sun5i_clksrc_read(struct clocksource *clksrc)
-{
-       struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
-
-       return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1));
-}
-
 static int sun5i_rate_cb_clksrc(struct notifier_block *nb,
                                unsigned long event, void *data)
 {
@@ -217,13 +210,8 @@ static int __init sun5i_setup_clocksource(struct device_node *node,
        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
               base + TIMER_CTL_REG(1));
 
-       cs->clksrc.name = node->name;
-       cs->clksrc.rating = 340;
-       cs->clksrc.read = sun5i_clksrc_read;
-       cs->clksrc.mask = CLOCKSOURCE_MASK(32);
-       cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-
-       ret = clocksource_register_hz(&cs->clksrc, rate);
+       ret = clocksource_mmio_init(base + TIMER_CNTVAL_LO_REG(1), node->name,
+                                   rate, 340, 32, clocksource_mmio_readl_down);
        if (ret) {
                pr_err("Couldn't register clock source.\n");
                goto err_remove_notifier;
index a92e94b..de49805 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/delay.h>
-#include <asm/mach/time.h>
 
 #include <linux/of.h>
 #include <linux/of_address.h>
index 6fd30d5..c378768 100644 (file)
@@ -21,9 +21,9 @@ static const char ipr_bit[] = {
        10, 10, 10, 10,  9,  9,  9,  9,
 };
 
-static void *intc_baseaddr;
+static void __iomem *intc_baseaddr;
 
-#define IPR ((unsigned long)intc_baseaddr + 6)
+#define IPR (intc_baseaddr + 6)
 
 static void h8300h_disable_irq(struct irq_data *data)
 {
@@ -81,8 +81,8 @@ static int __init h8300h_intc_of_init(struct device_node *intc,
        BUG_ON(!intc_baseaddr);
 
        /* All interrupt priority low */
-       ctrl_outb(0x00, IPR + 0);
-       ctrl_outb(0x00, IPR + 1);
+       writeb(0x00, IPR + 0);
+       writeb(0x00, IPR + 1);
 
        domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, NULL);
        BUG_ON(!domain);
index 7784b59..6013021 100644 (file)
@@ -62,12 +62,18 @@ struct module;
  * @suspend:           suspend function for the clocksource, if necessary
  * @resume:            resume function for the clocksource, if necessary
  * @owner:             module reference, must be set by clocksource in modules
+ *
+ * Note: This struct is not used in hotpathes of the timekeeping code
+ * because the timekeeper caches the hot path fields in its own data
+ * structure, so no line cache alignment is required,
+ *
+ * The pointer to the clocksource itself is handed to the read
+ * callback. If you need extra information there you can wrap struct
+ * clocksource into your own struct. Depending on the amount of
+ * information you need you should consider to cache line align that
+ * structure.
  */
 struct clocksource {
-       /*
-        * Hotpath data, fits in a single cache line when the
-        * clocksource itself is cacheline aligned.
-        */
        cycle_t (*read)(struct clocksource *cs);
        cycle_t mask;
        u32 mult;
@@ -95,7 +101,7 @@ struct clocksource {
        cycle_t wd_last;
 #endif
        struct module *owner;
-} ____cacheline_aligned;
+};
 
 /*
  * Clock source flags bits::
index efa931c..411b52e 100644 (file)
 
 #ifdef CONFIG_GENERIC_SCHED_CLOCK
 extern void sched_clock_postinit(void);
-#else
-static inline void sched_clock_postinit(void) { }
-#endif
 
 extern void sched_clock_register(u64 (*read)(void), int bits,
                                 unsigned long rate);
+#else
+static inline void sched_clock_postinit(void) { }
+
+static inline void sched_clock_register(u64 (*read)(void), int bits,
+                                       unsigned long rate)
+{
+       ;
+}
+#endif
 
 #endif
index beebe3a..297f09f 100644 (file)
@@ -125,6 +125,32 @@ static inline bool timeval_valid(const struct timeval *tv)
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 
+/*
+ * Validates if a timespec/timeval used to inject a time offset is valid.
+ * Offsets can be postive or negative. The value of the timeval/timespec
+ * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
+ * always be non-negative.
+ */
+static inline bool timeval_inject_offset_valid(const struct timeval *tv)
+{
+       /* We don't check the tv_sec as it can be positive or negative */
+
+       /* Can't have more microseconds then a second */
+       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+               return false;
+       return true;
+}
+
+static inline bool timespec_inject_offset_valid(const struct timespec *ts)
+{
+       /* We don't check the tv_sec as it can be positive or negative */
+
+       /* Can't have more nanoseconds then a second */
+       if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
+               return false;
+       return true;
+}
+
 #define CURRENT_TIME           (current_kernel_time())
 #define CURRENT_TIME_SEC       ((struct timespec) { get_seconds(), 0 })
 
index 7fbba63..e840ed8 100644 (file)
@@ -271,11 +271,27 @@ static int alarmtimer_suspend(struct device *dev)
                __pm_wakeup_event(ws, MSEC_PER_SEC);
        return ret;
 }
+
+static int alarmtimer_resume(struct device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = alarmtimer_get_rtcdev();
+       if (rtc)
+               rtc_timer_cancel(rtc, &rtctimer);
+       return 0;
+}
+
 #else
 static int alarmtimer_suspend(struct device *dev)
 {
        return 0;
 }
+
+static int alarmtimer_resume(struct device *dev)
+{
+       return 0;
+}
 #endif
 
 static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
@@ -800,6 +816,7 @@ out:
 /* Suspend hook structures */
 static const struct dev_pm_ops alarmtimer_pm_ops = {
        .suspend = alarmtimer_suspend,
+       .resume = alarmtimer_resume,
 };
 
 static struct platform_driver alarmtimer_driver = {
index 1347882..664de53 100644 (file)
@@ -218,8 +218,8 @@ static void clocksource_watchdog(unsigned long data)
 
                /* Check the deviation from the watchdog clocksource. */
                if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) {
-                       pr_warn("timekeeping watchdog: Marking clocksource '%s' as unstable because the skew is too large:\n",
-                               cs->name);
+                       pr_warn("timekeeping watchdog on CPU%d: Marking clocksource '%s' as unstable because the skew is too large:\n",
+                               smp_processor_id(), cs->name);
                        pr_warn("                      '%s' wd_now: %llx wd_last: %llx mask: %llx\n",
                                watchdog->name, wdnow, wdlast, watchdog->mask);
                        pr_warn("                      '%s' cs_now: %llx cs_last: %llx mask: %llx\n",
index 149cc80..36f2ca0 100644 (file)
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
+#include <linux/math64.h>
 
 #include "ntp_internal.h"
+#include "timekeeping_internal.h"
+
 
 /*
  * NTP timekeeping variables:
@@ -70,7 +73,7 @@ static long                   time_esterror = NTP_PHASE_LIMIT;
 static s64                     time_freq;
 
 /* time at last adjustment (secs):                                     */
-static long                    time_reftime;
+static time64_t                time_reftime;
 
 static long                    time_adjust;
 
@@ -297,25 +300,27 @@ static void ntp_update_offset(long offset)
        if (!(time_status & STA_PLL))
                return;
 
-       if (!(time_status & STA_NANO))
+       if (!(time_status & STA_NANO)) {
+               /* Make sure the multiplication below won't overflow */
+               offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC);
                offset *= NSEC_PER_USEC;
+       }
 
        /*
         * Scale the phase adjustment and
         * clamp to the operating range.
         */
-       offset = min(offset, MAXPHASE);
-       offset = max(offset, -MAXPHASE);
+       offset = clamp(offset, -MAXPHASE, MAXPHASE);
 
        /*
         * Select how the frequency is to be controlled
         * and in which mode (PLL or FLL).
         */
-       secs = get_seconds() - time_reftime;
+       secs = (long)(__ktime_get_real_seconds() - time_reftime);
        if (unlikely(time_status & STA_FREQHOLD))
                secs = 0;
 
-       time_reftime = get_seconds();
+       time_reftime = __ktime_get_real_seconds();
 
        offset64    = offset;
        freq_adj    = ntp_update_offset_fll(offset64, secs);
@@ -390,10 +395,11 @@ ktime_t ntp_get_next_leap(void)
  *
  * Also handles leap second processing, and returns leap offset
  */
-int second_overflow(unsigned long secs)
+int second_overflow(time64_t secs)
 {
        s64 delta;
        int leap = 0;
+       s32 rem;
 
        /*
         * Leap second processing. If in leap-insert state at the end of the
@@ -404,19 +410,19 @@ int second_overflow(unsigned long secs)
        case TIME_OK:
                if (time_status & STA_INS) {
                        time_state = TIME_INS;
-                       ntp_next_leap_sec = secs + SECS_PER_DAY -
-                                               (secs % SECS_PER_DAY);
+                       div_s64_rem(secs, SECS_PER_DAY, &rem);
+                       ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
                } else if (time_status & STA_DEL) {
                        time_state = TIME_DEL;
-                       ntp_next_leap_sec = secs + SECS_PER_DAY -
-                                                ((secs+1) % SECS_PER_DAY);
+                       div_s64_rem(secs + 1, SECS_PER_DAY, &rem);
+                       ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
                }
                break;
        case TIME_INS:
                if (!(time_status & STA_INS)) {
                        ntp_next_leap_sec = TIME64_MAX;
                        time_state = TIME_OK;
-               } else if (secs % SECS_PER_DAY == 0) {
+               } else if (secs == ntp_next_leap_sec) {
                        leap = -1;
                        time_state = TIME_OOP;
                        printk(KERN_NOTICE
@@ -427,7 +433,7 @@ int second_overflow(unsigned long secs)
                if (!(time_status & STA_DEL)) {
                        ntp_next_leap_sec = TIME64_MAX;
                        time_state = TIME_OK;
-               } else if ((secs + 1) % SECS_PER_DAY == 0) {
+               } else if (secs == ntp_next_leap_sec) {
                        leap = 1;
                        ntp_next_leap_sec = TIME64_MAX;
                        time_state = TIME_WAIT;
@@ -590,7 +596,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)
         * reference time to current time.
         */
        if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
-               time_reftime = get_seconds();
+               time_reftime = __ktime_get_real_seconds();
 
        /* only set allowed bits */
        time_status &= STA_RONLY;
@@ -674,8 +680,14 @@ int ntp_validate_timex(struct timex *txc)
                        return -EINVAL;
        }
 
-       if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
-               return -EPERM;
+       if (txc->modes & ADJ_SETOFFSET) {
+               /* In order to inject time, you gotta be super-user! */
+               if (!capable(CAP_SYS_TIME))
+                       return -EPERM;
+
+               if (!timeval_inject_offset_valid(&txc->time))
+                       return -EINVAL;
+       }
 
        /*
         * Check for potential multiplication overflows that can
index af92447..d8a7c11 100644 (file)
@@ -6,7 +6,7 @@ extern void ntp_clear(void);
 /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
 extern u64 ntp_tick_length(void);
 extern ktime_t ntp_get_next_leap(void);
-extern int second_overflow(unsigned long secs);
+extern int second_overflow(time64_t secs);
 extern int ntp_validate_timex(struct timex *);
 extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
 extern void __hardpps(const struct timespec64 *, const struct timespec64 *);
index ce033c7..9cff0ab 100644 (file)
@@ -69,10 +69,10 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf,
 static unsigned int posix_clock_poll(struct file *fp, poll_table *wait)
 {
        struct posix_clock *clk = get_posix_clock(fp);
-       int result = 0;
+       unsigned int result = 0;
 
        if (!clk)
-               return -ENODEV;
+               return POLLERR;
 
        if (clk->ops.poll)
                result = clk->ops.poll(clk, fp, wait);
index 11ce599..99ef0df 100644 (file)
@@ -603,15 +603,31 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
 
        /*
         * If the tick is due in the next period, keep it ticking or
-        * restart it proper.
+        * force prod the timer.
         */
        delta = next_tick - basemono;
        if (delta <= (u64)TICK_NSEC) {
                tick.tv64 = 0;
+               /*
+                * We've not stopped the tick yet, and there's a timer in the
+                * next period, so no point in stopping it either, bail.
+                */
                if (!ts->tick_stopped)
                        goto out;
+
+               /*
+                * If, OTOH, we did stop it, but there's a pending (expired)
+                * timer reprogram the timer hardware to fire now.
+                *
+                * We will not restart the tick proper, just prod the timer
+                * hardware into firing an interrupt to process the pending
+                * timers. Just like tick_irq_exit() will not restart the tick
+                * for 'normal' interrupts.
+                *
+                * Only once we exit the idle loop will we re-enable the tick,
+                * see tick_nohz_idle_exit().
+                */
                if (delta == 0) {
-                       /* Tick is stopped, but required now. Enforce it */
                        tick_nohz_restart(ts, now);
                        goto out;
                }
index d563c19..34b4ced 100644 (file)
@@ -305,8 +305,7 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
 
        delta = timekeeping_get_delta(tkr);
 
-       nsec = delta * tkr->mult + tkr->xtime_nsec;
-       nsec >>= tkr->shift;
+       nsec = (delta * tkr->mult + tkr->xtime_nsec) >> tkr->shift;
 
        /* If arch requires, add in get_arch_timeoffset() */
        return nsec + arch_gettimeoffset();
@@ -846,6 +845,19 @@ time64_t ktime_get_real_seconds(void)
 }
 EXPORT_SYMBOL_GPL(ktime_get_real_seconds);
 
+/**
+ * __ktime_get_real_seconds - The same as ktime_get_real_seconds
+ * but without the sequence counter protect. This internal function
+ * is called just when timekeeping lock is already held.
+ */
+time64_t __ktime_get_real_seconds(void)
+{
+       struct timekeeper *tk = &tk_core.timekeeper;
+
+       return tk->xtime_sec;
+}
+
+
 #ifdef CONFIG_NTP_PPS
 
 /**
@@ -959,7 +971,7 @@ int timekeeping_inject_offset(struct timespec *ts)
        struct timespec64 ts64, tmp;
        int ret = 0;
 
-       if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
+       if (!timespec_inject_offset_valid(ts))
                return -EINVAL;
 
        ts64 = timespec_to_timespec64(*ts);
@@ -1592,9 +1604,12 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
 {
        s64 interval = tk->cycle_interval;
        s64 xinterval = tk->xtime_interval;
+       u32 base = tk->tkr_mono.clock->mult;
+       u32 max = tk->tkr_mono.clock->maxadj;
+       u32 cur_adj = tk->tkr_mono.mult;
        s64 tick_error;
        bool negative;
-       u32 adj;
+       u32 adj_scale;
 
        /* Remove any current error adj from freq calculation */
        if (tk->ntp_err_mult)
@@ -1613,13 +1628,33 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
        /* preserve the direction of correction */
        negative = (tick_error < 0);
 
-       /* Sort out the magnitude of the correction */
+       /* If any adjustment would pass the max, just return */
+       if (negative && (cur_adj - 1) <= (base - max))
+               return;
+       if (!negative && (cur_adj + 1) >= (base + max))
+               return;
+       /*
+        * Sort out the magnitude of the correction, but
+        * avoid making so large a correction that we go
+        * over the max adjustment.
+        */
+       adj_scale = 0;
        tick_error = abs(tick_error);
-       for (adj = 0; tick_error > interval; adj++)
+       while (tick_error > interval) {
+               u32 adj = 1 << (adj_scale + 1);
+
+               /* Check if adjustment gets us within 1 unit from the max */
+               if (negative && (cur_adj - adj) <= (base - max))
+                       break;
+               if (!negative && (cur_adj + adj) >= (base + max))
+                       break;
+
+               adj_scale++;
                tick_error >>= 1;
+       }
 
        /* scale the corrections */
-       timekeeping_apply_adjustment(tk, offset, negative, adj);
+       timekeeping_apply_adjustment(tk, offset, negative, adj_scale);
 }
 
 /*
index 4ea005a..5be7627 100644 (file)
@@ -17,7 +17,11 @@ static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
 {
        cycle_t ret = (now - last) & mask;
 
-       return (s64) ret > 0 ? ret : 0;
+       /*
+        * Prevent time going backwards by checking the MSB of mask in
+        * the result. If set, return 0.
+        */
+       return ret & ~(mask >> 1) ? 0 : ret;
 }
 #else
 static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
@@ -26,4 +30,6 @@ static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
 }
 #endif
 
+extern time64_t __ktime_get_real_seconds(void);
+
 #endif /* _TIMEKEEPING_INTERNAL_H */
index 627ec74..fd88e30 100644 (file)
@@ -97,7 +97,7 @@ int get_cur_clocksource(char *buf, size_t size)
 int change_clocksource(char *clocksource)
 {
        int fd;
-       size_t size;
+       ssize_t size;
 
        fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY);