Skip to content

Commit

Permalink
Merge tag 'timers-core-2024-07-14' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/tip/tip

Pull timer updates from Thomas Gleixner:
 "Updates for timers, timekeeping and related functionality:

  Core:

   - Make the takeover of a hrtimer based broadcast timer reliable
     during CPU hot-unplug. The current implementation suffers from a
     race which can lead to broadcast timer starvation in the worst
     case.

   - VDSO related cleanups and simplifications

   - Small cleanups and enhancements all over the place

  PTP:

   - Replace the architecture specific base clock to clocksource, e.g.
     ART to TSC, conversion function with generic functionality to avoid
     exposing such internals to drivers and convert all existing drivers
     over. This also allows to provide functionality which converts the
     other way round in the core code based on the same parameter set.

   - Provide a function to convert CLOCK_REALTIME to the base clock to
     support the upcoming PPS output driver on Intel platforms.

  Drivers:

   - A set of Device Tree bindings for new hardware

   - Cleanups and enhancements all over the place"

* tag 'timers-core-2024-07-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (30 commits)
  clocksource/drivers/realtek: Add timer driver for rtl-otto platforms
  dt-bindings: timer: Add schema for realtek,otto-timer
  dt-bindings: timer: Add SOPHGO SG2002 clint
  dt-bindings: timer: renesas,tmu: Add R-Car Gen2 support
  dt-bindings: timer: renesas,tmu: Add RZ/G1 support
  dt-bindings: timer: renesas,tmu: Add R-Mobile APE6 support
  clocksource/drivers/mips-gic-timer: Correct sched_clock width
  clocksource/drivers/mips-gic-timer: Refine rating computation
  clocksource/drivers/sh_cmt: Address race condition for clock events
  clocksource/driver/arm_global_timer: Remove unnecessary ‘0’ values from err
  clocksource/drivers/arm_arch_timer: Remove unnecessary ‘0’ values from irq
  tick/broadcast: Make takeover of broadcast hrtimer reliable
  tick/sched: Combine WARN_ON_ONCE and print_once
  x86/vdso: Remove unused include
  x86/vgtod: Remove unused typedef gtod_long_t
  x86/vdso: Fix function reference in comment
  vdso: Add comment about reason for vdso struct ordering
  vdso/gettimeofday: Clarify comment about open coded function
  timekeeping: Add missing kernel-doc function comments
  tick: Remove unnused tick_nohz_get_idle_calls()
  ...
  • Loading branch information
torvalds committed Jul 15, 2024
2 parents 0eff049 + b7625d6 commit 4fd9435
Show file tree
Hide file tree
Showing 33 changed files with 647 additions and 131 deletions.
63 changes: 63 additions & 0 deletions Documentation/devicetree/bindings/timer/realtek,otto-timer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/timer/realtek,otto-timer.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Realtek Otto SoCs Timer/Counter

description:
Realtek SoCs support a number of timers/counters. These are used
as a per CPU clock event generator and an overall CPU clocksource.

maintainers:
- Chris Packham <[email protected]>

properties:
$nodename:
pattern: "^timer@[0-9a-f]+$"

compatible:
items:
- enum:
- realtek,rtl9302-timer
- const: realtek,otto-timer

reg:
items:
- description: timer0 registers
- description: timer1 registers
- description: timer2 registers
- description: timer3 registers
- description: timer4 registers

clocks:
maxItems: 1

interrupts:
items:
- description: timer0 interrupt
- description: timer1 interrupt
- description: timer2 interrupt
- description: timer3 interrupt
- description: timer4 interrupt

required:
- compatible
- reg
- clocks
- interrupts

additionalProperties: false

