Skip to contentSkip to conversation

treewide: Cleanup LATCH, CLOCK_TICK_RATE and get_cycles() [ab]use

PATCH In review Thomas Gleixner 19 participants 74 messages Apr 10 – Aug 20

Subsystems (58)
lore
Share & tools
lore

Thomas Gleixner

author maintainer
#0 lore raw

cover treewide: Cleanup LATCH, CLOCK_TICK_RATE and get_cycles() [ab]use

First of all sorry for the insanely big Cc list, but people can't make their mind up whether they want to be Cc'ed on everything or not. So I'm opting for the worst case to cater to the people who want to be Cc'ed on everything and assume that the rest of you got used to it by now. I really wanted this to be more confined but a treewide cleanup does not give a lot of options.

That said, let me explain what this is about.

1) LATCH

The LATCH define goes back to Linux version 0.1 and has survived until today for the very wrong reasons.

Initially it was based on the x86 PIT frequency and also steered the timekeeping conversions.

With the arrival of non x86 architectures it got changed to be based on CLOCK_TICK_RATE in order not to change core code which depended on LATCH.

That all got meaningless when timers, timekeeping and scheduling infrastructure got rewritten more than two decades ago.

But there is still a lonely survivor in arch/x86/kernel/apm_32.c which dates back to Linux 1.3.46 (Dec. 1995)

Which causes the next historical gem

2) CLOCK_TICK_RATE

When Linux got expanded beyond i386 LATCH was made "flexible" by basing it on CLOCK_TICK_RATE to adjust for other frequencies than the i386 PIT frequency.

As LATCH this got meaningless long ago and for amusement value it got copied into new architectures arriving way after it got obsolete for no reason but with comments to the effect that it's meaningless

And of course it had a lonely survivor in arch/x86/kernel/setup.c despite it being only an alias for PIT_TICK_RATE for a very long time.

3) get_cycles()

That was introduced in 2.1.133pre4 (Dec. 1998) to utilize the back then brand new TSC. The introduction broke everything except i386 SMP with a CPU having a TSC and got then fixed up within a couple of days with empty stubs returning 0 and #ifdeffery for CONFIG_TSC before the 2.2.0 release.

It's amusing that the naming deliberately ignored that TSC is the acronym for Time Stamp Counter and not Cycle Counter and rather went for the underlying coincidence that the TSC was running at the same fixed frequency as the CPU core.

That turned out to be interesting when CPUs started to have frequency scaling as the TSC then turned into a variable frequency random number generator.

A decade later CPU designers came to senses and made the TSC invariant usually running at the nominal CPU frequency, which allowed to use it for reliable timekeeping purposes.

Non x86 architectures implemented get_cycles() based on whatever continuously running counter they had available in their CPUs. Some of them actual CPU cycle counters, but many of them running at a fixed frequency which was completely unrelated to CPU cycles.

Around 2004/5 the timekeeping subsystem was completely rewritten and made generic along with the scheduling clock and other related infrastructure. With that rewrite get_cycles() got mostly obsolete, but despite it being on the todo list of quite some people it never ceased to exist and it was just a conveniance vehicle to base other things like the recent addition of random_get_entropy() on top with a hideous #ifdef/#define macro maze.

The other remaining use cases are mostly debugging and testing code. Especially the usage in performance test code is hillarious at best. While the name get_cycles() suggests that it provides access to CPU cycles the reality is that it provides a unspecified counter for most systems, where a lot of architectures simply return 0 because they either do not have such a counter or did not bother to implement it at all.

So in fact get_cycles() should have been renamed to get_bogo_cycles() long ago matching the BogoMIPS "impress your friends" printk which still exists for historical amusement value.

But the real solution is to remove it all together instead of proliferating the bogosity.

This is what this series does with the following steps:

1) Cleanup some header dependency hell which got unearthed by the restructuring and went unnoticed so far. It's amazing how the kernel build system magically "works". This affects not only x86, but the main fallout was observed and fixed there. ARM64 and MIPS are at least as bad as they silently rely on the accidental asm/timex.h include through a variety of generic headers to make their architecture code compile. See the changelog and patches specific to those two.

2) Removal of LATCH

3) Removal of CLOCK_TICK_RATE

4) Consolidation of cycles_t which was a typedef in asm/timex.h

5) Cleanup of read_current_timer() which is only used for delay calibration and has nothing to do with get_cycles()

6) Cleanup of get_cycles() usage in debug and test code

7) Decoupling of random_get_entropy() from get_cycles()

8) Removal of asm/timex.h includes except for architecture internal usage where necessary.

At the end get_cycles() survives in a couple of architectures as a purely architecture internal implementation detail.

This survives compile testing on all architectures except hexagon and nios2 because the current cross tools based on gcc15 do not offer a compiler for them anymore. Boot tested on x86 and some qemu instances covering only a few architectures.

The series applies on v7.0-rc7 and with very minor conflicts on -next. It is also available from git:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git getcycles-v1

Thanks,

tglx

---
 arch/alpha/include/asm/timex.h                 |   33 --------
 arch/arc/include/asm/timex.h                   |   15 ---
 arch/arm/include/asm/timex.h                   |   16 ---
 arch/arm64/include/asm/timex.h                 |   18 ----
 arch/hexagon/include/asm/timex.h               |   23 -----
 arch/m68k/include/asm/timex.h                  |   42 ----------
 arch/microblaze/include/asm/timex.h            |   13 ---
 arch/mips/include/asm/timex.h                  |  102 -------------------------
 arch/sh/include/asm/timex.h                    |   24 -----
 arch/sparc/include/asm/timex.h                 |    9 --
 arch/sparc/include/asm/timex_32.h              |   14 ---
 arch/um/include/asm/timex.h                    |    9 --
 b/Documentation/fb/udlfb.rst                   |    4 
 b/arch/Kconfig                                 |   10 ++
 b/arch/alpha/Kconfig                           |    1 
 b/arch/alpha/include/asm/random.h              |   14 +++
 b/arch/arm/Kconfig                             |    2 
 b/arch/arm/include/asm/delay.h                 |    1 
 b/arch/arm/include/asm/random.h                |   14 +++
 b/arch/arm/lib/delay.c                         |   14 +--
 b/arch/arm/mach-omap1/Kconfig                  |    2 
 b/arch/arm64/Kconfig                           |    2 
 b/arch/arm64/include/asm/io.h                  |    5 -
 b/arch/arm64/include/asm/ptp_vmclock.h         |   12 ++
 b/arch/arm64/include/asm/random.h              |   11 ++
 b/arch/arm64/include/asm/rqspinlock.h          |    1 
 b/arch/arm64/kernel/time.c                     |    6 +
 b/arch/arm64/kernel/topology.c                 |    1 
 b/arch/arm64/kernel/traps.c                    |    1 
 b/arch/arm64/kvm/emulate-nested.c              |    1 
 b/arch/arm64/kvm/hyp/include/hyp/switch.h      |    1 
 b/arch/arm64/lib/delay.c                       |    1 
 b/arch/hexagon/Kconfig                         |    1 
 b/arch/hexagon/kernel/time.c                   |    8 +
 b/arch/loongarch/Kconfig                       |    1 
 b/arch/loongarch/include/asm/random.h          |   15 +++
 b/arch/loongarch/include/asm/timex.h           |    2 
 b/arch/loongarch/kernel/relocate.c             |    1 
 b/arch/loongarch/kernel/syscall.c              |    1 
 b/arch/loongarch/lib/delay.c                   |    2 
 b/arch/m68k/Kconfig                            |    1 
 b/arch/m68k/amiga/config.c                     |    1 
 b/arch/m68k/include/asm/random.h               |   14 +++
 b/arch/m68k/kernel/time.c                      |    2 
 b/arch/mips/Kconfig                            |    1 
 b/arch/mips/generic/init.c                     |    1 
 b/arch/mips/include/asm/random.h               |    7 +
 b/arch/mips/kernel/pm-cps.c                    |    1 
 b/arch/mips/kernel/proc.c                      |    1 
 b/arch/mips/kernel/relocate.c                  |    2 
 b/arch/mips/kernel/time.c                      |   53 ++++++++++++
 b/arch/mips/lib/dump_tlb.c                     |    1 
 b/arch/mips/mm/cache.c                         |    1 
 b/arch/nios2/Kconfig                           |    1 
 b/arch/nios2/include/asm/random.h              |   14 +++
 b/arch/nios2/include/asm/timex.h               |    7 -
 b/arch/nios2/kernel/time.c                     |    4 
 b/arch/openrisc/Kconfig                        |    2 
 b/arch/openrisc/include/asm/random.h           |   12 ++
 b/arch/openrisc/include/asm/timex.h            |   10 --
 b/arch/openrisc/lib/delay.c                    |    8 -
 b/arch/parisc/Kconfig                          |    1 
 b/arch/parisc/include/asm/random.h             |   12 ++
 b/arch/parisc/include/asm/timex.h              |   10 --
 b/arch/parisc/kernel/processor.c               |    1 
 b/arch/parisc/kernel/time.c                    |    1 
 b/arch/powerpc/Kconfig                         |    1 
 b/arch/powerpc/include/asm/random.h            |   13 +++
 b/arch/powerpc/include/asm/timex.h             |   25 ------
 b/arch/powerpc/platforms/cell/spufs/switch.c   |    5 -
 b/arch/riscv/Kconfig                           |    2 
 b/arch/riscv/include/asm/random.h              |   25 ++++++
 b/arch/riscv/include/asm/timex.h               |   23 -----
 b/arch/riscv/kernel/unaligned_access_speed.c   |    1 
 b/arch/riscv/kvm/vcpu_timer.c                  |    1 
 b/arch/riscv/lib/delay.c                       |    8 +
 b/arch/s390/Kconfig                            |    1 
 b/arch/s390/include/asm/random.h               |   12 ++
 b/arch/s390/include/asm/timex.h                |   10 --
 b/arch/s390/kernel/time.c                      |    1 
 b/arch/s390/kernel/vtime.c                     |    1 
 b/arch/sparc/Kconfig                           |    2 
 b/arch/sparc/include/asm/random.h              |   15 +++
 b/arch/sparc/include/asm/timex_64.h            |   20 ----
 b/arch/sparc/kernel/pcic.c                     |    1 
 b/arch/sparc/kernel/time_32.c                  |    1 
 b/arch/sparc/kernel/time_64.c                  |    4 
 b/arch/sparc/vdso/vclock_gettime.c             |    1 
 b/arch/x86/Kconfig                             |    4 
 b/arch/x86/include/asm/iommu.h                 |    3 
 b/arch/x86/include/asm/msr.h                   |    5 -
 b/arch/x86/include/asm/percpu.h                |    5 -
 b/arch/x86/include/asm/percpu_types.h          |   17 ++++
 b/arch/x86/include/asm/ptp_vmclock.h           |   12 ++
 b/arch/x86/include/asm/pvclock.h               |    1 
 b/arch/x86/include/asm/random.h                |   12 --
 b/arch/x86/include/asm/smp.h                   |    2 
 b/arch/x86/include/asm/tsc.h                   |   11 --
 b/arch/x86/include/asm/vdso/gettimeofday.h     |    5 -
 b/arch/x86/kernel/apm_32.c                     |    4 
 b/arch/x86/kernel/cpu/mce/core.c               |    1 
 b/arch/x86/kernel/nmi.c                        |    1 
 b/arch/x86/kernel/setup.c                      |    2 
 b/arch/x86/kernel/smpboot.c                    |    1 
 b/arch/x86/kernel/tsc.c                        |   12 +-
 b/arch/x86/lib/delay.c                         |    8 -
 b/crypto/jitterentropy-kcapi.c                 |    1 
 b/crypto/tcrypt.c                              |   84 ++++++++++----------
 b/drivers/iommu/intel/dmar.c                   |    4 
 b/drivers/iommu/intel/iommu.h                  |    8 +
 b/drivers/irqchip/irq-apple-aic.c              |    1 
 b/drivers/misc/sgi-gru/gruhandles.c            |   20 +---
 b/drivers/misc/sgi-gru/grukservices.c          |    3 
 b/drivers/misc/sgi-gru/grutlbpurge.c           |    5 -
 b/drivers/net/arcnet/arc-rimi.c                |    4 
 b/drivers/net/arcnet/arcdevice.h               |   20 ----
 b/drivers/net/arcnet/com20020.c                |    6 -
 b/drivers/net/arcnet/com90io.c                 |    6 -
 b/drivers/net/arcnet/com90xx.c                 |    4 
 b/drivers/net/hamradio/baycom_epp.c            |   51 ------------
 b/drivers/net/wireless/ath/wil6210/debugfs.c   |    2 
 b/drivers/net/wireless/ath/wil6210/txrx.c      |    6 -
 b/drivers/net/wireless/ath/wil6210/txrx_edma.c |    4 
 b/drivers/net/wireless/ath/wil6210/wil6210.h   |    3 
 b/drivers/ptp/Kconfig                          |    6 -
 b/drivers/ptp/ptp_vmclock.c                    |    6 -
 b/drivers/video/fbdev/udlfb.c                  |   24 ++---
 b/fs/ext4/mballoc.c                            |    4 
 b/include/asm-generic/Kbuild                   |    2 
 b/include/asm-generic/percpu_types.h           |   20 ++++
 b/include/linux/compiler_types.h               |    1 
 b/include/linux/delay.h                        |    2 
 b/include/linux/jiffies.h                      |    3 
 b/include/linux/random.h                       |   18 ++++
 b/include/linux/timex.h                        |   26 ------
 b/include/linux/types.h                        |    6 +
 b/init/calibrate.c                             |   19 ++--
 b/kernel/kcsan/core.c                          |    3 
 b/kernel/kcsan/debugfs.c                       |    8 -
 b/kernel/time/timer.c                          |    1 
 b/lib/interval_tree_test.c                     |   17 +---
 b/lib/rbtree_test.c                            |   47 +++++------
 b/lib/test_vmalloc.c                           |   10 +-
 b/mm/kasan/sw_tags.c                           |    2 
 b/mm/slub.c                                    |   37 +++++----
 include/asm-generic/timex.h                    |   23 -----
 146 files changed, 622 insertions(+), 796 deletions(-)
author maintainer
#1 lore raw

PATCH 1/38 percpu: Sanitize __percpu_qual include hell

Slapping __percpu_qual into the next available header is sloppy at best.

It's required by __percpu which is defined in compiler_types.h and that is meant to be included without requiring a boatload of other headers so that a struct or function declaration can contain a __percpu qualifier w/o further prerequisites.

This implicit dependency on linux/percpu.h makes that impossible and causes a major problem when trying to seperate headers.

Create asm/percpu_types.h and move it there. Include that from compiler_types.h and the whole recursion problem goes away.

---
 arch/x86/include/asm/percpu.h       |    5 -----
 arch/x86/include/asm/percpu_types.h |   17 +++++++++++++++++
 include/asm-generic/Kbuild          |    1 +
 include/asm-generic/percpu_types.h  |   20 ++++++++++++++++++++
 include/linux/compiler_types.h      |    1 +
 5 files changed, 39 insertions(+), 5 deletions(-)
arch/x86/include/asm/percpu.h +0 -5
@@ -40,12 +40,10 @@
 #endif
 
 #define __percpu_prefix
-#define __percpu_seg_override	CONCATENATE(__seg_, __percpu_seg)
 
 #else /* !CONFIG_CC_HAS_NAMED_AS: */
 
 #define __percpu_prefix		__force_percpu_prefix
-#define __percpu_seg_override
 
 #endif /* CONFIG_CC_HAS_NAMED_AS */
 
@@ -82,7 +80,6 @@
 
 #define __force_percpu_prefix
 #define __percpu_prefix
-#define __percpu_seg_override
 
 #define PER_CPU_VAR(var)	(var)__percpu_rel
 
@@ -92,8 +89,6 @@
 # define __my_cpu_type(var)	typeof(var)
 # define __my_cpu_ptr(ptr)	(ptr)
 # define __my_cpu_var(var)	(var)
-
-# define __percpu_qual		__percpu_seg_override
 #else
 # define __my_cpu_type(var)	typeof(var) __percpu_seg_override
 # define __my_cpu_ptr(ptr)	(__my_cpu_type(*(ptr))*)(__force uintptr_t)(ptr)
arch/x86/include/asm/percpu_types.h new file +17 -0
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_PERCPU_TYPES_H
+#define _ASM_X86_PERCPU_TYPES_H
+
+#if defined(CONFIG_SMP) && defined(CONFIG_CC_HAS_NAMED_AS)
+#define __percpu_seg_override	CONCATENATE(__seg_, __percpu_seg)
+#else /* !CONFIG_CC_HAS_NAMED_AS: */
+#define __percpu_seg_override
+#endif
+
+#if defined(CONFIG_USE_X86_SEG_SUPPORT) && defined(USE_TYPEOF_UNQUAL)
+#define __percpu_qual		__percpu_seg_override
+#endif
+
+#include <asm-generic/percpu_types.h>
+
+#endif
include/asm-generic/Kbuild +1 -0
@@ -44,6 +44,7 @@ mandatory-y += module.lds.h
 mandatory-y += msi.h
 mandatory-y += pci.h
 mandatory-y += percpu.h
+mandatory-y += percpu_types.h
 mandatory-y += pgalloc.h
 mandatory-y += preempt.h
 mandatory-y += rqspinlock.h
include/asm-generic/percpu_types.h new file +20 -0
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_PERCPU_TYPES_H_
+#define _ASM_GENERIC_PERCPU_TYPES_H_
+
+#ifndef __ASSEMBLER__
+/*
+ * __percpu_qual is the qualifier for the percpu named address space.
+ *
+ * Most arches use generic named address space for percpu variables but
+ * some arches define percpu variables in different named address space
+ * (on the x86 arch, percpu variable may be declared as being relative
+ * to the %fs or %gs segments using __seg_fs or __seg_gs named address
+ * space qualifier).
+ */
+#ifndef __percpu_qual
+# define __percpu_qual
+#endif
+
+#endif /* __ASSEMBLER__ */
+#endif /* _ASM_GENERIC_PERCPU_TYPES_H_ */
include/linux/compiler_types.h +1 -0
@@ -41,6 +41,7 @@
 # define BTF_TYPE_TAG(value) /* nothing */
 #endif
 
+#include <asm/percpu_types.h>
 #include <linux/compiler-context-analysis.h>
 
 /* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */
author maintainer
#2 lore raw

PATCH 2/38 x86: Cleanup include recursion hell

In reply to Thomas Gleixner

Including a random architecture specific header which requires global headers just to avoid including that header at the two usage sites is really beyond lazy and tasteless. Including global headers just to get the __percpu macro from linux/compiler_types.h falls into the same category.

Remove the linux/percpu.h and asm/cpumask.h includes from msr.h and smp.h and fix the resulting fallout by a simple forward struct declaration and by including the x86 specific asm/cpumask.h header where it is actually required.

---
 arch/x86/include/asm/msr.h               |    5 +++--
 arch/x86/include/asm/pvclock.h           |    1 +
 arch/x86/include/asm/smp.h               |    2 --
 arch/x86/include/asm/vdso/gettimeofday.h |    5 ++---
 arch/x86/kernel/cpu/mce/core.c           |    1 +
 arch/x86/kernel/nmi.c                    |    1 +
 arch/x86/kernel/smpboot.c                |    1 +
 7 files changed, 9 insertions(+), 7 deletions(-)
arch/x86/include/asm/msr.h +3 -2
@@ -8,12 +8,11 @@
 
 #include <asm/asm.h>
 #include <asm/errno.h>
-#include <asm/cpumask.h>
 #include <uapi/asm/msr.h>
 #include <asm/shared/msr.h>
 
+#include <linux/compiler_types.h>
 #include <linux/types.h>
