diff --git a/MAINTAINERS b/MAINTAINERS index 026cea8b5a369952dc60e4f5c93b52389ae87cab..3cbad0f366f0a3a026ec61fdb1445d0a7705d6b8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9364,7 +9364,7 @@ M: Andreas Noever S: Maintained F: drivers/thunderbolt/ -TIMEKEEPING, CLOCKSOURCE CORE, NTP +TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER M: John Stultz M: Thomas Gleixner 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/ diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 34e1569a11ee322a0a020bdfe0c9b801b6b58c12..688dc7b0d95121a95285a998b6f019a4b8f30cf5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -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 diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 3a10f1a8317ae7a053ed997da88a06ddd5311b57..ff105399aae48973432e4f688a4efb5a570f0216 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -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) diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig index 125865daaf1719e931cb051b9039292799b8e930..12dd1dc0a04116e109f4a6a8754417fc668f7741 100644 --- a/arch/arm/mach-sti/Kconfig +++ b/arch/arm/mach-sti/Kconfig @@ -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 diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index c9ac19b24e5a5da7bbfbf7aa7afcaff34f067e96..5eacdd61e61c35ffa7edcaa64d05e4948abe05ab 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -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 diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index dd3ac75776ad982973d0ae2f5f2ccd0e58a53c7e..2e20333cbce90b947f13f5a11182bedef82a4d3c 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -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 diff --git a/arch/h8300/include/asm/io.h b/arch/h8300/include/asm/io.h index bb837cded268446bbd67d7610daf374807d502bb..f0e14f3a800d8d4eb65f2ac970543cc66375bcfe 100644 --- a/arch/h8300/include/asm/io.h +++ b/arch/h8300/include/asm/io.h @@ -3,40 +3,45 @@ #ifdef __KERNEL__ -#include - /* 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 + #endif /* __KERNEL__ */ #endif /* _H8300_IO_H */ diff --git a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c index c772abe6d19ce0d4ff06f12c8d5fb004905c26c5..e4985dfa91dc853e1c227759808814b2e5e2ea97 100644 --- a/arch/h8300/kernel/setup.c +++ b/arch/h8300/kernel/setup.c @@ -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; diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 2eb5f0efae903cd5235bdd2132ec455dfafe7c26..b251013eef0a952f28e3c3464e0876773bd9ddab 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -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 diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 56bd16e77ae37147da0fa4e977adffcb9bc1a4c6..dc2b8997f6e637c0ae83f09b4b6bd4b92bffbf8d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -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 diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 6eab8898567031cf0e6519ec6d0d970340fc1705..28037d0b8dcd133c4be8814bf609342c1520d0c4 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -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; } diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index a2cb6fae92958b7319c55ee20ef21e26268ffbea..d189d8cb69f70244cacca5a331b32e5beca4b5f1 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -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 diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index c76c75006ea6c412eedeaa790ef1f602123bc54b..63345260244d7d97df303b3fd12445612e6b4395 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -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; } diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index a19a3f619cc755d3a9a04dbdcde24b230cb30d6d..860843cef5725f6a4d64fc515d9ccac7b88b2457 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include #include #include @@ -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; diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c index 0e076c6fc006b26b52729c9389db7d87a9604ce3..75c44079b3454513b2f6a788872b4c579c7f27b8 100644 --- a/drivers/clocksource/h8300_timer16.c +++ b/drivers/clocksource/h8300_timer16.c @@ -4,85 +4,56 @@ * Copyright 2015 Yoshinori Sato */ -#include -#include -#include -#include -#include #include #include -#include #include -#include #include #include #include - -#include -#include +#include +#include #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); diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index 44375d8b9bc438878be58699fb95ce8fb624ebc6..c151941e1956d3a8338edeeeefd4c09e0d78066c 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -8,19 +8,15 @@ */ #include -#include #include #include #include -#include -#include #include -#include #include #include #include - -#include +#include +#include #define _8TCR 0 #define _8TCSR 2 @@ -28,126 +24,74 @@ #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); diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c index 5487410bfabb93b0c4768a91870485f6ba77d31f..d4c1a287c2622e459bbe544399e872cddcc44439 100644 --- a/drivers/clocksource/h8300_tpu.c +++ b/drivers/clocksource/h8300_tpu.c @@ -1,42 +1,30 @@ /* - * H8/300 TPU Driver + * H8S TPU Driver * * Copyright 2015 Yoshinori Sato * */ #include -#include #include -#include #include -#include -#include #include -#include #include #include #include +#include +#include -#include +#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); diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index fbfc74685e6afba837ae549021f7fe763f7c0de4..d67bc356488ffd0590f76abea3c28087c051ffcb 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -16,6 +16,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -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 @@ static void __init mtk_timer_init(struct device_node *node) 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); diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index d3c1742ded1af7655c3e2e77031ab3801ea84761..8c77a529d0d445bb91583f3256e7fdc4a6da6caf 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -17,16 +17,16 @@ #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); diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c index d297b30d2bc03cb5f19e195fdf18d765b4b6a3e9..2bcecafdeaeac76b2e4decf3dda66d8d7a6f027b 100644 --- a/drivers/clocksource/tango_xtal.c +++ b/drivers/clocksource/tango_xtal.c @@ -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; } diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 6ebda1177e791373e6db749f10620ef785bf198d..38333aba3055b3e376bb163ad0517c348178ec7b 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -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, diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c index a1c06a2bc77c55160fa8283378877cb8d1062820..1316876b487a715bf12bd03e007c4f178ec9136f 100644 --- a/drivers/clocksource/time-lpc32xx.c +++ b/drivers/clocksource/time-lpc32xx.c @@ -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); } diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c index bba6799000541d360081b41e4e87ee8d9bf7596a..3269d9ef7a18a1d0f1e505ea77878b87c529d5f7 100644 --- a/drivers/clocksource/time-pistachio.c +++ b/drivers/clocksource/time-pistachio.c @@ -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) diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index bca9573e036a7ece133a64476cd0dd1208d9a816..24c83f9efd87f5f5df361eb9e4b0ecd76b6827f9 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -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; diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index a92e94b40b5b031e12074e26483e2e0c61b1d986..de49805fbb0978bb2eac2bd019c252604cd6afe2 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff --git a/drivers/irqchip/irq-renesas-h8300h.c b/drivers/irqchip/irq-renesas-h8300h.c index 6fd30d5ee14dddcd7a35169632a26d2156c2e34c..c378768d75b333866778f0d2e63567a1d249cc4a 100644 --- a/drivers/irqchip/irq-renesas-h8300h.c +++ b/drivers/irqchip/irq-renesas-h8300h.c @@ -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); diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 7784b597e9592b0ea0a32d661a0068cf9a8e2137..6013021a3b39467ffd8a2fa3d10064fe561ae2e7 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -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:: diff --git a/include/linux/sched_clock.h b/include/linux/sched_clock.h index efa931c5cef145e354fd290cf0794bccb7446247..411b52e424e1b2178b961bbec2081c3a0e58affd 100644 --- a/include/linux/sched_clock.h +++ b/include/linux/sched_clock.h @@ -10,11 +10,17 @@ #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 diff --git a/include/linux/time.h b/include/linux/time.h index beebe3a02d43f5c527633cbd12af690c02e8288d..297f09f23896d2db41cd90a0cad37746e6ed77aa 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -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 }) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 7fbba635a5499805c316c36e99910f1d96eb6fb6..e840ed867a5d9406e26a8bc13f3e635b0d66cbdd 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -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 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, /* Suspend hook structures */ static const struct dev_pm_ops alarmtimer_pm_ops = { .suspend = alarmtimer_suspend, + .resume = alarmtimer_resume, }; static struct platform_driver alarmtimer_driver = { diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 1347882d131e11a404b029d83edfb281483b9c9c..664de539299b6ec3c8eb9a1565f02c14ae839379 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -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", diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 149cc8086aea16bbd811d3af37e187fd08bb366f..36f2ca09aa5e458bf1f31e3ec018e180dcc5b345 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -16,8 +16,11 @@ #include #include #include +#include #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 diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h index af924470eac04c046e3481750a32833cef9acc13..d8a7c11fa71a51e09063cf807d6f59959a6119ab 100644 --- a/kernel/time/ntp_internal.h +++ b/kernel/time/ntp_internal.h @@ -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 *); diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c index ce033c7aa2e8f8a179ae4a031c176e1a358a100d..9cff0ab82b635d33d2936697d909724d07767e69 100644 --- a/kernel/time/posix-clock.c +++ b/kernel/time/posix-clock.c @@ -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); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 11ce59916c1a2ee86d7b9c1e5fec9889ff8d7e33..99ef0df1280737f463ea578addc7967da4a2c810 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -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; } diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index d563c19603029bc6c57ac55154f71ed027320276..34b4cedfa80da0de969c12d1551620513f93d02c 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -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); } /* diff --git a/kernel/time/timekeeping_internal.h b/kernel/time/timekeeping_internal.h index 4ea005a7f9dab06f30eacc93b2ef18604a321746..5be76270ec4a8f155574aabe2812f9edefb80aec 100644 --- a/kernel/time/timekeeping_internal.h +++ b/kernel/time/timekeeping_internal.h @@ -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 */ diff --git a/tools/testing/selftests/timers/clocksource-switch.c b/tools/testing/selftests/timers/clocksource-switch.c index 627ec7425f78e1d235bd4561121ffe46bd12c362..fd88e3025bedc17d44c1537b8279aa6068d3ff47 100644 --- a/tools/testing/selftests/timers/clocksource-switch.c +++ b/tools/testing/selftests/timers/clocksource-switch.c @@ -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);