examples:
- |
timer@3200 {
compatible = "realtek,rtl9302-timer", "realtek,otto-timer";
reg = <0x3200 0x10>, <0x3210 0x10>, <0x3220 0x10>,
<0x3230 0x10>, <0x3240 0x10>;
interrupt-parent = <&intc>;
interrupts = <7>, <8>, <9>, <10>, <11>;
clocks = <&lx_clk>;
};
12 changes: 12 additions & 0 deletions Documentation/devicetree/bindings/timer/renesas,tmu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,24 @@ properties:
compatible:
items:
- enum:
- renesas,tmu-r8a73a4 # R-Mobile APE6
- renesas,tmu-r8a7740 # R-Mobile A1
- renesas,tmu-r8a7742 # RZ/G1H
- renesas,tmu-r8a7743 # RZ/G1M
- renesas,tmu-r8a7744 # RZ/G1N
- renesas,tmu-r8a7745 # RZ/G1E
- renesas,tmu-r8a77470 # RZ/G1C
- renesas,tmu-r8a774a1 # RZ/G2M
- renesas,tmu-r8a774b1 # RZ/G2N
- renesas,tmu-r8a774c0 # RZ/G2E
- renesas,tmu-r8a774e1 # RZ/G2H
- renesas,tmu-r8a7778 # R-Car M1A
- renesas,tmu-r8a7779 # R-Car H1
- renesas,tmu-r8a7790 # R-Car H2
- renesas,tmu-r8a7791 # R-Car M2-W
- renesas,tmu-r8a7792 # R-Car V2H
- renesas,tmu-r8a7793 # R-Car M2-N
- renesas,tmu-r8a7794 # R-Car E2
- renesas,tmu-r8a7795 # R-Car H3
- renesas,tmu-r8a7796 # R-Car M3-W
- renesas,tmu-r8a77961 # R-Car M3-W+
Expand Down Expand Up @@ -94,6 +105,7 @@ if:
compatible:
contains:
enum:
- renesas,tmu-r8a73a4
- renesas,tmu-r8a7740
- renesas,tmu-r8a7778
- renesas,tmu-r8a7779
Expand Down
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/timer/sifive,clint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ properties:
- allwinner,sun20i-d1-clint
- sophgo,cv1800b-clint
- sophgo,cv1812h-clint
- sophgo,sg2002-clint
- thead,th1520-clint
- const: thead,c900-clint
- items:
Expand Down
3 changes: 0 additions & 3 deletions arch/x86/include/asm/tsc.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ static inline cycles_t get_cycles(void)
}
#define get_cycles get_cycles

extern struct system_counterval_t convert_art_to_tsc(u64 art);
extern struct system_counterval_t convert_art_ns_to_tsc(u64 art_ns);

extern void tsc_early_init(void);
extern void tsc_init(void);
extern void mark_tsc_unstable(char *reason);
Expand Down
5 changes: 2 additions & 3 deletions arch/x86/include/asm/vdso/gettimeofday.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,8 @@ static __always_inline u64 vdso_calc_ns(const struct vdso_data *vd, u64 cycles,
* due to unsigned comparison.
*
* Due to the MSB/Sign-bit being used as invalid marker (see
* arch_vdso_cycles_valid() above), the effective mask is S64_MAX,
* but that case is also unlikely and will also take the unlikely path
* here.
* arch_vdso_cycles_ok() above), the effective mask is S64_MAX, but that
* case is also unlikely and will also take the unlikely path here.
*/
if (unlikely(delta > vd->max_cycles)) {
/*
Expand Down
1 change: 0 additions & 1 deletion arch/x86/include/asm/vdso/vsyscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#ifndef __ASSEMBLY__

#include <linux/hrtimer.h>
#include <linux/timekeeper_internal.h>
#include <vdso/datapage.h>
#include <asm/vgtod.h>
Expand Down
5 changes: 0 additions & 5 deletions arch/x86/include/asm/vgtod.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@

#include <uapi/linux/time.h>

#ifdef BUILD_VDSO32_64
typedef u64 gtod_long_t;
#else
typedef unsigned long gtod_long_t;
#endif
#endif /* CONFIG_GENERIC_GETTIMEOFDAY */

#endif /* _ASM_X86_VGTOD_H */
92 changes: 19 additions & 73 deletions arch/x86/kernel/tsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ int tsc_clocksource_reliable;

static int __read_mostly tsc_force_recalibrate;

static u32 art_to_tsc_numerator;
static u32 art_to_tsc_denominator;
static u64 art_to_tsc_offset;
static struct clocksource_base art_base_clk = {
.id = CSID_X86_ART,
};
static bool have_art;

struct cyc2ns {
Expand Down Expand Up @@ -1074,7 +1074,7 @@ core_initcall(cpufreq_register_tsc_scaling);
*/
static void __init detect_art(void)
{
unsigned int unused[2];
unsigned int unused;

if (boot_cpu_data.cpuid_level < ART_CPUID_LEAF)
return;
Expand All @@ -1089,13 +1089,14 @@ static void __init detect_art(void)
tsc_async_resets)
return;

cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
&art_to_tsc_numerator, unused, unused+1);
cpuid(ART_CPUID_LEAF, &art_base_clk.denominator,
&art_base_clk.numerator, &art_base_clk.freq_khz, &unused);

if (art_to_tsc_denominator < ART_MIN_DENOMINATOR)
art_base_clk.freq_khz /= KHZ;
if (art_base_clk.denominator < ART_MIN_DENOMINATOR)
return;

rdmsrl(MSR_IA32_TSC_ADJUST, art_to_tsc_offset);
rdmsrl(MSR_IA32_TSC_ADJUST, art_base_clk.offset);

/* Make this sticky over multiple CPU init calls */
setup_force_cpu_cap(X86_FEATURE_ART);
Expand Down Expand Up @@ -1296,67 +1297,6 @@ int unsynchronized_tsc(void)
return 0;
}