-#include <linux/percpu.h>
 
 struct msr_info {
 	u32			msr_no;
@@ -256,6 +255,8 @@ int msr_set_bit(u32 msr, u8 bit);
 int msr_clear_bit(u32 msr, u8 bit);
 
 #ifdef CONFIG_SMP
+struct cpumask;
+
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsrq_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
arch/x86/include/asm/pvclock.h +1 -0
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_PVCLOCK_H
 #define _ASM_X86_PVCLOCK_H
 
+#include <asm/barrier.h>
 #include <asm/clocksource.h>
 #include <asm/pvclock-abi.h>
 
arch/x86/include/asm/smp.h +0 -2
@@ -5,8 +5,6 @@
 #include <linux/cpumask.h>
 #include <linux/thread_info.h>
 
-#include <asm/cpumask.h>
-
 DECLARE_PER_CPU_CACHE_HOT(int, cpu_number);
 
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
arch/x86/include/asm/vdso/gettimeofday.h +2 -3
@@ -11,13 +11,12 @@
 #define __ASM_VDSO_GETTIMEOFDAY_H
 
 #ifndef __ASSEMBLER__
-
+#include <clocksource/hyperv_timer.h>
 #include <uapi/linux/time.h>
+
 #include <asm/vgtod.h>
 #include <asm/unistd.h>
-#include <asm/msr.h>
 #include <asm/pvclock.h>
-#include <clocksource/hyperv_timer.h>
 #include <asm/vdso/sys_call.h>
 
 #define VDSO_HAS_TIME 1
arch/x86/kernel/cpu/mce/core.c +1 -0
@@ -48,6 +48,7 @@
 #include <linux/vmcore_info.h>
 
 #include <asm/fred.h>
+#include <asm/cpumask.h>
 #include <asm/cpu_device_id.h>
 #include <asm/processor.h>
 #include <asm/traps.h>
arch/x86/kernel/nmi.c +1 -0
@@ -26,6 +26,7 @@
 #include <linux/sched/clock.h>
 #include <linux/kvm_types.h>
 
+#include <asm/cpumask.h>
 #include <asm/cpu_entry_area.h>
 #include <asm/traps.h>
 #include <asm/mach_traps.h>
arch/x86/kernel/smpboot.c +1 -0
@@ -70,6 +70,7 @@
 #include <asm/irq.h>
 #include <asm/realmode.h>
 #include <asm/cpu.h>
+#include <asm/cpumask.h>
 #include <asm/numa.h>
 #include <asm/tlbflush.h>
 #include <asm/mtrr.h>
author maintainer
#3 lore raw

PATCH 2/38 x86: Cleanup include recursion hell

Including a random architecture specific header which requires global headers just to avoid including that header at the two usage sites is really beyond lazy and tasteless. Including global headers just to get the __percpu macro from linux/compiler_types.h falls into the same category.

Remove the linux/percpu.h and asm/cpumask.h includes from msr.h and smp.h and fix the resulting fallout by a simple forward struct declaration and by including the x86 specific asm/cpumask.h header where it is actually required.

---
V1.1: Fix PARAVIRT_XXL fallout....

---
 arch/x86/include/asm/cache.h             |    1 +
 arch/x86/include/asm/msr.h               |    5 +++--
 arch/x86/include/asm/paravirt.h          |    3 ++-
 arch/x86/include/asm/pvclock.h           |    1 +
 arch/x86/include/asm/smp.h               |    2 --
 arch/x86/include/asm/vdso/gettimeofday.h |    5 ++---
 arch/x86/kernel/cpu/mce/core.c           |    1 +
 arch/x86/kernel/nmi.c                    |    1 +
 arch/x86/kernel/smpboot.c                |    1 +
 9 files changed, 12 insertions(+), 8 deletions(-)
arch/x86/include/asm/cache.h +1 -0
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_CACHE_H
 #define _ASM_X86_CACHE_H
 
+#include <vdso/page.h>
 #include <linux/linkage.h>
 
 /* L1 cache line size */
arch/x86/include/asm/msr.h +3 -2
@@ -8,12 +8,11 @@
 
 #include <asm/asm.h>
 #include <asm/errno.h>
-#include <asm/cpumask.h>
 #include <uapi/asm/msr.h>
 #include <asm/shared/msr.h>
 
+#include <linux/compiler_types.h>
 #include <linux/types.h>
-#include <linux/percpu.h>
 
 struct msr_info {
 	u32			msr_no;
@@ -256,6 +255,8 @@ int msr_set_bit(u32 msr, u8 bit);
 int msr_clear_bit(u32 msr, u8 bit);
 
 #ifdef CONFIG_SMP
+struct cpumask;
+
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsrq_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
arch/x86/include/asm/paravirt.h +2 -1
@@ -16,9 +16,10 @@
 
 #ifndef __ASSEMBLER__
 #include <linux/types.h>
-#include <linux/cpumask.h>
 #include <asm/frame.h>
 
+struct cpumask;
+
 /* The paravirtualized I/O functions */
 static inline void slow_down_io(void)
 {
arch/x86/include/asm/pvclock.h +1 -0
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_PVCLOCK_H
 #define _ASM_X86_PVCLOCK_H
 
+#include <asm/barrier.h>
 #include <asm/clocksource.h>
 #include <asm/pvclock-abi.h>
 
arch/x86/include/asm/smp.h +0 -2
@@ -5,8 +5,6 @@
 #include <linux/cpumask.h>
 #include <linux/thread_info.h>
 
-#include <asm/cpumask.h>
-
 DECLARE_PER_CPU_CACHE_HOT(int, cpu_number);
 
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
arch/x86/include/asm/vdso/gettimeofday.h +2 -3
@@ -11,13 +11,12 @@
 #define __ASM_VDSO_GETTIMEOFDAY_H
 
 #ifndef __ASSEMBLER__
-
+#include <clocksource/hyperv_timer.h>
 #include <uapi/linux/time.h>
+
 #include <asm/vgtod.h>
 #include <asm/unistd.h>
-#include <asm/msr.h>
 #include <asm/pvclock.h>
-#include <clocksource/hyperv_timer.h>
 #include <asm/vdso/sys_call.h>
 
 #define VDSO_HAS_TIME 1
arch/x86/kernel/cpu/mce/core.c +1 -0
@@ -48,6 +48,7 @@
 #include <linux/vmcore_info.h>
 
 #include <asm/fred.h>
+#include <asm/cpumask.h>
 #include <asm/cpu_device_id.h>
 #include <asm/processor.h>
 #include <asm/traps.h>
arch/x86/kernel/nmi.c +1 -0
@@ -26,6 +26,7 @@
 #include <linux/sched/clock.h>
 #include <linux/kvm_types.h>
 
+#include <asm/cpumask.h>
 #include <asm/cpu_entry_area.h>
 #include <asm/traps.h>
 #include <asm/mach_traps.h>
arch/x86/kernel/smpboot.c +1 -0
@@ -70,6 +70,7 @@
 #include <asm/irq.h>
 #include <asm/realmode.h>
 #include <asm/cpu.h>
+#include <asm/cpumask.h>
 #include <asm/numa.h>
 #include <asm/tlbflush.h>
 #include <asm/mtrr.h>
author maintainer
#4 lore raw

PATCH 3/38 x86/apm: Remove last LATCH usage

In reply to Thomas Gleixner

LATCH is a historical leftover and has been replaced with PIT_LATCH in all other places a decade ago. Replace the last holdout and remove the definition from jiffies.h.

This allows to remove the otherwise unused CLOCK_TICK_RATE define in the next step.

---
 arch/x86/kernel/apm_32.c |    4 ++--
 include/linux/jiffies.h  |    3 ---
 2 files changed, 2 insertions(+), 5 deletions(-)
arch/x86/kernel/apm_32.c +2 -2
@@ -1196,9 +1196,9 @@ static void reinit_timer(void)
 	/* set the clock to HZ */
 	outb_p(0x34, PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
 	udelay(10);
-	outb_p(LATCH & 0xff, PIT_CH0);	/* LSB */
+	outb_p(PIT_LATCH & 0xff, PIT_CH0);	/* LSB */
 	udelay(10);
-	outb_p(LATCH >> 8, PIT_CH0);	/* MSB */
+	outb_p(PIT_LATCH >> 8, PIT_CH0);	/* MSB */
 	udelay(10);
 	raw_spin_unlock_irqrestore(&i8253_lock, flags);
 #endif
include/linux/jiffies.h +0 -3
@@ -56,9 +56,6 @@
 #define SH_DIV(NOM,DEN,LSH) (   (((NOM) / (DEN)) << (LSH))              \
                              + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN))
 
-/* LATCH is used in the interval timer and ftape setup. */
-#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
-
 extern void register_refined_jiffies(long clock_tick_rate);
 
 /* TICK_USEC is the time between ticks in usec */
author maintainer
#5 lore raw

PATCH 4/38 x86: Use PIT_TICK_RATE instead of CLOCK_TICK_RATE

In reply to Thomas Gleixner

CLOCK_TICK_RATE is only used in x86 but defined all over the tree for no reason with comments that it's scheduled for removal for more than a decade.

Use PIT_TICK_RATE for registering refined jiffies to get rid of the last dependency.

---
 arch/x86/kernel/setup.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/setup.c +1 -1
@@ -1268,7 +1268,7 @@ void __init setup_arch(char **cmdline_p)
 
 	mcheck_init();
 
-	register_refined_jiffies(CLOCK_TICK_RATE);
+	register_refined_jiffies(PIT_TICK_RATE);
 
 #ifdef CONFIG_EFI
 	if (efi_enabled(EFI_BOOT))
author maintainer
#6 lore raw

PATCH 5/38 treewide: Remove CLOCK_TICK_RATE

In reply to Thomas Gleixner

This has been scheduled for removal more than a decade ago and the comments related to it have been dutifully ignored. The last dependencies are gone.

Remove it along with various now empty asm/timex.h files.

---
 arch/alpha/include/asm/timex.h      |    4 ----
 arch/arc/include/asm/timex.h        |   15 ---------------
 arch/arm/mach-omap1/Kconfig         |    2 +-
 arch/hexagon/include/asm/timex.h    |    3 ---
 arch/m68k/include/asm/timex.h       |   15 ---------------
 arch/microblaze/include/asm/timex.h |   13 -------------
 arch/mips/include/asm/timex.h       |    8 --------
 arch/openrisc/include/asm/timex.h   |    3 ---
 arch/parisc/include/asm/timex.h     |    2 --
 arch/powerpc/include/asm/timex.h    |    2 --
 arch/s390/include/asm/timex.h       |    2 --
 arch/sh/include/asm/timex.h         |   24 ------------------------
 arch/sparc/include/asm/timex.h      |    2 +-
 arch/sparc/include/asm/timex_32.h   |   14 --------------
 arch/sparc/include/asm/timex_64.h   |    2 --
 arch/um/include/asm/timex.h         |    9 ---------
 arch/x86/include/asm/timex.h        |    3 ---
 17 files changed, 2 insertions(+), 121 deletions(-)
arch/alpha/include/asm/timex.h +0 -4
@@ -7,10 +7,6 @@
 #ifndef _ASMALPHA_TIMEX_H
 #define _ASMALPHA_TIMEX_H
 
-/* With only one or two oddballs, we use the RTC as the ticker, selecting
-   the 32.768kHz reference clock, which nicely divides down to our HZ.  */
-#define CLOCK_TICK_RATE	32768
-
 /*
  * Standard way to access the cycle counter.
  * Currently only used on SMP for scheduling.
arch/arc/include/asm/timex.h deleted +0 -15
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
- */
-
-#ifndef _ASM_ARC_TIMEX_H
-#define _ASM_ARC_TIMEX_H
-
-#define CLOCK_TICK_RATE	80000000 /* slated to be removed */
-
-#include <asm-generic/timex.h>
-
-/* XXX: get_cycles() to be implemented with RTSC insn */
-
-#endif /* _ASM_ARC_TIMEX_H */
arch/arm/mach-omap1/Kconfig +1 -1
@@ -74,7 +74,7 @@ config OMAP_32K_TIMER
 	  currently only available for OMAP16XX, 24XX, 34XX, OMAP4/5 and DRA7XX.
 
 	  On OMAP2PLUS this value is only used for CONFIG_HZ and
-	  CLOCK_TICK_RATE compile time calculation.
+	  timer frequency compile time calculation.
 	  The actual timer selection is done in the board file
 	  through the (DT_)MACHINE_START structure.
 
arch/hexagon/include/asm/timex.h +0 -3
@@ -9,9 +9,6 @@
 #include <asm-generic/timex.h>
 #include <asm/hexagon_vm.h>
 
-/* Using TCX0 as our clock.  CLOCK_TICK_RATE scheduled to be removed. */
-#define CLOCK_TICK_RATE              19200
-
 #define ARCH_HAS_READ_CURRENT_TIMER
 
 static inline int read_current_timer(unsigned long *timer_val)
arch/m68k/include/asm/timex.h +0 -15
@@ -7,21 +7,6 @@
 #ifndef _ASMm68K_TIMEX_H
 #define _ASMm68K_TIMEX_H
 
-#ifdef CONFIG_COLDFIRE
-/*
- * CLOCK_TICK_RATE should give the underlying frequency of the tick timer
- * to make ntp work best.  For Coldfires, that's the main clock.
- */
-#include <asm/coldfire.h>
-#define CLOCK_TICK_RATE	MCF_CLK
-#else
-/*
- * This default CLOCK_TICK_RATE is probably wrong for many 68k boards
- * Users of those boards will need to check and modify accordingly
- */
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
-#endif
-
 typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles(void)
arch/microblaze/include/asm/timex.h deleted +0 -13
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- */
-
-#ifndef _ASM_MICROBLAZE_TIMEX_H
-#define _ASM_MICROBLAZE_TIMEX_H
-
-#include <asm-generic/timex.h>
-
-#define CLOCK_TICK_RATE 1000 /* Timer input freq. */
-
-#endif /* _ASM_TIMEX_H */
arch/mips/include/asm/timex.h +0 -8
@@ -19,14 +19,6 @@
 #include <asm/cpu-type.h>
 
 /*
- * This is the clock rate of the i8253 PIT.  A MIPS system may not have
- * a PIT by the symbol is used all over the kernel including some APIs.
- * So keeping it defined to the number for the PIT is the only sane thing
- * for now.
- */
-#define CLOCK_TICK_RATE 1193182
-
-/*
  * Standard way to access the cycle counter.
  * Currently only used on SMP for scheduling.
  *
arch/openrisc/include/asm/timex.h +0 -3
@@ -25,9 +25,6 @@ static inline cycles_t get_cycles(void)
 }
 #define get_cycles get_cycles
 
-/* This isn't really used any more */
-#define CLOCK_TICK_RATE 1000
-
 #define ARCH_HAS_READ_CURRENT_TIMER
 
 #endif
arch/parisc/include/asm/timex.h +0 -2
@@ -9,8 +9,6 @@
 
 #include <asm/special_insns.h>
 
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
-
 typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles(void)
arch/powerpc/include/asm/timex.h +0 -2
@@ -11,8 +11,6 @@
 #include <asm/cputable.h>
 #include <asm/vdso/timebase.h>
 
-#define CLOCK_TICK_RATE	1024000 /* Underlying HZ */
-
 typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles(void)
arch/s390/include/asm/timex.h +0 -2
@@ -177,8 +177,6 @@ static inline void local_tick_enable(uns
 	set_clock_comparator(get_lowcore()->clock_comparator);
 }
 
-#define CLOCK_TICK_RATE		1193180 /* Underlying HZ */
-
 typedef unsigned long cycles_t;
 
 static __always_inline unsigned long get_tod_clock(void)
arch/sh/include/asm/timex.h deleted +0 -24
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/asm-sh/timex.h
- *
- * sh architecture timex specifications
- */
-#ifndef __ASM_SH_TIMEX_H
-#define __ASM_SH_TIMEX_H
-
-/*
- * Only parts using the legacy CPG code for their clock framework
- * implementation need to define their own Pclk value. If provided, this
- * can be used for accurately setting CLOCK_TICK_RATE, otherwise we
- * simply fall back on the i8253 PIT value.
- */
-#ifdef CONFIG_SH_PCLK_FREQ
-#define CLOCK_TICK_RATE		(CONFIG_SH_PCLK_FREQ / 4) /* Underlying HZ */
-#else
-#define CLOCK_TICK_RATE		1193180
-#endif
-
-#include <asm-generic/timex.h>
-
-#endif /* __ASM_SH_TIMEX_H */
arch/sparc/include/asm/timex.h +1 -1
@@ -4,6 +4,6 @@
 #if defined(__sparc__) && defined(__arch64__)
 #include <asm/timex_64.h>
 #else
-#include <asm/timex_32.h>
+#include <asm-generic/timex.h>
 #endif
 #endif
arch/sparc/include/asm/timex_32.h deleted +0 -14
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/asm/timex.h
- *
- * sparc architecture timex specifications
- */
-#ifndef _ASMsparc_TIMEX_H
-#define _ASMsparc_TIMEX_H
-
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
-
-#include <asm-generic/timex.h>
-
-#endif
arch/sparc/include/asm/timex_64.h +0 -2
@@ -9,8 +9,6 @@
 
 #include <asm/timer.h>
 
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
-
 /* Getting on the cycle counter on sparc64. */
 typedef unsigned long cycles_t;
 #define get_cycles()	tick_ops->get_tick()
arch/um/include/asm/timex.h deleted +0 -9
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __UM_TIMEX_H
-#define __UM_TIMEX_H
-
-#define CLOCK_TICK_RATE (HZ)
-
-#include <asm-generic/timex.h>
-
-#endif
arch/x86/include/asm/timex.h +0 -3
@@ -14,9 +14,6 @@ static inline unsigned long random_get_e
 }
 #define random_get_entropy random_get_entropy
 
-/* Assume we use the PIT time source for the clock tick */
-#define CLOCK_TICK_RATE		PIT_TICK_RATE
-
 #define ARCH_HAS_READ_CURRENT_TIMER
 
 #endif /* _ASM_X86_TIMEX_H */
reviewer Reviewed-by on v1 5/38
#7 lore raw

Re: [patch 05/38] treewide: Remove CLOCK_TICK_RATE

Le 10/04/2026 à 14:18, Thomas Gleixner a écrit :

Quoted 6 lines

This has been scheduled for removal more than a decade ago and the comments related to it have been dutifully ignored. The last dependencies are gone.

Remove it along with various now empty asm/timex.h files.

For powerpc:

Quoted 267 lines
---
  arch/alpha/include/asm/timex.h      |    4 ----
  arch/arc/include/asm/timex.h        |   15 ---------------
  arch/arm/mach-omap1/Kconfig         |    2 +-
  arch/hexagon/include/asm/timex.h    |    3 ---
  arch/m68k/include/asm/timex.h       |   15 ---------------
  arch/microblaze/include/asm/timex.h |   13 -------------
  arch/mips/include/asm/timex.h       |    8 --------
  arch/openrisc/include/asm/timex.h   |    3 ---
  arch/parisc/include/asm/timex.h     |    2 --
  arch/powerpc/include/asm/timex.h    |    2 --
  arch/s390/include/asm/timex.h       |    2 --
  arch/sh/include/asm/timex.h         |   24 ------------------------
  arch/sparc/include/asm/timex.h      |    2 +-
  arch/sparc/include/asm/timex_32.h   |   14 --------------
  arch/sparc/include/asm/timex_64.h   |    2 --
  arch/um/include/asm/timex.h         |    9 ---------
  arch/x86/include/asm/timex.h        |    3 ---
  17 files changed, 2 insertions(+), 121 deletions(-)
arch/alpha/include/asm/timex.h +0 -4
@@ -7,10 +7,6 @@
  #ifndef _ASMALPHA_TIMEX_H
  #define _ASMALPHA_TIMEX_H
 
-/* With only one or two oddballs, we use the RTC as the ticker, selecting
-   the 32.768kHz reference clock, which nicely divides down to our HZ.  */
-#define CLOCK_TICK_RATE	32768
-
  /*
   * Standard way to access the cycle counter.
   * Currently only used on SMP for scheduling.
arch/arc/include/asm/timex.h deleted +0 -15
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.synopsys.com%2F&data=05%7C02%7Cchristophe.leroy%40csgroup.eu%7Cac13d5b928bc4eabd9b708de96fb5935%7C8b87af7d86474dc78df45f69a2011bb5%7C0%7C0%7C639114203455047148%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=uCL895qVLUoy3Stzhmgph2DiYmjpd4RPdQIW2dZcJ7w%3D&reserved=0)
- */
-
-#ifndef _ASM_ARC_TIMEX_H
-#define _ASM_ARC_TIMEX_H
-
-#define CLOCK_TICK_RATE	80000000 /* slated to be removed */
-
-#include <asm-generic/timex.h>
-
-/* XXX: get_cycles() to be implemented with RTSC insn */
-
-#endif /* _ASM_ARC_TIMEX_H */
arch/arm/mach-omap1/Kconfig +1 -1
@@ -74,7 +74,7 @@ config OMAP_32K_TIMER
  	  currently only available for OMAP16XX, 24XX, 34XX, OMAP4/5 and DRA7XX.
 
  	  On OMAP2PLUS this value is only used for CONFIG_HZ and
-	  CLOCK_TICK_RATE compile time calculation.
+	  timer frequency compile time calculation.
  	  The actual timer selection is done in the board file
  	  through the (DT_)MACHINE_START structure.
 
arch/hexagon/include/asm/timex.h +0 -3
@@ -9,9 +9,6 @@
  #include <asm-generic/timex.h>
  #include <asm/hexagon_vm.h>
 
-/* Using TCX0 as our clock.  CLOCK_TICK_RATE scheduled to be removed. */
-#define CLOCK_TICK_RATE              19200
-
  #define ARCH_HAS_READ_CURRENT_TIMER
 
  static inline int read_current_timer(unsigned long *timer_val)
arch/m68k/include/asm/timex.h +0 -15
@@ -7,21 +7,6 @@
  #ifndef _ASMm68K_TIMEX_H
  #define _ASMm68K_TIMEX_H
 
-#ifdef CONFIG_COLDFIRE
-/*
- * CLOCK_TICK_RATE should give the underlying frequency of the tick timer
- * to make ntp work best.  For Coldfires, that's the main clock.
- */
-#include <asm/coldfire.h>
-#define CLOCK_TICK_RATE	MCF_CLK
-#else
-/*
- * This default CLOCK_TICK_RATE is probably wrong for many 68k boards
- * Users of those boards will need to check and modify accordingly
- */
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
-#endif
-
  typedef unsigned long cycles_t;
 
  static inline cycles_t get_cycles(void)
arch/microblaze/include/asm/timex.h deleted +0 -13
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- */
-
-#ifndef _ASM_MICROBLAZE_TIMEX_H
-#define _ASM_MICROBLAZE_TIMEX_H
-
-#include <asm-generic/timex.h>
-
-#define CLOCK_TICK_RATE 1000 /* Timer input freq. */
-
-#endif /* _ASM_TIMEX_H */
arch/mips/include/asm/timex.h +0 -8
@@ -19,14 +19,6 @@
  #include <asm/cpu-type.h>
 
  /*
- * This is the clock rate of the i8253 PIT.  A MIPS system may not have
- * a PIT by the symbol is used all over the kernel including some APIs.
- * So keeping it defined to the number for the PIT is the only sane thing
- * for now.
- */
-#define CLOCK_TICK_RATE 1193182
-
-/*
   * Standard way to access the cycle counter.
   * Currently only used on SMP for scheduling.
   *
arch/openrisc/include/asm/timex.h +0 -3
@@ -25,9 +25,6 @@ static inline cycles_t get_cycles(void)
  }
  #define get_cycles get_cycles
 
-/* This isn't really used any more */
-#define CLOCK_TICK_RATE 1000
-
  #define ARCH_HAS_READ_CURRENT_TIMER
 
  #endif
arch/parisc/include/asm/timex.h +0 -2
@@ -9,8 +9,6 @@
 
  #include <asm/special_insns.h>
 
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
-
  typedef unsigned long cycles_t;
 
  static inline cycles_t get_cycles(void)
arch/powerpc/include/asm/timex.h +0 -2
@@ -11,8 +11,6 @@
  #include <asm/cputable.h>
  #include <asm/vdso/timebase.h>
 
-#define CLOCK_TICK_RATE	1024000 /* Underlying HZ */
-
  typedef unsigned long cycles_t;
 
  static inline cycles_t get_cycles(void)
arch/s390/include/asm/timex.h +0 -2
@@ -177,8 +177,6 @@ static inline void local_tick_enable(uns
  	set_clock_comparator(get_lowcore()->clock_comparator);
  }
 
-#define CLOCK_TICK_RATE		1193180 /* Underlying HZ */
-
  typedef unsigned long cycles_t;
 
  static __always_inline unsigned long get_tod_clock(void)
arch/sh/include/asm/timex.h deleted +0 -24
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/asm-sh/timex.h
- *
- * sh architecture timex specifications
- */
-#ifndef __ASM_SH_TIMEX_H
-#define __ASM_SH_TIMEX_H
-
-/*
- * Only parts using the legacy CPG code for their clock framework
- * implementation need to define their own Pclk value. If provided, this
- * can be used for accurately setting CLOCK_TICK_RATE, otherwise we
- * simply fall back on the i8253 PIT value.
- */
-#ifdef CONFIG_SH_PCLK_FREQ
-#define CLOCK_TICK_RATE		(CONFIG_SH_PCLK_FREQ / 4) /* Underlying HZ */
-#else
-#define CLOCK_TICK_RATE		1193180
-#endif
-
-#include <asm-generic/timex.h>
-
-#endif /* __ASM_SH_TIMEX_H */
arch/sparc/include/asm/timex.h +1 -1
@@ -4,6 +4,6 @@
  #if defined(__sparc__) && defined(__arch64__)
  #include <asm/timex_64.h>
  #else
-#include <asm/timex_32.h>
+#include <asm-generic/timex.h>
  #endif
  #endif
arch/sparc/include/asm/timex_32.h deleted +0 -14
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/asm/timex.h
- *
- * sparc architecture timex specifications
- */
-#ifndef _ASMsparc_TIMEX_H
-#define _ASMsparc_TIMEX_H
-
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
-
-#include <asm-generic/timex.h>
-
-#endif
arch/sparc/include/asm/timex_64.h +0 -2
@@ -9,8 +9,6 @@
 
  #include <asm/timer.h>
 
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
-
  /* Getting on the cycle counter on sparc64. */
  typedef unsigned long cycles_t;
  #define get_cycles()	tick_ops->get_tick()
arch/um/include/asm/timex.h deleted +0 -9
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __UM_TIMEX_H
-#define __UM_TIMEX_H
-
-#define CLOCK_TICK_RATE (HZ)
-
-#include <asm-generic/timex.h>
-
-#endif
arch/x86/include/asm/timex.h +0 -3
@@ -14,9 +14,6 @@ static inline unsigned long random_get_e
  }
  #define random_get_entropy random_get_entropy
 
-/* Assume we use the PIT time source for the clock tick */
-#define CLOCK_TICK_RATE		PIT_TICK_RATE
-
  #define ARCH_HAS_READ_CURRENT_TIMER
 
  #endif /* _ASM_X86_TIMEX_H */
maintainer Acked-by on v1 5/38
#8 lore raw

Re: [patch 05/38] treewide: Remove CLOCK_TICK_RATE

In reply to Thomas Gleixner
Quoted 8 lines · Thomas Gleixner

This has been scheduled for removal more than a decade ago and the comments related to it have been dutifully ignored. The last dependencies are gone.

Remove it along with various now empty asm/timex.h files.

 arch/m68k/include/asm/timex.h       |   15 ---------------

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

author maintainer
#9 lore raw

PATCH 6/38 calibrate: Rework delay timer calibration

In reply to Thomas Gleixner

The header define in asm/timex,h and the naming of the function to read the delay timer are confusing at best.

Convert it to a config switch selected by the archictures, which provide the functionality, and rename the function to delay_read_timer(), which makes the purpose clear. Move the declaration to linux/delay.h where it belongs.

Remove the resulting empty asm/timex.h files as well.

No functional change.

---
 arch/Kconfig                      |    3 +++
 arch/arm/Kconfig                  |    1 +
 arch/arm/include/asm/delay.h      |    1 -
 arch/arm/include/asm/timex.h      |    5 ++++-
 arch/arm/lib/delay.c              |   10 ++++------
 arch/hexagon/Kconfig              |    1 +
 arch/hexagon/include/asm/timex.h  |   20 --------------------
 arch/hexagon/kernel/time.c        |    8 +++++++-
 arch/openrisc/Kconfig             |    1 +
 arch/openrisc/include/asm/timex.h |    2 --
 arch/openrisc/lib/delay.c         |    9 ++++-----
 arch/riscv/Kconfig                |    1 +
 arch/riscv/include/asm/timex.h    |    8 --------
 arch/riscv/lib/delay.c            |    7 ++++++-
 arch/sparc/Kconfig                |    1 +
 arch/sparc/include/asm/timex_64.h |    2 --
 arch/sparc/kernel/time_64.c       |    4 ++--
 arch/x86/Kconfig                  |    1 +
 arch/x86/include/asm/timex.h      |    2 --
 arch/x86/lib/delay.c              |    8 +++-----
 include/asm-generic/timex.h       |    7 -------
 include/linux/delay.h             |    2 ++
 include/linux/timex.h             |    2 --
 init/calibrate.c                  |   19 +++++++++----------
 24 files changed, 50 insertions(+), 75 deletions(-)
arch/Kconfig +3 -0
@@ -363,6 +363,9 @@ config ARCH_HAS_DMA_CLEAR_UNCACHED
 config ARCH_HAS_CPU_FINALIZE_INIT
 	bool
 
+config ARCH_HAS_DELAY_TIMER
+	bool
+
 # The architecture has a per-task state that includes the mm's PASID
 config ARCH_HAS_CPU_PASID
 	bool
arch/arm/Kconfig +1 -0
@@ -11,6 +11,7 @@ config ARM
 	select ARCH_HAS_CPU_FINALIZE_INIT if MMU
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DEBUG_VIRTUAL if MMU
+	select ARCH_HAS_DELAY_TIMER
 	select ARCH_HAS_DMA_ALLOC if MMU
 	select ARCH_HAS_DMA_OPS
 	select ARCH_HAS_DMA_WRITE_COMBINE if !ARM_DMA_MEM_BUFFERABLE
arch/arm/include/asm/delay.h +0 -1
@@ -91,7 +91,6 @@ extern void __loop_udelay(unsigned long
 extern void __loop_const_udelay(unsigned long);
 
 /* Delay-loop timer registration. */
-#define ARCH_HAS_READ_CURRENT_TIMER
 extern void register_current_timer_delay(const struct delay_timer *timer);
 
 #endif /* __ASSEMBLY__ */
arch/arm/include/asm/timex.h +4 -1
@@ -10,7 +10,10 @@
 #define _ASMARM_TIMEX_H
 
 typedef unsigned long cycles_t;
-#define get_cycles()	({ cycles_t c; read_current_timer(&c) ? 0 : c; })
+// Temporary workaround
+bool delay_read_timer(unsigned long *t);
+
+#define get_cycles()	({ cycles_t c; delay_read_timer(&c) ? 0 : c; })
 #define random_get_entropy() (((unsigned long)get_cycles()) ?: random_get_entropy_fallback())
 
 #endif
arch/arm/lib/delay.c +4 -6
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/timex.h>
 
 /*
  * Default to the loop-based delay implementation.
@@ -27,15 +26,14 @@ static const struct delay_timer *delay_t
 static bool delay_calibrated;
 static u64 delay_res;
 
-int read_current_timer(unsigned long *timer_val)
+bool delay_read_timer(unsigned long *timer_val)
 {
 	if (!delay_timer)
-		return -ENXIO;
-
+		return false;
 	*timer_val = delay_timer->read_current_timer();
-	return 0;
+	return true;
 }
-EXPORT_SYMBOL_GPL(read_current_timer);
+EXPORT_SYMBOL_GPL(delay_read_timer);
 
 static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
 {
arch/hexagon/Kconfig +1 -0
@@ -5,6 +5,7 @@ comment "Linux Kernel Configuration for
 config HEXAGON
 	def_bool y
 	select ARCH_32BIT_OFF_T
+	select ARCH_HAS_DELAY_TIMER
 	select ARCH_HAS_SYNC_DMA_FOR_DEVICE
 	select ARCH_NO_PREEMPT
 	select ARCH_WANT_FRAME_POINTERS
arch/hexagon/include/asm/timex.h deleted +0 -20
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- */
-
-#ifndef _ASM_TIMEX_H
-#define _ASM_TIMEX_H
-
-#include <asm-generic/timex.h>
-#include <asm/hexagon_vm.h>
-
-#define ARCH_HAS_READ_CURRENT_TIMER
-
-static inline int read_current_timer(unsigned long *timer_val)
-{
-	*timer_val = __vmgettime();
-	return 0;
-}
-
-#endif
arch/hexagon/kernel/time.c +7 -1
@@ -6,6 +6,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <linux/clockchips.h>
 #include <linux/clocksource.h>
 #include <linux/interrupt.h>
@@ -17,7 +18,6 @@
 #include <linux/of_irq.h>
 #include <linux/module.h>
 
-#include <asm/delay.h>
 #include <asm/hexagon_vm.h>
 #include <asm/time.h>
 
@@ -231,3 +231,9 @@ void __udelay(unsigned long usecs)
 		cpu_relax(); /*  not sure how this improves readability  */
 }
 EXPORT_SYMBOL(__udelay);
