Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branches 'for-next/misc', 'for-next/kselftest', 'for-next/efi-preempt', 'for-next/assembler-macro', 'for-next/typos', 'for-next/sme-ptrace-disable', 'for-next/local-tlbi-page-reused', 'for-next/mpam', 'for-next/acpi' and 'for-next/documentation', remote-tracking branch 'arm64/for-next/perf' into for-next/core

* arm64/for-next/perf:
perf: arm_spe: Add support for filtering on data source
perf: Add perf_event_attr::config4
perf/imx_ddr: Add support for PMU in DB (system interconnects)
perf/imx_ddr: Get and enable optional clks
perf/imx_ddr: Move ida_alloc() from ddr_perf_init() to ddr_perf_probe()
dt-bindings: perf: fsl-imx-ddr: Add compatible string for i.MX8QM, i.MX8QXP and i.MX8DXL
arch_topology: Provide a stub topology_core_has_smt() for !CONFIG_GENERIC_ARCH_TOPOLOGY
perf/arm-ni: Fix and optimise register offset calculation
perf: arm_pmuv3: Add new Cortex and C1 CPU PMUs
perf: arm_cspmu: fix error handling in arm_cspmu_impl_unregister()
perf/arm-ni: Add NoC S3 support
perf/arm_cspmu: nvidia: Add pmevfiltr2 support
perf/arm_cspmu: nvidia: Add revision id matching
perf/arm_cspmu: Add pmpidr support
perf/arm_cspmu: Add callback to reset filter config
perf: arm_pmuv3: Don't use PMCCNTR_EL0 on SMT cores

* for-next/misc:
: Miscellaneous patches
arm64: atomics: lse: Remove unused parameters from ATOMIC_FETCH_OP_AND macros
arm64: remove duplicate ARCH_HAS_MEM_ENCRYPT
arm64: mm: use untagged address to calculate page index
arm64: mm: make linear mapping permission update more robust for patial range
arm64/mm: Elide TLB flush in certain pte protection transitions
arm64/mm: Rename try_pgd_pgtable_alloc_init_mm
arm64/mm: Allow __create_pgd_mapping() to propagate pgtable_alloc() errors
arm64: add unlikely hint to MTE async fault check in el0_svc_common
arm64: acpi: add newline to deferred APEI warning
arm64: entry: Clean out some indirection
arm64/mm: Ensure PGD_SIZE is aligned to 64 bytes when PA_BITS = 52
arm64/mm: Drop cpu_set_[default|idmap]_tcr_t0sz()
arm64: remove unused ARCH_PFN_OFFSET
arm64: use SOFTIRQ_ON_OWN_STACK for enabling softirq stack
arm64: Remove assertion on CONFIG_VMAP_STACK

* for-next/kselftest:
: arm64 kselftest patches
kselftest/arm64: Align zt-test register dumps

* for-next/efi-preempt:
: arm64: Make EFI calls preemptible
arm64/efi: Call EFI runtime services without disabling preemption
arm64/efi: Move uaccess en/disable out of efi_set_pgd()
arm64/efi: Drop efi_rt_lock spinlock from EFI arch wrapper
arm64/fpsimd: Permit kernel mode NEON with IRQs off
arm64/fpsimd: Don't warn when EFI execution context is preemptible
efi/runtime-wrappers: Keep track of the efi_runtime_lock owner
efi: Add missing static initializer for efi_mm::cpus_allowed_lock

* for-next/assembler-macro:
: arm64: Replace __ASSEMBLY__ with __ASSEMBLER__ in headers
arm64: Replace __ASSEMBLY__ with __ASSEMBLER__ in non-uapi headers
arm64: Replace __ASSEMBLY__ with __ASSEMBLER__ in uapi headers

* for-next/typos:
: Random typo/spelling fixes
arm64: Fix double word in comments
arm64: Fix typos and spelling errors in comments

* for-next/sme-ptrace-disable:
: Support disabling streaming mode via ptrace on SME only systems
kselftest/arm64: Cover disabling streaming mode without SVE in fp-ptrace
kselftst/arm64: Test NT_ARM_SVE FPSIMD format writes on non-SVE systems
arm64/sme: Support disabling streaming mode via ptrace on SME only systems

* for-next/local-tlbi-page-reused:
: arm64, mm: avoid TLBI broadcast if page reused in write fault
arm64, tlbflush: don't TLBI broadcast if page reused in write fault
mm: add spurious fault fixing support for huge pmd

* for-next/mpam: (34 commits)
: Basic Arm MPAM driver (more to follow)
MAINTAINERS: new entry for MPAM Driver
arm_mpam: Add kunit tests for props_mismatch()
arm_mpam: Add kunit test for bitmap reset
arm_mpam: Add helper to reset saved mbwu state
arm_mpam: Use long MBWU counters if supported
arm_mpam: Probe for long/lwd mbwu counters
arm_mpam: Consider overflow in bandwidth counter state
arm_mpam: Track bandwidth counter state for power management
arm_mpam: Add mpam_msmon_read() to read monitor value
arm_mpam: Add helpers to allocate monitors
arm_mpam: Probe and reset the rest of the features
arm_mpam: Allow configuration to be applied and restored during cpu online
arm_mpam: Use a static key to indicate when mpam is enabled
arm_mpam: Register and enable IRQs
arm_mpam: Extend reset logic to allow devices to be reset any time
arm_mpam: Add a helper to touch an MSC from any CPU
arm_mpam: Reset MSC controls from cpuhp callbacks
arm_mpam: Merge supported features during mpam_enable() into mpam_class
arm_mpam: Probe the hardware features resctrl supports
arm_mpam: Add helpers for managing the locking around the mon_sel registers
...

* for-next/acpi:
: arm64 acpi updates
ACPI: GTDT: Get rid of acpi_arch_timer_mem_init()

* for-next/documentation:
: arm64 Documentation updates
Documentation/arm64: Fix the typo of register names

+5298 -442
+4 -4
Documentation/arch/arm64/booting.rst
··· 391 391 - SMCR_EL2.LEN must be initialised to the same value for all CPUs the 392 392 kernel will execute on. 393 393 394 - - HWFGRTR_EL2.nTPIDR2_EL0 (bit 55) must be initialised to 0b01. 394 + - HFGRTR_EL2.nTPIDR2_EL0 (bit 55) must be initialised to 0b01. 395 395 396 - - HWFGWTR_EL2.nTPIDR2_EL0 (bit 55) must be initialised to 0b01. 396 + - HFGWTR_EL2.nTPIDR2_EL0 (bit 55) must be initialised to 0b01. 397 397 398 - - HWFGRTR_EL2.nSMPRI_EL1 (bit 54) must be initialised to 0b01. 398 + - HFGRTR_EL2.nSMPRI_EL1 (bit 54) must be initialised to 0b01. 399 399 400 - - HWFGWTR_EL2.nSMPRI_EL1 (bit 54) must be initialised to 0b01. 400 + - HFGWTR_EL2.nSMPRI_EL1 (bit 54) must be initialised to 0b01. 401 401 402 402 For CPUs with the Scalable Matrix Extension FA64 feature (FEAT_SME_FA64): 403 403
+5
Documentation/arch/arm64/sve.rst
··· 402 402 streaming mode and any SETREGSET of NT_ARM_SSVE will enter streaming mode 403 403 if the target was not in streaming mode. 404 404 405 + * On systems that do not support SVE it is permitted to use SETREGSET to 406 + write SVE_PT_REGS_FPSIMD formatted data via NT_ARM_SVE, in this case the 407 + vector length should be specified as 0. This allows streaming mode to be 408 + disabled on systems with SME but not SVE. 409 + 405 410 * If any register data is provided along with SVE_PT_VL_ONEXEC then the 406 411 registers data will be interpreted with the current vector length, not 407 412 the vector length configured for use on exec.
+10
MAINTAINERS
··· 17448 17448 F: Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml 17449 17449 F: drivers/video/backlight/mp3309c.c 17450 17450 17451 + MPAM DRIVER 17452 + M: James Morse <james.morse@arm.com> 17453 + M: Ben Horgan <ben.horgan@arm.com> 17454 + R: Reinette Chatre <reinette.chatre@intel.com> 17455 + R: Fenghua Yu <fenghuay@nvidia.com> 17456 + S: Maintained 17457 + F: drivers/resctrl/mpam_* 17458 + F: drivers/resctrl/test_mpam_* 17459 + F: include/linux/arm_mpam.h 17460 + 17451 17461 MPS MP2869 DRIVER 17452 17462 M: Wensheng Wang <wenswang@yeah.net> 17453 17463 L: linux-hwmon@vger.kernel.org
+25 -1
arch/arm64/Kconfig
··· 47 47 select ARCH_HAS_SETUP_DMA_OPS 48 48 select ARCH_HAS_SET_DIRECT_MAP 49 49 select ARCH_HAS_SET_MEMORY 50 - select ARCH_HAS_MEM_ENCRYPT 51 50 select ARCH_HAS_FORCE_DMA_UNENCRYPTED 52 51 select ARCH_STACKWALK 53 52 select ARCH_HAS_STRICT_KERNEL_RWX ··· 2021 2022 help 2022 2023 ARMv8.4-TLBI provides TLBI invalidation instruction that apply to a 2023 2024 range of input addresses. 2025 + 2026 + config ARM64_MPAM 2027 + bool "Enable support for MPAM" 2028 + select ARM64_MPAM_DRIVER if EXPERT # does nothing yet 2029 + select ACPI_MPAM if ACPI 2030 + help 2031 + Memory System Resource Partitioning and Monitoring (MPAM) is an 2032 + optional extension to the Arm architecture that allows each 2033 + transaction issued to the memory system to be labelled with a 2034 + Partition identifier (PARTID) and Performance Monitoring Group 2035 + identifier (PMG). 2036 + 2037 + Memory system components, such as the caches, can be configured with 2038 + policies to control how much of various physical resources (such as 2039 + memory bandwidth or cache memory) the transactions labelled with each 2040 + PARTID can consume. Depending on the capabilities of the hardware, 2041 + the PARTID and PMG can also be used as filtering criteria to measure 2042 + the memory system resource consumption of different parts of a 2043 + workload. 2044 + 2045 + Use of this extension requires CPU support, support in the 2046 + Memory System Components (MSC), and a description from firmware 2047 + of where the MSCs are in the address space. 2048 + 2049 + MPAM is exposed to user-space via the resctrl pseudo filesystem. 2024 2050 2025 2051 endmenu # "ARMv8.4 architectural features" 2026 2052
+4 -4
arch/arm64/include/asm/alternative-macros.h
··· 19 19 #error "cpucaps have overflown ARM64_CB_BIT" 20 20 #endif 21 21 22 - #ifndef __ASSEMBLY__ 22 + #ifndef __ASSEMBLER__ 23 23 24 24 #include <linux/stringify.h> 25 25 ··· 207 207 #define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...) \ 208 208 alternative_insn insn1, insn2, cap, IS_ENABLED(cfg) 209 209 210 - #endif /* __ASSEMBLY__ */ 210 + #endif /* __ASSEMBLER__ */ 211 211 212 212 /* 213 213 * Usage: asm(ALTERNATIVE(oldinstr, newinstr, cpucap)); ··· 219 219 #define ALTERNATIVE(oldinstr, newinstr, ...) \ 220 220 _ALTERNATIVE_CFG(oldinstr, newinstr, __VA_ARGS__, 1) 221 221 222 - #ifndef __ASSEMBLY__ 222 + #ifndef __ASSEMBLER__ 223 223 224 224 #include <linux/types.h> 225 225 ··· 263 263 return true; 264 264 } 265 265 266 - #endif /* __ASSEMBLY__ */ 266 + #endif /* __ASSEMBLER__ */ 267 267 268 268 #endif /* __ASM_ALTERNATIVE_MACROS_H */
+2 -2
arch/arm64/include/asm/alternative.h
··· 4 4 5 5 #include <asm/alternative-macros.h> 6 6 7 - #ifndef __ASSEMBLY__ 7 + #ifndef __ASSEMBLER__ 8 8 9 9 #include <linux/init.h> 10 10 #include <linux/types.h> ··· 34 34 void alt_cb_patch_nops(struct alt_instr *alt, __le32 *origptr, 35 35 __le32 *updptr, int nr_inst); 36 36 37 - #endif /* __ASSEMBLY__ */ 37 + #endif /* __ASSEMBLER__ */ 38 38 #endif /* __ASM_ALTERNATIVE_H */
+2 -2
arch/arm64/include/asm/arch_gicv3.h
··· 9 9 10 10 #include <asm/sysreg.h> 11 11 12 - #ifndef __ASSEMBLY__ 12 + #ifndef __ASSEMBLER__ 13 13 14 14 #include <linux/irqchip/arm-gic-common.h> 15 15 #include <linux/stringify.h> ··· 188 188 return cpus_have_cap(ARM64_HAS_GIC_PRIO_RELAXED_SYNC); 189 189 } 190 190 191 - #endif /* __ASSEMBLY__ */ 191 + #endif /* __ASSEMBLER__ */ 192 192 #endif /* __ASM_ARCH_GICV3_H */
+3 -3
arch/arm64/include/asm/asm-extable.h
··· 27 27 /* Data fields for EX_TYPE_UACCESS_CPY */ 28 28 #define EX_DATA_UACCESS_WRITE BIT(0) 29 29 30 - #ifdef __ASSEMBLY__ 30 + #ifdef __ASSEMBLER__ 31 31 32 32 #define __ASM_EXTABLE_RAW(insn, fixup, type, data) \ 33 33 .pushsection __ex_table, "a"; \ ··· 77 77 __ASM_EXTABLE_RAW(\insn, \fixup, EX_TYPE_UACCESS_CPY, \uaccess_is_write) 78 78 .endm 79 79 80 - #else /* __ASSEMBLY__ */ 80 + #else /* __ASSEMBLER__ */ 81 81 82 82 #include <linux/stringify.h> 83 83 ··· 132 132 EX_DATA_REG(ADDR, addr) \ 133 133 ")") 134 134 135 - #endif /* __ASSEMBLY__ */ 135 + #endif /* __ASSEMBLER__ */ 136 136 137 137 #endif /* __ASM_ASM_EXTABLE_H */
+3 -3
arch/arm64/include/asm/assembler.h
··· 5 5 * Copyright (C) 1996-2000 Russell King 6 6 * Copyright (C) 2012 ARM Ltd. 7 7 */ 8 - #ifndef __ASSEMBLY__ 8 + #ifndef __ASSEMBLER__ 9 9 #error "Only include this from assembly code" 10 10 #endif 11 11 ··· 371 371 * [start, end) with dcache line size explicitly provided. 372 372 * 373 373 * op: operation passed to dc instruction 374 - * domain: domain used in dsb instruciton 374 + * domain: domain used in dsb instruction 375 375 * start: starting virtual address of the region 376 376 * end: end virtual address of the region 377 377 * linesz: dcache line size ··· 412 412 * [start, end) 413 413 * 414 414 * op: operation passed to dc instruction 415 - * domain: domain used in dsb instruciton 415 + * domain: domain used in dsb instruction 416 416 * start: starting virtual address of the region 417 417 * end: end virtual address of the region 418 418 * fixup: optional label to branch to on user fault
+10 -10
arch/arm64/include/asm/atomic_lse.h
··· 103 103 return __lse_atomic_andnot(~i, v); 104 104 } 105 105 106 - #define ATOMIC_FETCH_OP_AND(name, mb, cl...) \ 106 + #define ATOMIC_FETCH_OP_AND(name) \ 107 107 static __always_inline int \ 108 108 __lse_atomic_fetch_and##name(int i, atomic_t *v) \ 109 109 { \ 110 110 return __lse_atomic_fetch_andnot##name(~i, v); \ 111 111 } 112 112 113 - ATOMIC_FETCH_OP_AND(_relaxed, ) 114 - ATOMIC_FETCH_OP_AND(_acquire, a, "memory") 115 - ATOMIC_FETCH_OP_AND(_release, l, "memory") 116 - ATOMIC_FETCH_OP_AND( , al, "memory") 113 + ATOMIC_FETCH_OP_AND(_relaxed) 114 + ATOMIC_FETCH_OP_AND(_acquire) 115 + ATOMIC_FETCH_OP_AND(_release) 116 + ATOMIC_FETCH_OP_AND( ) 117 117 118 118 #undef ATOMIC_FETCH_OP_AND 119 119 ··· 210 210 return __lse_atomic64_andnot(~i, v); 211 211 } 212 212 213 - #define ATOMIC64_FETCH_OP_AND(name, mb, cl...) \ 213 + #define ATOMIC64_FETCH_OP_AND(name) \ 214 214 static __always_inline long \ 215 215 __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \ 216 216 { \ 217 217 return __lse_atomic64_fetch_andnot##name(~i, v); \ 218 218 } 219 219 220 - ATOMIC64_FETCH_OP_AND(_relaxed, ) 221 - ATOMIC64_FETCH_OP_AND(_acquire, a, "memory") 222 - ATOMIC64_FETCH_OP_AND(_release, l, "memory") 223 - ATOMIC64_FETCH_OP_AND( , al, "memory") 220 + ATOMIC64_FETCH_OP_AND(_relaxed) 221 + ATOMIC64_FETCH_OP_AND(_acquire) 222 + ATOMIC64_FETCH_OP_AND(_release) 223 + ATOMIC64_FETCH_OP_AND( ) 224 224 225 225 #undef ATOMIC64_FETCH_OP_AND 226 226
+2 -2
arch/arm64/include/asm/barrier.h
··· 7 7 #ifndef __ASM_BARRIER_H 8 8 #define __ASM_BARRIER_H 9 9 10 - #ifndef __ASSEMBLY__ 10 + #ifndef __ASSEMBLER__ 11 11 12 12 #include <linux/kasan-checks.h> 13 13 ··· 221 221 222 222 #include <asm-generic/barrier.h> 223 223 224 - #endif /* __ASSEMBLY__ */ 224 + #endif /* __ASSEMBLER__ */ 225 225 226 226 #endif /* __ASM_BARRIER_H */
+2 -2
arch/arm64/include/asm/cache.h
··· 35 35 #define ARCH_DMA_MINALIGN (128) 36 36 #define ARCH_KMALLOC_MINALIGN (8) 37 37 38 - #if !defined(__ASSEMBLY__) && !defined(BUILD_VDSO) 38 + #if !defined(__ASSEMBLER__) && !defined(BUILD_VDSO) 39 39 40 40 #include <linux/bitops.h> 41 41 #include <linux/kasan-enabled.h> ··· 135 135 return ctr; 136 136 } 137 137 138 - #endif /* !defined(__ASSEMBLY__) && !defined(BUILD_VDSO) */ 138 + #endif /* !defined(__ASSEMBLER__) && !defined(BUILD_VDSO) */ 139 139 140 140 #endif
+2 -2
arch/arm64/include/asm/cpucaps.h
··· 5 5 6 6 #include <asm/cpucap-defs.h> 7 7 8 - #ifndef __ASSEMBLY__ 8 + #ifndef __ASSEMBLER__ 9 9 #include <linux/types.h> 10 10 /* 11 11 * Check whether a cpucap is possible at compiletime. ··· 77 77 78 78 return true; 79 79 } 80 - #endif /* __ASSEMBLY__ */ 80 + #endif /* __ASSEMBLER__ */ 81 81 82 82 #endif /* __ASM_CPUCAPS_H */
+4 -4
arch/arm64/include/asm/cpufeature.h
··· 19 19 #define ARM64_SW_FEATURE_OVERRIDE_HVHE 4 20 20 #define ARM64_SW_FEATURE_OVERRIDE_RODATA_OFF 8 21 21 22 - #ifndef __ASSEMBLY__ 22 + #ifndef __ASSEMBLER__ 23 23 24 24 #include <linux/bug.h> 25 25 #include <linux/jump_label.h> ··· 199 199 * registers (e.g, SCTLR, TCR etc.) or patching the kernel via 200 200 * alternatives. The kernel patching is batched and performed at later 201 201 * point. The actions are always initiated only after the capability 202 - * is finalised. This is usally denoted by "enabling" the capability. 202 + * is finalised. This is usually denoted by "enabling" the capability. 203 203 * The actions are initiated as follows : 204 204 * a) Action is triggered on all online CPUs, after the capability is 205 205 * finalised, invoked within the stop_machine() context from ··· 251 251 #define ARM64_CPUCAP_SCOPE_LOCAL_CPU ((u16)BIT(0)) 252 252 #define ARM64_CPUCAP_SCOPE_SYSTEM ((u16)BIT(1)) 253 253 /* 254 - * The capabilitiy is detected on the Boot CPU and is used by kernel 254 + * The capability is detected on the Boot CPU and is used by kernel 255 255 * during early boot. i.e, the capability should be "detected" and 256 256 * "enabled" as early as possibly on all booting CPUs. 257 257 */ ··· 1078 1078 #endif 1079 1079 } 1080 1080 1081 - #endif /* __ASSEMBLY__ */ 1081 + #endif /* __ASSEMBLER__ */ 1082 1082 1083 1083 #endif
+2 -2
arch/arm64/include/asm/cputype.h
··· 249 249 #define MIDR_FUJITSU_ERRATUM_010001_MASK (~MIDR_CPU_VAR_REV(1, 0)) 250 250 #define TCR_CLEAR_FUJITSU_ERRATUM_010001 (TCR_NFD1 | TCR_NFD0) 251 251 252 - #ifndef __ASSEMBLY__ 252 + #ifndef __ASSEMBLER__ 253 253 254 254 #include <asm/sysreg.h> 255 255 ··· 328 328 { 329 329 return read_cpuid(CTR_EL0); 330 330 } 331 - #endif /* __ASSEMBLY__ */ 331 + #endif /* __ASSEMBLER__ */ 332 332 333 333 #endif
+2 -2
arch/arm64/include/asm/current.h
··· 4 4 5 5 #include <linux/compiler.h> 6 6 7 - #ifndef __ASSEMBLY__ 7 + #ifndef __ASSEMBLER__ 8 8 9 9 struct task_struct; 10 10 ··· 23 23 24 24 #define current get_current() 25 25 26 - #endif /* __ASSEMBLY__ */ 26 + #endif /* __ASSEMBLER__ */ 27 27 28 28 #endif /* __ASM_CURRENT_H */ 29 29
+2 -2
arch/arm64/include/asm/debug-monitors.h
··· 48 48 #define AARCH32_BREAK_THUMB2_LO 0xf7f0 49 49 #define AARCH32_BREAK_THUMB2_HI 0xa000 50 50 51 - #ifndef __ASSEMBLY__ 51 + #ifndef __ASSEMBLER__ 52 52 struct task_struct; 53 53 54 54 #define DBG_ARCH_ID_RESERVED 0 /* In case of ptrace ABI updates. */ ··· 88 88 89 89 bool try_handle_aarch32_break(struct pt_regs *regs); 90 90 91 - #endif /* __ASSEMBLY */ 91 + #endif /* __ASSEMBLER__ */ 92 92 #endif /* __ASM_DEBUG_MONITORS_H */
+3 -10
arch/arm64/include/asm/efi.h
··· 126 126 if (mm != current->active_mm) { 127 127 /* 128 128 * Update the current thread's saved ttbr0 since it is 129 - * restored as part of a return from exception. Enable 130 - * access to the valid TTBR0_EL1 and invoke the errata 131 - * workaround directly since there is no return from 132 - * exception when invoking the EFI run-time services. 129 + * restored as part of a return from exception. 133 130 */ 134 131 update_saved_ttbr0(current, mm); 135 - uaccess_ttbr0_enable(); 136 - post_ttbr_update_workaround(); 137 132 } else { 138 133 /* 139 - * Defer the switch to the current thread's TTBR0_EL1 140 - * until uaccess_enable(). Restore the current 141 - * thread's saved ttbr0 corresponding to its active_mm 134 + * Restore the current thread's saved ttbr0 135 + * corresponding to its active_mm 142 136 */ 143 - uaccess_ttbr0_disable(); 144 137 update_saved_ttbr0(current, current->active_mm); 145 138 } 146 139 }
+2 -2
arch/arm64/include/asm/el2_setup.h
··· 7 7 #ifndef __ARM_KVM_INIT_H__ 8 8 #define __ARM_KVM_INIT_H__ 9 9 10 - #ifndef __ASSEMBLY__ 10 + #ifndef __ASSEMBLER__ 11 11 #error Assembly-only header 12 12 #endif 13 13 ··· 28 28 * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but 29 29 * don't advertise it (they predate this relaxation). 30 30 * 31 - * Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H 31 + * Initialize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H 32 32 * indicating whether the CPU is running in E2H mode. 33 33 */ 34 34 mrs_s x1, SYS_ID_AA64MMFR4_EL1
+2 -2
arch/arm64/include/asm/elf.h
··· 133 133 #define ELF_ET_DYN_BASE (2 * DEFAULT_MAP_WINDOW_64 / 3) 134 134 #endif /* CONFIG_ARM64_FORCE_52BIT */ 135 135 136 - #ifndef __ASSEMBLY__ 136 + #ifndef __ASSEMBLER__ 137 137 138 138 #include <uapi/linux/elf.h> 139 139 #include <linux/bug.h> ··· 293 293 return 0; 294 294 } 295 295 296 - #endif /* !__ASSEMBLY__ */ 296 + #endif /* !__ASSEMBLER__ */ 297 297 298 298 #endif
+2 -2
arch/arm64/include/asm/esr.h
··· 431 431 #define ESR_ELx_IT_GCSPOPCX 6 432 432 #define ESR_ELx_IT_GCSPOPX 7 433 433 434 - #ifndef __ASSEMBLY__ 434 + #ifndef __ASSEMBLER__ 435 435 #include <asm/types.h> 436 436 437 437 static inline unsigned long esr_brk_comment(unsigned long esr) ··· 534 534 } 535 535 536 536 const char *esr_get_class_string(unsigned long esr); 537 - #endif /* __ASSEMBLY */ 537 + #endif /* __ASSEMBLER__ */ 538 538 539 539 #endif /* __ASM_ESR_H */
+2 -2
arch/arm64/include/asm/fixmap.h
··· 15 15 #ifndef _ASM_ARM64_FIXMAP_H 16 16 #define _ASM_ARM64_FIXMAP_H 17 17 18 - #ifndef __ASSEMBLY__ 18 + #ifndef __ASSEMBLER__ 19 19 #include <linux/kernel.h> 20 20 #include <linux/math.h> 21 21 #include <linux/sizes.h> ··· 117 117 118 118 #include <asm-generic/fixmap.h> 119 119 120 - #endif /* !__ASSEMBLY__ */ 120 + #endif /* !__ASSEMBLER__ */ 121 121 #endif /* _ASM_ARM64_FIXMAP_H */
+1 -1
arch/arm64/include/asm/fpsimd.h
··· 12 12 #include <asm/sigcontext.h> 13 13 #include <asm/sysreg.h> 14 14 15 - #ifndef __ASSEMBLY__ 15 + #ifndef __ASSEMBLER__ 16 16 17 17 #include <linux/bitmap.h> 18 18 #include <linux/build_bug.h>
+3 -3
arch/arm64/include/asm/ftrace.h
··· 37 37 */ 38 38 #define ARCH_FTRACE_SHIFT_STACK_TRACER 1 39 39 40 - #ifndef __ASSEMBLY__ 40 + #ifndef __ASSEMBLER__ 41 41 #include <linux/compat.h> 42 42 43 43 extern void _mcount(unsigned long); ··· 217 217 */ 218 218 return !strcmp(sym + 8, name); 219 219 } 220 - #endif /* ifndef __ASSEMBLY__ */ 220 + #endif /* ifndef __ASSEMBLER__ */ 221 221 222 - #ifndef __ASSEMBLY__ 222 + #ifndef __ASSEMBLER__ 223 223 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 224 224 225 225 void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
+3 -3
arch/arm64/include/asm/gpr-num.h
··· 2 2 #ifndef __ASM_GPR_NUM_H 3 3 #define __ASM_GPR_NUM_H 4 4 5 - #ifdef __ASSEMBLY__ 5 + #ifdef __ASSEMBLER__ 6 6 7 7 .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 8 8 .equ .L__gpr_num_x\num, \num ··· 11 11 .equ .L__gpr_num_xzr, 31 12 12 .equ .L__gpr_num_wzr, 31 13 13 14 - #else /* __ASSEMBLY__ */ 14 + #else /* __ASSEMBLER__ */ 15 15 16 16 #define __DEFINE_ASM_GPR_NUMS \ 17 17 " .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" \ ··· 21 21 " .equ .L__gpr_num_xzr, 31\n" \ 22 22 " .equ .L__gpr_num_wzr, 31\n" 23 23 24 - #endif /* __ASSEMBLY__ */ 24 + #endif /* __ASSEMBLER__ */ 25 25 26 26 #endif /* __ASM_GPR_NUM_H */
+1 -1
arch/arm64/include/asm/hwcap.h
··· 46 46 #define COMPAT_HWCAP2_SB (1 << 5) 47 47 #define COMPAT_HWCAP2_SSBS (1 << 6) 48 48 49 - #ifndef __ASSEMBLY__ 49 + #ifndef __ASSEMBLER__ 50 50 #include <linux/log2.h> 51 51 52 52 /*
+2 -2
arch/arm64/include/asm/image.h
··· 20 20 #define ARM64_IMAGE_FLAG_PAGE_SIZE_64K 3 21 21 #define ARM64_IMAGE_FLAG_PHYS_BASE 1 22 22 23 - #ifndef __ASSEMBLY__ 23 + #ifndef __ASSEMBLER__ 24 24 25 25 #define arm64_image_flag_field(flags, field) \ 26 26 (((flags) >> field##_SHIFT) & field##_MASK) ··· 54 54 __le32 res5; 55 55 }; 56 56 57 - #endif /* __ASSEMBLY__ */ 57 + #endif /* __ASSEMBLER__ */ 58 58 59 59 #endif /* __ASM_IMAGE_H */
+2 -2
arch/arm64/include/asm/insn.h
··· 12 12 13 13 #include <asm/insn-def.h> 14 14 15 - #ifndef __ASSEMBLY__ 15 + #ifndef __ASSEMBLER__ 16 16 17 17 enum aarch64_insn_hint_cr_op { 18 18 AARCH64_INSN_HINT_NOP = 0x0 << 5, ··· 730 730 typedef bool (pstate_check_t)(unsigned long); 731 731 extern pstate_check_t * const aarch32_opcode_cond_checks[16]; 732 732 733 - #endif /* __ASSEMBLY__ */ 733 + #endif /* __ASSEMBLER__ */ 734 734 735 735 #endif /* __ASM_INSN_H */
+2 -2
arch/arm64/include/asm/jump_label.h
··· 8 8 #ifndef __ASM_JUMP_LABEL_H 9 9 #define __ASM_JUMP_LABEL_H 10 10 11 - #ifndef __ASSEMBLY__ 11 + #ifndef __ASSEMBLER__ 12 12 13 13 #include <linux/types.h> 14 14 #include <asm/insn.h> ··· 58 58 return true; 59 59 } 60 60 61 - #endif /* __ASSEMBLY__ */ 61 + #endif /* __ASSEMBLER__ */ 62 62 #endif /* __ASM_JUMP_LABEL_H */
+1 -1
arch/arm64/include/asm/kasan.h
··· 2 2 #ifndef __ASM_KASAN_H 3 3 #define __ASM_KASAN_H 4 4 5 - #ifndef __ASSEMBLY__ 5 + #ifndef __ASSEMBLER__ 6 6 7 7 #include <linux/linkage.h> 8 8 #include <asm/memory.h>
+2 -2
arch/arm64/include/asm/kexec.h
··· 25 25 26 26 #define KEXEC_ARCH KEXEC_ARCH_AARCH64 27 27 28 - #ifndef __ASSEMBLY__ 28 + #ifndef __ASSEMBLER__ 29 29 30 30 /** 31 31 * crash_setup_regs() - save registers for the panic kernel ··· 130 130 char *cmdline); 131 131 #endif 132 132 133 - #endif /* __ASSEMBLY__ */ 133 + #endif /* __ASSEMBLER__ */ 134 134 135 135 #endif
+2 -2
arch/arm64/include/asm/kgdb.h
··· 14 14 #include <linux/ptrace.h> 15 15 #include <asm/debug-monitors.h> 16 16 17 - #ifndef __ASSEMBLY__ 17 + #ifndef __ASSEMBLER__ 18 18 19 19 static inline void arch_kgdb_breakpoint(void) 20 20 { ··· 36 36 } 37 37 #endif 38 38 39 - #endif /* !__ASSEMBLY__ */ 39 + #endif /* !__ASSEMBLER__ */ 40 40 41 41 /* 42 42 * gdb remote procotol (well most versions of it) expects the following
+2 -2
arch/arm64/include/asm/kvm_asm.h
··· 46 46 47 47 #define __KVM_HOST_SMCCC_FUNC___kvm_hyp_init 0 48 48 49 - #ifndef __ASSEMBLY__ 49 + #ifndef __ASSEMBLER__ 50 50 51 51 #include <linux/mm.h> 52 52 ··· 303 303 void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, u64 elr_virt, 304 304 u64 elr_phys, u64 par, uintptr_t vcpu, u64 far, u64 hpfar); 305 305 306 - #else /* __ASSEMBLY__ */ 306 + #else /* __ASSEMBLER__ */ 307 307 308 308 .macro get_host_ctxt reg, tmp 309 309 adr_this_cpu \reg, kvm_host_data, \tmp
+2 -2
arch/arm64/include/asm/kvm_mmu.h
··· 49 49 * mappings, and none of this applies in that case. 50 50 */ 51 51 52 - #ifdef __ASSEMBLY__ 52 + #ifdef __ASSEMBLER__ 53 53 54 54 #include <asm/alternative.h> 55 55 ··· 396 396 static inline void kvm_s2_ptdump_create_debugfs(struct kvm *kvm) {} 397 397 #endif /* CONFIG_PTDUMP_STAGE2_DEBUGFS */ 398 398 399 - #endif /* __ASSEMBLY__ */ 399 + #endif /* __ASSEMBLER__ */ 400 400 #endif /* __ARM64_KVM_MMU_H__ */
+2 -2
arch/arm64/include/asm/kvm_mte.h
··· 5 5 #ifndef __ASM_KVM_MTE_H 6 6 #define __ASM_KVM_MTE_H 7 7 8 - #ifdef __ASSEMBLY__ 8 + #ifdef __ASSEMBLER__ 9 9 10 10 #include <asm/sysreg.h> 11 11 ··· 62 62 .endm 63 63 64 64 #endif /* CONFIG_ARM64_MTE */ 65 - #endif /* __ASSEMBLY__ */ 65 + #endif /* __ASSEMBLER__ */ 66 66 #endif /* __ASM_KVM_MTE_H */
+3 -3
arch/arm64/include/asm/kvm_ptrauth.h
··· 8 8 #ifndef __ASM_KVM_PTRAUTH_H 9 9 #define __ASM_KVM_PTRAUTH_H 10 10 11 - #ifdef __ASSEMBLY__ 11 + #ifdef __ASSEMBLER__ 12 12 13 13 #include <asm/sysreg.h> 14 14 ··· 100 100 .endm 101 101 #endif /* CONFIG_ARM64_PTR_AUTH */ 102 102 103 - #else /* !__ASSEMBLY */ 103 + #else /* !__ASSEMBLER__ */ 104 104 105 105 #define __ptrauth_save_key(ctxt, key) \ 106 106 do { \ ··· 120 120 __ptrauth_save_key(ctxt, APGA); \ 121 121 } while(0) 122 122 123 - #endif /* __ASSEMBLY__ */ 123 + #endif /* __ASSEMBLER__ */ 124 124 #endif /* __ASM_KVM_PTRAUTH_H */
+1 -1
arch/arm64/include/asm/linkage.h
··· 1 1 #ifndef __ASM_LINKAGE_H 2 2 #define __ASM_LINKAGE_H 3 3 4 - #ifdef __ASSEMBLY__ 4 + #ifdef __ASSEMBLER__ 5 5 #include <asm/assembler.h> 6 6 #endif 7 7
+2 -3
arch/arm64/include/asm/memory.h
··· 207 207 */ 208 208 #define TRAMP_SWAPPER_OFFSET (2 * PAGE_SIZE) 209 209 210 - #ifndef __ASSEMBLY__ 210 + #ifndef __ASSEMBLER__ 211 211 212 212 #include <linux/bitops.h> 213 213 #include <linux/compiler.h> ··· 392 392 * virt_to_page(x) convert a _valid_ virtual address to struct page * 393 393 * virt_addr_valid(x) indicates whether a virtual address is valid 394 394 */ 395 - #define ARCH_PFN_OFFSET ((unsigned long)PHYS_PFN_OFFSET) 396 395 397 396 #if defined(CONFIG_DEBUG_VIRTUAL) 398 397 #define page_to_virt(x) ({ \ ··· 421 422 }) 422 423 423 424 void dump_mem_limit(void); 424 - #endif /* !ASSEMBLY */ 425 + #endif /* !__ASSEMBLER__ */ 425 426 426 427 /* 427 428 * Given that the GIC architecture permits ITS implementations that can only be
+2 -2
arch/arm64/include/asm/mmu.h
··· 12 12 #define USER_ASID_FLAG (UL(1) << USER_ASID_BIT) 13 13 #define TTBR_ASID_MASK (UL(0xffff) << 48) 14 14 15 - #ifndef __ASSEMBLY__ 15 + #ifndef __ASSEMBLER__ 16 16 17 17 #include <linux/refcount.h> 18 18 #include <asm/cpufeature.h> ··· 112 112 static inline void kpti_install_ng_mappings(void) {} 113 113 #endif 114 114 115 - #endif /* !__ASSEMBLY__ */ 115 + #endif /* !__ASSEMBLER__ */ 116 116 #endif
+4 -12
arch/arm64/include/asm/mmu_context.h
··· 8 8 #ifndef __ASM_MMU_CONTEXT_H 9 9 #define __ASM_MMU_CONTEXT_H 10 10 11 - #ifndef __ASSEMBLY__ 11 + #ifndef __ASSEMBLER__ 12 12 13 13 #include <linux/compiler.h> 14 14 #include <linux/sched.h> ··· 62 62 } 63 63 64 64 /* 65 - * TCR.T0SZ value to use when the ID map is active. 66 - */ 67 - #define idmap_t0sz TCR_T0SZ(IDMAP_VA_BITS) 68 - 69 - /* 70 65 * Ensure TCR.T0SZ is set to the provided value. 71 66 */ 72 67 static inline void __cpu_set_tcr_t0sz(unsigned long t0sz) ··· 76 81 write_sysreg(tcr, tcr_el1); 77 82 isb(); 78 83 } 79 - 80 - #define cpu_set_default_tcr_t0sz() __cpu_set_tcr_t0sz(TCR_T0SZ(vabits_actual)) 81 - #define cpu_set_idmap_tcr_t0sz() __cpu_set_tcr_t0sz(idmap_t0sz) 82 84 83 85 /* 84 86 * Remove the idmap from TTBR0_EL1 and install the pgd of the active mm. ··· 95 103 96 104 cpu_set_reserved_ttbr0(); 97 105 local_flush_tlb_all(); 98 - cpu_set_default_tcr_t0sz(); 106 + __cpu_set_tcr_t0sz(TCR_T0SZ(vabits_actual)); 99 107 100 108 if (mm != &init_mm && !system_uses_ttbr0_pan()) 101 109 cpu_switch_mm(mm->pgd, mm); ··· 105 113 { 106 114 cpu_set_reserved_ttbr0(); 107 115 local_flush_tlb_all(); 108 - cpu_set_idmap_tcr_t0sz(); 116 + __cpu_set_tcr_t0sz(TCR_T0SZ(IDMAP_VA_BITS)); 109 117 110 118 cpu_switch_mm(lm_alias(idmap_pg_dir), &init_mm); 111 119 } ··· 322 330 323 331 #include <asm-generic/mmu_context.h> 324 332 325 - #endif /* !__ASSEMBLY__ */ 333 + #endif /* !__ASSEMBLER__ */ 326 334 327 335 #endif /* !__ASM_MMU_CONTEXT_H */
+2 -2
arch/arm64/include/asm/mte-kasan.h
··· 9 9 #include <asm/cputype.h> 10 10 #include <asm/mte-def.h> 11 11 12 - #ifndef __ASSEMBLY__ 12 + #ifndef __ASSEMBLER__ 13 13 14 14 #include <linux/types.h> 15 15 ··· 259 259 260 260 #endif /* CONFIG_ARM64_MTE */ 261 261 262 - #endif /* __ASSEMBLY__ */ 262 + #endif /* __ASSEMBLER__ */ 263 263 264 264 #endif /* __ASM_MTE_KASAN_H */
+2 -2
arch/arm64/include/asm/mte.h
··· 8 8 #include <asm/compiler.h> 9 9 #include <asm/mte-def.h> 10 10 11 - #ifndef __ASSEMBLY__ 11 + #ifndef __ASSEMBLER__ 12 12 13 13 #include <linux/bitfield.h> 14 14 #include <linux/kasan-enabled.h> ··· 282 282 } 283 283 #endif /* CONFIG_KASAN_HW_TAGS */ 284 284 285 - #endif /* __ASSEMBLY__ */ 285 + #endif /* __ASSEMBLER__ */ 286 286 #endif /* __ASM_MTE_H */
+2 -2
arch/arm64/include/asm/page.h
··· 10 10 11 11 #include <asm/page-def.h> 12 12 13 - #ifndef __ASSEMBLY__ 13 + #ifndef __ASSEMBLER__ 14 14 15 15 #include <linux/personality.h> /* for READ_IMPLIES_EXEC */ 16 16 #include <linux/types.h> /* for gfp_t */ ··· 45 45 46 46 #include <asm/memory.h> 47 47 48 - #endif /* !__ASSEMBLY__ */ 48 + #endif /* !__ASSEMBLER__ */ 49 49 50 50 #define VM_DATA_DEFAULT_FLAGS (VM_DATA_FLAGS_TSK_EXEC | VM_MTE_ALLOWED) 51 51
+2 -2
arch/arm64/include/asm/pgtable-prot.h
··· 62 62 #define _PAGE_READONLY_EXEC (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN) 63 63 #define _PAGE_EXECONLY (_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN) 64 64 65 - #ifndef __ASSEMBLY__ 65 + #ifndef __ASSEMBLER__ 66 66 67 67 #include <asm/cpufeature.h> 68 68 #include <asm/pgtable-types.h> ··· 127 127 #define PAGE_READONLY_EXEC __pgprot(_PAGE_READONLY_EXEC) 128 128 #define PAGE_EXECONLY __pgprot(_PAGE_EXECONLY) 129 129 130 - #endif /* __ASSEMBLY__ */ 130 + #endif /* __ASSEMBLER__ */ 131 131 132 132 #define pte_pi_index(pte) ( \ 133 133 ((pte & BIT(PTE_PI_IDX_3)) >> (PTE_PI_IDX_3 - 3)) | \
+13 -9
arch/arm64/include/asm/pgtable.h
··· 30 30 31 31 #define vmemmap ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT)) 32 32 33 - #ifndef __ASSEMBLY__ 33 + #ifndef __ASSEMBLER__ 34 34 35 35 #include <asm/cmpxchg.h> 36 36 #include <asm/fixmap.h> ··· 130 130 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 131 131 132 132 /* 133 - * Outside of a few very special situations (e.g. hibernation), we always 134 - * use broadcast TLB invalidation instructions, therefore a spurious page 135 - * fault on one CPU which has been handled concurrently by another CPU 136 - * does not need to perform additional invalidation. 133 + * We use local TLB invalidation instruction when reusing page in 134 + * write protection fault handler to avoid TLBI broadcast in the hot 135 + * path. This will cause spurious page faults if stale read-only TLB 136 + * entries exist. 137 137 */ 138 - #define flush_tlb_fix_spurious_fault(vma, address, ptep) do { } while (0) 138 + #define flush_tlb_fix_spurious_fault(vma, address, ptep) \ 139 + local_flush_tlb_page_nonotify(vma, address) 140 + 141 + #define flush_tlb_fix_spurious_fault_pmd(vma, address, pmdp) \ 142 + local_flush_tlb_page_nonotify(vma, address) 139 143 140 144 /* 141 145 * ZERO_PAGE is a global shared page that is always zero: used ··· 436 432 * 1 0 | 1 0 1 437 433 * 1 1 | 0 1 x 438 434 * 439 - * When hardware DBM is not present, the sofware PTE_DIRTY bit is updated via 435 + * When hardware DBM is not present, the software PTE_DIRTY bit is updated via 440 436 * the page fault mechanism. Checking the dirty status of a pte becomes: 441 437 * 442 438 * PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY) ··· 602 598 /* 603 599 * pte_present_invalid() tells us that the pte is invalid from HW 604 600 * perspective but present from SW perspective, so the fields are to be 605 - * interpretted as per the HW layout. The second 2 checks are the unique 601 + * interpreted as per the HW layout. The second 2 checks are the unique 606 602 * encoding that we use for PROT_NONE. It is insufficient to only use 607 603 * the first check because we share the same encoding scheme with pmds 608 604 * which support pmd_mkinvalid(), so can be present-invalid without ··· 1952 1948 1953 1949 #endif /* CONFIG_ARM64_CONTPTE */ 1954 1950 1955 - #endif /* !__ASSEMBLY__ */ 1951 + #endif /* !__ASSEMBLER__ */ 1956 1952 1957 1953 #endif /* __ASM_PGTABLE_H */
+2 -2
arch/arm64/include/asm/proc-fns.h
··· 9 9 #ifndef __ASM_PROCFNS_H 10 10 #define __ASM_PROCFNS_H 11 11 12 - #ifndef __ASSEMBLY__ 12 + #ifndef __ASSEMBLER__ 13 13 14 14 #include <asm/page.h> 15 15 ··· 21 21 22 22 #include <asm/memory.h> 23 23 24 - #endif /* __ASSEMBLY__ */ 24 + #endif /* __ASSEMBLER__ */ 25 25 #endif /* __ASM_PROCFNS_H */
+2 -2
arch/arm64/include/asm/processor.h
··· 25 25 26 26 #define MTE_CTRL_STORE_ONLY (1UL << 19) 27 27 28 - #ifndef __ASSEMBLY__ 28 + #ifndef __ASSEMBLER__ 29 29 30 30 #include <linux/build_bug.h> 31 31 #include <linux/cache.h> ··· 437 437 #define GET_TSC_CTL(adr) get_tsc_mode((adr)) 438 438 #define SET_TSC_CTL(val) set_tsc_mode((val)) 439 439 440 - #endif /* __ASSEMBLY__ */ 440 + #endif /* __ASSEMBLER__ */ 441 441 #endif /* __ASM_PROCESSOR_H */
+2 -2
arch/arm64/include/asm/ptrace.h
··· 94 94 */ 95 95 #define NO_SYSCALL (-1) 96 96 97 - #ifndef __ASSEMBLY__ 97 + #ifndef __ASSEMBLER__ 98 98 #include <linux/bug.h> 99 99 #include <linux/types.h> 100 100 ··· 361 361 362 362 extern unsigned long profile_pc(struct pt_regs *regs); 363 363 364 - #endif /* __ASSEMBLY__ */ 364 + #endif /* __ASSEMBLER__ */ 365 365 #endif
+2 -2
arch/arm64/include/asm/rsi_smc.h
··· 122 122 */ 123 123 #define SMC_RSI_ATTESTATION_TOKEN_CONTINUE SMC_RSI_FID(0x195) 124 124 125 - #ifndef __ASSEMBLY__ 125 + #ifndef __ASSEMBLER__ 126 126 127 127 struct realm_config { 128 128 union { ··· 142 142 */ 143 143 } __aligned(0x1000); 144 144 145 - #endif /* __ASSEMBLY__ */ 145 + #endif /* __ASSEMBLER__ */ 146 146 147 147 /* 148 148 * Read configuration for the current Realm.
+2 -2
arch/arm64/include/asm/rwonce.h
··· 5 5 #ifndef __ASM_RWONCE_H 6 6 #define __ASM_RWONCE_H 7 7 8 - #if defined(CONFIG_LTO) && !defined(__ASSEMBLY__) 8 + #if defined(CONFIG_LTO) && !defined(__ASSEMBLER__) 9 9 10 10 #include <linux/compiler_types.h> 11 11 #include <asm/alternative-macros.h> ··· 62 62 }) 63 63 64 64 #endif /* !BUILD_VDSO */ 65 - #endif /* CONFIG_LTO && !__ASSEMBLY__ */ 65 + #endif /* CONFIG_LTO && !__ASSEMBLER__ */ 66 66 67 67 #include <asm-generic/rwonce.h> 68 68
+2 -2
arch/arm64/include/asm/scs.h
··· 2 2 #ifndef _ASM_SCS_H 3 3 #define _ASM_SCS_H 4 4 5 - #ifdef __ASSEMBLY__ 5 + #ifdef __ASSEMBLER__ 6 6 7 7 #include <asm/asm-offsets.h> 8 8 #include <asm/sysreg.h> ··· 55 55 56 56 int __pi_scs_patch(const u8 eh_frame[], int size); 57 57 58 - #endif /* __ASSEMBLY __ */ 58 + #endif /* __ASSEMBLER__ */ 59 59 60 60 #endif /* _ASM_SCS_H */
+2 -2
arch/arm64/include/asm/sdei.h
··· 9 9 10 10 #define SDEI_STACK_SIZE IRQ_STACK_SIZE 11 11 12 - #ifndef __ASSEMBLY__ 12 + #ifndef __ASSEMBLER__ 13 13 14 14 #include <linux/linkage.h> 15 15 #include <linux/preempt.h> ··· 49 49 unsigned long sdei_arch_get_entry_point(int conduit); 50 50 #define sdei_arch_get_entry_point(x) sdei_arch_get_entry_point(x) 51 51 52 - #endif /* __ASSEMBLY__ */ 52 + #endif /* __ASSEMBLER__ */ 53 53 #endif /* __ASM_SDEI_H */
+1 -1
arch/arm64/include/asm/simd.h
··· 29 29 */ 30 30 return !WARN_ON(!system_capabilities_finalized()) && 31 31 system_supports_fpsimd() && 32 - !in_hardirq() && !irqs_disabled() && !in_nmi(); 32 + !in_hardirq() && !in_nmi(); 33 33 } 34 34 35 35 #else /* ! CONFIG_KERNEL_MODE_NEON */
+2 -2
arch/arm64/include/asm/smp.h
··· 23 23 #define CPU_STUCK_REASON_52_BIT_VA (UL(1) << CPU_STUCK_REASON_SHIFT) 24 24 #define CPU_STUCK_REASON_NO_GRAN (UL(2) << CPU_STUCK_REASON_SHIFT) 25 25 26 - #ifndef __ASSEMBLY__ 26 + #ifndef __ASSEMBLER__ 27 27 28 28 #include <linux/threads.h> 29 29 #include <linux/cpumask.h> ··· 155 155 extern void crash_smp_send_stop(void); 156 156 extern bool smp_crash_stop_failed(void); 157 157 158 - #endif /* ifndef __ASSEMBLY__ */ 158 + #endif /* ifndef __ASSEMBLER__ */ 159 159 160 160 #endif /* ifndef __ASM_SMP_H */
+2 -2
arch/arm64/include/asm/spectre.h
··· 12 12 #define BP_HARDEN_EL2_SLOTS 4 13 13 #define __BP_HARDEN_HYP_VECS_SZ ((BP_HARDEN_EL2_SLOTS - 1) * SZ_2K) 14 14 15 - #ifndef __ASSEMBLY__ 15 + #ifndef __ASSEMBLER__ 16 16 #include <linux/smp.h> 17 17 #include <asm/percpu.h> 18 18 ··· 118 118 void spectre_bhb_patch_clearbhb(struct alt_instr *alt, 119 119 __le32 *origptr, __le32 *updptr, int nr_inst); 120 120 121 - #endif /* __ASSEMBLY__ */ 121 + #endif /* __ASSEMBLER__ */ 122 122 #endif /* __ASM_SPECTRE_H */
+2 -2
arch/arm64/include/asm/stacktrace/frame.h
··· 25 25 #define FRAME_META_TYPE_FINAL 1 26 26 #define FRAME_META_TYPE_PT_REGS 2 27 27 28 - #ifndef __ASSEMBLY__ 28 + #ifndef __ASSEMBLER__ 29 29 /* 30 30 * A standard AAPCS64 frame record. 31 31 */ ··· 43 43 struct frame_record record; 44 44 u64 type; 45 45 }; 46 - #endif /* __ASSEMBLY */ 46 + #endif /* __ASSEMBLER__ */ 47 47 48 48 #endif /* __ASM_STACKTRACE_FRAME_H */
+1 -1
arch/arm64/include/asm/suspend.h
··· 23 23 * __cpu_suspend_enter()'s caller, and populated by __cpu_suspend_enter(). 24 24 * This data must survive until cpu_resume() is called. 25 25 * 26 - * This struct desribes the size and the layout of the saved cpu state. 26 + * This struct describes the size and the layout of the saved cpu state. 27 27 * The layout of the callee_saved_regs is defined by the implementation 28 28 * of __cpu_suspend_enter(), and cpu_resume(). This struct must be passed 29 29 * in by the caller as __cpu_suspend_enter()'s stack-frame is gone once it
+5 -5
arch/arm64/include/asm/sysreg.h
··· 52 52 53 53 #ifndef CONFIG_BROKEN_GAS_INST 54 54 55 - #ifdef __ASSEMBLY__ 55 + #ifdef __ASSEMBLER__ 56 56 // The space separator is omitted so that __emit_inst(x) can be parsed as 57 57 // either an assembler directive or an assembler macro argument. 58 58 #define __emit_inst(x) .inst(x) ··· 71 71 (((x) >> 24) & 0x000000ff)) 72 72 #endif /* CONFIG_CPU_BIG_ENDIAN */ 73 73 74 - #ifdef __ASSEMBLY__ 74 + #ifdef __ASSEMBLER__ 75 75 #define __emit_inst(x) .long __INSTR_BSWAP(x) 76 - #else /* __ASSEMBLY__ */ 76 + #else /* __ASSEMBLER__ */ 77 77 #define __emit_inst(x) ".long " __stringify(__INSTR_BSWAP(x)) "\n\t" 78 - #endif /* __ASSEMBLY__ */ 78 + #endif /* __ASSEMBLER__ */ 79 79 80 80 #endif /* CONFIG_BROKEN_GAS_INST */ 81 81 ··· 1131 1131 1132 1132 #define ARM64_FEATURE_FIELD_BITS 4 1133 1133 1134 - #ifdef __ASSEMBLY__ 1134 + #ifdef __ASSEMBLER__ 1135 1135 1136 1136 .macro mrs_s, rt, sreg 1137 1137 __emit_inst(0xd5200000|(\sreg)|(.L__gpr_num_\rt))
+2 -2
arch/arm64/include/asm/system_misc.h
··· 7 7 #ifndef __ASM_SYSTEM_MISC_H 8 8 #define __ASM_SYSTEM_MISC_H 9 9 10 - #ifndef __ASSEMBLY__ 10 + #ifndef __ASSEMBLER__ 11 11 12 12 #include <linux/compiler.h> 13 13 #include <linux/linkage.h> ··· 28 28 struct mm_struct; 29 29 extern void __show_regs(struct pt_regs *); 30 30 31 - #endif /* __ASSEMBLY__ */ 31 + #endif /* __ASSEMBLER__ */ 32 32 33 33 #endif /* __ASM_SYSTEM_MISC_H */
+1 -1
arch/arm64/include/asm/thread_info.h
··· 10 10 11 11 #include <linux/compiler.h> 12 12 13 - #ifndef __ASSEMBLY__ 13 + #ifndef __ASSEMBLER__ 14 14 15 15 struct task_struct; 16 16
+84 -1
arch/arm64/include/asm/tlbflush.h
··· 8 8 #ifndef __ASM_TLBFLUSH_H 9 9 #define __ASM_TLBFLUSH_H 10 10 11 - #ifndef __ASSEMBLY__ 11 + #ifndef __ASSEMBLER__ 12 12 13 13 #include <linux/bitfield.h> 14 14 #include <linux/mm_types.h> ··· 249 249 * cannot be easily determined, the value TLBI_TTL_UNKNOWN will 250 250 * perform a non-hinted invalidation. 251 251 * 252 + * local_flush_tlb_page(vma, addr) 253 + * Local variant of flush_tlb_page(). Stale TLB entries may 254 + * remain in remote CPUs. 255 + * 256 + * local_flush_tlb_page_nonotify(vma, addr) 257 + * Same as local_flush_tlb_page() except MMU notifier will not be 258 + * called. 259 + * 260 + * local_flush_tlb_contpte(vma, addr) 261 + * Invalidate the virtual-address range 262 + * '[addr, addr+CONT_PTE_SIZE)' mapped with contpte on local CPU 263 + * for the user address space corresponding to 'vma->mm'. Stale 264 + * TLB entries may remain in remote CPUs. 252 265 * 253 266 * Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented 254 267 * on top of these routines, since that is our interface to the mmu_gather ··· 293 280 __tlbi_user(aside1is, asid); 294 281 dsb(ish); 295 282 mmu_notifier_arch_invalidate_secondary_tlbs(mm, 0, -1UL); 283 + } 284 + 285 + static inline void __local_flush_tlb_page_nonotify_nosync(struct mm_struct *mm, 286 + unsigned long uaddr) 287 + { 288 + unsigned long addr; 289 + 290 + dsb(nshst); 291 + addr = __TLBI_VADDR(uaddr, ASID(mm)); 292 + __tlbi(vale1, addr); 293 + __tlbi_user(vale1, addr); 294 + } 295 + 296 + static inline void local_flush_tlb_page_nonotify(struct vm_area_struct *vma, 297 + unsigned long uaddr) 298 + { 299 + __local_flush_tlb_page_nonotify_nosync(vma->vm_mm, uaddr); 300 + dsb(nsh); 301 + } 302 + 303 + static inline void local_flush_tlb_page(struct vm_area_struct *vma, 304 + unsigned long uaddr) 305 + { 306 + __local_flush_tlb_page_nonotify_nosync(vma->vm_mm, uaddr); 307 + mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, uaddr & PAGE_MASK, 308 + (uaddr & PAGE_MASK) + PAGE_SIZE); 309 + dsb(nsh); 296 310 } 297 311 298 312 static inline void __flush_tlb_page_nosync(struct mm_struct *mm, ··· 512 472 dsb(ish); 513 473 } 514 474 475 + static inline void local_flush_tlb_contpte(struct vm_area_struct *vma, 476 + unsigned long addr) 477 + { 478 + unsigned long asid; 479 + 480 + addr = round_down(addr, CONT_PTE_SIZE); 481 + 482 + dsb(nshst); 483 + asid = ASID(vma->vm_mm); 484 + __flush_tlb_range_op(vale1, addr, CONT_PTES, PAGE_SIZE, asid, 485 + 3, true, lpa2_is_enabled()); 486 + mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, addr, 487 + addr + CONT_PTE_SIZE); 488 + dsb(nsh); 489 + } 490 + 515 491 static inline void flush_tlb_range(struct vm_area_struct *vma, 516 492 unsigned long start, unsigned long end) 517 493 { ··· 580 524 { 581 525 __flush_tlb_range_nosync(mm, start, end, PAGE_SIZE, true, 3); 582 526 } 527 + 528 + static inline bool __pte_flags_need_flush(ptdesc_t oldval, ptdesc_t newval) 529 + { 530 + ptdesc_t diff = oldval ^ newval; 531 + 532 + /* invalid to valid transition requires no flush */ 533 + if (!(oldval & PTE_VALID)) 534 + return false; 535 + 536 + /* Transition in the SW bits requires no flush */ 537 + diff &= ~PTE_SWBITS_MASK; 538 + 539 + return diff; 540 + } 541 + 542 + static inline bool pte_needs_flush(pte_t oldpte, pte_t newpte) 543 + { 544 + return __pte_flags_need_flush(pte_val(oldpte), pte_val(newpte)); 545 + } 546 + #define pte_needs_flush pte_needs_flush 547 + 548 + static inline bool huge_pmd_needs_flush(pmd_t oldpmd, pmd_t newpmd) 549 + { 550 + return __pte_flags_need_flush(pmd_val(oldpmd), pmd_val(newpmd)); 551 + } 552 + #define huge_pmd_needs_flush huge_pmd_needs_flush 553 + 583 554 #endif 584 555 585 556 #endif
+2 -2
arch/arm64/include/asm/vdso.h
··· 7 7 8 8 #define __VDSO_PAGES 4 9 9 10 - #ifndef __ASSEMBLY__ 10 + #ifndef __ASSEMBLER__ 11 11 12 12 #include <generated/vdso-offsets.h> 13 13 ··· 19 19 extern char vdso_start[], vdso_end[]; 20 20 extern char vdso32_start[], vdso32_end[]; 21 21 22 - #endif /* !__ASSEMBLY__ */ 22 + #endif /* !__ASSEMBLER__ */ 23 23 24 24 #endif /* __ASM_VDSO_H */
+2 -2
arch/arm64/include/asm/vdso/compat_barrier.h
··· 5 5 #ifndef __COMPAT_BARRIER_H 6 6 #define __COMPAT_BARRIER_H 7 7 8 - #ifndef __ASSEMBLY__ 8 + #ifndef __ASSEMBLER__ 9 9 /* 10 10 * Warning: This code is meant to be used from the compat vDSO only. 11 11 */ ··· 31 31 #define smp_rmb() aarch32_smp_rmb() 32 32 #define smp_wmb() aarch32_smp_wmb() 33 33 34 - #endif /* !__ASSEMBLY__ */ 34 + #endif /* !__ASSEMBLER__ */ 35 35 36 36 #endif /* __COMPAT_BARRIER_H */
+2 -2
arch/arm64/include/asm/vdso/compat_gettimeofday.h
··· 5 5 #ifndef __ASM_VDSO_COMPAT_GETTIMEOFDAY_H 6 6 #define __ASM_VDSO_COMPAT_GETTIMEOFDAY_H 7 7 8 - #ifndef __ASSEMBLY__ 8 + #ifndef __ASSEMBLER__ 9 9 10 10 #include <asm/barrier.h> 11 11 #include <asm/unistd_compat_32.h> ··· 161 161 } 162 162 #define vdso_clocksource_ok vdso_clocksource_ok 163 163 164 - #endif /* !__ASSEMBLY__ */ 164 + #endif /* !__ASSEMBLER__ */ 165 165 166 166 #endif /* __ASM_VDSO_COMPAT_GETTIMEOFDAY_H */
+2 -2
arch/arm64/include/asm/vdso/getrandom.h
··· 3 3 #ifndef __ASM_VDSO_GETRANDOM_H 4 4 #define __ASM_VDSO_GETRANDOM_H 5 5 6 - #ifndef __ASSEMBLY__ 6 + #ifndef __ASSEMBLER__ 7 7 8 8 #include <asm/unistd.h> 9 9 #include <asm/vdso/vsyscall.h> ··· 33 33 return ret; 34 34 } 35 35 36 - #endif /* !__ASSEMBLY__ */ 36 + #endif /* !__ASSEMBLER__ */ 37 37 38 38 #endif /* __ASM_VDSO_GETRANDOM_H */
+2 -2
arch/arm64/include/asm/vdso/gettimeofday.h
··· 7 7 8 8 #ifdef __aarch64__ 9 9 10 - #ifndef __ASSEMBLY__ 10 + #ifndef __ASSEMBLER__ 11 11 12 12 #include <asm/alternative.h> 13 13 #include <asm/arch_timer.h> ··· 96 96 #define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data 97 97 #endif /* IS_ENABLED(CONFIG_CC_IS_GCC) && IS_ENABLED(CONFIG_PAGE_SIZE_64KB) */ 98 98 99 - #endif /* !__ASSEMBLY__ */ 99 + #endif /* !__ASSEMBLER__ */ 100 100 101 101 #else /* !__aarch64__ */ 102 102
+2 -2
arch/arm64/include/asm/vdso/processor.h
··· 5 5 #ifndef __ASM_VDSO_PROCESSOR_H 6 6 #define __ASM_VDSO_PROCESSOR_H 7 7 8 - #ifndef __ASSEMBLY__ 8 + #ifndef __ASSEMBLER__ 9 9 10 10 static inline void cpu_relax(void) 11 11 { 12 12 asm volatile("yield" ::: "memory"); 13 13 } 14 14 15 - #endif /* __ASSEMBLY__ */ 15 + #endif /* __ASSEMBLER__ */ 16 16 17 17 #endif /* __ASM_VDSO_PROCESSOR_H */
+2 -2
arch/arm64/include/asm/vdso/vsyscall.h
··· 2 2 #ifndef __ASM_VDSO_VSYSCALL_H 3 3 #define __ASM_VDSO_VSYSCALL_H 4 4 5 - #ifndef __ASSEMBLY__ 5 + #ifndef __ASSEMBLER__ 6 6 7 7 #include <vdso/datapage.h> 8 8 ··· 22 22 /* The asm-generic header needs to be included after the definitions above */ 23 23 #include <asm-generic/vdso/vsyscall.h> 24 24 25 - #endif /* !__ASSEMBLY__ */ 25 + #endif /* !__ASSEMBLER__ */ 26 26 27 27 #endif /* __ASM_VDSO_VSYSCALL_H */
+2 -2
arch/arm64/include/asm/virt.h
··· 56 56 */ 57 57 #define BOOT_CPU_FLAG_E2H BIT_ULL(32) 58 58 59 - #ifndef __ASSEMBLY__ 59 + #ifndef __ASSEMBLER__ 60 60 61 61 #include <asm/ptrace.h> 62 62 #include <asm/sections.h> ··· 161 161 return is_hyp_mode_available() && !is_kernel_in_hyp_mode(); 162 162 } 163 163 164 - #endif /* __ASSEMBLY__ */ 164 + #endif /* __ASSEMBLER__ */ 165 165 166 166 #endif /* ! __ASM__VIRT_H */
-4
arch/arm64/include/asm/vmap_stack.h
··· 3 3 #ifndef __ASM_VMAP_STACK_H 4 4 #define __ASM_VMAP_STACK_H 5 5 6 - #include <linux/bug.h> 7 6 #include <linux/gfp.h> 8 - #include <linux/kconfig.h> 9 7 #include <linux/vmalloc.h> 10 8 #include <linux/pgtable.h> 11 9 #include <asm/memory.h> ··· 16 18 static inline unsigned long *arch_alloc_vmap_stack(size_t stack_size, int node) 17 19 { 18 20 void *p; 19 - 20 - BUILD_BUG_ON(!IS_ENABLED(CONFIG_VMAP_STACK)); 21 21 22 22 p = __vmalloc_node(stack_size, THREAD_ALIGN, THREADINFO_GFP, node, 23 23 __builtin_return_address(0));
+1 -1
arch/arm64/include/uapi/asm/kvm.h
··· 31 31 #define KVM_SPSR_FIQ 4 32 32 #define KVM_NR_SPSR 5 33 33 34 - #ifndef __ASSEMBLY__ 34 + #ifndef __ASSEMBLER__ 35 35 #include <linux/psci.h> 36 36 #include <linux/types.h> 37 37 #include <asm/ptrace.h>
+2 -2
arch/arm64/include/uapi/asm/ptrace.h
··· 80 80 #define PTRACE_PEEKMTETAGS 33 81 81 #define PTRACE_POKEMTETAGS 34 82 82 83 - #ifndef __ASSEMBLY__ 83 + #ifndef __ASSEMBLER__ 84 84 85 85 /* 86 86 * User structures for general purpose, floating point and debug registers. ··· 332 332 __u64 gcspr_el0; 333 333 }; 334 334 335 - #endif /* __ASSEMBLY__ */ 335 + #endif /* __ASSEMBLER__ */ 336 336 337 337 #endif /* _UAPI__ASM_PTRACE_H */
+2 -2
arch/arm64/include/uapi/asm/sigcontext.h
··· 17 17 #ifndef _UAPI__ASM_SIGCONTEXT_H 18 18 #define _UAPI__ASM_SIGCONTEXT_H 19 19 20 - #ifndef __ASSEMBLY__ 20 + #ifndef __ASSEMBLER__ 21 21 22 22 #include <linux/types.h> 23 23 ··· 192 192 __u64 reserved; 193 193 }; 194 194 195 - #endif /* !__ASSEMBLY__ */ 195 + #endif /* !__ASSEMBLER__ */ 196 196 197 197 #include <asm/sve_context.h> 198 198
+2 -2
arch/arm64/kernel/acpi.c
··· 133 133 134 134 /* 135 135 * FADT is required on arm64; retrieve it to check its presence 136 - * and carry out revision and ACPI HW reduced compliancy tests 136 + * and carry out revision and ACPI HW reduced compliance tests 137 137 */ 138 138 status = acpi_get_table(ACPI_SIG_FADT, 0, &table); 139 139 if (ACPI_FAILURE(status)) { ··· 439 439 irq_work_run(); 440 440 __irq_exit(); 441 441 } else { 442 - pr_warn_ratelimited("APEI work queued but not completed"); 442 + pr_warn_ratelimited("APEI work queued but not completed\n"); 443 443 err = -EINPROGRESS; 444 444 } 445 445 }
+1 -1
arch/arm64/kernel/cpufeature.c
··· 1002 1002 1003 1003 /* 1004 1004 * Initialise the CPU feature register from Boot CPU values. 1005 - * Also initiliases the strict_mask for the register. 1005 + * Also initialises the strict_mask for the register. 1006 1006 * Any bits that are not covered by an arm64_ftr_bits entry are considered 1007 1007 * RES0 for the system-wide value, and must strictly match. 1008 1008 */
+40 -6
arch/arm64/kernel/efi.c
··· 10 10 #include <linux/efi.h> 11 11 #include <linux/init.h> 12 12 #include <linux/kmemleak.h> 13 + #include <linux/kthread.h> 13 14 #include <linux/screen_info.h> 14 15 #include <linux/vmalloc.h> 15 16 ··· 166 165 return s; 167 166 } 168 167 169 - static DEFINE_RAW_SPINLOCK(efi_rt_lock); 170 - 171 168 void arch_efi_call_virt_setup(void) 172 169 { 173 - efi_virtmap_load(); 174 - raw_spin_lock(&efi_rt_lock); 170 + efi_runtime_assert_lock_held(); 171 + 172 + if (preemptible() && (current->flags & PF_KTHREAD)) { 173 + /* 174 + * Disable migration to ensure that a preempted EFI runtime 175 + * service call will be resumed on the same CPU. This avoids 176 + * potential issues with EFI runtime calls that are preempted 177 + * while polling for an asynchronous completion of a secure 178 + * firmware call, which may not permit the CPU to change. 179 + */ 180 + migrate_disable(); 181 + kthread_use_mm(&efi_mm); 182 + } else { 183 + efi_virtmap_load(); 184 + } 185 + 186 + /* 187 + * Enable access to the valid TTBR0_EL1 and invoke the errata 188 + * workaround directly since there is no return from exception when 189 + * invoking the EFI run-time services. 190 + */ 191 + uaccess_ttbr0_enable(); 192 + post_ttbr_update_workaround(); 193 + 175 194 __efi_fpsimd_begin(); 176 195 } 177 196 178 197 void arch_efi_call_virt_teardown(void) 179 198 { 180 199 __efi_fpsimd_end(); 181 - raw_spin_unlock(&efi_rt_lock); 182 - efi_virtmap_unload(); 200 + 201 + /* 202 + * Defer the switch to the current thread's TTBR0_EL1 until 203 + * uaccess_enable(). Do so before efi_virtmap_unload() updates the 204 + * saved TTBR0 value, so the userland page tables are not activated 205 + * inadvertently over the back of an exception. 206 + */ 207 + uaccess_ttbr0_disable(); 208 + 209 + if (preemptible() && (current->flags & PF_KTHREAD)) { 210 + kthread_unuse_mm(&efi_mm); 211 + migrate_enable(); 212 + } else { 213 + efi_virtmap_unload(); 214 + } 183 215 } 184 216 185 217 asmlinkage u64 *efi_rt_stack_top __ro_after_init;
+3 -25
arch/arm64/kernel/entry-common.c
··· 34 34 * Handle IRQ/context state management when entering from kernel mode. 35 35 * Before this function is called it is not safe to call regular kernel code, 36 36 * instrumentable code, or any code which may trigger an exception. 37 - * 38 - * This is intended to match the logic in irqentry_enter(), handling the kernel 39 - * mode transitions only. 40 37 */ 41 - static __always_inline irqentry_state_t __enter_from_kernel_mode(struct pt_regs *regs) 42 - { 43 - return irqentry_enter(regs); 44 - } 45 - 46 38 static noinstr irqentry_state_t enter_from_kernel_mode(struct pt_regs *regs) 47 39 { 48 40 irqentry_state_t state; 49 41 50 - state = __enter_from_kernel_mode(regs); 42 + state = irqentry_enter(regs); 51 43 mte_check_tfsr_entry(); 52 44 mte_disable_tco_entry(current); 53 45 ··· 50 58 * Handle IRQ/context state management when exiting to kernel mode. 51 59 * After this function returns it is not safe to call regular kernel code, 52 60 * instrumentable code, or any code which may trigger an exception. 53 - * 54 - * This is intended to match the logic in irqentry_exit(), handling the kernel 55 - * mode transitions only, and with preemption handled elsewhere. 56 61 */ 57 - static __always_inline void __exit_to_kernel_mode(struct pt_regs *regs, 58 - irqentry_state_t state) 59 - { 60 - irqentry_exit(regs, state); 61 - } 62 - 63 62 static void noinstr exit_to_kernel_mode(struct pt_regs *regs, 64 63 irqentry_state_t state) 65 64 { 66 65 mte_check_tfsr_exit(); 67 - __exit_to_kernel_mode(regs, state); 66 + irqentry_exit(regs, state); 68 67 } 69 68 70 69 /* ··· 63 80 * Before this function is called it is not safe to call regular kernel code, 64 81 * instrumentable code, or any code which may trigger an exception. 65 82 */ 66 - static __always_inline void __enter_from_user_mode(struct pt_regs *regs) 83 + static __always_inline void arm64_enter_from_user_mode(struct pt_regs *regs) 67 84 { 68 85 enter_from_user_mode(regs); 69 86 mte_disable_tco_entry(current); 70 - } 71 - 72 - static __always_inline void arm64_enter_from_user_mode(struct pt_regs *regs) 73 - { 74 - __enter_from_user_mode(regs); 75 87 } 76 88 77 89 /*
+1 -1
arch/arm64/kernel/entry-ftrace.S
··· 94 94 stp x29, x30, [sp, #FREGS_SIZE] 95 95 add x29, sp, #FREGS_SIZE 96 96 97 - /* Prepare arguments for the the tracer func */ 97 + /* Prepare arguments for the tracer func */ 98 98 sub x0, x30, #AARCH64_INSN_SIZE // ip (callsite's BL insn) 99 99 mov x1, x9 // parent_ip (callsite's LR) 100 100 mov x3, sp // regs
+21 -8
arch/arm64/kernel/fpsimd.c
··· 225 225 */ 226 226 static void get_cpu_fpsimd_context(void) 227 227 { 228 - if (!IS_ENABLED(CONFIG_PREEMPT_RT)) 229 - local_bh_disable(); 230 - else 228 + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { 229 + /* 230 + * The softirq subsystem lacks a true unmask/mask API, and 231 + * re-enabling softirq processing using local_bh_enable() will 232 + * not only unmask softirqs, it will also result in immediate 233 + * delivery of any pending softirqs. 234 + * This is undesirable when running with IRQs disabled, but in 235 + * that case, there is no need to mask softirqs in the first 236 + * place, so only bother doing so when IRQs are enabled. 237 + */ 238 + if (!irqs_disabled()) 239 + local_bh_disable(); 240 + } else { 231 241 preempt_disable(); 242 + } 232 243 } 233 244 234 245 /* ··· 251 240 */ 252 241 static void put_cpu_fpsimd_context(void) 253 242 { 254 - if (!IS_ENABLED(CONFIG_PREEMPT_RT)) 255 - local_bh_enable(); 256 - else 243 + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { 244 + if (!irqs_disabled()) 245 + local_bh_enable(); 246 + } else { 257 247 preempt_enable(); 248 + } 258 249 } 259 250 260 251 unsigned int task_get_vl(const struct task_struct *task, enum vec_type type) ··· 1947 1934 if (!system_supports_fpsimd()) 1948 1935 return; 1949 1936 1950 - WARN_ON(preemptible()); 1951 - 1952 1937 if (may_use_simd()) { 1953 1938 kernel_neon_begin(); 1954 1939 } else { 1940 + WARN_ON(preemptible()); 1941 + 1955 1942 /* 1956 1943 * If !efi_sve_state, SVE can't be in use yet and doesn't need 1957 1944 * preserving:
+1 -1
arch/arm64/kernel/ftrace.c
··· 492 492 return ret; 493 493 494 494 /* 495 - * When using mcount, callsites in modules may have been initalized to 495 + * When using mcount, callsites in modules may have been initialized to 496 496 * call an arbitrary module PLT (which redirects to the _mcount stub) 497 497 * rather than the ftrace PLT we'll use at runtime (which redirects to 498 498 * the ftrace trampoline). We can ignore the old PLT when initializing
+1 -1
arch/arm64/kernel/irq.c
··· 62 62 } 63 63 } 64 64 65 - #ifndef CONFIG_PREEMPT_RT 65 + #ifdef CONFIG_SOFTIRQ_ON_OWN_STACK 66 66 static void ____do_softirq(struct pt_regs *regs) 67 67 { 68 68 __do_softirq();
+1 -1
arch/arm64/kernel/machine_kexec.c
··· 251 251 * marked as Reserved as memory was allocated via memblock_reserve(). 252 252 * 253 253 * In hibernation, the pages which are Reserved and yet "nosave" are excluded 254 - * from the hibernation iamge. crash_is_nosave() does thich check for crash 254 + * from the hibernation image. crash_is_nosave() does thich check for crash 255 255 * dump kernel and will reduce the total size of hibernation image. 256 256 */ 257 257
+1 -1
arch/arm64/kernel/probes/uprobes.c
··· 131 131 struct uprobe_task *utask = current->utask; 132 132 133 133 /* 134 - * Task has received a fatal signal, so reset back to probbed 134 + * Task has received a fatal signal, so reset back to probed 135 135 * address. 136 136 */ 137 137 instruction_pointer_set(regs, utask->vaddr);
+33 -7
arch/arm64/kernel/ptrace.c
··· 912 912 return -EINVAL; 913 913 914 914 /* 915 - * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by 916 - * vec_set_vector_length(), which will also validate them for us: 915 + * On systems without SVE we accept FPSIMD format writes with 916 + * a VL of 0 to allow exiting streaming mode, otherwise a VL 917 + * is required. 917 918 */ 918 - ret = vec_set_vector_length(target, type, header.vl, 919 - ((unsigned long)header.flags & ~SVE_PT_REGS_MASK) << 16); 920 - if (ret) 921 - return ret; 919 + if (header.vl) { 920 + /* 921 + * If the system does not support SVE we can't 922 + * configure a SVE VL. 923 + */ 924 + if (!system_supports_sve() && type == ARM64_VEC_SVE) 925 + return -EINVAL; 926 + 927 + /* 928 + * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are 929 + * consumed by vec_set_vector_length(), which will 930 + * also validate them for us: 931 + */ 932 + ret = vec_set_vector_length(target, type, header.vl, 933 + ((unsigned long)header.flags & ~SVE_PT_REGS_MASK) << 16); 934 + if (ret) 935 + return ret; 936 + } else { 937 + /* If the system supports SVE we require a VL. */ 938 + if (system_supports_sve()) 939 + return -EINVAL; 940 + 941 + /* 942 + * Only FPSIMD formatted data with no flags set is 943 + * supported. 944 + */ 945 + if (header.flags != SVE_PT_REGS_FPSIMD) 946 + return -EINVAL; 947 + } 922 948 923 949 /* Allocate SME storage if necessary, preserving any existing ZA/ZT state */ 924 950 if (type == ARM64_VEC_SME) { ··· 1042 1016 unsigned int pos, unsigned int count, 1043 1017 const void *kbuf, const void __user *ubuf) 1044 1018 { 1045 - if (!system_supports_sve()) 1019 + if (!system_supports_sve() && !system_supports_sme()) 1046 1020 return -EINVAL; 1047 1021 1048 1022 return sve_set_common(target, regset, pos, count, kbuf, ubuf,
+1 -5
arch/arm64/kernel/sdei.c
··· 63 63 { 64 64 int cpu; 65 65 66 - BUILD_BUG_ON(!IS_ENABLED(CONFIG_VMAP_STACK)); 67 - 68 66 for_each_possible_cpu(cpu) { 69 67 _free_sdei_stack(&sdei_stack_normal_ptr, cpu); 70 68 _free_sdei_stack(&sdei_stack_critical_ptr, cpu); ··· 85 87 { 86 88 int cpu; 87 89 int err = 0; 88 - 89 - BUILD_BUG_ON(!IS_ENABLED(CONFIG_VMAP_STACK)); 90 90 91 91 for_each_possible_cpu(cpu) { 92 92 err = _init_sdei_stack(&sdei_stack_normal_ptr, cpu); ··· 198 202 /* 199 203 * do_sdei_event() returns one of: 200 204 * SDEI_EV_HANDLED - success, return to the interrupted context. 201 - * SDEI_EV_FAILED - failure, return this error code to firmare. 205 + * SDEI_EV_FAILED - failure, return this error code to firmware. 202 206 * virtual-address - success, return to this address. 203 207 */ 204 208 unsigned long __kprobes do_sdei_event(struct pt_regs *regs,
+2 -2
arch/arm64/kernel/smp.c
··· 350 350 351 351 /* 352 352 * Now that the dying CPU is beyond the point of no return w.r.t. 353 - * in-kernel synchronisation, try to get the firwmare to help us to 353 + * in-kernel synchronisation, try to get the firmware to help us to 354 354 * verify that it has really left the kernel before we consider 355 355 * clobbering anything it might still be using. 356 356 */ ··· 523 523 524 524 /* 525 525 * Availability of the acpi handle is sufficient to establish 526 - * that _STA has aleady been checked. No need to recheck here. 526 + * that _STA has already been checked. No need to recheck here. 527 527 */ 528 528 c->hotpluggable = arch_cpu_is_hotpluggable(cpu); 529 529
+1 -1
arch/arm64/kernel/syscall.c
··· 96 96 * (Similarly for HVC and SMC elsewhere.) 97 97 */ 98 98 99 - if (flags & _TIF_MTE_ASYNC_FAULT) { 99 + if (unlikely(flags & _TIF_MTE_ASYNC_FAULT)) { 100 100 /* 101 101 * Process the asynchronous tag check fault before the actual 102 102 * syscall. do_notify_resume() will send a signal to userspace
+1 -1
arch/arm64/kernel/traps.c
··· 922 922 __show_regs(regs); 923 923 924 924 /* 925 - * We use nmi_panic to limit the potential for recusive overflows, and 925 + * We use nmi_panic to limit the potential for recursive overflows, and 926 926 * to get a better stack trace. 927 927 */ 928 928 nmi_panic(NULL, "kernel stack overflow");
+1 -1
arch/arm64/kvm/arch_timer.c
··· 815 815 tpt = tpc = true; 816 816 817 817 /* 818 - * For the poor sods that could not correctly substract one value 818 + * For the poor sods that could not correctly subtract one value 819 819 * from another, trap the full virtual timer and counter. 820 820 */ 821 821 if (has_broken_cntvoff() && timer_get_offset(map->direct_vtimer))
+1 -1
arch/arm64/kvm/arm.c
··· 2441 2441 kvm_nvhe_sym(__icache_flags) = __icache_flags; 2442 2442 kvm_nvhe_sym(kvm_arm_vmid_bits) = kvm_arm_vmid_bits; 2443 2443 2444 - /* Propagate the FGT state to the the nVHE side */ 2444 + /* Propagate the FGT state to the nVHE side */ 2445 2445 kvm_nvhe_sym(hfgrtr_masks) = hfgrtr_masks; 2446 2446 kvm_nvhe_sym(hfgwtr_masks) = hfgwtr_masks; 2447 2447 kvm_nvhe_sym(hfgitr_masks) = hfgitr_masks;
+1 -1
arch/arm64/kvm/hyp/nvhe/ffa.c
··· 115 115 * 116 116 * FFA-1.3 introduces 64-bit variants of the CPU cycle management 117 117 * interfaces. Moreover, FF-A 1.3 clarifies that SMC32 direct requests 118 - * complete with SMC32 direct reponses which *should* allow us use the 118 + * complete with SMC32 direct responses which *should* allow us use the 119 119 * function ID sent by the caller to determine whether to return x8-x17. 120 120 * 121 121 * Note that we also cannot rely on function IDs in the response.
+1 -1
arch/arm64/kvm/mmu.c
··· 1755 1755 1756 1756 /* 1757 1757 * Check if this is non-struct page memory PFN, and cannot support 1758 - * CMOs. It could potentially be unsafe to access as cachable. 1758 + * CMOs. It could potentially be unsafe to access as cacheable. 1759 1759 */ 1760 1760 if (vm_flags & (VM_PFNMAP | VM_MIXEDMAP) && !pfn_is_map_memory(pfn)) { 1761 1761 if (is_vma_cacheable) {
+1 -1
arch/arm64/kvm/nested.c
··· 85 85 /* 86 86 * Let's treat memory allocation failures as benign: If we fail to 87 87 * allocate anything, return an error and keep the allocated array 88 - * alive. Userspace may try to recover by intializing the vcpu 88 + * alive. Userspace may try to recover by initializing the vcpu 89 89 * again, and there is no reason to affect the whole VM for this. 90 90 */ 91 91 num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU;
+1 -2
arch/arm64/mm/contpte.c
··· 622 622 __ptep_set_access_flags(vma, addr, ptep, entry, 0); 623 623 624 624 if (dirty) 625 - __flush_tlb_range(vma, start_addr, addr, 626 - PAGE_SIZE, true, 3); 625 + local_flush_tlb_contpte(vma, start_addr); 627 626 } else { 628 627 __contpte_try_unfold(vma->vm_mm, addr, ptep, orig_pte); 629 628 __ptep_set_access_flags(vma, addr, ptep, entry, dirty);
+6 -2
arch/arm64/mm/fault.c
··· 233 233 pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval, pteval); 234 234 } while (pteval != old_pteval); 235 235 236 - /* Invalidate a stale read-only entry */ 236 + /* 237 + * Invalidate the local stale read-only entry. Remote stale entries 238 + * may still cause page faults and be invalidated via 239 + * flush_tlb_fix_spurious_fault(). 240 + */ 237 241 if (dirty) 238 - flush_tlb_page(vma, address); 242 + local_flush_tlb_page(vma, address); 239 243 return 1; 240 244 } 241 245
+139 -81
arch/arm64/mm/mmu.c
··· 49 49 #define NO_CONT_MAPPINGS BIT(1) 50 50 #define NO_EXEC_MAPPINGS BIT(2) /* assumes FEAT_HPDS is not used */ 51 51 52 + #define INVALID_PHYS_ADDR (-1ULL) 53 + 52 54 DEFINE_STATIC_KEY_FALSE(arm64_ptdump_lock_key); 53 55 54 56 u64 kimage_voffset __ro_after_init; ··· 196 194 } while (ptep++, addr += PAGE_SIZE, addr != end); 197 195 } 198 196 199 - static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, 200 - unsigned long end, phys_addr_t phys, 201 - pgprot_t prot, 202 - phys_addr_t (*pgtable_alloc)(enum pgtable_type), 203 - int flags) 197 + static int alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, 198 + unsigned long end, phys_addr_t phys, 199 + pgprot_t prot, 200 + phys_addr_t (*pgtable_alloc)(enum pgtable_type), 201 + int flags) 204 202 { 205 203 unsigned long next; 206 204 pmd_t pmd = READ_ONCE(*pmdp); ··· 215 213 pmdval |= PMD_TABLE_PXN; 216 214 BUG_ON(!pgtable_alloc); 217 215 pte_phys = pgtable_alloc(TABLE_PTE); 216 + if (pte_phys == INVALID_PHYS_ADDR) 217 + return -ENOMEM; 218 218 ptep = pte_set_fixmap(pte_phys); 219 219 init_clear_pgtable(ptep); 220 220 ptep += pte_index(addr); ··· 248 244 * walker. 249 245 */ 250 246 pte_clear_fixmap(); 247 + 248 + return 0; 251 249 } 252 250 253 - static void init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end, 254 - phys_addr_t phys, pgprot_t prot, 255 - phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags) 251 + static int init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end, 252 + phys_addr_t phys, pgprot_t prot, 253 + phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags) 256 254 { 257 255 unsigned long next; 258 256 ··· 275 269 BUG_ON(!pgattr_change_is_safe(pmd_val(old_pmd), 276 270 READ_ONCE(pmd_val(*pmdp)))); 277 271 } else { 278 - alloc_init_cont_pte(pmdp, addr, next, phys, prot, 279 - pgtable_alloc, flags); 272 + int ret; 273 + 274 + ret = alloc_init_cont_pte(pmdp, addr, next, phys, prot, 275 + pgtable_alloc, flags); 276 + if (ret) 277 + return ret; 280 278 281 279 BUG_ON(pmd_val(old_pmd) != 0 && 282 280 pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp))); 283 281 } 284 282 phys += next - addr; 285 283 } while (pmdp++, addr = next, addr != end); 284 + 285 + return 0; 286 286 } 287 287 288 - static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, 289 - unsigned long end, phys_addr_t phys, 290 - pgprot_t prot, 291 - phys_addr_t (*pgtable_alloc)(enum pgtable_type), 292 - int flags) 288 + static int alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, 289 + unsigned long end, phys_addr_t phys, 290 + pgprot_t prot, 291 + phys_addr_t (*pgtable_alloc)(enum pgtable_type), 292 + int flags) 293 293 { 294 + int ret; 294 295 unsigned long next; 295 296 pud_t pud = READ_ONCE(*pudp); 296 297 pmd_t *pmdp; ··· 314 301 pudval |= PUD_TABLE_PXN; 315 302 BUG_ON(!pgtable_alloc); 316 303 pmd_phys = pgtable_alloc(TABLE_PMD); 304 + if (pmd_phys == INVALID_PHYS_ADDR) 305 + return -ENOMEM; 317 306 pmdp = pmd_set_fixmap(pmd_phys); 318 307 init_clear_pgtable(pmdp); 319 308 pmdp += pmd_index(addr); ··· 335 320 (flags & NO_CONT_MAPPINGS) == 0) 336 321 __prot = __pgprot(pgprot_val(prot) | PTE_CONT); 337 322 338 - init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags); 323 + ret = init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags); 324 + if (ret) 325 + goto out; 339 326 340 327 pmdp += pmd_index(next) - pmd_index(addr); 341 328 phys += next - addr; 342 329 } while (addr = next, addr != end); 343 330 331 + out: 344 332 pmd_clear_fixmap(); 333 + 334 + return ret; 345 335 } 346 336 347 - static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, 348 - phys_addr_t phys, pgprot_t prot, 349 - phys_addr_t (*pgtable_alloc)(enum pgtable_type), 350 - int flags) 337 + static int alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, 338 + phys_addr_t phys, pgprot_t prot, 339 + phys_addr_t (*pgtable_alloc)(enum pgtable_type), 340 + int flags) 351 341 { 342 + int ret = 0; 352 343 unsigned long next; 353 344 p4d_t p4d = READ_ONCE(*p4dp); 354 345 pud_t *pudp; ··· 367 346 p4dval |= P4D_TABLE_PXN; 368 347 BUG_ON(!pgtable_alloc); 369 348 pud_phys = pgtable_alloc(TABLE_PUD); 349 + if (pud_phys == INVALID_PHYS_ADDR) 350 + return -ENOMEM; 370 351 pudp = pud_set_fixmap(pud_phys); 371 352 init_clear_pgtable(pudp); 372 353 pudp += pud_index(addr); ··· 398 375 BUG_ON(!pgattr_change_is_safe(pud_val(old_pud), 399 376 READ_ONCE(pud_val(*pudp)))); 400 377 } else { 401 - alloc_init_cont_pmd(pudp, addr, next, phys, prot, 402 - pgtable_alloc, flags); 378 + ret = alloc_init_cont_pmd(pudp, addr, next, phys, prot, 379 + pgtable_alloc, flags); 380 + if (ret) 381 + goto out; 403 382 404 383 BUG_ON(pud_val(old_pud) != 0 && 405 384 pud_val(old_pud) != READ_ONCE(pud_val(*pudp))); ··· 409 384 phys += next - addr; 410 385 } while (pudp++, addr = next, addr != end); 411 386 387 + out: 412 388 pud_clear_fixmap(); 389 + 390 + return ret; 413 391 } 414 392 415 - static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, 416 - phys_addr_t phys, pgprot_t prot, 417 - phys_addr_t (*pgtable_alloc)(enum pgtable_type), 418 - int flags) 393 + static int alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, 394 + phys_addr_t phys, pgprot_t prot, 395 + phys_addr_t (*pgtable_alloc)(enum pgtable_type), 396 + int flags) 419 397 { 398 + int ret; 420 399 unsigned long next; 421 400 pgd_t pgd = READ_ONCE(*pgdp); 422 401 p4d_t *p4dp; ··· 433 404 pgdval |= PGD_TABLE_PXN; 434 405 BUG_ON(!pgtable_alloc); 435 406 p4d_phys = pgtable_alloc(TABLE_P4D); 407 + if (p4d_phys == INVALID_PHYS_ADDR) 408 + return -ENOMEM; 436 409 p4dp = p4d_set_fixmap(p4d_phys); 437 410 init_clear_pgtable(p4dp); 438 411 p4dp += p4d_index(addr); ··· 449 418 450 419 next = p4d_addr_end(addr, end); 451 420 452 - alloc_init_pud(p4dp, addr, next, phys, prot, 453 - pgtable_alloc, flags); 421 + ret = alloc_init_pud(p4dp, addr, next, phys, prot, 422 + pgtable_alloc, flags); 423 + if (ret) 424 + goto out; 454 425 455 426 BUG_ON(p4d_val(old_p4d) != 0 && 456 427 p4d_val(old_p4d) != READ_ONCE(p4d_val(*p4dp))); ··· 460 427 phys += next - addr; 461 428 } while (p4dp++, addr = next, addr != end); 462 429 430 + out: 463 431 p4d_clear_fixmap(); 432 + 433 + return ret; 464 434 } 465 435 466 - static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, 467 - unsigned long virt, phys_addr_t size, 468 - pgprot_t prot, 469 - phys_addr_t (*pgtable_alloc)(enum pgtable_type), 470 - int flags) 436 + static int __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, 437 + unsigned long virt, phys_addr_t size, 438 + pgprot_t prot, 439 + phys_addr_t (*pgtable_alloc)(enum pgtable_type), 440 + int flags) 471 441 { 442 + int ret; 472 443 unsigned long addr, end, next; 473 444 pgd_t *pgdp = pgd_offset_pgd(pgdir, virt); 474 445 ··· 481 444 * within a page, we cannot map the region as the caller expects. 482 445 */ 483 446 if (WARN_ON((phys ^ virt) & ~PAGE_MASK)) 484 - return; 447 + return -EINVAL; 485 448 486 449 phys &= PAGE_MASK; 487 450 addr = virt & PAGE_MASK; ··· 489 452 490 453 do { 491 454 next = pgd_addr_end(addr, end); 492 - alloc_init_p4d(pgdp, addr, next, phys, prot, pgtable_alloc, 493 - flags); 455 + ret = alloc_init_p4d(pgdp, addr, next, phys, prot, pgtable_alloc, 456 + flags); 457 + if (ret) 458 + return ret; 494 459 phys += next - addr; 495 460 } while (pgdp++, addr = next, addr != end); 461 + 462 + return 0; 496 463 } 497 464 498 - static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, 499 - unsigned long virt, phys_addr_t size, 500 - pgprot_t prot, 501 - phys_addr_t (*pgtable_alloc)(enum pgtable_type), 502 - int flags) 465 + static int __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, 466 + unsigned long virt, phys_addr_t size, 467 + pgprot_t prot, 468 + phys_addr_t (*pgtable_alloc)(enum pgtable_type), 469 + int flags) 503 470 { 471 + int ret; 472 + 504 473 mutex_lock(&fixmap_lock); 505 - __create_pgd_mapping_locked(pgdir, phys, virt, size, prot, 506 - pgtable_alloc, flags); 474 + ret = __create_pgd_mapping_locked(pgdir, phys, virt, size, prot, 475 + pgtable_alloc, flags); 507 476 mutex_unlock(&fixmap_lock); 477 + 478 + return ret; 508 479 } 509 480 510 - #define INVALID_PHYS_ADDR (-1ULL) 481 + static void early_create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, 482 + unsigned long virt, phys_addr_t size, 483 + pgprot_t prot, 484 + phys_addr_t (*pgtable_alloc)(enum pgtable_type), 485 + int flags) 486 + { 487 + int ret; 488 + 489 + ret = __create_pgd_mapping(pgdir, phys, virt, size, prot, pgtable_alloc, 490 + flags); 491 + if (ret) 492 + panic("Failed to create page tables\n"); 493 + } 511 494 512 495 static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp, 513 496 enum pgtable_type pgtable_type) ··· 560 503 } 561 504 562 505 static phys_addr_t 563 - try_pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type, gfp_t gfp) 506 + pgd_pgtable_alloc_init_mm_gfp(enum pgtable_type pgtable_type, gfp_t gfp) 564 507 { 565 508 return __pgd_pgtable_alloc(&init_mm, gfp, pgtable_type); 566 509 } ··· 568 511 static phys_addr_t __maybe_unused 569 512 pgd_pgtable_alloc_init_mm(enum pgtable_type pgtable_type) 570 513 { 571 - phys_addr_t pa; 572 - 573 - pa = __pgd_pgtable_alloc(&init_mm, GFP_PGTABLE_KERNEL, pgtable_type); 574 - BUG_ON(pa == INVALID_PHYS_ADDR); 575 - return pa; 514 + return pgd_pgtable_alloc_init_mm_gfp(pgtable_type, GFP_PGTABLE_KERNEL); 576 515 } 577 516 578 517 static phys_addr_t 579 518 pgd_pgtable_alloc_special_mm(enum pgtable_type pgtable_type) 580 519 { 581 - phys_addr_t pa; 582 - 583 - pa = __pgd_pgtable_alloc(NULL, GFP_PGTABLE_KERNEL, pgtable_type); 584 - BUG_ON(pa == INVALID_PHYS_ADDR); 585 - return pa; 520 + return __pgd_pgtable_alloc(NULL, GFP_PGTABLE_KERNEL, pgtable_type); 586 521 } 587 522 588 523 static void split_contpte(pte_t *ptep) ··· 595 546 pte_t *ptep; 596 547 int i; 597 548 598 - pte_phys = try_pgd_pgtable_alloc_init_mm(TABLE_PTE, gfp); 549 + pte_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PTE, gfp); 599 550 if (pte_phys == INVALID_PHYS_ADDR) 600 551 return -ENOMEM; 601 552 ptep = (pte_t *)phys_to_virt(pte_phys); ··· 640 591 pmd_t *pmdp; 641 592 int i; 642 593 643 - pmd_phys = try_pgd_pgtable_alloc_init_mm(TABLE_PMD, gfp); 594 + pmd_phys = pgd_pgtable_alloc_init_mm_gfp(TABLE_PMD, gfp); 644 595 if (pmd_phys == INVALID_PHYS_ADDR) 645 596 return -ENOMEM; 646 597 pmdp = (pmd_t *)phys_to_virt(pmd_phys); ··· 952 903 &phys, virt); 953 904 return; 954 905 } 955 - __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, 956 - NO_CONT_MAPPINGS); 906 + early_create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, 907 + NO_CONT_MAPPINGS); 957 908 } 958 909 959 910 void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, ··· 967 918 if (page_mappings_only) 968 919 flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; 969 920 970 - __create_pgd_mapping(mm->pgd, phys, virt, size, prot, 971 - pgd_pgtable_alloc_special_mm, flags); 921 + early_create_pgd_mapping(mm->pgd, phys, virt, size, prot, 922 + pgd_pgtable_alloc_special_mm, flags); 972 923 } 973 924 974 925 static void update_mapping_prot(phys_addr_t phys, unsigned long virt, ··· 980 931 return; 981 932 } 982 933 983 - __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, 984 - NO_CONT_MAPPINGS); 934 + early_create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, 935 + NO_CONT_MAPPINGS); 985 936 986 937 /* flush the TLBs after updating live kernel mappings */ 987 938 flush_tlb_kernel_range(virt, virt + size); ··· 990 941 static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start, 991 942 phys_addr_t end, pgprot_t prot, int flags) 992 943 { 993 - __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start, 994 - prot, early_pgtable_alloc, flags); 944 + early_create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start, 945 + prot, early_pgtable_alloc, flags); 995 946 } 996 947 997 948 void __init mark_linear_text_alias_ro(void) ··· 1207 1158 remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings); 1208 1159 1209 1160 if (!cpu) { 1161 + int ret; 1162 + 1210 1163 alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order); 1211 1164 kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE); 1212 1165 kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd); ··· 1229 1178 // covers the PTE[] page itself, the remaining entries are free 1230 1179 // to be used as a ad-hoc fixmap. 1231 1180 // 1232 - __create_pgd_mapping_locked(kpti_ng_temp_pgd, __pa(alloc), 1233 - KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL, 1234 - kpti_ng_pgd_alloc, 0); 1181 + ret = __create_pgd_mapping_locked(kpti_ng_temp_pgd, __pa(alloc), 1182 + KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL, 1183 + kpti_ng_pgd_alloc, 0); 1184 + if (ret) 1185 + panic("Failed to create page tables\n"); 1235 1186 } 1236 1187 1237 1188 cpu_install_idmap(); ··· 1286 1233 1287 1234 /* Map only the text into the trampoline page table */ 1288 1235 memset(tramp_pg_dir, 0, PGD_SIZE); 1289 - __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, 1290 - entry_tramp_text_size(), prot, 1291 - pgd_pgtable_alloc_init_mm, NO_BLOCK_MAPPINGS); 1236 + early_create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, 1237 + entry_tramp_text_size(), prot, 1238 + pgd_pgtable_alloc_init_mm, NO_BLOCK_MAPPINGS); 1292 1239 1293 1240 /* Map both the text and data into the kernel page table */ 1294 1241 for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++) ··· 1930 1877 if (force_pte_mapping()) 1931 1878 flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; 1932 1879 1933 - __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), 1934 - size, params->pgprot, pgd_pgtable_alloc_init_mm, 1935 - flags); 1880 + ret = __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), 1881 + size, params->pgprot, pgd_pgtable_alloc_init_mm, 1882 + flags); 1883 + if (ret) 1884 + goto err; 1936 1885 1937 1886 memblock_clear_nomap(start, size); 1938 1887 1939 1888 ret = __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT, 1940 1889 params); 1941 1890 if (ret) 1942 - __remove_pgd_mapping(swapper_pg_dir, 1943 - __phys_to_virt(start), size); 1944 - else { 1945 - /* Address of hotplugged memory can be smaller */ 1946 - max_pfn = max(max_pfn, PFN_UP(start + size)); 1947 - max_low_pfn = max_pfn; 1948 - } 1891 + goto err; 1949 1892 1893 + /* Address of hotplugged memory can be smaller */ 1894 + max_pfn = max(max_pfn, PFN_UP(start + size)); 1895 + max_low_pfn = max_pfn; 1896 + 1897 + return 0; 1898 + 1899 + err: 1900 + __remove_pgd_mapping(swapper_pg_dir, 1901 + __phys_to_virt(start), size); 1950 1902 return ret; 1951 1903 } 1952 1904
+4 -3
arch/arm64/mm/pageattr.c
··· 148 148 unsigned long size = PAGE_SIZE * numpages; 149 149 unsigned long end = start + size; 150 150 struct vm_struct *area; 151 - int i; 152 151 153 152 if (!PAGE_ALIGNED(addr)) { 154 153 start &= PAGE_MASK; ··· 183 184 */ 184 185 if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY || 185 186 pgprot_val(clear_mask) == PTE_RDONLY)) { 186 - for (i = 0; i < area->nr_pages; i++) { 187 - __change_memory_common((u64)page_address(area->pages[i]), 187 + unsigned long idx = (start - (unsigned long)kasan_reset_tag(area->addr)) 188 + >> PAGE_SHIFT; 189 + for (; numpages; idx++, numpages--) { 190 + __change_memory_common((u64)page_address(area->pages[idx]), 188 191 PAGE_SIZE, set_mask, clear_mask); 189 192 } 190 193 }
+1 -1
arch/arm64/mm/pgd.c
··· 56 56 * With 52-bit physical addresses, the architecture requires the 57 57 * top-level table to be aligned to at least 64 bytes. 58 58 */ 59 - BUILD_BUG_ON(PGD_SIZE < 64); 59 + BUILD_BUG_ON(!IS_ALIGNED(PGD_SIZE, 64)); 60 60 #endif 61 61 62 62 /*
+1 -1
arch/arm64/net/bpf_jit_comp.c
··· 3053 3053 /* We unwind through both kernel frames starting from within bpf_throw 3054 3054 * call and BPF frames. Therefore we require FP unwinder to be enabled 3055 3055 * to walk kernel frames and reach BPF frames in the stack trace. 3056 - * ARM64 kernel is aways compiled with CONFIG_FRAME_POINTER=y 3056 + * ARM64 kernel is always compiled with CONFIG_FRAME_POINTER=y 3057 3057 */ 3058 3058 return true; 3059 3059 }
+2
drivers/Kconfig
··· 251 251 252 252 source "drivers/cdx/Kconfig" 253 253 254 + source "drivers/resctrl/Kconfig" 255 + 254 256 endmenu
+1
drivers/Makefile
··· 194 194 obj-$(CONFIG_DRM_ACCEL) += accel/ 195 195 obj-$(CONFIG_CDX_BUS) += cdx/ 196 196 obj-$(CONFIG_DPLL) += dpll/ 197 + obj-y += resctrl/ 197 198 198 199 obj-$(CONFIG_DIBS) += dibs/ 199 200 obj-$(CONFIG_S390) += s390/
+3
drivers/acpi/arm64/Kconfig
··· 21 21 22 22 config ACPI_APMT 23 23 bool 24 + 25 + config ACPI_MPAM 26 + bool
+1
drivers/acpi/arm64/Makefile
··· 4 4 obj-$(CONFIG_ACPI_FFH) += ffh.o 5 5 obj-$(CONFIG_ACPI_GTDT) += gtdt.o 6 6 obj-$(CONFIG_ACPI_IORT) += iort.o 7 + obj-$(CONFIG_ACPI_MPAM) += mpam.o 7 8 obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o 8 9 obj-$(CONFIG_ARM_AMBA) += amba.o 9 10 obj-y += dma.o init.o
-34
drivers/acpi/arm64/gtdt.c
··· 303 303 return -EINVAL; 304 304 } 305 305 306 - /** 307 - * acpi_arch_timer_mem_init() - Get the info of all GT blocks in GTDT table. 308 - * @timer_mem: The pointer to the array of struct arch_timer_mem for returning 309 - * the result of parsing. The element number of this array should 310 - * be platform_timer_count(the total number of platform timers). 311 - * @timer_count: It points to a integer variable which is used for storing the 312 - * number of GT blocks we have parsed. 313 - * 314 - * Return: 0 if success, -EINVAL/-ENODEV if error. 315 - */ 316 - int __init acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, 317 - int *timer_count) 318 - { 319 - int ret; 320 - void *platform_timer; 321 - 322 - *timer_count = 0; 323 - for_each_platform_timer(platform_timer) { 324 - if (is_timer_block(platform_timer)) { 325 - ret = gtdt_parse_timer_block(platform_timer, timer_mem); 326 - if (ret) 327 - return ret; 328 - timer_mem++; 329 - (*timer_count)++; 330 - } 331 - } 332 - 333 - if (*timer_count) 334 - pr_info("found %d memory-mapped timer block(s).\n", 335 - *timer_count); 336 - 337 - return 0; 338 - } 339 - 340 306 /* 341 307 * Initialize a SBSA generic Watchdog platform device info from GTDT 342 308 */
+411
drivers/acpi/arm64/mpam.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2025 Arm Ltd. 3 + 4 + /* Parse the MPAM ACPI table feeding the discovered nodes into the driver */ 5 + 6 + #define pr_fmt(fmt) "ACPI MPAM: " fmt 7 + 8 + #include <linux/acpi.h> 9 + #include <linux/arm_mpam.h> 10 + #include <linux/bits.h> 11 + #include <linux/cpu.h> 12 + #include <linux/cpumask.h> 13 + #include <linux/platform_device.h> 14 + 15 + #include <acpi/processor.h> 16 + 17 + /* 18 + * Flags for acpi_table_mpam_msc.*_interrupt_flags. 19 + * See 2.1.1 Interrupt Flags, Table 5, of DEN0065B_MPAM_ACPI_3.0-bet. 20 + */ 21 + #define ACPI_MPAM_MSC_IRQ_MODE BIT(0) 22 + #define ACPI_MPAM_MSC_IRQ_TYPE_MASK GENMASK(2, 1) 23 + #define ACPI_MPAM_MSC_IRQ_TYPE_WIRED 0 24 + #define ACPI_MPAM_MSC_IRQ_AFFINITY_TYPE_MASK BIT(3) 25 + #define ACPI_MPAM_MSC_IRQ_AFFINITY_TYPE_PROCESSOR 0 26 + #define ACPI_MPAM_MSC_IRQ_AFFINITY_TYPE_PROCESSOR_CONTAINER 1 27 + #define ACPI_MPAM_MSC_IRQ_AFFINITY_VALID BIT(4) 28 + 29 + /* 30 + * Encodings for the MSC node body interface type field. 31 + * See 2.1 MPAM MSC node, Table 4 of DEN0065B_MPAM_ACPI_3.0-bet. 32 + */ 33 + #define ACPI_MPAM_MSC_IFACE_MMIO 0x00 34 + #define ACPI_MPAM_MSC_IFACE_PCC 0x0a 35 + 36 + static bool _is_ppi_partition(u32 flags) 37 + { 38 + u32 aff_type, is_ppi; 39 + bool ret; 40 + 41 + is_ppi = FIELD_GET(ACPI_MPAM_MSC_IRQ_AFFINITY_VALID, flags); 42 + if (!is_ppi) 43 + return false; 44 + 45 + aff_type = FIELD_GET(ACPI_MPAM_MSC_IRQ_AFFINITY_TYPE_MASK, flags); 46 + ret = (aff_type == ACPI_MPAM_MSC_IRQ_AFFINITY_TYPE_PROCESSOR_CONTAINER); 47 + if (ret) 48 + pr_err_once("Partitioned interrupts not supported\n"); 49 + 50 + return ret; 51 + } 52 + 53 + static int acpi_mpam_register_irq(struct platform_device *pdev, 54 + u32 intid, u32 flags) 55 + { 56 + int irq; 57 + u32 int_type; 58 + int trigger; 59 + 60 + if (!intid) 61 + return -EINVAL; 62 + 63 + if (_is_ppi_partition(flags)) 64 + return -EINVAL; 65 + 66 + trigger = FIELD_GET(ACPI_MPAM_MSC_IRQ_MODE, flags); 67 + int_type = FIELD_GET(ACPI_MPAM_MSC_IRQ_TYPE_MASK, flags); 68 + if (int_type != ACPI_MPAM_MSC_IRQ_TYPE_WIRED) 69 + return -EINVAL; 70 + 71 + irq = acpi_register_gsi(&pdev->dev, intid, trigger, ACPI_ACTIVE_HIGH); 72 + if (irq < 0) 73 + pr_err_once("Failed to register interrupt 0x%x with ACPI\n", intid); 74 + 75 + return irq; 76 + } 77 + 78 + static void acpi_mpam_parse_irqs(struct platform_device *pdev, 79 + struct acpi_mpam_msc_node *tbl_msc, 80 + struct resource *res, int *res_idx) 81 + { 82 + u32 flags, intid; 83 + int irq; 84 + 85 + intid = tbl_msc->overflow_interrupt; 86 + flags = tbl_msc->overflow_interrupt_flags; 87 + irq = acpi_mpam_register_irq(pdev, intid, flags); 88 + if (irq > 0) 89 + res[(*res_idx)++] = DEFINE_RES_IRQ_NAMED(irq, "overflow"); 90 + 91 + intid = tbl_msc->error_interrupt; 92 + flags = tbl_msc->error_interrupt_flags; 93 + irq = acpi_mpam_register_irq(pdev, intid, flags); 94 + if (irq > 0) 95 + res[(*res_idx)++] = DEFINE_RES_IRQ_NAMED(irq, "error"); 96 + } 97 + 98 + static int acpi_mpam_parse_resource(struct mpam_msc *msc, 99 + struct acpi_mpam_resource_node *res) 100 + { 101 + int level, nid; 102 + u32 cache_id; 103 + 104 + switch (res->locator_type) { 105 + case ACPI_MPAM_LOCATION_TYPE_PROCESSOR_CACHE: 106 + cache_id = res->locator.cache_locator.cache_reference; 107 + level = find_acpi_cache_level_from_id(cache_id); 108 + if (level <= 0) { 109 + pr_err_once("Bad level (%d) for cache with id %u\n", level, cache_id); 110 + return -EINVAL; 111 + } 112 + return mpam_ris_create(msc, res->ris_index, MPAM_CLASS_CACHE, 113 + level, cache_id); 114 + case ACPI_MPAM_LOCATION_TYPE_MEMORY: 115 + nid = pxm_to_node(res->locator.memory_locator.proximity_domain); 116 + if (nid == NUMA_NO_NODE) { 117 + pr_debug("Bad proximity domain %lld, using node 0 instead\n", 118 + res->locator.memory_locator.proximity_domain); 119 + nid = 0; 120 + } 121 + return mpam_ris_create(msc, res->ris_index, MPAM_CLASS_MEMORY, 122 + MPAM_CLASS_ID_DEFAULT, nid); 123 + default: 124 + /* These get discovered later and are treated as unknown */ 125 + return 0; 126 + } 127 + } 128 + 129 + int acpi_mpam_parse_resources(struct mpam_msc *msc, 130 + struct acpi_mpam_msc_node *tbl_msc) 131 + { 132 + int i, err; 133 + char *ptr, *table_end; 134 + struct acpi_mpam_resource_node *resource; 135 + 136 + table_end = (char *)tbl_msc + tbl_msc->length; 137 + ptr = (char *)(tbl_msc + 1); 138 + for (i = 0; i < tbl_msc->num_resource_nodes; i++) { 139 + u64 max_deps, remaining_table; 140 + 141 + if (ptr + sizeof(*resource) > table_end) 142 + return -EINVAL; 143 + 144 + resource = (struct acpi_mpam_resource_node *)ptr; 145 + 146 + remaining_table = table_end - ptr; 147 + max_deps = remaining_table / sizeof(struct acpi_mpam_func_deps); 148 + if (resource->num_functional_deps > max_deps) { 149 + pr_debug("MSC has impossible number of functional dependencies\n"); 150 + return -EINVAL; 151 + } 152 + 153 + err = acpi_mpam_parse_resource(msc, resource); 154 + if (err) 155 + return err; 156 + 157 + ptr += sizeof(*resource); 158 + ptr += resource->num_functional_deps * sizeof(struct acpi_mpam_func_deps); 159 + } 160 + 161 + return 0; 162 + } 163 + 164 + /* 165 + * Creates the device power management link and returns true if the 166 + * acpi id is valid and usable for cpu affinity. This is the case 167 + * when the linked device is a processor or a processor container. 168 + */ 169 + static bool __init parse_msc_pm_link(struct acpi_mpam_msc_node *tbl_msc, 170 + struct platform_device *pdev, 171 + u32 *acpi_id) 172 + { 173 + char hid[sizeof(tbl_msc->hardware_id_linked_device) + 1] = { 0 }; 174 + bool acpi_id_valid = false; 175 + struct acpi_device *buddy; 176 + char uid[11]; 177 + int len; 178 + 179 + memcpy(hid, &tbl_msc->hardware_id_linked_device, 180 + sizeof(tbl_msc->hardware_id_linked_device)); 181 + 182 + if (!strcmp(hid, ACPI_PROCESSOR_CONTAINER_HID)) { 183 + *acpi_id = tbl_msc->instance_id_linked_device; 184 + acpi_id_valid = true; 185 + } 186 + 187 + len = snprintf(uid, sizeof(uid), "%u", 188 + tbl_msc->instance_id_linked_device); 189 + if (len >= sizeof(uid)) { 190 + pr_debug("Failed to convert uid of device for power management."); 191 + return acpi_id_valid; 192 + } 193 + 194 + buddy = acpi_dev_get_first_match_dev(hid, uid, -1); 195 + if (buddy) { 196 + device_link_add(&pdev->dev, &buddy->dev, DL_FLAG_STATELESS); 197 + acpi_dev_put(buddy); 198 + } 199 + 200 + return acpi_id_valid; 201 + } 202 + 203 + static int decode_interface_type(struct acpi_mpam_msc_node *tbl_msc, 204 + enum mpam_msc_iface *iface) 205 + { 206 + switch (tbl_msc->interface_type) { 207 + case ACPI_MPAM_MSC_IFACE_MMIO: 208 + *iface = MPAM_IFACE_MMIO; 209 + return 0; 210 + case ACPI_MPAM_MSC_IFACE_PCC: 211 + *iface = MPAM_IFACE_PCC; 212 + return 0; 213 + default: 214 + return -EINVAL; 215 + } 216 + } 217 + 218 + static struct platform_device * __init acpi_mpam_parse_msc(struct acpi_mpam_msc_node *tbl_msc) 219 + { 220 + struct platform_device *pdev __free(platform_device_put) = 221 + platform_device_alloc("mpam_msc", tbl_msc->identifier); 222 + int next_res = 0, next_prop = 0, err; 223 + /* pcc, nrdy, affinity and a sentinel */ 224 + struct property_entry props[4] = { 0 }; 225 + /* mmio, 2xirq, no sentinel. */ 226 + struct resource res[3] = { 0 }; 227 + struct acpi_device *companion; 228 + enum mpam_msc_iface iface; 229 + char uid[16]; 230 + u32 acpi_id; 231 + 232 + if (!pdev) 233 + return ERR_PTR(-ENOMEM); 234 + 235 + /* Some power management is described in the namespace: */ 236 + err = snprintf(uid, sizeof(uid), "%u", tbl_msc->identifier); 237 + if (err > 0 && err < sizeof(uid)) { 238 + companion = acpi_dev_get_first_match_dev("ARMHAA5C", uid, -1); 239 + if (companion) { 240 + ACPI_COMPANION_SET(&pdev->dev, companion); 241 + acpi_dev_put(companion); 242 + } else { 243 + pr_debug("MSC.%u: missing namespace entry\n", tbl_msc->identifier); 244 + } 245 + } 246 + 247 + if (decode_interface_type(tbl_msc, &iface)) { 248 + pr_debug("MSC.%u: unknown interface type\n", tbl_msc->identifier); 249 + return ERR_PTR(-EINVAL); 250 + } 251 + 252 + if (iface == MPAM_IFACE_MMIO) { 253 + res[next_res++] = DEFINE_RES_MEM_NAMED(tbl_msc->base_address, 254 + tbl_msc->mmio_size, 255 + "MPAM:MSC"); 256 + } else if (iface == MPAM_IFACE_PCC) { 257 + props[next_prop++] = PROPERTY_ENTRY_U32("pcc-channel", 258 + tbl_msc->base_address); 259 + } 260 + 261 + acpi_mpam_parse_irqs(pdev, tbl_msc, res, &next_res); 262 + 263 + WARN_ON_ONCE(next_res > ARRAY_SIZE(res)); 264 + err = platform_device_add_resources(pdev, res, next_res); 265 + if (err) 266 + return ERR_PTR(err); 267 + 268 + props[next_prop++] = PROPERTY_ENTRY_U32("arm,not-ready-us", 269 + tbl_msc->max_nrdy_usec); 270 + 271 + /* 272 + * The MSC's CPU affinity is described via its linked power 273 + * management device, but only if it points at a Processor or 274 + * Processor Container. 275 + */ 276 + if (parse_msc_pm_link(tbl_msc, pdev, &acpi_id)) 277 + props[next_prop++] = PROPERTY_ENTRY_U32("cpu_affinity", acpi_id); 278 + 279 + WARN_ON_ONCE(next_prop > ARRAY_SIZE(props) - 1); 280 + err = device_create_managed_software_node(&pdev->dev, props, NULL); 281 + if (err) 282 + return ERR_PTR(err); 283 + 284 + /* 285 + * Stash the table entry for acpi_mpam_parse_resources() to discover 286 + * what this MSC controls. 287 + */ 288 + err = platform_device_add_data(pdev, tbl_msc, tbl_msc->length); 289 + if (err) 290 + return ERR_PTR(err); 291 + 292 + err = platform_device_add(pdev); 293 + if (err) 294 + return ERR_PTR(err); 295 + 296 + return_ptr(pdev); 297 + } 298 + 299 + static int __init acpi_mpam_parse(void) 300 + { 301 + char *table_end, *table_offset; 302 + struct acpi_mpam_msc_node *tbl_msc; 303 + struct platform_device *pdev; 304 + 305 + if (acpi_disabled || !system_supports_mpam()) 306 + return 0; 307 + 308 + struct acpi_table_header *table __free(acpi_put_table) = 309 + acpi_get_table_pointer(ACPI_SIG_MPAM, 0); 310 + 311 + if (IS_ERR(table)) 312 + return 0; 313 + 314 + if (table->revision < 1) { 315 + pr_debug("MPAM ACPI table revision %d not supported\n", table->revision); 316 + return 0; 317 + } 318 + 319 + table_offset = (char *)(table + 1); 320 + table_end = (char *)table + table->length; 321 + 322 + while (table_offset < table_end) { 323 + tbl_msc = (struct acpi_mpam_msc_node *)table_offset; 324 + if (table_offset + sizeof(*tbl_msc) > table_end || 325 + table_offset + tbl_msc->length > table_end) { 326 + pr_err("MSC entry overlaps end of ACPI table\n"); 327 + return -EINVAL; 328 + } 329 + table_offset += tbl_msc->length; 330 + 331 + /* 332 + * If any of the reserved fields are set, make no attempt to 333 + * parse the MSC structure. This MSC will still be counted by 334 + * acpi_mpam_count_msc(), meaning the MPAM driver can't probe 335 + * against all MSC, and will never be enabled. There is no way 336 + * to enable it safely, because we cannot determine safe 337 + * system-wide partid and pmg ranges in this situation. 338 + */ 339 + if (tbl_msc->reserved || tbl_msc->reserved1 || tbl_msc->reserved2) { 340 + pr_err_once("Unrecognised MSC, MPAM not usable\n"); 341 + pr_debug("MSC.%u: reserved field set\n", tbl_msc->identifier); 342 + continue; 343 + } 344 + 345 + if (!tbl_msc->mmio_size) { 346 + pr_debug("MSC.%u: marked as disabled\n", tbl_msc->identifier); 347 + continue; 348 + } 349 + 350 + pdev = acpi_mpam_parse_msc(tbl_msc); 351 + if (IS_ERR(pdev)) 352 + return PTR_ERR(pdev); 353 + } 354 + 355 + return 0; 356 + } 357 + 358 + /** 359 + * acpi_mpam_count_msc() - Count the number of MSC described by firmware. 360 + * 361 + * Returns the number of MSCs, or zero for an error. 362 + * 363 + * This can be called before or in parallel with acpi_mpam_parse(). 364 + */ 365 + int acpi_mpam_count_msc(void) 366 + { 367 + char *table_end, *table_offset; 368 + struct acpi_mpam_msc_node *tbl_msc; 369 + int count = 0; 370 + 371 + if (acpi_disabled || !system_supports_mpam()) 372 + return 0; 373 + 374 + struct acpi_table_header *table __free(acpi_put_table) = 375 + acpi_get_table_pointer(ACPI_SIG_MPAM, 0); 376 + 377 + if (IS_ERR(table)) 378 + return 0; 379 + 380 + if (table->revision < 1) 381 + return 0; 382 + 383 + table_offset = (char *)(table + 1); 384 + table_end = (char *)table + table->length; 385 + 386 + while (table_offset < table_end) { 387 + tbl_msc = (struct acpi_mpam_msc_node *)table_offset; 388 + 389 + if (table_offset + sizeof(*tbl_msc) > table_end) 390 + return -EINVAL; 391 + if (tbl_msc->length < sizeof(*tbl_msc)) 392 + return -EINVAL; 393 + if (tbl_msc->length > table_end - table_offset) 394 + return -EINVAL; 395 + table_offset += tbl_msc->length; 396 + 397 + if (!tbl_msc->mmio_size) 398 + continue; 399 + 400 + count++; 401 + } 402 + 403 + return count; 404 + } 405 + 406 + /* 407 + * Call after ACPI devices have been created, which happens behind acpi_scan_init() 408 + * called from subsys_initcall(). PCC requires the mailbox driver, which is 409 + * initialised from postcore_initcall(). 410 + */ 411 + subsys_initcall_sync(acpi_mpam_parse);
+263 -17
drivers/acpi/pptt.c
··· 21 21 #include <linux/cacheinfo.h> 22 22 #include <acpi/processor.h> 23 23 24 + /* 25 + * The acpi_pptt_cache_v1 in actbl2.h, which is imported from acpica, 26 + * only contains the cache_id field rather than all the fields of the 27 + * Cache Type Structure. Use this alternative structure until it is 28 + * resolved in acpica. 29 + */ 30 + struct acpi_pptt_cache_v1_full { 31 + struct acpi_subtable_header header; 32 + u16 reserved; 33 + u32 flags; 34 + u32 next_level_of_cache; 35 + u32 size; 36 + u32 number_of_sets; 37 + u8 associativity; 38 + u8 attributes; 39 + u16 line_size; 40 + u32 cache_id; 41 + } __packed; 42 + 24 43 static struct acpi_subtable_header *fetch_pptt_subtable(struct acpi_table_header *table_hdr, 25 44 u32 pptt_ref) 26 45 { ··· 73 54 u32 pptt_ref) 74 55 { 75 56 return (struct acpi_pptt_cache *)fetch_pptt_subtable(table_hdr, pptt_ref); 57 + } 58 + 59 + static struct acpi_pptt_cache_v1_full *upgrade_pptt_cache(struct acpi_pptt_cache *cache) 60 + { 61 + if (cache->header.length < sizeof(struct acpi_pptt_cache_v1_full)) 62 + return NULL; 63 + 64 + /* No use for v1 if the only additional field is invalid */ 65 + if (!(cache->flags & ACPI_PPTT_CACHE_ID_VALID)) 66 + return NULL; 67 + 68 + return (struct acpi_pptt_cache_v1_full *)cache; 76 69 } 77 70 78 71 static struct acpi_subtable_header *acpi_get_pptt_resource(struct acpi_table_header *table_hdr, ··· 208 177 } 209 178 210 179 /** 211 - * acpi_count_levels() - Given a PPTT table, and a CPU node, count the cache 212 - * levels and split cache levels (data/instruction). 180 + * acpi_count_levels() - Given a PPTT table, and a CPU node, count the 181 + * total number of levels and split cache levels (data/instruction). 213 182 * @table_hdr: Pointer to the head of the PPTT table 214 183 * @cpu_node: processor node we wish to count caches for 215 - * @levels: Number of levels if success. 216 184 * @split_levels: Number of split cache levels (data/instruction) if 217 185 * success. Can by NULL. 218 186 * 187 + * Return: number of levels. 219 188 * Given a processor node containing a processing unit, walk into it and count 220 189 * how many levels exist solely for it, and then walk up each level until we hit 221 190 * the root node (ignore the package level because it may be possible to have ··· 223 192 * split cache levels (data/instruction) that exist at each level on the way 224 193 * up. 225 194 */ 226 - static void acpi_count_levels(struct acpi_table_header *table_hdr, 227 - struct acpi_pptt_processor *cpu_node, 228 - unsigned int *levels, unsigned int *split_levels) 195 + static int acpi_count_levels(struct acpi_table_header *table_hdr, 196 + struct acpi_pptt_processor *cpu_node, 197 + unsigned int *split_levels) 229 198 { 199 + int current_level = 0; 200 + 230 201 do { 231 - acpi_find_cache_level(table_hdr, cpu_node, levels, split_levels, 0, 0); 202 + acpi_find_cache_level(table_hdr, cpu_node, &current_level, split_levels, 0, 0); 232 203 cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent); 233 204 } while (cpu_node); 205 + 206 + return current_level; 234 207 } 235 208 236 209 /** ··· 386 351 * @this_leaf: Kernel cache info structure being updated 387 352 * @found_cache: The PPTT node describing this cache instance 388 353 * @cpu_node: A unique reference to describe this cache instance 389 - * @revision: The revision of the PPTT table 390 354 * 391 355 * The ACPI spec implies that the fields in the cache structures are used to 392 356 * extend and correct the information probed from the hardware. Lets only ··· 395 361 */ 396 362 static void update_cache_properties(struct cacheinfo *this_leaf, 397 363 struct acpi_pptt_cache *found_cache, 398 - struct acpi_pptt_processor *cpu_node, 399 - u8 revision) 364 + struct acpi_pptt_processor *cpu_node) 400 365 { 401 - struct acpi_pptt_cache_v1* found_cache_v1; 366 + struct acpi_pptt_cache_v1_full *found_cache_v1; 402 367 403 368 this_leaf->fw_token = cpu_node; 404 369 if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID) ··· 447 414 found_cache->flags & ACPI_PPTT_CACHE_TYPE_VALID) 448 415 this_leaf->type = CACHE_TYPE_UNIFIED; 449 416 450 - if (revision >= 3 && (found_cache->flags & ACPI_PPTT_CACHE_ID_VALID)) { 451 - found_cache_v1 = ACPI_ADD_PTR(struct acpi_pptt_cache_v1, 452 - found_cache, sizeof(struct acpi_pptt_cache)); 417 + found_cache_v1 = upgrade_pptt_cache(found_cache); 418 + if (found_cache_v1) { 453 419 this_leaf->id = found_cache_v1->cache_id; 454 420 this_leaf->attributes |= CACHE_ID; 455 421 } ··· 473 441 pr_debug("found = %p %p\n", found_cache, cpu_node); 474 442 if (found_cache) 475 443 update_cache_properties(this_leaf, found_cache, 476 - ACPI_TO_POINTER(ACPI_PTR_DIFF(cpu_node, table)), 477 - table->revision); 444 + ACPI_TO_POINTER(ACPI_PTR_DIFF(cpu_node, table))); 478 445 479 446 index++; 480 447 } ··· 676 645 if (!cpu_node) 677 646 return -ENOENT; 678 647 679 - acpi_count_levels(table, cpu_node, levels, split_levels); 648 + *levels = acpi_count_levels(table, cpu_node, split_levels); 680 649 681 650 pr_debug("Cache Setup: last_level=%d split_levels=%d\n", 682 651 *levels, split_levels ? *split_levels : -1); ··· 847 816 { 848 817 return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE, 849 818 ACPI_PPTT_ACPI_IDENTICAL); 819 + } 820 + 821 + /** 822 + * acpi_pptt_get_child_cpus() - Find all the CPUs below a PPTT 823 + * processor hierarchy node 824 + * 825 + * @table_hdr: A reference to the PPTT table 826 + * @parent_node: A pointer to the processor hierarchy node in the 827 + * table_hdr 828 + * @cpus: A cpumask to fill with the CPUs below @parent_node 829 + * 830 + * Walks up the PPTT from every possible CPU to find if the provided 831 + * @parent_node is a parent of this CPU. 832 + */ 833 + static void acpi_pptt_get_child_cpus(struct acpi_table_header *table_hdr, 834 + struct acpi_pptt_processor *parent_node, 835 + cpumask_t *cpus) 836 + { 837 + struct acpi_pptt_processor *cpu_node; 838 + u32 acpi_id; 839 + int cpu; 840 + 841 + cpumask_clear(cpus); 842 + 843 + for_each_possible_cpu(cpu) { 844 + acpi_id = get_acpi_id_for_cpu(cpu); 845 + cpu_node = acpi_find_processor_node(table_hdr, acpi_id); 846 + 847 + while (cpu_node) { 848 + if (cpu_node == parent_node) { 849 + cpumask_set_cpu(cpu, cpus); 850 + break; 851 + } 852 + cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent); 853 + } 854 + } 855 + } 856 + 857 + /** 858 + * acpi_pptt_get_cpus_from_container() - Populate a cpumask with all CPUs in a 859 + * processor container 860 + * @acpi_cpu_id: The UID of the processor container 861 + * @cpus: The resulting CPU mask 862 + * 863 + * Find the specified Processor Container, and fill @cpus with all the cpus 864 + * below it. 865 + * 866 + * Not all 'Processor Hierarchy' entries in the PPTT are either a CPU 867 + * or a Processor Container, they may exist purely to describe a 868 + * Private resource. CPUs have to be leaves, so a Processor Container 869 + * is a non-leaf that has the 'ACPI Processor ID valid' flag set. 870 + */ 871 + void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id, cpumask_t *cpus) 872 + { 873 + struct acpi_table_header *table_hdr; 874 + struct acpi_subtable_header *entry; 875 + unsigned long table_end; 876 + u32 proc_sz; 877 + 878 + cpumask_clear(cpus); 879 + 880 + table_hdr = acpi_get_pptt(); 881 + if (!table_hdr) 882 + return; 883 + 884 + table_end = (unsigned long)table_hdr + table_hdr->length; 885 + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, 886 + sizeof(struct acpi_table_pptt)); 887 + proc_sz = sizeof(struct acpi_pptt_processor); 888 + while ((unsigned long)entry + proc_sz <= table_end) { 889 + if (entry->type == ACPI_PPTT_TYPE_PROCESSOR) { 890 + struct acpi_pptt_processor *cpu_node; 891 + 892 + cpu_node = (struct acpi_pptt_processor *)entry; 893 + if (cpu_node->flags & ACPI_PPTT_ACPI_PROCESSOR_ID_VALID && 894 + !acpi_pptt_leaf_node(table_hdr, cpu_node) && 895 + cpu_node->acpi_processor_id == acpi_cpu_id) { 896 + acpi_pptt_get_child_cpus(table_hdr, cpu_node, cpus); 897 + break; 898 + } 899 + } 900 + entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry, 901 + entry->length); 902 + } 903 + } 904 + 905 + /** 906 + * find_acpi_cache_level_from_id() - Get the level of the specified cache 907 + * @cache_id: The id field of the cache 908 + * 909 + * Determine the level relative to any CPU for the cache identified by 910 + * cache_id. This allows the property to be found even if the CPUs are offline. 911 + * 912 + * The returned level can be used to group caches that are peers. 913 + * 914 + * The PPTT table must be rev 3 or later. 915 + * 916 + * If one CPU's L2 is shared with another CPU as L3, this function will return 917 + * an unpredictable value. 918 + * 919 + * Return: -ENOENT if the PPTT doesn't exist, the revision isn't supported or 920 + * the cache cannot be found. 921 + * Otherwise returns a value which represents the level of the specified cache. 922 + */ 923 + int find_acpi_cache_level_from_id(u32 cache_id) 924 + { 925 + int cpu; 926 + struct acpi_table_header *table; 927 + 928 + table = acpi_get_pptt(); 929 + if (!table) 930 + return -ENOENT; 931 + 932 + if (table->revision < 3) 933 + return -ENOENT; 934 + 935 + for_each_possible_cpu(cpu) { 936 + bool empty; 937 + int level = 1; 938 + u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); 939 + struct acpi_pptt_cache *cache; 940 + struct acpi_pptt_processor *cpu_node; 941 + 942 + cpu_node = acpi_find_processor_node(table, acpi_cpu_id); 943 + if (!cpu_node) 944 + continue; 945 + 946 + do { 947 + int cache_type[] = {CACHE_TYPE_INST, CACHE_TYPE_DATA, CACHE_TYPE_UNIFIED}; 948 + 949 + empty = true; 950 + for (int i = 0; i < ARRAY_SIZE(cache_type); i++) { 951 + struct acpi_pptt_cache_v1_full *cache_v1; 952 + 953 + cache = acpi_find_cache_node(table, acpi_cpu_id, cache_type[i], 954 + level, &cpu_node); 955 + if (!cache) 956 + continue; 957 + 958 + empty = false; 959 + 960 + cache_v1 = upgrade_pptt_cache(cache); 961 + if (cache_v1 && cache_v1->cache_id == cache_id) 962 + return level; 963 + } 964 + level++; 965 + } while (!empty); 966 + } 967 + 968 + return -ENOENT; 969 + } 970 + 971 + /** 972 + * acpi_pptt_get_cpumask_from_cache_id() - Get the cpus associated with the 973 + * specified cache 974 + * @cache_id: The id field of the cache 975 + * @cpus: Where to build the cpumask 976 + * 977 + * Determine which CPUs are below this cache in the PPTT. This allows the property 978 + * to be found even if the CPUs are offline. 979 + * 980 + * The PPTT table must be rev 3 or later, 981 + * 982 + * Return: -ENOENT if the PPTT doesn't exist, or the cache cannot be found. 983 + * Otherwise returns 0 and sets the cpus in the provided cpumask. 984 + */ 985 + int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus) 986 + { 987 + int cpu; 988 + struct acpi_table_header *table; 989 + 990 + cpumask_clear(cpus); 991 + 992 + table = acpi_get_pptt(); 993 + if (!table) 994 + return -ENOENT; 995 + 996 + if (table->revision < 3) 997 + return -ENOENT; 998 + 999 + for_each_possible_cpu(cpu) { 1000 + bool empty; 1001 + int level = 1; 1002 + u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); 1003 + struct acpi_pptt_cache *cache; 1004 + struct acpi_pptt_processor *cpu_node; 1005 + 1006 + cpu_node = acpi_find_processor_node(table, acpi_cpu_id); 1007 + if (!cpu_node) 1008 + continue; 1009 + 1010 + do { 1011 + int cache_type[] = {CACHE_TYPE_INST, CACHE_TYPE_DATA, CACHE_TYPE_UNIFIED}; 1012 + 1013 + empty = true; 1014 + for (int i = 0; i < ARRAY_SIZE(cache_type); i++) { 1015 + struct acpi_pptt_cache_v1_full *cache_v1; 1016 + 1017 + cache = acpi_find_cache_node(table, acpi_cpu_id, cache_type[i], 1018 + level, &cpu_node); 1019 + 1020 + if (!cache) 1021 + continue; 1022 + 1023 + empty = false; 1024 + 1025 + cache_v1 = upgrade_pptt_cache(cache); 1026 + if (cache_v1 && cache_v1->cache_id == cache_id) 1027 + cpumask_set_cpu(cpu, cpus); 1028 + } 1029 + level++; 1030 + } while (!empty); 1031 + } 1032 + 1033 + return 0; 850 1034 }
+1 -1
drivers/acpi/tables.c
··· 408 408 ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, 409 409 ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, 410 410 ACPI_SIG_NHLT, ACPI_SIG_AEST, ACPI_SIG_CEDT, ACPI_SIG_AGDI, 411 - ACPI_SIG_NBFT, ACPI_SIG_SWFT}; 411 + ACPI_SIG_NBFT, ACPI_SIG_SWFT, ACPI_SIG_MPAM}; 412 412 413 413 #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) 414 414
+3
drivers/firmware/efi/efi.c
··· 74 74 .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), 75 75 .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), 76 76 .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0}, 77 + #ifdef CONFIG_SCHED_MM_CID 78 + .cpus_allowed_lock = __RAW_SPIN_LOCK_UNLOCKED(efi_mm.cpus_allowed_lock), 79 + #endif 77 80 }; 78 81 79 82 struct workqueue_struct *efi_rts_wq;
+16 -1
drivers/firmware/efi/runtime-wrappers.c
··· 202 202 */ 203 203 static DEFINE_SEMAPHORE(efi_runtime_lock, 1); 204 204 205 + static struct task_struct *efi_runtime_lock_owner; 206 + 205 207 /* 206 208 * Expose the EFI runtime lock to the UV platform 207 209 */ ··· 220 218 const union efi_rts_args *args = efi_rts_work.args; 221 219 efi_status_t status = EFI_NOT_FOUND; 222 220 unsigned long flags; 221 + 222 + efi_runtime_lock_owner = current; 223 223 224 224 arch_efi_call_virt_setup(); 225 225 flags = efi_call_virt_save_flags(); ··· 314 310 315 311 efi_rts_work.status = status; 316 312 complete(&efi_rts_work.efi_rts_comp); 313 + efi_runtime_lock_owner = NULL; 317 314 } 318 315 319 316 static efi_status_t __efi_queue_work(enum efi_rts_ids id, ··· 449 444 if (down_trylock(&efi_runtime_lock)) 450 445 return EFI_NOT_READY; 451 446 447 + efi_runtime_lock_owner = current; 452 448 status = efi_call_virt_pointer(efi.runtime, set_variable, name, vendor, 453 449 attr, data_size, data); 450 + efi_runtime_lock_owner = NULL; 454 451 up(&efi_runtime_lock); 455 452 return status; 456 453 } ··· 488 481 if (down_trylock(&efi_runtime_lock)) 489 482 return EFI_NOT_READY; 490 483 484 + efi_runtime_lock_owner = current; 491 485 status = efi_call_virt_pointer(efi.runtime, query_variable_info, attr, 492 486 storage_space, remaining_space, 493 487 max_variable_size); 488 + efi_runtime_lock_owner = NULL; 494 489 up(&efi_runtime_lock); 495 490 return status; 496 491 } ··· 518 509 return; 519 510 } 520 511 512 + efi_runtime_lock_owner = current; 521 513 arch_efi_call_virt_setup(); 522 514 efi_rts_work.efi_rts_id = EFI_RESET_SYSTEM; 523 515 arch_efi_call_virt(efi.runtime, reset_system, reset_type, status, 524 516 data_size, data); 525 517 arch_efi_call_virt_teardown(); 526 - 518 + efi_runtime_lock_owner = NULL; 527 519 up(&efi_runtime_lock); 528 520 } 529 521 ··· 597 587 } 598 588 599 589 #endif 590 + 591 + void efi_runtime_assert_lock_held(void) 592 + { 593 + WARN_ON(efi_runtime_lock_owner != current); 594 + }
+24
drivers/resctrl/Kconfig
··· 1 + menuconfig ARM64_MPAM_DRIVER 2 + bool "MPAM driver" 3 + depends on ARM64 && ARM64_MPAM && EXPERT 4 + help 5 + Memory System Resource Partitioning and Monitoring (MPAM) driver for 6 + System IP, e.g. caches and memory controllers. 7 + 8 + if ARM64_MPAM_DRIVER 9 + 10 + config ARM64_MPAM_DRIVER_DEBUG 11 + bool "Enable debug messages from the MPAM driver" 12 + help 13 + Say yes here to enable debug messages from the MPAM driver. 14 + 15 + config MPAM_KUNIT_TEST 16 + bool "KUnit tests for MPAM driver " if !KUNIT_ALL_TESTS 17 + depends on KUNIT=y 18 + default KUNIT_ALL_TESTS 19 + help 20 + Enable this option to run tests in the MPAM driver. 21 + 22 + If unsure, say N. 23 + 24 + endif
+4
drivers/resctrl/Makefile
··· 1 + obj-$(CONFIG_ARM64_MPAM_DRIVER) += mpam.o 2 + mpam-y += mpam_devices.o 3 + 4 + ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG) += -DDEBUG
+2723
drivers/resctrl/mpam_devices.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2025 Arm Ltd. 3 + 4 + #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ 5 + 6 + #include <linux/acpi.h> 7 + #include <linux/atomic.h> 8 + #include <linux/arm_mpam.h> 9 + #include <linux/bitfield.h> 10 + #include <linux/bitmap.h> 11 + #include <linux/cacheinfo.h> 12 + #include <linux/cpu.h> 13 + #include <linux/cpumask.h> 14 + #include <linux/device.h> 15 + #include <linux/errno.h> 16 + #include <linux/gfp.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/irq.h> 19 + #include <linux/irqdesc.h> 20 + #include <linux/list.h> 21 + #include <linux/lockdep.h> 22 + #include <linux/mutex.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/printk.h> 25 + #include <linux/srcu.h> 26 + #include <linux/spinlock.h> 27 + #include <linux/types.h> 28 + #include <linux/workqueue.h> 29 + 30 + #include "mpam_internal.h" 31 + 32 + DEFINE_STATIC_KEY_FALSE(mpam_enabled); /* This moves to arch code */ 33 + 34 + /* 35 + * mpam_list_lock protects the SRCU lists when writing. Once the 36 + * mpam_enabled key is enabled these lists are read-only, 37 + * unless the error interrupt disables the driver. 38 + */ 39 + static DEFINE_MUTEX(mpam_list_lock); 40 + static LIST_HEAD(mpam_all_msc); 41 + 42 + struct srcu_struct mpam_srcu; 43 + 44 + /* 45 + * Number of MSCs that have been probed. Once all MSCs have been probed MPAM 46 + * can be enabled. 47 + */ 48 + static atomic_t mpam_num_msc; 49 + 50 + static int mpam_cpuhp_state; 51 + static DEFINE_MUTEX(mpam_cpuhp_state_lock); 52 + 53 + /* 54 + * The smallest common values for any CPU or MSC in the system. 55 + * Generating traffic outside this range will result in screaming interrupts. 56 + */ 57 + u16 mpam_partid_max; 58 + u8 mpam_pmg_max; 59 + static bool partid_max_init, partid_max_published; 60 + static DEFINE_SPINLOCK(partid_max_lock); 61 + 62 + /* 63 + * mpam is enabled once all devices have been probed from CPU online callbacks, 64 + * scheduled via this work_struct. If access to an MSC depends on a CPU that 65 + * was not brought online at boot, this can happen surprisingly late. 66 + */ 67 + static DECLARE_WORK(mpam_enable_work, &mpam_enable); 68 + 69 + /* 70 + * All mpam error interrupts indicate a software bug. On receipt, disable the 71 + * driver. 72 + */ 73 + static DECLARE_WORK(mpam_broken_work, &mpam_disable); 74 + 75 + /* When mpam is disabled, the printed reason to aid debugging */ 76 + static char *mpam_disable_reason; 77 + 78 + /* 79 + * An MSC is a physical container for controls and monitors, each identified by 80 + * their RIS index. These share a base-address, interrupts and some MMIO 81 + * registers. A vMSC is a virtual container for RIS in an MSC that control or 82 + * monitor the same thing. Members of a vMSC are all RIS in the same MSC, but 83 + * not all RIS in an MSC share a vMSC. 84 + * 85 + * Components are a group of vMSC that control or monitor the same thing but 86 + * are from different MSC, so have different base-address, interrupts etc. 87 + * Classes are the set components of the same type. 88 + * 89 + * The features of a vMSC is the union of the RIS it contains. 90 + * The features of a Class and Component are the common subset of the vMSC 91 + * they contain. 92 + * 93 + * e.g. The system cache may have bandwidth controls on multiple interfaces, 94 + * for regulating traffic from devices independently of traffic from CPUs. 95 + * If these are two RIS in one MSC, they will be treated as controlling 96 + * different things, and will not share a vMSC/component/class. 97 + * 98 + * e.g. The L2 may have one MSC and two RIS, one for cache-controls another 99 + * for bandwidth. These two RIS are members of the same vMSC. 100 + * 101 + * e.g. The set of RIS that make up the L2 are grouped as a component. These 102 + * are sometimes termed slices. They should be configured the same, as if there 103 + * were only one. 104 + * 105 + * e.g. The SoC probably has more than one L2, each attached to a distinct set 106 + * of CPUs. All the L2 components are grouped as a class. 107 + * 108 + * When creating an MSC, struct mpam_msc is added to the all mpam_all_msc list, 109 + * then linked via struct mpam_ris to a vmsc, component and class. 110 + * The same MSC may exist under different class->component->vmsc paths, but the 111 + * RIS index will be unique. 112 + */ 113 + LIST_HEAD(mpam_classes); 114 + 115 + /* List of all objects that can be free()d after synchronise_srcu() */ 116 + static LLIST_HEAD(mpam_garbage); 117 + 118 + static inline void init_garbage(struct mpam_garbage *garbage) 119 + { 120 + init_llist_node(&garbage->llist); 121 + } 122 + 123 + #define add_to_garbage(x) \ 124 + do { \ 125 + __typeof__(x) _x = (x); \ 126 + _x->garbage.to_free = _x; \ 127 + llist_add(&_x->garbage.llist, &mpam_garbage); \ 128 + } while (0) 129 + 130 + static void mpam_free_garbage(void) 131 + { 132 + struct mpam_garbage *iter, *tmp; 133 + struct llist_node *to_free = llist_del_all(&mpam_garbage); 134 + 135 + if (!to_free) 136 + return; 137 + 138 + synchronize_srcu(&mpam_srcu); 139 + 140 + llist_for_each_entry_safe(iter, tmp, to_free, llist) { 141 + if (iter->pdev) 142 + devm_kfree(&iter->pdev->dev, iter->to_free); 143 + else 144 + kfree(iter->to_free); 145 + } 146 + } 147 + 148 + /* 149 + * Once mpam is enabled, new requestors cannot further reduce the available 150 + * partid. Assert that the size is fixed, and new requestors will be turned 151 + * away. 152 + */ 153 + static void mpam_assert_partid_sizes_fixed(void) 154 + { 155 + WARN_ON_ONCE(!partid_max_published); 156 + } 157 + 158 + static u32 __mpam_read_reg(struct mpam_msc *msc, u16 reg) 159 + { 160 + WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility)); 161 + 162 + return readl_relaxed(msc->mapped_hwpage + reg); 163 + } 164 + 165 + static inline u32 _mpam_read_partsel_reg(struct mpam_msc *msc, u16 reg) 166 + { 167 + lockdep_assert_held_once(&msc->part_sel_lock); 168 + return __mpam_read_reg(msc, reg); 169 + } 170 + 171 + #define mpam_read_partsel_reg(msc, reg) _mpam_read_partsel_reg(msc, MPAMF_##reg) 172 + 173 + static void __mpam_write_reg(struct mpam_msc *msc, u16 reg, u32 val) 174 + { 175 + WARN_ON_ONCE(reg + sizeof(u32) > msc->mapped_hwpage_sz); 176 + WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility)); 177 + 178 + writel_relaxed(val, msc->mapped_hwpage + reg); 179 + } 180 + 181 + static inline void _mpam_write_partsel_reg(struct mpam_msc *msc, u16 reg, u32 val) 182 + { 183 + lockdep_assert_held_once(&msc->part_sel_lock); 184 + __mpam_write_reg(msc, reg, val); 185 + } 186 + 187 + #define mpam_write_partsel_reg(msc, reg, val) _mpam_write_partsel_reg(msc, MPAMCFG_##reg, val) 188 + 189 + static inline u32 _mpam_read_monsel_reg(struct mpam_msc *msc, u16 reg) 190 + { 191 + mpam_mon_sel_lock_held(msc); 192 + return __mpam_read_reg(msc, reg); 193 + } 194 + 195 + #define mpam_read_monsel_reg(msc, reg) _mpam_read_monsel_reg(msc, MSMON_##reg) 196 + 197 + static inline void _mpam_write_monsel_reg(struct mpam_msc *msc, u16 reg, u32 val) 198 + { 199 + mpam_mon_sel_lock_held(msc); 200 + __mpam_write_reg(msc, reg, val); 201 + } 202 + 203 + #define mpam_write_monsel_reg(msc, reg, val) _mpam_write_monsel_reg(msc, MSMON_##reg, val) 204 + 205 + static u64 mpam_msc_read_idr(struct mpam_msc *msc) 206 + { 207 + u64 idr_high = 0, idr_low; 208 + 209 + lockdep_assert_held(&msc->part_sel_lock); 210 + 211 + idr_low = mpam_read_partsel_reg(msc, IDR); 212 + if (FIELD_GET(MPAMF_IDR_EXT, idr_low)) 213 + idr_high = mpam_read_partsel_reg(msc, IDR + 4); 214 + 215 + return (idr_high << 32) | idr_low; 216 + } 217 + 218 + static void mpam_msc_clear_esr(struct mpam_msc *msc) 219 + { 220 + u64 esr_low = __mpam_read_reg(msc, MPAMF_ESR); 221 + 222 + if (!esr_low) 223 + return; 224 + 225 + /* 226 + * Clearing the high/low bits of MPAMF_ESR can not be atomic. 227 + * Clear the top half first, so that the pending error bits in the 228 + * lower half prevent hardware from updating either half of the 229 + * register. 230 + */ 231 + if (msc->has_extd_esr) 232 + __mpam_write_reg(msc, MPAMF_ESR + 4, 0); 233 + __mpam_write_reg(msc, MPAMF_ESR, 0); 234 + } 235 + 236 + static u64 mpam_msc_read_esr(struct mpam_msc *msc) 237 + { 238 + u64 esr_high = 0, esr_low; 239 + 240 + esr_low = __mpam_read_reg(msc, MPAMF_ESR); 241 + if (msc->has_extd_esr) 242 + esr_high = __mpam_read_reg(msc, MPAMF_ESR + 4); 243 + 244 + return (esr_high << 32) | esr_low; 245 + } 246 + 247 + static void __mpam_part_sel_raw(u32 partsel, struct mpam_msc *msc) 248 + { 249 + lockdep_assert_held(&msc->part_sel_lock); 250 + 251 + mpam_write_partsel_reg(msc, PART_SEL, partsel); 252 + } 253 + 254 + static void __mpam_part_sel(u8 ris_idx, u16 partid, struct mpam_msc *msc) 255 + { 256 + u32 partsel = FIELD_PREP(MPAMCFG_PART_SEL_RIS, ris_idx) | 257 + FIELD_PREP(MPAMCFG_PART_SEL_PARTID_SEL, partid); 258 + 259 + __mpam_part_sel_raw(partsel, msc); 260 + } 261 + 262 + static void __mpam_intpart_sel(u8 ris_idx, u16 intpartid, struct mpam_msc *msc) 263 + { 264 + u32 partsel = FIELD_PREP(MPAMCFG_PART_SEL_RIS, ris_idx) | 265 + FIELD_PREP(MPAMCFG_PART_SEL_PARTID_SEL, intpartid) | 266 + MPAMCFG_PART_SEL_INTERNAL; 267 + 268 + __mpam_part_sel_raw(partsel, msc); 269 + } 270 + 271 + int mpam_register_requestor(u16 partid_max, u8 pmg_max) 272 + { 273 + guard(spinlock)(&partid_max_lock); 274 + if (!partid_max_init) { 275 + mpam_partid_max = partid_max; 276 + mpam_pmg_max = pmg_max; 277 + partid_max_init = true; 278 + } else if (!partid_max_published) { 279 + mpam_partid_max = min(mpam_partid_max, partid_max); 280 + mpam_pmg_max = min(mpam_pmg_max, pmg_max); 281 + } else { 282 + /* New requestors can't lower the values */ 283 + if (partid_max < mpam_partid_max || pmg_max < mpam_pmg_max) 284 + return -EBUSY; 285 + } 286 + 287 + return 0; 288 + } 289 + EXPORT_SYMBOL(mpam_register_requestor); 290 + 291 + static struct mpam_class * 292 + mpam_class_alloc(u8 level_idx, enum mpam_class_types type) 293 + { 294 + struct mpam_class *class; 295 + 296 + lockdep_assert_held(&mpam_list_lock); 297 + 298 + class = kzalloc(sizeof(*class), GFP_KERNEL); 299 + if (!class) 300 + return ERR_PTR(-ENOMEM); 301 + init_garbage(&class->garbage); 302 + 303 + INIT_LIST_HEAD_RCU(&class->components); 304 + /* Affinity is updated when ris are added */ 305 + class->level = level_idx; 306 + class->type = type; 307 + INIT_LIST_HEAD_RCU(&class->classes_list); 308 + ida_init(&class->ida_csu_mon); 309 + ida_init(&class->ida_mbwu_mon); 310 + 311 + list_add_rcu(&class->classes_list, &mpam_classes); 312 + 313 + return class; 314 + } 315 + 316 + static void mpam_class_destroy(struct mpam_class *class) 317 + { 318 + lockdep_assert_held(&mpam_list_lock); 319 + 320 + list_del_rcu(&class->classes_list); 321 + add_to_garbage(class); 322 + } 323 + 324 + static struct mpam_class * 325 + mpam_class_find(u8 level_idx, enum mpam_class_types type) 326 + { 327 + struct mpam_class *class; 328 + 329 + lockdep_assert_held(&mpam_list_lock); 330 + 331 + list_for_each_entry(class, &mpam_classes, classes_list) { 332 + if (class->type == type && class->level == level_idx) 333 + return class; 334 + } 335 + 336 + return mpam_class_alloc(level_idx, type); 337 + } 338 + 339 + static struct mpam_component * 340 + mpam_component_alloc(struct mpam_class *class, int id) 341 + { 342 + struct mpam_component *comp; 343 + 344 + lockdep_assert_held(&mpam_list_lock); 345 + 346 + comp = kzalloc(sizeof(*comp), GFP_KERNEL); 347 + if (!comp) 348 + return ERR_PTR(-ENOMEM); 349 + init_garbage(&comp->garbage); 350 + 351 + comp->comp_id = id; 352 + INIT_LIST_HEAD_RCU(&comp->vmsc); 353 + /* Affinity is updated when RIS are added */ 354 + INIT_LIST_HEAD_RCU(&comp->class_list); 355 + comp->class = class; 356 + 357 + list_add_rcu(&comp->class_list, &class->components); 358 + 359 + return comp; 360 + } 361 + 362 + static void __destroy_component_cfg(struct mpam_component *comp); 363 + 364 + static void mpam_component_destroy(struct mpam_component *comp) 365 + { 366 + struct mpam_class *class = comp->class; 367 + 368 + lockdep_assert_held(&mpam_list_lock); 369 + 370 + __destroy_component_cfg(comp); 371 + 372 + list_del_rcu(&comp->class_list); 373 + add_to_garbage(comp); 374 + 375 + if (list_empty(&class->components)) 376 + mpam_class_destroy(class); 377 + } 378 + 379 + static struct mpam_component * 380 + mpam_component_find(struct mpam_class *class, int id) 381 + { 382 + struct mpam_component *comp; 383 + 384 + lockdep_assert_held(&mpam_list_lock); 385 + 386 + list_for_each_entry(comp, &class->components, class_list) { 387 + if (comp->comp_id == id) 388 + return comp; 389 + } 390 + 391 + return mpam_component_alloc(class, id); 392 + } 393 + 394 + static struct mpam_vmsc * 395 + mpam_vmsc_alloc(struct mpam_component *comp, struct mpam_msc *msc) 396 + { 397 + struct mpam_vmsc *vmsc; 398 + 399 + lockdep_assert_held(&mpam_list_lock); 400 + 401 + vmsc = kzalloc(sizeof(*vmsc), GFP_KERNEL); 402 + if (!vmsc) 403 + return ERR_PTR(-ENOMEM); 404 + init_garbage(&vmsc->garbage); 405 + 406 + INIT_LIST_HEAD_RCU(&vmsc->ris); 407 + INIT_LIST_HEAD_RCU(&vmsc->comp_list); 408 + vmsc->comp = comp; 409 + vmsc->msc = msc; 410 + 411 + list_add_rcu(&vmsc->comp_list, &comp->vmsc); 412 + 413 + return vmsc; 414 + } 415 + 416 + static void mpam_vmsc_destroy(struct mpam_vmsc *vmsc) 417 + { 418 + struct mpam_component *comp = vmsc->comp; 419 + 420 + lockdep_assert_held(&mpam_list_lock); 421 + 422 + list_del_rcu(&vmsc->comp_list); 423 + add_to_garbage(vmsc); 424 + 425 + if (list_empty(&comp->vmsc)) 426 + mpam_component_destroy(comp); 427 + } 428 + 429 + static struct mpam_vmsc * 430 + mpam_vmsc_find(struct mpam_component *comp, struct mpam_msc *msc) 431 + { 432 + struct mpam_vmsc *vmsc; 433 + 434 + lockdep_assert_held(&mpam_list_lock); 435 + 436 + list_for_each_entry(vmsc, &comp->vmsc, comp_list) { 437 + if (vmsc->msc->id == msc->id) 438 + return vmsc; 439 + } 440 + 441 + return mpam_vmsc_alloc(comp, msc); 442 + } 443 + 444 + /* 445 + * The cacheinfo structures are only populated when CPUs are online. 446 + * This helper walks the acpi tables to include offline CPUs too. 447 + */ 448 + int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level, 449 + cpumask_t *affinity) 450 + { 451 + return acpi_pptt_get_cpumask_from_cache_id(cache_id, affinity); 452 + } 453 + 454 + /* 455 + * cpumask_of_node() only knows about online CPUs. This can't tell us whether 456 + * a class is represented on all possible CPUs. 457 + */ 458 + static void get_cpumask_from_node_id(u32 node_id, cpumask_t *affinity) 459 + { 460 + int cpu; 461 + 462 + for_each_possible_cpu(cpu) { 463 + if (node_id == cpu_to_node(cpu)) 464 + cpumask_set_cpu(cpu, affinity); 465 + } 466 + } 467 + 468 + static int mpam_ris_get_affinity(struct mpam_msc *msc, cpumask_t *affinity, 469 + enum mpam_class_types type, 470 + struct mpam_class *class, 471 + struct mpam_component *comp) 472 + { 473 + int err; 474 + 475 + switch (type) { 476 + case MPAM_CLASS_CACHE: 477 + err = mpam_get_cpumask_from_cache_id(comp->comp_id, class->level, 478 + affinity); 479 + if (err) { 480 + dev_warn_once(&msc->pdev->dev, 481 + "Failed to determine CPU affinity\n"); 482 + return err; 483 + } 484 + 485 + if (cpumask_empty(affinity)) 486 + dev_warn_once(&msc->pdev->dev, "no CPUs associated with cache node\n"); 487 + 488 + break; 489 + case MPAM_CLASS_MEMORY: 490 + get_cpumask_from_node_id(comp->comp_id, affinity); 491 + /* affinity may be empty for CPU-less memory nodes */ 492 + break; 493 + case MPAM_CLASS_UNKNOWN: 494 + return 0; 495 + } 496 + 497 + cpumask_and(affinity, affinity, &msc->accessibility); 498 + 499 + return 0; 500 + } 501 + 502 + static int mpam_ris_create_locked(struct mpam_msc *msc, u8 ris_idx, 503 + enum mpam_class_types type, u8 class_id, 504 + int component_id) 505 + { 506 + int err; 507 + struct mpam_vmsc *vmsc; 508 + struct mpam_msc_ris *ris; 509 + struct mpam_class *class; 510 + struct mpam_component *comp; 511 + struct platform_device *pdev = msc->pdev; 512 + 513 + lockdep_assert_held(&mpam_list_lock); 514 + 515 + if (ris_idx > MPAM_MSC_MAX_NUM_RIS) 516 + return -EINVAL; 517 + 518 + if (test_and_set_bit(ris_idx, &msc->ris_idxs)) 519 + return -EBUSY; 520 + 521 + ris = devm_kzalloc(&msc->pdev->dev, sizeof(*ris), GFP_KERNEL); 522 + if (!ris) 523 + return -ENOMEM; 524 + init_garbage(&ris->garbage); 525 + ris->garbage.pdev = pdev; 526 + 527 + class = mpam_class_find(class_id, type); 528 + if (IS_ERR(class)) 529 + return PTR_ERR(class); 530 + 531 + comp = mpam_component_find(class, component_id); 532 + if (IS_ERR(comp)) { 533 + if (list_empty(&class->components)) 534 + mpam_class_destroy(class); 535 + return PTR_ERR(comp); 536 + } 537 + 538 + vmsc = mpam_vmsc_find(comp, msc); 539 + if (IS_ERR(vmsc)) { 540 + if (list_empty(&comp->vmsc)) 541 + mpam_component_destroy(comp); 542 + return PTR_ERR(vmsc); 543 + } 544 + 545 + err = mpam_ris_get_affinity(msc, &ris->affinity, type, class, comp); 546 + if (err) { 547 + if (list_empty(&vmsc->ris)) 548 + mpam_vmsc_destroy(vmsc); 549 + return err; 550 + } 551 + 552 + ris->ris_idx = ris_idx; 553 + INIT_LIST_HEAD_RCU(&ris->msc_list); 554 + INIT_LIST_HEAD_RCU(&ris->vmsc_list); 555 + ris->vmsc = vmsc; 556 + 557 + cpumask_or(&comp->affinity, &comp->affinity, &ris->affinity); 558 + cpumask_or(&class->affinity, &class->affinity, &ris->affinity); 559 + list_add_rcu(&ris->vmsc_list, &vmsc->ris); 560 + list_add_rcu(&ris->msc_list, &msc->ris); 561 + 562 + return 0; 563 + } 564 + 565 + static void mpam_ris_destroy(struct mpam_msc_ris *ris) 566 + { 567 + struct mpam_vmsc *vmsc = ris->vmsc; 568 + struct mpam_msc *msc = vmsc->msc; 569 + struct mpam_component *comp = vmsc->comp; 570 + struct mpam_class *class = comp->class; 571 + 572 + lockdep_assert_held(&mpam_list_lock); 573 + 574 + /* 575 + * It is assumed affinities don't overlap. If they do the class becomes 576 + * unusable immediately. 577 + */ 578 + cpumask_andnot(&class->affinity, &class->affinity, &ris->affinity); 579 + cpumask_andnot(&comp->affinity, &comp->affinity, &ris->affinity); 580 + clear_bit(ris->ris_idx, &msc->ris_idxs); 581 + list_del_rcu(&ris->msc_list); 582 + list_del_rcu(&ris->vmsc_list); 583 + add_to_garbage(ris); 584 + 585 + if (list_empty(&vmsc->ris)) 586 + mpam_vmsc_destroy(vmsc); 587 + } 588 + 589 + int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx, 590 + enum mpam_class_types type, u8 class_id, int component_id) 591 + { 592 + int err; 593 + 594 + mutex_lock(&mpam_list_lock); 595 + err = mpam_ris_create_locked(msc, ris_idx, type, class_id, 596 + component_id); 597 + mutex_unlock(&mpam_list_lock); 598 + if (err) 599 + mpam_free_garbage(); 600 + 601 + return err; 602 + } 603 + 604 + static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc, 605 + u8 ris_idx) 606 + { 607 + int err; 608 + struct mpam_msc_ris *ris; 609 + 610 + lockdep_assert_held(&mpam_list_lock); 611 + 612 + if (!test_bit(ris_idx, &msc->ris_idxs)) { 613 + err = mpam_ris_create_locked(msc, ris_idx, MPAM_CLASS_UNKNOWN, 614 + 0, 0); 615 + if (err) 616 + return ERR_PTR(err); 617 + } 618 + 619 + list_for_each_entry(ris, &msc->ris, msc_list) { 620 + if (ris->ris_idx == ris_idx) 621 + return ris; 622 + } 623 + 624 + return ERR_PTR(-ENOENT); 625 + } 626 + 627 + /* 628 + * IHI009A.a has this nugget: "If a monitor does not support automatic behaviour 629 + * of NRDY, software can use this bit for any purpose" - so hardware might not 630 + * implement this - but it isn't RES0. 631 + * 632 + * Try and see what values stick in this bit. If we can write either value, 633 + * its probably not implemented by hardware. 634 + */ 635 + static bool _mpam_ris_hw_probe_hw_nrdy(struct mpam_msc_ris *ris, u32 mon_reg) 636 + { 637 + u32 now; 638 + u64 mon_sel; 639 + bool can_set, can_clear; 640 + struct mpam_msc *msc = ris->vmsc->msc; 641 + 642 + if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc))) 643 + return false; 644 + 645 + mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, 0) | 646 + FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); 647 + _mpam_write_monsel_reg(msc, mon_reg, mon_sel); 648 + 649 + _mpam_write_monsel_reg(msc, mon_reg, MSMON___NRDY); 650 + now = _mpam_read_monsel_reg(msc, mon_reg); 651 + can_set = now & MSMON___NRDY; 652 + 653 + _mpam_write_monsel_reg(msc, mon_reg, 0); 654 + now = _mpam_read_monsel_reg(msc, mon_reg); 655 + can_clear = !(now & MSMON___NRDY); 656 + mpam_mon_sel_unlock(msc); 657 + 658 + return (!can_set || !can_clear); 659 + } 660 + 661 + #define mpam_ris_hw_probe_hw_nrdy(_ris, _mon_reg) \ 662 + _mpam_ris_hw_probe_hw_nrdy(_ris, MSMON_##_mon_reg) 663 + 664 + static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) 665 + { 666 + int err; 667 + struct mpam_msc *msc = ris->vmsc->msc; 668 + struct device *dev = &msc->pdev->dev; 669 + struct mpam_props *props = &ris->props; 670 + struct mpam_class *class = ris->vmsc->comp->class; 671 + 672 + lockdep_assert_held(&msc->probe_lock); 673 + lockdep_assert_held(&msc->part_sel_lock); 674 + 675 + /* Cache Capacity Partitioning */ 676 + if (FIELD_GET(MPAMF_IDR_HAS_CCAP_PART, ris->idr)) { 677 + u32 ccap_features = mpam_read_partsel_reg(msc, CCAP_IDR); 678 + 679 + props->cmax_wd = FIELD_GET(MPAMF_CCAP_IDR_CMAX_WD, ccap_features); 680 + if (props->cmax_wd && 681 + FIELD_GET(MPAMF_CCAP_IDR_HAS_CMAX_SOFTLIM, ccap_features)) 682 + mpam_set_feature(mpam_feat_cmax_softlim, props); 683 + 684 + if (props->cmax_wd && 685 + !FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) 686 + mpam_set_feature(mpam_feat_cmax_cmax, props); 687 + 688 + if (props->cmax_wd && 689 + FIELD_GET(MPAMF_CCAP_IDR_HAS_CMIN, ccap_features)) 690 + mpam_set_feature(mpam_feat_cmax_cmin, props); 691 + 692 + props->cassoc_wd = FIELD_GET(MPAMF_CCAP_IDR_CASSOC_WD, ccap_features); 693 + if (props->cassoc_wd && 694 + FIELD_GET(MPAMF_CCAP_IDR_HAS_CASSOC, ccap_features)) 695 + mpam_set_feature(mpam_feat_cmax_cassoc, props); 696 + } 697 + 698 + /* Cache Portion partitioning */ 699 + if (FIELD_GET(MPAMF_IDR_HAS_CPOR_PART, ris->idr)) { 700 + u32 cpor_features = mpam_read_partsel_reg(msc, CPOR_IDR); 701 + 702 + props->cpbm_wd = FIELD_GET(MPAMF_CPOR_IDR_CPBM_WD, cpor_features); 703 + if (props->cpbm_wd) 704 + mpam_set_feature(mpam_feat_cpor_part, props); 705 + } 706 + 707 + /* Memory bandwidth partitioning */ 708 + if (FIELD_GET(MPAMF_IDR_HAS_MBW_PART, ris->idr)) { 709 + u32 mbw_features = mpam_read_partsel_reg(msc, MBW_IDR); 710 + 711 + /* portion bitmap resolution */ 712 + props->mbw_pbm_bits = FIELD_GET(MPAMF_MBW_IDR_BWPBM_WD, mbw_features); 713 + if (props->mbw_pbm_bits && 714 + FIELD_GET(MPAMF_MBW_IDR_HAS_PBM, mbw_features)) 715 + mpam_set_feature(mpam_feat_mbw_part, props); 716 + 717 + props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features); 718 + if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features)) 719 + mpam_set_feature(mpam_feat_mbw_max, props); 720 + 721 + if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MIN, mbw_features)) 722 + mpam_set_feature(mpam_feat_mbw_min, props); 723 + 724 + if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_PROP, mbw_features)) 725 + mpam_set_feature(mpam_feat_mbw_prop, props); 726 + } 727 + 728 + /* Priority partitioning */ 729 + if (FIELD_GET(MPAMF_IDR_HAS_PRI_PART, ris->idr)) { 730 + u32 pri_features = mpam_read_partsel_reg(msc, PRI_IDR); 731 + 732 + props->intpri_wd = FIELD_GET(MPAMF_PRI_IDR_INTPRI_WD, pri_features); 733 + if (props->intpri_wd && FIELD_GET(MPAMF_PRI_IDR_HAS_INTPRI, pri_features)) { 734 + mpam_set_feature(mpam_feat_intpri_part, props); 735 + if (FIELD_GET(MPAMF_PRI_IDR_INTPRI_0_IS_LOW, pri_features)) 736 + mpam_set_feature(mpam_feat_intpri_part_0_low, props); 737 + } 738 + 739 + props->dspri_wd = FIELD_GET(MPAMF_PRI_IDR_DSPRI_WD, pri_features); 740 + if (props->dspri_wd && FIELD_GET(MPAMF_PRI_IDR_HAS_DSPRI, pri_features)) { 741 + mpam_set_feature(mpam_feat_dspri_part, props); 742 + if (FIELD_GET(MPAMF_PRI_IDR_DSPRI_0_IS_LOW, pri_features)) 743 + mpam_set_feature(mpam_feat_dspri_part_0_low, props); 744 + } 745 + } 746 + 747 + /* Performance Monitoring */ 748 + if (FIELD_GET(MPAMF_IDR_HAS_MSMON, ris->idr)) { 749 + u32 msmon_features = mpam_read_partsel_reg(msc, MSMON_IDR); 750 + 751 + /* 752 + * If the firmware max-nrdy-us property is missing, the 753 + * CSU counters can't be used. Should we wait forever? 754 + */ 755 + err = device_property_read_u32(&msc->pdev->dev, 756 + "arm,not-ready-us", 757 + &msc->nrdy_usec); 758 + 759 + if (FIELD_GET(MPAMF_MSMON_IDR_MSMON_CSU, msmon_features)) { 760 + u32 csumonidr; 761 + 762 + csumonidr = mpam_read_partsel_reg(msc, CSUMON_IDR); 763 + props->num_csu_mon = FIELD_GET(MPAMF_CSUMON_IDR_NUM_MON, csumonidr); 764 + if (props->num_csu_mon) { 765 + bool hw_managed; 766 + 767 + mpam_set_feature(mpam_feat_msmon_csu, props); 768 + 769 + if (FIELD_GET(MPAMF_CSUMON_IDR_HAS_XCL, csumonidr)) 770 + mpam_set_feature(mpam_feat_msmon_csu_xcl, props); 771 + 772 + /* Is NRDY hardware managed? */ 773 + hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, CSU); 774 + if (hw_managed) 775 + mpam_set_feature(mpam_feat_msmon_csu_hw_nrdy, props); 776 + } 777 + 778 + /* 779 + * Accept the missing firmware property if NRDY appears 780 + * un-implemented. 781 + */ 782 + if (err && mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, props)) 783 + dev_err_once(dev, "Counters are not usable because not-ready timeout was not provided by firmware."); 784 + } 785 + if (FIELD_GET(MPAMF_MSMON_IDR_MSMON_MBWU, msmon_features)) { 786 + bool has_long, hw_managed; 787 + u32 mbwumon_idr = mpam_read_partsel_reg(msc, MBWUMON_IDR); 788 + 789 + props->num_mbwu_mon = FIELD_GET(MPAMF_MBWUMON_IDR_NUM_MON, mbwumon_idr); 790 + if (props->num_mbwu_mon) { 791 + mpam_set_feature(mpam_feat_msmon_mbwu, props); 792 + 793 + if (FIELD_GET(MPAMF_MBWUMON_IDR_HAS_RWBW, mbwumon_idr)) 794 + mpam_set_feature(mpam_feat_msmon_mbwu_rwbw, props); 795 + 796 + has_long = FIELD_GET(MPAMF_MBWUMON_IDR_HAS_LONG, mbwumon_idr); 797 + if (has_long) { 798 + if (FIELD_GET(MPAMF_MBWUMON_IDR_LWD, mbwumon_idr)) 799 + mpam_set_feature(mpam_feat_msmon_mbwu_63counter, props); 800 + else 801 + mpam_set_feature(mpam_feat_msmon_mbwu_44counter, props); 802 + } else { 803 + mpam_set_feature(mpam_feat_msmon_mbwu_31counter, props); 804 + } 805 + 806 + /* Is NRDY hardware managed? */ 807 + hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, MBWU); 808 + if (hw_managed) 809 + mpam_set_feature(mpam_feat_msmon_mbwu_hw_nrdy, props); 810 + 811 + /* 812 + * Don't warn about any missing firmware property for 813 + * MBWU NRDY - it doesn't make any sense! 814 + */ 815 + } 816 + } 817 + } 818 + 819 + /* 820 + * RIS with PARTID narrowing don't have enough storage for one 821 + * configuration per PARTID. If these are in a class we could use, 822 + * reduce the supported partid_max to match the number of intpartid. 823 + * If the class is unknown, just ignore it. 824 + */ 825 + if (FIELD_GET(MPAMF_IDR_HAS_PARTID_NRW, ris->idr) && 826 + class->type != MPAM_CLASS_UNKNOWN) { 827 + u32 nrwidr = mpam_read_partsel_reg(msc, PARTID_NRW_IDR); 828 + u16 partid_max = FIELD_GET(MPAMF_PARTID_NRW_IDR_INTPARTID_MAX, nrwidr); 829 + 830 + mpam_set_feature(mpam_feat_partid_nrw, props); 831 + msc->partid_max = min(msc->partid_max, partid_max); 832 + } 833 + } 834 + 835 + static int mpam_msc_hw_probe(struct mpam_msc *msc) 836 + { 837 + u64 idr; 838 + u16 partid_max; 839 + u8 ris_idx, pmg_max; 840 + struct mpam_msc_ris *ris; 841 + struct device *dev = &msc->pdev->dev; 842 + 843 + lockdep_assert_held(&msc->probe_lock); 844 + 845 + idr = __mpam_read_reg(msc, MPAMF_AIDR); 846 + if ((idr & MPAMF_AIDR_ARCH_MAJOR_REV) != MPAM_ARCHITECTURE_V1) { 847 + dev_err_once(dev, "MSC does not match MPAM architecture v1.x\n"); 848 + return -EIO; 849 + } 850 + 851 + /* Grab an IDR value to find out how many RIS there are */ 852 + mutex_lock(&msc->part_sel_lock); 853 + idr = mpam_msc_read_idr(msc); 854 + mutex_unlock(&msc->part_sel_lock); 855 + 856 + msc->ris_max = FIELD_GET(MPAMF_IDR_RIS_MAX, idr); 857 + 858 + /* Use these values so partid/pmg always starts with a valid value */ 859 + msc->partid_max = FIELD_GET(MPAMF_IDR_PARTID_MAX, idr); 860 + msc->pmg_max = FIELD_GET(MPAMF_IDR_PMG_MAX, idr); 861 + 862 + for (ris_idx = 0; ris_idx <= msc->ris_max; ris_idx++) { 863 + mutex_lock(&msc->part_sel_lock); 864 + __mpam_part_sel(ris_idx, 0, msc); 865 + idr = mpam_msc_read_idr(msc); 866 + mutex_unlock(&msc->part_sel_lock); 867 + 868 + partid_max = FIELD_GET(MPAMF_IDR_PARTID_MAX, idr); 869 + pmg_max = FIELD_GET(MPAMF_IDR_PMG_MAX, idr); 870 + msc->partid_max = min(msc->partid_max, partid_max); 871 + msc->pmg_max = min(msc->pmg_max, pmg_max); 872 + msc->has_extd_esr = FIELD_GET(MPAMF_IDR_HAS_EXTD_ESR, idr); 873 + 874 + mutex_lock(&mpam_list_lock); 875 + ris = mpam_get_or_create_ris(msc, ris_idx); 876 + mutex_unlock(&mpam_list_lock); 877 + if (IS_ERR(ris)) 878 + return PTR_ERR(ris); 879 + ris->idr = idr; 880 + 881 + mutex_lock(&msc->part_sel_lock); 882 + __mpam_part_sel(ris_idx, 0, msc); 883 + mpam_ris_hw_probe(ris); 884 + mutex_unlock(&msc->part_sel_lock); 885 + } 886 + 887 + /* Clear any stale errors */ 888 + mpam_msc_clear_esr(msc); 889 + 890 + spin_lock(&partid_max_lock); 891 + mpam_partid_max = min(mpam_partid_max, msc->partid_max); 892 + mpam_pmg_max = min(mpam_pmg_max, msc->pmg_max); 893 + spin_unlock(&partid_max_lock); 894 + 895 + msc->probed = true; 896 + 897 + return 0; 898 + } 899 + 900 + struct mon_read { 901 + struct mpam_msc_ris *ris; 902 + struct mon_cfg *ctx; 903 + enum mpam_device_features type; 904 + u64 *val; 905 + int err; 906 + }; 907 + 908 + static bool mpam_ris_has_mbwu_long_counter(struct mpam_msc_ris *ris) 909 + { 910 + return (mpam_has_feature(mpam_feat_msmon_mbwu_63counter, &ris->props) || 911 + mpam_has_feature(mpam_feat_msmon_mbwu_44counter, &ris->props)); 912 + } 913 + 914 + static u64 mpam_msc_read_mbwu_l(struct mpam_msc *msc) 915 + { 916 + int retry = 3; 917 + u32 mbwu_l_low; 918 + u64 mbwu_l_high1, mbwu_l_high2; 919 + 920 + mpam_mon_sel_lock_held(msc); 921 + 922 + WARN_ON_ONCE((MSMON_MBWU_L + sizeof(u64)) > msc->mapped_hwpage_sz); 923 + WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility)); 924 + 925 + mbwu_l_high2 = __mpam_read_reg(msc, MSMON_MBWU_L + 4); 926 + do { 927 + mbwu_l_high1 = mbwu_l_high2; 928 + mbwu_l_low = __mpam_read_reg(msc, MSMON_MBWU_L); 929 + mbwu_l_high2 = __mpam_read_reg(msc, MSMON_MBWU_L + 4); 930 + 931 + retry--; 932 + } while (mbwu_l_high1 != mbwu_l_high2 && retry > 0); 933 + 934 + if (mbwu_l_high1 == mbwu_l_high2) 935 + return (mbwu_l_high1 << 32) | mbwu_l_low; 936 + 937 + pr_warn("Failed to read a stable value\n"); 938 + return MSMON___L_NRDY; 939 + } 940 + 941 + static void mpam_msc_zero_mbwu_l(struct mpam_msc *msc) 942 + { 943 + mpam_mon_sel_lock_held(msc); 944 + 945 + WARN_ON_ONCE((MSMON_MBWU_L + sizeof(u64)) > msc->mapped_hwpage_sz); 946 + WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility)); 947 + 948 + __mpam_write_reg(msc, MSMON_MBWU_L, 0); 949 + __mpam_write_reg(msc, MSMON_MBWU_L + 4, 0); 950 + } 951 + 952 + static void gen_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val, 953 + u32 *flt_val) 954 + { 955 + struct mon_cfg *ctx = m->ctx; 956 + 957 + /* 958 + * For CSU counters its implementation-defined what happens when not 959 + * filtering by partid. 960 + */ 961 + *ctl_val = MSMON_CFG_x_CTL_MATCH_PARTID; 962 + 963 + *flt_val = FIELD_PREP(MSMON_CFG_x_FLT_PARTID, ctx->partid); 964 + 965 + if (m->ctx->match_pmg) { 966 + *ctl_val |= MSMON_CFG_x_CTL_MATCH_PMG; 967 + *flt_val |= FIELD_PREP(MSMON_CFG_x_FLT_PMG, ctx->pmg); 968 + } 969 + 970 + switch (m->type) { 971 + case mpam_feat_msmon_csu: 972 + *ctl_val |= MSMON_CFG_CSU_CTL_TYPE_CSU; 973 + 974 + if (mpam_has_feature(mpam_feat_msmon_csu_xcl, &m->ris->props)) 975 + *flt_val |= FIELD_PREP(MSMON_CFG_CSU_FLT_XCL, ctx->csu_exclude_clean); 976 + 977 + break; 978 + case mpam_feat_msmon_mbwu_31counter: 979 + case mpam_feat_msmon_mbwu_44counter: 980 + case mpam_feat_msmon_mbwu_63counter: 981 + *ctl_val |= MSMON_CFG_MBWU_CTL_TYPE_MBWU; 982 + 983 + if (mpam_has_feature(mpam_feat_msmon_mbwu_rwbw, &m->ris->props)) 984 + *flt_val |= FIELD_PREP(MSMON_CFG_MBWU_FLT_RWBW, ctx->opts); 985 + 986 + break; 987 + default: 988 + pr_warn("Unexpected monitor type %d\n", m->type); 989 + } 990 + } 991 + 992 + static void read_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val, 993 + u32 *flt_val) 994 + { 995 + struct mpam_msc *msc = m->ris->vmsc->msc; 996 + 997 + switch (m->type) { 998 + case mpam_feat_msmon_csu: 999 + *ctl_val = mpam_read_monsel_reg(msc, CFG_CSU_CTL); 1000 + *flt_val = mpam_read_monsel_reg(msc, CFG_CSU_FLT); 1001 + break; 1002 + case mpam_feat_msmon_mbwu_31counter: 1003 + case mpam_feat_msmon_mbwu_44counter: 1004 + case mpam_feat_msmon_mbwu_63counter: 1005 + *ctl_val = mpam_read_monsel_reg(msc, CFG_MBWU_CTL); 1006 + *flt_val = mpam_read_monsel_reg(msc, CFG_MBWU_FLT); 1007 + break; 1008 + default: 1009 + pr_warn("Unexpected monitor type %d\n", m->type); 1010 + } 1011 + } 1012 + 1013 + /* Remove values set by the hardware to prevent apparent mismatches. */ 1014 + static inline void clean_msmon_ctl_val(u32 *cur_ctl) 1015 + { 1016 + *cur_ctl &= ~MSMON_CFG_x_CTL_OFLOW_STATUS; 1017 + 1018 + if (FIELD_GET(MSMON_CFG_x_CTL_TYPE, *cur_ctl) == MSMON_CFG_MBWU_CTL_TYPE_MBWU) 1019 + *cur_ctl &= ~MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L; 1020 + } 1021 + 1022 + static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val, 1023 + u32 flt_val) 1024 + { 1025 + struct mpam_msc *msc = m->ris->vmsc->msc; 1026 + 1027 + /* 1028 + * Write the ctl_val with the enable bit cleared, reset the counter, 1029 + * then enable counter. 1030 + */ 1031 + switch (m->type) { 1032 + case mpam_feat_msmon_csu: 1033 + mpam_write_monsel_reg(msc, CFG_CSU_FLT, flt_val); 1034 + mpam_write_monsel_reg(msc, CFG_CSU_CTL, ctl_val); 1035 + mpam_write_monsel_reg(msc, CSU, 0); 1036 + mpam_write_monsel_reg(msc, CFG_CSU_CTL, ctl_val | MSMON_CFG_x_CTL_EN); 1037 + break; 1038 + case mpam_feat_msmon_mbwu_31counter: 1039 + case mpam_feat_msmon_mbwu_44counter: 1040 + case mpam_feat_msmon_mbwu_63counter: 1041 + mpam_write_monsel_reg(msc, CFG_MBWU_FLT, flt_val); 1042 + mpam_write_monsel_reg(msc, CFG_MBWU_CTL, ctl_val); 1043 + mpam_write_monsel_reg(msc, CFG_MBWU_CTL, ctl_val | MSMON_CFG_x_CTL_EN); 1044 + /* Counting monitors require NRDY to be reset by software */ 1045 + if (m->type == mpam_feat_msmon_mbwu_31counter) 1046 + mpam_write_monsel_reg(msc, MBWU, 0); 1047 + else 1048 + mpam_msc_zero_mbwu_l(m->ris->vmsc->msc); 1049 + break; 1050 + default: 1051 + pr_warn("Unexpected monitor type %d\n", m->type); 1052 + } 1053 + } 1054 + 1055 + static u64 mpam_msmon_overflow_val(enum mpam_device_features type) 1056 + { 1057 + /* TODO: implement scaling counters */ 1058 + switch (type) { 1059 + case mpam_feat_msmon_mbwu_63counter: 1060 + return BIT_ULL(hweight_long(MSMON___LWD_VALUE)); 1061 + case mpam_feat_msmon_mbwu_44counter: 1062 + return BIT_ULL(hweight_long(MSMON___L_VALUE)); 1063 + case mpam_feat_msmon_mbwu_31counter: 1064 + return BIT_ULL(hweight_long(MSMON___VALUE)); 1065 + default: 1066 + return 0; 1067 + } 1068 + } 1069 + 1070 + static void __ris_msmon_read(void *arg) 1071 + { 1072 + u64 now; 1073 + bool nrdy = false; 1074 + bool config_mismatch; 1075 + bool overflow; 1076 + struct mon_read *m = arg; 1077 + struct mon_cfg *ctx = m->ctx; 1078 + bool reset_on_next_read = false; 1079 + struct mpam_msc_ris *ris = m->ris; 1080 + struct msmon_mbwu_state *mbwu_state; 1081 + struct mpam_props *rprops = &ris->props; 1082 + struct mpam_msc *msc = m->ris->vmsc->msc; 1083 + u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt; 1084 + 1085 + if (!mpam_mon_sel_lock(msc)) { 1086 + m->err = -EIO; 1087 + return; 1088 + } 1089 + mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, ctx->mon) | 1090 + FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); 1091 + mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel); 1092 + 1093 + switch (m->type) { 1094 + case mpam_feat_msmon_mbwu_31counter: 1095 + case mpam_feat_msmon_mbwu_44counter: 1096 + case mpam_feat_msmon_mbwu_63counter: 1097 + mbwu_state = &ris->mbwu_state[ctx->mon]; 1098 + if (mbwu_state) { 1099 + reset_on_next_read = mbwu_state->reset_on_next_read; 1100 + mbwu_state->reset_on_next_read = false; 1101 + } 1102 + break; 1103 + default: 1104 + break; 1105 + } 1106 + 1107 + /* 1108 + * Read the existing configuration to avoid re-writing the same values. 1109 + * This saves waiting for 'nrdy' on subsequent reads. 1110 + */ 1111 + read_msmon_ctl_flt_vals(m, &cur_ctl, &cur_flt); 1112 + 1113 + if (mpam_feat_msmon_mbwu_31counter == m->type) 1114 + overflow = cur_ctl & MSMON_CFG_x_CTL_OFLOW_STATUS; 1115 + else if (mpam_feat_msmon_mbwu_44counter == m->type || 1116 + mpam_feat_msmon_mbwu_63counter == m->type) 1117 + overflow = cur_ctl & MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L; 1118 + 1119 + clean_msmon_ctl_val(&cur_ctl); 1120 + gen_msmon_ctl_flt_vals(m, &ctl_val, &flt_val); 1121 + config_mismatch = cur_flt != flt_val || 1122 + cur_ctl != (ctl_val | MSMON_CFG_x_CTL_EN); 1123 + 1124 + if (config_mismatch || reset_on_next_read) { 1125 + write_msmon_ctl_flt_vals(m, ctl_val, flt_val); 1126 + overflow = false; 1127 + } else if (overflow) { 1128 + mpam_write_monsel_reg(msc, CFG_MBWU_CTL, 1129 + cur_ctl & 1130 + ~(MSMON_CFG_x_CTL_OFLOW_STATUS | 1131 + MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L)); 1132 + } 1133 + 1134 + switch (m->type) { 1135 + case mpam_feat_msmon_csu: 1136 + now = mpam_read_monsel_reg(msc, CSU); 1137 + if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops)) 1138 + nrdy = now & MSMON___NRDY; 1139 + now = FIELD_GET(MSMON___VALUE, now); 1140 + break; 1141 + case mpam_feat_msmon_mbwu_31counter: 1142 + case mpam_feat_msmon_mbwu_44counter: 1143 + case mpam_feat_msmon_mbwu_63counter: 1144 + if (m->type != mpam_feat_msmon_mbwu_31counter) { 1145 + now = mpam_msc_read_mbwu_l(msc); 1146 + if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) 1147 + nrdy = now & MSMON___L_NRDY; 1148 + 1149 + if (m->type == mpam_feat_msmon_mbwu_63counter) 1150 + now = FIELD_GET(MSMON___LWD_VALUE, now); 1151 + else 1152 + now = FIELD_GET(MSMON___L_VALUE, now); 1153 + } else { 1154 + now = mpam_read_monsel_reg(msc, MBWU); 1155 + if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) 1156 + nrdy = now & MSMON___NRDY; 1157 + now = FIELD_GET(MSMON___VALUE, now); 1158 + } 1159 + 1160 + if (nrdy) 1161 + break; 1162 + 1163 + mbwu_state = &ris->mbwu_state[ctx->mon]; 1164 + 1165 + if (overflow) 1166 + mbwu_state->correction += mpam_msmon_overflow_val(m->type); 1167 + 1168 + /* 1169 + * Include bandwidth consumed before the last hardware reset and 1170 + * a counter size increment for each overflow. 1171 + */ 1172 + now += mbwu_state->correction; 1173 + break; 1174 + default: 1175 + m->err = -EINVAL; 1176 + } 1177 + mpam_mon_sel_unlock(msc); 1178 + 1179 + if (nrdy) { 1180 + m->err = -EBUSY; 1181 + return; 1182 + } 1183 + 1184 + *m->val += now; 1185 + } 1186 + 1187 + static int _msmon_read(struct mpam_component *comp, struct mon_read *arg) 1188 + { 1189 + int err, any_err = 0; 1190 + struct mpam_vmsc *vmsc; 1191 + 1192 + guard(srcu)(&mpam_srcu); 1193 + list_for_each_entry_srcu(vmsc, &comp->vmsc, comp_list, 1194 + srcu_read_lock_held(&mpam_srcu)) { 1195 + struct mpam_msc *msc = vmsc->msc; 1196 + struct mpam_msc_ris *ris; 1197 + 1198 + list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list, 1199 + srcu_read_lock_held(&mpam_srcu)) { 1200 + arg->ris = ris; 1201 + 1202 + err = smp_call_function_any(&msc->accessibility, 1203 + __ris_msmon_read, arg, 1204 + true); 1205 + if (!err && arg->err) 1206 + err = arg->err; 1207 + 1208 + /* 1209 + * Save one error to be returned to the caller, but 1210 + * keep reading counters so that get reprogrammed. On 1211 + * platforms with NRDY this lets us wait once. 1212 + */ 1213 + if (err) 1214 + any_err = err; 1215 + } 1216 + } 1217 + 1218 + return any_err; 1219 + } 1220 + 1221 + static enum mpam_device_features mpam_msmon_choose_counter(struct mpam_class *class) 1222 + { 1223 + struct mpam_props *cprops = &class->props; 1224 + 1225 + if (mpam_has_feature(mpam_feat_msmon_mbwu_63counter, cprops)) 1226 + return mpam_feat_msmon_mbwu_63counter; 1227 + if (mpam_has_feature(mpam_feat_msmon_mbwu_44counter, cprops)) 1228 + return mpam_feat_msmon_mbwu_44counter; 1229 + 1230 + return mpam_feat_msmon_mbwu_31counter; 1231 + } 1232 + 1233 + int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx, 1234 + enum mpam_device_features type, u64 *val) 1235 + { 1236 + int err; 1237 + struct mon_read arg; 1238 + u64 wait_jiffies = 0; 1239 + struct mpam_class *class = comp->class; 1240 + struct mpam_props *cprops = &class->props; 1241 + 1242 + might_sleep(); 1243 + 1244 + if (!mpam_is_enabled()) 1245 + return -EIO; 1246 + 1247 + if (!mpam_has_feature(type, cprops)) 1248 + return -EOPNOTSUPP; 1249 + 1250 + if (type == mpam_feat_msmon_mbwu) 1251 + type = mpam_msmon_choose_counter(class); 1252 + 1253 + arg = (struct mon_read) { 1254 + .ctx = ctx, 1255 + .type = type, 1256 + .val = val, 1257 + }; 1258 + *val = 0; 1259 + 1260 + err = _msmon_read(comp, &arg); 1261 + if (err == -EBUSY && class->nrdy_usec) 1262 + wait_jiffies = usecs_to_jiffies(class->nrdy_usec); 1263 + 1264 + while (wait_jiffies) 1265 + wait_jiffies = schedule_timeout_uninterruptible(wait_jiffies); 1266 + 1267 + if (err == -EBUSY) { 1268 + arg = (struct mon_read) { 1269 + .ctx = ctx, 1270 + .type = type, 1271 + .val = val, 1272 + }; 1273 + *val = 0; 1274 + 1275 + err = _msmon_read(comp, &arg); 1276 + } 1277 + 1278 + return err; 1279 + } 1280 + 1281 + void mpam_msmon_reset_mbwu(struct mpam_component *comp, struct mon_cfg *ctx) 1282 + { 1283 + struct mpam_msc *msc; 1284 + struct mpam_vmsc *vmsc; 1285 + struct mpam_msc_ris *ris; 1286 + 1287 + if (!mpam_is_enabled()) 1288 + return; 1289 + 1290 + guard(srcu)(&mpam_srcu); 1291 + list_for_each_entry_srcu(vmsc, &comp->vmsc, comp_list, 1292 + srcu_read_lock_held(&mpam_srcu)) { 1293 + if (!mpam_has_feature(mpam_feat_msmon_mbwu, &vmsc->props)) 1294 + continue; 1295 + 1296 + msc = vmsc->msc; 1297 + list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list, 1298 + srcu_read_lock_held(&mpam_srcu)) { 1299 + if (!mpam_has_feature(mpam_feat_msmon_mbwu, &ris->props)) 1300 + continue; 1301 + 1302 + if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc))) 1303 + continue; 1304 + 1305 + ris->mbwu_state[ctx->mon].correction = 0; 1306 + ris->mbwu_state[ctx->mon].reset_on_next_read = true; 1307 + mpam_mon_sel_unlock(msc); 1308 + } 1309 + } 1310 + } 1311 + 1312 + static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd) 1313 + { 1314 + u32 num_words, msb; 1315 + u32 bm = ~0; 1316 + int i; 1317 + 1318 + lockdep_assert_held(&msc->part_sel_lock); 1319 + 1320 + if (wd == 0) 1321 + return; 1322 + 1323 + /* 1324 + * Write all ~0 to all but the last 32bit-word, which may 1325 + * have fewer bits... 1326 + */ 1327 + num_words = DIV_ROUND_UP(wd, 32); 1328 + for (i = 0; i < num_words - 1; i++, reg += sizeof(bm)) 1329 + __mpam_write_reg(msc, reg, bm); 1330 + 1331 + /* 1332 + * ....and then the last (maybe) partial 32bit word. When wd is a 1333 + * multiple of 32, msb should be 31 to write a full 32bit word. 1334 + */ 1335 + msb = (wd - 1) % 32; 1336 + bm = GENMASK(msb, 0); 1337 + __mpam_write_reg(msc, reg, bm); 1338 + } 1339 + 1340 + /* Called via IPI. Call while holding an SRCU reference */ 1341 + static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, 1342 + struct mpam_config *cfg) 1343 + { 1344 + u32 pri_val = 0; 1345 + u16 cmax = MPAMCFG_CMAX_CMAX; 1346 + struct mpam_msc *msc = ris->vmsc->msc; 1347 + struct mpam_props *rprops = &ris->props; 1348 + u16 dspri = GENMASK(rprops->dspri_wd, 0); 1349 + u16 intpri = GENMASK(rprops->intpri_wd, 0); 1350 + 1351 + mutex_lock(&msc->part_sel_lock); 1352 + __mpam_part_sel(ris->ris_idx, partid, msc); 1353 + 1354 + if (mpam_has_feature(mpam_feat_partid_nrw, rprops)) { 1355 + /* Update the intpartid mapping */ 1356 + mpam_write_partsel_reg(msc, INTPARTID, 1357 + MPAMCFG_INTPARTID_INTERNAL | partid); 1358 + 1359 + /* 1360 + * Then switch to the 'internal' partid to update the 1361 + * configuration. 1362 + */ 1363 + __mpam_intpart_sel(ris->ris_idx, partid, msc); 1364 + } 1365 + 1366 + if (mpam_has_feature(mpam_feat_cpor_part, rprops) && 1367 + mpam_has_feature(mpam_feat_cpor_part, cfg)) { 1368 + if (cfg->reset_cpbm) 1369 + mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, rprops->cpbm_wd); 1370 + else 1371 + mpam_write_partsel_reg(msc, CPBM, cfg->cpbm); 1372 + } 1373 + 1374 + if (mpam_has_feature(mpam_feat_mbw_part, rprops) && 1375 + mpam_has_feature(mpam_feat_mbw_part, cfg)) { 1376 + if (cfg->reset_mbw_pbm) 1377 + mpam_reset_msc_bitmap(msc, MPAMCFG_MBW_PBM, rprops->mbw_pbm_bits); 1378 + else 1379 + mpam_write_partsel_reg(msc, MBW_PBM, cfg->mbw_pbm); 1380 + } 1381 + 1382 + if (mpam_has_feature(mpam_feat_mbw_min, rprops) && 1383 + mpam_has_feature(mpam_feat_mbw_min, cfg)) 1384 + mpam_write_partsel_reg(msc, MBW_MIN, 0); 1385 + 1386 + if (mpam_has_feature(mpam_feat_mbw_max, rprops) && 1387 + mpam_has_feature(mpam_feat_mbw_max, cfg)) { 1388 + if (cfg->reset_mbw_max) 1389 + mpam_write_partsel_reg(msc, MBW_MAX, MPAMCFG_MBW_MAX_MAX); 1390 + else 1391 + mpam_write_partsel_reg(msc, MBW_MAX, cfg->mbw_max); 1392 + } 1393 + 1394 + if (mpam_has_feature(mpam_feat_mbw_prop, rprops) && 1395 + mpam_has_feature(mpam_feat_mbw_prop, cfg)) 1396 + mpam_write_partsel_reg(msc, MBW_PROP, 0); 1397 + 1398 + if (mpam_has_feature(mpam_feat_cmax_cmax, rprops)) 1399 + mpam_write_partsel_reg(msc, CMAX, cmax); 1400 + 1401 + if (mpam_has_feature(mpam_feat_cmax_cmin, rprops)) 1402 + mpam_write_partsel_reg(msc, CMIN, 0); 1403 + 1404 + if (mpam_has_feature(mpam_feat_cmax_cassoc, rprops)) 1405 + mpam_write_partsel_reg(msc, CASSOC, MPAMCFG_CASSOC_CASSOC); 1406 + 1407 + if (mpam_has_feature(mpam_feat_intpri_part, rprops) || 1408 + mpam_has_feature(mpam_feat_dspri_part, rprops)) { 1409 + /* aces high? */ 1410 + if (!mpam_has_feature(mpam_feat_intpri_part_0_low, rprops)) 1411 + intpri = 0; 1412 + if (!mpam_has_feature(mpam_feat_dspri_part_0_low, rprops)) 1413 + dspri = 0; 1414 + 1415 + if (mpam_has_feature(mpam_feat_intpri_part, rprops)) 1416 + pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, intpri); 1417 + if (mpam_has_feature(mpam_feat_dspri_part, rprops)) 1418 + pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri); 1419 + 1420 + mpam_write_partsel_reg(msc, PRI, pri_val); 1421 + } 1422 + 1423 + mutex_unlock(&msc->part_sel_lock); 1424 + } 1425 + 1426 + /* Call with msc cfg_lock held */ 1427 + static int mpam_restore_mbwu_state(void *_ris) 1428 + { 1429 + int i; 1430 + struct mon_read mwbu_arg; 1431 + struct mpam_msc_ris *ris = _ris; 1432 + struct mpam_class *class = ris->vmsc->comp->class; 1433 + 1434 + for (i = 0; i < ris->props.num_mbwu_mon; i++) { 1435 + if (ris->mbwu_state[i].enabled) { 1436 + mwbu_arg.ris = ris; 1437 + mwbu_arg.ctx = &ris->mbwu_state[i].cfg; 1438 + mwbu_arg.type = mpam_msmon_choose_counter(class); 1439 + 1440 + __ris_msmon_read(&mwbu_arg); 1441 + } 1442 + } 1443 + 1444 + return 0; 1445 + } 1446 + 1447 + /* Call with MSC cfg_lock held */ 1448 + static int mpam_save_mbwu_state(void *arg) 1449 + { 1450 + int i; 1451 + u64 val; 1452 + struct mon_cfg *cfg; 1453 + u32 cur_flt, cur_ctl, mon_sel; 1454 + struct mpam_msc_ris *ris = arg; 1455 + struct msmon_mbwu_state *mbwu_state; 1456 + struct mpam_msc *msc = ris->vmsc->msc; 1457 + 1458 + for (i = 0; i < ris->props.num_mbwu_mon; i++) { 1459 + mbwu_state = &ris->mbwu_state[i]; 1460 + cfg = &mbwu_state->cfg; 1461 + 1462 + if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc))) 1463 + return -EIO; 1464 + 1465 + mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, i) | 1466 + FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); 1467 + mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel); 1468 + 1469 + cur_flt = mpam_read_monsel_reg(msc, CFG_MBWU_FLT); 1470 + cur_ctl = mpam_read_monsel_reg(msc, CFG_MBWU_CTL); 1471 + mpam_write_monsel_reg(msc, CFG_MBWU_CTL, 0); 1472 + 1473 + if (mpam_ris_has_mbwu_long_counter(ris)) { 1474 + val = mpam_msc_read_mbwu_l(msc); 1475 + mpam_msc_zero_mbwu_l(msc); 1476 + } else { 1477 + val = mpam_read_monsel_reg(msc, MBWU); 1478 + mpam_write_monsel_reg(msc, MBWU, 0); 1479 + } 1480 + 1481 + cfg->mon = i; 1482 + cfg->pmg = FIELD_GET(MSMON_CFG_x_FLT_PMG, cur_flt); 1483 + cfg->match_pmg = FIELD_GET(MSMON_CFG_x_CTL_MATCH_PMG, cur_ctl); 1484 + cfg->partid = FIELD_GET(MSMON_CFG_x_FLT_PARTID, cur_flt); 1485 + mbwu_state->correction += val; 1486 + mbwu_state->enabled = FIELD_GET(MSMON_CFG_x_CTL_EN, cur_ctl); 1487 + mpam_mon_sel_unlock(msc); 1488 + } 1489 + 1490 + return 0; 1491 + } 1492 + 1493 + static void mpam_init_reset_cfg(struct mpam_config *reset_cfg) 1494 + { 1495 + *reset_cfg = (struct mpam_config) { 1496 + .reset_cpbm = true, 1497 + .reset_mbw_pbm = true, 1498 + .reset_mbw_max = true, 1499 + }; 1500 + bitmap_fill(reset_cfg->features, MPAM_FEATURE_LAST); 1501 + } 1502 + 1503 + /* 1504 + * Called via smp_call_on_cpu() to prevent migration, while still being 1505 + * pre-emptible. Caller must hold mpam_srcu. 1506 + */ 1507 + static int mpam_reset_ris(void *arg) 1508 + { 1509 + u16 partid, partid_max; 1510 + struct mpam_config reset_cfg; 1511 + struct mpam_msc_ris *ris = arg; 1512 + 1513 + if (ris->in_reset_state) 1514 + return 0; 1515 + 1516 + mpam_init_reset_cfg(&reset_cfg); 1517 + 1518 + spin_lock(&partid_max_lock); 1519 + partid_max = mpam_partid_max; 1520 + spin_unlock(&partid_max_lock); 1521 + for (partid = 0; partid <= partid_max; partid++) 1522 + mpam_reprogram_ris_partid(ris, partid, &reset_cfg); 1523 + 1524 + return 0; 1525 + } 1526 + 1527 + /* 1528 + * Get the preferred CPU for this MSC. If it is accessible from this CPU, 1529 + * this CPU is preferred. This can be preempted/migrated, it will only result 1530 + * in more work. 1531 + */ 1532 + static int mpam_get_msc_preferred_cpu(struct mpam_msc *msc) 1533 + { 1534 + int cpu = raw_smp_processor_id(); 1535 + 1536 + if (cpumask_test_cpu(cpu, &msc->accessibility)) 1537 + return cpu; 1538 + 1539 + return cpumask_first_and(&msc->accessibility, cpu_online_mask); 1540 + } 1541 + 1542 + static int mpam_touch_msc(struct mpam_msc *msc, int (*fn)(void *a), void *arg) 1543 + { 1544 + lockdep_assert_irqs_enabled(); 1545 + lockdep_assert_cpus_held(); 1546 + WARN_ON_ONCE(!srcu_read_lock_held((&mpam_srcu))); 1547 + 1548 + return smp_call_on_cpu(mpam_get_msc_preferred_cpu(msc), fn, arg, true); 1549 + } 1550 + 1551 + struct mpam_write_config_arg { 1552 + struct mpam_msc_ris *ris; 1553 + struct mpam_component *comp; 1554 + u16 partid; 1555 + }; 1556 + 1557 + static int __write_config(void *arg) 1558 + { 1559 + struct mpam_write_config_arg *c = arg; 1560 + 1561 + mpam_reprogram_ris_partid(c->ris, c->partid, &c->comp->cfg[c->partid]); 1562 + 1563 + return 0; 1564 + } 1565 + 1566 + static void mpam_reprogram_msc(struct mpam_msc *msc) 1567 + { 1568 + u16 partid; 1569 + bool reset; 1570 + struct mpam_config *cfg; 1571 + struct mpam_msc_ris *ris; 1572 + struct mpam_write_config_arg arg; 1573 + 1574 + /* 1575 + * No lock for mpam_partid_max as partid_max_published has been 1576 + * set by mpam_enabled(), so the values can no longer change. 1577 + */ 1578 + mpam_assert_partid_sizes_fixed(); 1579 + 1580 + mutex_lock(&msc->cfg_lock); 1581 + list_for_each_entry_srcu(ris, &msc->ris, msc_list, 1582 + srcu_read_lock_held(&mpam_srcu)) { 1583 + if (!mpam_is_enabled() && !ris->in_reset_state) { 1584 + mpam_touch_msc(msc, &mpam_reset_ris, ris); 1585 + ris->in_reset_state = true; 1586 + continue; 1587 + } 1588 + 1589 + arg.comp = ris->vmsc->comp; 1590 + arg.ris = ris; 1591 + reset = true; 1592 + for (partid = 0; partid <= mpam_partid_max; partid++) { 1593 + cfg = &ris->vmsc->comp->cfg[partid]; 1594 + if (!bitmap_empty(cfg->features, MPAM_FEATURE_LAST)) 1595 + reset = false; 1596 + 1597 + arg.partid = partid; 1598 + mpam_touch_msc(msc, __write_config, &arg); 1599 + } 1600 + ris->in_reset_state = reset; 1601 + 1602 + if (mpam_has_feature(mpam_feat_msmon_mbwu, &ris->props)) 1603 + mpam_touch_msc(msc, &mpam_restore_mbwu_state, ris); 1604 + } 1605 + mutex_unlock(&msc->cfg_lock); 1606 + } 1607 + 1608 + static void _enable_percpu_irq(void *_irq) 1609 + { 1610 + int *irq = _irq; 1611 + 1612 + enable_percpu_irq(*irq, IRQ_TYPE_NONE); 1613 + } 1614 + 1615 + static int mpam_cpu_online(unsigned int cpu) 1616 + { 1617 + struct mpam_msc *msc; 1618 + 1619 + guard(srcu)(&mpam_srcu); 1620 + list_for_each_entry_srcu(msc, &mpam_all_msc, all_msc_list, 1621 + srcu_read_lock_held(&mpam_srcu)) { 1622 + if (!cpumask_test_cpu(cpu, &msc->accessibility)) 1623 + continue; 1624 + 1625 + if (msc->reenable_error_ppi) 1626 + _enable_percpu_irq(&msc->reenable_error_ppi); 1627 + 1628 + if (atomic_fetch_inc(&msc->online_refs) == 0) 1629 + mpam_reprogram_msc(msc); 1630 + } 1631 + 1632 + return 0; 1633 + } 1634 + 1635 + /* Before mpam is enabled, try to probe new MSC */ 1636 + static int mpam_discovery_cpu_online(unsigned int cpu) 1637 + { 1638 + int err = 0; 1639 + struct mpam_msc *msc; 1640 + bool new_device_probed = false; 1641 + 1642 + if (mpam_is_enabled()) 1643 + return 0; 1644 + 1645 + guard(srcu)(&mpam_srcu); 1646 + list_for_each_entry_srcu(msc, &mpam_all_msc, all_msc_list, 1647 + srcu_read_lock_held(&mpam_srcu)) { 1648 + if (!cpumask_test_cpu(cpu, &msc->accessibility)) 1649 + continue; 1650 + 1651 + mutex_lock(&msc->probe_lock); 1652 + if (!msc->probed) 1653 + err = mpam_msc_hw_probe(msc); 1654 + mutex_unlock(&msc->probe_lock); 1655 + 1656 + if (err) 1657 + break; 1658 + new_device_probed = true; 1659 + } 1660 + 1661 + if (new_device_probed && !err) 1662 + schedule_work(&mpam_enable_work); 1663 + if (err) { 1664 + mpam_disable_reason = "error during probing"; 1665 + schedule_work(&mpam_broken_work); 1666 + } 1667 + 1668 + return err; 1669 + } 1670 + 1671 + static int mpam_cpu_offline(unsigned int cpu) 1672 + { 1673 + struct mpam_msc *msc; 1674 + 1675 + guard(srcu)(&mpam_srcu); 1676 + list_for_each_entry_srcu(msc, &mpam_all_msc, all_msc_list, 1677 + srcu_read_lock_held(&mpam_srcu)) { 1678 + if (!cpumask_test_cpu(cpu, &msc->accessibility)) 1679 + continue; 1680 + 1681 + if (msc->reenable_error_ppi) 1682 + disable_percpu_irq(msc->reenable_error_ppi); 1683 + 1684 + if (atomic_dec_and_test(&msc->online_refs)) { 1685 + struct mpam_msc_ris *ris; 1686 + 1687 + mutex_lock(&msc->cfg_lock); 1688 + list_for_each_entry_srcu(ris, &msc->ris, msc_list, 1689 + srcu_read_lock_held(&mpam_srcu)) { 1690 + mpam_touch_msc(msc, &mpam_reset_ris, ris); 1691 + 1692 + /* 1693 + * The reset state for non-zero partid may be 1694 + * lost while the CPUs are offline. 1695 + */ 1696 + ris->in_reset_state = false; 1697 + 1698 + if (mpam_is_enabled()) 1699 + mpam_touch_msc(msc, &mpam_save_mbwu_state, ris); 1700 + } 1701 + mutex_unlock(&msc->cfg_lock); 1702 + } 1703 + } 1704 + 1705 + return 0; 1706 + } 1707 + 1708 + static void mpam_register_cpuhp_callbacks(int (*online)(unsigned int online), 1709 + int (*offline)(unsigned int offline), 1710 + char *name) 1711 + { 1712 + mutex_lock(&mpam_cpuhp_state_lock); 1713 + if (mpam_cpuhp_state) { 1714 + cpuhp_remove_state(mpam_cpuhp_state); 1715 + mpam_cpuhp_state = 0; 1716 + } 1717 + 1718 + mpam_cpuhp_state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, name, online, 1719 + offline); 1720 + if (mpam_cpuhp_state <= 0) { 1721 + pr_err("Failed to register cpuhp callbacks"); 1722 + mpam_cpuhp_state = 0; 1723 + } 1724 + mutex_unlock(&mpam_cpuhp_state_lock); 1725 + } 1726 + 1727 + static int __setup_ppi(struct mpam_msc *msc) 1728 + { 1729 + int cpu; 1730 + 1731 + msc->error_dev_id = alloc_percpu(struct mpam_msc *); 1732 + if (!msc->error_dev_id) 1733 + return -ENOMEM; 1734 + 1735 + for_each_cpu(cpu, &msc->accessibility) 1736 + *per_cpu_ptr(msc->error_dev_id, cpu) = msc; 1737 + 1738 + return 0; 1739 + } 1740 + 1741 + static int mpam_msc_setup_error_irq(struct mpam_msc *msc) 1742 + { 1743 + int irq; 1744 + 1745 + irq = platform_get_irq_byname_optional(msc->pdev, "error"); 1746 + if (irq <= 0) 1747 + return 0; 1748 + 1749 + /* Allocate and initialise the percpu device pointer for PPI */ 1750 + if (irq_is_percpu(irq)) 1751 + return __setup_ppi(msc); 1752 + 1753 + /* sanity check: shared interrupts can be routed anywhere? */ 1754 + if (!cpumask_equal(&msc->accessibility, cpu_possible_mask)) { 1755 + pr_err_once("msc:%u is a private resource with a shared error interrupt", 1756 + msc->id); 1757 + return -EINVAL; 1758 + } 1759 + 1760 + return 0; 1761 + } 1762 + 1763 + /* 1764 + * An MSC can control traffic from a set of CPUs, but may only be accessible 1765 + * from a (hopefully wider) set of CPUs. The common reason for this is power 1766 + * management. If all the CPUs in a cluster are in PSCI:CPU_SUSPEND, the 1767 + * corresponding cache may also be powered off. By making accesses from 1768 + * one of those CPUs, we ensure we don't access a cache that's powered off. 1769 + */ 1770 + static void update_msc_accessibility(struct mpam_msc *msc) 1771 + { 1772 + u32 affinity_id; 1773 + int err; 1774 + 1775 + err = device_property_read_u32(&msc->pdev->dev, "cpu_affinity", 1776 + &affinity_id); 1777 + if (err) 1778 + cpumask_copy(&msc->accessibility, cpu_possible_mask); 1779 + else 1780 + acpi_pptt_get_cpus_from_container(affinity_id, &msc->accessibility); 1781 + } 1782 + 1783 + /* 1784 + * There are two ways of reaching a struct mpam_msc_ris. Via the 1785 + * class->component->vmsc->ris, or via the msc. 1786 + * When destroying the msc, the other side needs unlinking and cleaning up too. 1787 + */ 1788 + static void mpam_msc_destroy(struct mpam_msc *msc) 1789 + { 1790 + struct platform_device *pdev = msc->pdev; 1791 + struct mpam_msc_ris *ris, *tmp; 1792 + 1793 + lockdep_assert_held(&mpam_list_lock); 1794 + 1795 + list_for_each_entry_safe(ris, tmp, &msc->ris, msc_list) 1796 + mpam_ris_destroy(ris); 1797 + 1798 + list_del_rcu(&msc->all_msc_list); 1799 + platform_set_drvdata(pdev, NULL); 1800 + 1801 + add_to_garbage(msc); 1802 + } 1803 + 1804 + static void mpam_msc_drv_remove(struct platform_device *pdev) 1805 + { 1806 + struct mpam_msc *msc = platform_get_drvdata(pdev); 1807 + 1808 + mutex_lock(&mpam_list_lock); 1809 + mpam_msc_destroy(msc); 1810 + mutex_unlock(&mpam_list_lock); 1811 + 1812 + mpam_free_garbage(); 1813 + } 1814 + 1815 + static struct mpam_msc *do_mpam_msc_drv_probe(struct platform_device *pdev) 1816 + { 1817 + int err; 1818 + u32 tmp; 1819 + struct mpam_msc *msc; 1820 + struct resource *msc_res; 1821 + struct device *dev = &pdev->dev; 1822 + 1823 + lockdep_assert_held(&mpam_list_lock); 1824 + 1825 + msc = devm_kzalloc(&pdev->dev, sizeof(*msc), GFP_KERNEL); 1826 + if (!msc) 1827 + return ERR_PTR(-ENOMEM); 1828 + init_garbage(&msc->garbage); 1829 + msc->garbage.pdev = pdev; 1830 + 1831 + err = devm_mutex_init(dev, &msc->probe_lock); 1832 + if (err) 1833 + return ERR_PTR(err); 1834 + 1835 + err = devm_mutex_init(dev, &msc->part_sel_lock); 1836 + if (err) 1837 + return ERR_PTR(err); 1838 + 1839 + err = devm_mutex_init(dev, &msc->error_irq_lock); 1840 + if (err) 1841 + return ERR_PTR(err); 1842 + 1843 + err = devm_mutex_init(dev, &msc->cfg_lock); 1844 + if (err) 1845 + return ERR_PTR(err); 1846 + 1847 + mpam_mon_sel_lock_init(msc); 1848 + msc->id = pdev->id; 1849 + msc->pdev = pdev; 1850 + INIT_LIST_HEAD_RCU(&msc->all_msc_list); 1851 + INIT_LIST_HEAD_RCU(&msc->ris); 1852 + 1853 + update_msc_accessibility(msc); 1854 + if (cpumask_empty(&msc->accessibility)) { 1855 + dev_err_once(dev, "MSC is not accessible from any CPU!"); 1856 + return ERR_PTR(-EINVAL); 1857 + } 1858 + 1859 + err = mpam_msc_setup_error_irq(msc); 1860 + if (err) 1861 + return ERR_PTR(err); 1862 + 1863 + if (device_property_read_u32(&pdev->dev, "pcc-channel", &tmp)) 1864 + msc->iface = MPAM_IFACE_MMIO; 1865 + else 1866 + msc->iface = MPAM_IFACE_PCC; 1867 + 1868 + if (msc->iface == MPAM_IFACE_MMIO) { 1869 + void __iomem *io; 1870 + 1871 + io = devm_platform_get_and_ioremap_resource(pdev, 0, 1872 + &msc_res); 1873 + if (IS_ERR(io)) { 1874 + dev_err_once(dev, "Failed to map MSC base address\n"); 1875 + return ERR_CAST(io); 1876 + } 1877 + msc->mapped_hwpage_sz = msc_res->end - msc_res->start; 1878 + msc->mapped_hwpage = io; 1879 + } else { 1880 + return ERR_PTR(-EINVAL); 1881 + } 1882 + 1883 + list_add_rcu(&msc->all_msc_list, &mpam_all_msc); 1884 + platform_set_drvdata(pdev, msc); 1885 + 1886 + return msc; 1887 + } 1888 + 1889 + static int fw_num_msc; 1890 + 1891 + static int mpam_msc_drv_probe(struct platform_device *pdev) 1892 + { 1893 + int err; 1894 + struct mpam_msc *msc = NULL; 1895 + void *plat_data = pdev->dev.platform_data; 1896 + 1897 + mutex_lock(&mpam_list_lock); 1898 + msc = do_mpam_msc_drv_probe(pdev); 1899 + mutex_unlock(&mpam_list_lock); 1900 + 1901 + if (IS_ERR(msc)) 1902 + return PTR_ERR(msc); 1903 + 1904 + /* Create RIS entries described by firmware */ 1905 + err = acpi_mpam_parse_resources(msc, plat_data); 1906 + if (err) { 1907 + mpam_msc_drv_remove(pdev); 1908 + return err; 1909 + } 1910 + 1911 + if (atomic_add_return(1, &mpam_num_msc) == fw_num_msc) 1912 + mpam_register_cpuhp_callbacks(mpam_discovery_cpu_online, NULL, 1913 + "mpam:drv_probe"); 1914 + 1915 + return 0; 1916 + } 1917 + 1918 + static struct platform_driver mpam_msc_driver = { 1919 + .driver = { 1920 + .name = "mpam_msc", 1921 + }, 1922 + .probe = mpam_msc_drv_probe, 1923 + .remove = mpam_msc_drv_remove, 1924 + }; 1925 + 1926 + /* Any of these features mean the BWA_WD field is valid. */ 1927 + static bool mpam_has_bwa_wd_feature(struct mpam_props *props) 1928 + { 1929 + if (mpam_has_feature(mpam_feat_mbw_min, props)) 1930 + return true; 1931 + if (mpam_has_feature(mpam_feat_mbw_max, props)) 1932 + return true; 1933 + if (mpam_has_feature(mpam_feat_mbw_prop, props)) 1934 + return true; 1935 + return false; 1936 + } 1937 + 1938 + /* Any of these features mean the CMAX_WD field is valid. */ 1939 + static bool mpam_has_cmax_wd_feature(struct mpam_props *props) 1940 + { 1941 + if (mpam_has_feature(mpam_feat_cmax_cmax, props)) 1942 + return true; 1943 + if (mpam_has_feature(mpam_feat_cmax_cmin, props)) 1944 + return true; 1945 + return false; 1946 + } 1947 + 1948 + #define MISMATCHED_HELPER(parent, child, helper, field, alias) \ 1949 + helper(parent) && \ 1950 + ((helper(child) && (parent)->field != (child)->field) || \ 1951 + (!helper(child) && !(alias))) 1952 + 1953 + #define MISMATCHED_FEAT(parent, child, feat, field, alias) \ 1954 + mpam_has_feature((feat), (parent)) && \ 1955 + ((mpam_has_feature((feat), (child)) && (parent)->field != (child)->field) || \ 1956 + (!mpam_has_feature((feat), (child)) && !(alias))) 1957 + 1958 + #define CAN_MERGE_FEAT(parent, child, feat, alias) \ 1959 + (alias) && !mpam_has_feature((feat), (parent)) && \ 1960 + mpam_has_feature((feat), (child)) 1961 + 1962 + /* 1963 + * Combine two props fields. 1964 + * If this is for controls that alias the same resource, it is safe to just 1965 + * copy the values over. If two aliasing controls implement the same scheme 1966 + * a safe value must be picked. 1967 + * For non-aliasing controls, these control different resources, and the 1968 + * resulting safe value must be compatible with both. When merging values in 1969 + * the tree, all the aliasing resources must be handled first. 1970 + * On mismatch, parent is modified. 1971 + */ 1972 + static void __props_mismatch(struct mpam_props *parent, 1973 + struct mpam_props *child, bool alias) 1974 + { 1975 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_cpor_part, alias)) { 1976 + parent->cpbm_wd = child->cpbm_wd; 1977 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_cpor_part, 1978 + cpbm_wd, alias)) { 1979 + pr_debug("cleared cpor_part\n"); 1980 + mpam_clear_feature(mpam_feat_cpor_part, parent); 1981 + parent->cpbm_wd = 0; 1982 + } 1983 + 1984 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_mbw_part, alias)) { 1985 + parent->mbw_pbm_bits = child->mbw_pbm_bits; 1986 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_mbw_part, 1987 + mbw_pbm_bits, alias)) { 1988 + pr_debug("cleared mbw_part\n"); 1989 + mpam_clear_feature(mpam_feat_mbw_part, parent); 1990 + parent->mbw_pbm_bits = 0; 1991 + } 1992 + 1993 + /* bwa_wd is a count of bits, fewer bits means less precision */ 1994 + if (alias && !mpam_has_bwa_wd_feature(parent) && 1995 + mpam_has_bwa_wd_feature(child)) { 1996 + parent->bwa_wd = child->bwa_wd; 1997 + } else if (MISMATCHED_HELPER(parent, child, mpam_has_bwa_wd_feature, 1998 + bwa_wd, alias)) { 1999 + pr_debug("took the min bwa_wd\n"); 2000 + parent->bwa_wd = min(parent->bwa_wd, child->bwa_wd); 2001 + } 2002 + 2003 + if (alias && !mpam_has_cmax_wd_feature(parent) && mpam_has_cmax_wd_feature(child)) { 2004 + parent->cmax_wd = child->cmax_wd; 2005 + } else if (MISMATCHED_HELPER(parent, child, mpam_has_cmax_wd_feature, 2006 + cmax_wd, alias)) { 2007 + pr_debug("%s took the min cmax_wd\n", __func__); 2008 + parent->cmax_wd = min(parent->cmax_wd, child->cmax_wd); 2009 + } 2010 + 2011 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_cmax_cassoc, alias)) { 2012 + parent->cassoc_wd = child->cassoc_wd; 2013 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_cmax_cassoc, 2014 + cassoc_wd, alias)) { 2015 + pr_debug("%s cleared cassoc_wd\n", __func__); 2016 + mpam_clear_feature(mpam_feat_cmax_cassoc, parent); 2017 + parent->cassoc_wd = 0; 2018 + } 2019 + 2020 + /* For num properties, take the minimum */ 2021 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_msmon_csu, alias)) { 2022 + parent->num_csu_mon = child->num_csu_mon; 2023 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_msmon_csu, 2024 + num_csu_mon, alias)) { 2025 + pr_debug("took the min num_csu_mon\n"); 2026 + parent->num_csu_mon = min(parent->num_csu_mon, 2027 + child->num_csu_mon); 2028 + } 2029 + 2030 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_msmon_mbwu, alias)) { 2031 + parent->num_mbwu_mon = child->num_mbwu_mon; 2032 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_msmon_mbwu, 2033 + num_mbwu_mon, alias)) { 2034 + pr_debug("took the min num_mbwu_mon\n"); 2035 + parent->num_mbwu_mon = min(parent->num_mbwu_mon, 2036 + child->num_mbwu_mon); 2037 + } 2038 + 2039 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_intpri_part, alias)) { 2040 + parent->intpri_wd = child->intpri_wd; 2041 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_intpri_part, 2042 + intpri_wd, alias)) { 2043 + pr_debug("%s took the min intpri_wd\n", __func__); 2044 + parent->intpri_wd = min(parent->intpri_wd, child->intpri_wd); 2045 + } 2046 + 2047 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_dspri_part, alias)) { 2048 + parent->dspri_wd = child->dspri_wd; 2049 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_dspri_part, 2050 + dspri_wd, alias)) { 2051 + pr_debug("%s took the min dspri_wd\n", __func__); 2052 + parent->dspri_wd = min(parent->dspri_wd, child->dspri_wd); 2053 + } 2054 + 2055 + /* TODO: alias support for these two */ 2056 + /* {int,ds}pri may not have differing 0-low behaviour */ 2057 + if (mpam_has_feature(mpam_feat_intpri_part, parent) && 2058 + (!mpam_has_feature(mpam_feat_intpri_part, child) || 2059 + mpam_has_feature(mpam_feat_intpri_part_0_low, parent) != 2060 + mpam_has_feature(mpam_feat_intpri_part_0_low, child))) { 2061 + pr_debug("%s cleared intpri_part\n", __func__); 2062 + mpam_clear_feature(mpam_feat_intpri_part, parent); 2063 + mpam_clear_feature(mpam_feat_intpri_part_0_low, parent); 2064 + } 2065 + if (mpam_has_feature(mpam_feat_dspri_part, parent) && 2066 + (!mpam_has_feature(mpam_feat_dspri_part, child) || 2067 + mpam_has_feature(mpam_feat_dspri_part_0_low, parent) != 2068 + mpam_has_feature(mpam_feat_dspri_part_0_low, child))) { 2069 + pr_debug("%s cleared dspri_part\n", __func__); 2070 + mpam_clear_feature(mpam_feat_dspri_part, parent); 2071 + mpam_clear_feature(mpam_feat_dspri_part_0_low, parent); 2072 + } 2073 + 2074 + if (alias) { 2075 + /* Merge features for aliased resources */ 2076 + bitmap_or(parent->features, parent->features, child->features, MPAM_FEATURE_LAST); 2077 + } else { 2078 + /* Clear missing features for non aliasing */ 2079 + bitmap_and(parent->features, parent->features, child->features, MPAM_FEATURE_LAST); 2080 + } 2081 + } 2082 + 2083 + /* 2084 + * If a vmsc doesn't match class feature/configuration, do the right thing(tm). 2085 + * For 'num' properties we can just take the minimum. 2086 + * For properties where the mismatched unused bits would make a difference, we 2087 + * nobble the class feature, as we can't configure all the resources. 2088 + * e.g. The L3 cache is composed of two resources with 13 and 17 portion 2089 + * bitmaps respectively. 2090 + */ 2091 + static void 2092 + __class_props_mismatch(struct mpam_class *class, struct mpam_vmsc *vmsc) 2093 + { 2094 + struct mpam_props *cprops = &class->props; 2095 + struct mpam_props *vprops = &vmsc->props; 2096 + struct device *dev = &vmsc->msc->pdev->dev; 2097 + 2098 + lockdep_assert_held(&mpam_list_lock); /* we modify class */ 2099 + 2100 + dev_dbg(dev, "Merging features for class:0x%lx &= vmsc:0x%lx\n", 2101 + (long)cprops->features, (long)vprops->features); 2102 + 2103 + /* Take the safe value for any common features */ 2104 + __props_mismatch(cprops, vprops, false); 2105 + } 2106 + 2107 + static void 2108 + __vmsc_props_mismatch(struct mpam_vmsc *vmsc, struct mpam_msc_ris *ris) 2109 + { 2110 + struct mpam_props *rprops = &ris->props; 2111 + struct mpam_props *vprops = &vmsc->props; 2112 + struct device *dev = &vmsc->msc->pdev->dev; 2113 + 2114 + lockdep_assert_held(&mpam_list_lock); /* we modify vmsc */ 2115 + 2116 + dev_dbg(dev, "Merging features for vmsc:0x%lx |= ris:0x%lx\n", 2117 + (long)vprops->features, (long)rprops->features); 2118 + 2119 + /* 2120 + * Merge mismatched features - Copy any features that aren't common, 2121 + * but take the safe value for any common features. 2122 + */ 2123 + __props_mismatch(vprops, rprops, true); 2124 + } 2125 + 2126 + /* 2127 + * Copy the first component's first vMSC's properties and features to the 2128 + * class. __class_props_mismatch() will remove conflicts. 2129 + * It is not possible to have a class with no components, or a component with 2130 + * no resources. The vMSC properties have already been built. 2131 + */ 2132 + static void mpam_enable_init_class_features(struct mpam_class *class) 2133 + { 2134 + struct mpam_vmsc *vmsc; 2135 + struct mpam_component *comp; 2136 + 2137 + comp = list_first_entry(&class->components, 2138 + struct mpam_component, class_list); 2139 + vmsc = list_first_entry(&comp->vmsc, 2140 + struct mpam_vmsc, comp_list); 2141 + 2142 + class->props = vmsc->props; 2143 + } 2144 + 2145 + static void mpam_enable_merge_vmsc_features(struct mpam_component *comp) 2146 + { 2147 + struct mpam_vmsc *vmsc; 2148 + struct mpam_msc_ris *ris; 2149 + struct mpam_class *class = comp->class; 2150 + 2151 + list_for_each_entry(vmsc, &comp->vmsc, comp_list) { 2152 + list_for_each_entry(ris, &vmsc->ris, vmsc_list) { 2153 + __vmsc_props_mismatch(vmsc, ris); 2154 + class->nrdy_usec = max(class->nrdy_usec, 2155 + vmsc->msc->nrdy_usec); 2156 + } 2157 + } 2158 + } 2159 + 2160 + static void mpam_enable_merge_class_features(struct mpam_component *comp) 2161 + { 2162 + struct mpam_vmsc *vmsc; 2163 + struct mpam_class *class = comp->class; 2164 + 2165 + list_for_each_entry(vmsc, &comp->vmsc, comp_list) 2166 + __class_props_mismatch(class, vmsc); 2167 + } 2168 + 2169 + /* 2170 + * Merge all the common resource features into class. 2171 + * vmsc features are bitwise-or'd together by mpam_enable_merge_vmsc_features() 2172 + * as the first step so that mpam_enable_init_class_features() can initialise 2173 + * the class with a representative set of features. 2174 + * Next the mpam_enable_merge_class_features() bitwise-and's all the vmsc 2175 + * features to form the class features. 2176 + * Other features are the min/max as appropriate. 2177 + * 2178 + * To avoid walking the whole tree twice, the class->nrdy_usec property is 2179 + * updated when working with the vmsc as it is a max(), and doesn't need 2180 + * initialising first. 2181 + */ 2182 + static void mpam_enable_merge_features(struct list_head *all_classes_list) 2183 + { 2184 + struct mpam_class *class; 2185 + struct mpam_component *comp; 2186 + 2187 + lockdep_assert_held(&mpam_list_lock); 2188 + 2189 + list_for_each_entry(class, all_classes_list, classes_list) { 2190 + list_for_each_entry(comp, &class->components, class_list) 2191 + mpam_enable_merge_vmsc_features(comp); 2192 + 2193 + mpam_enable_init_class_features(class); 2194 + 2195 + list_for_each_entry(comp, &class->components, class_list) 2196 + mpam_enable_merge_class_features(comp); 2197 + } 2198 + } 2199 + 2200 + static char *mpam_errcode_names[16] = { 2201 + [MPAM_ERRCODE_NONE] = "No error", 2202 + [MPAM_ERRCODE_PARTID_SEL_RANGE] = "PARTID_SEL_Range", 2203 + [MPAM_ERRCODE_REQ_PARTID_RANGE] = "Req_PARTID_Range", 2204 + [MPAM_ERRCODE_MSMONCFG_ID_RANGE] = "MSMONCFG_ID_RANGE", 2205 + [MPAM_ERRCODE_REQ_PMG_RANGE] = "Req_PMG_Range", 2206 + [MPAM_ERRCODE_MONITOR_RANGE] = "Monitor_Range", 2207 + [MPAM_ERRCODE_INTPARTID_RANGE] = "intPARTID_Range", 2208 + [MPAM_ERRCODE_UNEXPECTED_INTERNAL] = "Unexpected_INTERNAL", 2209 + [MPAM_ERRCODE_UNDEFINED_RIS_PART_SEL] = "Undefined_RIS_PART_SEL", 2210 + [MPAM_ERRCODE_RIS_NO_CONTROL] = "RIS_No_Control", 2211 + [MPAM_ERRCODE_UNDEFINED_RIS_MON_SEL] = "Undefined_RIS_MON_SEL", 2212 + [MPAM_ERRCODE_RIS_NO_MONITOR] = "RIS_No_Monitor", 2213 + [12 ... 15] = "Reserved" 2214 + }; 2215 + 2216 + static int mpam_enable_msc_ecr(void *_msc) 2217 + { 2218 + struct mpam_msc *msc = _msc; 2219 + 2220 + __mpam_write_reg(msc, MPAMF_ECR, MPAMF_ECR_INTEN); 2221 + 2222 + return 0; 2223 + } 2224 + 2225 + /* This can run in mpam_disable(), and the interrupt handler on the same CPU */ 2226 + static int mpam_disable_msc_ecr(void *_msc) 2227 + { 2228 + struct mpam_msc *msc = _msc; 2229 + 2230 + __mpam_write_reg(msc, MPAMF_ECR, 0); 2231 + 2232 + return 0; 2233 + } 2234 + 2235 + static irqreturn_t __mpam_irq_handler(int irq, struct mpam_msc *msc) 2236 + { 2237 + u64 reg; 2238 + u16 partid; 2239 + u8 errcode, pmg, ris; 2240 + 2241 + if (WARN_ON_ONCE(!msc) || 2242 + WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), 2243 + &msc->accessibility))) 2244 + return IRQ_NONE; 2245 + 2246 + reg = mpam_msc_read_esr(msc); 2247 + 2248 + errcode = FIELD_GET(MPAMF_ESR_ERRCODE, reg); 2249 + if (!errcode) 2250 + return IRQ_NONE; 2251 + 2252 + /* Clear level triggered irq */ 2253 + mpam_msc_clear_esr(msc); 2254 + 2255 + partid = FIELD_GET(MPAMF_ESR_PARTID_MON, reg); 2256 + pmg = FIELD_GET(MPAMF_ESR_PMG, reg); 2257 + ris = FIELD_GET(MPAMF_ESR_RIS, reg); 2258 + 2259 + pr_err_ratelimited("error irq from msc:%u '%s', partid:%u, pmg: %u, ris: %u\n", 2260 + msc->id, mpam_errcode_names[errcode], partid, pmg, 2261 + ris); 2262 + 2263 + /* Disable this interrupt. */ 2264 + mpam_disable_msc_ecr(msc); 2265 + 2266 + /* Are we racing with the thread disabling MPAM? */ 2267 + if (!mpam_is_enabled()) 2268 + return IRQ_HANDLED; 2269 + 2270 + /* 2271 + * Schedule the teardown work. Don't use a threaded IRQ as we can't 2272 + * unregister the interrupt from the threaded part of the handler. 2273 + */ 2274 + mpam_disable_reason = "hardware error interrupt"; 2275 + schedule_work(&mpam_broken_work); 2276 + 2277 + return IRQ_HANDLED; 2278 + } 2279 + 2280 + static irqreturn_t mpam_ppi_handler(int irq, void *dev_id) 2281 + { 2282 + struct mpam_msc *msc = *(struct mpam_msc **)dev_id; 2283 + 2284 + return __mpam_irq_handler(irq, msc); 2285 + } 2286 + 2287 + static irqreturn_t mpam_spi_handler(int irq, void *dev_id) 2288 + { 2289 + struct mpam_msc *msc = dev_id; 2290 + 2291 + return __mpam_irq_handler(irq, msc); 2292 + } 2293 + 2294 + static int mpam_register_irqs(void) 2295 + { 2296 + int err, irq; 2297 + struct mpam_msc *msc; 2298 + 2299 + lockdep_assert_cpus_held(); 2300 + 2301 + guard(srcu)(&mpam_srcu); 2302 + list_for_each_entry_srcu(msc, &mpam_all_msc, all_msc_list, 2303 + srcu_read_lock_held(&mpam_srcu)) { 2304 + irq = platform_get_irq_byname_optional(msc->pdev, "error"); 2305 + if (irq <= 0) 2306 + continue; 2307 + 2308 + /* The MPAM spec says the interrupt can be SPI, PPI or LPI */ 2309 + /* We anticipate sharing the interrupt with other MSCs */ 2310 + if (irq_is_percpu(irq)) { 2311 + err = request_percpu_irq(irq, &mpam_ppi_handler, 2312 + "mpam:msc:error", 2313 + msc->error_dev_id); 2314 + if (err) 2315 + return err; 2316 + 2317 + msc->reenable_error_ppi = irq; 2318 + smp_call_function_many(&msc->accessibility, 2319 + &_enable_percpu_irq, &irq, 2320 + true); 2321 + } else { 2322 + err = devm_request_irq(&msc->pdev->dev, irq, 2323 + &mpam_spi_handler, IRQF_SHARED, 2324 + "mpam:msc:error", msc); 2325 + if (err) 2326 + return err; 2327 + } 2328 + 2329 + mutex_lock(&msc->error_irq_lock); 2330 + msc->error_irq_req = true; 2331 + mpam_touch_msc(msc, mpam_enable_msc_ecr, msc); 2332 + msc->error_irq_hw_enabled = true; 2333 + mutex_unlock(&msc->error_irq_lock); 2334 + } 2335 + 2336 + return 0; 2337 + } 2338 + 2339 + static void mpam_unregister_irqs(void) 2340 + { 2341 + int irq; 2342 + struct mpam_msc *msc; 2343 + 2344 + guard(cpus_read_lock)(); 2345 + guard(srcu)(&mpam_srcu); 2346 + list_for_each_entry_srcu(msc, &mpam_all_msc, all_msc_list, 2347 + srcu_read_lock_held(&mpam_srcu)) { 2348 + irq = platform_get_irq_byname_optional(msc->pdev, "error"); 2349 + if (irq <= 0) 2350 + continue; 2351 + 2352 + mutex_lock(&msc->error_irq_lock); 2353 + if (msc->error_irq_hw_enabled) { 2354 + mpam_touch_msc(msc, mpam_disable_msc_ecr, msc); 2355 + msc->error_irq_hw_enabled = false; 2356 + } 2357 + 2358 + if (msc->error_irq_req) { 2359 + if (irq_is_percpu(irq)) { 2360 + msc->reenable_error_ppi = 0; 2361 + free_percpu_irq(irq, msc->error_dev_id); 2362 + } else { 2363 + devm_free_irq(&msc->pdev->dev, irq, msc); 2364 + } 2365 + msc->error_irq_req = false; 2366 + } 2367 + mutex_unlock(&msc->error_irq_lock); 2368 + } 2369 + } 2370 + 2371 + static void __destroy_component_cfg(struct mpam_component *comp) 2372 + { 2373 + struct mpam_msc *msc; 2374 + struct mpam_vmsc *vmsc; 2375 + struct mpam_msc_ris *ris; 2376 + 2377 + lockdep_assert_held(&mpam_list_lock); 2378 + 2379 + add_to_garbage(comp->cfg); 2380 + list_for_each_entry(vmsc, &comp->vmsc, comp_list) { 2381 + msc = vmsc->msc; 2382 + 2383 + if (mpam_mon_sel_lock(msc)) { 2384 + list_for_each_entry(ris, &vmsc->ris, vmsc_list) 2385 + add_to_garbage(ris->mbwu_state); 2386 + mpam_mon_sel_unlock(msc); 2387 + } 2388 + } 2389 + } 2390 + 2391 + static void mpam_reset_component_cfg(struct mpam_component *comp) 2392 + { 2393 + int i; 2394 + struct mpam_props *cprops = &comp->class->props; 2395 + 2396 + mpam_assert_partid_sizes_fixed(); 2397 + 2398 + if (!comp->cfg) 2399 + return; 2400 + 2401 + for (i = 0; i <= mpam_partid_max; i++) { 2402 + comp->cfg[i] = (struct mpam_config) {}; 2403 + if (cprops->cpbm_wd) 2404 + comp->cfg[i].cpbm = GENMASK(cprops->cpbm_wd - 1, 0); 2405 + if (cprops->mbw_pbm_bits) 2406 + comp->cfg[i].mbw_pbm = GENMASK(cprops->mbw_pbm_bits - 1, 0); 2407 + if (cprops->bwa_wd) 2408 + comp->cfg[i].mbw_max = GENMASK(15, 16 - cprops->bwa_wd); 2409 + } 2410 + } 2411 + 2412 + static int __allocate_component_cfg(struct mpam_component *comp) 2413 + { 2414 + struct mpam_vmsc *vmsc; 2415 + 2416 + mpam_assert_partid_sizes_fixed(); 2417 + 2418 + if (comp->cfg) 2419 + return 0; 2420 + 2421 + comp->cfg = kcalloc(mpam_partid_max + 1, sizeof(*comp->cfg), GFP_KERNEL); 2422 + if (!comp->cfg) 2423 + return -ENOMEM; 2424 + 2425 + /* 2426 + * The array is free()d in one go, so only cfg[0]'s structure needs 2427 + * to be initialised. 2428 + */ 2429 + init_garbage(&comp->cfg[0].garbage); 2430 + 2431 + mpam_reset_component_cfg(comp); 2432 + 2433 + list_for_each_entry(vmsc, &comp->vmsc, comp_list) { 2434 + struct mpam_msc *msc; 2435 + struct mpam_msc_ris *ris; 2436 + struct msmon_mbwu_state *mbwu_state; 2437 + 2438 + if (!vmsc->props.num_mbwu_mon) 2439 + continue; 2440 + 2441 + msc = vmsc->msc; 2442 + list_for_each_entry(ris, &vmsc->ris, vmsc_list) { 2443 + if (!ris->props.num_mbwu_mon) 2444 + continue; 2445 + 2446 + mbwu_state = kcalloc(ris->props.num_mbwu_mon, 2447 + sizeof(*ris->mbwu_state), 2448 + GFP_KERNEL); 2449 + if (!mbwu_state) { 2450 + __destroy_component_cfg(comp); 2451 + return -ENOMEM; 2452 + } 2453 + 2454 + init_garbage(&mbwu_state[0].garbage); 2455 + 2456 + if (mpam_mon_sel_lock(msc)) { 2457 + ris->mbwu_state = mbwu_state; 2458 + mpam_mon_sel_unlock(msc); 2459 + } 2460 + } 2461 + } 2462 + 2463 + return 0; 2464 + } 2465 + 2466 + static int mpam_allocate_config(void) 2467 + { 2468 + struct mpam_class *class; 2469 + struct mpam_component *comp; 2470 + 2471 + lockdep_assert_held(&mpam_list_lock); 2472 + 2473 + list_for_each_entry(class, &mpam_classes, classes_list) { 2474 + list_for_each_entry(comp, &class->components, class_list) { 2475 + int err = __allocate_component_cfg(comp); 2476 + if (err) 2477 + return err; 2478 + } 2479 + } 2480 + 2481 + return 0; 2482 + } 2483 + 2484 + static void mpam_enable_once(void) 2485 + { 2486 + int err; 2487 + 2488 + /* 2489 + * Once the cpuhp callbacks have been changed, mpam_partid_max can no 2490 + * longer change. 2491 + */ 2492 + spin_lock(&partid_max_lock); 2493 + partid_max_published = true; 2494 + spin_unlock(&partid_max_lock); 2495 + 2496 + /* 2497 + * If all the MSC have been probed, enabling the IRQs happens next. 2498 + * That involves cross-calling to a CPU that can reach the MSC, and 2499 + * the locks must be taken in this order: 2500 + */ 2501 + cpus_read_lock(); 2502 + mutex_lock(&mpam_list_lock); 2503 + do { 2504 + mpam_enable_merge_features(&mpam_classes); 2505 + 2506 + err = mpam_register_irqs(); 2507 + if (err) { 2508 + pr_warn("Failed to register irqs: %d\n", err); 2509 + break; 2510 + } 2511 + 2512 + err = mpam_allocate_config(); 2513 + if (err) { 2514 + pr_err("Failed to allocate configuration arrays.\n"); 2515 + break; 2516 + } 2517 + } while (0); 2518 + mutex_unlock(&mpam_list_lock); 2519 + cpus_read_unlock(); 2520 + 2521 + if (err) { 2522 + mpam_disable_reason = "Failed to enable."; 2523 + schedule_work(&mpam_broken_work); 2524 + return; 2525 + } 2526 + 2527 + static_branch_enable(&mpam_enabled); 2528 + mpam_register_cpuhp_callbacks(mpam_cpu_online, mpam_cpu_offline, 2529 + "mpam:online"); 2530 + 2531 + /* Use printk() to avoid the pr_fmt adding the function name. */ 2532 + printk(KERN_INFO "MPAM enabled with %u PARTIDs and %u PMGs\n", 2533 + mpam_partid_max + 1, mpam_pmg_max + 1); 2534 + } 2535 + 2536 + static void mpam_reset_component_locked(struct mpam_component *comp) 2537 + { 2538 + struct mpam_vmsc *vmsc; 2539 + 2540 + lockdep_assert_cpus_held(); 2541 + mpam_assert_partid_sizes_fixed(); 2542 + 2543 + mpam_reset_component_cfg(comp); 2544 + 2545 + guard(srcu)(&mpam_srcu); 2546 + list_for_each_entry_srcu(vmsc, &comp->vmsc, comp_list, 2547 + srcu_read_lock_held(&mpam_srcu)) { 2548 + struct mpam_msc *msc = vmsc->msc; 2549 + struct mpam_msc_ris *ris; 2550 + 2551 + list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list, 2552 + srcu_read_lock_held(&mpam_srcu)) { 2553 + if (!ris->in_reset_state) 2554 + mpam_touch_msc(msc, mpam_reset_ris, ris); 2555 + ris->in_reset_state = true; 2556 + } 2557 + } 2558 + } 2559 + 2560 + static void mpam_reset_class_locked(struct mpam_class *class) 2561 + { 2562 + struct mpam_component *comp; 2563 + 2564 + lockdep_assert_cpus_held(); 2565 + 2566 + guard(srcu)(&mpam_srcu); 2567 + list_for_each_entry_srcu(comp, &class->components, class_list, 2568 + srcu_read_lock_held(&mpam_srcu)) 2569 + mpam_reset_component_locked(comp); 2570 + } 2571 + 2572 + static void mpam_reset_class(struct mpam_class *class) 2573 + { 2574 + cpus_read_lock(); 2575 + mpam_reset_class_locked(class); 2576 + cpus_read_unlock(); 2577 + } 2578 + 2579 + /* 2580 + * Called in response to an error IRQ. 2581 + * All of MPAMs errors indicate a software bug, restore any modified 2582 + * controls to their reset values. 2583 + */ 2584 + void mpam_disable(struct work_struct *ignored) 2585 + { 2586 + int idx; 2587 + struct mpam_class *class; 2588 + struct mpam_msc *msc, *tmp; 2589 + 2590 + mutex_lock(&mpam_cpuhp_state_lock); 2591 + if (mpam_cpuhp_state) { 2592 + cpuhp_remove_state(mpam_cpuhp_state); 2593 + mpam_cpuhp_state = 0; 2594 + } 2595 + mutex_unlock(&mpam_cpuhp_state_lock); 2596 + 2597 + static_branch_disable(&mpam_enabled); 2598 + 2599 + mpam_unregister_irqs(); 2600 + 2601 + idx = srcu_read_lock(&mpam_srcu); 2602 + list_for_each_entry_srcu(class, &mpam_classes, classes_list, 2603 + srcu_read_lock_held(&mpam_srcu)) 2604 + mpam_reset_class(class); 2605 + srcu_read_unlock(&mpam_srcu, idx); 2606 + 2607 + mutex_lock(&mpam_list_lock); 2608 + list_for_each_entry_safe(msc, tmp, &mpam_all_msc, all_msc_list) 2609 + mpam_msc_destroy(msc); 2610 + mutex_unlock(&mpam_list_lock); 2611 + mpam_free_garbage(); 2612 + 2613 + pr_err_once("MPAM disabled due to %s\n", mpam_disable_reason); 2614 + } 2615 + 2616 + /* 2617 + * Enable mpam once all devices have been probed. 2618 + * Scheduled by mpam_discovery_cpu_online() once all devices have been created. 2619 + * Also scheduled when new devices are probed when new CPUs come online. 2620 + */ 2621 + void mpam_enable(struct work_struct *work) 2622 + { 2623 + static atomic_t once; 2624 + struct mpam_msc *msc; 2625 + bool all_devices_probed = true; 2626 + 2627 + /* Have we probed all the hw devices? */ 2628 + guard(srcu)(&mpam_srcu); 2629 + list_for_each_entry_srcu(msc, &mpam_all_msc, all_msc_list, 2630 + srcu_read_lock_held(&mpam_srcu)) { 2631 + mutex_lock(&msc->probe_lock); 2632 + if (!msc->probed) 2633 + all_devices_probed = false; 2634 + mutex_unlock(&msc->probe_lock); 2635 + 2636 + if (!all_devices_probed) 2637 + break; 2638 + } 2639 + 2640 + if (all_devices_probed && !atomic_fetch_inc(&once)) 2641 + mpam_enable_once(); 2642 + } 2643 + 2644 + #define maybe_update_config(cfg, feature, newcfg, member, changes) do { \ 2645 + if (mpam_has_feature(feature, newcfg) && \ 2646 + (newcfg)->member != (cfg)->member) { \ 2647 + (cfg)->member = (newcfg)->member; \ 2648 + mpam_set_feature(feature, cfg); \ 2649 + \ 2650 + (changes) = true; \ 2651 + } \ 2652 + } while (0) 2653 + 2654 + static bool mpam_update_config(struct mpam_config *cfg, 2655 + const struct mpam_config *newcfg) 2656 + { 2657 + bool has_changes = false; 2658 + 2659 + maybe_update_config(cfg, mpam_feat_cpor_part, newcfg, cpbm, has_changes); 2660 + maybe_update_config(cfg, mpam_feat_mbw_part, newcfg, mbw_pbm, has_changes); 2661 + maybe_update_config(cfg, mpam_feat_mbw_max, newcfg, mbw_max, has_changes); 2662 + 2663 + return has_changes; 2664 + } 2665 + 2666 + int mpam_apply_config(struct mpam_component *comp, u16 partid, 2667 + struct mpam_config *cfg) 2668 + { 2669 + struct mpam_write_config_arg arg; 2670 + struct mpam_msc_ris *ris; 2671 + struct mpam_vmsc *vmsc; 2672 + struct mpam_msc *msc; 2673 + 2674 + lockdep_assert_cpus_held(); 2675 + 2676 + /* Don't pass in the current config! */ 2677 + WARN_ON_ONCE(&comp->cfg[partid] == cfg); 2678 + 2679 + if (!mpam_update_config(&comp->cfg[partid], cfg)) 2680 + return 0; 2681 + 2682 + arg.comp = comp; 2683 + arg.partid = partid; 2684 + 2685 + guard(srcu)(&mpam_srcu); 2686 + list_for_each_entry_srcu(vmsc, &comp->vmsc, comp_list, 2687 + srcu_read_lock_held(&mpam_srcu)) { 2688 + msc = vmsc->msc; 2689 + 2690 + mutex_lock(&msc->cfg_lock); 2691 + list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list, 2692 + srcu_read_lock_held(&mpam_srcu)) { 2693 + arg.ris = ris; 2694 + mpam_touch_msc(msc, __write_config, &arg); 2695 + } 2696 + mutex_unlock(&msc->cfg_lock); 2697 + } 2698 + 2699 + return 0; 2700 + } 2701 + 2702 + static int __init mpam_msc_driver_init(void) 2703 + { 2704 + if (!system_supports_mpam()) 2705 + return -EOPNOTSUPP; 2706 + 2707 + init_srcu_struct(&mpam_srcu); 2708 + 2709 + fw_num_msc = acpi_mpam_count_msc(); 2710 + if (fw_num_msc <= 0) { 2711 + pr_err("No MSC devices found in firmware\n"); 2712 + return -EINVAL; 2713 + } 2714 + 2715 + return platform_driver_register(&mpam_msc_driver); 2716 + } 2717 + 2718 + /* Must occur after arm64_mpam_register_cpus() from arch_initcall() */ 2719 + subsys_initcall(mpam_msc_driver_init); 2720 + 2721 + #ifdef CONFIG_MPAM_KUNIT_TEST 2722 + #include "test_mpam_devices.c" 2723 + #endif
+658
drivers/resctrl/mpam_internal.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + // Copyright (C) 2025 Arm Ltd. 3 + 4 + #ifndef MPAM_INTERNAL_H 5 + #define MPAM_INTERNAL_H 6 + 7 + #include <linux/arm_mpam.h> 8 + #include <linux/atomic.h> 9 + #include <linux/bitmap.h> 10 + #include <linux/cpumask.h> 11 + #include <linux/io.h> 12 + #include <linux/jump_label.h> 13 + #include <linux/llist.h> 14 + #include <linux/mutex.h> 15 + #include <linux/srcu.h> 16 + #include <linux/spinlock.h> 17 + #include <linux/srcu.h> 18 + #include <linux/types.h> 19 + 20 + #define MPAM_MSC_MAX_NUM_RIS 16 21 + 22 + struct platform_device; 23 + 24 + DECLARE_STATIC_KEY_FALSE(mpam_enabled); 25 + 26 + #ifdef CONFIG_MPAM_KUNIT_TEST 27 + #define PACKED_FOR_KUNIT __packed 28 + #else 29 + #define PACKED_FOR_KUNIT 30 + #endif 31 + 32 + static inline bool mpam_is_enabled(void) 33 + { 34 + return static_branch_likely(&mpam_enabled); 35 + } 36 + 37 + /* 38 + * Structures protected by SRCU may not be freed for a surprising amount of 39 + * time (especially if perf is running). To ensure the MPAM error interrupt can 40 + * tear down all the structures, build a list of objects that can be garbage 41 + * collected once synchronize_srcu() has returned. 42 + * If pdev is non-NULL, use devm_kfree(). 43 + */ 44 + struct mpam_garbage { 45 + /* member of mpam_garbage */ 46 + struct llist_node llist; 47 + 48 + void *to_free; 49 + struct platform_device *pdev; 50 + }; 51 + 52 + struct mpam_msc { 53 + /* member of mpam_all_msc */ 54 + struct list_head all_msc_list; 55 + 56 + int id; 57 + struct platform_device *pdev; 58 + 59 + /* Not modified after mpam_is_enabled() becomes true */ 60 + enum mpam_msc_iface iface; 61 + u32 nrdy_usec; 62 + cpumask_t accessibility; 63 + bool has_extd_esr; 64 + 65 + int reenable_error_ppi; 66 + struct mpam_msc * __percpu *error_dev_id; 67 + 68 + atomic_t online_refs; 69 + 70 + /* 71 + * probe_lock is only taken during discovery. After discovery these 72 + * properties become read-only and the lists are protected by SRCU. 73 + */ 74 + struct mutex probe_lock; 75 + bool probed; 76 + u16 partid_max; 77 + u8 pmg_max; 78 + unsigned long ris_idxs; 79 + u32 ris_max; 80 + 81 + /* 82 + * error_irq_lock is taken when registering/unregistering the error 83 + * interrupt and maniupulating the below flags. 84 + */ 85 + struct mutex error_irq_lock; 86 + bool error_irq_req; 87 + bool error_irq_hw_enabled; 88 + 89 + /* mpam_msc_ris of this component */ 90 + struct list_head ris; 91 + 92 + /* 93 + * part_sel_lock protects access to the MSC hardware registers that are 94 + * affected by MPAMCFG_PART_SEL. (including the ID registers that vary 95 + * by RIS). 96 + * If needed, take msc->probe_lock first. 97 + */ 98 + struct mutex part_sel_lock; 99 + 100 + /* 101 + * cfg_lock protects the msc configuration and guards against mbwu_state 102 + * save and restore racing. 103 + */ 104 + struct mutex cfg_lock; 105 + 106 + /* 107 + * mon_sel_lock protects access to the MSC hardware registers that are 108 + * affected by MPAMCFG_MON_SEL, and the mbwu_state. 109 + * Access to mon_sel is needed from both process and interrupt contexts, 110 + * but is complicated by firmware-backed platforms that can't make any 111 + * access unless they can sleep. 112 + * Always use the mpam_mon_sel_lock() helpers. 113 + * Accesses to mon_sel need to be able to fail if they occur in the wrong 114 + * context. 115 + * If needed, take msc->probe_lock first. 116 + */ 117 + raw_spinlock_t _mon_sel_lock; 118 + unsigned long _mon_sel_flags; 119 + 120 + void __iomem *mapped_hwpage; 121 + size_t mapped_hwpage_sz; 122 + 123 + struct mpam_garbage garbage; 124 + }; 125 + 126 + /* Returning false here means accesses to mon_sel must fail and report an error. */ 127 + static inline bool __must_check mpam_mon_sel_lock(struct mpam_msc *msc) 128 + { 129 + /* Locking will require updating to support a firmware backed interface */ 130 + if (WARN_ON_ONCE(msc->iface != MPAM_IFACE_MMIO)) 131 + return false; 132 + 133 + raw_spin_lock_irqsave(&msc->_mon_sel_lock, msc->_mon_sel_flags); 134 + return true; 135 + } 136 + 137 + static inline void mpam_mon_sel_unlock(struct mpam_msc *msc) 138 + { 139 + raw_spin_unlock_irqrestore(&msc->_mon_sel_lock, msc->_mon_sel_flags); 140 + } 141 + 142 + static inline void mpam_mon_sel_lock_held(struct mpam_msc *msc) 143 + { 144 + lockdep_assert_held_once(&msc->_mon_sel_lock); 145 + } 146 + 147 + static inline void mpam_mon_sel_lock_init(struct mpam_msc *msc) 148 + { 149 + raw_spin_lock_init(&msc->_mon_sel_lock); 150 + } 151 + 152 + /* Bits for mpam features bitmaps */ 153 + enum mpam_device_features { 154 + mpam_feat_cpor_part, 155 + mpam_feat_cmax_softlim, 156 + mpam_feat_cmax_cmax, 157 + mpam_feat_cmax_cmin, 158 + mpam_feat_cmax_cassoc, 159 + mpam_feat_mbw_part, 160 + mpam_feat_mbw_min, 161 + mpam_feat_mbw_max, 162 + mpam_feat_mbw_prop, 163 + mpam_feat_intpri_part, 164 + mpam_feat_intpri_part_0_low, 165 + mpam_feat_dspri_part, 166 + mpam_feat_dspri_part_0_low, 167 + mpam_feat_msmon, 168 + mpam_feat_msmon_csu, 169 + mpam_feat_msmon_csu_capture, 170 + mpam_feat_msmon_csu_xcl, 171 + mpam_feat_msmon_csu_hw_nrdy, 172 + mpam_feat_msmon_mbwu, 173 + mpam_feat_msmon_mbwu_31counter, 174 + mpam_feat_msmon_mbwu_44counter, 175 + mpam_feat_msmon_mbwu_63counter, 176 + mpam_feat_msmon_mbwu_capture, 177 + mpam_feat_msmon_mbwu_rwbw, 178 + mpam_feat_msmon_mbwu_hw_nrdy, 179 + mpam_feat_partid_nrw, 180 + MPAM_FEATURE_LAST 181 + }; 182 + 183 + struct mpam_props { 184 + DECLARE_BITMAP(features, MPAM_FEATURE_LAST); 185 + 186 + u16 cpbm_wd; 187 + u16 mbw_pbm_bits; 188 + u16 bwa_wd; 189 + u16 cmax_wd; 190 + u16 cassoc_wd; 191 + u16 intpri_wd; 192 + u16 dspri_wd; 193 + u16 num_csu_mon; 194 + u16 num_mbwu_mon; 195 + 196 + /* 197 + * Kunit tests use memset() to set up feature combinations that should be 198 + * removed, and will false-positive if the compiler introduces padding that 199 + * isn't cleared during sanitisation. 200 + */ 201 + } PACKED_FOR_KUNIT; 202 + 203 + #define mpam_has_feature(_feat, x) test_bit(_feat, (x)->features) 204 + #define mpam_set_feature(_feat, x) set_bit(_feat, (x)->features) 205 + #define mpam_clear_feature(_feat, x) clear_bit(_feat, (x)->features) 206 + 207 + /* The values for MSMON_CFG_MBWU_FLT.RWBW */ 208 + enum mon_filter_options { 209 + COUNT_BOTH = 0, 210 + COUNT_WRITE = 1, 211 + COUNT_READ = 2, 212 + }; 213 + 214 + struct mon_cfg { 215 + u16 mon; 216 + u8 pmg; 217 + bool match_pmg; 218 + bool csu_exclude_clean; 219 + u32 partid; 220 + enum mon_filter_options opts; 221 + }; 222 + 223 + /* Changes to msmon_mbwu_state are protected by the msc's mon_sel_lock. */ 224 + struct msmon_mbwu_state { 225 + bool enabled; 226 + bool reset_on_next_read; 227 + struct mon_cfg cfg; 228 + 229 + /* 230 + * The value to add to the new reading to account for power management, 231 + * and overflow. 232 + */ 233 + u64 correction; 234 + 235 + struct mpam_garbage garbage; 236 + }; 237 + 238 + struct mpam_class { 239 + /* mpam_components in this class */ 240 + struct list_head components; 241 + 242 + cpumask_t affinity; 243 + 244 + struct mpam_props props; 245 + u32 nrdy_usec; 246 + u8 level; 247 + enum mpam_class_types type; 248 + 249 + /* member of mpam_classes */ 250 + struct list_head classes_list; 251 + 252 + struct ida ida_csu_mon; 253 + struct ida ida_mbwu_mon; 254 + 255 + struct mpam_garbage garbage; 256 + }; 257 + 258 + struct mpam_config { 259 + /* Which configuration values are valid. */ 260 + DECLARE_BITMAP(features, MPAM_FEATURE_LAST); 261 + 262 + u32 cpbm; 263 + u32 mbw_pbm; 264 + u16 mbw_max; 265 + 266 + bool reset_cpbm; 267 + bool reset_mbw_pbm; 268 + bool reset_mbw_max; 269 + 270 + struct mpam_garbage garbage; 271 + }; 272 + 273 + struct mpam_component { 274 + u32 comp_id; 275 + 276 + /* mpam_vmsc in this component */ 277 + struct list_head vmsc; 278 + 279 + cpumask_t affinity; 280 + 281 + /* 282 + * Array of configuration values, indexed by partid. 283 + * Read from cpuhp callbacks, hold the cpuhp lock when writing. 284 + */ 285 + struct mpam_config *cfg; 286 + 287 + /* member of mpam_class:components */ 288 + struct list_head class_list; 289 + 290 + /* parent: */ 291 + struct mpam_class *class; 292 + 293 + struct mpam_garbage garbage; 294 + }; 295 + 296 + struct mpam_vmsc { 297 + /* member of mpam_component:vmsc_list */ 298 + struct list_head comp_list; 299 + 300 + /* mpam_msc_ris in this vmsc */ 301 + struct list_head ris; 302 + 303 + struct mpam_props props; 304 + 305 + /* All RIS in this vMSC are members of this MSC */ 306 + struct mpam_msc *msc; 307 + 308 + /* parent: */ 309 + struct mpam_component *comp; 310 + 311 + struct mpam_garbage garbage; 312 + }; 313 + 314 + struct mpam_msc_ris { 315 + u8 ris_idx; 316 + u64 idr; 317 + struct mpam_props props; 318 + bool in_reset_state; 319 + 320 + cpumask_t affinity; 321 + 322 + /* member of mpam_vmsc:ris */ 323 + struct list_head vmsc_list; 324 + 325 + /* member of mpam_msc:ris */ 326 + struct list_head msc_list; 327 + 328 + /* parent: */ 329 + struct mpam_vmsc *vmsc; 330 + 331 + /* msmon mbwu configuration is preserved over reset */ 332 + struct msmon_mbwu_state *mbwu_state; 333 + 334 + struct mpam_garbage garbage; 335 + }; 336 + 337 + static inline int mpam_alloc_csu_mon(struct mpam_class *class) 338 + { 339 + struct mpam_props *cprops = &class->props; 340 + 341 + if (!mpam_has_feature(mpam_feat_msmon_csu, cprops)) 342 + return -EOPNOTSUPP; 343 + 344 + return ida_alloc_max(&class->ida_csu_mon, cprops->num_csu_mon - 1, 345 + GFP_KERNEL); 346 + } 347 + 348 + static inline void mpam_free_csu_mon(struct mpam_class *class, int csu_mon) 349 + { 350 + ida_free(&class->ida_csu_mon, csu_mon); 351 + } 352 + 353 + static inline int mpam_alloc_mbwu_mon(struct mpam_class *class) 354 + { 355 + struct mpam_props *cprops = &class->props; 356 + 357 + if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops)) 358 + return -EOPNOTSUPP; 359 + 360 + return ida_alloc_max(&class->ida_mbwu_mon, cprops->num_mbwu_mon - 1, 361 + GFP_KERNEL); 362 + } 363 + 364 + static inline void mpam_free_mbwu_mon(struct mpam_class *class, int mbwu_mon) 365 + { 366 + ida_free(&class->ida_mbwu_mon, mbwu_mon); 367 + } 368 + 369 + /* List of all classes - protected by srcu*/ 370 + extern struct srcu_struct mpam_srcu; 371 + extern struct list_head mpam_classes; 372 + 373 + /* System wide partid/pmg values */ 374 + extern u16 mpam_partid_max; 375 + extern u8 mpam_pmg_max; 376 + 377 + /* Scheduled work callback to enable mpam once all MSC have been probed */ 378 + void mpam_enable(struct work_struct *work); 379 + void mpam_disable(struct work_struct *work); 380 + 381 + int mpam_apply_config(struct mpam_component *comp, u16 partid, 382 + struct mpam_config *cfg); 383 + 384 + int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx, 385 + enum mpam_device_features, u64 *val); 386 + void mpam_msmon_reset_mbwu(struct mpam_component *comp, struct mon_cfg *ctx); 387 + 388 + int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level, 389 + cpumask_t *affinity); 390 + 391 + /* 392 + * MPAM MSCs have the following register layout. See: 393 + * Arm Memory System Resource Partitioning and Monitoring (MPAM) System 394 + * Component Specification. 395 + * https://developer.arm.com/documentation/ihi0099/aa/ 396 + */ 397 + #define MPAM_ARCHITECTURE_V1 0x10 398 + 399 + /* Memory mapped control pages */ 400 + /* ID Register offsets in the memory mapped page */ 401 + #define MPAMF_IDR 0x0000 /* features id register */ 402 + #define MPAMF_IIDR 0x0018 /* implementer id register */ 403 + #define MPAMF_AIDR 0x0020 /* architectural id register */ 404 + #define MPAMF_IMPL_IDR 0x0028 /* imp-def partitioning */ 405 + #define MPAMF_CPOR_IDR 0x0030 /* cache-portion partitioning */ 406 + #define MPAMF_CCAP_IDR 0x0038 /* cache-capacity partitioning */ 407 + #define MPAMF_MBW_IDR 0x0040 /* mem-bw partitioning */ 408 + #define MPAMF_PRI_IDR 0x0048 /* priority partitioning */ 409 + #define MPAMF_MSMON_IDR 0x0080 /* performance monitoring features */ 410 + #define MPAMF_CSUMON_IDR 0x0088 /* cache-usage monitor */ 411 + #define MPAMF_MBWUMON_IDR 0x0090 /* mem-bw usage monitor */ 412 + #define MPAMF_PARTID_NRW_IDR 0x0050 /* partid-narrowing */ 413 + 414 + /* Configuration and Status Register offsets in the memory mapped page */ 415 + #define MPAMCFG_PART_SEL 0x0100 /* partid to configure */ 416 + #define MPAMCFG_CPBM 0x1000 /* cache-portion config */ 417 + #define MPAMCFG_CMAX 0x0108 /* cache-capacity config */ 418 + #define MPAMCFG_CMIN 0x0110 /* cache-capacity config */ 419 + #define MPAMCFG_CASSOC 0x0118 /* cache-associativity config */ 420 + #define MPAMCFG_MBW_MIN 0x0200 /* min mem-bw config */ 421 + #define MPAMCFG_MBW_MAX 0x0208 /* max mem-bw config */ 422 + #define MPAMCFG_MBW_WINWD 0x0220 /* mem-bw accounting window config */ 423 + #define MPAMCFG_MBW_PBM 0x2000 /* mem-bw portion bitmap config */ 424 + #define MPAMCFG_PRI 0x0400 /* priority partitioning config */ 425 + #define MPAMCFG_MBW_PROP 0x0500 /* mem-bw stride config */ 426 + #define MPAMCFG_INTPARTID 0x0600 /* partid-narrowing config */ 427 + 428 + #define MSMON_CFG_MON_SEL 0x0800 /* monitor selector */ 429 + #define MSMON_CFG_CSU_FLT 0x0810 /* cache-usage monitor filter */ 430 + #define MSMON_CFG_CSU_CTL 0x0818 /* cache-usage monitor config */ 431 + #define MSMON_CFG_MBWU_FLT 0x0820 /* mem-bw monitor filter */ 432 + #define MSMON_CFG_MBWU_CTL 0x0828 /* mem-bw monitor config */ 433 + #define MSMON_CSU 0x0840 /* current cache-usage */ 434 + #define MSMON_CSU_CAPTURE 0x0848 /* last cache-usage value captured */ 435 + #define MSMON_MBWU 0x0860 /* current mem-bw usage value */ 436 + #define MSMON_MBWU_CAPTURE 0x0868 /* last mem-bw value captured */ 437 + #define MSMON_MBWU_L 0x0880 /* current long mem-bw usage value */ 438 + #define MSMON_MBWU_L_CAPTURE 0x0890 /* last long mem-bw value captured */ 439 + #define MSMON_CAPT_EVNT 0x0808 /* signal a capture event */ 440 + #define MPAMF_ESR 0x00F8 /* error status register */ 441 + #define MPAMF_ECR 0x00F0 /* error control register */ 442 + 443 + /* MPAMF_IDR - MPAM features ID register */ 444 + #define MPAMF_IDR_PARTID_MAX GENMASK(15, 0) 445 + #define MPAMF_IDR_PMG_MAX GENMASK(23, 16) 446 + #define MPAMF_IDR_HAS_CCAP_PART BIT(24) 447 + #define MPAMF_IDR_HAS_CPOR_PART BIT(25) 448 + #define MPAMF_IDR_HAS_MBW_PART BIT(26) 449 + #define MPAMF_IDR_HAS_PRI_PART BIT(27) 450 + #define MPAMF_IDR_EXT BIT(28) 451 + #define MPAMF_IDR_HAS_IMPL_IDR BIT(29) 452 + #define MPAMF_IDR_HAS_MSMON BIT(30) 453 + #define MPAMF_IDR_HAS_PARTID_NRW BIT(31) 454 + #define MPAMF_IDR_HAS_RIS BIT(32) 455 + #define MPAMF_IDR_HAS_EXTD_ESR BIT(38) 456 + #define MPAMF_IDR_HAS_ESR BIT(39) 457 + #define MPAMF_IDR_RIS_MAX GENMASK(59, 56) 458 + 459 + /* MPAMF_MSMON_IDR - MPAM performance monitoring ID register */ 460 + #define MPAMF_MSMON_IDR_MSMON_CSU BIT(16) 461 + #define MPAMF_MSMON_IDR_MSMON_MBWU BIT(17) 462 + #define MPAMF_MSMON_IDR_HAS_LOCAL_CAPT_EVNT BIT(31) 463 + 464 + /* MPAMF_CPOR_IDR - MPAM features cache portion partitioning ID register */ 465 + #define MPAMF_CPOR_IDR_CPBM_WD GENMASK(15, 0) 466 + 467 + /* MPAMF_CCAP_IDR - MPAM features cache capacity partitioning ID register */ 468 + #define MPAMF_CCAP_IDR_CMAX_WD GENMASK(5, 0) 469 + #define MPAMF_CCAP_IDR_CASSOC_WD GENMASK(12, 8) 470 + #define MPAMF_CCAP_IDR_HAS_CASSOC BIT(28) 471 + #define MPAMF_CCAP_IDR_HAS_CMIN BIT(29) 472 + #define MPAMF_CCAP_IDR_NO_CMAX BIT(30) 473 + #define MPAMF_CCAP_IDR_HAS_CMAX_SOFTLIM BIT(31) 474 + 475 + /* MPAMF_MBW_IDR - MPAM features memory bandwidth partitioning ID register */ 476 + #define MPAMF_MBW_IDR_BWA_WD GENMASK(5, 0) 477 + #define MPAMF_MBW_IDR_HAS_MIN BIT(10) 478 + #define MPAMF_MBW_IDR_HAS_MAX BIT(11) 479 + #define MPAMF_MBW_IDR_HAS_PBM BIT(12) 480 + #define MPAMF_MBW_IDR_HAS_PROP BIT(13) 481 + #define MPAMF_MBW_IDR_WINDWR BIT(14) 482 + #define MPAMF_MBW_IDR_BWPBM_WD GENMASK(28, 16) 483 + 484 + /* MPAMF_PRI_IDR - MPAM features priority partitioning ID register */ 485 + #define MPAMF_PRI_IDR_HAS_INTPRI BIT(0) 486 + #define MPAMF_PRI_IDR_INTPRI_0_IS_LOW BIT(1) 487 + #define MPAMF_PRI_IDR_INTPRI_WD GENMASK(9, 4) 488 + #define MPAMF_PRI_IDR_HAS_DSPRI BIT(16) 489 + #define MPAMF_PRI_IDR_DSPRI_0_IS_LOW BIT(17) 490 + #define MPAMF_PRI_IDR_DSPRI_WD GENMASK(25, 20) 491 + 492 + /* MPAMF_CSUMON_IDR - MPAM cache storage usage monitor ID register */ 493 + #define MPAMF_CSUMON_IDR_NUM_MON GENMASK(15, 0) 494 + #define MPAMF_CSUMON_IDR_HAS_OFLOW_CAPT BIT(24) 495 + #define MPAMF_CSUMON_IDR_HAS_CEVNT_OFLW BIT(25) 496 + #define MPAMF_CSUMON_IDR_HAS_OFSR BIT(26) 497 + #define MPAMF_CSUMON_IDR_HAS_OFLOW_LNKG BIT(27) 498 + #define MPAMF_CSUMON_IDR_HAS_XCL BIT(29) 499 + #define MPAMF_CSUMON_IDR_CSU_RO BIT(30) 500 + #define MPAMF_CSUMON_IDR_HAS_CAPTURE BIT(31) 501 + 502 + /* MPAMF_MBWUMON_IDR - MPAM memory bandwidth usage monitor ID register */ 503 + #define MPAMF_MBWUMON_IDR_NUM_MON GENMASK(15, 0) 504 + #define MPAMF_MBWUMON_IDR_HAS_RWBW BIT(28) 505 + #define MPAMF_MBWUMON_IDR_LWD BIT(29) 506 + #define MPAMF_MBWUMON_IDR_HAS_LONG BIT(30) 507 + #define MPAMF_MBWUMON_IDR_HAS_CAPTURE BIT(31) 508 + 509 + /* MPAMF_PARTID_NRW_IDR - MPAM PARTID narrowing ID register */ 510 + #define MPAMF_PARTID_NRW_IDR_INTPARTID_MAX GENMASK(15, 0) 511 + 512 + /* MPAMF_IIDR - MPAM implementation ID register */ 513 + #define MPAMF_IIDR_IMPLEMENTER GENMASK(11, 0) 514 + #define MPAMF_IIDR_REVISION GENMASK(15, 12) 515 + #define MPAMF_IIDR_VARIANT GENMASK(19, 16) 516 + #define MPAMF_IIDR_PRODUCTID GENMASK(31, 20) 517 + 518 + /* MPAMF_AIDR - MPAM architecture ID register */ 519 + #define MPAMF_AIDR_ARCH_MINOR_REV GENMASK(3, 0) 520 + #define MPAMF_AIDR_ARCH_MAJOR_REV GENMASK(7, 4) 521 + 522 + /* MPAMCFG_PART_SEL - MPAM partition configuration selection register */ 523 + #define MPAMCFG_PART_SEL_PARTID_SEL GENMASK(15, 0) 524 + #define MPAMCFG_PART_SEL_INTERNAL BIT(16) 525 + #define MPAMCFG_PART_SEL_RIS GENMASK(27, 24) 526 + 527 + /* MPAMCFG_CASSOC - MPAM cache maximum associativity partition configuration register */ 528 + #define MPAMCFG_CASSOC_CASSOC GENMASK(15, 0) 529 + 530 + /* MPAMCFG_CMAX - MPAM cache capacity configuration register */ 531 + #define MPAMCFG_CMAX_SOFTLIM BIT(31) 532 + #define MPAMCFG_CMAX_CMAX GENMASK(15, 0) 533 + 534 + /* MPAMCFG_CMIN - MPAM cache capacity configuration register */ 535 + #define MPAMCFG_CMIN_CMIN GENMASK(15, 0) 536 + 537 + /* 538 + * MPAMCFG_MBW_MIN - MPAM memory minimum bandwidth partitioning configuration 539 + * register 540 + */ 541 + #define MPAMCFG_MBW_MIN_MIN GENMASK(15, 0) 542 + 543 + /* 544 + * MPAMCFG_MBW_MAX - MPAM memory maximum bandwidth partitioning configuration 545 + * register 546 + */ 547 + #define MPAMCFG_MBW_MAX_MAX GENMASK(15, 0) 548 + #define MPAMCFG_MBW_MAX_HARDLIM BIT(31) 549 + 550 + /* 551 + * MPAMCFG_MBW_WINWD - MPAM memory bandwidth partitioning window width 552 + * register 553 + */ 554 + #define MPAMCFG_MBW_WINWD_US_FRAC GENMASK(7, 0) 555 + #define MPAMCFG_MBW_WINWD_US_INT GENMASK(23, 8) 556 + 557 + /* MPAMCFG_PRI - MPAM priority partitioning configuration register */ 558 + #define MPAMCFG_PRI_INTPRI GENMASK(15, 0) 559 + #define MPAMCFG_PRI_DSPRI GENMASK(31, 16) 560 + 561 + /* 562 + * MPAMCFG_MBW_PROP - Memory bandwidth proportional stride partitioning 563 + * configuration register 564 + */ 565 + #define MPAMCFG_MBW_PROP_STRIDEM1 GENMASK(15, 0) 566 + #define MPAMCFG_MBW_PROP_EN BIT(31) 567 + 568 + /* 569 + * MPAMCFG_INTPARTID - MPAM internal partition narrowing configuration register 570 + */ 571 + #define MPAMCFG_INTPARTID_INTPARTID GENMASK(15, 0) 572 + #define MPAMCFG_INTPARTID_INTERNAL BIT(16) 573 + 574 + /* MSMON_CFG_MON_SEL - Memory system performance monitor selection register */ 575 + #define MSMON_CFG_MON_SEL_MON_SEL GENMASK(15, 0) 576 + #define MSMON_CFG_MON_SEL_RIS GENMASK(27, 24) 577 + 578 + /* MPAMF_ESR - MPAM Error Status Register */ 579 + #define MPAMF_ESR_PARTID_MON GENMASK(15, 0) 580 + #define MPAMF_ESR_PMG GENMASK(23, 16) 581 + #define MPAMF_ESR_ERRCODE GENMASK(27, 24) 582 + #define MPAMF_ESR_OVRWR BIT(31) 583 + #define MPAMF_ESR_RIS GENMASK(35, 32) 584 + 585 + /* MPAMF_ECR - MPAM Error Control Register */ 586 + #define MPAMF_ECR_INTEN BIT(0) 587 + 588 + /* Error conditions in accessing memory mapped registers */ 589 + #define MPAM_ERRCODE_NONE 0 590 + #define MPAM_ERRCODE_PARTID_SEL_RANGE 1 591 + #define MPAM_ERRCODE_REQ_PARTID_RANGE 2 592 + #define MPAM_ERRCODE_MSMONCFG_ID_RANGE 3 593 + #define MPAM_ERRCODE_REQ_PMG_RANGE 4 594 + #define MPAM_ERRCODE_MONITOR_RANGE 5 595 + #define MPAM_ERRCODE_INTPARTID_RANGE 6 596 + #define MPAM_ERRCODE_UNEXPECTED_INTERNAL 7 597 + #define MPAM_ERRCODE_UNDEFINED_RIS_PART_SEL 8 598 + #define MPAM_ERRCODE_RIS_NO_CONTROL 9 599 + #define MPAM_ERRCODE_UNDEFINED_RIS_MON_SEL 10 600 + #define MPAM_ERRCODE_RIS_NO_MONITOR 11 601 + 602 + /* 603 + * MSMON_CFG_CSU_CTL - Memory system performance monitor configure cache storage 604 + * usage monitor control register 605 + * MSMON_CFG_MBWU_CTL - Memory system performance monitor configure memory 606 + * bandwidth usage monitor control register 607 + */ 608 + #define MSMON_CFG_x_CTL_TYPE GENMASK(7, 0) 609 + #define MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L BIT(15) 610 + #define MSMON_CFG_x_CTL_MATCH_PARTID BIT(16) 611 + #define MSMON_CFG_x_CTL_MATCH_PMG BIT(17) 612 + #define MSMON_CFG_MBWU_CTL_SCLEN BIT(19) 613 + #define MSMON_CFG_x_CTL_SUBTYPE GENMASK(22, 20) 614 + #define MSMON_CFG_x_CTL_OFLOW_FRZ BIT(24) 615 + #define MSMON_CFG_x_CTL_OFLOW_INTR BIT(25) 616 + #define MSMON_CFG_x_CTL_OFLOW_STATUS BIT(26) 617 + #define MSMON_CFG_x_CTL_CAPT_RESET BIT(27) 618 + #define MSMON_CFG_x_CTL_CAPT_EVNT GENMASK(30, 28) 619 + #define MSMON_CFG_x_CTL_EN BIT(31) 620 + 621 + #define MSMON_CFG_MBWU_CTL_TYPE_MBWU 0x42 622 + #define MSMON_CFG_CSU_CTL_TYPE_CSU 0x43 623 + 624 + /* 625 + * MSMON_CFG_CSU_FLT - Memory system performance monitor configure cache storage 626 + * usage monitor filter register 627 + * MSMON_CFG_MBWU_FLT - Memory system performance monitor configure memory 628 + * bandwidth usage monitor filter register 629 + */ 630 + #define MSMON_CFG_x_FLT_PARTID GENMASK(15, 0) 631 + #define MSMON_CFG_x_FLT_PMG GENMASK(23, 16) 632 + 633 + #define MSMON_CFG_MBWU_FLT_RWBW GENMASK(31, 30) 634 + #define MSMON_CFG_CSU_FLT_XCL BIT(31) 635 + 636 + /* 637 + * MSMON_CSU - Memory system performance monitor cache storage usage monitor 638 + * register 639 + * MSMON_CSU_CAPTURE - Memory system performance monitor cache storage usage 640 + * capture register 641 + * MSMON_MBWU - Memory system performance monitor memory bandwidth usage 642 + * monitor register 643 + * MSMON_MBWU_CAPTURE - Memory system performance monitor memory bandwidth usage 644 + * capture register 645 + */ 646 + #define MSMON___VALUE GENMASK(30, 0) 647 + #define MSMON___NRDY BIT(31) 648 + #define MSMON___L_NRDY BIT(63) 649 + #define MSMON___L_VALUE GENMASK(43, 0) 650 + #define MSMON___LWD_VALUE GENMASK(62, 0) 651 + 652 + /* 653 + * MSMON_CAPT_EVNT - Memory system performance monitoring capture event 654 + * generation register 655 + */ 656 + #define MSMON_CAPT_EVNT_NOW BIT(0) 657 + 658 + #endif /* MPAM_INTERNAL_H */
+389
drivers/resctrl/test_mpam_devices.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2025 Arm Ltd. 3 + /* This file is intended to be included into mpam_devices.c */ 4 + 5 + #include <kunit/test.h> 6 + 7 + /* 8 + * This test catches fields that aren't being sanitised - but can't tell you 9 + * which one... 10 + */ 11 + static void test__props_mismatch(struct kunit *test) 12 + { 13 + struct mpam_props parent = { 0 }; 14 + struct mpam_props child; 15 + 16 + memset(&child, 0xff, sizeof(child)); 17 + __props_mismatch(&parent, &child, false); 18 + 19 + memset(&child, 0, sizeof(child)); 20 + KUNIT_EXPECT_EQ(test, memcmp(&parent, &child, sizeof(child)), 0); 21 + 22 + memset(&child, 0xff, sizeof(child)); 23 + __props_mismatch(&parent, &child, true); 24 + 25 + KUNIT_EXPECT_EQ(test, memcmp(&parent, &child, sizeof(child)), 0); 26 + } 27 + 28 + static struct list_head fake_classes_list; 29 + static struct mpam_class fake_class = { 0 }; 30 + static struct mpam_component fake_comp1 = { 0 }; 31 + static struct mpam_component fake_comp2 = { 0 }; 32 + static struct mpam_vmsc fake_vmsc1 = { 0 }; 33 + static struct mpam_vmsc fake_vmsc2 = { 0 }; 34 + static struct mpam_msc fake_msc1 = { 0 }; 35 + static struct mpam_msc fake_msc2 = { 0 }; 36 + static struct mpam_msc_ris fake_ris1 = { 0 }; 37 + static struct mpam_msc_ris fake_ris2 = { 0 }; 38 + static struct platform_device fake_pdev = { 0 }; 39 + 40 + static inline void reset_fake_hierarchy(void) 41 + { 42 + INIT_LIST_HEAD(&fake_classes_list); 43 + 44 + memset(&fake_class, 0, sizeof(fake_class)); 45 + fake_class.level = 3; 46 + fake_class.type = MPAM_CLASS_CACHE; 47 + INIT_LIST_HEAD_RCU(&fake_class.components); 48 + INIT_LIST_HEAD(&fake_class.classes_list); 49 + 50 + memset(&fake_comp1, 0, sizeof(fake_comp1)); 51 + memset(&fake_comp2, 0, sizeof(fake_comp2)); 52 + fake_comp1.comp_id = 1; 53 + fake_comp2.comp_id = 2; 54 + INIT_LIST_HEAD(&fake_comp1.vmsc); 55 + INIT_LIST_HEAD(&fake_comp1.class_list); 56 + INIT_LIST_HEAD(&fake_comp2.vmsc); 57 + INIT_LIST_HEAD(&fake_comp2.class_list); 58 + 59 + memset(&fake_vmsc1, 0, sizeof(fake_vmsc1)); 60 + memset(&fake_vmsc2, 0, sizeof(fake_vmsc2)); 61 + INIT_LIST_HEAD(&fake_vmsc1.ris); 62 + INIT_LIST_HEAD(&fake_vmsc1.comp_list); 63 + fake_vmsc1.msc = &fake_msc1; 64 + INIT_LIST_HEAD(&fake_vmsc2.ris); 65 + INIT_LIST_HEAD(&fake_vmsc2.comp_list); 66 + fake_vmsc2.msc = &fake_msc2; 67 + 68 + memset(&fake_ris1, 0, sizeof(fake_ris1)); 69 + memset(&fake_ris2, 0, sizeof(fake_ris2)); 70 + fake_ris1.ris_idx = 1; 71 + INIT_LIST_HEAD(&fake_ris1.msc_list); 72 + fake_ris2.ris_idx = 2; 73 + INIT_LIST_HEAD(&fake_ris2.msc_list); 74 + 75 + fake_msc1.pdev = &fake_pdev; 76 + fake_msc2.pdev = &fake_pdev; 77 + 78 + list_add(&fake_class.classes_list, &fake_classes_list); 79 + } 80 + 81 + static void test_mpam_enable_merge_features(struct kunit *test) 82 + { 83 + reset_fake_hierarchy(); 84 + 85 + mutex_lock(&mpam_list_lock); 86 + 87 + /* One Class+Comp, two RIS in one vMSC with common features */ 88 + fake_comp1.class = &fake_class; 89 + list_add(&fake_comp1.class_list, &fake_class.components); 90 + fake_comp2.class = NULL; 91 + fake_vmsc1.comp = &fake_comp1; 92 + list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 93 + fake_vmsc2.comp = NULL; 94 + fake_ris1.vmsc = &fake_vmsc1; 95 + list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 96 + fake_ris2.vmsc = &fake_vmsc1; 97 + list_add(&fake_ris2.vmsc_list, &fake_vmsc1.ris); 98 + 99 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 100 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris2.props); 101 + fake_ris1.props.cpbm_wd = 4; 102 + fake_ris2.props.cpbm_wd = 4; 103 + 104 + mpam_enable_merge_features(&fake_classes_list); 105 + 106 + KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 107 + KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 4); 108 + 109 + reset_fake_hierarchy(); 110 + 111 + /* One Class+Comp, two RIS in one vMSC with non-overlapping features */ 112 + fake_comp1.class = &fake_class; 113 + list_add(&fake_comp1.class_list, &fake_class.components); 114 + fake_comp2.class = NULL; 115 + fake_vmsc1.comp = &fake_comp1; 116 + list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 117 + fake_vmsc2.comp = NULL; 118 + fake_ris1.vmsc = &fake_vmsc1; 119 + list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 120 + fake_ris2.vmsc = &fake_vmsc1; 121 + list_add(&fake_ris2.vmsc_list, &fake_vmsc1.ris); 122 + 123 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 124 + mpam_set_feature(mpam_feat_cmax_cmin, &fake_ris2.props); 125 + fake_ris1.props.cpbm_wd = 4; 126 + fake_ris2.props.cmax_wd = 4; 127 + 128 + mpam_enable_merge_features(&fake_classes_list); 129 + 130 + /* Multiple RIS within one MSC controlling the same resource can be mismatched */ 131 + KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 132 + KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cmax_cmin, &fake_class.props)); 133 + KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cmax_cmin, &fake_vmsc1.props)); 134 + KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 4); 135 + KUNIT_EXPECT_EQ(test, fake_vmsc1.props.cmax_wd, 4); 136 + KUNIT_EXPECT_EQ(test, fake_class.props.cmax_wd, 4); 137 + 138 + reset_fake_hierarchy(); 139 + 140 + /* One Class+Comp, two MSC with overlapping features */ 141 + fake_comp1.class = &fake_class; 142 + list_add(&fake_comp1.class_list, &fake_class.components); 143 + fake_comp2.class = NULL; 144 + fake_vmsc1.comp = &fake_comp1; 145 + list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 146 + fake_vmsc2.comp = &fake_comp1; 147 + list_add(&fake_vmsc2.comp_list, &fake_comp1.vmsc); 148 + fake_ris1.vmsc = &fake_vmsc1; 149 + list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 150 + fake_ris2.vmsc = &fake_vmsc2; 151 + list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 152 + 153 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 154 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris2.props); 155 + fake_ris1.props.cpbm_wd = 4; 156 + fake_ris2.props.cpbm_wd = 4; 157 + 158 + mpam_enable_merge_features(&fake_classes_list); 159 + 160 + KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 161 + KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 4); 162 + 163 + reset_fake_hierarchy(); 164 + 165 + /* One Class+Comp, two MSC with non-overlapping features */ 166 + fake_comp1.class = &fake_class; 167 + list_add(&fake_comp1.class_list, &fake_class.components); 168 + fake_comp2.class = NULL; 169 + fake_vmsc1.comp = &fake_comp1; 170 + list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 171 + fake_vmsc2.comp = &fake_comp1; 172 + list_add(&fake_vmsc2.comp_list, &fake_comp1.vmsc); 173 + fake_ris1.vmsc = &fake_vmsc1; 174 + list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 175 + fake_ris2.vmsc = &fake_vmsc2; 176 + list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 177 + 178 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 179 + mpam_set_feature(mpam_feat_cmax_cmin, &fake_ris2.props); 180 + fake_ris1.props.cpbm_wd = 4; 181 + fake_ris2.props.cmax_wd = 4; 182 + 183 + mpam_enable_merge_features(&fake_classes_list); 184 + 185 + /* 186 + * Multiple RIS in different MSC can't control the same resource, 187 + * mismatched features can not be supported. 188 + */ 189 + KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 190 + KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cmax_cmin, &fake_class.props)); 191 + KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 0); 192 + KUNIT_EXPECT_EQ(test, fake_class.props.cmax_wd, 0); 193 + 194 + reset_fake_hierarchy(); 195 + 196 + /* One Class+Comp, two MSC with incompatible overlapping features */ 197 + fake_comp1.class = &fake_class; 198 + list_add(&fake_comp1.class_list, &fake_class.components); 199 + fake_comp2.class = NULL; 200 + fake_vmsc1.comp = &fake_comp1; 201 + list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 202 + fake_vmsc2.comp = &fake_comp1; 203 + list_add(&fake_vmsc2.comp_list, &fake_comp1.vmsc); 204 + fake_ris1.vmsc = &fake_vmsc1; 205 + list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 206 + fake_ris2.vmsc = &fake_vmsc2; 207 + list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 208 + 209 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 210 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris2.props); 211 + mpam_set_feature(mpam_feat_mbw_part, &fake_ris1.props); 212 + mpam_set_feature(mpam_feat_mbw_part, &fake_ris2.props); 213 + fake_ris1.props.cpbm_wd = 5; 214 + fake_ris2.props.cpbm_wd = 3; 215 + fake_ris1.props.mbw_pbm_bits = 5; 216 + fake_ris2.props.mbw_pbm_bits = 3; 217 + 218 + mpam_enable_merge_features(&fake_classes_list); 219 + 220 + /* 221 + * Multiple RIS in different MSC can't control the same resource, 222 + * mismatched features can not be supported. 223 + */ 224 + KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 225 + KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_mbw_part, &fake_class.props)); 226 + KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 0); 227 + KUNIT_EXPECT_EQ(test, fake_class.props.mbw_pbm_bits, 0); 228 + 229 + reset_fake_hierarchy(); 230 + 231 + /* One Class+Comp, two MSC with overlapping features that need tweaking */ 232 + fake_comp1.class = &fake_class; 233 + list_add(&fake_comp1.class_list, &fake_class.components); 234 + fake_comp2.class = NULL; 235 + fake_vmsc1.comp = &fake_comp1; 236 + list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 237 + fake_vmsc2.comp = &fake_comp1; 238 + list_add(&fake_vmsc2.comp_list, &fake_comp1.vmsc); 239 + fake_ris1.vmsc = &fake_vmsc1; 240 + list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 241 + fake_ris2.vmsc = &fake_vmsc2; 242 + list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 243 + 244 + mpam_set_feature(mpam_feat_mbw_min, &fake_ris1.props); 245 + mpam_set_feature(mpam_feat_mbw_min, &fake_ris2.props); 246 + mpam_set_feature(mpam_feat_cmax_cmax, &fake_ris1.props); 247 + mpam_set_feature(mpam_feat_cmax_cmax, &fake_ris2.props); 248 + fake_ris1.props.bwa_wd = 5; 249 + fake_ris2.props.bwa_wd = 3; 250 + fake_ris1.props.cmax_wd = 5; 251 + fake_ris2.props.cmax_wd = 3; 252 + 253 + mpam_enable_merge_features(&fake_classes_list); 254 + 255 + /* 256 + * RIS with different control properties need to be sanitised so the 257 + * class has the common set of properties. 258 + */ 259 + KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_class.props)); 260 + KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cmax_cmax, &fake_class.props)); 261 + KUNIT_EXPECT_EQ(test, fake_class.props.bwa_wd, 3); 262 + KUNIT_EXPECT_EQ(test, fake_class.props.cmax_wd, 3); 263 + 264 + reset_fake_hierarchy(); 265 + 266 + /* One Class Two Comp with overlapping features */ 267 + fake_comp1.class = &fake_class; 268 + list_add(&fake_comp1.class_list, &fake_class.components); 269 + fake_comp2.class = &fake_class; 270 + list_add(&fake_comp2.class_list, &fake_class.components); 271 + fake_vmsc1.comp = &fake_comp1; 272 + list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 273 + fake_vmsc2.comp = &fake_comp2; 274 + list_add(&fake_vmsc2.comp_list, &fake_comp2.vmsc); 275 + fake_ris1.vmsc = &fake_vmsc1; 276 + list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 277 + fake_ris2.vmsc = &fake_vmsc2; 278 + list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 279 + 280 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 281 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris2.props); 282 + fake_ris1.props.cpbm_wd = 4; 283 + fake_ris2.props.cpbm_wd = 4; 284 + 285 + mpam_enable_merge_features(&fake_classes_list); 286 + 287 + KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 288 + KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 4); 289 + 290 + reset_fake_hierarchy(); 291 + 292 + /* One Class Two Comp with non-overlapping features */ 293 + fake_comp1.class = &fake_class; 294 + list_add(&fake_comp1.class_list, &fake_class.components); 295 + fake_comp2.class = &fake_class; 296 + list_add(&fake_comp2.class_list, &fake_class.components); 297 + fake_vmsc1.comp = &fake_comp1; 298 + list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 299 + fake_vmsc2.comp = &fake_comp2; 300 + list_add(&fake_vmsc2.comp_list, &fake_comp2.vmsc); 301 + fake_ris1.vmsc = &fake_vmsc1; 302 + list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 303 + fake_ris2.vmsc = &fake_vmsc2; 304 + list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 305 + 306 + mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 307 + mpam_set_feature(mpam_feat_cmax_cmin, &fake_ris2.props); 308 + fake_ris1.props.cpbm_wd = 4; 309 + fake_ris2.props.cmax_wd = 4; 310 + 311 + mpam_enable_merge_features(&fake_classes_list); 312 + 313 + /* 314 + * Multiple components can't control the same resource, mismatched features can 315 + * not be supported. 316 + */ 317 + KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 318 + KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cmax_cmin, &fake_class.props)); 319 + KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 0); 320 + KUNIT_EXPECT_EQ(test, fake_class.props.cmax_wd, 0); 321 + 322 + mutex_unlock(&mpam_list_lock); 323 + } 324 + 325 + static void test_mpam_reset_msc_bitmap(struct kunit *test) 326 + { 327 + char __iomem *buf = kunit_kzalloc(test, SZ_16K, GFP_KERNEL); 328 + struct mpam_msc fake_msc = {}; 329 + u32 *test_result; 330 + 331 + if (!buf) 332 + return; 333 + 334 + fake_msc.mapped_hwpage = buf; 335 + fake_msc.mapped_hwpage_sz = SZ_16K; 336 + cpumask_copy(&fake_msc.accessibility, cpu_possible_mask); 337 + 338 + /* Satisfy lockdep checks */ 339 + mutex_init(&fake_msc.part_sel_lock); 340 + mutex_lock(&fake_msc.part_sel_lock); 341 + 342 + test_result = (u32 *)(buf + MPAMCFG_CPBM); 343 + 344 + mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 0); 345 + KUNIT_EXPECT_EQ(test, test_result[0], 0); 346 + KUNIT_EXPECT_EQ(test, test_result[1], 0); 347 + test_result[0] = 0; 348 + test_result[1] = 0; 349 + 350 + mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 1); 351 + KUNIT_EXPECT_EQ(test, test_result[0], 1); 352 + KUNIT_EXPECT_EQ(test, test_result[1], 0); 353 + test_result[0] = 0; 354 + test_result[1] = 0; 355 + 356 + mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 16); 357 + KUNIT_EXPECT_EQ(test, test_result[0], 0xffff); 358 + KUNIT_EXPECT_EQ(test, test_result[1], 0); 359 + test_result[0] = 0; 360 + test_result[1] = 0; 361 + 362 + mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 32); 363 + KUNIT_EXPECT_EQ(test, test_result[0], 0xffffffff); 364 + KUNIT_EXPECT_EQ(test, test_result[1], 0); 365 + test_result[0] = 0; 366 + test_result[1] = 0; 367 + 368 + mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 33); 369 + KUNIT_EXPECT_EQ(test, test_result[0], 0xffffffff); 370 + KUNIT_EXPECT_EQ(test, test_result[1], 1); 371 + test_result[0] = 0; 372 + test_result[1] = 0; 373 + 374 + mutex_unlock(&fake_msc.part_sel_lock); 375 + } 376 + 377 + static struct kunit_case mpam_devices_test_cases[] = { 378 + KUNIT_CASE(test_mpam_reset_msc_bitmap), 379 + KUNIT_CASE(test_mpam_enable_merge_features), 380 + KUNIT_CASE(test__props_mismatch), 381 + {} 382 + }; 383 + 384 + static struct kunit_suite mpam_devices_test_suite = { 385 + .name = "mpam_devices_test_suite", 386 + .test_cases = mpam_devices_test_cases, 387 + }; 388 + 389 + kunit_test_suites(&mpam_devices_test_suite);
+26 -1
include/linux/acpi.h
··· 8 8 #ifndef _LINUX_ACPI_H 9 9 #define _LINUX_ACPI_H 10 10 11 + #include <linux/cleanup.h> 11 12 #include <linux/errno.h> 12 13 #include <linux/ioport.h> /* for struct resource */ 13 14 #include <linux/resource_ext.h> ··· 221 220 void acpi_reserve_initial_tables (void); 222 221 void acpi_table_init_complete (void); 223 222 int acpi_table_init (void); 223 + 224 + static inline struct acpi_table_header *acpi_get_table_pointer(char *signature, u32 instance) 225 + { 226 + struct acpi_table_header *table; 227 + int status = acpi_get_table(signature, instance, &table); 228 + 229 + if (ACPI_FAILURE(status)) 230 + return ERR_PTR(-ENOENT); 231 + return table; 232 + } 233 + DEFINE_FREE(acpi_put_table, struct acpi_table_header *, if (!IS_ERR_OR_NULL(_T)) acpi_put_table(_T)) 224 234 225 235 int acpi_table_parse(char *id, acpi_tbl_table_handler handler); 226 236 int __init_or_acpilib acpi_table_parse_entries(char *id, ··· 767 755 int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count); 768 756 int acpi_gtdt_map_ppi(int type); 769 757 bool acpi_gtdt_c3stop(int type); 770 - int acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, int *timer_count); 771 758 #endif 772 759 773 760 #ifndef ACPI_HAVE_ARCH_SET_ROOT_POINTER ··· 1552 1541 int find_acpi_cpu_topology_cluster(unsigned int cpu); 1553 1542 int find_acpi_cpu_topology_package(unsigned int cpu); 1554 1543 int find_acpi_cpu_topology_hetero_id(unsigned int cpu); 1544 + void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id, cpumask_t *cpus); 1545 + int find_acpi_cache_level_from_id(u32 cache_id); 1546 + int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus); 1555 1547 #else 1556 1548 static inline int acpi_pptt_cpu_is_thread(unsigned int cpu) 1557 1549 { ··· 1575 1561 static inline int find_acpi_cpu_topology_hetero_id(unsigned int cpu) 1576 1562 { 1577 1563 return -EINVAL; 1564 + } 1565 + static inline void acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id, 1566 + cpumask_t *cpus) { } 1567 + static inline int find_acpi_cache_level_from_id(u32 cache_id) 1568 + { 1569 + return -ENOENT; 1570 + } 1571 + static inline int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, 1572 + cpumask_t *cpus) 1573 + { 1574 + return -ENOENT; 1578 1575 } 1579 1576 #endif 1580 1577
+66
include/linux/arm_mpam.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (C) 2025 Arm Ltd. */ 3 + 4 + #ifndef __LINUX_ARM_MPAM_H 5 + #define __LINUX_ARM_MPAM_H 6 + 7 + #include <linux/acpi.h> 8 + #include <linux/types.h> 9 + 10 + struct mpam_msc; 11 + 12 + enum mpam_msc_iface { 13 + MPAM_IFACE_MMIO, /* a real MPAM MSC */ 14 + MPAM_IFACE_PCC, /* a fake MPAM MSC */ 15 + }; 16 + 17 + enum mpam_class_types { 18 + MPAM_CLASS_CACHE, /* Caches, e.g. L2, L3 */ 19 + MPAM_CLASS_MEMORY, /* Main memory */ 20 + MPAM_CLASS_UNKNOWN, /* Everything else, e.g. SMMU */ 21 + }; 22 + 23 + #define MPAM_CLASS_ID_DEFAULT 255 24 + 25 + #ifdef CONFIG_ACPI_MPAM 26 + int acpi_mpam_parse_resources(struct mpam_msc *msc, 27 + struct acpi_mpam_msc_node *tbl_msc); 28 + 29 + int acpi_mpam_count_msc(void); 30 + #else 31 + static inline int acpi_mpam_parse_resources(struct mpam_msc *msc, 32 + struct acpi_mpam_msc_node *tbl_msc) 33 + { 34 + return -EINVAL; 35 + } 36 + 37 + static inline int acpi_mpam_count_msc(void) { return -EINVAL; } 38 + #endif 39 + 40 + #ifdef CONFIG_ARM64_MPAM_DRIVER 41 + int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx, 42 + enum mpam_class_types type, u8 class_id, int component_id); 43 + #else 44 + static inline int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx, 45 + enum mpam_class_types type, u8 class_id, 46 + int component_id) 47 + { 48 + return -EINVAL; 49 + } 50 + #endif 51 + 52 + /** 53 + * mpam_register_requestor() - Register a requestor with the MPAM driver 54 + * @partid_max: The maximum PARTID value the requestor can generate. 55 + * @pmg_max: The maximum PMG value the requestor can generate. 56 + * 57 + * Registers a requestor with the MPAM driver to ensure the chosen system-wide 58 + * minimum PARTID and PMG values will allow the requestors features to be used. 59 + * 60 + * Returns an error if the registration is too late, and a larger PARTID/PMG 61 + * value has been advertised to user-space. In this case the requestor should 62 + * not use its MPAM features. Returns 0 on success. 63 + */ 64 + int mpam_register_requestor(u16 partid_max, u8 pmg_max); 65 + 66 + #endif /* __LINUX_ARM_MPAM_H */
+2
include/linux/efi.h
··· 1126 1126 extern void efi_call_virt_check_flags(unsigned long flags, const void *caller); 1127 1127 extern unsigned long efi_call_virt_save_flags(void); 1128 1128 1129 + void efi_runtime_assert_lock_held(void); 1130 + 1129 1131 enum efi_secureboot_mode { 1130 1132 efi_secureboot_mode_unset, 1131 1133 efi_secureboot_mode_unknown,
+1 -1
include/linux/huge_mm.h
··· 11 11 int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, 12 12 pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long addr, 13 13 struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma); 14 - void huge_pmd_set_accessed(struct vm_fault *vmf); 14 + bool huge_pmd_set_accessed(struct vm_fault *vmf); 15 15 int copy_huge_pud(struct mm_struct *dst_mm, struct mm_struct *src_mm, 16 16 pud_t *dst_pud, pud_t *src_pud, unsigned long addr, 17 17 struct vm_area_struct *vma);
+4
include/linux/pgtable.h
··· 1232 1232 #define flush_tlb_fix_spurious_fault(vma, address, ptep) flush_tlb_page(vma, address) 1233 1233 #endif 1234 1234 1235 + #ifndef flush_tlb_fix_spurious_fault_pmd 1236 + #define flush_tlb_fix_spurious_fault_pmd(vma, address, pmdp) do { } while (0) 1237 + #endif 1238 + 1235 1239 /* 1236 1240 * When walking page tables, get the address of the next boundary, 1237 1241 * or the end address of the range if that comes earlier. Although no
+1
include/linux/platform_device.h
··· 232 232 extern int platform_device_add(struct platform_device *pdev); 233 233 extern void platform_device_del(struct platform_device *pdev); 234 234 extern void platform_device_put(struct platform_device *pdev); 235 + DEFINE_FREE(platform_device_put, struct platform_device *, if (_T) platform_device_put(_T)) 235 236 236 237 struct platform_driver { 237 238 int (*probe)(struct platform_device *);
+21 -12
mm/huge_memory.c
··· 1641 1641 EXPORT_SYMBOL_GPL(vmf_insert_folio_pud); 1642 1642 #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */ 1643 1643 1644 - void touch_pmd(struct vm_area_struct *vma, unsigned long addr, 1644 + /** 1645 + * touch_pmd - Mark page table pmd entry as accessed and dirty (for write) 1646 + * @vma: The VMA covering @addr 1647 + * @addr: The virtual address 1648 + * @pmd: pmd pointer into the page table mapping @addr 1649 + * @write: Whether it's a write access 1650 + * 1651 + * Return: whether the pmd entry is changed 1652 + */ 1653 + bool touch_pmd(struct vm_area_struct *vma, unsigned long addr, 1645 1654 pmd_t *pmd, bool write) 1646 1655 { 1647 - pmd_t _pmd; 1656 + pmd_t entry; 1648 1657 1649 - _pmd = pmd_mkyoung(*pmd); 1658 + entry = pmd_mkyoung(*pmd); 1650 1659 if (write) 1651 - _pmd = pmd_mkdirty(_pmd); 1660 + entry = pmd_mkdirty(entry); 1652 1661 if (pmdp_set_access_flags(vma, addr & HPAGE_PMD_MASK, 1653 - pmd, _pmd, write)) 1662 + pmd, entry, write)) { 1654 1663 update_mmu_cache_pmd(vma, addr, pmd); 1664 + return true; 1665 + } 1666 + 1667 + return false; 1655 1668 } 1656 1669 1657 1670 int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, ··· 1854 1841 } 1855 1842 #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */ 1856 1843 1857 - void huge_pmd_set_accessed(struct vm_fault *vmf) 1844 + bool huge_pmd_set_accessed(struct vm_fault *vmf) 1858 1845 { 1859 1846 bool write = vmf->flags & FAULT_FLAG_WRITE; 1860 1847 1861 - vmf->ptl = pmd_lock(vmf->vma->vm_mm, vmf->pmd); 1862 1848 if (unlikely(!pmd_same(*vmf->pmd, vmf->orig_pmd))) 1863 - goto unlock; 1849 + return false; 1864 1850 1865 - touch_pmd(vmf->vma, vmf->address, vmf->pmd, write); 1866 - 1867 - unlock: 1868 - spin_unlock(vmf->ptl); 1851 + return touch_pmd(vmf->vma, vmf->address, vmf->pmd, write); 1869 1852 } 1870 1853 1871 1854 static vm_fault_t do_huge_zero_wp_pmd(struct vm_fault *vmf)
+1 -1
mm/internal.h
··· 1402 1402 */ 1403 1403 void touch_pud(struct vm_area_struct *vma, unsigned long addr, 1404 1404 pud_t *pud, bool write); 1405 - void touch_pmd(struct vm_area_struct *vma, unsigned long addr, 1405 + bool touch_pmd(struct vm_area_struct *vma, unsigned long addr, 1406 1406 pmd_t *pmd, bool write); 1407 1407 1408 1408 /*
+46 -16
mm/memory.c
··· 6116 6116 } 6117 6117 6118 6118 /* 6119 + * The page faults may be spurious because of the racy access to the 6120 + * page table. For example, a non-populated virtual page is accessed 6121 + * on 2 CPUs simultaneously, thus the page faults are triggered on 6122 + * both CPUs. However, it's possible that one CPU (say CPU A) cannot 6123 + * find the reason for the page fault if the other CPU (say CPU B) has 6124 + * changed the page table before the PTE is checked on CPU A. Most of 6125 + * the time, the spurious page faults can be ignored safely. However, 6126 + * if the page fault is for the write access, it's possible that a 6127 + * stale read-only TLB entry exists in the local CPU and needs to be 6128 + * flushed on some architectures. This is called the spurious page 6129 + * fault fixing. 6130 + * 6131 + * Note: flush_tlb_fix_spurious_fault() is defined as flush_tlb_page() 6132 + * by default and used as such on most architectures, while 6133 + * flush_tlb_fix_spurious_fault_pmd() is defined as NOP by default and 6134 + * used as such on most architectures. 6135 + */ 6136 + static void fix_spurious_fault(struct vm_fault *vmf, 6137 + enum pgtable_level ptlevel) 6138 + { 6139 + /* Skip spurious TLB flush for retried page fault */ 6140 + if (vmf->flags & FAULT_FLAG_TRIED) 6141 + return; 6142 + /* 6143 + * This is needed only for protection faults but the arch code 6144 + * is not yet telling us if this is a protection fault or not. 6145 + * This still avoids useless tlb flushes for .text page faults 6146 + * with threads. 6147 + */ 6148 + if (vmf->flags & FAULT_FLAG_WRITE) { 6149 + if (ptlevel == PGTABLE_LEVEL_PTE) 6150 + flush_tlb_fix_spurious_fault(vmf->vma, vmf->address, 6151 + vmf->pte); 6152 + else 6153 + flush_tlb_fix_spurious_fault_pmd(vmf->vma, vmf->address, 6154 + vmf->pmd); 6155 + } 6156 + } 6157 + /* 6119 6158 * These routines also need to handle stuff like marking pages dirty 6120 6159 * and/or accessed for architectures that don't do it in hardware (most 6121 6160 * RISC architectures). The early dirtying is also good on the i386. ··· 6235 6196 } 6236 6197 entry = pte_mkyoung(entry); 6237 6198 if (ptep_set_access_flags(vmf->vma, vmf->address, vmf->pte, entry, 6238 - vmf->flags & FAULT_FLAG_WRITE)) { 6199 + vmf->flags & FAULT_FLAG_WRITE)) 6239 6200 update_mmu_cache_range(vmf, vmf->vma, vmf->address, 6240 6201 vmf->pte, 1); 6241 - } else { 6242 - /* Skip spurious TLB flush for retried page fault */ 6243 - if (vmf->flags & FAULT_FLAG_TRIED) 6244 - goto unlock; 6245 - /* 6246 - * This is needed only for protection faults but the arch code 6247 - * is not yet telling us if this is a protection fault or not. 6248 - * This still avoids useless tlb flushes for .text page faults 6249 - * with threads. 6250 - */ 6251 - if (vmf->flags & FAULT_FLAG_WRITE) 6252 - flush_tlb_fix_spurious_fault(vmf->vma, vmf->address, 6253 - vmf->pte); 6254 - } 6202 + else 6203 + fix_spurious_fault(vmf, PGTABLE_LEVEL_PTE); 6255 6204 unlock: 6256 6205 pte_unmap_unlock(vmf->pte, vmf->ptl); 6257 6206 return 0; ··· 6336 6309 if (!(ret & VM_FAULT_FALLBACK)) 6337 6310 return ret; 6338 6311 } else { 6339 - huge_pmd_set_accessed(&vmf); 6312 + vmf.ptl = pmd_lock(mm, vmf.pmd); 6313 + if (!huge_pmd_set_accessed(&vmf)) 6314 + fix_spurious_fault(&vmf, PGTABLE_LEVEL_PMD); 6315 + spin_unlock(vmf.ptl); 6340 6316 return 0; 6341 6317 } 6342 6318 }
+2 -2
tools/arch/arm64/include/asm/cputype.h
··· 245 245 #define MIDR_FUJITSU_ERRATUM_010001_MASK (~MIDR_CPU_VAR_REV(1, 0)) 246 246 #define TCR_CLEAR_FUJITSU_ERRATUM_010001 (TCR_NFD1 | TCR_NFD0) 247 247 248 - #ifndef __ASSEMBLY__ 248 + #ifndef __ASSEMBLER__ 249 249 250 250 #include <asm/sysreg.h> 251 251 ··· 338 338 { 339 339 return read_cpuid(CTR_EL0); 340 340 } 341 - #endif /* __ASSEMBLY__ */ 341 + #endif /* __ASSEMBLER__ */ 342 342 343 343 #endif
+2 -2
tools/arch/arm64/include/asm/esr.h
··· 385 385 #define ESR_ELx_MOPS_ISS_SRCREG(esr) (((esr) & (UL(0x1f) << 5)) >> 5) 386 386 #define ESR_ELx_MOPS_ISS_SIZEREG(esr) (((esr) & (UL(0x1f) << 0)) >> 0) 387 387 388 - #ifndef __ASSEMBLY__ 388 + #ifndef __ASSEMBLER__ 389 389 #include <asm/types.h> 390 390 391 391 static inline unsigned long esr_brk_comment(unsigned long esr) ··· 450 450 } 451 451 452 452 const char *esr_get_class_string(unsigned long esr); 453 - #endif /* __ASSEMBLY */ 453 + #endif /* __ASSEMBLER__ */ 454 454 455 455 #endif /* __ASM_ESR_H */
+3 -3
tools/arch/arm64/include/asm/gpr-num.h
··· 2 2 #ifndef __ASM_GPR_NUM_H 3 3 #define __ASM_GPR_NUM_H 4 4 5 - #ifdef __ASSEMBLY__ 5 + #ifdef __ASSEMBLER__ 6 6 7 7 .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 8 8 .equ .L__gpr_num_x\num, \num ··· 11 11 .equ .L__gpr_num_xzr, 31 12 12 .equ .L__gpr_num_wzr, 31 13 13 14 - #else /* __ASSEMBLY__ */ 14 + #else /* __ASSEMBLER__ */ 15 15 16 16 #define __DEFINE_ASM_GPR_NUMS \ 17 17 " .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" \ ··· 21 21 " .equ .L__gpr_num_xzr, 31\n" \ 22 22 " .equ .L__gpr_num_wzr, 31\n" 23 23 24 - #endif /* __ASSEMBLY__ */ 24 + #endif /* __ASSEMBLER__ */ 25 25 26 26 #endif /* __ASM_GPR_NUM_H */
+5 -5
tools/arch/arm64/include/asm/sysreg.h
··· 51 51 52 52 #ifndef CONFIG_BROKEN_GAS_INST 53 53 54 - #ifdef __ASSEMBLY__ 54 + #ifdef __ASSEMBLER__ 55 55 // The space separator is omitted so that __emit_inst(x) can be parsed as 56 56 // either an assembler directive or an assembler macro argument. 57 57 #define __emit_inst(x) .inst(x) ··· 70 70 (((x) >> 24) & 0x000000ff)) 71 71 #endif /* CONFIG_CPU_BIG_ENDIAN */ 72 72 73 - #ifdef __ASSEMBLY__ 73 + #ifdef __ASSEMBLER__ 74 74 #define __emit_inst(x) .long __INSTR_BSWAP(x) 75 - #else /* __ASSEMBLY__ */ 75 + #else /* __ASSEMBLER__ */ 76 76 #define __emit_inst(x) ".long " __stringify(__INSTR_BSWAP(x)) "\n\t" 77 - #endif /* __ASSEMBLY__ */ 77 + #endif /* __ASSEMBLER__ */ 78 78 79 79 #endif /* CONFIG_BROKEN_GAS_INST */ 80 80 ··· 1080 1080 1081 1081 #define ARM64_FEATURE_FIELD_BITS 4 1082 1082 1083 - #ifdef __ASSEMBLY__ 1083 + #ifdef __ASSEMBLER__ 1084 1084 1085 1085 .macro mrs_s, rt, sreg 1086 1086 __emit_inst(0xd5200000|(\sreg)|(.L__gpr_num_\rt))
+1 -1
tools/arch/arm64/include/uapi/asm/kvm.h
··· 31 31 #define KVM_SPSR_FIQ 4 32 32 #define KVM_NR_SPSR 5 33 33 34 - #ifndef __ASSEMBLY__ 34 + #ifndef __ASSEMBLER__ 35 35 #include <linux/psci.h> 36 36 #include <linux/types.h> 37 37 #include <asm/ptrace.h>
+1 -4
tools/testing/selftests/arm64/fp/fp-ptrace.c
··· 1071 1071 1072 1072 static bool sve_write_fpsimd_supported(struct test_config *config) 1073 1073 { 1074 - if (!sve_supported()) 1074 + if (!sve_supported() && !sme_supported()) 1075 1075 return false; 1076 1076 1077 1077 if ((config->svcr_in & SVCR_ZA) != (config->svcr_expected & SVCR_ZA)) ··· 1230 1230 1231 1231 vl = vl_expected(config); 1232 1232 vq = __sve_vq_from_vl(vl); 1233 - 1234 - if (!vl) 1235 - return; 1236 1233 1237 1234 iov.iov_len = SVE_PT_SIZE(vq, SVE_PT_REGS_FPSIMD); 1238 1235 iov.iov_base = malloc(iov.iov_len);
+61
tools/testing/selftests/arm64/fp/sve-ptrace.c
··· 394 394 free(svebuf); 395 395 } 396 396 397 + /* Write the FPSIMD registers via the SVE regset when SVE is not supported */ 398 + static void ptrace_sve_fpsimd_no_sve(pid_t child) 399 + { 400 + void *svebuf; 401 + struct user_sve_header *sve; 402 + struct user_fpsimd_state *fpsimd, new_fpsimd; 403 + unsigned int i, j; 404 + unsigned char *p; 405 + int ret; 406 + 407 + svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD)); 408 + if (!svebuf) { 409 + ksft_test_result_fail("Failed to allocate FPSIMD buffer\n"); 410 + return; 411 + } 412 + 413 + /* On a system without SVE the VL should be set to 0 */ 414 + memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD)); 415 + sve = svebuf; 416 + sve->flags = SVE_PT_REGS_FPSIMD; 417 + sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD); 418 + sve->vl = 0; 419 + 420 + /* Try to set a known FPSIMD state via PT_REGS_SVE */ 421 + fpsimd = (struct user_fpsimd_state *)((char *)sve + 422 + SVE_PT_FPSIMD_OFFSET); 423 + for (i = 0; i < 32; ++i) { 424 + p = (unsigned char *)&fpsimd->vregs[i]; 425 + 426 + for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j) 427 + p[j] = j; 428 + } 429 + 430 + ret = set_sve(child, &vec_types[0], sve); 431 + ksft_test_result(ret == 0, "FPSIMD write via SVE\n"); 432 + if (ret) { 433 + ksft_test_result_skip("Verify FPSIMD write via SVE\n"); 434 + goto out; 435 + } 436 + 437 + /* Verify via the FPSIMD regset */ 438 + if (get_fpsimd(child, &new_fpsimd)) { 439 + ksft_test_result_skip("Verify FPSIMD write via SVE\n"); 440 + goto out; 441 + } 442 + ksft_test_result(memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0, 443 + "Verify FPSIMD write via SVE\n"); 444 + 445 + out: 446 + free(svebuf); 447 + } 448 + 397 449 /* Validate attempting to set SVE data and read SVE data */ 398 450 static void ptrace_set_sve_get_sve_data(pid_t child, 399 451 const struct vec_type *type, ··· 876 824 vec_types[i].name, vl); 877 825 } 878 826 } 827 + } 828 + 829 + /* We support SVE writes of FPSMID format on SME only systems */ 830 + if (!(getauxval(AT_HWCAP) & HWCAP_SVE) && 831 + (getauxval(AT_HWCAP2) & HWCAP2_SME)) { 832 + ptrace_sve_fpsimd_no_sve(child); 833 + } else { 834 + ksft_test_result_skip("FPSIMD write via SVE\n"); 835 + ksft_test_result_skip("Verify FPSIMD write via SVE\n"); 879 836 } 880 837 881 838 ret = EXIT_SUCCESS;
+1 -1
tools/testing/selftests/arm64/fp/zt-test.S
··· 276 276 bl putdec 277 277 puts ", iteration=" 278 278 mov x0, x22 279 - bl putdec 279 + bl putdecn 280 280 puts "\tExpected [" 281 281 mov x0, x10 282 282 mov x1, x12