From 7ec88e4be461590b5a3817460c34603f76d9b3ae Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 28 Sep 2015 22:21:28 +0200 Subject: ntp/pps: use timespec64 for hardpps() There is only one user of the hardpps function in the kernel, so it makes sense to atomically change it over to using 64-bit timestamps for y2038 safety. In the hardpps implementation, we also need to change the pps_normtime structure, which is similar to struct timespec and also requires a 64-bit seconds portion. This introduces two temporary variables in pps_kc_event() to do the conversion, they will be removed again in the next step, which seemed preferable to having a larger patch changing it all at the same time. Acked-by: Richard Cochran Acked-by: David S. Miller Reviewed-by: Thomas Gleixner Signed-off-by: Arnd Bergmann Signed-off-by: John Stultz --- drivers/pps/kc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c index e219db1f1c84..a16cea2ba980 100644 --- a/drivers/pps/kc.c +++ b/drivers/pps/kc.c @@ -113,10 +113,12 @@ void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts, int event) { unsigned long flags; + struct timespec64 real = timespec_to_timespec64(ts->ts_real); + struct timespec64 raw = timespec_to_timespec64(ts->ts_raw); /* Pass some events to kernel consumer if activated */ spin_lock_irqsave(&pps_kc_hardpps_lock, flags); if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode) - hardpps(&ts->ts_real, &ts->ts_raw); + hardpps(&real, &raw); spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags); } -- cgit v1.2.3 From ade1bdffe90e59cd257cb9bd4f5abe4de5f14911 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 28 Sep 2015 22:21:31 +0200 Subject: ntp/pps: use y2038 safe types in pps_event_time The pps_event_time uses two 'timespec' structures internally, which suffer from the y2038 problem. The uses of this structure are fairly self-contained in the pps code, so this replaces them all at once. Unfortunately, this includes the sfc ethernet driver aside from the pps subsystem, so we change that one as well. Both touch the same data structure, and there probably is no good way to split the patch into smaller units. Acked-by: Richard Cochran Acked-by: David S. Miller Reviewed-by: Thomas Gleixner Signed-off-by: Arnd Bergmann Signed-off-by: John Stultz --- drivers/net/ethernet/sfc/ptp.c | 16 ++++++++-------- drivers/pps/kapi.c | 4 ++-- drivers/pps/kc.c | 4 +--- include/linux/pps_kernel.h | 21 ++++++++------------- 4 files changed, 19 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index ad62615a93dc..fe849dbf9f80 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -646,28 +646,28 @@ static void efx_ptp_send_times(struct efx_nic *efx, struct pps_event_time *last_time) { struct pps_event_time now; - struct timespec limit; + struct timespec64 limit; struct efx_ptp_data *ptp = efx->ptp_data; - struct timespec start; + struct timespec64 start; int *mc_running = ptp->start.addr; pps_get_ts(&now); start = now.ts_real; limit = now.ts_real; - timespec_add_ns(&limit, SYNCHRONISE_PERIOD_NS); + timespec64_add_ns(&limit, SYNCHRONISE_PERIOD_NS); /* Write host time for specified period or until MC is done */ - while ((timespec_compare(&now.ts_real, &limit) < 0) && + while ((timespec64_compare(&now.ts_real, &limit) < 0) && ACCESS_ONCE(*mc_running)) { - struct timespec update_time; + struct timespec64 update_time; unsigned int host_time; /* Don't update continuously to avoid saturating the PCIe bus */ update_time = now.ts_real; - timespec_add_ns(&update_time, SYNCHRONISATION_GRANULARITY_NS); + timespec64_add_ns(&update_time, SYNCHRONISATION_GRANULARITY_NS); do { pps_get_ts(&now); - } while ((timespec_compare(&now.ts_real, &update_time) < 0) && + } while ((timespec64_compare(&now.ts_real, &update_time) < 0) && ACCESS_ONCE(*mc_running)); /* Synchronise NIC with single word of time only */ @@ -723,7 +723,7 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf), struct efx_ptp_data *ptp = efx->ptp_data; u32 last_sec; u32 start_sec; - struct timespec delta; + struct timespec64 delta; ktime_t mc_time; if (number_readings == 0) diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index cdad4d95b20e..805c749ac1ad 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -179,8 +179,8 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, /* check event type */ BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0); - dev_dbg(pps->dev, "PPS event at %ld.%09ld\n", - ts->ts_real.tv_sec, ts->ts_real.tv_nsec); + dev_dbg(pps->dev, "PPS event at %lld.%09ld\n", + (s64)ts->ts_real.tv_sec, ts->ts_real.tv_nsec); timespec_to_pps_ktime(&ts_real, ts->ts_real); diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c index a16cea2ba980..e219db1f1c84 100644 --- a/drivers/pps/kc.c +++ b/drivers/pps/kc.c @@ -113,12 +113,10 @@ void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts, int event) { unsigned long flags; - struct timespec64 real = timespec_to_timespec64(ts->ts_real); - struct timespec64 raw = timespec_to_timespec64(ts->ts_raw); /* Pass some events to kernel consumer if activated */ spin_lock_irqsave(&pps_kc_hardpps_lock, flags); if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode) - hardpps(&real, &raw); + hardpps(&ts->ts_real, &ts->ts_raw); spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags); } diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index b2fbd62ab18d..54bf1484d41f 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -48,9 +48,9 @@ struct pps_source_info { struct pps_event_time { #ifdef CONFIG_NTP_PPS - struct timespec ts_raw; + struct timespec64 ts_raw; #endif /* CONFIG_NTP_PPS */ - struct timespec ts_real; + struct timespec64 ts_real; }; /* The main struct */ @@ -105,7 +105,7 @@ extern void pps_event(struct pps_device *pps, struct pps_device *pps_lookup_dev(void const *cookie); static inline void timespec_to_pps_ktime(struct pps_ktime *kt, - struct timespec ts) + struct timespec64 ts) { kt->sec = ts.tv_sec; kt->nsec = ts.tv_nsec; @@ -115,29 +115,24 @@ static inline void timespec_to_pps_ktime(struct pps_ktime *kt, static inline void pps_get_ts(struct pps_event_time *ts) { - struct timespec64 raw, real; - - ktime_get_raw_and_real_ts64(&raw, &real); - - ts->ts_raw = timespec64_to_timespec(raw); - ts->ts_real = timespec64_to_timespec(real); + ktime_get_raw_and_real_ts64(&ts->ts_raw, &ts->ts_real); } #else /* CONFIG_NTP_PPS */ static inline void pps_get_ts(struct pps_event_time *ts) { - getnstimeofday(&ts->ts_real); + ktime_get_real_ts64(&ts->ts_real); } #endif /* CONFIG_NTP_PPS */ /* Subtract known time delay from PPS event time(s) */ -static inline void pps_sub_ts(struct pps_event_time *ts, struct timespec delta) +static inline void pps_sub_ts(struct pps_event_time *ts, struct timespec64 delta) { - ts->ts_real = timespec_sub(ts->ts_real, delta); + ts->ts_real = timespec64_sub(ts->ts_real, delta); #ifdef CONFIG_NTP_PPS - ts->ts_raw = timespec_sub(ts->ts_raw, delta); + ts->ts_raw = timespec64_sub(ts->ts_raw, delta); #endif } -- cgit v1.2.3 From 090e2edb4171dae4872c4eaae972dd3ccf96d4a8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 28 Sep 2015 22:21:32 +0200 Subject: net: sfc: avoid using timespec The sfc driver internally uses a time format based on 32-bit (unsigned) seconds and 32-bit nanoseconds. This means it will overflow in 2106, but the value we pass into it is a signed 32-bit tv_sec that already overflows in 2038 to a negative value. This patch changes the logic to use the lower 32 bits of the timespec64 tv_sec in efx_ptp_ns_to_s_ns, which will have the correct value beyond the overflow. While this does not change any of the register values, it lets us keep using the driver after we deprecate the use of the timespec type in the kernel. In the efx_ptp_process_times function, the change to use timespec64 is similar, in that the tv_sec portion is ignored anyway and we only care about the nanosecond portion that remains unchanged. Acked-by: Richard Cochran Acked-by: David S. Miller Reviewed-by: Thomas Gleixner Signed-off-by: Arnd Bergmann Signed-off-by: John Stultz --- drivers/net/ethernet/sfc/ptp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index fe849dbf9f80..c771e0af4e06 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -401,8 +401,8 @@ size_t efx_ptp_update_stats(struct efx_nic *efx, u64 *stats) /* For Siena platforms NIC time is s and ns */ static void efx_ptp_ns_to_s_ns(s64 ns, u32 *nic_major, u32 *nic_minor) { - struct timespec ts = ns_to_timespec(ns); - *nic_major = ts.tv_sec; + struct timespec64 ts = ns_to_timespec64(ns); + *nic_major = (u32)ts.tv_sec; *nic_minor = ts.tv_nsec; } @@ -431,8 +431,8 @@ static ktime_t efx_ptp_s_ns_to_ktime_correction(u32 nic_major, u32 nic_minor, */ static void efx_ptp_ns_to_s27(s64 ns, u32 *nic_major, u32 *nic_minor) { - struct timespec ts = ns_to_timespec(ns); - u32 maj = ts.tv_sec; + struct timespec64 ts = ns_to_timespec64(ns); + u32 maj = (u32)ts.tv_sec; u32 min = (u32)(((u64)ts.tv_nsec * NS_TO_S27_MULT + (1ULL << (NS_TO_S27_SHIFT - 1))) >> NS_TO_S27_SHIFT); @@ -737,14 +737,14 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf), */ for (i = 0; i < number_readings; i++) { s32 window, corrected; - struct timespec wait; + struct timespec64 wait; efx_ptp_read_timeset( MCDI_ARRAY_STRUCT_PTR(synch_buf, PTP_OUT_SYNCHRONIZE_TIMESET, i), &ptp->timeset[i]); - wait = ktime_to_timespec( + wait = ktime_to_timespec64( ptp->nic_to_kernel_time(0, ptp->timeset[i].wait, 0)); window = ptp->timeset[i].window; corrected = window - wait.tv_nsec; @@ -803,7 +803,7 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf), ptp->timeset[last_good].minor, 0); /* Calculate delay from NIC top of second to last_time */ - delta.tv_nsec += ktime_to_timespec(mc_time).tv_nsec; + delta.tv_nsec += ktime_to_timespec64(mc_time).tv_nsec; /* Set PPS timestamp to match NIC top of second */ ptp->host_time_pps = *last_time; -- cgit v1.2.3 From fc686d0037d782c994e338ecb01bfef8bbafff9f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 24 Aug 2015 15:14:30 +0200 Subject: clockevents/drivers/mtk: Fix spurious interrupt leading to crash After analysis done by Yingjoe Chen, the timer appears to have a pending interrupt when it is enabled. Fix this by acknowledging the pending interrupt when enabling the timer interrupt. Signed-off-by: Daniel Lezcano Tested-by: Yingjoe Chen --- drivers/clocksource/mtk_timer.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index 50f0641c65b6..c8badc427eec 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -141,14 +141,6 @@ static irqreturn_t mtk_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void mtk_timer_global_reset(struct mtk_clock_event_device *evt) -{ - /* Disable all interrupts */ - writel(0x0, evt->gpt_base + GPT_IRQ_EN_REG); - /* Acknowledge all interrupts */ - writel(0x3f, evt->gpt_base + GPT_IRQ_ACK_REG); -} - static void mtk_timer_setup(struct mtk_clock_event_device *evt, u8 timer, u8 option) { @@ -168,6 +160,12 @@ static void mtk_timer_enable_irq(struct mtk_clock_event_device *evt, u8 timer) { u32 val; + /* Disable all interrupts */ + writel(0x0, evt->gpt_base + GPT_IRQ_EN_REG); + + /* Acknowledge all spurious pending interrupts */ + writel(0x3f, evt->gpt_base + GPT_IRQ_ACK_REG); + val = readl(evt->gpt_base + GPT_IRQ_EN_REG); writel(val | GPT_IRQ_ENABLE(timer), evt->gpt_base + GPT_IRQ_EN_REG); @@ -220,8 +218,6 @@ static void __init mtk_timer_init(struct device_node *node) } rate = clk_get_rate(clk); - mtk_timer_global_reset(evt); - 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); -- cgit v1.2.3 From f14665f63b92f958636b7e7610ec2c9726ea9335 Mon Sep 17 00:00:00 2001 From: Yingjoe Chen Date: Mon, 13 Jul 2015 17:32:46 +0800 Subject: clocksource/drivers/mediatek: Use GPT as sched clock source When cpu is in deep idle, arch timer will stop counting. Setup GPT as sched clock source so it can keep counting in idle. Signed-off-by: Yingjoe Chen Signed-off-by: Daniel Lezcano Acked-by: Stephen Boyd Acked-by: Matthias Brugger --- drivers/clocksource/mtk_timer.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index c8badc427eec..fbfc74685e6a 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #define GPT_IRQ_EN_REG 0x00 @@ -59,6 +60,13 @@ struct mtk_clock_event_device { struct clock_event_device dev; }; +static void __iomem *gpt_sched_reg __read_mostly; + +static u64 notrace mtk_read_sched_clock(void) +{ + return readl_relaxed(gpt_sched_reg); +} + static inline struct mtk_clock_event_device *to_mtk_clk( struct clock_event_device *c) { @@ -230,6 +238,8 @@ static void __init mtk_timer_init(struct device_node *node) mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN); clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC), node->name, rate, 300, 32, clocksource_mmio_readl_up); + gpt_sched_reg = evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC); + sched_clock_register(mtk_read_sched_clock, 32, rate); /* Configure clock event */ mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT); -- cgit v1.2.3 From fdbd13105d08fed6a8201549f389e9c12021b67b Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Thu, 10 Sep 2015 03:38:19 +0300 Subject: clocksource/drivers/em_sti: Remove unneeded memset()s Memory for cs and ced fields in struct em_sti_priv is allocated by devm_kzalloc() in the beginning of em_sti_probe() so they don't need to be zeroed one more time in em_sti_register_clocksource() and in em_sti_register_clockevent(). Signed-off-by: Alexey Klimov Signed-off-by: Daniel Lezcano --- drivers/clocksource/em_sti.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 7a97a34dba70..19bb1792d647 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -228,7 +228,6 @@ static int em_sti_register_clocksource(struct em_sti_priv *p) { struct clocksource *cs = &p->cs; - memset(cs, 0, sizeof(*cs)); cs->name = dev_name(&p->pdev->dev); cs->rating = 200; cs->read = em_sti_clocksource_read; @@ -285,7 +284,6 @@ static void em_sti_register_clockevent(struct em_sti_priv *p) { struct clock_event_device *ced = &p->ced; - memset(ced, 0, sizeof(*ced)); ced->name = dev_name(&p->pdev->dev); ced->features = CLOCK_EVT_FEAT_ONESHOT; ced->rating = 200; -- cgit v1.2.3 From 6eeb8c355fbbe66d1d52eadaa588d5651f8cb092 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Thu, 10 Sep 2015 03:38:20 +0300 Subject: clocksource/drivers/sh_cmt: Remove unneeded memset() in sh_cmt_setup() Memory for cmt struct is allocated by kzalloc() in sh_cmt_setup. Signed-off-by: Alexey Klimov Signed-off-by: Daniel Lezcano --- drivers/clocksource/sh_cmt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index ba73a6eb8d66..103c49362c68 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -962,7 +962,6 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) unsigned int i; int ret; - memset(cmt, 0, sizeof(*cmt)); cmt->pdev = pdev; raw_spin_lock_init(&cmt->lock); -- cgit v1.2.3 From ba49af35be8a41af7f00a37902a2d70764078bc5 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Thu, 10 Sep 2015 03:38:21 +0300 Subject: clocksource/drivers/h8300_*: Remove unneeded memset()s Memory for timer16_priv, timer8_priv and tpu_priv structs is allocated by devm_kzalloc() in corresponding probe functions of drivers. No need to zero it one more time. Signed-off-by: Alexey Klimov Signed-off-by: Daniel Lezcano --- drivers/clocksource/h8300_timer16.c | 1 - drivers/clocksource/h8300_timer8.c | 1 - drivers/clocksource/h8300_tpu.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c index 82941c1e9e33..0e076c6fc006 100644 --- a/drivers/clocksource/h8300_timer16.c +++ b/drivers/clocksource/h8300_timer16.c @@ -153,7 +153,6 @@ static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev) int ret, irq; unsigned int ch; - memset(p, 0, sizeof(*p)); p->pdev = pdev; res[REG_CH] = platform_get_resource(p->pdev, diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index f9b3b7033a97..44375d8b9bc4 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -215,7 +215,6 @@ static int timer8_setup(struct timer8_priv *p, int irq; int ret; - memset(p, 0, sizeof(*p)); p->pdev = pdev; res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c index 64195fdd78bf..5487410bfabb 100644 --- a/drivers/clocksource/h8300_tpu.c +++ b/drivers/clocksource/h8300_tpu.c @@ -123,7 +123,6 @@ static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev) { struct resource *res[2]; - memset(p, 0, sizeof(*p)); p->pdev = pdev; res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L); -- cgit v1.2.3 From 31f7987406497dc65408dee4e84e3f3cc3ffe9cd Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Fri, 4 Sep 2015 02:49:58 +0300 Subject: clocksource/drivers/exynos_mct: Use container_of() instead of this_cpu_ptr() Since evt structure is embedded in per-CPU mevt structure it's definitely faster to use container_of() to get access to mevt if we have evt (for example as incoming function argument) instead of more expensive approach with this_cpu_ptr(&percpu_mct_tick). this_cpu_ptr() on per-CPU mevt structure leads to access to cp15 to get cpu id and arithmetic operations. Container_of() is cheaper since it's just one asm instruction. This should work if used evt pointer is correct and owned by local mevt structure. For example, before this patch set_state_shutdown() looks like: 4a4: e92d4010 push {r4, lr} 4a8: e3004000 movw r4, #0 4ac: ebfffffe bl 0 4b0: e3003000 movw r3, #0 4b4: e3404000 movt r4, #0 4b8: e3403000 movt r3, #0 4bc: e7933100 ldr r3, [r3, r0, lsl #2] 4c0: e0844003 add r4, r4, r3 4c4: e59400c0 ldr r0, [r4, #192] ; 0xc0 4c8: ebffffd4 bl 420 4cc: e3a00000 mov r0, #0 4d0: e8bd8010 pop {r4, pc} With this patch: 4a4: e92d4010 push {r4, lr} 4a8: e59000c0 ldr r0, [r0, #192] ; 0xc0 4ac: ebffffdb bl 420 4b0: e3a00000 mov r0, #0 4b4: e8bd8010 pop {r4, pc} Also, for me size of exynos_mct.o decreased from 84588 bytes to 83956. Signed-off-by: Alexey Klimov Signed-off-by: Daniel Lezcano Reviewed-by: Krzysztof Kozlowski --- drivers/clocksource/exynos_mct.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 029f96ab131a..ff44082a0827 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -382,24 +382,28 @@ static void exynos4_mct_tick_start(unsigned long cycles, static int exynos4_tick_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); + struct mct_clock_event_device *mevt; + mevt = container_of(evt, struct mct_clock_event_device, evt); exynos4_mct_tick_start(cycles, mevt); - return 0; } static int set_state_shutdown(struct clock_event_device *evt) { - exynos4_mct_tick_stop(this_cpu_ptr(&percpu_mct_tick)); + struct mct_clock_event_device *mevt; + + mevt = container_of(evt, struct mct_clock_event_device, evt); + exynos4_mct_tick_stop(mevt); return 0; } static int set_state_periodic(struct clock_event_device *evt) { - struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); + struct mct_clock_event_device *mevt; unsigned long cycles_per_jiffy; + mevt = container_of(evt, struct mct_clock_event_device, evt); cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult) >> evt->shift); exynos4_mct_tick_stop(mevt); -- cgit v1.2.3 From f1c08c9bc8f475aa242270da30b6cc9232bd19e0 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 14 Oct 2015 11:24:17 +0200 Subject: clocksource/drivers/imx: Allow timer irq affinity change Allow the timer core to change the smp affinity of the broadcast timer irq by setting CLOCK_EVT_FEAT_DYNIRQ flag. For this to work the timer core needs to be told about the used irq. This reduces interrupt pressure and wakeups on CPU0 as well as vastly reducing the number of timer broadcast IPIs. Signed-off-by: Lucas Stach Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-imx-gpt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 839aba92fc39..99ec96769dda 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -305,13 +305,14 @@ static int __init mxc_clockevent_init(struct imx_timer *imxtm) struct irqaction *act = &imxtm->act; ced->name = "mxc_timer1"; - ced->features = CLOCK_EVT_FEAT_ONESHOT; + ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ; ced->set_state_shutdown = mxc_shutdown; ced->set_state_oneshot = mxc_set_oneshot; ced->tick_resume = mxc_shutdown; ced->set_next_event = imxtm->gpt->set_next_event; ced->rating = 200; ced->cpumask = cpumask_of(0); + ced->irq = imxtm->irq; clockevents_config_and_register(ced, clk_get_rate(imxtm->clk_per), 0xff, 0xfffffffe); -- cgit v1.2.3 From ccd63ce471c9b69663783e919ca4dba9967cd690 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Fri, 9 Oct 2015 16:59:18 +0200 Subject: clocksource/drivers/tango_xtal: Add new timer for Tango SoCs Sigma Designs Tango platforms provide a 27 MHz crystal oscillator. Use it for clocksource, sched_clock, and delay_timer. Signed-off-by: Marc Gonzalez Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 4 +++ drivers/clocksource/Makefile | 1 + drivers/clocksource/tango_xtal.c | 66 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 drivers/clocksource/tango_xtal.c (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index a7726db13abb..50b68bc20720 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -279,6 +279,10 @@ config CLKSRC_MIPS_GIC depends on MIPS_GIC select CLKSRC_OF +config CLKSRC_TANGO_XTAL + bool + select CLKSRC_OF + config CLKSRC_PXA def_bool y if ARCH_PXA || ARCH_SA1100 select CLKSRC_OF if OF diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 5c00863c3e33..fc9348dc4f92 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o 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 diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c new file mode 100644 index 000000000000..d297b30d2bc0 --- /dev/null +++ b/drivers/clocksource/tango_xtal.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include + +static void __iomem *xtal_in_cnt; +static struct delay_timer delay_timer; + +static unsigned long notrace read_xtal_counter(void) +{ + return readl_relaxed(xtal_in_cnt); +} + +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; + int xtal_freq, ret; + + xtal_in_cnt = of_iomap(np, 0); + if (xtal_in_cnt == NULL) { + pr_err("%s: invalid address\n", np->full_name); + return; + } + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("%s: invalid clock\n", np->full_name); + return; + } + + xtal_freq = clk_get_rate(clk); + delay_timer.freq = xtal_freq; + delay_timer.read_current_timer = read_xtal_counter; + + ret = clocksource_register_hz(&tango_xtal, xtal_freq); + if (ret != 0) { + pr_err("%s: registration failed\n", np->full_name); + return; + } + + sched_clock_register(read_sched_clock, 32, xtal_freq); + register_current_timer_delay(&delay_timer); +} + +CLOCKSOURCE_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init); -- cgit v1.2.3 From cb0f2538039c65f2bb64a9d427dbe9dd7d0f71a6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 19 Oct 2015 16:19:20 +0100 Subject: clocksource/drivers/armada-370-xp: Implement ARM delay timer Implement an ARM delay timer to be used for udelay() on Armada 37x platforms. This allows us to skip the delay loop calibration at boot, saving 180ms on the boot time of the kernel (which is around 10%). It also means that udelay() will be unaffected by CPU frequency changes when cpufreq is enabled on these platforms. Signed-off-by: Russell King Signed-off-by: Daniel Lezcano Tested-by: Gregory CLEMENT Acked-by: Gregory CLEMENT --- drivers/clocksource/time-armada-370-xp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 2162796fd504..d93ec3c4f139 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -45,6 +45,8 @@ #include #include +#include + /* * Timer block registers. */ @@ -249,6 +251,15 @@ struct syscore_ops armada_370_xp_timer_syscore_ops = { .resume = armada_370_xp_timer_resume, }; +static unsigned long armada_370_delay_timer_read(void) +{ + return ~readl(timer_base + TIMER0_VAL_OFF); +} + +static struct delay_timer armada_370_delay_timer = { + .read_current_timer = armada_370_delay_timer_read, +}; + static void __init armada_370_xp_timer_common_init(struct device_node *np) { u32 clr = 0, set = 0; @@ -287,6 +298,9 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np) TIMER0_RELOAD_EN | enable_mask, TIMER0_RELOAD_EN | enable_mask); + armada_370_delay_timer.freq = timer_clk; + register_current_timer_delay(&armada_370_delay_timer); + /* * Set scale and timer for sched_clock. */ -- cgit v1.2.3