diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-01-27 08:50:19 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-01-27 08:50:19 -0800 |
commit | 816cef980d816bdb1b3121a5c406df839a85d7f5 (patch) | |
tree | fc5a2563c930ea74d7c68322820dd04242f3dc5e /arch | |
parent | 3cbb9ce2b9e3e5799f31c53aadebaddc6aad66cb (diff) | |
parent | f520fab580c9179bacc432f3a3bf1eada73fdfcc (diff) |
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux
Pull ARM updates from Russell King:
- fix typos in vfpmodule.c
- drop obsolete VFP accessor fallback for old assemblers
- add cache line identifier register accessor functions
- add cacheinfo support
* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux:
ARM: 9440/1: cacheinfo fix format field mask
ARM: 9433/2: implement cacheinfo support
ARM: 9432/2: add CLIDR accessor functions
ARM: 9438/1: assembler: Drop obsolete VFP accessor fallback
ARM: 9437/1: vfp: Fix typographical errors in vfpmodule.c
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/Kconfig.assembler | 6 | ||||
-rw-r--r-- | arch/arm/include/asm/cache.h | 6 | ||||
-rw-r--r-- | arch/arm/include/asm/cachetype.h | 13 | ||||
-rw-r--r-- | arch/arm/include/asm/vfp.h | 10 | ||||
-rw-r--r-- | arch/arm/include/asm/vfpmacros.h | 11 | ||||
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/cacheinfo.c | 173 | ||||
-rw-r--r-- | arch/arm/vfp/vfpinstr.h | 22 | ||||
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 2 |
10 files changed, 195 insertions, 52 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3ad4c3c97918..835b5f100e92 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -5,6 +5,7 @@ config ARM select ARCH_32BIT_OFF_T select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE if HAVE_KRETPROBES && FRAME_POINTER && !ARM_UNWIND select ARCH_HAS_BINFMT_FLAT + select ARCH_HAS_CACHE_LINE_SIZE if OF select ARCH_HAS_CPU_CACHE_ALIASING select ARCH_HAS_CPU_FINALIZE_INIT if MMU select ARCH_HAS_CRC32 if KERNEL_MODE_NEON @@ -1753,5 +1754,3 @@ config ARCH_HIBERNATION_POSSIBLE default y if ARCH_SUSPEND_POSSIBLE endmenu - -source "arch/arm/Kconfig.assembler" diff --git a/arch/arm/Kconfig.assembler b/arch/arm/Kconfig.assembler deleted file mode 100644 index 5cb31aae1188..000000000000 --- a/arch/arm/Kconfig.assembler +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -config AS_VFP_VMRS_FPINST - def_bool $(as-instr,.fpu vfpv2\nvmrs r0$(comma)FPINST) - help - Supported by binutils >= 2.24 and LLVM integrated assembler. diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h index e3ea34558ada..ecbc100d22a5 100644 --- a/arch/arm/include/asm/cache.h +++ b/arch/arm/include/asm/cache.h @@ -26,4 +26,10 @@ #define __read_mostly __section(".data..read_mostly") +#ifndef __ASSEMBLY__ +#ifdef CONFIG_ARCH_HAS_CACHE_LINE_SIZE +int cache_line_size(void); +#endif +#endif + #endif diff --git a/arch/arm/include/asm/cachetype.h b/arch/arm/include/asm/cachetype.h index b9dbe1d4c8fe..b01c59076b84 100644 --- a/arch/arm/include/asm/cachetype.h +++ b/arch/arm/include/asm/cachetype.h @@ -83,6 +83,14 @@ static inline unsigned int read_ccsidr(void) asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r" (val)); return val; } + +static inline unsigned int read_clidr(void) +{ + unsigned int val; + + asm volatile("mrc p15, 1, %0, c0, c0, 1" : "=r" (val)); + return val; +} #else /* CONFIG_CPU_V7M */ #include <linux/io.h> #include "asm/v7m.h" @@ -96,6 +104,11 @@ static inline unsigned int read_ccsidr(void) { return readl(BASEADDR_V7M_SCB + V7M_SCB_CCSIDR); } + +static inline unsigned int read_clidr(void) +{ + return readl(BASEADDR_V7M_SCB + V7M_SCB_CLIDR); +} #endif #endif diff --git a/arch/arm/include/asm/vfp.h b/arch/arm/include/asm/vfp.h index 157ea3426158..85ccc422d4d0 100644 --- a/arch/arm/include/asm/vfp.h +++ b/arch/arm/include/asm/vfp.h @@ -9,16 +9,6 @@ #ifndef __ASM_VFP_H #define __ASM_VFP_H -#ifndef CONFIG_AS_VFP_VMRS_FPINST -#define FPSID cr0 -#define FPSCR cr1 -#define MVFR1 cr6 -#define MVFR0 cr7 -#define FPEXC cr8 -#define FPINST cr9 -#define FPINST2 cr10 -#endif - /* FPSID bits */ #define FPSID_IMPLEMENTER_BIT (24) #define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT) diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h index ba0d4cb5377e..e2e1d5a3727a 100644 --- a/arch/arm/include/asm/vfpmacros.h +++ b/arch/arm/include/asm/vfpmacros.h @@ -8,7 +8,6 @@ #include <asm/vfp.h> -#ifdef CONFIG_AS_VFP_VMRS_FPINST .macro VFPFMRX, rd, sysreg, cond vmrs\cond \rd, \sysreg .endm @@ -16,16 +15,6 @@ .macro VFPFMXR, sysreg, rd, cond vmsr\cond \sysreg, \rd .endm -#else - @ Macros to allow building with old toolkits (with no VFP support) - .macro VFPFMRX, rd, sysreg, cond - MRC\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMRX \rd, \sysreg - .endm - - .macro VFPFMXR, sysreg, rd, cond - MCR\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMXR \sysreg, \rd - .endm -#endif @ read all the working registers back into the VFP .macro VFPFLDMIA, base, tmp diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index aaae31b8c4a5..b3333d070390 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -40,6 +40,7 @@ obj-y += entry-armv.o endif obj-$(CONFIG_MMU) += bugs.o +obj-$(CONFIG_OF) += cacheinfo.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_FIQ) += fiq.o fiqasm.o diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c new file mode 100644 index 000000000000..e1469b641780 --- /dev/null +++ b/arch/arm/kernel/cacheinfo.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ARM cacheinfo support + * + * Copyright (C) 2023 Linaro Ltd. + * Copyright (C) 2015 ARM Ltd. + * All Rights Reserved + */ + +#include <linux/bitfield.h> +#include <linux/cacheinfo.h> +#include <linux/of.h> + +#include <asm/cachetype.h> +#include <asm/cputype.h> +#include <asm/system_info.h> + +/* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */ +#define CLIDR_CTYPE_SHIFT(level) (3 * (level - 1)) +#define CLIDR_CTYPE_MASK(level) (7 << CLIDR_CTYPE_SHIFT(level)) +#define CLIDR_CTYPE(clidr, level) \ + (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level)) + +#define MAX_CACHE_LEVEL 7 /* Max 7 level supported */ + +#define CTR_FORMAT_MASK GENMASK(31, 29) +#define CTR_FORMAT_ARMV6 0 +#define CTR_FORMAT_ARMV7 4 +#define CTR_CWG_MASK GENMASK(27, 24) +#define CTR_DSIZE_LEN_MASK GENMASK(13, 12) +#define CTR_ISIZE_LEN_MASK GENMASK(1, 0) + +/* Also valid for v7m */ +static inline int cache_line_size_cp15(void) +{ + u32 ctr = read_cpuid_cachetype(); + u32 format = FIELD_GET(CTR_FORMAT_MASK, ctr); + + if (format == CTR_FORMAT_ARMV7) { + u32 cwg = FIELD_GET(CTR_CWG_MASK, ctr); + + return cwg ? 4 << cwg : ARCH_DMA_MINALIGN; + } else if (WARN_ON_ONCE(format != CTR_FORMAT_ARMV6)) { + return ARCH_DMA_MINALIGN; + } + + return 8 << max(FIELD_GET(CTR_ISIZE_LEN_MASK, ctr), + FIELD_GET(CTR_DSIZE_LEN_MASK, ctr)); +} + +int cache_line_size(void) +{ + if (coherency_max_size != 0) + return coherency_max_size; + + /* CP15 is optional / implementation defined before ARMv6 */ + if (cpu_architecture() < CPU_ARCH_ARMv6) + return ARCH_DMA_MINALIGN; + + return cache_line_size_cp15(); +} +EXPORT_SYMBOL_GPL(cache_line_size); + +static inline enum cache_type get_cache_type(int level) +{ + u32 clidr; + + if (level > MAX_CACHE_LEVEL) + return CACHE_TYPE_NOCACHE; + + clidr = read_clidr(); + + return CLIDR_CTYPE(clidr, level); +} + +static void ci_leaf_init(struct cacheinfo *this_leaf, + enum cache_type type, unsigned int level) +{ + this_leaf->level = level; + this_leaf->type = type; +} + +static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p) +{ + unsigned int ctype, level, leaves; + u32 ctr, format; + + /* CLIDR is not present before ARMv7/v7m */ + if (cpu_architecture() < CPU_ARCH_ARMv7) + return -EOPNOTSUPP; + + /* Don't try reading CLIDR if CTR declares old format */ + ctr = read_cpuid_cachetype(); + format = FIELD_GET(CTR_FORMAT_MASK, ctr); + if (format != CTR_FORMAT_ARMV7) + return -EOPNOTSUPP; + + for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) { + ctype = get_cache_type(level); + if (ctype == CACHE_TYPE_NOCACHE) { + level--; + break; + } + /* Separate instruction and data caches */ + leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1; + } + + *level_p = level; + *leaves_p = leaves; + + return 0; +} + +int early_cache_level(unsigned int cpu) +{ + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + + return detect_cache_level(&this_cpu_ci->num_levels, &this_cpu_ci->num_leaves); +} + +int init_cache_level(unsigned int cpu) +{ + unsigned int level, leaves; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + int fw_level; + int ret; + + ret = detect_cache_level(&level, &leaves); + if (ret) + return ret; + + fw_level = of_find_last_cache_level(cpu); + + if (level < fw_level) { + /* + * some external caches not specified in CLIDR_EL1 + * the information may be available in the device tree + * only unified external caches are considered here + */ + leaves += (fw_level - level); + level = fw_level; + } + + this_cpu_ci->num_levels = level; + this_cpu_ci->num_leaves = leaves; + return 0; +} + +int populate_cache_leaves(unsigned int cpu) +{ + unsigned int level, idx; + enum cache_type type; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf = this_cpu_ci->info_list; + unsigned int arch = cpu_architecture(); + + /* CLIDR is not present before ARMv7/v7m */ + if (arch < CPU_ARCH_ARMv7) + return -EOPNOTSUPP; + + for (idx = 0, level = 1; level <= this_cpu_ci->num_levels && + idx < this_cpu_ci->num_leaves; idx++, level++) { + type = get_cache_type(level); + if (type == CACHE_TYPE_SEPARATE) { + ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level); + ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level); + } else { + ci_leaf_init(this_leaf++, type, level); + } + } + + return 0; +} diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h index 32090b0fb250..a2f0c47e0ce7 100644 --- a/arch/arm/vfp/vfpinstr.h +++ b/arch/arm/vfp/vfpinstr.h @@ -62,8 +62,6 @@ #define FPSCR_C (1 << 29) #define FPSCR_V (1 << 28) -#ifdef CONFIG_AS_VFP_VMRS_FPINST - #define fmrx(_vfp_) ({ \ u32 __v; \ asm volatile (".fpu vfpv2\n" \ @@ -78,26 +76,6 @@ : : "r" (_var_) : "cc"); \ }) -#else - -#define vfpreg(_vfp_) #_vfp_ - -#define fmrx(_vfp_) ({ \ - u32 __v; \ - asm volatile ("mrc p10, 7, %0, " vfpreg(_vfp_) "," \ - "cr0, 0 @ fmrx %0, " #_vfp_ \ - : "=r" (__v) : : "cc"); \ - __v; \ -}) - -#define fmxr(_vfp_, _var_) ({ \ - asm volatile ("mcr p10, 7, %0, " vfpreg(_vfp_) "," \ - "cr0, 0 @ fmxr " #_vfp_ ", %0" \ - : : "r" (_var_) : "cc"); \ -}) - -#endif - u32 vfp_single_cpdo(u32 inst, u32 fpscr); u32 vfp_single_cprt(u32 inst, u32 fpscr, struct pt_regs *regs); diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index d44867fc0c5e..7803d50b90f8 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -168,7 +168,7 @@ static void vfp_thread_copy(struct thread_info *thread) /* * When this function is called with the following 'cmd's, the following * is true while this function is being run: - * THREAD_NOFTIFY_SWTICH: + * THREAD_NOTIFY_SWITCH: * - the previously running thread will not be scheduled onto another CPU. * - the next thread to be run (v) will not be running on another CPU. * - thread->cpu is the local CPU number |