+
+bool delay_read_timer(unsigned long *timer_val)
+{
+	*timer_val = __vmgettime();
+	return true;
+}
arch/openrisc/Kconfig +1 -0
@@ -7,6 +7,7 @@
 config OPENRISC
 	def_bool y
 	select ARCH_32BIT_OFF_T
+	select ARCH_HAS_DELAY_TIMER
 	select ARCH_HAS_DMA_SET_UNCACHED
 	select ARCH_HAS_DMA_CLEAR_UNCACHED
 	select ARCH_HAS_SYNC_DMA_FOR_DEVICE
arch/openrisc/include/asm/timex.h +0 -2
@@ -25,6 +25,4 @@ static inline cycles_t get_cycles(void)
 }
 #define get_cycles get_cycles
 
-#define ARCH_HAS_READ_CURRENT_TIMER
-
 #endif
arch/openrisc/lib/delay.c +4 -5
@@ -13,18 +13,17 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/init.h>
-#include <linux/timex.h>
+
 #include <asm/param.h>
-#include <asm/delay.h>
-#include <asm/timex.h>
 #include <asm/processor.h>
 
-int read_current_timer(unsigned long *timer_value)
+bool delay_read_timer(unsigned long *timer_value)
 {
 	*timer_value = get_cycles();
-	return 0;
+	return true;
 }
 
 void __delay(unsigned long cycles)
arch/riscv/Kconfig +1 -0
@@ -29,6 +29,7 @@ config RISCV
 	select ARCH_HAS_DEBUG_VIRTUAL if MMU
 	select ARCH_HAS_DEBUG_VM_PGTABLE
 	select ARCH_HAS_DEBUG_WX
+	select ARCH_HAS_DELAY_TIMER
 	select ARCH_HAS_ELF_CORE_EFLAGS if BINFMT_ELF && ELF_CORE
 	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_FORTIFY_SOURCE
arch/riscv/include/asm/timex.h +0 -8
@@ -80,12 +80,4 @@ static inline u64 get_cycles64(void)
 	return ((u64)hi << 32) | lo;
 }
 #endif /* CONFIG_64BIT */
-
-#define ARCH_HAS_READ_CURRENT_TIMER
-static inline int read_current_timer(unsigned long *timer_val)
-{
-	*timer_val = get_cycles();
-	return 0;
-}
-
 #endif /* _ASM_RISCV_TIMEX_H */
arch/riscv/lib/delay.c +6 -1
@@ -6,7 +6,6 @@
 #include <linux/delay.h>
 #include <linux/math.h>
 #include <linux/param.h>
-#include <linux/timex.h>
 #include <linux/types.h>
 #include <linux/export.h>
 
@@ -109,3 +108,9 @@ void ndelay(unsigned long nsecs)
 	__delay(ncycles >> NDELAY_SHIFT);
 }
 EXPORT_SYMBOL(ndelay);
+
+bool delay_read_timer(unsigned long *timer_val)
+{
+	*timer_val = get_cycles();
+	return true;
+}
arch/sparc/Kconfig +1 -0
@@ -70,6 +70,7 @@ config SPARC32
 config SPARC64
 	def_bool 64BIT
 	select ALTERNATE_USER_ADDRESS_SPACE
+	select ARCH_HAS_DELAY_TIMER
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_KRETPROBES
arch/sparc/include/asm/timex_64.h +0 -2
@@ -13,6 +13,4 @@
 typedef unsigned long cycles_t;
 #define get_cycles()	tick_ops->get_tick()
 
-#define ARCH_HAS_READ_CURRENT_TIMER
-
 #endif
arch/sparc/kernel/time_64.c +2 -2
@@ -894,8 +894,8 @@ unsigned long long sched_clock(void)
 	return ((get_tick() * quotient) >> SPARC64_NSEC_PER_CYC_SHIFT) - offset;
 }
 
-int read_current_timer(unsigned long *timer_val)
+bool delay_read_timer(unsigned long *timer_val)
 {
 	*timer_val = get_tick();
-	return 0;
+	return true;
 }
arch/x86/Kconfig +1 -0
@@ -81,6 +81,7 @@ config X86
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DEBUG_VIRTUAL
 	select ARCH_HAS_DEBUG_VM_PGTABLE	if !X86_PAE
+	select ARCH_HAS_DELAY_TIMER
 	select ARCH_HAS_DEVMEM_IS_ALLOWED
 	select ARCH_HAS_DMA_OPS			if GART_IOMMU || XEN
 	select ARCH_HAS_EARLY_DEBUG		if KGDB
arch/x86/include/asm/timex.h +0 -2
@@ -14,6 +14,4 @@ static inline unsigned long random_get_e
 }
 #define random_get_entropy random_get_entropy
 
-#define ARCH_HAS_READ_CURRENT_TIMER
-
 #endif /* _ASM_X86_TIMEX_H */
arch/x86/lib/delay.c +3 -5
@@ -14,12 +14,10 @@
 
 #include <linux/export.h>
 #include <linux/sched.h>
-#include <linux/timex.h>
 #include <linux/preempt.h>
 #include <linux/delay.h>
 
 #include <asm/processor.h>
-#include <asm/delay.h>
 #include <asm/timer.h>
 #include <asm/mwait.h>
 
@@ -189,13 +187,13 @@ void use_mwaitx_delay(void)
 	delay_fn = delay_halt;
 }
 
-int read_current_timer(unsigned long *timer_val)
+bool delay_read_timer(unsigned long *timer_val)
 {
 	if (delay_fn == delay_tsc) {
 		*timer_val = rdtsc();
-		return 0;
+		return true;
 	}
-	return -1;
+	return false;
 }
 
 void __delay(unsigned long loops)
include/asm-generic/timex.h +0 -7
@@ -13,11 +13,4 @@ static inline cycles_t get_cycles(void)
 }
 #endif
 
-/*
- * Architectures are encouraged to implement read_current_timer
- * and define this in order to avoid the expensive delay loop
- * calibration during boot.
- */
-#undef ARCH_HAS_READ_CURRENT_TIMER
-
 #endif /* __ASM_GENERIC_TIMEX_H */
include/linux/delay.h +2 -0
@@ -17,6 +17,8 @@ extern unsigned long loops_per_jiffy;
 
 #include <asm/delay.h>
 
+bool delay_read_timer(unsigned long *t);
+
 /*
  * Using udelay() for intervals greater than a few milliseconds can
  * risk overflow for high loops_per_jiffy (high bogomips) machines. The
include/linux/timex.h +0 -2
@@ -156,8 +156,6 @@ extern int do_clock_adjtime(const clocki
 
 extern void hardpps(const struct timespec64 *, const struct timespec64 *);
 
-int read_current_timer(unsigned long *timer_val);
-
 /* The clock frequency of the i8253/i8254 PIT */
 #define PIT_TICK_RATE 1193182ul
 
init/calibrate.c +9 -10
@@ -13,7 +13,6 @@
 #include <linux/printk.h>
 #include <linux/smp.h>
 #include <linux/stddef.h>
-#include <linux/timex.h>
 
 unsigned long lpj_fine;
 unsigned long preset_lpj;
@@ -25,9 +24,9 @@ static int __init lpj_setup(char *str)
 
 __setup("lpj=", lpj_setup);
 
-#ifdef ARCH_HAS_READ_CURRENT_TIMER
+#ifdef CONFIG_ARCH_HAS_DELAY_TIMER
 
-/* This routine uses the read_current_timer() routine and gets the
+/* This routine uses the delay_read_timer() routine and gets the
  * loops per jiffy directly, instead of guessing it using delay().
  * Also, this code tries to handle non-maskable asynchronous events
  * (like SMIs)
@@ -48,13 +47,13 @@ static unsigned long calibrate_delay_dir
 	int min = -1;
 	int i;
 
-	if (read_current_timer(&pre_start) < 0 )
+	if (!delay_read_timer(&pre_start))
 		return 0;
 
 	/*
 	 * A simple loop like
 	 *	while ( jiffies < start_jiffies+1)
-	 *		start = read_current_timer();
+	 *		start = delay_read_timer();
 	 * will not do. As we don't really know whether jiffy switch
 	 * happened first or timer_value was read first. And some asynchronous
 	 * event can happen between these two events introducing errors in lpj.
@@ -72,22 +71,22 @@ static unsigned long calibrate_delay_dir
 
 	for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
 		pre_start = 0;
-		read_current_timer(&start);
+		delay_read_timer(&start);
 		start_jiffies = jiffies;
 		while (time_before_eq(jiffies, start_jiffies + 1)) {
 			pre_start = start;
-			read_current_timer(&start);
+			delay_read_timer(&start);
 		}
-		read_current_timer(&post_start);
+		delay_read_timer(&post_start);
 
 		pre_end = 0;
 		end = post_start;
 		while (time_before_eq(jiffies, start_jiffies + 1 +
 					       DELAY_CALIBRATION_TICKS)) {
 			pre_end = end;
-			read_current_timer(&end);
+			delay_read_timer(&end);
 		}
-		read_current_timer(&post_end);
+		delay_read_timer(&post_end);
 
 		timer_rate_max = (post_end - pre_start) /
 					DELAY_CALIBRATION_TICKS;
maintainer
#10 lore raw

Re: [patch 06/38] calibrate: Rework delay timer calibration

Hi Thomas,

Quoted 14 lines · Thomas Gleixner

The header define in asm/timex,h and the naming of the function to read the delay timer are confusing at best.

Convert it to a config switch selected by the archictures, which provide the functionality, and rename the function to delay_read_timer(), which makes the purpose clear. Move the declaration to linux/delay.h where it belongs.

Remove the resulting empty asm/timex.h files as well.

No functional change.

...

arch/arm/include/asm/timex.h line 17

Quoted 12 lines
arch/arm/include/asm/timex.h +4 -1
@@ -10,7 +10,10 @@
  #define _ASMARM_TIMEX_H
 
  typedef unsigned long cycles_t;
-#define get_cycles()	({ cycles_t c; read_current_timer(&c) ? 0 : c; })
+// Temporary workaround
+bool delay_read_timer(unsigned long *t);
+
+#define get_cycles()	({ cycles_t c; delay_read_timer(&c) ? 0 : c; })
  #define random_get_entropy() (((unsigned long)get_cycles()) ?: random_get_entropy_fallback())

I have noticed a boot regression on some of our 32-bit Tegra platforms. Bisect is pointing to this commit. Making the following change does fix it, as delay_read_timer() now returns a valid value when true ...

arch/arm/include/asm/timex.h +1 -1
index 94e40c19cfc5..4d31eab9dba2 100644
@@ -13,7 +13,7 @@ typedef unsigned long cycles_t;
 // Temporary workaround until timex.h is cleaned up
 bool delay_read_timer(unsigned long *t);
 
-#define get_cycles()   ({ cycles_t c; delay_read_timer(&c) ? 0 : c; })
+#define get_cycles()   ({ cycles_t c; delay_read_timer(&c) ? c : 0; })
 #define random_get_entropy() (((unsigned long)get_cycles()) ?: 

random_get_entropy_fallback())

Cheers
Jon

Signature · 1 line
nvpublic
author maintainer
#11 lore raw

PATCH 7/38 treewide: Consolidate cycles_t

In reply to Thomas Gleixner

Most architectures define cycles_t as unsigned long execpt:

- x86 requires it to be 64-bit independent of the 32-bit/64-bit build.

- parisc and mips define it as unsigned int

parisc has no real reason to do so as there are only a few usage sites which either expand it to a 64-bit value or utilize only the lower 32bits.

mips has no real requirement either.

Move the typedef to types.h and provide a config switch to enforce the 64-bit type for x86.

---
 arch/Kconfig                       |    4 ++++
 arch/alpha/include/asm/timex.h     |    3 ---
 arch/arm/include/asm/timex.h       |    1 -
 arch/loongarch/include/asm/timex.h |    2 --
 arch/m68k/include/asm/timex.h      |    2 --
 arch/mips/include/asm/timex.h      |    2 --
 arch/nios2/include/asm/timex.h     |    2 --
 arch/parisc/include/asm/timex.h    |    2 --
 arch/powerpc/include/asm/timex.h   |    4 +---
 arch/riscv/include/asm/timex.h     |    2 --
 arch/s390/include/asm/timex.h      |    2 --
 arch/sparc/include/asm/timex_64.h  |    1 -
 arch/x86/Kconfig                   |    1 +
 arch/x86/include/asm/tsc.h         |    2 --
 include/asm-generic/timex.h        |    1 -
 include/linux/types.h              |    6 ++++++
 16 files changed, 12 insertions(+), 25 deletions(-)
arch/Kconfig +4 -0
@@ -360,6 +360,10 @@ config ARCH_HAS_DMA_SET_UNCACHED
 config ARCH_HAS_DMA_CLEAR_UNCACHED
 	bool
 
+# cycles_t is always 64bit wide
+config ARCH_HAS_CYCLES_T_64
+	bool
+
 config ARCH_HAS_CPU_FINALIZE_INIT
 	bool
 
arch/alpha/include/asm/timex.h +0 -3
@@ -15,9 +15,6 @@
  * But this only means we'll force a reschedule every 8 seconds or so,
  * which isn't an evil thing.
  */