/*
* Convert ART to TSC given numerator/denominator found in detect_art()
*/
struct system_counterval_t convert_art_to_tsc(u64 art)
{
u64 tmp, res, rem;

rem = do_div(art, art_to_tsc_denominator);

res = art * art_to_tsc_numerator;
tmp = rem * art_to_tsc_numerator;

do_div(tmp, art_to_tsc_denominator);
res += tmp + art_to_tsc_offset;

return (struct system_counterval_t) {
.cs_id = have_art ? CSID_X86_TSC : CSID_GENERIC,
.cycles = res,
};
}
EXPORT_SYMBOL(convert_art_to_tsc);

/**
* convert_art_ns_to_tsc() - Convert ART in nanoseconds to TSC.
* @art_ns: ART (Always Running Timer) in unit of nanoseconds
*
* PTM requires all timestamps to be in units of nanoseconds. When user
* software requests a cross-timestamp, this function converts system timestamp
* to TSC.
*
* This is valid when CPU feature flag X86_FEATURE_TSC_KNOWN_FREQ is set
* indicating the tsc_khz is derived from CPUID[15H]. Drivers should check
* that this flag is set before conversion to TSC is attempted.
*
* Return:
* struct system_counterval_t - system counter value with the ID of the
* corresponding clocksource:
* cycles: System counter value
* cs_id: The clocksource ID for validating comparability
*/

struct system_counterval_t convert_art_ns_to_tsc(u64 art_ns)
{
u64 tmp, res, rem;

rem = do_div(art_ns, USEC_PER_SEC);

res = art_ns * tsc_khz;
tmp = rem * tsc_khz;

do_div(tmp, USEC_PER_SEC);
res += tmp;

return (struct system_counterval_t) {
.cs_id = have_art ? CSID_X86_TSC : CSID_GENERIC,
.cycles = res,
};
}
EXPORT_SYMBOL(convert_art_ns_to_tsc);


