From 1349401ff1aa425e7381ed26feb63e0d6b557fc6 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Tue, 19 Nov 2019 23:12:26 -0800 Subject: clocksource/drivers/hyper-v: Suspend/resume Hyper-V clocksource for hibernation This is needed for hibernation, e.g. when we resume the old kernel, we need to disable the "current" kernel's TSC page and then resume the old kernel's. Signed-off-by: Dexuan Cui Reviewed-by: Michael Kelley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1574233946-48377-1-git-send-email-decui@microsoft.com --- drivers/clocksource/hyperv_timer.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 287d8d58c21a..1aec08e82b7a 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -330,12 +330,37 @@ static u64 read_hv_sched_clock_tsc(void) return read_hv_clock_tsc(NULL) - hv_sched_clock_offset; } +static void suspend_hv_clock_tsc(struct clocksource *arg) +{ + u64 tsc_msr; + + /* Disable the TSC page */ + hv_get_reference_tsc(tsc_msr); + tsc_msr &= ~BIT_ULL(0); + hv_set_reference_tsc(tsc_msr); +} + + +static void resume_hv_clock_tsc(struct clocksource *arg) +{ + phys_addr_t phys_addr = virt_to_phys(&tsc_pg); + u64 tsc_msr; + + /* Re-enable the TSC page */ + hv_get_reference_tsc(tsc_msr); + tsc_msr &= GENMASK_ULL(11, 0); + tsc_msr |= BIT_ULL(0) | (u64)phys_addr; + hv_set_reference_tsc(tsc_msr); +} + static struct clocksource hyperv_cs_tsc = { .name = "hyperv_clocksource_tsc_page", .rating = 400, .read = read_hv_clock_tsc, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .suspend= suspend_hv_clock_tsc, + .resume = resume_hv_clock_tsc, }; static u64 notrace read_hv_clock_msr(struct clocksource *arg) -- cgit v1.2.3 From 9ca9fe69eedb483c0811a4db7cb94942edfb1404 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 20 Nov 2019 21:42:36 +0800 Subject: clocksource: Fix Kconfig indentation Adjust indentation from spaces to tab (+optional two spaces) as in coding style with command like: $ sed -e 's/^ /\t/' -i */Kconfig Signed-off-by: Krzysztof Kozlowski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191120134236.15959-1-krzk@kernel.org --- drivers/clocksource/Kconfig | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5fdd76cb1768..c981ff64bc13 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -470,7 +470,7 @@ config OXNAS_RPS_TIMER This enables support for the Oxford Semiconductor OXNAS RPS timers. config SYS_SUPPORTS_SH_CMT - bool + bool config MTK_TIMER bool "Mediatek timer driver" if COMPILE_TEST @@ -490,13 +490,13 @@ config SPRD_TIMER Enables support for the Spreadtrum timer driver. config SYS_SUPPORTS_SH_MTU2 - bool + bool config SYS_SUPPORTS_SH_TMU - bool + bool config SYS_SUPPORTS_EM_STI - bool + bool config CLKSRC_JCORE_PIT bool "J-Core PIT timer driver" if COMPILE_TEST @@ -591,21 +591,21 @@ config CLKSRC_PXA platforms. config H8300_TMR8 - bool "Clockevent timer for the H8300 platform" if COMPILE_TEST - depends on HAS_IOMEM + bool "Clockevent timer for the H8300 platform" if COMPILE_TEST + depends on HAS_IOMEM help This enables the 8 bits timer for the H8300 platform. config H8300_TMR16 - bool "Clockevent timer for the H83069 platform" if COMPILE_TEST - depends on HAS_IOMEM + bool "Clockevent timer for the H83069 platform" if COMPILE_TEST + depends on HAS_IOMEM help This enables the 16 bits timer for the H8300 platform with the H83069 cpu. config H8300_TPU - bool "Clocksource for the H8300 platform" if COMPILE_TEST - depends on HAS_IOMEM + bool "Clocksource for the H8300 platform" if COMPILE_TEST + depends on HAS_IOMEM help This enables the clocksource for the H8300 platform with the H8S2678 cpu. -- cgit v1.2.3 From 062934634dc3ae38baeb9961dcc80c44a00ffcf2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 27 Nov 2019 21:10:22 -0800 Subject: clocksource: Fix Kconfig miscues Fix lots of typo, spelling, punctuation, and grammar miscues in drivers/clocksource/Kconfig. Signed-off-by: Randy Dunlap Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: John Stultz Cc: Stephen Boyd Cc: linux-kernel@vger.kernel.org Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/4deb42a9-82f2-72f9-891f-972a9a399f4f@infradead.org --- drivers/clocksource/Kconfig | 46 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c981ff64bc13..94192fb0533e 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -88,7 +88,7 @@ config ROCKCHIP_TIMER select TIMER_OF select CLKSRC_MMIO help - Enables the support for the rockchip timer driver. + Enables the support for the Rockchip timer driver. config ARMADA_370_XP_TIMER bool "Armada 370 and XP timer driver" if COMPILE_TEST @@ -162,13 +162,13 @@ config NPCM7XX_TIMER select CLKSRC_MMIO help Enable 24-bit TIMER0 and TIMER1 counters in the NPCM7xx architecture, - While TIMER0 serves as clockevent and TIMER1 serves as clocksource. + where TIMER0 serves as clockevent and TIMER1 serves as clocksource. config CADENCE_TTC_TIMER bool "Cadence TTC timer driver" if COMPILE_TEST depends on COMMON_CLK help - Enables support for the cadence ttc driver. + Enables support for the Cadence TTC driver. config ASM9260_TIMER bool "ASM9260 timer driver" if COMPILE_TEST @@ -190,10 +190,10 @@ config CLKSRC_DBX500_PRCMU bool "Clocksource PRCMU Timer" if COMPILE_TEST depends on HAS_IOMEM help - Use the always on PRCMU Timer as clocksource + Use the always on PRCMU Timer as clocksource. config CLPS711X_TIMER - bool "Cirrus logic timer driver" if COMPILE_TEST + bool "Cirrus Logic timer driver" if COMPILE_TEST select CLKSRC_MMIO help Enables support for the Cirrus Logic PS711 timer. @@ -205,11 +205,11 @@ config ATLAS7_TIMER Enables support for the Atlas7 timer. config MXS_TIMER - bool "Mxs timer driver" if COMPILE_TEST + bool "MXS timer driver" if COMPILE_TEST select CLKSRC_MMIO select STMP_DEVICE help - Enables support for the Mxs timer. + Enables support for the MXS timer. config PRIMA2_TIMER bool "Prima2 timer driver" if COMPILE_TEST @@ -238,10 +238,10 @@ config KEYSTONE_TIMER Enables support for the Keystone timer. config INTEGRATOR_AP_TIMER - bool "Integrator-ap timer driver" if COMPILE_TEST + bool "Integrator-AP timer driver" if COMPILE_TEST select CLKSRC_MMIO help - Enables support for the Integrator-ap timer. + Enables support for the Integrator-AP timer. config CLKSRC_EFM32 bool "Clocksource for Energy Micro's EFM32 SoCs" if !ARCH_EFM32 @@ -283,8 +283,8 @@ config CLKSRC_NPS select TIMER_OF if OF help NPS400 clocksource support. - Got 64 bit counter with update rate up to 1000MHz. - This counter is accessed via couple of 32 bit memory mapped registers. + It has a 64-bit counter with update rate up to 1000MHz. + This counter is accessed via couple of 32-bit memory-mapped registers. config CLKSRC_STM32 bool "Clocksource for STM32 SoCs" if !ARCH_STM32 @@ -305,14 +305,14 @@ config ARC_TIMERS help These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores (ARC700 as well as ARC HS38). - TIMER0 serves as clockevent while TIMER1 provides clocksource + TIMER0 serves as clockevent while TIMER1 provides clocksource. config ARC_TIMERS_64BIT bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST depends on ARC_TIMERS select TIMER_OF help - This enables 2 different 64-bit timers: RTC (for UP) and GFRC (for SMP) + This enables 2 different 64-bit timers: RTC (for UP) and GFRC (for SMP). RTC is implemented inside the core, while GFRC sits outside the core in ARConnect IP block. Driver automatically picks one of them for clocksource as appropriate. @@ -390,7 +390,7 @@ config ARM_GLOBAL_TIMER select TIMER_OF if OF depends on ARM help - This options enables support for the ARM global timer unit + This option enables support for the ARM global timer unit. config ARM_TIMER_SP804 bool "Support for Dual Timer SP804 module" if COMPILE_TEST @@ -403,14 +403,14 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK depends on ARM_GLOBAL_TIMER default y help - Use ARM global timer clock source as sched_clock + Use ARM global timer clock source as sched_clock. config ARMV7M_SYSTICK bool "Support for the ARMv7M system time" if COMPILE_TEST select TIMER_OF if OF select CLKSRC_MMIO help - This options enables support for the ARMv7M system timer unit + This option enables support for the ARMv7M system timer unit. config ATMEL_PIT bool "Atmel PIT support" if COMPILE_TEST @@ -460,7 +460,7 @@ config VF_PIT_TIMER bool select CLKSRC_MMIO help - Support for Period Interrupt Timer on Freescale Vybrid Family SoCs. + Support for Periodic Interrupt Timer on Freescale Vybrid Family SoCs. config OXNAS_RPS_TIMER bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST @@ -523,7 +523,7 @@ config SH_TIMER_MTU2 help This enables build of a clockevent driver for the Multi-Function Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas. - This hardware comes with 16 bit-timer registers. + This hardware comes with 16-bit timer registers. config RENESAS_OSTM bool "Renesas OSTM timer driver" if COMPILE_TEST @@ -580,7 +580,7 @@ config CLKSRC_TANGO_XTAL select TIMER_OF select CLKSRC_MMIO help - This enables the clocksource for Tango SoC + This enables the clocksource for Tango SoC. config CLKSRC_PXA bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST @@ -601,14 +601,14 @@ config H8300_TMR16 depends on HAS_IOMEM help This enables the 16 bits timer for the H8300 platform with the - H83069 cpu. + H83069 CPU. config H8300_TPU bool "Clocksource for the H8300 platform" if COMPILE_TEST depends on HAS_IOMEM help This enables the clocksource for the H8300 platform with the - H8S2678 cpu. + H8S2678 CPU. config CLKSRC_IMX_GPT bool "Clocksource using i.MX GPT" if COMPILE_TEST @@ -666,8 +666,8 @@ config CSKY_MP_TIMER help Say yes here to enable C-SKY SMP timer driver used for C-SKY SMP system. - csky,mptimer is not only used in SMP system, it also could be used - single core system. It's not a mmio reg and it use mtcr/mfcr instruction. + csky,mptimer is not only used in SMP system, it also could be used in + single core system. It's not a mmio reg and it uses mtcr/mfcr instruction. config GX6605S_TIMER bool "Gx6605s SOC system timer driver" if COMPILE_TEST -- cgit v1.2.3 From ddc61bbc45017726a2b450350d476b4dc5ae25ce Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Tue, 26 Nov 2019 10:17:20 +0800 Subject: clocksource/drivers/hyper-v: Reserve PAGE_SIZE space for tsc page Currently, the reserved size for a tsc page is 4K, which is enough for communicating with hypervisor. However, in the case where we want to export the tsc page to userspace (e.g. for vDSO to read the clocksource), the tsc page should be at least PAGE_SIZE, otherwise, when PAGE_SIZE is larger than 4K, extra kernel data will be mapped into userspace, which means leaking kernel information. Therefore reserve PAGE_SIZE space for tsc_pg as a preparation for the vDSO support of ARM64 in the future. Also, while at it, replace all reference to tsc_pg with hv_get_tsc_page() since it should be the only interface to access tsc page. Signed-off-by: Boqun Feng (Microsoft) Cc: linux-hyperv@vger.kernel.org Reviewed-by: Michael Kelley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191126021723.4710-1-boqun.feng@gmail.com --- drivers/clocksource/hyperv_timer.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 1aec08e82b7a..12d75b50a317 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -307,17 +307,20 @@ EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup); struct clocksource *hyperv_cs; EXPORT_SYMBOL_GPL(hyperv_cs); -static struct ms_hyperv_tsc_page tsc_pg __aligned(PAGE_SIZE); +static union { + struct ms_hyperv_tsc_page page; + u8 reserved[PAGE_SIZE]; +} tsc_pg __aligned(PAGE_SIZE); struct ms_hyperv_tsc_page *hv_get_tsc_page(void) { - return &tsc_pg; + return &tsc_pg.page; } EXPORT_SYMBOL_GPL(hv_get_tsc_page); static u64 notrace read_hv_clock_tsc(struct clocksource *arg) { - u64 current_tick = hv_read_tsc_page(&tsc_pg); + u64 current_tick = hv_read_tsc_page(hv_get_tsc_page()); if (current_tick == U64_MAX) hv_get_time_ref_count(current_tick); @@ -397,7 +400,7 @@ static bool __init hv_init_tsc_clocksource(void) return false; hyperv_cs = &hyperv_cs_tsc; - phys_addr = virt_to_phys(&tsc_pg); + phys_addr = virt_to_phys(hv_get_tsc_page()); /* * The Hyper-V TLFS specifies to preserve the value of reserved -- cgit v1.2.3 From 625022a5f160619ae180d54097ddd65bb3795913 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 13 Dec 2019 13:19:21 +0200 Subject: clocksource/drivers/timer-microchip-pit64b: Add Microchip PIT64B support Add driver for Microchip PIT64B timer. Timer could be used in continuous mode or oneshot mode. The hardware has 2x32 bit registers for period emulating a 64 bit timer. The LSB_PR and MSB_PR registers are used to set the period value (compare value). TLSB and TMSB keeps the current value of the counter. After a compare the TLSB and TMSB register resets. The driver uses PIT64B timer for clocksource or clockevent. First requested timer would be registered as clockevent, second one would be registered as clocksource. Individual PIT64B hardware resources were used for clocksource and clockevent to be able to support high resolution timers with this hardware implementation. Signed-off-by: Claudiu Beznea Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1576235962-30123-3-git-send-email-claudiu.beznea@microchip.com --- drivers/clocksource/Kconfig | 10 + drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-microchip-pit64b.c | 449 +++++++++++++++++++++++++++ 3 files changed, 460 insertions(+) create mode 100644 drivers/clocksource/timer-microchip-pit64b.c (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 94192fb0533e..cc909e465823 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -697,4 +697,14 @@ config INGENIC_TIMER help Support for the timer/counter unit of the Ingenic JZ SoCs. +config MICROCHIP_PIT64B + bool "Microchip PIT64B support" + depends on OF || COMPILE_TEST + select CLKSRC_MMIO + help + This option enables Microchip PIT64B timer for Atmel + based system. It supports the oneshot, the periodic + modes and high resolution. It is used as a clocksource + and a clockevent. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 4dfe4225ece7..713686faa549 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -88,3 +88,4 @@ obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o +obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c new file mode 100644 index 000000000000..27a389a7e078 --- /dev/null +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 64-bit Periodic Interval Timer driver + * + * Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MCHP_PIT64B_CR 0x00 /* Control Register */ +#define MCHP_PIT64B_CR_START BIT(0) +#define MCHP_PIT64B_CR_SWRST BIT(8) + +#define MCHP_PIT64B_MR 0x04 /* Mode Register */ +#define MCHP_PIT64B_MR_CONT BIT(0) +#define MCHP_PIT64B_MR_ONE_SHOT (0) +#define MCHP_PIT64B_MR_SGCLK BIT(3) +#define MCHP_PIT64B_MR_PRES GENMASK(11, 8) + +#define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */ + +#define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */ + +#define MCHP_PIT64B_IER 0x10 /* Interrupt Enable Register */ +#define MCHP_PIT64B_IER_PERIOD BIT(0) + +#define MCHP_PIT64B_ISR 0x1C /* Interrupt Status Register */ + +#define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */ + +#define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */ + +#define MCHP_PIT64B_PRES_MAX 0x10 +#define MCHP_PIT64B_LSBMASK GENMASK_ULL(31, 0) +#define MCHP_PIT64B_PRES_TO_MODE(p) (MCHP_PIT64B_MR_PRES & ((p) << 8)) +#define MCHP_PIT64B_MODE_TO_PRES(m) ((MCHP_PIT64B_MR_PRES & (m)) >> 8) +#define MCHP_PIT64B_DEF_CS_FREQ 5000000UL /* 5 MHz */ +#define MCHP_PIT64B_DEF_CE_FREQ 32768 /* 32 KHz */ + +#define MCHP_PIT64B_NAME "pit64b" + +/** + * struct mchp_pit64b_timer - PIT64B timer data structure + * @base: base address of PIT64B hardware block + * @pclk: PIT64B's peripheral clock + * @gclk: PIT64B's generic clock + * @mode: precomputed value for mode register + */ +struct mchp_pit64b_timer { + void __iomem *base; + struct clk *pclk; + struct clk *gclk; + u32 mode; +}; + +/** + * mchp_pit64b_clkevt - PIT64B clockevent data structure + * @timer: PIT64B timer + * @clkevt: clockevent + */ +struct mchp_pit64b_clkevt { + struct mchp_pit64b_timer timer; + struct clock_event_device clkevt; +}; + +#define to_mchp_pit64b_timer(x) \ + ((struct mchp_pit64b_timer *)container_of(x,\ + struct mchp_pit64b_clkevt, clkevt)) + +/* Base address for clocksource timer. */ +static void __iomem *mchp_pit64b_cs_base; +/* Default cycles for clockevent timer. */ +static u64 mchp_pit64b_ce_cycles; + +static inline u64 mchp_pit64b_cnt_read(void __iomem *base) +{ + unsigned long flags; + u32 low, high; + + raw_local_irq_save(flags); + + /* + * When using a 64 bit period TLSB must be read first, followed by the + * read of TMSB. This sequence generates an atomic read of the 64 bit + * timer value whatever the lapse of time between the accesses. + */ + low = readl_relaxed(base + MCHP_PIT64B_TLSBR); + high = readl_relaxed(base + MCHP_PIT64B_TMSBR); + + raw_local_irq_restore(flags); + + return (((u64)high << 32) | low); +} + +static inline void mchp_pit64b_reset(struct mchp_pit64b_timer *timer, + u64 cycles, u32 mode, u32 irqs) +{ + u32 low, high; + + low = cycles & MCHP_PIT64B_LSBMASK; + high = cycles >> 32; + + writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR); + writel_relaxed(mode | timer->mode, timer->base + MCHP_PIT64B_MR); + writel_relaxed(high, timer->base + MCHP_PIT64B_MSB_PR); + writel_relaxed(low, timer->base + MCHP_PIT64B_LSB_PR); + writel_relaxed(irqs, timer->base + MCHP_PIT64B_IER); + writel_relaxed(MCHP_PIT64B_CR_START, timer->base + MCHP_PIT64B_CR); +} + +static u64 mchp_pit64b_clksrc_read(struct clocksource *cs) +{ + return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); +} + +static u64 mchp_pit64b_sched_read_clk(void) +{ + return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); +} + +static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev) +{ + struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + + writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR); + + return 0; +} + +static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev) +{ + struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + + mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_CONT, + MCHP_PIT64B_IER_PERIOD); + + return 0; +} + +static int mchp_pit64b_clkevt_set_next_event(unsigned long evt, + struct clock_event_device *cedev) +{ + struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + + mchp_pit64b_reset(timer, evt, MCHP_PIT64B_MR_ONE_SHOT, + MCHP_PIT64B_IER_PERIOD); + + return 0; +} + +static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev) +{ + struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + + writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR); + if (timer->mode & MCHP_PIT64B_MR_SGCLK) + clk_disable_unprepare(timer->gclk); + clk_disable_unprepare(timer->pclk); +} + +static void mchp_pit64b_clkevt_resume(struct clock_event_device *cedev) +{ + struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + + clk_prepare_enable(timer->pclk); + if (timer->mode & MCHP_PIT64B_MR_SGCLK) + clk_prepare_enable(timer->gclk); +} + +static irqreturn_t mchp_pit64b_interrupt(int irq, void *dev_id) +{ + struct mchp_pit64b_clkevt *irq_data = dev_id; + + /* Need to clear the interrupt. */ + readl_relaxed(irq_data->timer.base + MCHP_PIT64B_ISR); + + irq_data->clkevt.event_handler(&irq_data->clkevt); + + return IRQ_HANDLED; +} + +static void __init mchp_pit64b_pres_compute(u32 *pres, u32 clk_rate, + u32 max_rate) +{ + u32 tmp; + + for (*pres = 0; *pres < MCHP_PIT64B_PRES_MAX; (*pres)++) { + tmp = clk_rate / (*pres + 1); + if (tmp <= max_rate) + break; + } + + /* Use the bigest prescaler if we didn't match one. */ + if (*pres == MCHP_PIT64B_PRES_MAX) + *pres = MCHP_PIT64B_PRES_MAX - 1; +} + +/** + * mchp_pit64b_init_mode - prepare PIT64B mode register value to be used at + * runtime; this includes prescaler and SGCLK bit + * + * PIT64B timer may be fed by gclk or pclk. When gclk is used its rate has to + * be at least 3 times lower that pclk's rate. pclk rate is fixed, gclk rate + * could be changed via clock APIs. The chosen clock (pclk or gclk) could be + * divided by the internal PIT64B's divider. + * + * This function, first tries to use GCLK by requesting the desired rate from + * PMC and then using the internal PIT64B prescaler, if any, to reach the + * requested rate. If PCLK/GCLK < 3 (condition requested by PIT64B hardware) + * then the function falls back on using PCLK as clock source for PIT64B timer + * choosing the highest prescaler in case it doesn't locate one to match the + * requested frequency. + * + * Below is presented the PIT64B block in relation with PMC: + * + * PIT64B + * PMC +------------------------------------+ + * +----+ | +-----+ | + * | |-->gclk -->|-->| | +---------+ +-----+ | + * | | | | MUX |--->| Divider |->|timer| | + * | |-->pclk -->|-->| | +---------+ +-----+ | + * +----+ | +-----+ | + * | ^ | + * | sel | + * +------------------------------------+ + * + * Where: + * - gclk rate <= pclk rate/3 + * - gclk rate could be requested from PMC + * - pclk rate is fixed (cannot be requested from PMC) + */ +static int __init mchp_pit64b_init_mode(struct mchp_pit64b_timer *timer, + unsigned long max_rate) +{ + unsigned long pclk_rate, diff = 0, best_diff = ULONG_MAX; + long gclk_round = 0; + u32 pres, best_pres = 0; + + pclk_rate = clk_get_rate(timer->pclk); + if (!pclk_rate) + return -EINVAL; + + /* Try using GCLK. */ + gclk_round = clk_round_rate(timer->gclk, max_rate); + if (gclk_round < 0) + goto pclk; + + if (pclk_rate / gclk_round < 3) + goto pclk; + + mchp_pit64b_pres_compute(&pres, gclk_round, max_rate); + best_diff = abs(gclk_round / (pres + 1) - max_rate); + best_pres = pres; + + if (!best_diff) { + timer->mode |= MCHP_PIT64B_MR_SGCLK; + goto done; + } + +pclk: + /* Check if requested rate could be obtained using PCLK. */ + mchp_pit64b_pres_compute(&pres, pclk_rate, max_rate); + diff = abs(pclk_rate / (pres + 1) - max_rate); + + if (best_diff > diff) { + /* Use PCLK. */ + best_pres = pres; + } else { + /* Use GCLK. */ + timer->mode |= MCHP_PIT64B_MR_SGCLK; + clk_set_rate(timer->gclk, gclk_round); + } + +done: + timer->mode |= MCHP_PIT64B_PRES_TO_MODE(best_pres); + + pr_info("PIT64B: using clk=%s with prescaler %u, freq=%lu [Hz]\n", + timer->mode & MCHP_PIT64B_MR_SGCLK ? "gclk" : "pclk", best_pres, + timer->mode & MCHP_PIT64B_MR_SGCLK ? + gclk_round / (best_pres + 1) : pclk_rate / (best_pres + 1)); + + return 0; +} + +static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer, + u32 clk_rate) +{ + int ret; + + mchp_pit64b_reset(timer, ULLONG_MAX, MCHP_PIT64B_MR_CONT, 0); + + mchp_pit64b_cs_base = timer->base; + + ret = clocksource_mmio_init(timer->base, MCHP_PIT64B_NAME, clk_rate, + 210, 64, mchp_pit64b_clksrc_read); + if (ret) { + pr_debug("clksrc: Failed to register PIT64B clocksource!\n"); + + /* Stop timer. */ + writel_relaxed(MCHP_PIT64B_CR_SWRST, + timer->base + MCHP_PIT64B_CR); + + return ret; + } + + sched_clock_register(mchp_pit64b_sched_read_clk, 64, clk_rate); + + return 0; +} + +static int __init mchp_pit64b_init_clkevt(struct mchp_pit64b_timer *timer, + u32 clk_rate, u32 irq) +{ + struct mchp_pit64b_clkevt *ce; + int ret; + + ce = kzalloc(sizeof(*ce), GFP_KERNEL); + if (!ce) + return -ENOMEM; + + mchp_pit64b_ce_cycles = DIV_ROUND_CLOSEST(clk_rate, HZ); + + ce->timer.base = timer->base; + ce->timer.pclk = timer->pclk; + ce->timer.gclk = timer->gclk; + ce->timer.mode = timer->mode; + ce->clkevt.name = MCHP_PIT64B_NAME; + ce->clkevt.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; + ce->clkevt.rating = 150; + ce->clkevt.set_state_shutdown = mchp_pit64b_clkevt_shutdown; + ce->clkevt.set_state_periodic = mchp_pit64b_clkevt_set_periodic; + ce->clkevt.set_next_event = mchp_pit64b_clkevt_set_next_event; + ce->clkevt.suspend = mchp_pit64b_clkevt_suspend; + ce->clkevt.resume = mchp_pit64b_clkevt_resume; + ce->clkevt.cpumask = cpumask_of(0); + ce->clkevt.irq = irq; + + ret = request_irq(irq, mchp_pit64b_interrupt, IRQF_TIMER, + "pit64b_tick", ce); + if (ret) { + pr_debug("clkevt: Failed to setup PIT64B IRQ\n"); + kfree(ce); + return ret; + } + + clockevents_config_and_register(&ce->clkevt, clk_rate, 1, ULONG_MAX); + + return 0; +} + +static int __init mchp_pit64b_dt_init_timer(struct device_node *node, + bool clkevt) +{ + u32 freq = clkevt ? MCHP_PIT64B_DEF_CE_FREQ : MCHP_PIT64B_DEF_CS_FREQ; + struct mchp_pit64b_timer timer = { 0 }; + unsigned long clk_rate; + u32 irq = 0; + int ret; + + /* Parse DT node. */ + timer.pclk = of_clk_get_by_name(node, "pclk"); + if (IS_ERR(timer.pclk)) + return PTR_ERR(timer.pclk); + + timer.gclk = of_clk_get_by_name(node, "gclk"); + if (IS_ERR(timer.gclk)) + return PTR_ERR(timer.gclk); + + timer.base = of_iomap(node, 0); + if (!timer.base) + return -ENXIO; + + if (clkevt) { + irq = irq_of_parse_and_map(node, 0); + if (!irq) { + ret = -ENODEV; + goto io_unmap; + } + } + + /* Initialize mode (prescaler + SGCK bit). To be used at runtime. */ + ret = mchp_pit64b_init_mode(&timer, freq); + if (ret) + goto irq_unmap; + + ret = clk_prepare_enable(timer.pclk); + if (ret) + goto irq_unmap; + + if (timer.mode & MCHP_PIT64B_MR_SGCLK) { + ret = clk_prepare_enable(timer.gclk); + if (ret) + goto pclk_unprepare; + + clk_rate = clk_get_rate(timer.gclk); + } else { + clk_rate = clk_get_rate(timer.pclk); + } + clk_rate = clk_rate / (MCHP_PIT64B_MODE_TO_PRES(timer.mode) + 1); + + if (clkevt) + ret = mchp_pit64b_init_clkevt(&timer, clk_rate, irq); + else + ret = mchp_pit64b_init_clksrc(&timer, clk_rate); + + if (ret) + goto gclk_unprepare; + + return 0; + +gclk_unprepare: + if (timer.mode & MCHP_PIT64B_MR_SGCLK) + clk_disable_unprepare(timer.gclk); +pclk_unprepare: + clk_disable_unprepare(timer.pclk); +irq_unmap: + irq_dispose_mapping(irq); +io_unmap: + iounmap(timer.base); + + return ret; +} + +static int __init mchp_pit64b_dt_init(struct device_node *node) +{ + static int inits; + + switch (inits++) { + case 0: + /* 1st request, register clockevent. */ + return mchp_pit64b_dt_init_timer(node, true); + case 1: + /* 2nd request, register clocksource. */ + return mchp_pit64b_dt_init_timer(node, false); + } + + /* The rest, don't care. */ + return -EINVAL; +} + +TIMER_OF_DECLARE(mchp_pit64b, "microchip,sam9x60-pit64b", mchp_pit64b_dt_init); -- cgit v1.2.3 From f5ac896b6a23eb46681cdbef440c1d991b04e519 Mon Sep 17 00:00:00 2001 From: Rajan Vaja Date: Thu, 7 Nov 2019 02:36:28 -0800 Subject: clocksource/drivers/cadence-ttc: Use ttc driver as platform driver Currently TTC driver is TIMER_OF_DECLARE type driver. Because of that, TTC driver may be initialized before other clock drivers. If TTC driver is dependent on that clock driver then initialization of TTC driver will failed. So use TTC driver as platform driver instead of using TIMER_OF_DECLARE. Signed-off-by: Rajan Vaja Tested-by: Michal Simek Acked-by: Michal Simek Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1573122988-18399-1-git-send-email-rajan.vaja@xilinx.com --- drivers/clocksource/timer-cadence-ttc.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/timer-cadence-ttc.c b/drivers/clocksource/timer-cadence-ttc.c index 88fe2e9ba9a3..38858e141731 100644 --- a/drivers/clocksource/timer-cadence-ttc.c +++ b/drivers/clocksource/timer-cadence-ttc.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include /* * This driver configures the 2 16/32-bit count-up timers as follows: @@ -464,13 +466,7 @@ static int __init ttc_setup_clockevent(struct clk *clk, return 0; } -/** - * ttc_timer_init - Initialize the timer - * - * Initializes the timer hardware and register the clock source and clock event - * timers with Linux kernal timer framework - */ -static int __init ttc_timer_init(struct device_node *timer) +static int __init ttc_timer_probe(struct platform_device *pdev) { unsigned int irq; void __iomem *timer_baseaddr; @@ -478,6 +474,7 @@ static int __init ttc_timer_init(struct device_node *timer) static int initialized; int clksel, ret; u32 timer_width = 16; + struct device_node *timer = pdev->dev.of_node; if (initialized) return 0; @@ -532,4 +529,17 @@ static int __init ttc_timer_init(struct device_node *timer) return 0; } -TIMER_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); +static const struct of_device_id ttc_timer_of_match[] = { + {.compatible = "cdns,ttc"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, ttc_timer_of_match); + +static struct platform_driver ttc_timer_driver = { + .driver = { + .name = "cdns_ttc_timer", + .of_match_table = ttc_timer_of_match, + }, +}; +builtin_platform_driver_probe(ttc_timer_driver, ttc_timer_probe); -- cgit v1.2.3 From 2052d032c06761330bca4944bb7858b00960e868 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 19 Dec 2019 21:32:46 +0000 Subject: clocksource/drivers/bcm2835_timer: Fix memory leak of timer Currently when setup_irq fails the error exit path will leak the recently allocated timer structure. Originally the code would throw a panic but a later commit changed the behaviour to return via the err_iounmap path and hence we now have a memory leak. Fix this by adding a err_timer_free error path that kfree's timer. Addresses-Coverity: ("Resource Leak") Fixes: 524a7f08983d ("clocksource/drivers/bcm2835_timer: Convert init function to return error") Signed-off-by: Colin Ian King Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191219213246.34437-1-colin.king@canonical.com --- drivers/clocksource/bcm2835_timer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 2b196cbfadb6..b235f446ee50 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -121,7 +121,7 @@ static int __init bcm2835_timer_init(struct device_node *node) ret = setup_irq(irq, &timer->act); if (ret) { pr_err("Can't set up timer IRQ\n"); - goto err_iounmap; + goto err_timer_free; } clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff); @@ -130,6 +130,9 @@ static int __init bcm2835_timer_init(struct device_node *node) return 0; +err_timer_free: + kfree(timer); + err_iounmap: iounmap(base); return ret; -- cgit v1.2.3 From 9a97b2fb070d497c683aed9fb86b7ec5245cea86 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 21 Dec 2019 17:30:24 +0000 Subject: clocksource/drivers/em_sti: Convert to devm_platform_ioremap_resource Use devm_platform_ioremap_resource() to simplify code, which wraps 'platform_get_resource' and 'devm_ioremap_resource' in a single helper. Signed-off-by: Yangtao Li Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191221173027.30716-2-tiny.windzz@gmail.com --- drivers/clocksource/em_sti.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 9039df4f90e2..086fd5d80b99 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -279,7 +279,6 @@ static void em_sti_register_clockevent(struct em_sti_priv *p) static int em_sti_probe(struct platform_device *pdev) { struct em_sti_priv *p; - struct resource *res; int irq; int ret; @@ -295,8 +294,7 @@ static int em_sti_probe(struct platform_device *pdev) return irq; /* map memory, let base point to the STI instance */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - p->base = devm_ioremap_resource(&pdev->dev, res); + p->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(p->base)) return PTR_ERR(p->base); -- cgit v1.2.3 From ba25322edd600300e55cd58eb7fbdf9cbdc5a82d Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 21 Dec 2019 17:30:25 +0000 Subject: clocksource/drivers/em_sti: Fix variable declaration in em_sti_probe 'irq' and 'ret' are variables of the same type and there is no need to use two lines. Signed-off-by: Yangtao Li Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191221173027.30716-3-tiny.windzz@gmail.com --- drivers/clocksource/em_sti.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 086fd5d80b99..ab190dffb1ed 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -279,8 +279,7 @@ static void em_sti_register_clockevent(struct em_sti_priv *p) static int em_sti_probe(struct platform_device *pdev) { struct em_sti_priv *p; - int irq; - int ret; + int irq, ret; p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); if (p == NULL) -- cgit v1.2.3 From cdab83f9d0fb13926f6633f20c3327545fd6f70f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 21 Dec 2019 17:30:26 +0000 Subject: clocksource/drivers/timer-ti-dm: Convert to devm_platform_ioremap_resource Use devm_platform_ioremap_resource() to simplify code, which wraps 'platform_get_resource' and 'devm_ioremap_resource' in a single helper. Signed-off-by: Yangtao Li Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191221173027.30716-4-tiny.windzz@gmail.com --- drivers/clocksource/timer-ti-dm.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 5394d9dbdfbc..aa2ede266edf 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -780,7 +780,7 @@ static int omap_dm_timer_probe(struct platform_device *pdev) { unsigned long flags; struct omap_dm_timer *timer; - struct resource *mem, *irq; + struct resource *irq; struct device *dev = &pdev->dev; const struct dmtimer_platform_data *pdata; int ret; @@ -802,18 +802,12 @@ static int omap_dm_timer_probe(struct platform_device *pdev) return -ENODEV; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!mem)) { - dev_err(dev, "%s: no memory resource.\n", __func__); - return -ENODEV; - } - timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL); if (!timer) return -ENOMEM; timer->fclk = ERR_PTR(-ENODEV); - timer->io_base = devm_ioremap_resource(dev, mem); + timer->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(timer->io_base)) return PTR_ERR(timer->io_base); -- cgit v1.2.3 From bc83caddf17bd592cc19887e252c4ba416484d79 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 21 Dec 2019 17:30:27 +0000 Subject: clocksource/drivers/timer-ti-dm: Switch to platform_get_irq platform_get_resource(pdev, IORESOURCE_IRQ) is not recommended for requesting IRQ's resources, as they can be not ready yet. Using platform_get_irq() instead is preferred for getting IRQ even if it was not retrieved earlier. Signed-off-by: Yangtao Li Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20191221173027.30716-5-tiny.windzz@gmail.com --- drivers/clocksource/timer-ti-dm.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index aa2ede266edf..bd16efb2740b 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -780,7 +780,6 @@ static int omap_dm_timer_probe(struct platform_device *pdev) { unsigned long flags; struct omap_dm_timer *timer; - struct resource *irq; struct device *dev = &pdev->dev; const struct dmtimer_platform_data *pdata; int ret; @@ -796,11 +795,9 @@ static int omap_dm_timer_probe(struct platform_device *pdev) return -ENODEV; } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (unlikely(!irq)) { - dev_err(dev, "%s: no IRQ resource.\n", __func__); - return -ENODEV; - } + timer->irq = platform_get_irq(pdev, 0); + if (timer->irq < 0) + return timer->irq; timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL); if (!timer) @@ -830,7 +827,6 @@ static int omap_dm_timer_probe(struct platform_device *pdev) if (pdata) timer->errata = pdata->timer_errata; - timer->irq = irq->start; timer->pdev = pdev; pm_runtime_enable(dev); -- cgit v1.2.3 From 4341067cfc20582195f47383cf059589b2641465 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 6 Jan 2020 12:37:00 -0800 Subject: clocksource/drivers/timer-ti-dm: Fix uninitialized pointer access Clean-up commit 8c82723414d5 ("clocksource/drivers/timer-ti-dm: Switch to platform_get_irq") caused a regression where we now try to access uninitialized data for timer: drivers/clocksource/timer-ti-dm.c: In function 'omap_dm_timer_probe': drivers/clocksource/timer-ti-dm.c:798:13: warning: 'timer' may be used uninitialized in this function [-Wmaybe-uninitialized] On boot we now get: Unable to handle kernel NULL pointer dereference at virtual address 00000004 ... (omap_dm_timer_probe) from [] (platform_drv_probe+0x48/0x98) (platform_drv_probe) from [] (really_probe+0x1dc/0x348) (really_probe) from [] (driver_probe_device+0x5c/0x160) Let's fix the issue by moving platform_get_irq to happen after timer has been allocated. Fixes: bc83caddf17b ("clocksource/drivers/timer-ti-dm: Switch to platform_get_irq") Cc: Yangtao Li Signed-off-by: Tony Lindgren Acked-by: Olof Johansson Acked-by: Yangtao Li Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200106203700.21009-1-tony@atomide.com --- drivers/clocksource/timer-ti-dm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index bd16efb2740b..269a994d6a99 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -795,14 +795,14 @@ static int omap_dm_timer_probe(struct platform_device *pdev) return -ENODEV; } - timer->irq = platform_get_irq(pdev, 0); - if (timer->irq < 0) - return timer->irq; - timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL); if (!timer) return -ENOMEM; + timer->irq = platform_get_irq(pdev, 0); + if (timer->irq < 0) + return timer->irq; + timer->fclk = ERR_PTR(-ENODEV); timer->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(timer->io_base)) -- cgit v1.2.3 From 4ad35346da9cb99c02a4c5e99633c36f8f344be0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 4 Jan 2020 16:20:58 +0100 Subject: clocksource/drivers/exynos_mct: Rename Exynos to lowercase Fix up inconsistent usage of upper and lowercase letters in "Exynos" name. "EXYNOS" is not an abbreviation but a regular trademarked name. Therefore it should be written with lowercase letters starting with capital letter. The lowercase "Exynos" name is promoted by its manufacturer Samsung Electronics Co., Ltd., in advertisement materials and on website. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200104152107.11407-12-krzk@kernel.org --- drivers/clocksource/exynos_mct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 74cb299f5089..a267fe31ef13 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -4,7 +4,7 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * EXYNOS4 MCT(Multi-Core Timer) support + * Exynos4 MCT(Multi-Core Timer) support */ #include -- cgit v1.2.3 From b9c60a741f06eda56d12c7216accb317b74266b4 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 6 Jan 2020 11:58:08 +0200 Subject: clocksource/drivers/timer-microchip-pit64b: Fix sparse warning Fix sparse warning: "warning: Using plain integer as NULL pointer" Reported-by: kbuild test robot Signed-off-by: Claudiu Beznea Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1578304688-14882-1-git-send-email-claudiu.beznea@microchip.com --- drivers/clocksource/timer-microchip-pit64b.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c index 27a389a7e078..bd63d3484838 100644 --- a/drivers/clocksource/timer-microchip-pit64b.c +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -248,6 +248,8 @@ static int __init mchp_pit64b_init_mode(struct mchp_pit64b_timer *timer, if (!pclk_rate) return -EINVAL; + timer->mode = 0; + /* Try using GCLK. */ gclk_round = clk_round_rate(timer->gclk, max_rate); if (gclk_round < 0) @@ -360,7 +362,7 @@ static int __init mchp_pit64b_dt_init_timer(struct device_node *node, bool clkevt) { u32 freq = clkevt ? MCHP_PIT64B_DEF_CE_FREQ : MCHP_PIT64B_DEF_CS_FREQ; - struct mchp_pit64b_timer timer = { 0 }; + struct mchp_pit64b_timer timer; unsigned long clk_rate; u32 irq = 0; int ret; -- cgit v1.2.3 From 0af3e137c144377fbaf5025ba784ff5ba7ad40c9 Mon Sep 17 00:00:00 2001 From: Andrea Parri Date: Thu, 9 Jan 2020 17:06:49 +0100 Subject: clocksource/drivers/hyper-v: Untangle stimers and timesync from clocksources hyperv_timer.c exports hyperv_cs, which is used by stimers and the timesync mechanism. However, the clocksource dependency is not needed: these mechanisms only depend on the partition reference counter (which can be read via a MSR or via the TSC Reference Page). Introduce the (function) pointer hv_read_reference_counter, as an embodiment of the partition reference counter read, and export it in place of the hyperv_cs pointer. The latter can be removed. This should clarify that there's no relationship between Hyper-V stimers & timesync and the Linux clocksource abstractions. No functional or semantic change. Suggested-by: Michael Kelley Signed-off-by: Andrea Parri Reviewed-by: Michael Kelley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200109160650.16150-2-parri.andrea@gmail.com --- drivers/clocksource/hyperv_timer.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 12d75b50a317..42748adccc98 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -66,7 +66,7 @@ static int hv_ce_set_next_event(unsigned long delta, { u64 current_tick; - current_tick = hyperv_cs->read(NULL); + current_tick = hv_read_reference_counter(); current_tick += delta; hv_init_timer(0, current_tick); return 0; @@ -304,8 +304,8 @@ EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup); * Hyper-V and 32-bit x86. The TSC reference page version is preferred. */ -struct clocksource *hyperv_cs; -EXPORT_SYMBOL_GPL(hyperv_cs); +u64 (*hv_read_reference_counter)(void); +EXPORT_SYMBOL_GPL(hv_read_reference_counter); static union { struct ms_hyperv_tsc_page page; @@ -318,7 +318,7 @@ struct ms_hyperv_tsc_page *hv_get_tsc_page(void) } EXPORT_SYMBOL_GPL(hv_get_tsc_page); -static u64 notrace read_hv_clock_tsc(struct clocksource *arg) +static u64 notrace read_hv_clock_tsc(void) { u64 current_tick = hv_read_tsc_page(hv_get_tsc_page()); @@ -328,9 +328,14 @@ static u64 notrace read_hv_clock_tsc(struct clocksource *arg) return current_tick; } +static u64 notrace read_hv_clock_tsc_cs(struct clocksource *arg) +{ + return read_hv_clock_tsc(); +} + static u64 read_hv_sched_clock_tsc(void) { - return read_hv_clock_tsc(NULL) - hv_sched_clock_offset; + return read_hv_clock_tsc() - hv_sched_clock_offset; } static void suspend_hv_clock_tsc(struct clocksource *arg) @@ -359,14 +364,14 @@ static void resume_hv_clock_tsc(struct clocksource *arg) static struct clocksource hyperv_cs_tsc = { .name = "hyperv_clocksource_tsc_page", .rating = 400, - .read = read_hv_clock_tsc, + .read = read_hv_clock_tsc_cs, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, .suspend= suspend_hv_clock_tsc, .resume = resume_hv_clock_tsc, }; -static u64 notrace read_hv_clock_msr(struct clocksource *arg) +static u64 notrace read_hv_clock_msr(void) { u64 current_tick; /* @@ -378,15 +383,20 @@ static u64 notrace read_hv_clock_msr(struct clocksource *arg) return current_tick; } +static u64 notrace read_hv_clock_msr_cs(struct clocksource *arg) +{ + return read_hv_clock_msr(); +} + static u64 read_hv_sched_clock_msr(void) { - return read_hv_clock_msr(NULL) - hv_sched_clock_offset; + return read_hv_clock_msr() - hv_sched_clock_offset; } static struct clocksource hyperv_cs_msr = { .name = "hyperv_clocksource_msr", .rating = 400, - .read = read_hv_clock_msr, + .read = read_hv_clock_msr_cs, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -399,7 +409,7 @@ static bool __init hv_init_tsc_clocksource(void) if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) return false; - hyperv_cs = &hyperv_cs_tsc; + hv_read_reference_counter = read_hv_clock_tsc; phys_addr = virt_to_phys(hv_get_tsc_page()); /* @@ -417,7 +427,7 @@ static bool __init hv_init_tsc_clocksource(void) hv_set_clocksource_vdso(hyperv_cs_tsc); clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); - hv_sched_clock_offset = hyperv_cs->read(hyperv_cs); + hv_sched_clock_offset = hv_read_reference_counter(); hv_setup_sched_clock(read_hv_sched_clock_tsc); return true; @@ -439,10 +449,10 @@ void __init hv_init_clocksource(void) if (!(ms_hyperv.features & HV_MSR_TIME_REF_COUNT_AVAILABLE)) return; - hyperv_cs = &hyperv_cs_msr; + hv_read_reference_counter = read_hv_clock_msr; clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100); - hv_sched_clock_offset = hyperv_cs->read(hyperv_cs); + hv_sched_clock_offset = hv_read_reference_counter(); hv_setup_sched_clock(read_hv_sched_clock_msr); } EXPORT_SYMBOL_GPL(hv_init_clocksource); -- cgit v1.2.3 From 9e0333ae38eeb42249e10f95d209244a6e22ac9f Mon Sep 17 00:00:00 2001 From: Andrea Parri Date: Thu, 9 Jan 2020 17:06:50 +0100 Subject: clocksource/drivers/hyper-v: Set TSC clocksource as default w/ InvariantTSC Change the Hyper-V clocksource ratings to 250, below the TSC clocksource rating of 300. In configurations where Hyper-V offers an InvariantTSC, the TSC is not marked "unstable", so the TSC clocksource is available and preferred. With the higher rating, it will be the default. On older hardware and Hyper-V versions, the TSC is marked "unstable", so no TSC clocksource is created and the selected Hyper-V clocksource will be the default. Signed-off-by: Andrea Parri Reviewed-by: Michael Kelley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200109160650.16150-3-parri.andrea@gmail.com --- drivers/clocksource/hyperv_timer.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 42748adccc98..9d808d595ca8 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -302,6 +302,14 @@ EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup); * the other that uses the TSC reference page feature as defined in the * TLFS. The MSR version is for compatibility with old versions of * Hyper-V and 32-bit x86. The TSC reference page version is preferred. + * + * The Hyper-V clocksource ratings of 250 are chosen to be below the + * TSC clocksource rating of 300. In configurations where Hyper-V offers + * an InvariantTSC, the TSC is not marked "unstable", so the TSC clocksource + * is available and preferred. With the higher rating, it will be the + * default. On older hardware and Hyper-V versions, the TSC is marked + * "unstable", so no TSC clocksource is created and the selected Hyper-V + * clocksource will be the default. */ u64 (*hv_read_reference_counter)(void); @@ -363,7 +371,7 @@ static void resume_hv_clock_tsc(struct clocksource *arg) static struct clocksource hyperv_cs_tsc = { .name = "hyperv_clocksource_tsc_page", - .rating = 400, + .rating = 250, .read = read_hv_clock_tsc_cs, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, @@ -395,7 +403,7 @@ static u64 read_hv_sched_clock_msr(void) static struct clocksource hyperv_cs_msr = { .name = "hyperv_clocksource_msr", - .rating = 400, + .rating = 250, .read = read_hv_clock_msr_cs, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, -- cgit v1.2.3