-
-typedef unsigned int cycles_t;
-
 static inline cycles_t get_cycles (void)
 {
 	cycles_t ret;
arch/arm/include/asm/timex.h +0 -1
@@ -9,7 +9,6 @@
 #ifndef _ASMARM_TIMEX_H
 #define _ASMARM_TIMEX_H
 
-typedef unsigned long cycles_t;
 // Temporary workaround
 bool delay_read_timer(unsigned long *t);
 
arch/loongarch/include/asm/timex.h +0 -2
@@ -12,8 +12,6 @@
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
 
-typedef unsigned long cycles_t;
-
 #define get_cycles get_cycles
 
 static inline cycles_t get_cycles(void)
arch/m68k/include/asm/timex.h +0 -2
@@ -7,8 +7,6 @@
 #ifndef _ASMm68K_TIMEX_H
 #define _ASMm68K_TIMEX_H
 
-typedef unsigned long cycles_t;
-
 static inline cycles_t get_cycles(void)
 {
 	return 0;
arch/mips/include/asm/timex.h +0 -2
@@ -29,8 +29,6 @@
  * We know that all SMP capable CPUs have cycle counters.
  */
 
-typedef unsigned int cycles_t;
-
 /*
  * On R4000/R4400 an erratum exists such that if the cycle counter is
  * read in the exact moment that it is matching the compare register,
arch/nios2/include/asm/timex.h +0 -2
@@ -5,8 +5,6 @@
 #ifndef _ASM_NIOS2_TIMEX_H
 #define _ASM_NIOS2_TIMEX_H
 
-typedef unsigned long cycles_t;
-
 extern cycles_t get_cycles(void);
 #define get_cycles get_cycles
 
arch/parisc/include/asm/timex.h +0 -2
@@ -9,8 +9,6 @@
 
 #include <asm/special_insns.h>
 
-typedef unsigned long cycles_t;
-
 static inline cycles_t get_cycles(void)
 {
 	return mfctl(16);
arch/powerpc/include/asm/timex.h +1 -3
@@ -11,9 +11,7 @@
 #include <asm/cputable.h>
 #include <asm/vdso/timebase.h>
 
-typedef unsigned long cycles_t;
-
-static inline cycles_t get_cycles(void)
+ostatic inline cycles_t get_cycles(void)
 {
 	return mftb();
 }
arch/riscv/include/asm/timex.h +0 -2
@@ -8,8 +8,6 @@
 
 #include <asm/csr.h>
 
-typedef unsigned long cycles_t;
-
 #ifdef CONFIG_RISCV_M_MODE
 
 #include <asm/clint.h>
arch/s390/include/asm/timex.h +0 -2
@@ -177,8 +177,6 @@ static inline void local_tick_enable(uns
 	set_clock_comparator(get_lowcore()->clock_comparator);
 }
 
-typedef unsigned long cycles_t;
-
 static __always_inline unsigned long get_tod_clock(void)
 {
 	union tod_clock clk;
arch/sparc/include/asm/timex_64.h +0 -1
@@ -10,7 +10,6 @@
 #include <asm/timer.h>
 
 /* Getting on the cycle counter on sparc64. */
-typedef unsigned long cycles_t;
 #define get_cycles()	tick_ops->get_tick()
 
 #endif
arch/x86/Kconfig +1 -0
@@ -79,6 +79,7 @@ config X86
 	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_HAS_CPU_PASID		if IOMMU_SVA
 	select ARCH_HAS_CURRENT_STACK_POINTER
+	select ARCH_HAS_CYCLES_T_64
 	select ARCH_HAS_DEBUG_VIRTUAL
 	select ARCH_HAS_DEBUG_VM_PGTABLE	if !X86_PAE
 	select ARCH_HAS_DELAY_TIMER
arch/x86/include/asm/tsc.h +0 -2
@@ -67,8 +67,6 @@ static __always_inline u64 rdtsc_ordered
 /*
  * Standard way to access the cycle counter.
  */
-typedef unsigned long long cycles_t;
-
 extern unsigned int cpu_khz;
 extern unsigned int tsc_khz;
 
include/asm-generic/timex.h +0 -1
@@ -5,7 +5,6 @@
 /*
  * If you have a cycle counter, return the value here.
  */
-typedef unsigned long cycles_t;
 #ifndef get_cycles
 static inline cycles_t get_cycles(void)
 {
include/linux/types.h +6 -0
@@ -270,5 +270,11 @@ struct rcuwait {
 	struct task_struct __rcu *task;
 };
 
+#ifdef CONFIG_ARCH_HAS_CYCLES_T_64
+typedef unsigned long long	cycles_t;
+#else
+typedef unsigned long		cycles_t;
+#endif
+
 #endif /*  __ASSEMBLY__ */
 #endif /* _LINUX_TYPES_H */
reviewer
#12 lore raw

Re: [patch 07/38] treewide: Consolidate cycles_t

Quoted 35 lines · Thomas Gleixner

Most architectures define cycles_t as unsigned long execpt:

- x86 requires it to be 64-bit independent of the 32-bit/64-bit build.

- parisc and mips define it as unsigned int

parisc has no real reason to do so as there are only a few usage sites which either expand it to a 64-bit value or utilize only the lower 32bits.

mips has no real requirement either.

Move the typedef to types.h and provide a config switch to enforce the 64-bit type for x86.

---
 arch/Kconfig                       |    4 ++++
 arch/alpha/include/asm/timex.h     |    3 ---
 arch/arm/include/asm/timex.h       |    1 -
 arch/loongarch/include/asm/timex.h |    2 --
 arch/m68k/include/asm/timex.h      |    2 --
 arch/mips/include/asm/timex.h      |    2 --
 arch/nios2/include/asm/timex.h     |    2 --
 arch/parisc/include/asm/timex.h    |    2 --
 arch/powerpc/include/asm/timex.h   |    4 +---
 arch/riscv/include/asm/timex.h     |    2 --
 arch/s390/include/asm/timex.h      |    2 --
 arch/sparc/include/asm/timex_64.h  |    1 -
 arch/x86/Kconfig                   |    1 +
 arch/x86/include/asm/tsc.h         |    2 --
 include/asm-generic/timex.h        |    1 -
 include/linux/types.h              |    6 ++++++
 16 files changed, 12 insertions(+), 25 deletions(-)

<...>

arch/powerpc/include/asm/timex.h line 14

Quoted 10 lines
arch/powerpc/include/asm/timex.h +1 -3
@@ -11,9 +11,7 @@
 #include <asm/cputable.h>
 #include <asm/vdso/timebase.h>
 
-typedef unsigned long cycles_t;
-
-static inline cycles_t get_cycles(void)
+ostatic inline cycles_t get_cycles(void)

Hi Thomas, I'm in middle of testing this series on powerpc. In the meantime I noticed that there's probably a small typo here (althrough this is fixed later)

Regards,
ojaswin

Quoted 3 lines
arch/powerpc/include/asm/timex.h +0 -0
 {
 	return mftb();
 }
#13 lore raw

Re: [patch 07/38] treewide: Consolidate cycles_t

In reply to Thomas Gleixner

Le 10/04/2026 à 14:19, Thomas Gleixner a écrit :

Quoted 38 lines

Most architectures define cycles_t as unsigned long execpt:

- x86 requires it to be 64-bit independent of the 32-bit/64-bit build.

- parisc and mips define it as unsigned int

parisc has no real reason to do so as there are only a few usage sites which either expand it to a 64-bit value or utilize only the lower 32bits.

mips has no real requirement either.

Move the typedef to types.h and provide a config switch to enforce the 64-bit type for x86.

---
  arch/Kconfig                       |    4 ++++
  arch/alpha/include/asm/timex.h     |    3 ---
  arch/arm/include/asm/timex.h       |    1 -
  arch/loongarch/include/asm/timex.h |    2 --
  arch/m68k/include/asm/timex.h      |    2 --
  arch/mips/include/asm/timex.h      |    2 --
  arch/nios2/include/asm/timex.h     |    2 --
  arch/parisc/include/asm/timex.h    |    2 --
  arch/powerpc/include/asm/timex.h   |    4 +---
  arch/riscv/include/asm/timex.h     |    2 --
  arch/s390/include/asm/timex.h      |    2 --
  arch/sparc/include/asm/timex_64.h  |    1 -
  arch/x86/Kconfig                   |    1 +
  arch/x86/include/asm/tsc.h         |    2 --
  include/asm-generic/timex.h        |    1 -
  include/linux/types.h              |    6 ++++++
  16 files changed, 12 insertions(+), 25 deletions(-)

arch/powerpc/include/asm/timex.h line 14

Quoted 7 lines
arch/powerpc/include/asm/timex.h +1 -3
@@ -11,9 +11,7 @@
  #include <asm/cputable.h>
  #include <asm/vdso/timebase.h>
 
-typedef unsigned long cycles_t;
-
-static inline cycles_t get_cycles(void)
+ostatic inline cycles_t get_cycles(void)

What is 'ostatic' ?

Quoted 3 lines
arch/powerpc/include/asm/timex.h +0 -0
  {
  	return mftb();
  }
author maintainer
#14 lore raw

Re: [patch 07/38] treewide: Consolidate cycles_t

Quoted 6 lines · Christophe Leroy

arch/powerpc/include/asm/timex.h line 14

Quoted 4 lines
arch/powerpc/include/asm/timex.h +1 -3
-typedef unsigned long cycles_t;
-
-static inline cycles_t get_cycles(void)
+ostatic inline cycles_t get_cycles(void)

What is 'ostatic' ?

That's a really good question :)

maintainer Acked-by on v1 7/38
#15 lore raw

Re: [patch 07/38] treewide: Consolidate cycles_t

In reply to Thomas Gleixner
Quoted 10 lines · Thomas Gleixner

Most architectures define cycles_t as unsigned long execpt:

- x86 requires it to be 64-bit independent of the 32-bit/64-bit build.

- parisc and mips define it as unsigned int

parisc has no real reason to do so as there are only a few usage sites which either expand it to a 64-bit value or utilize only the lower 32bits.

Quoted 8 lines

mips has no real requirement either.

Move the typedef to types.h and provide a config switch to enforce the 64-bit type for x86.

 arch/m68k/include/asm/timex.h      |    2 --

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

author maintainer
#16 lore raw

PATCH 8/38 x86/tsc: Use rdtsc() instead of get_cycles()

In reply to Thomas Gleixner

This code knows that TSC is available so there is no point to use the TSC feature guarded get_cycles().

No functional change.

---
 arch/x86/kernel/tsc.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
arch/x86/kernel/tsc.c +6 -6
@@ -371,12 +371,12 @@ static u64 tsc_read_refs(u64 *p, int hpe
 	int i;
 
 	for (i = 0; i < MAX_RETRIES; i++) {
-		t1 = get_cycles();
+		t1 = rdtsc();
 		if (hpet)
 			*p = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
 		else
 			*p = acpi_pm_read_early();
-		t2 = get_cycles();
+		t2 = rdtsc();
 		if ((t2 - t1) < thresh)
 			return t2;
 	}
@@ -468,13 +468,13 @@ static unsigned long pit_calibrate_tsc(u
 	outb(latch & 0xff, 0x42);
 	outb(latch >> 8, 0x42);
 
-	tsc = t1 = t2 = get_cycles();
+	tsc = t1 = t2 = rdtsc();
 
 	pitcnt = 0;
 	tscmax = 0;
 	tscmin = ULONG_MAX;
 	while ((inb(0x61) & 0x20) == 0) {
-		t2 = get_cycles();
+		t2 = rdtsc();
 		delta = t2 - tsc;
 		tsc = t2;
 		if ((unsigned long) delta < tscmin)
@@ -553,9 +553,9 @@ static inline int pit_expect_msb(unsigne
 		if (!pit_verify_msb(val))
 			break;
 		prev_tsc = tsc;
-		tsc = get_cycles();
+		tsc = rdtsc();
 	}
-	*deltap = get_cycles() - prev_tsc;
+	*deltap = rdtsc() - prev_tsc;
 	*tscp = tsc;
 
 	/*
author maintainer
#17 lore raw

PATCH 9/38 iommu/vt-d: Use sched_clock() instead of get_cycles()

In reply to Thomas Gleixner

Calculating the timeout from get_cycles() is a historical leftover without any functional requirement.

Use ktime_get() instead.

---
 arch/x86/include/asm/iommu.h |    3 ---
 drivers/iommu/intel/dmar.c   |    4 ++--
 drivers/iommu/intel/iommu.h  |    8 ++++++--
 3 files changed, 8 insertions(+), 7 deletions(-)
arch/x86/include/asm/iommu.h +0 -3
@@ -18,9 +18,6 @@ extern bool x86_swiotlb_enable;
 #define x86_swiotlb_enable false
 #endif
 
-/* 10 seconds */
-#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
-
 static inline int __init
 arch_rmrr_sanity_check(struct acpi_dmar_reserved_memory *rmrr)
 {
drivers/iommu/intel/dmar.c +2 -2
@@ -1606,9 +1606,9 @@ void qi_flush_pasid_cache(struct intel_i
  */
 void dmar_disable_qi(struct intel_iommu *iommu)
 {
+	ktime_t start_time = ktime_get();
 	unsigned long flags;
 	u32 sts;
-	cycles_t start_time = get_cycles();
 
 	if (!ecap_qis(iommu->ecap))
 		return;
@@ -1624,7 +1624,7 @@ void dmar_disable_qi(struct intel_iommu
 	 */
 	while ((readl(iommu->reg + DMAR_IQT_REG) !=
 		readl(iommu->reg + DMAR_IQH_REG)) &&
-		(DMAR_OPERATION_TIMEOUT > (get_cycles() - start_time)))
+	       (DMAR_OPERATION_TIMEOUT > (ktime_get() - start_time)))
 		cpu_relax();
 
 	iommu->gcmd &= ~DMA_GCMD_QIE;
drivers/iommu/intel/iommu.h +6 -2
@@ -23,6 +23,7 @@
 #include <linux/xarray.h>
 #include <linux/perf_event.h>
 #include <linux/pci.h>
+#include <linux/timekeeping.h>
 #include <linux/generic_pt/iommu.h>
 
 #include <asm/iommu.h>
@@ -360,14 +361,17 @@
 /* PERFINTRSTS_REG */
 #define DMA_PERFINTRSTS_PIS	((u32)1)
 
+#define DMAR_OPERATION_TIMEOUT  (((ktime_t)10) * NSEC_PER_SEC)
+
 #define IOMMU_WAIT_OP(iommu, offset, op, cond, sts)			\
 do {									\
-	cycles_t start_time = get_cycles();				\
+	ktime_t start_time = ktime_get();				\
+									\
 	while (1) {							\
 		sts = op(iommu->reg + offset);				\
 		if (cond)						\
 			break;						\
-		if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
+		if (DMAR_OPERATION_TIMEOUT < (ktime_get() - start_time))\
 			panic("DMAR hardware is malfunctioning\n");	\
 		cpu_relax();						\
 	}								\
maintainer Reviewed-by on v1 9/38
#18 lore raw

Re: [patch 09/38] iommu/vt-d: Use sched_clock() instead of get_cycles()

Quoted 4 lines · Thomas Gleixner

Calculating the timeout from get_cycles() is a historical leftover without any functional requirement.

Use ktime_get() instead.

The subject line says "Use sched_clock() ...", but the implementation actually uses ktime_get(). Is it a typo or anything I misunderstood?

Other parts look good to me,

Quoted 10 lines
---
  arch/x86/include/asm/iommu.h |    3 ---
  drivers/iommu/intel/dmar.c   |    4 ++--
  drivers/iommu/intel/iommu.h  |    8 ++++++--
  3 files changed, 8 insertions(+), 7 deletions(-)

Thanks,
baolu

author maintainer
#19 lore raw

Re: [patch 09/38] iommu/vt-d: Use sched_clock() instead of get_cycles()

Quoted 8 lines · Baolu Lu
Quoted 4 lines · Thomas Gleixner

Calculating the timeout from get_cycles() is a historical leftover without any functional requirement.

Use ktime_get() instead.

The subject line says "Use sched_clock() ...", but the implementation actually uses ktime_get(). Is it a typo or anything I misunderstood?

Indeed. Leftover from an earlier version.

Thanks,

tglx

author maintainer
#20 lore raw

PATCH 10/38 arcnet: Remove function timing code

In reply to Thomas Gleixner

ARCNET is a museums piece and the function timing can be done with ftrace. Remove the cruft.

---
 drivers/net/arcnet/arc-rimi.c  |    4 ++--
 drivers/net/arcnet/arcdevice.h |   20 +-------------------
 drivers/net/arcnet/com20020.c  |    6 ++----
 drivers/net/arcnet/com90io.c   |    6 ++----
 drivers/net/arcnet/com90xx.c   |    4 ++--
 5 files changed, 9 insertions(+), 31 deletions(-)
drivers/net/arcnet/arc-rimi.c +2 -2
@@ -291,7 +291,7 @@ static void arcrimi_copy_to_card(struct
 	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
 
-	TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count));
+	memcpy_toio(memaddr, buf, count);
 }
 
 static void arcrimi_copy_from_card(struct net_device *dev, int bufnum,
@@ -300,7 +300,7 @@ static void arcrimi_copy_from_card(struc
 	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
 
-	TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
+	memcpy_fromio(buf, memaddr, count);
 }
 
 static int node;
drivers/net/arcnet/arcdevice.h +1 -19
@@ -11,7 +11,6 @@
 #ifndef _LINUX_ARCDEVICE_H
 #define _LINUX_ARCDEVICE_H
 
-#include <asm/timex.h>
 #include <linux/if_arcnet.h>
 
 #ifdef __KERNEL__
@@ -62,7 +61,7 @@
 #define D_RX		512	/* show rx packets                        */
 #define D_SKB		1024	/* show skb's                             */
 #define D_SKB_SIZE	2048	/* show skb sizes			  */
-#define D_TIMING	4096	/* show time needed to copy buffers to card */
+#define D_TIMING	4096	/* Not longer supported. Use tracing instead */
 #define D_DEBUG         8192    /* Very detailed debug line for line */
 
 #ifndef ARCNET_DEBUG_MAX
@@ -95,23 +94,6 @@ do {									\
 		pr_cont(fmt, ##__VA_ARGS__);				\
 } while (0)
 
-/* see how long a function call takes to run, expressed in CPU cycles */
-#define TIME(dev, name, bytes, call)					\
-do {									\
-	if (BUGLVL(D_TIMING)) {						\
-		unsigned long _x, _y;					\
-		_x = get_cycles();					\
-		call;							\
-		_y = get_cycles();					\
-		arc_printk(D_TIMING, dev,				\
-			   "%s: %d bytes in %lu cycles == %lu Kbytes/100Mcycle\n", \
-			   name, bytes, _y - _x,			\
-			   100000000 / 1024 * bytes / (_y - _x + 1));	\
-	} else {							\
-		call;							\
-	}								\
-} while (0)
-
 /*
  * Time needed to reset the card - in ms (milliseconds).  This works on my
  * SMC PC100.  I can't find a reference that tells me just how long I
drivers/net/arcnet/com20020.c +2 -4
@@ -70,8 +70,7 @@ static void com20020_copy_from_card(stru
 	arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
 
 	/* copy the data */
-	TIME(dev, "insb", count,
-	     arcnet_insb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));
+	arcnet_insb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count);
 }
 
 static void com20020_copy_to_card(struct net_device *dev, int bufnum,
@@ -84,8 +83,7 @@ static void com20020_copy_to_card(struct
 	arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
 
 	/* copy the data */
-	TIME(dev, "outsb", count,
-	     arcnet_outsb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));
+	arcnet_outsb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count);
 }
 
 /* Reset the card and check some basic stuff during the detection stage. */
drivers/net/arcnet/com90io.c +2 -4
@@ -332,15 +332,13 @@ static void com90io_setmask(struct net_d
 static void com90io_copy_to_card(struct net_device *dev, int bufnum,
 				 int offset, void *buf, int count)
 {
-	TIME(dev, "put_whole_buffer", count,
-	     put_whole_buffer(dev, bufnum * 512 + offset, count, buf));
+	put_whole_buffer(dev, bufnum * 512 + offset, count, buf);
 }
 
 static void com90io_copy_from_card(struct net_device *dev, int bufnum,
 				   int offset, void *buf, int count)
 {
-	TIME(dev, "get_whole_buffer", count,
-	     get_whole_buffer(dev, bufnum * 512 + offset, count, buf));
+	get_whole_buffer(dev, bufnum * 512 + offset, count, buf);
 }
 
 static int io;			/* use the insmod io= irq= shmem= options */
drivers/net/arcnet/com90xx.c +2 -2
@@ -633,7 +633,7 @@ static void com90xx_copy_to_card(struct
 	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
 
-	TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count));
+	memcpy_toio(memaddr, buf, count);
 }
 
 static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
@@ -642,7 +642,7 @@ static void com90xx_copy_from_card(struc
 	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
 
-	TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
+	memcpy_fromio(buf, memaddr, count);
 }
 
 MODULE_DESCRIPTION("ARCnet COM90xx normal chipset driver");
maintainer Acked-by on v1 10/38
#21 lore raw

Re: [patch 10/38] arcnet: Remove function timing code

Quoted 6 lines · Thomas Gleixner

ARCNET is a museums piece and the function timing can be done with ftrace. Remove the cruft.

Quoted 7 lines

---
 drivers/net/arcnet/arc-rimi.c  |    4 ++-- drivers/net/arcnet/arcdevice.h |   20 +------------------- drivers/net/arcnet/com20020.c  |    6 ++---- drivers/net/arcnet/com90io.c   |    6 ++---- drivers/net/arcnet/com90xx.c   |    4 ++--

 5 files changed, 9 insertions(+), 31 deletions(-)

By coincidence, I took the last of my ARCNET cards to the tip just this morning...

author maintainer
#22 lore raw

PATCH 11/38 misc: sgi-gru: Remove get_cycles() [ab]use

In reply to Thomas Gleixner

Calculating a timeout from get_cycles() is a historical leftover without any functional requirement.

Use ktime_get() instead.

---
 drivers/misc/sgi-gru/gruhandles.c   |   20 ++++++++------------
 drivers/misc/sgi-gru/grukservices.c |    3 ++-
 drivers/misc/sgi-gru/grutlbpurge.c  |    5 ++---
 3 files changed, 12 insertions(+), 16 deletions(-)
drivers/misc/sgi-gru/gruhandles.c +8 -12
@@ -6,26 +6,22 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/timekeeping.h>
 #include "gru.h"
 #include "grulib.h"
 #include "grutables.h"
 
-/* 10 sec */
 #include <linux/sync_core.h>
-#include <asm/tsc.h>
-#define GRU_OPERATION_TIMEOUT	((cycles_t) tsc_khz*10*1000)
-#define CLKS2NSEC(c)		((c) * 1000000 / tsc_khz)
+
+#define GRU_OPERATION_TIMEOUT_NSEC	(((ktime_t)10 * NSEC_PER_SEC))
 
 /* Extract the status field from a kernel handle */
 #define GET_MSEG_HANDLE_STATUS(h)	(((*(unsigned long *)(h)) >> 16) & 3)
 
 struct mcs_op_statistic mcs_op_statistics[mcsop_last];
 
-static void update_mcs_stats(enum mcs_op op, unsigned long clks)
+static void update_mcs_stats(enum mcs_op op, unsigned long nsec)
 {
-	unsigned long nsec;
-
-	nsec = CLKS2NSEC(clks);
 	atomic_long_inc(&mcs_op_statistics[op].count);
 	atomic_long_add(nsec, &mcs_op_statistics[op].total);
 	if (mcs_op_statistics[op].max < nsec)
@@ -58,21 +54,21 @@ static void report_instruction_timeout(v
 
 static int wait_instruction_complete(void *h, enum mcs_op opc)
 {
+	ktime_t start_time = ktime_get();
 	int status;
-	unsigned long start_time = get_cycles();
 
 	while (1) {
 		cpu_relax();
 		status = GET_MSEG_HANDLE_STATUS(h);
 		if (status != CCHSTATUS_ACTIVE)
 			break;
-		if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) {
+		if (GRU_OP_TIMEOUT_NSEC < (ktime_get() - start_time)) {
 			report_instruction_timeout(h);
-			start_time = get_cycles();
+			start_time = ktime_get();
 		}
 	}
 	if (gru_options & OPT_STATS)
-		update_mcs_stats(opc, get_cycles() - start_time);
+		update_mcs_stats(opc, (unsigned long)(ktime_get() - start_time));
 	return status;
 }
 
drivers/misc/sgi-gru/grukservices.c +2 -1
@@ -20,6 +20,7 @@
 #include <linux/uaccess.h>
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/random.h>
 #include <asm/io_apic.h>
 #include "gru.h"
 #include "grulib.h"
@@ -1106,7 +1107,7 @@ static int quicktest3(unsigned long arg)
 	int ret = 0;
 
 	memset(buf2, 0, sizeof(buf2));
-	memset(buf1, get_cycles() & 255, sizeof(buf1));
+	memset(buf1, get_random_u32() & 255, sizeof(buf1));
 	gru_copy_gpa(uv_gpa(buf2), uv_gpa(buf1), BUFSIZE);
 	if (memcmp(buf1, buf2, BUFSIZE)) {
 		printk(KERN_DEBUG "GRU:%d quicktest3 error\n", smp_processor_id());
drivers/misc/sgi-gru/grutlbpurge.c +2 -3
@@ -22,13 +22,12 @@
 #include <linux/delay.h>
 #include <linux/timex.h>
 #include <linux/srcu.h>
+#include <linux/random.h>
 #include <asm/processor.h>
 #include "gru.h"
 #include "grutables.h"
 #include <asm/uv/uv_hub.h>
 
-#define gru_random()	get_cycles()
-
 /* ---------------------------------- TLB Invalidation functions --------
  * get_tgh_handle
  *
@@ -49,7 +48,7 @@ static inline int get_off_blade_tgh(stru
 	int n;
 
 	n = GRU_NUM_TGH - gru->gs_tgh_first_remote;
-	n = gru_random() % n;
+	n = get_random_u32() % n;
 	n += gru->gs_tgh_first_remote;
 	return n;
 }
author maintainer
#23 lore raw

PATCH 11/38 misc: sgi-gru: Remove get_cycles() [ab]use

Calculating a timeout from get_cycles() is a historical leftover without any functional requirement.

Use ktime_get() instead.

---
V2: Fix typo

---
 drivers/misc/sgi-gru/gruhandles.c   |   20 ++++++++------------
 drivers/misc/sgi-gru/grukservices.c |    3 ++-
 drivers/misc/sgi-gru/grutlbpurge.c  |    5 ++---
 3 files changed, 12 insertions(+), 16 deletions(-)
drivers/misc/sgi-gru/gruhandles.c +8 -12
@@ -6,26 +6,22 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/timekeeping.h>
 #include "gru.h"
 #include "grulib.h"
 #include "grutables.h"
 
-/* 10 sec */
 #include <linux/sync_core.h>
-#include <asm/tsc.h>
-#define GRU_OPERATION_TIMEOUT	((cycles_t) tsc_khz*10*1000)
-#define CLKS2NSEC(c)		((c) * 1000000 / tsc_khz)
+
+#define GRU_OPERATION_TIMEOUT_NSEC	(((ktime_t)10 * NSEC_PER_SEC))
 
 /* Extract the status field from a kernel handle */
 #define GET_MSEG_HANDLE_STATUS(h)	(((*(unsigned long *)(h)) >> 16) & 3)
 
 struct mcs_op_statistic mcs_op_statistics[mcsop_last];
 
-static void update_mcs_stats(enum mcs_op op, unsigned long clks)
+static void update_mcs_stats(enum mcs_op op, unsigned long nsec)
 {
-	unsigned long nsec;
-
-	nsec = CLKS2NSEC(clks);
 	atomic_long_inc(&mcs_op_statistics[op].count);
 	atomic_long_add(nsec, &mcs_op_statistics[op].total);
 	if (mcs_op_statistics[op].max < nsec)
@@ -58,21 +54,21 @@ static void report_instruction_timeout(v
 
 static int wait_instruction_complete(void *h, enum mcs_op opc)
 {
+	ktime_t start_time = ktime_get();
 	int status;
-	unsigned long start_time = get_cycles();
 
 	while (1) {
 		cpu_relax();
 		status = GET_MSEG_HANDLE_STATUS(h);
 		if (status != CCHSTATUS_ACTIVE)
 			break;
-		if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) {
+		if (GRU_OPERATION_TIMEOUT_NSEC < (ktime_get() - start_time)) {
 			report_instruction_timeout(h);
-			start_time = get_cycles();
+			start_time = ktime_get();
 		}
 	}
 	if (gru_options & OPT_STATS)
-		update_mcs_stats(opc, get_cycles() - start_time);
+		update_mcs_stats(opc, (unsigned long)(ktime_get() - start_time));
 	return status;
 }
 
drivers/misc/sgi-gru/grukservices.c +2 -1
@@ -20,6 +20,7 @@
 #include <linux/uaccess.h>
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/random.h>
 #include <asm/io_apic.h>
 #include "gru.h"
 #include "grulib.h"
@@ -1106,7 +1107,7 @@ static int quicktest3(unsigned long arg)
 	int ret = 0;
 
 	memset(buf2, 0, sizeof(buf2));
-	memset(buf1, get_cycles() & 255, sizeof(buf1));
+	memset(buf1, get_random_u32() & 255, sizeof(buf1));
 	gru_copy_gpa(uv_gpa(buf2), uv_gpa(buf1), BUFSIZE);
 	if (memcmp(buf1, buf2, BUFSIZE)) {
 		printk(KERN_DEBUG "GRU:%d quicktest3 error\n", smp_processor_id());
drivers/misc/sgi-gru/grutlbpurge.c +2 -3
@@ -22,13 +22,12 @@
 #include <linux/delay.h>
 #include <linux/timex.h>
 #include <linux/srcu.h>
+#include <linux/random.h>
 #include <asm/processor.h>
 #include "gru.h"
 #include "grutables.h"
 #include <asm/uv/uv_hub.h>
 
-#define gru_random()	get_cycles()
-
 /* ---------------------------------- TLB Invalidation functions --------
  * get_tgh_handle
  *
@@ -49,7 +48,7 @@ static inline int get_off_blade_tgh(stru
 	int n;
 
 	n = GRU_NUM_TGH - gru->gs_tgh_first_remote;
-	n = gru_random() % n;
+	n = get_random_u32() % n;
 	n += gru->gs_tgh_first_remote;
 	return n;
 }
author maintainer
#24 lore raw

PATCH 12/38 wifi: wil6210: Replace get_cyles() usage

In reply to Thomas Gleixner

There is no reason why this debug code requires to use get_cycles() for timing purposes.

Use ktime_get() instead.

---
 drivers/net/wireless/ath/wil6210/debugfs.c   |    2 +-
 drivers/net/wireless/ath/wil6210/txrx.c      |    6 +++---
 drivers/net/wireless/ath/wil6210/txrx_edma.c |    4 ++--
 drivers/net/wireless/ath/wil6210/wil6210.h   |    3 ++-
 4 files changed, 8 insertions(+), 7 deletions(-)
drivers/net/wireless/ath/wil6210/debugfs.c +1 -1
@@ -151,7 +151,7 @@ static int ring_show(struct seq_file *s,
 			char name[10];
 			char sidle[10];
 			/* performance monitoring */
-			cycles_t now = get_cycles();
+			ktime_t now = ktime_get();
 			uint64_t idle = txdata->idle * 100;
 			uint64_t total = now - txdata->begin;
 
drivers/net/wireless/ath/wil6210/txrx.c +3 -3
@@ -1976,7 +1976,7 @@ static int __wil_tx_vring_tso(struct wil
 	used = wil_ring_used_tx(vring);
 	if (wil_val_in_range(wil->ring_idle_trsh,
 			     used, used + descs_used)) {
-		txdata->idle += get_cycles() - txdata->last_idle;
+		txdata->idle += ktime_get() - txdata->last_idle;
 		wil_dbg_txrx(wil,  "Ring[%2d] not idle %d -> %d\n",
 			     vring_index, used, used + descs_used);
 	}
@@ -2129,7 +2129,7 @@ static int __wil_tx_ring(struct wil6210_
 	used = wil_ring_used_tx(ring);
 	if (wil_val_in_range(wil->ring_idle_trsh,
 			     used, used + nr_frags + 1)) {
-		txdata->idle += get_cycles() - txdata->last_idle;
+		txdata->idle += ktime_get() - txdata->last_idle;
 		wil_dbg_txrx(wil,  "Ring[%2d] not idle %d -> %d\n",
 			     ring_index, used, used + nr_frags + 1);
 	}
@@ -2531,7 +2531,7 @@ int wil_tx_complete(struct wil6210_vif *
 			     used_new, used_before_complete)) {
 		wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n",
 			     ringid, used_before_complete, used_new);
-		txdata->last_idle = get_cycles();
+		txdata->last_idle = ktime_get();
 	}
 
 	/* shall we wake net queues? */
drivers/net/wireless/ath/wil6210/txrx_edma.c +2 -2
@@ -1286,7 +1286,7 @@ int wil_tx_sring_handler(struct wil6210_
 				     used_new, used_before_complete)) {
 			wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n",
 				     ring_id, used_before_complete, used_new);
-			txdata->last_idle = get_cycles();
+			txdata->last_idle = ktime_get();
 		}
 
 again:
@@ -1499,7 +1499,7 @@ static int __wil_tx_ring_tso_edma(struct
 	used = wil_ring_used_tx(ring);
 	if (wil_val_in_range(wil->ring_idle_trsh,
 			     used, used + descs_used)) {
-		txdata->idle += get_cycles() - txdata->last_idle;
+		txdata->idle += ktime_get() - txdata->last_idle;
 		wil_dbg_txrx(wil,  "Ring[%2d] not idle %d -> %d\n",
 			     ring_index, used, used + descs_used);
 	}
drivers/net/wireless/ath/wil6210/wil6210.h +2 -1
@@ -14,6 +14,7 @@
 #include <linux/timex.h>
 #include <linux/types.h>
 #include <linux/irqreturn.h>
+#include <linux/timekeeping.h>
 #include "wmi.h"
 #include "wil_platform.h"
 #include "fw.h"
@@ -632,7 +633,7 @@ struct wil_txrx_ops {
 struct wil_ring_tx_data {
 	bool dot1x_open;
 	int enabled;
-	cycles_t idle, last_idle, begin;
+	ktime_t idle, last_idle, begin;
 	u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
 	u16 agg_timeout;
 	u8 agg_amsdu;
author maintainer
#25 lore raw

PATCH 13/38 crypto: tcrypt: Replace get_cycles() with ktime_get()

In reply to Thomas Gleixner

get_cycles() is the historical access to a fine grained time source, but it is a suboptimal choice for two reasons:

- get_cycles() is not guaranteed to be supported and functional on all systems/platforms. If not supported or not functional it returns 0, which makes benchmarking moot.

- get_cycles() returns the raw counter value of whatever the architecture platform provides. The original x86 Time Stamp Counter (TSC) was despite its name tied to the actual CPU core frequency. That's not longer the case. So the counter value is only meaningful when the CPU operates at the same frequency as the TSC or the value is adjusted to the actual CPU frequency. Other architectures and platforms provide similar disjunct counters via get_cycles(), so the result is operations per BOGO-cycles, which is not really meaningful.

Use ktime_get() instead which provides nanosecond timestamps with the granularity of the underlying hardware counter, which is not different to the variety of get_cycles() implementations.

This provides at least understandable metrics, i.e. operations/nanoseconds, and is available on all platforms. As with get_cycles() the result might have to be put into relation with the CPU operating frequency, but that's not any different.

This is part of a larger effort to remove get_cycles() usage from non-architecture code.

---
 crypto/tcrypt.c |   84 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 42 insertions(+), 42 deletions(-)
crypto/tcrypt.c +42 -42
@@ -202,7 +202,7 @@ static int test_mb_aead_jiffies(struct t
 static int test_mb_aead_cycles(struct test_mb_aead_data *data, int enc,
 			       int blen, u32 num_mb)
 {
-	unsigned long cycles = 0;
+	unsigned long nsecs = 0;
 	int ret = 0;
 	int i;
 	int *rc;
@@ -220,20 +220,20 @@ static int test_mb_aead_cycles(struct te
 
 	/* The real thing. */
 	for (i = 0; i < 8; i++) {
-		cycles_t start, end;
+		ktime_t start, end;
 
-		start = get_cycles();
+		start = ktime_get();
 		ret = do_mult_aead_op(data, enc, num_mb, rc);
-		end = get_cycles();
+		end = ktime_get();
 
 		if (ret)
 			goto out;
 
-		cycles += end - start;
+		nsecs += (unsigned long)(end - start);
 	}
 
-	pr_cont("1 operation in %lu cycles (%d bytes)\n",
-		(cycles + 4) / (8 * num_mb), blen);
+	pr_cont("1 operation in %lu nsecs (%d bytes)\n",
+		nsecs / (8 * num_mb), blen);
 
 out:
 	kfree(rc);
@@ -475,7 +475,7 @@ static int test_aead_jiffies(struct aead
 
 static int test_aead_cycles(struct aead_request *req, int enc, int blen)
 {
-	unsigned long cycles = 0;
+	unsigned long nsecs = 0;
 	int ret = 0;
 	int i;
 
@@ -492,25 +492,24 @@ static int test_aead_cycles(struct aead_
 
 	/* The real thing. */
 	for (i = 0; i < 8; i++) {
-		cycles_t start, end;
+		ktime_t start, end;
 
-		start = get_cycles();
+		start = ktime_get();
 		if (enc)
 			ret = do_one_aead_op(req, crypto_aead_encrypt(req));
 		else
 			ret = do_one_aead_op(req, crypto_aead_decrypt(req));
-		end = get_cycles();
+		end = ktime_get();
 
 		if (ret)
 			goto out;
 
-		cycles += end - start;
+		nsecs += (unsigned long)(end - start);
 	}
 
 out:
 	if (ret == 0)
-		pr_cont("1 operation in %lu cycles (%d bytes)\n",
-			(cycles + 4) / 8, blen);
+		pr_cont("1 operation in %lu nsecs (%d bytes)\n", nsecs / 8, blen);
 
 	return ret;
 }
@@ -771,7 +770,7 @@ static int test_ahash_jiffies(struct aha
 static int test_ahash_cycles_digest(struct ahash_request *req, int blen,
 				    char *out)
 {
-	unsigned long cycles = 0;
+	unsigned long nsecs = 0;
 	int ret, i;
 
 	/* Warm-up run. */
@@ -783,25 +782,25 @@ static int test_ahash_cycles_digest(stru
 
 	/* The real thing. */
 	for (i = 0; i < 8; i++) {
-		cycles_t start, end;
+		ktime_t start, end;
 
-		start = get_cycles();
+		start = ktime_get();
 
 		ret = do_one_ahash_op(req, crypto_ahash_digest(req));
 		if (ret)
 			goto out;
 
-		end = get_cycles();
+		end = ktime_get();
 
-		cycles += end - start;
+		nsecs += (unsigned long)(end - start);
 	}
 
 out:
 	if (ret)
 		return ret;
 
-	pr_cont("%6lu cycles/operation, %4lu cycles/byte\n",
-		cycles / 8, cycles / (8 * blen));
+	pr_cont("%6lu nsecs/operation, %4lu nsecs/byte\n",
+		nsecs / 8, nsecs / (8 * blen));
 
 	return 0;
 }
@@ -809,7 +808,7 @@ static int test_ahash_cycles_digest(stru
 static int test_ahash_cycles(struct ahash_request *req, int blen,
 			     int plen, char *out)
 {
-	unsigned long cycles = 0;
+	unsigned long nsecs = 0;
 	int i, pcount, ret;
 
 	if (plen == blen)
@@ -832,9 +831,9 @@ static int test_ahash_cycles(struct ahas
 
 	/* The real thing. */
 	for (i = 0; i < 8; i++) {
-		cycles_t start, end;
+		ktime_t start, end;
 
-		start = get_cycles();
+		start = ktime_get();
 
 		ret = do_one_ahash_op(req, crypto_ahash_init(req));
 		if (ret)
@@ -848,17 +847,17 @@ static int test_ahash_cycles(struct ahas
 		if (ret)
 			goto out;
 
-		end = get_cycles();
+		end = ktime_get();
 
-		cycles += end - start;
+		nsecs += (unsigned long)(end - start);
 	}
 
 out:
 	if (ret)
 		return ret;
 
-	pr_cont("%6lu cycles/operation, %4lu cycles/byte\n",
-		cycles / 8, cycles / (8 * blen));
+	pr_cont("%6lu nsecs/operation, %4lu nsecs/byte\n",
+		nsecs / 8, nsecs / (8 * blen));
 
 	return 0;
 }
@@ -1019,7 +1018,7 @@ static int test_mb_acipher_jiffies(struc
 static int test_mb_acipher_cycles(struct test_mb_skcipher_data *data, int enc,
 			       int blen, u32 num_mb)
 {
-	unsigned long cycles = 0;
+	unsigned long nsecs = 0;
 	int ret = 0;
 	int i;
 	int *rc;
@@ -1037,20 +1036,20 @@ static int test_mb_acipher_cycles(struct
 
 	/* The real thing. */
 	for (i = 0; i < 8; i++) {
-		cycles_t start, end;
+		ktime_t start, end;
 
-		start = get_cycles();
+		start = ktime_get();
 		ret = do_mult_acipher_op(data, enc, num_mb, rc);
-		end = get_cycles();
+		end = ktime_get();
 
 		if (ret)
 			goto out;
 
-		cycles += end - start;
+		nsecs += (unsigned long)(end - start);
 	}
 
-	pr_cont("1 operation in %lu cycles (%d bytes)\n",
-		(cycles + 4) / (8 * num_mb), blen);
+	pr_cont("1 operation in %lu nsecs (%d bytes)\n",
+		nsecs / (8 * num_mb), blen);
 
 out:
 	kfree(rc);
@@ -1246,7 +1245,7 @@ static int test_acipher_jiffies(struct s
 static int test_acipher_cycles(struct skcipher_request *req, int enc,
 			       int blen)
 {
-	unsigned long cycles = 0;
+	unsigned long nsecs = 0;
 	int ret = 0;
 	int i;
 
@@ -1265,27 +1264,28 @@ static int test_acipher_cycles(struct sk
 
 	/* The real thing. */
 	for (i = 0; i < 8; i++) {
-		cycles_t start, end;
+		ktime_t start, end;
+
+		start = ktime_get();
 
-		start = get_cycles();
 		if (enc)
 			ret = do_one_acipher_op(req,
 						crypto_skcipher_encrypt(req));
 		else
 			ret = do_one_acipher_op(req,
 						crypto_skcipher_decrypt(req));
-		end = get_cycles();
+		end = ktime_get();
 
 		if (ret)
 			goto out;
 
-		cycles += end - start;
+		nsecs += (unsigned long)(end - start);
 	}
 
 out:
 	if (ret == 0)
-		pr_cont("1 operation in %lu cycles (%d bytes)\n",
-			(cycles + 4) / 8, blen);
+		pr_cont("1 operation in %lu nsecs (%d bytes)\n",
+			nsecs / 8, blen);
 
 	return ret;
 }
author maintainer
#26 lore raw

PATCH 14/38 slub: Use prandom instead of get_cycles()

In reply to Thomas Gleixner

The decision whether to scan remote nodes is based on a 'random' number retrieved via get_cycles(). get_cycles() is about to be removed.

There is already prandom state in the code, so use that instead.

---
 mm/slub.c |   37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)
mm/slub.c +23 -14
@@ -3302,6 +3302,25 @@ static inline struct slab *alloc_slab_pa
 	return slab;
 }
 
+#if defined(CONFIG_SLAB_FREELIST_RANDOM) || defined(CONFIG_NUMA)
+static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
+
+static unsigned int slab_get_prandom_state(unsigned int limit)
+{
+	struct rnd_state *state;
+	unsigned int res;
+
+	/*
+	 * An interrupt or NMI handler might interrupt and change
+	 * the state in the middle, but that's safe.
+	 */
+	state = &get_cpu_var(slab_rnd_state);
+	res = prandom_u32_state(state) % limit;
+	put_cpu_var(slab_rnd_state);
+	return res;
+}
+#endif
+
 #ifdef CONFIG_SLAB_FREELIST_RANDOM
 /* Pre-initialize the random sequence cache */
 static int init_cache_random_seq(struct kmem_cache *s)
@@ -3365,8 +3384,6 @@ static void *next_freelist_entry(struct
 	return (char *)start + idx;
 }
 
-static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
-
 /* Shuffle the single linked freelist based on a random pre-computed sequence */
 static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab,
 			     bool allow_spin)
@@ -3383,15 +3400,7 @@ static bool shuffle_freelist(struct kmem
 	if (allow_spin) {
 		pos = get_random_u32_below(freelist_count);
 	} else {
-		struct rnd_state *state;
-
-		/*
-		 * An interrupt or NMI handler might interrupt and change
-		 * the state in the middle, but that's safe.
-		 */
-		state = &get_cpu_var(slab_rnd_state);
-		pos = prandom_u32_state(state) % freelist_count;
-		put_cpu_var(slab_rnd_state);
+		pos = slab_get_prandom_state(freelist_count);
 	}
 
 	page_limit = slab->objects * s->size;
@@ -3882,7 +3891,7 @@ static void *get_from_any_partial(struct
 	 * with available objects.
 	 */
 	if (!s->remote_node_defrag_ratio ||
-			get_cycles() % 1024 > s->remote_node_defrag_ratio)
+	    slab_get_prandom_state(1024) > s->remote_node_defrag_ratio)
 		return NULL;
 
 	do {
@@ -7102,7 +7111,7 @@ static unsigned int
 
 	/* see get_from_any_partial() for the defrag ratio description */
 	if (!s->remote_node_defrag_ratio ||
-			get_cycles() % 1024 > s->remote_node_defrag_ratio)
+	    slab_get_prandom_state(1024) > s->remote_node_defrag_ratio)
 		return 0;
 
 	do {
@@ -8421,7 +8430,7 @@ void __init kmem_cache_init_late(void)
 	flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM | WQ_PERCPU,
 				  0);
 	WARN_ON(!flushwq);
-#ifdef CONFIG_SLAB_FREELIST_RANDOM
+#if defined(CONFIG_SLAB_FREELIST_RANDOM) || defined(CONFIG_NUMA)
 	prandom_init_once(&slab_rnd_state);
 #endif
 }
maintainer Acked-by on v1 14/38
#27 lore raw

Re: [patch 14/38] slub: Use prandom instead of get_cycles()

Quoted 8 lines · Thomas Gleixner

The decision whether to scan remote nodes is based on a 'random' number retrieved via get_cycles(). get_cycles() is about to be removed.

There is already prandom state in the code, so use that instead.

LGTM.

maintainer Acked-by on v1 14/38
#28 lore raw

Re: [patch 14/38] slub: Use prandom instead of get_cycles()

In reply to Thomas Gleixner

[Resending after fixing broken email headers]

Quoted 9 lines · Thomas Gleixner

The decision whether to scan remote nodes is based on a 'random' number retrieved via get_cycles(). get_cycles() is about to be removed.

There is already prandom state in the code, so use that instead.

---

Is this for this merge window?

This may conflict with upcoming changes on freelist shuffling [1] (not queued for slab/for-next yet though), but it should be easy to resolve.

[Cc'ing Shengming and SLAB ALLOCATOR folks]
[1] https://lore.kernel.org/linux-mm/[email protected]

Signature · 2 lines
Cheers,
Harry / Hyeonggon
Quoted 86 lines
 mm/slub.c |   37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)
mm/slub.c +23 -14
@@ -3302,6 +3302,25 @@ static inline struct slab *alloc_slab_pa
 	return slab;
 }
 
+#if defined(CONFIG_SLAB_FREELIST_RANDOM) || defined(CONFIG_NUMA)
+static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
+
+static unsigned int slab_get_prandom_state(unsigned int limit)
+{
+	struct rnd_state *state;
+	unsigned int res;
+
+	/*
+	 * An interrupt or NMI handler might interrupt and change
+	 * the state in the middle, but that's safe.
+	 */
+	state = &get_cpu_var(slab_rnd_state);
+	res = prandom_u32_state(state) % limit;
+	put_cpu_var(slab_rnd_state);
+	return res;
+}
+#endif
+
 #ifdef CONFIG_SLAB_FREELIST_RANDOM
 /* Pre-initialize the random sequence cache */
 static int init_cache_random_seq(struct kmem_cache *s)
@@ -3365,8 +3384,6 @@ static void *next_freelist_entry(struct
 	return (char *)start + idx;
 }
 
-static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
-
 /* Shuffle the single linked freelist based on a random pre-computed sequence */
 static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab,
 			     bool allow_spin)
@@ -3383,15 +3400,7 @@ static bool shuffle_freelist(struct kmem
 	if (allow_spin) {
 		pos = get_random_u32_below(freelist_count);
 	} else {
-		struct rnd_state *state;
-
-		/*
-		 * An interrupt or NMI handler might interrupt and change
-		 * the state in the middle, but that's safe.
-		 */
-		state = &get_cpu_var(slab_rnd_state);
-		pos = prandom_u32_state(state) % freelist_count;
-		put_cpu_var(slab_rnd_state);
+		pos = slab_get_prandom_state(freelist_count);
 	}
 
 	page_limit = slab->objects * s->size;
@@ -3882,7 +3891,7 @@ static void *get_from_any_partial(struct
 	 * with available objects.
 	 */
 	if (!s->remote_node_defrag_ratio ||
-			get_cycles() % 1024 > s->remote_node_defrag_ratio)
+	    slab_get_prandom_state(1024) > s->remote_node_defrag_ratio)
 		return NULL;
 
 	do {
@@ -7102,7 +7111,7 @@ static unsigned int
 
 	/* see get_from_any_partial() for the defrag ratio description */
 	if (!s->remote_node_defrag_ratio ||
-			get_cycles() % 1024 > s->remote_node_defrag_ratio)
+	    slab_get_prandom_state(1024) > s->remote_node_defrag_ratio)
 		return 0;
 
 	do {
@@ -8421,7 +8430,7 @@ void __init kmem_cache_init_late(void)
 	flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM | WQ_PERCPU,
 				  0);
 	WARN_ON(!flushwq);
-#ifdef CONFIG_SLAB_FREELIST_RANDOM
+#if defined(CONFIG_SLAB_FREELIST_RANDOM) || defined(CONFIG_NUMA)
 	prandom_init_once(&slab_rnd_state);
 #endif
 }
#29 lore raw

Re: [patch 14/38] slub: Use prandom instead of get_cycles()

Quoted 13 lines · Harry

[Resending after fixing broken email headers]

Quoted 9 lines · Thomas Gleixner

The decision whether to scan remote nodes is based on a 'random' number retrieved via get_cycles(). get_cycles() is about to be removed.

There is already prandom state in the code, so use that instead.

---

Quoted 8 lines

Is this for this merge window?

This may conflict with upcoming changes on freelist shuffling [1] (not queued for slab/for-next yet though), but it should be easy to resolve.

Hi Harry,

Would you like me to wait for this patch to land linux-next and then rebase and send v6 on top?

Thanks,

--
With Best Regards,
Shengming

Quoted 93 lines

[Cc'ing Shengming and SLAB ALLOCATOR folks]
[1] https://lore.kernel.org/linux-mm/[email protected]

Signature · 2 lines
Cheers,
Harry / Hyeonggon
Quoted 86 lines
 mm/slub.c |   37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)
mm/slub.c +23 -14
@@ -3302,6 +3302,25 @@ static inline struct slab *alloc_slab_pa
     return slab;
 }
 
+#if defined(CONFIG_SLAB_FREELIST_RANDOM) || defined(CONFIG_NUMA)
+static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
+
+static unsigned int slab_get_prandom_state(unsigned int limit)
+{
+    struct rnd_state *state;
+    unsigned int res;
+
+    /*
+     * An interrupt or NMI handler might interrupt and change
+     * the state in the middle, but that's safe.
+     */
+    state = &get_cpu_var(slab_rnd_state);
+    res = prandom_u32_state(state) % limit;
+    put_cpu_var(slab_rnd_state);
+    return res;
+}
+#endif
+
 #ifdef CONFIG_SLAB_FREELIST_RANDOM
 /* Pre-initialize the random sequence cache */
 static int init_cache_random_seq(struct kmem_cache *s)
@@ -3365,8 +3384,6 @@ static void *next_freelist_entry(struct
     return (char *)start + idx;
 }
 
-static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
-
 /* Shuffle the single linked freelist based on a random pre-computed sequence */
 static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab,
                  bool allow_spin)
@@ -3383,15 +3400,7 @@ static bool shuffle_freelist(struct kmem
     if (allow_spin) {
         pos = get_random_u32_below(freelist_count);
     } else {
-        struct rnd_state *state;
-
-        /*
-         * An interrupt or NMI handler might interrupt and change
-         * the state in the middle, but that's safe.
-         */
-        state = &get_cpu_var(slab_rnd_state);
-        pos = prandom_u32_state(state) % freelist_count;
-        put_cpu_var(slab_rnd_state);
+        pos = slab_get_prandom_state(freelist_count);
     }
 
     page_limit = slab->objects * s->size;
@@ -3882,7 +3891,7 @@ static void *get_from_any_partial(struct
      * with available objects.
      */
     if (!s->remote_node_defrag_ratio ||
-            get_cycles() % 1024 > s->remote_node_defrag_ratio)
+        slab_get_prandom_state(1024) > s->remote_node_defrag_ratio)
         return NULL;
 
     do {
@@ -7102,7 +7111,7 @@ static unsigned int
 
     /* see get_from_any_partial() for the defrag ratio description */
     if (!s->remote_node_defrag_ratio ||
-            get_cycles() % 1024 > s->remote_node_defrag_ratio)
+        slab_get_prandom_state(1024) > s->remote_node_defrag_ratio)
         return 0;
 
     do {
@@ -8421,7 +8430,7 @@ void __init kmem_cache_init_late(void)
     flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM | WQ_PERCPU,
                   0);
     WARN_ON(!flushwq);
-#ifdef CONFIG_SLAB_FREELIST_RANDOM
+#if defined(CONFIG_SLAB_FREELIST_RANDOM) || defined(CONFIG_NUMA)
     prandom_init_once(&slab_rnd_state);
 #endif
 }
#30 lore raw

Re: [patch 14/38] slub: Use prandom instead of get_cycles()

Quoted 9 lines · On 4/13/26 15:02, [email protected] wrote:
Quoted 8 lines · Harry

[Resending after fixing broken email headers]

Quoted 5 lines · Thomas Gleixner

The decision whether to scan remote nodes is based on a 'random' number retrieved via get_cycles(). get_cycles() is about to be removed.

There is already prandom state in the code, so use that instead.

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

---

Is this for this merge window?

I'd say it's not intended for 7.1 as it's not in -next and v1 was posted just before the merge window.

Quoted 3 lines
Quoted 3 lines

This may conflict with upcoming changes on freelist shuffling [1] (not queued for slab/for-next yet though), but it should be easy to resolve.

Indeed, it's a simple conflict.

Quoted 5 lines

Hi Harry,

Would you like me to wait for this patch to land linux-next and then rebase and send v6 on top?

Just send it now based same as previously so we can finish the reviews, and we'll deal with it after rc1.

author maintainer
#31 lore raw

PATCH 15/38 ptp: ptp_vmclock: Replace get_cycles() usage

In reply to Thomas Gleixner

get_cycles() is not really well defined and similar to other usaage of the underlying hardware CPU counters the PTP vmclock should use an explicit interface as well.

Implement ptp_vmclock_read_cpu_counter() in arm64 and x86 and simplify the Kconfig selection while at it.

No functional change.

---
 arch/arm64/Kconfig                   |    1 +
 arch/arm64/include/asm/ptp_vmclock.h |   12 ++++++++++++
 arch/x86/Kconfig                     |    1 +
 arch/x86/include/asm/ptp_vmclock.h   |   12 ++++++++++++
 drivers/ptp/Kconfig                  |    6 ++++--
 drivers/ptp/ptp_vmclock.c            |    6 ++++--
 6 files changed, 34 insertions(+), 4 deletions(-)
arch/arm64/Kconfig +1 -0
@@ -112,6 +112,7 @@ config ARM64
 	select ARCH_SUPPORTS_SCHED_SMT
 	select ARCH_SUPPORTS_SCHED_CLUSTER
 	select ARCH_SUPPORTS_SCHED_MC
+	select ARCH_SUPPORTS_PTP_VMCLOCK if ARCH_SUPPORTS_INT128
 	select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
 	select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT
 	select ARCH_WANT_DEFAULT_BPF_JIT
arch/arm64/include/asm/ptp_vmclock.h new file +12 -0
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PTP_VMCLOCK_H
+#define __ASM_PTP_VMCLOCK_H
+
+#include <asm/arch_timer.h>
+
+static inline u64 ptp_vmclock_read_cpu_counter(void)
+{
+	return arch_timer_read_counter();
+}
+
+#endif
arch/x86/Kconfig +1 -0
@@ -135,6 +135,7 @@ config X86
 	select ARCH_SUPPORTS_RT
 	select ARCH_SUPPORTS_AUTOFDO_CLANG
 	select ARCH_SUPPORTS_PROPELLER_CLANG    if X86_64
+	select ARCH_SUPPORTS_PTP_VMCLOCK	if X86_TSC
 	select ARCH_USE_BUILTIN_BSWAP
 	select ARCH_USE_CMPXCHG_LOCKREF		if X86_CX8
 	select ARCH_USE_MEMTEST
arch/x86/include/asm/ptp_vmclock.h new file +12 -0
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PTP_VMCLOCK_H
+#define __ASM_PTP_VMCLOCK_H
+
+#include <asm/tsc.h>
+
+static inline u64 ptp_vmclock_read_cpu_counter(void)
+{
+	return cpu_feature_enabled(X86_FEATURE_TSC) ? rdtsc() : 0;
+}
+
+#endif
drivers/ptp/Kconfig +4 -2
@@ -131,10 +131,12 @@ config PTP_1588_CLOCK_KVM
 	  To compile this driver as a module, choose M here: the module
 	  will be called ptp_kvm.
 
+config ARCH_SUPPORTS_PTP_VMCLOCK
+	bool
+
 config PTP_1588_CLOCK_VMCLOCK
 	tristate "Virtual machine PTP clock"
-	depends on X86_TSC || ARM_ARCH_TIMER
-	depends on PTP_1588_CLOCK && ARCH_SUPPORTS_INT128
+	depends on PTP_1588_CLOCK && ARCH_SUPPORTS_PTP_VMCLOCK
 	default PTP_1588_CLOCK_KVM
 	help
 	  This driver adds support for using a virtual precision clock
drivers/ptp/ptp_vmclock.c +4 -2
@@ -28,6 +28,8 @@
 
 #include <linux/ptp_clock_kernel.h>
 
+#include <asm/ptp_vmclock.h>
+
 #ifdef CONFIG_X86
 #include <asm/pvclock.h>
 #include <asm/kvmclock.h>
@@ -144,11 +146,11 @@ static int vmclock_get_crosststamp(struc
 			if (systime_snapshot.cs_id == st->cs_id) {
 				cycle = systime_snapshot.cycles;
 			} else {
-				cycle = get_cycles();
+				cycle = ptp_vmclock_read_cpu_counter();
 				ptp_read_system_postts(sts);
 			}
 		} else {
-			cycle = get_cycles();
+			cycle = ptp_vmclock_read_cpu_counter();
 		}
 
 		delta = cycle - le64_to_cpu(st->clk->counter_value);
maintainer Acked-by on v1 15/38
#32 lore raw

Re: [patch 15/38] ptp: ptp_vmclock: Replace get_cycles() usage

Quoted 11 lines · Thomas Gleixner

get_cycles() is not really well defined and similar to other usaage of the underlying hardware CPU counters the PTP vmclock should use an explicit interface as well.

Implement ptp_vmclock_read_cpu_counter() in arm64 and x86 and simplify the Kconfig selection while at it.

No functional change.

Although I might follow up with a change to make this...

arch/x86/include/asm/ptp_vmclock.h line 11

Quoted 5 lines
arch/x86/include/asm/ptp_vmclock.h new file +5 -0
+static inline u64 ptp_vmclock_read_cpu_counter(void)
+{
+	return cpu_feature_enabled(X86_FEATURE_TSC) ? rdtsc() : 0;
+}
+

... depend on TSC_RELIABLE¹, since if the guest doesn't believe that it is, then the guest shouldn't be trying to use it as the basis for precise timing.

¹ (Or... one of the other zoo of TSC flags for the gradually reducing brokenness over the years...)

maintainer
#33 lore raw

Re: [patch 15/38] ptp: ptp_vmclock: Replace get_cycles() usage

Quoted 8 lines · David Woodhouse

On Fri, 2026-04-10 at 14:19 +0200, Thomas Gleixner wrote:

... depend on TSC_RELIABLE¹, since if the guest doesn't believe that it is, then the guest shouldn't be trying to use it as the basis for precise timing.

¹ (Or... one of the other zoo of TSC flags for the gradually reducing brokenness over the years...)

It looks like this is sufficiently handled in the caller:

static int vmclock_get_crosststamp(struct vmclock_state *st,
struct ptp_system_timestamp *sts, struct system_counterval_t *system_counter, struct timespec64 *tspec)
{
....

#ifdef CONFIG_X86
        /*
         * We'd expect the hypervisor to know this and to report the clock
         * status as VMCLOCK_STATUS_UNRELIABLE. But be paranoid.
         */
        if (check_tsc_unstable())
                return -EINVAL;

#endif

With 486 and ELAN out of the way, Winchip6 seems to be the only one without X86_FEATURE_TSC, so I think the next logical step would be to turn off Winchip6 as well and remove all X86_FEATURE_TSC and CONFIG_X86_TSC checks.

Arnd

author maintainer
#34 lore raw

PATCH 16/38 fbdev: udlfb: Replace get_cycles() with ktime_get()

In reply to Thomas Gleixner

These metrics are not really requiring CPU cycles and as those are meanlingless when the CPU is running at a different frequency, this can use ktime_get() and achieve the same result.

Part of a larger effort to confine get_cycles() access to low level architecture code.

---
 Documentation/fb/udlfb.rst  |    4 ++--
 drivers/video/fbdev/udlfb.c |   24 ++++++++++++------------
 2 files changed, 14 insertions(+), 14 deletions(-)
Documentation/fb/udlfb.rst +2 -2
@@ -156,8 +156,8 @@ metrics_bytes_sent	 32-bit count of how
 			 USB to communicate the resulting changed pixels to the
 			 hardware. Includes compression and protocol overhead
 
-metrics_cpu_kcycles_used 32-bit count of CPU cycles used in processing the
-			 above pixels (in thousands of cycles).
+metrics_cpu_kcycles_used 32-bit count of microseconds used in processing the
+			 above pixels
 
 metrics_reset		 Write-only. Any write to this file resets all metrics
 			 above to zero.  Note that the 32-bit counters above
drivers/video/fbdev/udlfb.c +12 -12
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/unaligned.h>
+#include <linux/timekeeping.h>
 #include <video/udlfb.h>
 #include "edid.h"
 
@@ -600,15 +601,15 @@ static int dlfb_render_hline(struct dlfb
 
 static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, int height)
 {
+	ktime_t t_start, t_delta;
 	int i, ret;
 	char *cmd;
-	cycles_t start_cycles, end_cycles;
 	int bytes_sent = 0;
 	int bytes_identical = 0;
 	struct urb *urb;
 	int aligned_x;
 
-	start_cycles = get_cycles();
+	t_start = ktime_get();
 
 	mutex_lock(&dlfb->render_mutex);
 
@@ -661,10 +662,9 @@ static int dlfb_handle_damage(struct dlf
 	atomic_add(bytes_sent, &dlfb->bytes_sent);
 	atomic_add(bytes_identical, &dlfb->bytes_identical);
 	atomic_add(width*height*2, &dlfb->bytes_rendered);
-	end_cycles = get_cycles();
-	atomic_add(((unsigned int) ((end_cycles - start_cycles)
-		    >> 10)), /* Kcycles */
-		   &dlfb->cpu_kcycles_used);
+	t_delta = ktime_get() - t_start;
+	/* Avoid a division and approximate microseconds with shift right ten */
+	atomic_add(((int)(t_delta >> 10)), &dlfb->cpu_kcycles_used);
 
 	ret = 0;
 
@@ -727,9 +727,9 @@ static void dlfb_dpy_deferred_io(struct
 {
 	struct fb_deferred_io_pageref *pageref;
 	struct dlfb_data *dlfb = info->par;
+	ktime_t t_start, t_delta;
 	struct urb *urb;
 	char *cmd;
-	cycles_t start_cycles, end_cycles;
 	int bytes_sent = 0;
 	int bytes_identical = 0;
 	int bytes_rendered = 0;
@@ -742,7 +742,7 @@ static void dlfb_dpy_deferred_io(struct
 	if (!atomic_read(&dlfb->usb_active))
 		goto unlock_ret;
 
-	start_cycles = get_cycles();
+	t_start = ktime_get();
 
 	urb = dlfb_get_urb(dlfb);
 	if (!urb)
@@ -774,10 +774,10 @@ static void dlfb_dpy_deferred_io(struct
 	atomic_add(bytes_sent, &dlfb->bytes_sent);
 	atomic_add(bytes_identical, &dlfb->bytes_identical);
 	atomic_add(bytes_rendered, &dlfb->bytes_rendered);
-	end_cycles = get_cycles();
-	atomic_add(((unsigned int) ((end_cycles - start_cycles)
-		    >> 10)), /* Kcycles */
-		   &dlfb->cpu_kcycles_used);
+	t_delta = ktime_get() - t_start;
+	/* Avoid a division and approximate microseconds with shift right ten */
+	atomic_add(((int)(t_delta >> 10)), &dlfb->cpu_kcycles_used);
+
 unlock_ret:
 	mutex_unlock(&dlfb->render_mutex);
 }
author maintainer
#35 lore raw

PATCH 17/38 ext4: Replace get_cycles() usage with ktime_get()

In reply to Thomas Gleixner

get_cycles() is not guaranteed to be functional on all systems/platforms and the values returned are unitless and not easy to map to something useful.

Use ktime_get() instead, which provides nanosecond timestamps and is functional everywhere.

This is part of a larger effort to limit get_cycles() usage to low level architecture code.

---
 fs/ext4/mballoc.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
fs/ext4/mballoc.c +2 -2
@@ -1289,7 +1289,7 @@ void ext4_mb_generate_buddy(struct super
 	ext4_grpblk_t len;
 	unsigned free = 0;
 	unsigned fragments = 0;
-	unsigned long long period = get_cycles();
+	ktime_t period = ktime_get();
 
 	/* initialize buddy from bitmap which is aggregation
 	 * of on-disk bitmap and preallocations */
@@ -1328,7 +1328,7 @@ void ext4_mb_generate_buddy(struct super
 
 	clear_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &(grp->bb_state));
 
-	period = get_cycles() - period;
+	period = ktime_get() - period;
 	atomic_inc(&sbi->s_mb_buddies_generated);
 	atomic64_add(period, &sbi->s_mb_generation_time);
 }
maintainer
#36 lore raw

Re: [patch 17/38] ext4: Replace get_cycles() usage with ktime_get()

Quoted 7 lines · Thomas Gleixner

get_cycles() is not guaranteed to be functional on all systems/platforms and the values returned are unitless and not easy to map to something useful.

Use ktime_get() instead, which provides nanosecond timestamps and is functional everywhere.

Quoted 6 lines

This is part of a larger effort to limit get_cycles() usage to low level architecture code.

I think this is technically an ABI chance, since the time difference gets exported through procfs, but the new version is clearly the right thing to do since it replaces a hardware specific value with a portable one.

Arnd

author maintainer
#37 lore raw

PATCH 18/38 lib/tests: Replace get_cycles() with ktime_get()

In reply to Thomas Gleixner

get_cycles() is the historical access to a fine grained time source, but it is a suboptimal choice for two reasons:

- get_cycles() is not guaranteed to be supported and functional on all systems/platforms. If not supported or not functional it returns 0, which makes benchmarking moot.

- get_cycles() returns the raw counter value of whatever the architecture platform provides. The original x86 Time Stamp Counter (TSC) was despite its name tied to the actual CPU core frequency. That's not longer the case. So the counter value is only meaningful when the CPU operates at the same frequency as the TSC or the value is adjusted to the actual CPU frequency. Other architectures and platforms provide similar disjunct counters via get_cycles(), so the result is operations per BOGO-cycles, which is not really meaningful.

Use ktime_get() instead which provides nanosecond timestamps with the granularity of the underlying hardware counter, which is not different to the variety of get_cycles() implementations.

This provides at least understandable metrics, i.e. operations/nanoseconds, and is available on all platforms. As with get_cycles() the result might have to be put into relation with the CPU operating frequency, but that's not any different.

This is part of a larger effort to remove get_cycles() usage from non-architecture code.

---
 lib/interval_tree_test.c |   16 ++++++++--------
 lib/rbtree_test.c        |   46 +++++++++++++++++++++++-----------------------
 lib/test_vmalloc.c       |   10 +++++-----
 3 files changed, 36 insertions(+), 36 deletions(-)
lib/interval_tree_test.c +8 -8
@@ -65,13 +65,13 @@ static void init(void)
 static int basic_check(void)
 {
 	int i, j;
-	cycles_t time1, time2, time;
+	ktime_t time1, time2, time;
 
 	printk(KERN_ALERT "interval tree insert/remove");
 
 	init();
 
-	time1 = get_cycles();
+	time1 = ktime_get();
 
 	for (i = 0; i < perf_loops; i++) {
 		for (j = 0; j < nnodes; j++)
@@ -80,11 +80,11 @@ static int basic_check(void)
 			interval_tree_remove(nodes + j, &root);
 	}
 
-	time2 = get_cycles();
+	time2 = ktime_get();
 	time = time2 - time1;
 
 	time = div_u64(time, perf_loops);
-	printk(" -> %llu cycles\n", (unsigned long long)time);
+	printk(" -> %llu nsecs\n", (unsigned long long)time);
 
 	return 0;
 }
@@ -93,7 +93,7 @@ static int search_check(void)
 {
 	int i, j;
 	unsigned long results;
-	cycles_t time1, time2, time;
+	ktime_t time1, time2, time;
 
 	printk(KERN_ALERT "interval tree search");
 
@@ -102,7 +102,7 @@ static int search_check(void)
 	for (j = 0; j < nnodes; j++)
 		interval_tree_insert(nodes + j, &root);
 
-	time1 = get_cycles();
+	time1 = ktime_get();
 
 	results = 0;
 	for (i = 0; i < search_loops; i++)
@@ -113,12 +113,12 @@ static int search_check(void)
 			results += search(&root, start, last);
 		}
 
-	time2 = get_cycles();
+	time2 = ktime_get();
 	time = time2 - time1;
 
 	time = div_u64(time, search_loops);
 	results = div_u64(results, search_loops);
-	printk(" -> %llu cycles (%lu results)\n",
+	printk(" -> %llu nsecs (%lu results)\n",
 	       (unsigned long long)time, results);
 
 	for (j = 0; j < nnodes; j++)
lib/rbtree_test.c +23 -23

140 lines not on this page · raw message

lib/test_vmalloc.c +5 -5
@@ -454,8 +454,8 @@ static struct test_driver {
 	struct task_struct *task;
 	struct test_case_data data[ARRAY_SIZE(test_case_array)];
 
-	unsigned long start;
-	unsigned long stop;
+	ktime_t start;
+	ktime_t stop;
 } *tdriver;
 
 static void shuffle_array(int *arr, int n)
@@ -490,7 +490,7 @@ static int test_func(void *private)
 	 */
 	synchronize_srcu(&prepare_for_test_srcu);
 
-	t->start = get_cycles();
+	t->start = ktime_get();
 	for (i = 0; i < ARRAY_SIZE(test_case_array); i++) {
 		index = random_array[i];
 
@@ -519,7 +519,7 @@ static int test_func(void *private)
 
 		t->data[index].time = delta;
 	}
-	t->stop = get_cycles();
+	t->stop = ktime_get();
 	test_report_one_done();
 
 	/*
@@ -619,7 +619,7 @@ static void do_concurrent_test(void)
 				t->data[j].time);
 		}
 
-		pr_info("All test took worker%d=%lu cycles\n",
+		pr_info("All test took worker%d=%lld nsecs\n",
 			i, t->stop - t->start);
 	}
 
#38 lore raw

Re: [patch 18/38] lib/tests: Replace get_cycles() with ktime_get()

Hi Thomas,

Quoted 25 lines · Thomas Gleixner

get_cycles() is the historical access to a fine grained time source, but it is a suboptimal choice for two reasons:

- get_cycles() is not guaranteed to be supported and functional on all systems/platforms. If not supported or not functional it returns 0, which makes benchmarking moot.

- get_cycles() returns the raw counter value of whatever the architecture platform provides. The original x86 Time Stamp Counter (TSC) was despite its name tied to the actual CPU core frequency. That's not longer the case. So the counter value is only meaningful when the CPU operates at the same frequency as the TSC or the value is adjusted to the actual CPU frequency. Other architectures and platforms provide similar disjunct counters via get_cycles(), so the result is operations per BOGO-cycles, which is not really meaningful.

Use ktime_get() instead which provides nanosecond timestamps with the granularity of the underlying hardware counter, which is not different to the variety of get_cycles() implementations.

This provides at least understandable metrics, i.e. operations/nanoseconds, and is available on all platforms. As with get_cycles() the result might have to be put into relation with the CPU operating frequency, but that's not any different.

Quoted 4 lines

This is part of a larger effort to remove get_cycles() usage from non-architecture code.

Thanks for your patch!

Quoted 19 lines
lib/interval_tree_test.c +2 -2
@@ -65,13 +65,13 @@ static void init(void)
 static int basic_check(void)
 {
        int i, j;
-       cycles_t time1, time2, time;
+       ktime_t time1, time2, time;
 
        printk(KERN_ALERT "interval tree insert/remove");
 
        init();
 
-       time1 = get_cycles();
+       time1 = ktime_get();
 
        for (i = 0; i < perf_loops; i++) {
                for (j = 0; j < nnodes; j++)

lib/interval_tree_test.c static int basic_check(void) · line 87

Quoted 10 lines
lib/interval_tree_test.c +2 -2
@@ -80,11 +80,11 @@ static int basic_check(void)
                        interval_tree_remove(nodes + j, &root);
        }
 
-       time2 = get_cycles();
+       time2 = ktime_get();
        time = time2 - time1;
 
        time = div_u64(time, perf_loops);
-       printk(" -> %llu cycles\n", (unsigned long long)time);
+       printk(" -> %llu nsecs\n", (unsigned long long)time);

While cycles_t was unsigned long or long long, ktime_t is always s64, so "%lld", and the cast can be dropped (everywhere).

Gr{oetje,eeting}s,

Geert

Signature · 5 lines
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
author maintainer
#39 lore raw

PATCH 19/38 kcsan: Replace get_cycles() usage

In reply to Thomas Gleixner

KCSAN uses get_cycles() for two purposes:

1) Seeding the random state with get_cycles() is a historical leftover.

2) The microbenchmark uses get_cycles(), which provides an unit less counter value and is not guaranteed to be functional on all systems/platforms.

Use random_get_entropy() for seeding the random state and ktime_get() which is universaly functional and provides at least a comprehensible unit.

This is part of a larger effort to remove get_cycles() usage from non-architecture code.

---
 kernel/kcsan/core.c    |    2 +-
 kernel/kcsan/debugfs.c |    8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)
kernel/kcsan/core.c +1 -1
@@ -798,7 +798,7 @@ void __init kcsan_init(void)
 	BUG_ON(!in_task());
 
 	for_each_possible_cpu(cpu)
-		per_cpu(kcsan_rand_state, cpu) = (u32)get_cycles();
+		per_cpu(kcsan_rand_state, cpu) = (u32)random_get_entropy();
 
 	/*
 	 * We are in the init task, and no other tasks should be running;
kernel/kcsan/debugfs.c +4 -4
@@ -58,7 +58,7 @@ static noinline void microbenchmark(unsi
 {
 	const struct kcsan_ctx ctx_save = current->kcsan_ctx;
 	const bool was_enabled = READ_ONCE(kcsan_enabled);
-	u64 cycles;
+	ktime_t nsecs;
 
 	/* We may have been called from an atomic region; reset context. */
 	memset(&current->kcsan_ctx, 0, sizeof(current->kcsan_ctx));
@@ -70,16 +70,16 @@ static noinline void microbenchmark(unsi
 
 	pr_info("%s begin | iters: %lu\n", __func__, iters);
 
-	cycles = get_cycles();
+	nsecs = ktime_get();
 	while (iters--) {
 		unsigned long addr = iters & ((PAGE_SIZE << 8) - 1);
 		int type = !(iters & 0x7f) ? KCSAN_ACCESS_ATOMIC :
 				(!(iters & 0xf) ? KCSAN_ACCESS_WRITE : 0);
 		__kcsan_check_access((void *)addr, sizeof(long), type);
 	}
-	cycles = get_cycles() - cycles;
+	nsecs = ktime_get() - nsecs;
 
-	pr_info("%s end   | cycles: %llu\n", __func__, cycles);
+	pr_info("%s end   | nsecs: %llu\n", __func__, nsecs);
 
 	WRITE_ONCE(kcsan_enabled, was_enabled);
 	/* restore context */
maintainer Reviewed-by on v1 19/38
#40 lore raw

Re: [patch 19/38] kcsan: Replace get_cycles() usage

Quoted 12 lines · Thomas Gleixner

KCSAN uses get_cycles() for two purposes:

1) Seeding the random state with get_cycles() is a historical leftover.

2) The microbenchmark uses get_cycles(), which provides an unit less counter value and is not guaranteed to be functional on all systems/platforms.

Use random_get_entropy() for seeding the random state and ktime_get() which is universaly functional and provides at least a comprehensible unit.

Quoted 7 lines

This is part of a larger effort to remove get_cycles() usage from non-architecture code.

Quoted 48 lines
---
 kernel/kcsan/core.c    |    2 +-
 kernel/kcsan/debugfs.c |    8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)
kernel/kcsan/core.c +1 -1
@@ -798,7 +798,7 @@ void __init kcsan_init(void)
        BUG_ON(!in_task());
 
        for_each_possible_cpu(cpu)
-               per_cpu(kcsan_rand_state, cpu) = (u32)get_cycles();
+               per_cpu(kcsan_rand_state, cpu) = (u32)random_get_entropy();
 
        /*
         * We are in the init task, and no other tasks should be running;
kernel/kcsan/debugfs.c +4 -4
@@ -58,7 +58,7 @@ static noinline void microbenchmark(unsi
 {
        const struct kcsan_ctx ctx_save = current->kcsan_ctx;
        const bool was_enabled = READ_ONCE(kcsan_enabled);
-       u64 cycles;
+       ktime_t nsecs;
 
        /* We may have been called from an atomic region; reset context. */
        memset(&current->kcsan_ctx, 0, sizeof(current->kcsan_ctx));
@@ -70,16 +70,16 @@ static noinline void microbenchmark(unsi
 
        pr_info("%s begin | iters: %lu\n", __func__, iters);
 
-       cycles = get_cycles();
+       nsecs = ktime_get();
        while (iters--) {
                unsigned long addr = iters & ((PAGE_SIZE << 8) - 1);
                int type = !(iters & 0x7f) ? KCSAN_ACCESS_ATOMIC :
                                (!(iters & 0xf) ? KCSAN_ACCESS_WRITE : 0);
                __kcsan_check_access((void *)addr, sizeof(long), type);
        }
-       cycles = get_cycles() - cycles;
+       nsecs = ktime_get() - nsecs;
 
-       pr_info("%s end   | cycles: %llu\n", __func__, cycles);
+       pr_info("%s end   | nsecs: %llu\n", __func__, nsecs);
 
        WRITE_ONCE(kcsan_enabled, was_enabled);
        /* restore context */
author maintainer
#41 lore raw

PATCH 20/38 kasan: sw_tags: Replace get_cycles() by random_get_entropy()

In reply to Thomas Gleixner

Seeding the random state with get_cycles() is functionally equivalent on the architectures which provide get_cycles(), but it does not make sense semantically.

Use random_get_entropy() instead, which is the proper interface.

This is part of a larger effort to remove get_cycles() usage from non-architecture code.

---
 mm/kasan/sw_tags.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/kasan/sw_tags.c +1 -1
@@ -41,7 +41,7 @@ void __init kasan_init_sw_tags(void)
 	int cpu;
 
 	for_each_possible_cpu(cpu)
-		per_cpu(prng_state, cpu) = (u32)get_cycles();
+		per_cpu(prng_state, cpu) = (u32)random_get_entropy();
 
 	kasan_init_tags();
 	kasan_enable();
author maintainer
#42 lore raw

PATCH 21/38 hamradio: baycom_epp: Remove BAYCOM_DEBUG

In reply to Thomas Gleixner

The whole code guarded by BAYCOM_DEBUG is only writing debug values into a datastructure, but there is no way to ever access them.

Remove the pointless ballast.

This is part of a larger effort to remove get_cycles() usage from non-architecture code.

---
 drivers/net/hamradio/baycom_epp.c |   51 --------------------------------------
 1 file changed, 51 deletions(-)
drivers/net/hamradio/baycom_epp.c +0 -51
@@ -44,7 +44,6 @@
 
 /* --------------------------------------------------------------------- */
 
-#define BAYCOM_DEBUG
 #define BAYCOM_MAGIC 19730510
 
 /* --------------------------------------------------------------------- */
@@ -191,18 +190,6 @@ struct baycom_state {
 
 	unsigned int ptt_keyed;
 	struct sk_buff *skb;  /* next transmit packet  */
-
-#ifdef BAYCOM_DEBUG
-	struct debug_vals {
-		unsigned long last_jiffies;
-		unsigned cur_intcnt;
-		unsigned last_intcnt;
-		int cur_pllcorr;
-		int last_pllcorr;
-		unsigned int mod_cycles;
-		unsigned int demod_cycles;
-	} debug_vals;
-#endif /* BAYCOM_DEBUG */
 };
 
 /* --------------------------------------------------------------------- */
@@ -259,26 +246,6 @@ static inline int calc_crc_ccitt(const u
 
 #define tenms_to_flags(bc,tenms) ((tenms * bc->bitrate) / 800)
 
-/* --------------------------------------------------------------------- */
-
-static inline void baycom_int_freq(struct baycom_state *bc)
-{
-#ifdef BAYCOM_DEBUG
-	unsigned long cur_jiffies = jiffies;
-	/*
-	 * measure the interrupt frequency
-	 */
-	bc->debug_vals.cur_intcnt++;
-	if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
-		bc->debug_vals.last_jiffies = cur_jiffies;
-		bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
-		bc->debug_vals.cur_intcnt = 0;
-		bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
-		bc->debug_vals.cur_pllcorr = 0;
-	}
-#endif /* BAYCOM_DEBUG */
-}
-
 /* ---------------------------------------------------------------------- */
 /*
  *    eppconfig_path should be setable  via /proc/sys.
@@ -621,13 +588,6 @@ static int receive(struct net_device *de
 	return ret;
 }
 
-/* --------------------------------------------------------------------- */
-
-#define GETTICK(x)						\
-({								\
-	x = (unsigned int)get_cycles();				\
-})
-
 static void epp_bh(struct work_struct *work)
 {
 	struct net_device *dev;
@@ -635,21 +595,17 @@ static void epp_bh(struct work_struct *w
 	struct parport *pp;
 	unsigned char stat;
 	unsigned char tmp[2];
-	unsigned int time1 = 0, time2 = 0, time3 = 0;
 	int cnt, cnt2;
 
 	bc = container_of(work, struct baycom_state, run_work.work);
 	dev = bc->dev;
 	if (!bc->work_running)
 		return;
-	baycom_int_freq(bc);
 	pp = bc->pdev->port;
 	/* update status */
 	if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
 		goto epptimeout;
 	bc->stat = stat;
-	bc->debug_vals.last_pllcorr = stat;
-	GETTICK(time1);
 	if (bc->modem == EPP_FPGAEXTSTATUS) {
 		/* get input count */
 		tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1;
@@ -673,7 +629,6 @@ static void epp_bh(struct work_struct *w
 			goto epptimeout;
 		if (transmit(bc, cnt2, stat))
 			goto epptimeout;
-		GETTICK(time2);
 		if (receive(dev, cnt))
 			goto epptimeout;
 		if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
@@ -700,7 +655,6 @@ static void epp_bh(struct work_struct *w
 		}
 		if (transmit(bc, cnt, stat))
 			goto epptimeout;
-		GETTICK(time2);
 		/* do receiver */
 		while ((stat & (EPP_NRAEF|EPP_NRHF)) != EPP_NRHF) {
 			switch (stat & (EPP_NRAEF|EPP_NRHF)) {
@@ -734,11 +688,6 @@ static void epp_bh(struct work_struct *w
 				goto epptimeout;
 		}
 	}
-	GETTICK(time3);
-#ifdef BAYCOM_DEBUG
-	bc->debug_vals.mod_cycles = time2 - time1;
-	bc->debug_vals.demod_cycles = time3 - time2;
-#endif /* BAYCOM_DEBUG */
 	schedule_delayed_work(&bc->run_work, 1);
 	if (!bc->skb)
 		netif_wake_queue(dev);
author maintainer
#43 lore raw

PATCH 22/38 random: Provide CONFIG_ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

Chasing down to what random_get_entropy() resolves is a 'spot the mouse' game through a maze of #ifdeffery. Also the placement in timex.h is non-obvious and has just been chosen because it provides conveniant access to the underlying get_cycles() #ifdeffery.

Provide a config switch which is selectable by the architecture and a temporary #ifdef guard in timex.h. Architectures which select the config switch must provide asm/random.h with the architecture specific implementation.

Update all usage sites to include linux/random.h so that the gradual conversion does not cause build regressions.

This is part of a larger effort to remove get_cycles() usage from non-architecture code.

Cc "Jason A. Donenfeld" <[email protected]>
---
 arch/Kconfig                     |    3 +++
 arch/loongarch/kernel/relocate.c |    1 +
 arch/mips/kernel/relocate.c      |    1 +
 crypto/jitterentropy-kcapi.c     |    1 +
 include/linux/random.h           |   15 +++++++++++++++
 include/linux/timex.h            |    2 ++
 kernel/kcsan/core.c              |    1 +
 7 files changed, 24 insertions(+)
arch/Kconfig +3 -0
@@ -370,6 +370,9 @@ config ARCH_HAS_CPU_FINALIZE_INIT
 config ARCH_HAS_DELAY_TIMER
 	bool
 
+config ARCH_HAS_RANDOM_ENTROPY
+	bool
+
 # The architecture has a per-task state that includes the mm's PASID
 config ARCH_HAS_CPU_PASID
 	bool
arch/loongarch/kernel/relocate.c +1 -0
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/printk.h>
 #include <linux/panic_notifier.h>
+#include <linux/random.h>
 #include <linux/start_kernel.h>
 #include <asm/bootinfo.h>
 #include <asm/early_ioremap.h>
arch/mips/kernel/relocate.c +1 -0
@@ -19,6 +19,7 @@
 #include <linux/libfdt.h>
 #include <linux/of_fdt.h>
 #include <linux/panic_notifier.h>
+#include <linux/random.h>
 #include <linux/sched/task.h>
 #include <linux/start_kernel.h>
 #include <linux/string.h>
crypto/jitterentropy-kcapi.c +1 -0
@@ -42,6 +42,7 @@
 #include <linux/fips.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/random.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <crypto/internal/rng.h>
include/linux/random.h +15 -0
@@ -139,4 +139,19 @@ int random_online_cpu(unsigned int cpu);
 extern const struct file_operations random_fops, urandom_fops;
 #endif
 
+unsigned long random_get_entropy_fallback(void);
+
+/*
+ * random_get_entropy() is used by the /dev/random driver in order to extract
+ * entropy via the relative unpredictability of when an interrupt takes places
+ * versus a high speed, fine-grained timing source or cycle counter.  Since it
+ * will be occurred on every single interrupt, it must have a very low
+ * cost/overhead.
+ *
+ * If an architecture does not provide it, then use random_get_entropy_fallback().
+ */
+#ifdef CONFIG_ARCH_HAS_RANDOM_ENTROPY
+#include <asm/random.h>
+#endif
+
 #endif /* _LINUX_RANDOM_H */
include/linux/timex.h +2 -0
@@ -66,6 +66,7 @@ unsigned long random_get_entropy_fallbac
 
 #include <asm/timex.h>
 
+#ifndef CONFIG_ARCH_HAS_RANDOM_ENTROPY
 #ifndef random_get_entropy
 /*
  * The random_get_entropy() function is used by the /dev/random driver
@@ -85,6 +86,7 @@ unsigned long random_get_entropy_fallbac
 #define random_get_entropy()	random_get_entropy_fallback()
 #endif
 #endif
+#endif
 
 /*
  * SHIFT_PLL is used as a dampening factor to define how much we
kernel/kcsan/core.c +1 -0
@@ -18,6 +18,7 @@
 #include <linux/moduleparam.h>
 #include <linux/percpu.h>
 #include <linux/preempt.h>
+#include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/uaccess.h>
author maintainer
#44 lore raw

PATCH 23/38 alpha: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch alpha over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

---
 arch/alpha/Kconfig              |    1 +
 arch/alpha/include/asm/random.h |   14 ++++++++++++++
 arch/alpha/include/asm/timex.h  |   26 --------------------------
 3 files changed, 15 insertions(+), 26 deletions(-)
arch/alpha/Kconfig +1 -0
@@ -5,6 +5,7 @@ config ALPHA
 	select ARCH_32BIT_USTAT_F_TINODE
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DMA_OPS if PCI
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_MIGHT_HAVE_PC_SERIO
 	select ARCH_MODULE_NEEDS_WEAK_PER_CPU if SMP
arch/alpha/include/asm/random.h new file +14 -0
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASMALPHA_RANDOM_H
+#define _ASMALPHA_RANDOM_H
+
+/* Use the cycle counter for entropy. */
+static inline unsigned long random_get_entropy(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__ ("rpcc %0" : "=r"(ret));
+	return ret;
+}
+
+#endif
arch/alpha/include/asm/timex.h deleted +0 -26
@@ -1,26 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/asm-alpha/timex.h
- *
- * ALPHA architecture timex specifications
- */
-#ifndef _ASMALPHA_TIMEX_H
-#define _ASMALPHA_TIMEX_H
-
-/*
- * Standard way to access the cycle counter.
- * Currently only used on SMP for scheduling.
- *
- * Only the low 32 bits are available as a continuously counting entity. 
- * But this only means we'll force a reschedule every 8 seconds or so,
- * which isn't an evil thing.
- */
-static inline cycles_t get_cycles (void)
-{
-	cycles_t ret;
-	__asm__ __volatile__ ("rpcc %0" : "=r"(ret));
-	return ret;
-}
-#define get_cycles get_cycles
-
-#endif
maintainer Acked-by Tested-by on v1 23/38
#45 lore raw

Re: [patch 23/38] alpha: Select ARCH_HAS_RANDOM_ENTROPY

Quoted 9 lines · Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch alpha over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

Quoted 8 lines
---
 arch/alpha/Kconfig              |    1 +
 arch/alpha/include/asm/random.h |   14 ++++++++++++++
 arch/alpha/include/asm/timex.h  |   26 --------------------------
 3 files changed, 15 insertions(+), 26 deletions(-)

Hi,

The Alpha side looks fine to me.

I've applied this patch on top of v7.0-rc7, built a kernel successfully, boot-tested it on an Alpha UP2000+ (SMP) without issues.

author maintainer
#46 lore raw

PATCH 24/38 ARM: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch ARM over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

---
 arch/arm/Kconfig              |    1 +
 arch/arm/include/asm/random.h |   14 ++++++++++++++
 arch/arm/include/asm/timex.h  |   18 ------------------
 arch/arm/lib/delay.c          |    4 ++--
 4 files changed, 17 insertions(+), 20 deletions(-)
arch/arm/Kconfig +1 -0
@@ -22,6 +22,7 @@ config ARM
 	select ARCH_HAS_MEMBARRIER_SYNC_CORE
 	select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
 	select ARCH_HAS_PTE_SPECIAL if ARM_LPAE
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SETUP_DMA_OPS
 	select ARCH_HAS_SET_MEMORY
 	select ARCH_STACKWALK
arch/arm/include/asm/random.h new file +14 -0
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASMARM_RANDOM_H
+#define _ASMARM_RANDOM_H
+
+bool delay_read_timer(unsigned long *t);
+
+static inline unsigned long random_get_entropy(void)
+{
+	unsigned long t;
+
+	return delay_read_timer(&t) ? t : random_get_entropy_fallback();
+}
+
+#endif
arch/arm/include/asm/timex.h deleted +0 -18
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *  arch/arm/include/asm/timex.h
- *
- *  Copyright (C) 1997,1998 Russell King
- *
- *  Architecture Specific TIME specifications
- */
-#ifndef _ASMARM_TIMEX_H
-#define _ASMARM_TIMEX_H
-
-// Temporary workaround
-bool delay_read_timer(unsigned long *t);
-
-#define get_cycles()	({ cycles_t c; delay_read_timer(&c) ? 0 : c; })
-#define random_get_entropy() (((unsigned long)get_cycles()) ?: random_get_entropy_fallback())
-
-#endif
arch/arm/lib/delay.c +2 -2
@@ -42,9 +42,9 @@ static inline u64 cyc_to_ns(u64 cyc, u32
 
 static void __timer_delay(unsigned long cycles)
 {
-	cycles_t start = get_cycles();
+	cycles_t start = delay_timer->read_current_timer();
 
-	while ((get_cycles() - start) < cycles)
+	while ((delay_timer->read_current_timer() - start) < cycles)
 		cpu_relax();
 }
 
author maintainer
#47 lore raw

PATCH 25/38 arm64: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch arm64 over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

As a consequence this unearthed a nasty include dependecy hell where random code including rqspinlock.h relies on a magic include of asm/arch_timer.h. Including the headers in asm/random.h turned out to be impossible as well.

The only solution for now is to uninline random_get_entropy(). Fix up all other dependencies on the content of asm/timex.h in those files which really depend on it.

Remove asm/timex.h as it has no functionality anymore.

---
 arch/arm64/Kconfig                      |    1 +
 arch/arm64/include/asm/io.h             |    5 +++--
 arch/arm64/include/asm/random.h         |   11 +++++++++++
 arch/arm64/include/asm/rqspinlock.h     |    1 +
 arch/arm64/include/asm/timex.h          |   18 ------------------
 arch/arm64/kernel/time.c                |    6 ++++++
 arch/arm64/kernel/topology.c            |    1 +
 arch/arm64/kernel/traps.c               |    1 +
 arch/arm64/kvm/emulate-nested.c         |    1 +
 arch/arm64/kvm/hyp/include/hyp/switch.h |    1 +
 arch/arm64/lib/delay.c                  |    1 +
 drivers/irqchip/irq-apple-aic.c         |    1 +
 12 files changed, 28 insertions(+), 20 deletions(-)
arch/arm64/Kconfig +1 -0
@@ -45,6 +45,7 @@ config ARM64
 	select ARCH_HAS_PREEMPT_LAZY
 	select ARCH_HAS_PTDUMP
 	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_HW_PTE_YOUNG
 	select ARCH_HAS_SETUP_DMA_OPS
 	select ARCH_HAS_SET_DIRECT_MAP
arch/arm64/include/asm/io.h +3 -2
@@ -100,12 +100,13 @@ static __always_inline u64 __raw_readq(c
 ({									\
 	unsigned long tmp;						\
 									\
-	dma_rmb();								\
+	dma_rmb();							\
 									\
 	/*								\
 	 * Create a dummy control dependency from the IO read to any	\
 	 * later instructions. This ensures that a subsequent call to	\
-	 * udelay() will be ordered due to the ISB in get_cycles().	\
+	 * udelay() will be ordered due to the ISB in			\
+	 * arm_timer_read_counter().					\
 	 */								\
 	asm volatile("eor	%0, %1, %1\n"				\
 		     "cbnz	%0, ."					\
arch/arm64/include/asm/random.h new file +11 -0
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ */
+#ifndef __ASM_RANDOM_H
+#define __ASM_RANDOM_H
+
+/* Out of line to avoid recursive include hell */
+unsigned long random_get_entropy(void);
+
+#endif
arch/arm64/include/asm/rqspinlock.h +1 -0
@@ -2,6 +2,7 @@
 #ifndef _ASM_RQSPINLOCK_H
 #define _ASM_RQSPINLOCK_H
 
+#include <asm/arch_timer.h>
 #include <asm/barrier.h>
 
 /*
arch/arm64/include/asm/timex.h deleted +0 -18
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2012 ARM Ltd.
- */
-#ifndef __ASM_TIMEX_H
-#define __ASM_TIMEX_H
-
-#include <asm/arch_timer.h>
-
-/*
- * Use the current timer as a cycle counter since this is what we use for
- * the delay loop.
- */
-#define get_cycles()	arch_timer_read_counter()
-
-#include <asm-generic/timex.h>
-
-#endif
arch/arm64/kernel/time.c +6 -0
@@ -29,6 +29,7 @@
 
 #include <clocksource/arm_arch_timer.h>
 
+#include <asm/arch_timer.h>
 #include <asm/thread_info.h>
 #include <asm/paravirt.h>
 
@@ -52,6 +53,11 @@ unsigned long profile_pc(struct pt_regs
 }
 EXPORT_SYMBOL(profile_pc);
 
+static unsigned long random_get_entropy(void)
+{
+	return arch_timer_read_counter();
+}
+
 void __init time_init(void)
 {
 	u32 arch_timer_rate;
arch/arm64/kernel/topology.c +1 -0
@@ -21,6 +21,7 @@
 #include <linux/sched/isolation.h>
 #include <linux/xarray.h>
 
+#include <asm/arch_timer.h>
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/topology.h>
arch/arm64/kernel/traps.c +1 -0
@@ -30,6 +30,7 @@
 #include <linux/ubsan.h>
 #include <linux/cfi.h>
 
+#include <asm/arch_timer.h>
 #include <asm/atomic.h>
 #include <asm/bug.h>
 #include <asm/cpufeature.h>
arch/arm64/kvm/emulate-nested.c +1 -0
@@ -7,6 +7,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 
+#include <asm/arch_timer.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_nested.h>
 
arch/arm64/kvm/hyp/include/hyp/switch.h +1 -0
@@ -18,6 +18,7 @@
 
 #include <kvm/arm_psci.h>
 
+#include <asm/arch_timer.h>
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
 #include <asm/extable.h>
arch/arm64/lib/delay.c +1 -0
@@ -14,6 +14,7 @@
 #include <linux/timex.h>
 
 #include <clocksource/arm_arch_timer.h>
+#include <asm/arch_timer.h>
 
 #define USECS_TO_CYCLES(time_usecs)			\
 	xloops_to_cycles((time_usecs) * 0x10C7UL)
drivers/irqchip/irq-apple-aic.c +1 -0
@@ -55,6 +55,7 @@
 #include <linux/jump_label.h>
 #include <linux/limits.h>
 #include <linux/of_address.h>
+#include <asm/arch_timer.h>
 #include <linux/slab.h>
 #include <asm/apple_m1_pmu.h>
 #include <asm/cputype.h>
author maintainer
#48 lore raw

PATCH 26/38 loongarch: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch loongarch over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

---
 arch/loongarch/Kconfig              |    1 +
 arch/loongarch/include/asm/random.h |   15 +++++++++++++++
 arch/loongarch/kernel/syscall.c     |    1 +
 arch/loongarch/lib/delay.c          |    2 +-
 4 files changed, 18 insertions(+), 1 deletion(-)
arch/loongarch/Kconfig +1 -0
@@ -26,6 +26,7 @@ config LOONGARCH
 	select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
 	select ARCH_HAS_PREEMPT_LAZY
 	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SET_MEMORY
 	select ARCH_HAS_SET_DIRECT_MAP
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
arch/loongarch/include/asm/random.h new file +15 -0
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+#ifndef _ASM_RANDOM_H
+#define _ASM_RANDOM_H
+
+#include <asm/timex.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return get_cycles();
+}
+
+#endif /*  _ASM_RANDOM_H */
arch/loongarch/kernel/syscall.c +1 -0
@@ -19,6 +19,7 @@
 #include <asm/loongarch.h>
 #include <asm/signal.h>
 #include <asm/switch_to.h>
+#include <asm/timex.h>
 #include <asm-generic/syscalls.h>
 
 #undef __SYSCALL
arch/loongarch/lib/delay.c +1 -1
@@ -5,9 +5,9 @@
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/smp.h>
-#include <linux/timex.h>
 
 #include <asm/processor.h>
+#include <asm/timex.h>
 
 void __delay(unsigned long cycles)
 {
author maintainer
#49 lore raw

PATCH 27/38 m68k: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch m68k over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

---
 arch/m68k/Kconfig              |    1 +
 arch/m68k/amiga/config.c       |    1 +
 arch/m68k/include/asm/random.h |   14 ++++++++++++++
 arch/m68k/include/asm/timex.h  |   25 -------------------------
 arch/m68k/kernel/time.c        |    2 +-
 5 files changed, 17 insertions(+), 26 deletions(-)
arch/m68k/Kconfig +1 -0
@@ -8,6 +8,7 @@ config M68K
 	select ARCH_HAS_CPU_FINALIZE_INIT if MMU
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DMA_PREP_COHERENT if M68K_NONCOHERENT_DMA && !COLDFIRE
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SYNC_DMA_FOR_DEVICE if M68K_NONCOHERENT_DMA
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
 	select ARCH_MIGHT_HAVE_PC_PARPORT if ISA
arch/m68k/amiga/config.c +1 -0
@@ -36,6 +36,7 @@
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/config.h>
+#include <asm/random.h>
 
 #include "amiga.h"
 
arch/m68k/include/asm/random.h new file +14 -0
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASMm68K_RANDOM_H
+#define _ASMm68K_RANDOM_H
+
+extern unsigned long (*mach_random_get_entropy)(void);
+
+static inline unsigned long random_get_entropy(void)
+{
+	if (mach_random_get_entropy)
+		return mach_random_get_entropy();
+	return random_get_entropy_fallback();
+}
+
+#endif
arch/m68k/include/asm/timex.h deleted +0 -25
@@ -1,25 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/asm-m68k/timex.h
- *
- * m68k architecture timex specifications
- */
-#ifndef _ASMm68K_TIMEX_H
-#define _ASMm68K_TIMEX_H
-
-static inline cycles_t get_cycles(void)
-{
-	return 0;
-}
-
-extern unsigned long (*mach_random_get_entropy)(void);
-
-static inline unsigned long random_get_entropy(void)
-{
-	if (mach_random_get_entropy)
-		return mach_random_get_entropy();
-	return random_get_entropy_fallback();
-}
-#define random_get_entropy	random_get_entropy
-
-#endif
arch/m68k/kernel/time.c +1 -1
@@ -26,12 +26,12 @@
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/irq_regs.h>
+#include <asm/random.h>
 
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/profile.h>
 
-
 unsigned long (*mach_random_get_entropy)(void);
 EXPORT_SYMBOL_GPL(mach_random_get_entropy);
 
Tested-by on v1 27/38
#50 lore raw

Re: [patch 27/38] m68k: Select ARCH_HAS_RANDOM_ENTROPY

Hi

Quoted 6 lines · Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch m68k over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

I have built and booted this on my Amiga 4000 and it apparently still works so FWIW:

maintainer Reviewed-by Acked-by on v1 27/38
#51 lore raw

Re: [patch 27/38] m68k: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner
Quoted 9 lines · Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch m68k over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

author maintainer
#52 lore raw

PATCH 28/38 mips: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch mips over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

As a consequence this unearthed a nasty include dependency hell because arbitrary code relies on a magic include of asm/timex.h. Including the headers in asm/random.h turned out to be impossible as well.

The only solution for now is to uninline random_get_entropy(). Fix up all other dependencies on the content of asm/timex.h in those files which really depend on it.

Remove asm/timex.h as it has no functionality anymore.

---
 arch/mips/Kconfig              |    1 
 arch/mips/generic/init.c       |    1 
 arch/mips/include/asm/random.h |    7 +++
 arch/mips/include/asm/timex.h  |   92 -----------------------------------------
 arch/mips/kernel/pm-cps.c      |    1 
 arch/mips/kernel/proc.c        |    1 
 arch/mips/kernel/relocate.c    |    1 
 arch/mips/kernel/time.c        |   53 +++++++++++++++++++++++
 arch/mips/lib/dump_tlb.c       |    1 
 arch/mips/mm/cache.c           |    1 
 10 files changed, 66 insertions(+), 93 deletions(-)
arch/mips/Kconfig +1 -0
@@ -19,6 +19,7 @@ config MIPS
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_HAS_UBSAN
 	select ARCH_HAS_GCOV_PROFILE_ALL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_KEEP_MEMBLOCK
 	select ARCH_USE_BUILTIN_BSWAP
 	select ARCH_USE_CMPXCHG_LOCKREF if 64BIT
arch/mips/generic/init.c +1 -0
@@ -12,6 +12,7 @@
 #include <linux/of_fdt.h>
 
 #include <asm/bootinfo.h>
+#include <asm/cpu-type.h>
 #include <asm/fw/fw.h>
 #include <asm/irq_cpu.h>
 #include <asm/machine.h>
arch/mips/include/asm/random.h new file +7 -0
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-v2.0-only */
+#ifndef _ASM_RANDOM_H
+#define _ASM_RANDOM_H
+
+unsigned long random_get_entropy(void);
+
+#endif /*  _ASM_RANDOM_H */
arch/mips/include/asm/timex.h deleted +0 -92

92 lines not on this page · raw message

arch/mips/kernel/pm-cps.c +1 -0
@@ -13,6 +13,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/cacheflush.h>
 #include <asm/cacheops.h>
+#include <asm/cpu-type.h>
 #include <asm/idle.h>
 #include <asm/mips-cps.h>
 #include <asm/mipsmtregs.h>
arch/mips/kernel/proc.c +1 -0
@@ -11,6 +11,7 @@
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
+#include <asm/cpu-type.h>
 #include <asm/idle.h>
 #include <asm/mipsregs.h>
 #include <asm/processor.h>
arch/mips/kernel/relocate.c +0 -1
@@ -13,7 +13,6 @@
 #include <asm/fw/fw.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
-#include <asm/timex.h>
 #include <linux/elf.h>
 #include <linux/kernel.h>
 #include <linux/libfdt.h>
arch/mips/kernel/time.c +53 -0

74 lines not on this page · raw message

arch/mips/lib/dump_tlb.c +1 -0
@@ -8,6 +8,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 
+#include <asm/cpu-type.h>
 #include <asm/hazards.h>
 #include <asm/mipsregs.h>
 #include <asm/mmu_context.h>
arch/mips/mm/cache.c +1 -0
@@ -22,6 +22,7 @@
 #include <asm/processor.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
+#include <asm/cpu-type.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
 
#53 lore raw

Re: [patch 28/38] mips: Select ARCH_HAS_RANDOM_ENTROPY

Quoted 3 lines · Thomas Gleixner

The only solution for now is to uninline random_get_entropy(). Fix up all other dependencies on the content of asm/timex.h in those files which really depend on it.

Oh dear! I'd yet have to fully evaluate the consequences, but offhand
this has clearly turned what compiles to a single CPU instruction on the vast majority of MIPS platforms into an expensive function call, possibly also changing the caller from a leaf to a nested function with all the associated execution penalty. Is there no other way?

Cf. commit 06947aaaf9bf ("MIPS: Implement random_get_entropy with CP0
Random").

Maciej

author maintainer
#54 lore raw

PATCH 29/38 nios2: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch nios2 over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

---
 arch/nios2/Kconfig              |    1 +
 arch/nios2/include/asm/random.h |   14 ++++++++++++++
 arch/nios2/include/asm/timex.h  |    5 +----
 arch/nios2/kernel/time.c        |    4 ++--
 4 files changed, 18 insertions(+), 6 deletions(-)
arch/nios2/Kconfig +1 -0
@@ -7,6 +7,7 @@ config NIOS2
 	select ARCH_HAS_SYNC_DMA_FOR_CPU
 	select ARCH_HAS_SYNC_DMA_FOR_DEVICE
 	select ARCH_HAS_DMA_SET_UNCACHED
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_NO_SWAP
 	select COMMON_CLK
 	select TIMER_OF
arch/nios2/include/asm/random.h new file +14 -0
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_NIOS2_RANDOM_H
+#define _ASM_NIOS2_RANDOM_H
+
+#include <asm/timex.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	unsigned long c = get_cycles();
+
+	return c ? c : random_get_entropy_fallback();
+}
+
+#endif
arch/nios2/include/asm/timex.h +1 -4
@@ -5,9 +5,6 @@
 #ifndef _ASM_NIOS2_TIMEX_H
 #define _ASM_NIOS2_TIMEX_H
 
-extern cycles_t get_cycles(void);
-#define get_cycles get_cycles
-
-#define random_get_entropy() (((unsigned long)get_cycles()) ?: random_get_entropy_fallback())
+cycles_t get_cycles(void);
 
 #endif
arch/nios2/kernel/time.c +2 -2
@@ -7,7 +7,6 @@
  * License. See the file "COPYING" in the main directory of this archive
  * for more details.
  */
-
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/clockchips.h>
@@ -19,6 +18,8 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 
+#include <asm/timex.h>
+
 #define ALTR_TIMER_COMPATIBLE		"altr,timer-1.0"
 
 #define ALTERA_TIMER_STATUS_REG	0
@@ -112,7 +113,6 @@ cycles_t get_cycles(void)
 		return nios2_timer_read(&nios2_cs.cs);
 	return 0;
 }
-EXPORT_SYMBOL(get_cycles);
 
 static void nios2_timer_start(struct nios2_timer *timer)
 {
author maintainer
#55 lore raw

PATCH 30/38 openrisc: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch openrisc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

---
 arch/openrisc/Kconfig              |    1 +
 arch/openrisc/include/asm/random.h |   12 ++++++++++++
 arch/openrisc/include/asm/timex.h  |    5 -----
 arch/openrisc/lib/delay.c          |    1 +
 4 files changed, 14 insertions(+), 5 deletions(-)
arch/openrisc/Kconfig +1 -0
@@ -10,6 +10,7 @@ config OPENRISC
 	select ARCH_HAS_DELAY_TIMER
 	select ARCH_HAS_DMA_SET_UNCACHED
 	select ARCH_HAS_DMA_CLEAR_UNCACHED
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SYNC_DMA_FOR_DEVICE
 	select GENERIC_BUILTIN_DTB
 	select COMMON_CLK
arch/openrisc/include/asm/random.h new file +12 -0
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __ASM_OPENRISC_RANDOM_H
+#define __ASM_OPENRISC_RANDOM_H
+
+#include <asm/timex.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return get_cycles();
+}
+
+#endif
arch/openrisc/include/asm/timex.h +0 -5
@@ -9,13 +9,9 @@
  * OpenRISC implementation:
  * Copyright (C) 2010-2011 Jonas Bonn <[email protected]>
  */
-
 #ifndef __ASM_OPENRISC_TIMEX_H
 #define __ASM_OPENRISC_TIMEX_H
 
-#define get_cycles get_cycles
-
-#include <asm-generic/timex.h>
 #include <asm/spr.h>
 #include <asm/spr_defs.h>
 
@@ -23,6 +19,5 @@ static inline cycles_t get_cycles(void)
 {
 	return mfspr(SPR_TTCR);
 }
-#define get_cycles get_cycles
 
 #endif
arch/openrisc/lib/delay.c +1 -0
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 
 #include <asm/param.h>
+#include <asm/timex.h>
 #include <asm/processor.h>
 
 bool delay_read_timer(unsigned long *timer_value)
maintainer Acked-by on v1 30/38
#56 lore raw

Re: [patch 30/38] openrisc: Select ARCH_HAS_RANDOM_ENTROPY

Quoted 6 lines · Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch openrisc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Quoted 6 lines

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

This looks good to me.

Quoted 67 lines
---
 arch/openrisc/Kconfig              |    1 +
 arch/openrisc/include/asm/random.h |   12 ++++++++++++
 arch/openrisc/include/asm/timex.h  |    5 -----
 arch/openrisc/lib/delay.c          |    1 +
 4 files changed, 14 insertions(+), 5 deletions(-)
arch/openrisc/Kconfig +1 -0
@@ -10,6 +10,7 @@ config OPENRISC
 	select ARCH_HAS_DELAY_TIMER
 	select ARCH_HAS_DMA_SET_UNCACHED
 	select ARCH_HAS_DMA_CLEAR_UNCACHED
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SYNC_DMA_FOR_DEVICE
 	select GENERIC_BUILTIN_DTB
 	select COMMON_CLK
arch/openrisc/include/asm/random.h new file +12 -0
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __ASM_OPENRISC_RANDOM_H
+#define __ASM_OPENRISC_RANDOM_H
+
+#include <asm/timex.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return get_cycles();
+}
+
+#endif
arch/openrisc/include/asm/timex.h +0 -5
@@ -9,13 +9,9 @@
  * OpenRISC implementation:
  * Copyright (C) 2010-2011 Jonas Bonn <[email protected]>
  */
-
 #ifndef __ASM_OPENRISC_TIMEX_H
 #define __ASM_OPENRISC_TIMEX_H
 
-#define get_cycles get_cycles
-
-#include <asm-generic/timex.h>
 #include <asm/spr.h>
 #include <asm/spr_defs.h>
 
@@ -23,6 +19,5 @@ static inline cycles_t get_cycles(void)
 {
 	return mfspr(SPR_TTCR);
 }
-#define get_cycles get_cycles
 
 #endif
arch/openrisc/lib/delay.c +1 -0
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 
 #include <asm/param.h>
+#include <asm/timex.h>
 #include <asm/processor.h>
 
 bool delay_read_timer(unsigned long *timer_value)
author maintainer
#57 lore raw

PATCH 31/38 parisc: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch parisc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

---
 arch/parisc/Kconfig              |    1 +
 arch/parisc/include/asm/random.h |   12 ++++++++++++
 arch/parisc/include/asm/timex.h  |    6 ------
 arch/parisc/kernel/processor.c   |    1 +
 arch/parisc/kernel/time.c        |    1 +
 5 files changed, 15 insertions(+), 6 deletions(-)
arch/parisc/Kconfig +1 -0
@@ -16,6 +16,7 @@ config PARISC
 	select ARCH_HAS_STRICT_MODULE_RWX
 	select ARCH_HAS_UBSAN
 	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_NO_SG_CHAIN
 	select ARCH_SPLIT_ARG64 if !64BIT
 	select ARCH_SUPPORTS_HUGETLBFS if PA20
arch/parisc/include/asm/random.h new file +12 -0
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASMPARISC_RANDOM_H
+#define _ASMPARISC_RANDOM_H
+
+#include <asm/timex.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return get_cycles();
+}
+
+#endif
arch/parisc/include/asm/timex.h +0 -6
@@ -1,9 +1,4 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/asm-parisc/timex.h
- *
- * PARISC architecture timex specifications
- */
 #ifndef _ASMPARISC_TIMEX_H
 #define _ASMPARISC_TIMEX_H
 
@@ -13,6 +8,5 @@ static inline cycles_t get_cycles(void)
 {
 	return mfctl(16);
 }
-#define get_cycles get_cycles
 
 #endif
arch/parisc/kernel/processor.c +1 -0
@@ -30,6 +30,7 @@
 #include <asm/pdcpat.h>
 #include <asm/irq.h>		/* for struct irq_region */
 #include <asm/parisc-device.h>
+#include <asm/timex.h>
 
 struct system_cpuinfo_parisc boot_cpu_data __ro_after_init;
 EXPORT_SYMBOL(boot_cpu_data);
arch/parisc/kernel/time.c +1 -0
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <asm/processor.h>
 #include <asm/pdcpat.h>
+#include <asm/timex.h>
 
 static u64 cr16_clock_freq;
 static unsigned long clocktick;
maintainer Tested-by on v1 31/38
#58 lore raw

Re: [patch 31/38] parisc: Select ARCH_HAS_RANDOM_ENTROPY

Quoted 12 lines · Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch parisc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

Quoted 7 lines
---
  arch/parisc/Kconfig              |    1 +
  arch/parisc/include/asm/random.h |   12 ++++++++++++
  arch/parisc/include/asm/timex.h  |    6 ------
  arch/parisc/kernel/processor.c   |    1 +
  arch/parisc/kernel/time.c        |    1 +
  5 files changed, 15 insertions(+), 6 deletions(-)

I tested this series on parisc.
Works as expected.

Thanks!
Helge

author maintainer
#59 lore raw

PATCH 32/38 powerpc/spufs: Use mftb() directly

In reply to Thomas Gleixner

There is no reason to indirect via get_cycles(), which is about to be removed.

Use mftb() directly.

---
 arch/powerpc/platforms/cell/spufs/switch.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
arch/powerpc/platforms/cell/spufs/switch.c +3 -2
@@ -34,6 +34,7 @@
 #include <asm/spu_priv1.h>
 #include <asm/spu_csa.h>
 #include <asm/mmu_context.h>
+#include <asm/time.h>
 
 #include "spufs.h"
 
@@ -279,7 +280,7 @@ static inline void save_timebase(struct
 	 *    Read PPE Timebase High and Timebase low registers
 	 *    and save in CSA.  TBD.
 	 */
-	csa->suspend_time = get_cycles();
+	csa->suspend_time = mftb();
 }
 
 static inline void remove_other_spu_access(struct spu_state *csa,
@@ -1261,7 +1262,7 @@ static inline void setup_decr(struct spu
 	 *     in LSCSA.
 	 */
 	if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) {
-		cycles_t resume_time = get_cycles();
+		cycles_t resume_time = mftb();
 		cycles_t delta_time = resume_time - csa->suspend_time;
 
 		csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
reviewer Reviewed-by on v1 32/38
#61 lore raw

Re: [patch 32/38] powerpc/spufs: Use mftb() directly

In reply to Thomas Gleixner

Le 10/04/2026 à 14:21, Thomas Gleixner a écrit :

Quoted 8 lines

There is no reason to indirect via get_cycles(), which is about to be removed.

Use mftb() directly.

Quoted 34 lines
---
  arch/powerpc/platforms/cell/spufs/switch.c |    5 +++--
  1 file changed, 3 insertions(+), 2 deletions(-)
arch/powerpc/platforms/cell/spufs/switch.c +3 -2
@@ -34,6 +34,7 @@
  #include <asm/spu_priv1.h>
  #include <asm/spu_csa.h>
  #include <asm/mmu_context.h>
+#include <asm/time.h>
 
  #include "spufs.h"
 
@@ -279,7 +280,7 @@ static inline void save_timebase(struct
  	 *    Read PPE Timebase High and Timebase low registers
  	 *    and save in CSA.  TBD.
  	 */
-	csa->suspend_time = get_cycles();
+	csa->suspend_time = mftb();
  }
 
  static inline void remove_other_spu_access(struct spu_state *csa,
@@ -1261,7 +1262,7 @@ static inline void setup_decr(struct spu
  	 *     in LSCSA.
  	 */
  	if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) {
-		cycles_t resume_time = get_cycles();
+		cycles_t resume_time = mftb();
  		cycles_t delta_time = resume_time - csa->suspend_time;
 
  		csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
Reviewed-by on v1 32/38
#62 lore raw

Re: [patch 32/38] powerpc/spufs: Use mftb() directly

In reply to Thomas Gleixner
Quoted 33 lines · Thomas Gleixner

There is no reason to indirect via get_cycles(), which is about to be removed.

Use mftb() directly.

---
 arch/powerpc/platforms/cell/spufs/switch.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
arch/powerpc/platforms/cell/spufs/switch.c +2 -1
@@ -34,6 +34,7 @@
 #include <asm/spu_priv1.h>
 #include <asm/spu_csa.h>
 #include <asm/mmu_context.h>
+#include <asm/time.h>
 
 #include "spufs.h"
 
@@ -279,7 +280,7 @@ static inline void save_timebase(struct
 	 *    Read PPE Timebase High and Timebase low registers
 	 *    and save in CSA.  TBD.
 	 */
-	csa->suspend_time = get_cycles();
+	csa->suspend_time = mftb();
 }
 
 static inline void remove_other_spu_access(struct spu_state *csa,

arch/powerpc/platforms/cell/spufs/switch.c static inline void setup_decr(struct spu · line 1268

Quoted 8 lines
arch/powerpc/platforms/cell/spufs/switch.c +1 -1
@@ -1261,7 +1262,7 @@ static inline void setup_decr(struct spu
 	 *     in LSCSA.
 	 */
 	if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) {
-		cycles_t resume_time = get_cycles();
+		cycles_t resume_time = mftb();
 		cycles_t delta_time = resume_time - csa->suspend_time;
 
 		csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
author maintainer
#63 lore raw

PATCH 33/38 powerpc: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch powerpc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

---
 arch/powerpc/Kconfig              |    1 +
 arch/powerpc/include/asm/random.h |   13 +++++++++++++
 arch/powerpc/include/asm/timex.h  |   21 ---------------------
 3 files changed, 14 insertions(+), 21 deletions(-)
arch/powerpc/Kconfig +1 -0
@@ -150,6 +150,7 @@ config PPC
 	select ARCH_HAS_PREEMPT_LAZY
 	select ARCH_HAS_PTDUMP
 	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SCALED_CPUTIME		if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
 	select ARCH_HAS_SET_MEMORY
 	select ARCH_HAS_STRICT_KERNEL_RWX	if (PPC_BOOK3S || PPC_8xx) && !HIBERNATION
arch/powerpc/include/asm/random.h new file +13 -0
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_RANDOM_H
+#define _ASM_POWERPC_RANDOM_H
+
+#include <asm/cputable.h>
+#include <asm/vdso/timebase.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return mftb();
+}
+
+#endif	/* _ASM_POWERPC_RANDOM_H */
arch/powerpc/include/asm/timex.h +0 -21
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_POWERPC_TIMEX_H
-#define _ASM_POWERPC_TIMEX_H
-
-#ifdef __KERNEL__
-
-/*
- * PowerPC architecture timex specifications
- */
-
-#include <asm/cputable.h>
-#include <asm/vdso/timebase.h>
-
-ostatic inline cycles_t get_cycles(void)
-{
-	return mftb();
-}
-#define get_cycles get_cycles
-
-#endif	/* __KERNEL__ */
-#endif	/* _ASM_POWERPC_TIMEX_H */
reviewer Reviewed-by on v1 33/38
#64 lore raw

Re: [patch 33/38] powerpc: Select ARCH_HAS_RANDOM_ENTROPY

Le 10/04/2026 à 14:21, Thomas Gleixner a écrit :

Quoted 10 lines

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch powerpc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

Quoted 58 lines
---
  arch/powerpc/Kconfig              |    1 +
  arch/powerpc/include/asm/random.h |   13 +++++++++++++
  arch/powerpc/include/asm/timex.h  |   21 ---------------------
  3 files changed, 14 insertions(+), 21 deletions(-)
arch/powerpc/Kconfig +1 -0
@@ -150,6 +150,7 @@ config PPC
  	select ARCH_HAS_PREEMPT_LAZY
  	select ARCH_HAS_PTDUMP
  	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
  	select ARCH_HAS_SCALED_CPUTIME		if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
  	select ARCH_HAS_SET_MEMORY
  	select ARCH_HAS_STRICT_KERNEL_RWX	if (PPC_BOOK3S || PPC_8xx) && !HIBERNATION
arch/powerpc/include/asm/random.h new file +13 -0
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_RANDOM_H
+#define _ASM_POWERPC_RANDOM_H
+
+#include <asm/cputable.h>
+#include <asm/vdso/timebase.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return mftb();
+}
+
+#endif	/* _ASM_POWERPC_RANDOM_H */
arch/powerpc/include/asm/timex.h +0 -21
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_POWERPC_TIMEX_H
-#define _ASM_POWERPC_TIMEX_H
-
-#ifdef __KERNEL__
-
-/*
- * PowerPC architecture timex specifications
- */
-
-#include <asm/cputable.h>
-#include <asm/vdso/timebase.h>
-
-ostatic inline cycles_t get_cycles(void)
-{
-	return mftb();
-}
-#define get_cycles get_cycles
-
-#endif	/* __KERNEL__ */
-#endif	/* _ASM_POWERPC_TIMEX_H */
Tested-by Reviewed-by on v1 33/38
#65 lore raw

Re: [patch 33/38] powerpc: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner
Quoted 50 lines · Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch powerpc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

---
 arch/powerpc/Kconfig              |    1 +
 arch/powerpc/include/asm/random.h |   13 +++++++++++++
 arch/powerpc/include/asm/timex.h  |   21 ---------------------
 3 files changed, 14 insertions(+), 21 deletions(-)
arch/powerpc/Kconfig +1 -0
@@ -150,6 +150,7 @@ config PPC
 	select ARCH_HAS_PREEMPT_LAZY
 	select ARCH_HAS_PTDUMP
 	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SCALED_CPUTIME		if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
 	select ARCH_HAS_SET_MEMORY
 	select ARCH_HAS_STRICT_KERNEL_RWX	if (PPC_BOOK3S || PPC_8xx) && !HIBERNATION
arch/powerpc/include/asm/random.h new file +13 -0
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_RANDOM_H
+#define _ASM_POWERPC_RANDOM_H
+
+#include <asm/cputable.h>
+#include <asm/vdso/timebase.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return mftb();
+}
+
+#endif	/* _ASM_POWERPC_RANDOM_H */
arch/powerpc/include/asm/timex.h +0 -5
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_POWERPC_TIMEX_H
-#define _ASM_POWERPC_TIMEX_H
-
-#ifdef __KERNEL__

arch/powerpc/include/asm/timex.h line 15

Quoted 10 lines
arch/powerpc/include/asm/timex.h +0 -10
-
-/*
- * PowerPC architecture timex specifications
- */
-
-#include <asm/cputable.h>
-#include <asm/vdso/timebase.h>
-
-ostatic inline cycles_t get_cycles(void)
-{

R> - return mftb();

arch/powerpc/include/asm/timex.h line 21

Quoted 6 lines
arch/powerpc/include/asm/timex.h +0 -5
-}
-#define get_cycles get_cycles
-
-#endif	/* __KERNEL__ */
-#endif	/* _ASM_POWERPC_TIMEX_H */

Build tested for this series with allmodconfig and allyesconfig on ppc64le machine for ppc64le.
tree: git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git getcycles-v1

Boot tested for this series on powernv9 qemu, powernv10 qemu and pSeries power11 hardware.

author maintainer
#66 lore raw

PATCH 34/38 riscv: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch riscv over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

---
 arch/riscv/Kconfig                         |    1 +
 arch/riscv/include/asm/random.h            |   25 +++++++++++++++++++++++++
 arch/riscv/include/asm/timex.h             |   13 -------------
 arch/riscv/kernel/unaligned_access_speed.c |    1 +
 arch/riscv/kvm/vcpu_timer.c                |    1 +
 arch/riscv/lib/delay.c                     |    1 +
 6 files changed, 29 insertions(+), 13 deletions(-)
arch/riscv/Kconfig +1 -0
@@ -47,6 +47,7 @@ config RISCV
 	select ARCH_HAS_PREPARE_SYNC_CORE_CMD
 	select ARCH_HAS_PTDUMP if MMU
 	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SET_DIRECT_MAP if MMU
 	select ARCH_HAS_SET_MEMORY if MMU
 	select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
arch/riscv/include/asm/random.h new file +25 -0
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_RISCV_RANDOM_H
+#define _ASM_RISCV_RANDOM_H
+
+#include <asm/timex.h>
+
+#ifdef CONFIG_RISCV_M_MODE
+/*
+ * Much like MIPS, we may not have a viable counter to use at an early point
+ * in the boot process. Unfortunately we don't have a fallback, so instead
+ * invoke the fallback function.
+ */
+static inline unsigned long random_get_entropy(void)
+{
+	if (unlikely(clint_time_val == NULL))
+		return random_get_entropy_fallback();
+	return get_cycles();
+}
+#else  /* !CONFIG_RISCV_M_MODE */
+static inline unsigned long random_get_entropy(void)
+{
+	return get_cycles();
+}
+#endif /* CONFIG_RISCV_M_MODE */
+#endif /* _ASM_RISCV_RANDOM_H */
arch/riscv/include/asm/timex.h +0 -13
@@ -31,19 +31,6 @@ static inline u32 get_cycles_hi(void)
 #define get_cycles_hi get_cycles_hi
 #endif /* CONFIG_64BIT */
 
-/*
- * Much like MIPS, we may not have a viable counter to use at an early point
- * in the boot process. Unfortunately we don't have a fallback, so instead
- * we just return 0.
- */
-static inline unsigned long random_get_entropy(void)
-{
-	if (unlikely(clint_time_val == NULL))
-		return random_get_entropy_fallback();
-	return get_cycles();
-}
-#define random_get_entropy()	random_get_entropy()
-
 #else /* CONFIG_RISCV_M_MODE */
 
 static inline cycles_t get_cycles(void)
arch/riscv/kernel/unaligned_access_speed.c +1 -0
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <asm/cpufeature.h>
 #include <asm/hwprobe.h>
+#include <asm/timex.h>
 #include <asm/vector.h>
 
 #include "copy-unaligned.h"
arch/riscv/kvm/vcpu_timer.c +1 -0
@@ -14,6 +14,7 @@
 #include <asm/delay.h>
 #include <asm/kvm_nacl.h>
 #include <asm/kvm_vcpu_timer.h>
+#include <asm/timex.h>
 
 static u64 kvm_riscv_current_cycles(struct kvm_guest_timer *gt)
 {
arch/riscv/lib/delay.c +1 -0
@@ -10,6 +10,7 @@
 #include <linux/export.h>
 
 #include <asm/processor.h>
+#include <asm/timex.h>
 
 /*
  * This is copies from arch/arm/include/asm/delay.h
author maintainer
#67 lore raw

PATCH 35/38 s390: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch s390 over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

---
 arch/s390/Kconfig              |    1 +
 arch/s390/include/asm/random.h |   12 ++++++++++++
 arch/s390/include/asm/timex.h  |    6 ------
 arch/s390/kernel/time.c        |    1 +
 arch/s390/kernel/vtime.c       |    1 +
 5 files changed, 15 insertions(+), 6 deletions(-)
arch/s390/Kconfig +1 -0
@@ -108,6 +108,7 @@ config S390
 	select ARCH_HAS_PREEMPT_LAZY
 	select ARCH_HAS_PTDUMP
 	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_SCALED_CPUTIME
 	select ARCH_HAS_SET_DIRECT_MAP
 	select ARCH_HAS_SET_MEMORY
arch/s390/include/asm/random.h new file +12 -0
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_RANDOM_H
+#define _ASM_S390_RANDOM_H
+
+#include <asm/timex.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return (unsigned long)get_tod_clock_monotonic() >> 2;
+}
+
+#endif
arch/s390/include/asm/timex.h +0 -6
@@ -219,12 +219,6 @@ static inline unsigned long get_tod_cloc
 	return tod;
 }
 
-static inline cycles_t get_cycles(void)
-{
-	return (cycles_t)get_tod_clock_monotonic() >> 2;
-}
-#define get_cycles get_cycles
-
 /**
  * tod_to_ns - convert a TOD format value to nanoseconds
  * @todval: to be converted TOD format value
arch/s390/kernel/time.c +1 -0
@@ -50,6 +50,7 @@
 #include <asm/irq_regs.h>
 #include <asm/vtimer.h>
 #include <asm/stp.h>
+#include <asm/timex.h>
 #include <asm/cio.h>
 #include "entry.h"
 
arch/s390/kernel/vtime.c +1 -0
@@ -14,6 +14,7 @@
 #include <linux/time.h>
 #include <asm/alternative.h>
 #include <asm/cputime.h>
+#include <asm/timex.h>
 #include <asm/vtimer.h>
 #include <asm/vtime.h>
 #include <asm/cpu_mf.h>
maintainer Acked-by on v1 35/38
#68 lore raw

Re: [patch 35/38] s390: Select ARCH_HAS_RANDOM_ENTROPY

Quoted 12 lines · Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch s390 over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

Quoted 7 lines
---
 arch/s390/Kconfig              |    1 +
 arch/s390/include/asm/random.h |   12 ++++++++++++
 arch/s390/include/asm/timex.h  |    6 ------
 arch/s390/kernel/time.c        |    1 +
 arch/s390/kernel/vtime.c       |    1 +
 5 files changed, 15 insertions(+), 6 deletions(-)

Thomas, would you mind adding the below as minor improvement to this series?

From 7072e5d66b99a7fa666d17c6ad8cb254f2d8f473 Mon Sep 17 00:00:00 2001
From: Heiko Carstens <[email protected]>
Date: Thu, 16 Apr 2026 15:08:15 +0200
Subject: [PATCH] s390: Use get_tod_clock_fast() for random_get_entropy()

Use get_tod_clock_fast() instead of get_tod_clock_monotonic() to implement random_get_entropy().

There is no need for random_get_entropy() to provide monotonic increasing values, nor is there any need to provide (close to) nanosecond granularity timestamps by shifting the result.

This slightly reduces the execution time of random_get_entropy() and adds two bits of randomness.

---
 arch/s390/include/asm/random.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/include/asm/random.h +1 -1
index 7daf42dbed32..f6d9312efdbf 100644
@@ -6,7 +6,7 @@
 
 static inline unsigned long random_get_entropy(void)
 {
-	return (unsigned long)get_tod_clock_monotonic() >> 2;
+	return get_tod_clock_fast();
 }
 
 #endif
Signature · 1 line
2.51.0
author maintainer
#69 lore raw

Re: [patch 35/38] s390: Select ARCH_HAS_RANDOM_ENTROPY

Quoted 21 lines · Heiko Carstens
Quoted 12 lines · Thomas Gleixner

The only remaining non-architecture usage of get_cycles() is to provide random_get_entropy().

Switch s390 over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Add 'asm/timex.h' includes to the relevant files, so the global include can be removed once all architectures are converted over.

Quoted 7 lines
---
 arch/s390/Kconfig              |    1 +
 arch/s390/include/asm/random.h |   12 ++++++++++++
 arch/s390/include/asm/timex.h  |    6 ------
 arch/s390/kernel/time.c        |    1 +
 arch/s390/kernel/vtime.c       |    1 +
 5 files changed, 15 insertions(+), 6 deletions(-)
Quoted 4 lines

Thomas, would you mind adding the below as minor improvement to this series?

Sure. I'll respin it next week.

author maintainer
#70 lore raw

PATCH 36/38 sparc: Select ARCH_HAS_RANDOM_ENTROPY for SPARC64

In reply to Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch sparc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex*.h as it has no functionality anymore.

---
 arch/sparc/Kconfig                |    1 +
 arch/sparc/include/asm/random.h   |   15 +++++++++++++++
 arch/sparc/include/asm/timex.h    |    9 ---------
 arch/sparc/include/asm/timex_64.h |   15 ---------------
 arch/sparc/kernel/pcic.c          |    1 -
 arch/sparc/kernel/time_32.c       |    1 -
 arch/sparc/vdso/vclock_gettime.c  |    1 -
 7 files changed, 16 insertions(+), 27 deletions(-)
arch/sparc/Kconfig +1 -0
@@ -71,6 +71,7 @@ config SPARC64
 	def_bool 64BIT
 	select ALTERNATE_USER_ADDRESS_SPACE
 	select ARCH_HAS_DELAY_TIMER
+	select ARCH_HAS_RANDOM_ENTROPY
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_KRETPROBES
arch/sparc/include/asm/random.h new file +15 -0
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASMsparc_RANDOM_H
+#define _ASMsparc_RANDOM_H
+
+#if defined(__sparc__) && defined(__arch64__)
+
+#include <asm/timer.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	return tick_ops->get_tick();
+}
+
+#endif
+#endif
arch/sparc/include/asm/timex.h deleted +0 -9
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef ___ASM_SPARC_TIMEX_H
-#define ___ASM_SPARC_TIMEX_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/timex_64.h>
-#else
-#include <asm-generic/timex.h>
-#endif
-#endif
arch/sparc/include/asm/timex_64.h +0 -15
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/asm/timex.h
- *
- * sparc64 architecture timex specifications
- */
-#ifndef _ASMsparc64_TIMEX_H
-#define _ASMsparc64_TIMEX_H
-
-#include <asm/timer.h>
-
-/* Getting on the cycle counter on sparc64. */
-#define get_cycles()	tick_ops->get_tick()
-
-#endif
arch/sparc/kernel/pcic.c +0 -1
@@ -33,7 +33,6 @@
 #include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/pcic.h>
-#include <asm/timex.h>
 #include <asm/timer.h>
 #include <linux/uaccess.h>
 #include <asm/irq_regs.h>
arch/sparc/kernel/time_32.c +0 -1
@@ -37,7 +37,6 @@
 
 #include <asm/mc146818rtc.h>
 #include <asm/oplib.h>
-#include <asm/timex.h>
 #include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
arch/sparc/vdso/vclock_gettime.c +0 -1
@@ -17,7 +17,6 @@
 #include <linux/string.h>
 #include <asm/io.h>
 #include <asm/unistd.h>
-#include <asm/timex.h>
 #include <asm/clocksource.h>
 #include <asm/vvar.h>
 
author maintainer
#71 lore raw

PATCH 37/38 x86: Select ARCH_HAS_RANDOM_ENTROPY

In reply to Thomas Gleixner

The only remaining usage of get_cycles() is to provide random_get_entropy().

Switch x86 over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY and providing random_get_entropy() in asm/random.h.

Remove asm/timex.h as it has no functionality anymore.

---
 arch/x86/Kconfig              |    1 +
 arch/x86/include/asm/random.h |   16 ++++++++++++++++
 arch/x86/include/asm/timex.h  |   17 -----------------
 arch/x86/include/asm/tsc.h    |    9 ---------
 4 files changed, 17 insertions(+), 26 deletions(-)
arch/x86/Kconfig +1 -0
@@ -101,6 +101,7 @@ config X86
 	select ARCH_HAS_PREEMPT_LAZY
 	select ARCH_HAS_PTDUMP
 	select ARCH_HAS_PTE_SPECIAL
+	select ARCH_HAS_RANDOM_ENTROPY
 	select ARCH_HAS_HW_PTE_YOUNG
 	select ARCH_HAS_NONLEAF_PMD_YOUNG	if PGTABLE_LEVELS > 2
 	select ARCH_HAS_UACCESS_FLUSHCACHE	if X86_64
arch/x86/include/asm/random.h new file +16 -0
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_RANDOM_H
+#define _ASM_X86_RANDOM_H
+
+#include <asm/processor.h>
+#include <asm/tsc.h>
+
+static inline unsigned long random_get_entropy(void)
+{
+	if (!IS_ENABLED(CONFIG_X86_TSC) &&
+	    !cpu_feature_enabled(X86_FEATURE_TSC))
+		return random_get_entropy_fallback();
+	return rdtsc();
+}
+
+#endif /* _ASM_X86_RANDOM_H */
arch/x86/include/asm/timex.h deleted +0 -17
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_X86_TIMEX_H
-#define _ASM_X86_TIMEX_H
-
-#include <asm/processor.h>
-#include <asm/tsc.h>
-
-static inline unsigned long random_get_entropy(void)
-{
-	if (!IS_ENABLED(CONFIG_X86_TSC) &&
-	    !cpu_feature_enabled(X86_FEATURE_TSC))
-		return random_get_entropy_fallback();
-	return rdtsc();
-}
-#define random_get_entropy random_get_entropy
-
-#endif /* _ASM_X86_TIMEX_H */
arch/x86/include/asm/tsc.h +0 -9
@@ -72,15 +72,6 @@ extern unsigned int tsc_khz;
 
 extern void disable_TSC(void);
 
-static inline cycles_t get_cycles(void)
-{
-	if (!IS_ENABLED(CONFIG_X86_TSC) &&
-	    !cpu_feature_enabled(X86_FEATURE_TSC))
-		return 0;
-	return rdtsc();
-}
-#define get_cycles get_cycles
-
 extern void tsc_early_init(void);
 extern void tsc_init(void);
 extern void mark_tsc_unstable(char *reason);
author maintainer
#72 lore raw

PATCH 38/38 treewide: Remove asm/timex.h includes from generic code

In reply to Thomas Gleixner

asm/timex.h does not provide any functionality for non-architecture code anymore.

Remove the asm-generic fallback and all references in include and source files along with the random_get_entropy() #ifdeffery in timex.h.

---
 include/asm-generic/Kbuild  |    1 -
 include/asm-generic/timex.h |   15 ---------------
 include/linux/random.h      |    3 +++
 include/linux/timex.h       |   26 --------------------------
 kernel/time/timer.c         |    1 -
 lib/interval_tree_test.c    |    1 -
 lib/rbtree_test.c           |    1 -
 7 files changed, 3 insertions(+), 45 deletions(-)
include/asm-generic/Kbuild +0 -1
@@ -56,7 +56,6 @@ mandatory-y += shmparam.h
 mandatory-y += simd.h
 mandatory-y += softirq_stack.h
 mandatory-y += switch_to.h
-mandatory-y += timex.h
 mandatory-y += tlbflush.h
 mandatory-y += topology.h
 mandatory-y += trace_clock.h
include/asm-generic/timex.h deleted +0 -15
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __ASM_GENERIC_TIMEX_H
-#define __ASM_GENERIC_TIMEX_H
-
-/*
- * If you have a cycle counter, return the value here.
- */
-#ifndef get_cycles
-static inline cycles_t get_cycles(void)
-{
-	return 0;
-}
-#endif
-
-#endif /* __ASM_GENERIC_TIMEX_H */
include/linux/random.h +3 -0
@@ -1,3 +1,4 @@
+
 /* SPDX-License-Identifier: GPL-2.0 */
 
 #ifndef _LINUX_RANDOM_H
@@ -152,6 +153,8 @@ unsigned long random_get_entropy_fallbac
  */
 #ifdef CONFIG_ARCH_HAS_RANDOM_ENTROPY
 #include <asm/random.h>
+#else
+#define random_get_entropy()	random_get_entropy_fallback()
 #endif
 
 #endif /* _LINUX_RANDOM_H */
include/linux/timex.h +0 -26
@@ -62,32 +62,6 @@
 #include <linux/types.h>
 #include <linux/param.h>
 
-unsigned long random_get_entropy_fallback(void);
-
-#include <asm/timex.h>
-
-#ifndef CONFIG_ARCH_HAS_RANDOM_ENTROPY
-#ifndef random_get_entropy
-/*
- * The random_get_entropy() function is used by the /dev/random driver
- * in order to extract entropy via the relative unpredictability of
- * when an interrupt takes places versus a high speed, fine-grained
- * timing source or cycle counter.  Since it will be occurred on every
- * single interrupt, it must have a very low cost/overhead.
- *
- * By default we use get_cycles() for this purpose, but individual
- * architectures may override this in their asm/timex.h header file.
- * If a given arch does not have get_cycles(), then we fallback to
- * using random_get_entropy_fallback().
- */
-#ifdef get_cycles
-#define random_get_entropy()	((unsigned long)get_cycles())
-#else
-#define random_get_entropy()	random_get_entropy_fallback()
-#endif
-#endif
-#endif
-
 /*
  * SHIFT_PLL is used as a dampening factor to define how much we
  * adjust the frequency correction for a given offset in PLL mode.
kernel/time/timer.c +0 -1
@@ -48,7 +48,6 @@
 #include <linux/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/div64.h>
-#include <asm/timex.h>
 #include <asm/io.h>
 
 #include "tick-internal.h"
lib/interval_tree_test.c +0 -1
@@ -4,7 +4,6 @@
 #include <linux/interval_tree.h>
 #include <linux/prandom.h>
 #include <linux/slab.h>
-#include <asm/timex.h>
 #include <linux/bitmap.h>
 #include <linux/maple_tree.h>
 
lib/rbtree_test.c +0 -1
@@ -4,7 +4,6 @@
 #include <linux/rbtree_augmented.h>
 #include <linux/prandom.h>
 #include <linux/slab.h>
-#include <asm/timex.h>
 
 #define __param(type, name, init, msg)		\
 	static type name = init;		\
maintainer Acked-by on v1 38/38
#73 lore raw

Re: [patch 38/38] treewide: Remove asm/timex.h includes from generic code

Quoted 6 lines · Thomas Gleixner

asm/timex.h does not provide any functionality for non-architecture code anymore.

Remove the asm-generic fallback and all references in include and source files along with the random_get_entropy() #ifdeffery in timex.h.

Quoted 6 lines
---
 include/asm-generic/Kbuild  |    1 -
 include/asm-generic/timex.h |   15 ---------------
 include/linux/random.h      |    3 +++
 include/linux/timex.h       |   26 --------------------------