[PATCH OLK-6.6 0/4] arm64: smt: Introduce VIP-SMT QoS mode for SMT
This patchset introduces VIP-SMT, an Hisilicon-specific SMT QoS enhancement for Arm64. It allows marking specific hardware threads as "VIP" (high-priority) and others as non-VIP within the same physical core, enabling differentiated resource allocation (instruction fetch, execution pipeline, and out-of-order resources) for latency-sensitive workloads while background tasks run on non-VIP threads. Use cases include running real-time/network packet processing on VIP threads, performance isolation for mixed-criticality tasks, and QoS enforcement for cloud/virtualization scenarios. The series is organized as follows: Patch 1 refactors arch_cpu_idle_{enter,exit}() so the SMT measurement and the VIP-SMT hooks can be shared cleanly across all configs; the ACTLR_XCALL_XINT register save/restore is moved under its own config guard. Patch 2 is the core feature. It adds CONFIG_ARM64_VIP_SMT and a new vip_smt.c driver exposing per-CPU sysfs entries under /sys/devices/system/cpu/cpuN/regs/vip-smt/ to configure three ACTLR system registers (IFU_ACTLR1_EL1, OOO_DEC_ROB_SHA_CTLR_EL1, and OOO_DEC_DSP_CTLR_EL1). Feature detection is based on MIDR (HIP13), restricted to EL2 at the moment, and requires SMT to be enabled on the physical core. Per-CPU register values are shadowed and restored on idle exit so they survive core power-down. Patch 3 adds a "novipsmt" kernel command line parameter (with an optional "force" value) that disables the feature at boot time and prevents the vip_smt sysfs directory from being created. Yipeng Zou (4): arm64: idle: make arch_cpu_idle_{enter,exit} more refactorable arm64: smt: Introduce VIP-SMT a QoS Mode for SMT arm64: smt: Add novipsmt kernel command line parameter arm64: configs: Enable ARM64_VIP_SMT in openeuler_defconfig .../admin-guide/kernel-parameters.txt | 4 + arch/arm64/Kconfig | 16 + arch/arm64/configs/openeuler_defconfig | 1 + arch/arm64/include/asm/vip_smt.h | 109 ++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/cpufeature.c | 9 + arch/arm64/kernel/cpuinfo.c | 7 + arch/arm64/kernel/idle.c | 51 +- arch/arm64/kernel/vip_smt.c | 483 ++++++++++++++++++ arch/arm64/tools/cpucaps | 2 +- 10 files changed, 653 insertions(+), 30 deletions(-) create mode 100644 arch/arm64/include/asm/vip_smt.h create mode 100644 arch/arm64/kernel/vip_smt.c -- 2.34.1
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/10013 ---------------------------------------------- arch_cpu_idle_{enter,exit} is common code for all modules. Patch their own code to make it more refactorable. Signed-off-by: Yipeng Zou <zouyipeng@huawei.com> Reviewed-by: Liao Chang <liaochang1@huawei.com> --- arch/arm64/kernel/idle.c | 48 ++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c index 31d9bfbe10b8..a986bab39eb4 100644 --- a/arch/arm64/kernel/idle.c +++ b/arch/arm64/kernel/idle.c @@ -72,46 +72,36 @@ struct arm_cpuidle_xcall_xint_context { }; DEFINE_PER_CPU_ALIGNED(struct arm_cpuidle_xcall_xint_context, contexts); +#endif void arch_cpu_idle_enter(void) { +#ifdef CONFIG_ACTLR_XCALL_XINT struct arm_cpuidle_xcall_xint_context *context; + if (system_uses_xcall_xint()) { + context = &get_cpu_var(contexts); + context->actlr_el1 = read_sysreg(actlr_el1); + if (read_sysreg(CurrentEL) == CurrentEL_EL2) + context->actlr_el2 = read_sysreg(actlr_el2); + put_cpu_var(contexts); + } +#endif smt_measurement_begin(); - - if (!system_uses_xcall_xint()) - return; - - context = &get_cpu_var(contexts); - context->actlr_el1 = read_sysreg(actlr_el1); - if (read_sysreg(CurrentEL) == CurrentEL_EL2) - context->actlr_el2 = read_sysreg(actlr_el2); - put_cpu_var(contexts); } void arch_cpu_idle_exit(void) { +#ifdef CONFIG_ACTLR_XCALL_XINT struct arm_cpuidle_xcall_xint_context *context; - smt_measurement_done(); - - if (!system_uses_xcall_xint()) - return; - - context = &get_cpu_var(contexts); - write_sysreg(context->actlr_el1, actlr_el1); - if (read_sysreg(CurrentEL) == CurrentEL_EL2) - write_sysreg(context->actlr_el2, actlr_el2); - put_cpu_var(contexts); -} -#else -void arch_cpu_idle_enter(void) -{ - smt_measurement_begin(); -} - -void arch_cpu_idle_exit(void) -{ + if (system_uses_xcall_xint()) { + context = &get_cpu_var(contexts); + write_sysreg(context->actlr_el1, actlr_el1); + if (read_sysreg(CurrentEL) == CurrentEL_EL2) + write_sysreg(context->actlr_el2, actlr_el2); + put_cpu_var(contexts); + } +#endif smt_measurement_done(); } -#endif -- 2.34.1
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/10013 ---------------------------------------------- VIP-SMT is an Hisilicon-specific feature that enables per-core QoS control for SMT workloads. It allows marking specific hardware threads as "VIP" (high-priority) while others remain as non-VIP, enabling differentiated resource allocation within the same physical core. Use Cases: - Running latency-sensitive workloads (e.g., real-time applications, network packet processing) on VIP threads while background tasks run on non-VIP threads - Performance isolation for mixed-criticality workloads on the same core - QoS enforcement for cloud/virtualization scenarios where VIP threads receive priority in instruction fetch, execution pipeline, and out-of-order resources. Usage: - Enable via kernel config: CONFIG_ARM64_VIP_SMT=y - sysfs interface at /sys/devices/system/cpu/cpuN/regs/vip_smt/: - Register format: "ifu_ooo_dsp" (hex values) Implementation: - Three ARM64 system registers control VIP-SMT QoS: * IFU_ACTLR1_EL1: Instruction Fetch Unit control * OOO_DEC_ROB_SHA_CTLR_EL1: Out-of-Order Decoder ROQ/Shaper control * OOO_DEC_DSP_CTLR_EL1: Out-of-Order Dispatch control - CPU hotplug callbacks create/remove sysfs entries dynamically - SMP cross-call used for register access on target CPUs Signed-off-by: Yipeng Zou <zouyipeng@huawei.com> Reviewed-by: Liao Chang <liaochang1@huawei.com> --- arch/arm64/Kconfig | 16 ++ arch/arm64/include/asm/vip_smt.h | 109 ++++++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/cpufeature.c | 9 + arch/arm64/kernel/cpuinfo.c | 7 + arch/arm64/kernel/idle.c | 3 + arch/arm64/kernel/vip_smt.c | 447 +++++++++++++++++++++++++++++++ arch/arm64/tools/cpucaps | 2 +- 8 files changed, 593 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/vip_smt.h create mode 100644 arch/arm64/kernel/vip_smt.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 736908afc98a..69df3e287473 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2323,6 +2323,22 @@ config ARM64_MPAM MPAM is exposed to user-space via the resctrl pseudo filesystem. +config ARM64_VIP_SMT + bool "Enable support for VIP-SMT" + default y + depends on ARM64 && SMP && ARCH_HISI + help + VIP-SMT is an ARM64 SMT enhancement feature that allows + configuring VIP (high-priority) threads and non-VIP threads + within the same physical core. It uses hardware registers + to control thread priority and resource allocation. + + This feature requires hardware support for SMT QoS mode. + When enabled, sysfs interfaces are created under + /sys/devices/system/cpu/regs/vip-smt to configure VIP-SMT settings. + + Say N if you want to disable this feature. + endmenu menu "ARMv8.5 architectural features" diff --git a/arch/arm64/include/asm/vip_smt.h b/arch/arm64/include/asm/vip_smt.h new file mode 100644 index 000000000000..0ec1f46dbfdb --- /dev/null +++ b/arch/arm64/include/asm/vip_smt.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * VIP-SMT support for ARM64 + * + * Copyright (C) 2026 Huawei Technologies Co., Ltd. + */ + +#ifndef __ASM_VIP_SMT_H +#define __ASM_VIP_SMT_H + +#include <linux/types.h> +#include <linux/cpumask.h> +#include <asm/cpu.h> + +#ifdef CONFIG_ARM64_VIP_SMT + +/* + * VIP-SMT Register encodings + * Format: sys_reg(Op0, Op1, CRn, CRm, Op2) + */ +#define sys_ifu_actlr1 sys_reg(3, 1, 15, 4, 0) +#define sys_ooo_dec_rob_sha_ctlr sys_reg(3, 1, 15, 8, 6) +#define sys_ooo_dec_dsp_ctlr sys_reg(3, 1, 15, 2, 5) + +/* + * IFU_ACTLR1_EL1 bit definitions (only defined bits can be accessed) + */ +#define IFU_ACTLR1_IMPL_SMT_QOS_SCH1_EN (UL(0x1) << (63)) +#define IFU_ACTLR1_IMPL_SMT_QOS_SCH1_THR_SHIFT (59) +#define IFU_ACTLR1_IMPL_SMT_QOS_SCH1_THR_MASK GENMASK_ULL(62, 59) +#define IFU_ACTLR1_IMPL_SMT_QOS_SCH2_EN (UL(0x1) << (58)) +#define IFU_ACTLR1_IMPL_SMT_QOS_SCH2_PLUS_EN (UL(0x1) << (57)) +#define IFU_ACTLR1_IMPL_SMT_QOS_SCH2_THR_SHIFT (49) +#define IFU_ACTLR1_IMPL_SMT_QOS_SCH2_THR_MASK GENMASK_ULL(56, 49) +#define IFU_ACTLR1_IMPL_SMT_QOS_SCH2_TWICE_EN (UL(0x1) << (48)) +#define ifu_actlr1_allow_mask (IFU_ACTLR1_IMPL_SMT_QOS_SCH1_EN | \ + IFU_ACTLR1_IMPL_SMT_QOS_SCH1_THR_MASK |\ + IFU_ACTLR1_IMPL_SMT_QOS_SCH2_EN | \ + IFU_ACTLR1_IMPL_SMT_QOS_SCH2_PLUS_EN | \ + IFU_ACTLR1_IMPL_SMT_QOS_SCH2_THR_MASK |\ + IFU_ACTLR1_IMPL_SMT_QOS_SCH2_TWICE_EN) + +/* + * OOO_DEC_ROB_SHA_CTLR_EL1 bit definitions + */ +#define OOO_DEC_ROB_SHA_CTLR_OOO_DEC_SMT_QOS_TSLOT_EN (UL(0x1) << (59)) +#define OOO_DEC_ROB_SHA_CTLR_OOO_ROB_STARVE_QOS_THRED_SHIFT (57) +#define OOO_DEC_ROB_SHA_CTLR_OOO_ROB_STARVE_QOS_THRED_MASK GENMASK_ULL(58, 57) +#define OOO_DEC_ROB_SHA_CTLR_OOO_ROB_STARVE_QOS_SAFE_MODE (UL(0x1) << (56)) +#define OOO_DEC_ROB_SHA_CTLR_OOO_DEV_QOS_MODEL_SEL (UL(0x1) << (55)) +#define OOO_DEC_ROB_SHA_CTLR_OOO_FRC_IFU_THREAD_RR (UL(0x1) << (50)) +#define ooo_dec_rob_sha_ctlr_allow_mask (OOO_DEC_ROB_SHA_CTLR_OOO_DEC_SMT_QOS_TSLOT_EN | \ + OOO_DEC_ROB_SHA_CTLR_OOO_ROB_STARVE_QOS_THRED_MASK | \ + OOO_DEC_ROB_SHA_CTLR_OOO_ROB_STARVE_QOS_SAFE_MODE | \ + OOO_DEC_ROB_SHA_CTLR_OOO_DEV_QOS_MODEL_SEL | \ + OOO_DEC_ROB_SHA_CTLR_OOO_FRC_IFU_THREAD_RR) + +/* + * OOO_DEC_DSP_CTLR_EL1 bit definitions + */ +#define OOO_DEC_DSP_CTLR_OOO_DSP_THRESHOLD (UL(0x1) << (63)) +#define OOO_DEC_DSP_CTLR_OOO_ISSQ_THRESHOLD_ISU_SHIFT (49) +#define OOO_DEC_DSP_CTLR_OOO_ISSQ_THRESHOLD_ISU_MASK GENMASK_ULL(51, 49) +#define OOO_DEC_DSP_CTLR_OOO_ISSQ_THRESHOLD_ALU_SHIFT (46) +#define OOO_DEC_DSP_CTLR_OOO_ISSQ_THRESHOLD_ALU_MASK GENMASK_ULL(48, 46) +#define OOO_DEC_DSP_CTLR_OOO_SMT_QOS_EN (UL(0x1) << (37)) +#define OOO_DEC_DSP_CTLR_OOO_DEC_THREAD_CYCLE_FRC_SHIFT (32) +#define OOO_DEC_DSP_CTLR_OOO_DEC_THREAD_CYCLE_FRC_MASK GENMASK_ULL(33, 32) +#define OOO_DEC_DSP_CTLR_OOO_DEC_ICOUNT_CFG_SHIFT (30) +#define OOO_DEC_DSP_CTLR_OOO_DEC_ICOUNT_CFG_MASK GENMASK_ULL(31, 30) +#define ooo_dec_dsp_ctlr_allow_mask (OOO_DEC_DSP_CTLR_OOO_DSP_THRESHOLD | \ + OOO_DEC_DSP_CTLR_OOO_ISSQ_THRESHOLD_ISU_MASK | \ + OOO_DEC_DSP_CTLR_OOO_ISSQ_THRESHOLD_ALU_MASK | \ + OOO_DEC_DSP_CTLR_OOO_SMT_QOS_EN | \ + OOO_DEC_DSP_CTLR_OOO_DEC_THREAD_CYCLE_FRC_MASK | \ + OOO_DEC_DSP_CTLR_OOO_DEC_ICOUNT_CFG_MASK) + +/* + * Field definition for sysfs interface + * Used to parse FIELD_NAME=value format input + */ +struct vip_smt_field { + const char *name; /* Field name, e.g., "SCH1_EN" */ + u64 bitmask; /* Corresponding bitmask */ +}; + +/* + * VIP-SMT control states + */ +enum vip_smt_control { + VIP_SMT_ENABLED, + VIP_SMT_DISABLED, + VIP_SMT_FORCE_DISABLED, +}; + +/* + * API functions + */ +bool vip_smt_available(void); +int vip_smt_cpu_sysfs_create(unsigned int cpu, struct cpuinfo_arm64 *info); +bool has_vip_smt_support(const struct arm64_cpu_capabilities *entry, int __unused); +void vip_smt_enter_idle(void); +void vip_smt_exit_idle(void); +#else +static inline void vip_smt_enter_idle(void) { } +static inline void vip_smt_exit_idle(void) { } +#endif /* CONFIG_ARM64_VIP_SMT */ + +#endif /* __ASM_VIP_SMT_H */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 245b77f1636d..daa48c192ea1 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_HISI_VIRTCCA_HOST) += virtcca_cvm_host.o CFLAGS_patch-scs.o += -mbranch-protection=none obj-$(CONFIG_SCHED_PARAL) += prefer_numa.o obj-$(CONFIG_BPF_RVI) += bpf-rvi.o +obj-$(CONFIG_ARM64_VIP_SMT) += vip_smt.o # Force dependency (vdso*-wrap.S includes vdso.so through incbin) $(obj)/vdso-wrap.o: $(obj)/vdso/vdso.so diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 87e43294c6a8..3e0e7f04d319 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -95,6 +95,7 @@ #include <asm/traps.h> #include <asm/vectors.h> #include <asm/virt.h> +#include <asm/vip_smt.h> /* Kernel representation of AT_HWCAP and AT_HWCAP2 */ static DECLARE_BITMAP(elf_hwcap, MAX_CPU_FEATURES) __read_mostly; @@ -3279,6 +3280,14 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .cpu_enable = cpu_enable_fpmr, ARM64_CPUID_FIELDS(ID_AA64PFR2_EL1, FPMR, IMP) }, +#ifdef CONFIG_ARM64_VIP_SMT + { + .desc = "VIP-SMT", + .capability = ARM64_HAS_VIP_SMT, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_vip_smt_support, + }, +#endif {}, }; diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index fe1b511464c2..492cbb4ff874 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -10,6 +10,7 @@ #include <asm/cputype.h> #include <asm/cpufeature.h> #include <asm/fpsimd.h> +#include <asm/vip_smt.h> #include <linux/bitops.h> #include <linux/bug.h> @@ -208,6 +209,12 @@ static int cpuid_cpu_online(unsigned int cpu) rc = kobject_add(&info->kobj, &dev->kobj, "regs"); if (rc) goto out; + +#ifdef CONFIG_ARM64_VIP_SMT + /* Add sysfs attribute group */ + vip_smt_cpu_sysfs_create(cpu, info); +#endif + rc = sysfs_create_group(&info->kobj, &cpuregs_attr_group); if (rc) kobject_del(&info->kobj); diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c index a986bab39eb4..4cd55d32b048 100644 --- a/arch/arm64/kernel/idle.c +++ b/arch/arm64/kernel/idle.c @@ -10,6 +10,7 @@ #include <asm/cpuidle.h> #include <asm/cpufeature.h> #include <asm/sysreg.h> +#include <asm/vip_smt.h> /* * cpu_do_idle() @@ -88,6 +89,7 @@ void arch_cpu_idle_enter(void) } #endif smt_measurement_begin(); + vip_smt_enter_idle(); } void arch_cpu_idle_exit(void) @@ -104,4 +106,5 @@ void arch_cpu_idle_exit(void) } #endif smt_measurement_done(); + vip_smt_exit_idle(); } diff --git a/arch/arm64/kernel/vip_smt.c b/arch/arm64/kernel/vip_smt.c new file mode 100644 index 000000000000..c3823a674cfe --- /dev/null +++ b/arch/arm64/kernel/vip_smt.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VIP-SMT support for ARM64 + * + * Copyright (C) 2026 Huawei Technologies Co., Ltd. + */ + +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/node.h> +#include <linux/percpu-defs.h> +#include <linux/smp.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/topology.h> +#include <asm/cpu.h> +#include <asm/cputype.h> +#include <asm/smp.h> +#include <asm/sysreg.h> +#include <asm/vip_smt.h> + +/* ============================================================================ + * Global Variables + * ============================================================================ + */ + +/* VIP-SMT control state */ +static enum vip_smt_control vip_smt_control = VIP_SMT_ENABLED; + +static DEFINE_PER_CPU(u64, vip_smt_ifu_actlr1); +static DEFINE_PER_CPU(u64, vip_smt_ooo_dec_rob_sha_ctlr); +static DEFINE_PER_CPU(u64, vip_smt_ooo_dec_dsp_ctlr); +static DEFINE_PER_CPU(u64, vip_smt_is_init); + +/* ======================================================================== + * Field Definition Arrays + * ======================================================================== + */ + +/* IFU_ACTLR1 fields */ +static const struct vip_smt_field ifu_actlr1_fields[] = { + { "SCH1_EN", IFU_ACTLR1_IMPL_SMT_QOS_SCH1_EN }, + { "SCH1_THR", IFU_ACTLR1_IMPL_SMT_QOS_SCH1_THR_MASK }, + { "SCH2_EN", IFU_ACTLR1_IMPL_SMT_QOS_SCH2_EN }, + { "SCH2_PLUS_EN", IFU_ACTLR1_IMPL_SMT_QOS_SCH2_PLUS_EN }, + { "SCH2_THR", IFU_ACTLR1_IMPL_SMT_QOS_SCH2_THR_MASK }, + { "SCH2_TWICE_EN", IFU_ACTLR1_IMPL_SMT_QOS_SCH2_TWICE_EN }, +}; + +/* OOO_DEC_ROB_SHA_CTLR fields */ +static const struct vip_smt_field ooo_dec_rob_sha_ctlr_fields[] = { + { "TSLOT_EN", OOO_DEC_ROB_SHA_CTLR_OOO_DEC_SMT_QOS_TSLOT_EN }, + { "STARVE_QOS_THRED", OOO_DEC_ROB_SHA_CTLR_OOO_ROB_STARVE_QOS_THRED_MASK }, + { "SAFE_MODE", OOO_DEC_ROB_SHA_CTLR_OOO_ROB_STARVE_QOS_SAFE_MODE }, + { "DEV_QOS_MODEL_SEL", OOO_DEC_ROB_SHA_CTLR_OOO_DEV_QOS_MODEL_SEL }, + { "FRC_IFU_THREAD_RR", OOO_DEC_ROB_SHA_CTLR_OOO_FRC_IFU_THREAD_RR }, +}; + +/* OOO_DEC_DSP_CTLR fields */ +static const struct vip_smt_field ooo_dec_dsp_ctlr_fields[] = { + { "DSP_THRESHOLD", OOO_DEC_DSP_CTLR_OOO_DSP_THRESHOLD }, + { "ISSQ_THRESHOLD_ISU", OOO_DEC_DSP_CTLR_OOO_ISSQ_THRESHOLD_ISU_MASK }, + { "ISSQ_THRESHOLD_ALU", OOO_DEC_DSP_CTLR_OOO_ISSQ_THRESHOLD_ALU_MASK }, + { "SMT_QOS_EN", OOO_DEC_DSP_CTLR_OOO_SMT_QOS_EN }, + { "THREAD_CYCLE_FRC", OOO_DEC_DSP_CTLR_OOO_DEC_THREAD_CYCLE_FRC_MASK }, + { "ICOUNT_CFG", OOO_DEC_DSP_CTLR_OOO_DEC_ICOUNT_CFG_MASK }, +}; + +/* ======================================================================== + * Helper Functions + * ======================================================================== + */ + +/** + * vip_smt_core_has_smt - Check if physical core supports SMT + * @cpu: Logical CPU number + * + * Returns: true if SMT is supported + */ +static bool vip_smt_core_has_smt(int cpu) +{ + if (!cpu_smt_possible()) + return false; + + return topology_core_has_smt(cpu); +} + +/** + * vip_smt_parse_field_name - Parse FIELD_NAME=value format input + * @buf: Input buffer containing the string + * @count: Buffer size + * @fields: Field definition array + * @num_fields: Number of fields in array + * @out_value: Output value to write (will be shifted to correct bit position) + * @out_mask: Output mask for the field + * + * Returns: 0 on success, -EINVAL on failure + * + * Parse format: FIELD_NAME=value + * Example: "SCH1_EN=1" or "SCH1_THR=7" + */ +static int vip_smt_parse_field_name(const char *buf, size_t count, + const struct vip_smt_field *fields, + int num_fields, + u64 *out_value, u64 *out_mask) +{ + char *kbuf; + char *name, *value_str; + u64 value; + int i; + int ret = -EINVAL; + + /* Make a null-terminated copy */ + kbuf = kstrndup(buf, count, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + /* Remove trailing newline */ + strim(kbuf); + + /* Find the '=' separator */ + value_str = strchr(kbuf, '='); + if (!value_str) + goto out; + + *value_str = '\0'; + value_str++; + + /* Parse the value */ + if (kstrtoull(value_str, 0, &value) < 0) + goto out; + + /* Find matching field by name */ + name = kbuf; + for (i = 0; i < num_fields; i++) { + if (strcmp(name, fields[i].name) == 0) + break; + } + + if (i >= num_fields) + goto out; + + u64 mask = fields[i].bitmask; + int shift = __ffs(mask); + + /* Validate value fits in the field width */ + if (value > mask >> shift) { + pr_err("VIP-SMT: value 0x%llx exceeds field width for %s\n", + value, name); + goto out; + } + + *out_value = value << shift; + *out_mask = mask; + ret = 0; + +out: + kfree(kbuf); + return ret; +} + +/** + * vip_smt_find_base_cpu - Find the base CPU for a physical core + * @cpu: Any CPU in the physical core + * + * For a 2-SMT-thread physical core, the "base CPU" (even CPU with sibling + * index 0) is designated as the single authority for managing shared register + * state and performing restore operations. This prevents concurrent writes + * to the same physical register from multiple SMT threads. + * + * For single-thread cores, returns the CPU itself. + * + * Returns: The base CPU number for the physical core + */ +static int vip_smt_find_base_cpu(int cpu, u64 mask) +{ + const struct cpumask *siblings = topology_sibling_cpumask(cpu); + int first_cpu = cpumask_first(siblings); + + if (mask != ooo_dec_rob_sha_ctlr_allow_mask) + return cpu; + + return first_cpu; +} + +/* ============================================================================ + * Register Access Functions (executed on target CPU) + * ============================================================================ + */ + +/** + * Parameters for register read/write operations + */ +struct vip_smt_reg_data { + u64 val; + int cpu; + u64 mask; +}; + +/* ============================================================================ + * VIP-SMT API Functions + * ============================================================================ + */ + +/** + * vip_smt_available - Check if VIP-SMT is supported on current system + * + * Returns: true if VIP-SMT is available + */ +bool vip_smt_available(void) +{ + return cpus_have_cap(ARM64_HAS_VIP_SMT); +} +EXPORT_SYMBOL_GPL(vip_smt_available); + +/* ============================================================================ + * sysfs Interface Implementation + * ============================================================================ + */ + +/** + * vip_smt_get_cpu - Get CPU number from sysfs attribute + * @dev: device structure + * + * Returns: CPU number + */ +static int vip_smt_get_cpu(struct kobject *kobj) +{ + struct cpuinfo_arm64 *info; + int cpu = nr_cpu_ids; + int index; + + info = container_of(kobj, struct cpuinfo_arm64, kobj); + for_each_possible_cpu(index) { + if (info == &per_cpu(cpu_data, index)) { + cpu = index; + break; + } + } + return cpu; +} + +#define VIPSMT_SYS_FUNC(_name) \ + static long __vip_smt_read_raw_##_name(void *val) \ + { \ + u64 *ret = val; \ + if (!ret) \ + return 0; \ + *ret = read_sysreg_s(sys_##_name); \ + return 0; \ + } \ + static void __vip_smt_read_##_name(void *info) \ + { \ + struct vip_smt_reg_data *data = info; \ + work_on_cpu(data->cpu, __vip_smt_read_raw_##_name, &(data->val)); \ + } \ + static void __vip_smt_write_##_name(void *info) \ + { \ + struct vip_smt_reg_data *data = info; \ + u64 mask = data->mask; \ + u64 reg; \ + unsigned long flags; \ + local_irq_save(flags); \ + reg = __this_cpu_read(vip_smt_##_name); \ + reg = (reg & ~mask) | (data->val & mask); \ + write_sysreg_s(reg, sys_##_name); \ + __this_cpu_write(vip_smt_##_name, reg); \ + local_irq_restore(flags); \ + } + +#define VIPSMT_ATTR_RW(_name, _fields, _num_fields) \ + VIPSMT_SYS_FUNC(_name) \ + static u64 vip_smt_read_##_name(int cpu) \ + { \ + struct vip_smt_reg_data data = { .cpu = cpu, .val = 0 }; \ + __vip_smt_read_##_name(&data); \ + return data.val; \ + } \ + static void vip_smt_write_##_name(int cpu, u64 val, u64 maskval, u64 regmask) \ + { \ + struct vip_smt_reg_data data = { .cpu = cpu, .val = val, .mask = maskval }; \ + smp_call_function_single(vip_smt_find_base_cpu(cpu, regmask), \ + __vip_smt_write_##_name, &data, true); \ + } \ + static ssize_t _name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ + { \ + int cpu = vip_smt_get_cpu(kobj); \ + u64 reg; \ + ssize_t len = 0; \ + int i; \ + if (cpu < 0 || cpu >= nr_cpu_ids) \ + return -EINVAL; \ + if (!vip_smt_available() || !vip_smt_core_has_smt(cpu)) \ + return -ENODEV; \ + reg = vip_smt_read_##_name(cpu); \ + /* Output original register value */ \ + len += snprintf(buf + len, 64, #_name":0x%016llx(0x%016llx)\n", \ + reg, _name##_allow_mask); \ + /* Output field names and values */ \ + for (i = 0; i < _num_fields; i++) { \ + u64 mask = _fields[i].bitmask; \ + u64 value; \ + int shift = __ffs(mask); \ + int width = __fls(mask) - shift + 1; \ + value = (reg & mask) >> shift; \ + if (width == 1) \ + len += snprintf(buf + len, 64, "%s(bit %d)=0x%llx\n", \ + _fields[i].name, shift, value); \ + else \ + len += snprintf(buf + len, 64, "%s(bit %d-%d)=0x%llx\n", \ + _fields[i].name, shift + width - 1, shift, value); \ + } \ + len += snprintf(buf + len, 2, "\n"); \ + return len; \ + } \ + static ssize_t _name##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + const char *buf, \ + size_t count) \ + { \ + int cpu = vip_smt_get_cpu(kobj); \ + u64 reg = 0; \ + u64 mask = _name##_allow_mask; \ + int ret; \ + if (cpu < 0 || cpu >= nr_cpu_ids) \ + return -EINVAL; \ + if (!vip_smt_available() || !vip_smt_core_has_smt(cpu)) \ + return -ENODEV; \ + /* Try to parse FIELD_NAME=value format first */ \ + ret = vip_smt_parse_field_name(buf, count, _fields, _num_fields, \ + ®, &mask); \ + if (ret != 0) \ + return -EINVAL; \ + vip_smt_write_##_name(cpu, reg, mask, _name##_allow_mask); \ + return count; \ + } \ + static struct kobj_attribute cpuregs_attr_##_name = __ATTR_RW(_name) + +VIPSMT_ATTR_RW(ifu_actlr1, ifu_actlr1_fields, ARRAY_SIZE(ifu_actlr1_fields)); +VIPSMT_ATTR_RW(ooo_dec_rob_sha_ctlr, ooo_dec_rob_sha_ctlr_fields, + ARRAY_SIZE(ooo_dec_rob_sha_ctlr_fields)); +VIPSMT_ATTR_RW(ooo_dec_dsp_ctlr, ooo_dec_dsp_ctlr_fields, + ARRAY_SIZE(ooo_dec_dsp_ctlr_fields)); + +static struct attribute *vip_smt_attrs[] = { + &cpuregs_attr_ifu_actlr1.attr, + &cpuregs_attr_ooo_dec_rob_sha_ctlr.attr, + &cpuregs_attr_ooo_dec_dsp_ctlr.attr, + NULL +}; + +static const struct attribute_group vip_smt_attr_group = { + .attrs = vip_smt_attrs, + .name = "vip-smt" +}; + +int vip_smt_cpu_sysfs_create(unsigned int cpu, struct cpuinfo_arm64 *info) +{ + if (!vip_smt_core_has_smt(cpu)) + return -1; + + if (!cpus_have_cap(ARM64_HAS_VIP_SMT)) + return -1; + + /* Store register which maybe clear after core powerdown(LPI) */ + __this_cpu_write(vip_smt_ifu_actlr1, + read_sysreg_s(sys_ifu_actlr1)); + __this_cpu_write(vip_smt_ooo_dec_rob_sha_ctlr, + read_sysreg_s(sys_ooo_dec_rob_sha_ctlr)); + __this_cpu_write(vip_smt_ooo_dec_dsp_ctlr, + read_sysreg_s(sys_ooo_dec_dsp_ctlr)); + __this_cpu_write(vip_smt_is_init, 1); + return sysfs_create_group(&info->kobj, &vip_smt_attr_group); +} + +void vip_smt_enter_idle(void) +{ + /* No need Store value here */ +} + +static void restore_shared_register(void *info) +{ + unsigned long flags; + u64 reg; + + local_irq_save(flags); + reg = __this_cpu_read(vip_smt_ooo_dec_rob_sha_ctlr); + write_sysreg_s(reg, sys_ooo_dec_rob_sha_ctlr); + local_irq_restore(flags); +} + +void vip_smt_exit_idle(void) +{ + if (!vip_smt_available() || !vip_smt_core_has_smt(smp_processor_id())) + return; + + if (__this_cpu_read(vip_smt_is_init)) { + /* There is no need restore for shared register */ + write_sysreg_s(__this_cpu_read(vip_smt_ifu_actlr1), sys_ifu_actlr1); + write_sysreg_s(__this_cpu_read(vip_smt_ooo_dec_dsp_ctlr), sys_ooo_dec_dsp_ctlr); + /* For Shared register we need always restore base cpu value */ + smp_call_function_single(vip_smt_find_base_cpu(smp_processor_id(), + ooo_dec_rob_sha_ctlr_allow_mask), + restore_shared_register, NULL, true); + } +} + +/** + * vip_smt_probe - Detect hardware support for VIP-SMT + * + * Determine by MIDR. + */ +static bool vip_smt_probe(void) +{ + /* List of CPUs that support VIP-SMT */ + static const struct midr_range hip13_cpus[] = { + MIDR_ALL_VERSIONS(MIDR_HISI_HIP13), + { /* sentinel */ } + }; + + if (is_midr_in_range_list(hip13_cpus)) + return true; + + return false; +} + +bool has_vip_smt_support(const struct arm64_cpu_capabilities *entry, int __unused) +{ + /* Only can access from el2 for now!, configure in el3. */ + if (!is_kernel_in_hyp_mode()) { + pr_info("VIP-SMT: Only support in EL2 for now.\n"); + return false; + } + + /* Check if current CPU has SMT enabled */ + if (!vip_smt_core_has_smt(smp_processor_id())) { + pr_info("VIP-SMT: SMT not enabled on CPU%d\n", smp_processor_id()); + return false; + } + + return vip_smt_probe(); +} diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index 36888f479f78..82ce2389f7a2 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -108,6 +108,7 @@ WORKAROUND_SPECULATIVE_UNPRIV_LOAD WORKAROUND_HISILICON_ERRATUM_162100125 WORKAROUND_HISI_HIP08_RU_PREFETCH WORKAROUND_HISILICON_1980005 +HAS_VIP_SMT HAS_XCALL HAS_XINT HAS_LS64 @@ -117,7 +118,6 @@ WORKAROUND_PHYTIUM_FT3386 HAS_COPY_OPT HAS_LSUI HAS_FPMR -KABI_RESERVE_10 KABI_RESERVE_11 KABI_RESERVE_12 KABI_RESERVE_13 -- 2.34.1
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/10013 ---------------------------------------------- Add a kernel command line parameter "novipsmt" to disable VIP-SMT sysfs interface at boot time. When novipsmt is specified, the vip_smt directory will not be created under/sys/devices/system/cpu/cpuX/regs/. This allows users to disable VIP-SMT functionality if needed. Usage: - Disable via boot param: novipsmt or novipsmt=force Signed-off-by: Yipeng Zou <zouyipeng@huawei.com> Reviewed-by: Liao Chang <liaochang1@huawei.com> --- .../admin-guide/kernel-parameters.txt | 4 ++ arch/arm64/kernel/vip_smt.c | 38 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index cbc2064a8d80..9e52f393b679 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3998,6 +3998,10 @@ nosmt=force: Force disable SMT, cannot be undone via the sysfs control file. + novipsmt [ARM64] Disable VIP-SMT sysfs interface at boot. + When specified, vip_smt directory will not be created + under /sys/devices/system/cpu/cpuX/regs/. + nosoftlockup [KNL] Disable the soft-lockup detector. nospec_store_bypass_disable diff --git a/arch/arm64/kernel/vip_smt.c b/arch/arm64/kernel/vip_smt.c index c3823a674cfe..ff9b1675aa83 100644 --- a/arch/arm64/kernel/vip_smt.c +++ b/arch/arm64/kernel/vip_smt.c @@ -213,7 +213,7 @@ struct vip_smt_reg_data { */ bool vip_smt_available(void) { - return cpus_have_cap(ARM64_HAS_VIP_SMT); + return (vip_smt_control == VIP_SMT_ENABLED) && cpus_have_cap(ARM64_HAS_VIP_SMT); } EXPORT_SYMBOL_GPL(vip_smt_available); @@ -361,6 +361,9 @@ static const struct attribute_group vip_smt_attr_group = { int vip_smt_cpu_sysfs_create(unsigned int cpu, struct cpuinfo_arm64 *info) { + if (vip_smt_control != VIP_SMT_ENABLED) + return -1; + if (!vip_smt_core_has_smt(cpu)) return -1; @@ -410,6 +413,33 @@ void vip_smt_exit_idle(void) } } +/** + * vip_smt_disable - Disable VIP-SMT feature + * @state: Disable state ("force" means force disable) + */ +static void __init vip_smt_disable(char *state) +{ + if (!state) { + vip_smt_control = VIP_SMT_DISABLED; + pr_info("VIP-SMT: Disabled via cmdline\n"); + } else if (strcmp(state, "force") == 0) { + vip_smt_control = VIP_SMT_FORCE_DISABLED; + pr_info("VIP-SMT: Force disabled via cmdline\n"); + } else { + vip_smt_control = VIP_SMT_DISABLED; + } +} + +/** + * vip_smt_cmdline_disable - cmdline parameter handler + */ +static int __init vip_smt_cmdline_disable(char *str) +{ + vip_smt_disable(str); + return 0; +} +early_param("novipsmt", vip_smt_cmdline_disable); + /** * vip_smt_probe - Detect hardware support for VIP-SMT * @@ -431,6 +461,12 @@ static bool vip_smt_probe(void) bool has_vip_smt_support(const struct arm64_cpu_capabilities *entry, int __unused) { + /* If hardware not supported or disabled, set to NOT_SUPPORTED */ + if (vip_smt_control != VIP_SMT_ENABLED) { + pr_info("VIP-SMT: Disabled in cmdline.\n"); + return false; + } + /* Only can access from el2 for now!, configure in el3. */ if (!is_kernel_in_hyp_mode()) { pr_info("VIP-SMT: Only support in EL2 for now.\n"); -- 2.34.1
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/10013 ---------------------------------------------- Enable CONFIG_ARM64_VIP_SMT in openeuler_defconfig so that the VIP-SMT QoS feature is built in by default on ARM64 openEuler kernels. Signed-off-by: Yipeng Zou <zouyipeng@huawei.com> Reviewed-by: Liao Chang <liaochang1@huawei.com> --- arch/arm64/configs/openeuler_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 12ed365e9340..2b90bba63b01 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -407,6 +407,7 @@ CONFIG_ACTLR_XCALL_XINT=y CONFIG_DYNAMIC_XCALL=y CONFIG_ARM64_COPY_FROM_USER_OPT=y CONFIG_SMT_QOS=y +CONFIG_ARM64_VIP_SMT=y # end of Turbo features selection # -- 2.34.1
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/28003 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/ICZ... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/28003 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/ICZ...
participants (2)
-
patchwork bot -
Yipeng Zou