From b5e995e671d8e4d7a75b339ce78ecc586014b0eb Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 12 Jun 2014 16:24:41 +0530 Subject: [PATCH 01/16] nohz: Fix spurious periodic tick behaviour in low-res dynticks mode When we reach the end of the tick handler, we unconditionally reschedule the next tick to the next jiffy. Then on irq exit, the nohz code overrides that setting if needed and defers the next tick as far away in the future as possible. Now in the best dynticks case, when we actually don't need any tick in the future (ie: expires == KTIME_MAX), low-res and high-res behave differently. What we want in this case is to cancel the next tick programmed by the previous one. That's what we do in high-res mode. OTOH we lack a low-res mode equivalent of hrtimer_cancel() so we simply don't do anything in this case and the next tick remains scheduled to jiffies + 1. As a result, in low-res mode, when the dynticks code determines that no tick is needed in the future, we can recursively get a spurious tick every jiffy because then the next tick is always reprogrammed from the tick handler and is never cancelled. And this can happen indefinetly until some subsystem actually needs a precise tick in the future and only then we eventually overwrite the previous tick handler setting to defer the next tick. We are fixing this by introducing the ONESHOT_STOPPED mode which will let us pause a clockevent when no further interrupt is needed. Meanwhile we can't expect all drivers to support this new mode. So lets reduce much of the symptoms by skipping the nohz-blind tick rescheduling from the tick-handler when the CPU is in dynticks mode. That tick rescheduling wrongly assumed periodicity and the low-res dynticks code can't cancel such decision. This breaks the recursive (and thus the worst) part of the problem. In the worst case now, we'll get only one extra tick due to uncancelled tick scheduled before we entered dynticks mode. This also removes a needless clockevent write on idle ticks. Since those clock write are usually considered to be slow, it's a general win. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Cc: Thomas Gleixner Signed-off-by: Frederic Weisbecker --- kernel/time/tick-sched.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 99aa6ee3908f..153870a91350 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -968,6 +968,10 @@ static void tick_nohz_handler(struct clock_event_device *dev) tick_sched_do_timer(now); tick_sched_handle(ts, regs); + /* No need to reprogram if we are running tickless */ + if (unlikely(ts->tick_stopped)) + return; + while (tick_nohz_reprogram(ts, now)) { now = ktime_get(); tick_do_update_jiffies64(now); From 2a16fc93d2c9568e16d45db77c7b5f15e1921cf1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 12 Jun 2014 16:24:41 +0530 Subject: [PATCH 02/16] nohz: Avoid tick's double reprogramming in highres mode In highres mode, the tick reschedules itself unconditionally to the next jiffies. However while this clock reprogramming is relevant when the tick is in periodic mode, it's not that interesting when we run in dynticks mode because irq exit is likely going to overwrite the next tick to some randomly deferred future. So lets just get rid of this tick self rescheduling in dynticks mode. This way we can avoid some clockevents double write in favourable scenarios like when we stop the tick completely in idle while no other hrtimer is pending. Suggested-by: Frederic Weisbecker Signed-off-by: Viresh Kumar Cc: Thomas Gleixner Signed-off-by: Frederic Weisbecker --- kernel/time/tick-sched.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 153870a91350..cc0a5b6f741b 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -1099,6 +1099,10 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) if (regs) tick_sched_handle(ts, regs); + /* No need to reprogram if we are in idle or full dynticks mode */ + if (unlikely(ts->tick_stopped)) + return HRTIMER_NORESTART; + hrtimer_forward(timer, now, tick_period); return HRTIMER_RESTART; From 88299c9bdb109e0d95abdca648065631ff91b2cb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2014 11:28:48 +0300 Subject: [PATCH 03/16] timerfd: Remove an always true check We would have returned -EINVAL earlier if ticks wasn't set. Signed-off-by: Dan Carpenter Cc: Alexander Viro Cc: Cyrill Gorcunov Link: http://lkml.kernel.org/r/20140801082848.GF28869@mwanda Signed-off-by: Thomas Gleixner --- fs/timerfd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/timerfd.c b/fs/timerfd.c index 80c350216ea8..b46ffa94372a 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -333,8 +333,7 @@ static long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg spin_lock_irq(&ctx->wqh.lock); if (!timerfd_canceled(ctx)) { ctx->ticks = ticks; - if (ticks) - wake_up_locked(&ctx->wqh); + wake_up_locked(&ctx->wqh); } else ret = -ECANCELED; spin_unlock_irq(&ctx->wqh.lock); From 01fe3aaa3abd3379788173e0017a6299b5b438db Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 27 Aug 2014 13:36:51 +0900 Subject: [PATCH 04/16] clocksource: sh_cmt: Document SoC specific bindings In general Renesas hardware is not documented to the extent where the relationship between IP blocks on different SoCs can be assumed although they may appear to operate the same way. Furthermore the documentation typically does not specify a version for individual IP blocks. For these reasons a convention of using the SoC name in place of a version and providing SoC-specific compat strings has been adopted. Although not universally liked this convention is used in the bindings for a number of drivers for Renesas hardware. The purpose of this patch is to update the Renesas R-Car Compare Match Timer (CMT) driver to follow this convention. Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Acked-by: Mark Rutland Acked-by: Laurent Pinchart --- * I plan to follow up with patches to use these new bindings in the dtsi files for the affected SoCs. v2 * Reorder compat entries so more-specific entries and their fallbacks are grouped with the fallback entry coming last. * Explicitly document fallback v3 * Avoid circular dependency in documentation of fallback behaviour of renesas,cmt-48-gen2 * Use consistent case for SoC names in compat string descriptions --- .../devicetree/bindings/timer/renesas,cmt.txt | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.txt b/Documentation/devicetree/bindings/timer/renesas,cmt.txt index a17418b0ece3..1a05c1b243c1 100644 --- a/Documentation/devicetree/bindings/timer/renesas,cmt.txt +++ b/Documentation/devicetree/bindings/timer/renesas,cmt.txt @@ -11,15 +11,47 @@ datasheets. Required Properties: - - compatible: must contain one of the following. - - "renesas,cmt-32" for the 32-bit CMT + - compatible: must contain one or more of the following: + - "renesas,cmt-32-r8a7740" for the r8a7740 32-bit CMT + (CMT0) + - "renesas,cmt-32-sh7372" for the sh7372 32-bit CMT + (CMT0) + - "renesas,cmt-32-sh73a0" for the sh73a0 32-bit CMT + (CMT0) + - "renesas,cmt-32" for all 32-bit CMT without fast clock support (CMT0 on sh7372, sh73a0 and r8a7740) - - "renesas,cmt-32-fast" for the 32-bit CMT with fast clock support + This is a fallback for the above renesas,cmt-32-* entries. + + - "renesas,cmt-32-fast-r8a7740" for the r8a7740 32-bit CMT with fast + clock support (CMT[234]) + - "renesas,cmt-32-fast-sh7372" for the sh7372 32-bit CMT with fast + clock support (CMT[234]) + - "renesas,cmt-32-fast-sh73a0" for the sh73A0 32-bit CMT with fast + clock support (CMT[234]) + - "renesas,cmt-32-fast" for all 32-bit CMT with fast clock support (CMT[234] on sh7372, sh73a0 and r8a7740) - - "renesas,cmt-48" for the 48-bit CMT + This is a fallback for the above renesas,cmt-32-fast-* entries. + + - "renesas,cmt-48-sh7372" for the sh7372 48-bit CMT + (CMT1) + - "renesas,cmt-48-sh73a0" for the sh73A0 48-bit CMT + (CMT1) + - "renesas,cmt-48-r8a7740" for the r8a7740 48-bit CMT + (CMT1) + - "renesas,cmt-48" for all non-second generation 48-bit CMT (CMT1 on sh7372, sh73a0 and r8a7740) - - "renesas,cmt-48-gen2" for the second generation 48-bit CMT + This is a fallback for the above renesas,cmt-48-* entries. + + - "renesas,cmt-48-r8a73a4" for the r8a73a4 48-bit CMT + (CMT[01]) + - "renesas,cmt-48-r8a7790" for the r8a7790 48-bit CMT + (CMT[01]) + - "renesas,cmt-48-r8a7791" for the r8a7791 48-bit CMT + (CMT[01]) + - "renesas,cmt-48-gen2" for all second generation 48-bit CMT (CMT[01] on r8a73a4, r8a7790 and r8a7791) + This is a fallback for the renesas,cmt-48-r8a73a4, + renesas,cmt-48-r8a7790 and renesas,cmt-48-r8a7791 entries. - reg: base address and length of the registers block for the timer module. - interrupts: interrupt-specifier for the timer, one per channel. @@ -36,7 +68,7 @@ Example: R8A7790 (R-Car H2) CMT0 node them channels 0 and 1 in the documentation. cmt0: timer@ffca0000 { - compatible = "renesas,cmt-48-gen2"; + compatible = "renesas,cmt-48-r8a7790", "renesas,cmt-48-gen2"; reg = <0 0xffca0000 0 0x1004>; interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>, <0 142 IRQ_TYPE_LEVEL_HIGH>; From ffd24a543afe4c693d5c611ecfa01cc48e97f97d Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 27 Aug 2014 13:36:51 +0900 Subject: [PATCH 05/16] clocksource: sh_mtu2: Document r7s72100 binding In general Renesas hardware is not documented to the extent where the relationship between IP blocks on different SoCs can be assumed although they may appear to operate the same way. Furthermore the documentation typically does not specify a version for individual IP blocks. For these reasons a convention of using the SoC name in place of a version and providing SoC-specific compat strings has been adopted. Although not universally liked this convention is used in the bindings for a number of drivers for Renesas hardware. The purpose of this patch is to update the Renesas R-Car Multi-Function Timer Pulse Unit 2 (MTU2) driver to follow this convention. Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Acked-by: Laurent Pinchart --- * I plan to follow up with a patch patch to use the new binding in the dtsi files for the r7s72100 SoC. v2 * Suggestions by Mark Rutland and Sergei Shtylyov - Compatible strings should be "one or more" not "one" of those listed - Describe the generic binding as covering any MTU2 device - Re-order compat strings from most to least specific v3 * Suggested by Laurent Pinchart - Reword compat documentation for consistency with a more extensive CMT change --- Documentation/devicetree/bindings/timer/renesas,mtu2.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/timer/renesas,mtu2.txt b/Documentation/devicetree/bindings/timer/renesas,mtu2.txt index 917453f826bc..d9a8d5af1a21 100644 --- a/Documentation/devicetree/bindings/timer/renesas,mtu2.txt +++ b/Documentation/devicetree/bindings/timer/renesas,mtu2.txt @@ -8,7 +8,10 @@ are independent. The MTU2 hardware supports five channels indexed from 0 to 4. Required Properties: - - compatible: must contain "renesas,mtu2" + - compatible: must be one or more of the following: + - "renesas,mtu2-r7s72100" for the r7s72100 MTU2 + - "renesas,mtu2" for any MTU2 + This is a fallback for the above renesas,mtu2-* entries - reg: base address and length of the registers block for the timer module. @@ -26,7 +29,7 @@ Required Properties: Example: R7S72100 (RZ/A1H) MTU2 node mtu2: timer@fcff0000 { - compatible = "renesas,mtu2"; + compatible = "renesas,mtu2-r7s72100", "renesas,mtu2"; reg = <0xfcff0000 0x400>; interrupts = <0 139 IRQ_TYPE_LEVEL_HIGH>, <0 146 IRQ_TYPE_LEVEL_HIGH>, From fb0eee2f141976b5d7f31e477a71556d312f7dc3 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 27 Aug 2014 13:36:51 +0900 Subject: [PATCH 06/16] clocksource: sh_tmu: Document r8a7779 binding In general Renesas hardware is not documented to the extent where the relationship between IP blocks on different SoCs can be assumed although they may appear to operate the same way. Furthermore the documentation typically does not specify a version for individual IP blocks. For these reasons a convention of using the SoC name in place of a version and providing SoC-specific compat strings has been adopted. Although not universally liked this convention is used in the bindings for a number of drivers for Renesas hardware. The purpose of this patch is to update the Renesas R-Car Timer Unit (TMU) driver to follow this convention. Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Acked-by: Laurent Pinchart --- * I plan to follow up with a patch patch to use the new binding in the dtsi files for the r8a7779 SoC. commit 471269b790aec03385dc4fb127ed7094ff83c16d v2 * Suggestions by Mark Rutland and Sergei Shtylyov - Compatible strings should be "one or more" not "one" of those listed - Describe the generic binding as covering any MTU2 device - Re-order compat strings from most to least specific v3 * Suggested by Laurent Pinchart - Reword in keeping with a similar though more extensive patch for CMT --- Documentation/devicetree/bindings/timer/renesas,tmu.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.txt b/Documentation/devicetree/bindings/timer/renesas,tmu.txt index 425d0c5f4aee..7db89fb25444 100644 --- a/Documentation/devicetree/bindings/timer/renesas,tmu.txt +++ b/Documentation/devicetree/bindings/timer/renesas,tmu.txt @@ -8,7 +8,10 @@ are independent. The TMU hardware supports up to three channels. Required Properties: - - compatible: must contain "renesas,tmu" + - compatible: must contain one or more of the following: + - "renesas,tmu-r8a7779" for the r8a7779 TMU + - "renesas,tmu" for any TMU. + This is a fallback for the above renesas,tmu-* entries - reg: base address and length of the registers block for the timer module. @@ -27,7 +30,7 @@ Optional Properties: Example: R8A7779 (R-Car H1) TMU0 node tmu0: timer@ffd80000 { - compatible = "renesas,tmu"; + compatible = "renesas,tmu-r8a7779", "renesas,tmu"; reg = <0xffd80000 0x30>; interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>, <0 33 IRQ_TYPE_LEVEL_HIGH>, From 66b2e373b3092ee8b1131c790074e7eb20ed1545 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Mon, 29 Sep 2014 01:50:05 +0200 Subject: [PATCH 07/16] ARM: meson: documentation: Add timer documentation Acked-by: Arnd Bergmann Signed-off-by: Carlo Caione Signed-off-by: Daniel Lezcano --- .../bindings/timer/amlogic,meson6-timer.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/amlogic,meson6-timer.txt diff --git a/Documentation/devicetree/bindings/timer/amlogic,meson6-timer.txt b/Documentation/devicetree/bindings/timer/amlogic,meson6-timer.txt new file mode 100644 index 000000000000..a092053f7902 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/amlogic,meson6-timer.txt @@ -0,0 +1,15 @@ +Amlogic Meson6 SoCs Timer Controller + +Required properties: + +- compatible : should be "amlogic,meson6-timer" +- reg : Specifies base physical address and size of the registers. +- interrupts : The interrupt of the first timer + +Example: + +timer@c1109940 { + compatible = "amlogic,meson6-timer"; + reg = <0xc1109940 0x14>; + interrupts = <0 10 1>; +}; From e4a6b378751fa8934c691816da1423e849059fad Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Mon, 29 Sep 2014 01:50:05 +0200 Subject: [PATCH 08/16] ARM: meson6: clocksource: Add Meson6 timer support Meson6 SoCs are equipped with 5 32-bit timers, called TIMER_A, TIMER_B, TIMER_C, TIMER_D and TIMER_E. The driver is providing clocksource support for the 32-bit counter using TIMER_E. Clockevents are also supported using TIMER_A. Acked-by: Arnd Bergmann Signed-off-by: Carlo Caione Signed-off-by: Daniel Lezcano Reviewed-by: Matthias Brugger --- drivers/clocksource/Kconfig | 3 + drivers/clocksource/Makefile | 1 + drivers/clocksource/meson6_timer.c | 167 +++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 drivers/clocksource/meson6_timer.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cfd6519df661..38029ca4e777 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -30,6 +30,9 @@ config ARMADA_370_XP_TIMER bool select CLKSRC_OF +config MESON6_TIMER + bool + config ORION_TIMER select CLKSRC_OF select CLKSRC_MMIO diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 7fd9fd1dff42..e4ae987d70aa 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o +obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c new file mode 100644 index 000000000000..5c15cba41dca --- /dev/null +++ b/drivers/clocksource/meson6_timer.c @@ -0,0 +1,167 @@ +/* + * Amlogic Meson6 SoCs timer handling. + * + * Copyright (C) 2014 Carlo Caione + * + * Based on code from Amlogic, Inc + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CED_ID 0 +#define CSD_ID 4 + +#define TIMER_ISA_MUX 0 +#define TIMER_ISA_VAL(t) (((t) + 1) << 2) + +#define TIMER_INPUT_BIT(t) (2 * (t)) +#define TIMER_ENABLE_BIT(t) (16 + (t)) +#define TIMER_PERIODIC_BIT(t) (12 + (t)) + +#define TIMER_CED_INPUT_MASK (3UL << TIMER_INPUT_BIT(CED_ID)) +#define TIMER_CSD_INPUT_MASK (7UL << TIMER_INPUT_BIT(CSD_ID)) + +#define TIMER_CED_UNIT_1US 0 +#define TIMER_CSD_UNIT_1US 1 + +static void __iomem *timer_base; + +static u64 notrace meson6_timer_sched_read(void) +{ + return (u64)readl(timer_base + TIMER_ISA_VAL(CSD_ID)); +} + +static void meson6_clkevt_time_stop(unsigned char timer) +{ + u32 val = readl(timer_base + TIMER_ISA_MUX); + + writel(val & ~TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); +} + +static void meson6_clkevt_time_setup(unsigned char timer, unsigned long delay) +{ + writel(delay, timer_base + TIMER_ISA_VAL(timer)); +} + +static void meson6_clkevt_time_start(unsigned char timer, bool periodic) +{ + u32 val = readl(timer_base + TIMER_ISA_MUX); + + if (periodic) + val |= TIMER_PERIODIC_BIT(timer); + else + val &= ~TIMER_PERIODIC_BIT(timer); + + writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); +} + +static void meson6_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC/HZ - 1); + meson6_clkevt_time_start(CED_ID, true); + break; + case CLOCK_EVT_MODE_ONESHOT: + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_start(CED_ID, false); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + meson6_clkevt_time_stop(CED_ID); + break; + } +} + +static int meson6_clkevt_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_setup(CED_ID, evt); + meson6_clkevt_time_start(CED_ID, false); + + return 0; +} + +static struct clock_event_device meson6_clockevent = { + .name = "meson6_tick", + .rating = 400, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = meson6_clkevt_mode, + .set_next_event = meson6_clkevt_next_event, +}; + +static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = (struct clock_event_device *)dev_id; + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct irqaction meson6_timer_irq = { + .name = "meson6_timer", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = meson6_timer_interrupt, + .dev_id = &meson6_clockevent, +}; + +static void __init meson6_timer_init(struct device_node *node) +{ + u32 val; + int ret, irq; + + timer_base = of_io_request_and_map(node, 0, "meson6-timer"); + if (IS_ERR(timer_base)) + panic("Can't map registers"); + + irq = irq_of_parse_and_map(node, 0); + if (irq <= 0) + panic("Can't parse IRQ"); + + /* Set 1us for timer E */ + val = readl(timer_base + TIMER_ISA_MUX); + val &= ~TIMER_CSD_INPUT_MASK; + val |= TIMER_CSD_UNIT_1US << TIMER_INPUT_BIT(CSD_ID); + writel(val, timer_base + TIMER_ISA_MUX); + + sched_clock_register(meson6_timer_sched_read, 32, USEC_PER_SEC); + clocksource_mmio_init(timer_base + TIMER_ISA_VAL(CSD_ID), node->name, + 1000 * 1000, 300, 32, clocksource_mmio_readl_up); + + /* Timer A base 1us */ + val &= ~TIMER_CED_INPUT_MASK; + val |= TIMER_CED_UNIT_1US << TIMER_INPUT_BIT(CED_ID); + writel(val, timer_base + TIMER_ISA_MUX); + + /* Stop the timer A */ + meson6_clkevt_time_stop(CED_ID); + + ret = setup_irq(irq, &meson6_timer_irq); + if (ret) + pr_warn("failed to setup irq %d\n", irq); + + meson6_clockevent.cpumask = cpu_possible_mask; + meson6_clockevent.irq = irq; + + clockevents_config_and_register(&meson6_clockevent, USEC_PER_SEC, + 1, 0xfffe); +} +CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", + meson6_timer_init); From 04f7e3e5134b9517bd9a78a84a9ee0f982d3ebdd Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 29 Sep 2014 01:50:05 +0200 Subject: [PATCH 09/16] clocksource: vf_pit_timer: Support shutdown mode In order to avoid waking up the system in a low power mode, the clocksource should not generate interrupts anymore. Disable the PIT timer interrupt when changing into the CLOCK_EVT_MODE_SHUTDOWN mode. [dlezcano] : remove superfluous empty line Signed-off-by: Stefan Agner Signed-off-by: Daniel Lezcano Acked-by: Bill Pringlemeir --- drivers/clocksource/vf_pit_timer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c index a918bc481c52..b45ac6229b57 100644 --- a/drivers/clocksource/vf_pit_timer.c +++ b/drivers/clocksource/vf_pit_timer.c @@ -93,6 +93,10 @@ static void pit_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_PERIODIC: pit_set_next_event(cycle_per_jiffy, evt); break; + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + pit_timer_disable(); + break; default: break; } From c387f07e6205cc13f57c1def5f885bf0a20e1c2d Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 29 Sep 2014 01:50:05 +0200 Subject: [PATCH 10/16] clocksource: arm_arch_timer: Discard unavailable timers correctly Currently we wait until both cp15 and mem timers are probed if we have both timer device nodes present in the device tree without checking if the device is actually available. If one of the timer device node present is disabled, the system locks up on the boot as no timer gets registered. This patch adds the check for the availability of the timer device so that unavailable timers are discarded correctly. It also adds the missing of_node_put. Signed-off-by: Sudeep Holla Reviewed-by: Stephen Boyd Acked-by: Mark Rutland Signed-off-by: Daniel Lezcano --- drivers/clocksource/arm_arch_timer.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 5163ec13429d..7e267e3990ab 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -616,17 +616,29 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = { {}, }; +static bool __init +arch_timer_probed(int type, const struct of_device_id *matches) +{ + struct device_node *dn; + bool probed = false; + + dn = of_find_matching_node(NULL, matches); + if (dn && of_device_is_available(dn) && (arch_timers_present & type)) + probed = true; + of_node_put(dn); + + return probed; +} + static void __init arch_timer_common_init(void) { unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER; /* Wait until both nodes are probed if we have two timers */ if ((arch_timers_present & mask) != mask) { - if (of_find_matching_node(NULL, arch_timer_mem_of_match) && - !(arch_timers_present & ARCH_MEM_TIMER)) + if (!arch_timer_probed(ARCH_MEM_TIMER, arch_timer_mem_of_match)) return; - if (of_find_matching_node(NULL, arch_timer_of_match) && - !(arch_timers_present & ARCH_CP15_TIMER)) + if (!arch_timer_probed(ARCH_CP15_TIMER, arch_timer_of_match)) return; } From 2743f1beb0d31be9f59b6fc84f755fb4e173df4d Mon Sep 17 00:00:00 2001 From: Gael Portay Date: Mon, 29 Sep 2014 01:50:05 +0200 Subject: [PATCH 11/16] clocksource: tcb_clksrc: Sanitize IRQ request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clock is not unprepared in case of the request IRQ fails. Also update to request_irq. Signed-off-by: Gaƫl PORTAY Acked-by: Daniel Lezcano Acked-by: Boris Brezillon Signed-off-by: Daniel Lezcano --- drivers/clocksource/tcb_clksrc.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index a8d7ea14f183..c0b56ea2ddf6 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -178,12 +178,6 @@ static irqreturn_t ch2_irq(int irq, void *handle) return IRQ_NONE; } -static struct irqaction tc_irqaction = { - .name = "tc_clkevt", - .flags = IRQF_TIMER, - .handler = ch2_irq, -}; - static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) { int ret; @@ -198,15 +192,16 @@ static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) clkevt.regs = tc->regs; clkevt.clk = t2_clk; - tc_irqaction.dev_id = &clkevt; timer_clock = clk32k_divisor_idx; clkevt.clkevt.cpumask = cpumask_of(0); - ret = setup_irq(irq, &tc_irqaction); - if (ret) + ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt); + if (ret) { + clk_disable_unprepare(t2_clk); return ret; + } clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff); From 4e2bec0c327025671c1ec2101660e8fea29d9d89 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 29 Sep 2014 01:50:05 +0200 Subject: [PATCH 12/16] clocksource: cadence_ttc: Add support for 32bit mode New TTCs support 32bit mode. Older versions support only 16bit modes. Keep 16bit mode as default and 32bit optional. Signed-off-by: Michal Simek Signed-off-by: Daniel Lezcano --- drivers/clocksource/cadence_ttc_timer.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 7a08811df9aa..510c8a1d37b3 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -25,7 +25,7 @@ #include /* - * This driver configures the 2 16-bit count-up timers as follows: + * This driver configures the 2 16/32-bit count-up timers as follows: * * T1: Timer 1, clocksource for generic timekeeping * T2: Timer 2, clockevent source for hrtimers @@ -321,7 +321,8 @@ static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, return NOTIFY_DONE; } -static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) +static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base, + u32 timer_width) { struct ttc_timer_clocksource *ttccs; int err; @@ -351,7 +352,7 @@ static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) ttccs->cs.name = "ttc_clocksource"; ttccs->cs.rating = 200; ttccs->cs.read = __ttc_clocksource_read; - ttccs->cs.mask = CLOCKSOURCE_MASK(16); + ttccs->cs.mask = CLOCKSOURCE_MASK(timer_width); ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; /* @@ -372,7 +373,8 @@ static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) } ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET; - sched_clock_register(ttc_sched_clock_read, 16, ttccs->ttc.freq / PRESCALE); + sched_clock_register(ttc_sched_clock_read, timer_width, + ttccs->ttc.freq / PRESCALE); } static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, @@ -467,6 +469,7 @@ static void __init ttc_timer_init(struct device_node *timer) struct clk *clk_cs, *clk_ce; static int initialized; int clksel; + u32 timer_width = 16; if (initialized) return; @@ -490,6 +493,8 @@ static void __init ttc_timer_init(struct device_node *timer) BUG(); } + of_property_read_u32(timer, "timer-width", &timer_width); + clksel = readl_relaxed(timer_baseaddr + TTC_CLK_CNTRL_OFFSET); clksel = !!(clksel & TTC_CLK_CNTRL_CSRC_MASK); clk_cs = of_clk_get(timer, clksel); @@ -506,7 +511,7 @@ static void __init ttc_timer_init(struct device_node *timer) BUG(); } - ttc_setup_clocksource(clk_cs, timer_baseaddr); + ttc_setup_clocksource(clk_cs, timer_baseaddr, timer_width); ttc_setup_clockevent(clk_ce, timer_baseaddr + 4, irq); pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq); From 28cf35675a66947b20731f6acbc9d5b131930ce3 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Mon, 29 Sep 2014 01:50:06 +0200 Subject: [PATCH 13/16] clocksource: sirf: Disable counter before re-setting it According to HW spec, we have to disable the counter before setting it, if we don't this, in pressure test, sometimes the timer might not generate interrupt any more. And this patch also fixes a typo for register set by changing 0x7 to 0x3. 0x7 is loop mode in HW, but here we are using oneshot 0x3. Signed-off-by: Hao Liu Signed-off-by: Barry Song Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-marco.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index 330e93064692..caf7a2030461 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c @@ -63,7 +63,7 @@ static inline void sirfsoc_timer_count_disable(int idx) /* enable count and interrupt */ static inline void sirfsoc_timer_count_enable(int idx) { - writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x7, + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); } @@ -103,6 +103,9 @@ static int sirfsoc_timer_set_next_event(unsigned long delta, { int cpu = smp_processor_id(); + /* disable timer first, then modify the related registers */ + sirfsoc_timer_count_disable(cpu); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 + 4 * cpu); writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 + From 423bd69e69f565167ba14e2fe61df76c3c4a0d26 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Mon, 29 Sep 2014 01:50:06 +0200 Subject: [PATCH 14/16] clocksource: arm_arch_timer: Change clocksource name if CP15 unavailable The arm and arm64 VDSOs need CP15 access to the architected counter. If this is unavailable (which is allowed by ARM v7), indicate this by changing the clocksource name to "arch_mem_counter" before registering the clocksource. Suggested by Stephen Boyd. Signed-off-by: Nathan Lynch Reviewed-by: Stephen Boyd Signed-off-by: Daniel Lezcano Acked-by: Will Deacon --- drivers/clocksource/arm_arch_timer.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 7e267e3990ab..e0e7729d37fd 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -429,11 +429,19 @@ static void __init arch_counter_register(unsigned type) u64 start_count; /* Register the CP15 based counter if we have one */ - if (type & ARCH_CP15_TIMER) + if (type & ARCH_CP15_TIMER) { arch_timer_read_counter = arch_counter_get_cntvct; - else + } else { arch_timer_read_counter = arch_counter_get_cntvct_mem; + /* If the clocksource name is "arch_sys_counter" the + * VDSO will attempt to read the CP15-based counter. + * Ensure this does not happen when CP15-based + * counter is not available. + */ + clocksource_counter.name = "arch_mem_counter"; + } + start_count = arch_timer_read_counter(); clocksource_register_hz(&clocksource_counter, arch_timer_rate); cyclecounter.mult = clocksource_counter.mult; From 8b8dde00347ef409b29abd97e5833ffdb4ed7508 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Mon, 29 Sep 2014 01:50:06 +0200 Subject: [PATCH 15/16] clocksource: arm_arch_timer: Enable counter access for 32-bit ARM The only difference between arm and arm64's implementations of arch_counter_set_user_access is that 32-bit ARM does not enable user access to the virtual counter. We want to enable this access for the 32-bit ARM VDSO, so copy the arm64 version to the driver itself, and remove the arch-specific implementations. Signed-off-by: Nathan Lynch Signed-off-by: Daniel Lezcano Acked-by: Will Deacon --- arch/arm/include/asm/arch_timer.h | 14 -------------- arch/arm64/include/asm/arch_timer.h | 17 ----------------- drivers/clocksource/arm_arch_timer.c | 17 +++++++++++++++++ 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index 0704e0cf5571..b7ae44464231 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h @@ -99,20 +99,6 @@ static inline void arch_timer_set_cntkctl(u32 cntkctl) asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); } -static inline void arch_counter_set_user_access(void) -{ - u32 cntkctl = arch_timer_get_cntkctl(); - - /* Disable user access to both physical/virtual counters/timers */ - /* Also disable virtual event stream */ - cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN - | ARCH_TIMER_USR_VT_ACCESS_EN - | ARCH_TIMER_VIRT_EVT_EN - | ARCH_TIMER_USR_VCT_ACCESS_EN - | ARCH_TIMER_USR_PCT_ACCESS_EN); - arch_timer_set_cntkctl(cntkctl); -} - static inline void arch_timer_evtstrm_enable(int divider) { u32 cntkctl = arch_timer_get_cntkctl(); diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index 9400596a0f39..49e94c677e7a 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -104,23 +104,6 @@ static inline void arch_timer_set_cntkctl(u32 cntkctl) asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl)); } -static inline void arch_counter_set_user_access(void) -{ - u32 cntkctl = arch_timer_get_cntkctl(); - - /* Disable user access to the timers and the physical counter */ - /* Also disable virtual event stream */ - cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN - | ARCH_TIMER_USR_VT_ACCESS_EN - | ARCH_TIMER_VIRT_EVT_EN - | ARCH_TIMER_USR_PCT_ACCESS_EN); - - /* Enable user access to the virtual counter */ - cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; - - arch_timer_set_cntkctl(cntkctl); -} - static inline void arch_timer_evtstrm_enable(int divider) { u32 cntkctl = arch_timer_get_cntkctl(); diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index e0e7729d37fd..42bd4455daca 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -312,6 +312,23 @@ static void arch_timer_configure_evtstream(void) arch_timer_evtstrm_enable(min(pos, 15)); } +static void arch_counter_set_user_access(void) +{ + u32 cntkctl = arch_timer_get_cntkctl(); + + /* Disable user access to the timers and the physical counter */ + /* Also disable virtual event stream */ + cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN + | ARCH_TIMER_USR_VT_ACCESS_EN + | ARCH_TIMER_VIRT_EVT_EN + | ARCH_TIMER_USR_PCT_ACCESS_EN); + + /* Enable user access to the virtual counter */ + cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; + + arch_timer_set_cntkctl(cntkctl); +} + static int arch_timer_setup(struct clock_event_device *clk) { __arch_timer_setup(ARCH_CP15_TIMER, clk); From e1ce5c7adc735ce96a35806ca32ceb78e607a283 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Mon, 29 Sep 2014 01:50:06 +0200 Subject: [PATCH 16/16] clocksource: arm_arch_timer: Consolidate arch_timer_evtstrm_enable The arch_timer_evtstrm_enable hooks in arm and arm64 are substantially similar, the only difference being a CONFIG_COMPAT-conditional section which is relevant only for arm64. Copy the arm64 version to the driver, removing the arch-specific hooks. Signed-off-by: Nathan Lynch Signed-off-by: Daniel Lezcano Acked-by: Will Deacon --- arch/arm/include/asm/arch_timer.h | 11 ----------- arch/arm64/include/asm/arch_timer.h | 14 -------------- drivers/clocksource/arm_arch_timer.c | 15 +++++++++++++++ 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index b7ae44464231..92793ba69c40 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h @@ -99,17 +99,6 @@ static inline void arch_timer_set_cntkctl(u32 cntkctl) asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); } -static inline void arch_timer_evtstrm_enable(int divider) -{ - u32 cntkctl = arch_timer_get_cntkctl(); - cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK; - /* Set the divider and enable virtual event stream */ - cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) - | ARCH_TIMER_VIRT_EVT_EN; - arch_timer_set_cntkctl(cntkctl); - elf_hwcap |= HWCAP_EVTSTRM; -} - #endif #endif diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index 49e94c677e7a..f19097134b02 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -104,20 +104,6 @@ static inline void arch_timer_set_cntkctl(u32 cntkctl) asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl)); } -static inline void arch_timer_evtstrm_enable(int divider) -{ - u32 cntkctl = arch_timer_get_cntkctl(); - cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK; - /* Set the divider and enable virtual event stream */ - cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) - | ARCH_TIMER_VIRT_EVT_EN; - arch_timer_set_cntkctl(cntkctl); - elf_hwcap |= HWCAP_EVTSTRM; -#ifdef CONFIG_COMPAT - compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM; -#endif -} - static inline u64 arch_counter_get_cntvct(void) { u64 cval; diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 42bd4455daca..2133f9d59d06 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -299,6 +299,21 @@ static void __arch_timer_setup(unsigned type, clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); } +static void arch_timer_evtstrm_enable(int divider) +{ + u32 cntkctl = arch_timer_get_cntkctl(); + + cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK; + /* Set the divider and enable virtual event stream */ + cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) + | ARCH_TIMER_VIRT_EVT_EN; + arch_timer_set_cntkctl(cntkctl); + elf_hwcap |= HWCAP_EVTSTRM; +#ifdef CONFIG_COMPAT + compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM; +#endif +} + static void arch_timer_configure_evtstream(void) { int evt_stream_div, pos;