static void tsc_refine_calibration_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work);
/**
Expand Down Expand Up @@ -1458,8 +1398,10 @@ static void tsc_refine_calibration_work(struct work_struct *work)
if (tsc_unstable)
goto unreg;

if (boot_cpu_has(X86_FEATURE_ART))
if (boot_cpu_has(X86_FEATURE_ART)) {
have_art = true;
clocksource_tsc.base = &art_base_clk;
}
clocksource_register_khz(&clocksource_tsc, tsc_khz);
unreg:
clocksource_unregister(&clocksource_tsc_early);
Expand All @@ -1484,8 +1426,10 @@ static int __init init_tsc_clocksource(void)
* the refined calibration and directly register it as a clocksource.
*/
if (boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ)) {
if (boot_cpu_has(X86_FEATURE_ART))
if (boot_cpu_has(X86_FEATURE_ART)) {
have_art = true;
clocksource_tsc.base = &art_base_clk;
}
clocksource_register_khz(&clocksource_tsc, tsc_khz);
clocksource_unregister(&clocksource_tsc_early);

Expand All @@ -1509,10 +1453,12 @@ static bool __init determine_cpu_tsc_frequencies(bool early)

if (early) {
cpu_khz = x86_platform.calibrate_cpu();
if (tsc_early_khz)
if (tsc_early_khz) {
tsc_khz = tsc_early_khz;
else
} else {
tsc_khz = x86_platform.calibrate_tsc();
clocksource_tsc.freq_khz = tsc_khz;
}
} else {
/* We should not be here with non-native cpu calibration */
WARN_ON(x86_platform.calibrate_cpu != native_calibrate_cpu);
Expand Down
10 changes: 10 additions & 0 deletions drivers/clocksource/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ config RDA_TIMER
help
Enables the support for the RDA Micro timer driver.

config REALTEK_OTTO_TIMER
bool "Clocksource/timer for the Realtek Otto platform" if COMPILE_TEST
select TIMER_OF
help
This driver adds support for the timers found in the Realtek RTL83xx
and RTL93xx SoCs series. This includes chips such as RTL8380, RTL8381
and RTL832, as well as chips from the RTL839x series, such as RTL8390
RT8391, RTL8392, RTL8393 and RTL8396 and chips of the RTL930x series
such as RTL9301, RTL9302 or RTL9303.

config SUN4I_TIMER
bool "Sun4i timer driver" if COMPILE_TEST
depends on HAS_IOMEM
Expand Down
1 change: 1 addition & 0 deletions drivers/clocksource/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ obj-$(CONFIG_MILBEAUT_TIMER) += timer-milbeaut.o
obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o
obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o
obj-$(CONFIG_RDA_TIMER) += timer-rda.o
obj-$(CONFIG_REALTEK_OTTO_TIMER) += timer-rtl-otto.o

obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
Expand Down
2 changes: 1 addition & 1 deletion drivers/clocksource/arm_arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1556,7 +1556,7 @@ static int __init
arch_timer_mem_frame_register(struct arch_timer_mem_frame *frame)
{
void __iomem *base;
int ret, irq = 0;
int ret, irq;

if (arch_timer_mem_use_virtual)
irq = frame->virt_irq;
Expand Down
2 changes: 1 addition & 1 deletion drivers/clocksource/arm_global_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ static int __init global_timer_of_register(struct device_node *np)
{
struct clk *gt_clk;
static unsigned long gt_clk_rate;
int err = 0;
int err;

/*
* In A9 r2p0 the comparators for each processor with the global timer
Expand Down
20 changes: 12 additions & 8 deletions drivers/clocksource/mips-gic-timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
static DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device);
static int gic_timer_irq;
static unsigned int gic_frequency;
static unsigned int gic_count_width;
static bool __read_mostly gic_clock_unstable;

static void gic_clocksource_unstable(char *reason);
Expand Down Expand Up @@ -186,18 +187,21 @@ static void gic_clocksource_unstable(char *reason)

static int __init __gic_clocksource_init(void)
{
unsigned int count_width;
int ret;

/* Set clocksource mask. */
count_width = read_gic_config() & GIC_CONFIG_COUNTBITS;
count_width >>= __ffs(GIC_CONFIG_COUNTBITS);
count_width *= 4;
count_width += 32;
gic_clocksource.mask = CLOCKSOURCE_MASK(count_width);
gic_count_width = read_gic_config() & GIC_CONFIG_COUNTBITS;
gic_count_width >>= __ffs(GIC_CONFIG_COUNTBITS);
gic_count_width *= 4;
gic_count_width += 32;
gic_clocksource.mask = CLOCKSOURCE_MASK(gic_count_width);

/* Calculate a somewhat reasonable rating value. */
gic_clocksource.rating = 200 + gic_frequency / 10000000;
if (mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ))
gic_clocksource.rating = 300; /* Good when frequecy is stable */
else
gic_clocksource.rating = 200;
gic_clocksource.rating += clamp(gic_frequency / 10000000, 0, 99);

ret = clocksource_register_hz(&gic_clocksource, gic_frequency);
if (ret < 0)
Expand Down Expand Up @@ -260,7 +264,7 @@ static int __init gic_clocksource_of_init(struct device_node *node)
if (mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ)) {
sched_clock_register(mips_cm_is64 ?
gic_read_count_64 : gic_read_count_2x32,
64, gic_frequency);
gic_count_width, gic_frequency);
}

return 0;
Expand Down
Loading

0 comments on commit 4fd9435

Please sign in to comment.