From nobody Wed Oct 8 20:17:03 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id CE53625D552 for ; Wed, 25 Jun 2025 11:34:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750851293; cv=none; b=ltWw3RiXuVldtt9YDMw4jghjc86GsVzFpvCYXYKBeB9QmQJWCvqx1JcHT9Ota2GozqhVNHn/dvWT+YQRN+pjJs/uzhyHJeh3i2fPg2zNKgQq9AM98Pn1gZXcLAPRyh0pf/7dn8UUOxdm5VLSCy+YDfb7IzuusqPc5lH1QTsT4aI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750851293; c=relaxed/simple; bh=RbP84HcCEnwX9DUuFw/tD8N6Pg3hmMFQLfZUlLdOBs0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=j7S0KO+Yp4TVTvtvcgEB0Pr9mNP8Io5L36TMOEvlhpbWmiKqw4yCsPB230NDpjmhXNCRpDeun/vp5n1TWMpDyjEsNNlEz/qlwoWYM9LC4YXSYIcR8Ov2OsGW4sjgt4FWE2SnZCpUFgkJGAs3AGFE5OzCt6Na0mId3iX8i+mz6bs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D4D9C204C; Wed, 25 Jun 2025 04:34:32 -0700 (PDT) Received: from mazurka.cambridge.arm.com (mazurka.cambridge.arm.com [10.2.80.43]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 134DA3F58B; Wed, 25 Jun 2025 04:34:46 -0700 (PDT) From: =?UTF-8?q?Miko=C5=82aj=20Lenczewski?= To: ryan.roberts@arm.com, yang@os.amperecomputing.com, catalin.marinas@arm.com, will@kernel.org, jean-philippe@linaro.org, robin.murphy@arm.com, joro@8bytes.org, maz@kernel.org, oliver.upton@linux.dev, joey.gouly@arm.com, james.morse@arm.com, broonie@kernel.org, ardb@kernel.org, baohua@kernel.org, suzuki.poulose@arm.com, david@redhat.com, jgg@ziepe.ca, nicolinc@nvidia.com, jsnitsel@redhat.com, mshavit@google.com, kevin.tian@intel.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, iommu@lists.linux.dev Cc: =?UTF-8?q?Miko=C5=82aj=20Lenczewski?= , Suzuki K Poulose Subject: [PATCH v8 1/4] arm64: cpufeature: Introduce MATCH_ALL_EARLY_CPUS capability type Date: Wed, 25 Jun 2025 11:34:32 +0000 Message-ID: <20250625113435.26849-2-miko.lenczewski@arm.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250625113435.26849-1-miko.lenczewski@arm.com> References: <20250625113435.26849-1-miko.lenczewski@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Catalin Marinas For system-wide capabilities, the kernel has the SCOPE_SYSTEM type. Such capabilities are checked once the SMP boot has completed using the sanitised ID registers. However, there is a need for a new capability type similar in scope to the system one but with checking performed locally on each CPU during boot (e.g. based on MIDR_EL1 which is not a sanitised register). Introduce ARM64_CPUCAP_MATCH_ALL_EARLY_CPUS which, together with ARM64_CPUCAP_SCOPE_LOCAL_CPU, ensures that such capability is enabled only if all early CPUs have it. For ease of use, define ARM64_CPUCAP_EARLY_LOCAL_CPU_FEATURE which combines SCOPE_LOCAL_CPU, PERMITTED_FOR_LATE_CPUS and MATCH_ALL_EARLY_CPUS. Signed-off-by: Catalin Marinas Signed-off-by: Miko=C5=82aj Lenczewski Reviewed-by: Suzuki K Poulose --- arch/arm64/include/asm/cpufeature.h | 23 +++++++++++ arch/arm64/kernel/cpufeature.c | 60 +++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/c= pufeature.h index c4326f1cb917..155ebd040c55 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -275,6 +275,14 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; #define ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU ((u16)BIT(5)) /* Panic when a conflict is detected */ #define ARM64_CPUCAP_PANIC_ON_CONFLICT ((u16)BIT(6)) +/* + * When paired with SCOPE_LOCAL_CPU, all early CPUs must satisfy the + * condition. This is different from SCOPE_SYSTEM where the check is perfo= rmed + * only once at the end of the SMP boot on the sanitised ID registers. + * SCOPE_SYSTEM is not suitable for cases where the capability depends on + * properties local to a CPU like MIDR_EL1. + */ +#define ARM64_CPUCAP_MATCH_ALL_EARLY_CPUS ((u16)BIT(7)) =20 /* * CPU errata workarounds that need to be enabled at boot time if one or @@ -304,6 +312,16 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; (ARM64_CPUCAP_SCOPE_LOCAL_CPU | \ ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU | \ ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU) +/* + * CPU feature detected at boot time and present on all early CPUs. Late C= PUs + * are permitted to have the feature even if it hasn't been enabled, altho= ugh + * the feature will not be used by Linux in this case. If all early CPUs h= ave + * the feature, then every late CPU must have it. + */ +#define ARM64_CPUCAP_EARLY_LOCAL_CPU_FEATURE \ + (ARM64_CPUCAP_SCOPE_LOCAL_CPU | \ + ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU | \ + ARM64_CPUCAP_MATCH_ALL_EARLY_CPUS) =20 /* * CPU feature detected at boot time, on one or more CPUs. A late CPU @@ -391,6 +409,11 @@ static inline int cpucap_default_scope(const struct ar= m64_cpu_capabilities *cap) return cap->type & ARM64_CPUCAP_SCOPE_MASK; } =20 +static inline bool cpucap_match_all_early_cpus(const struct arm64_cpu_capa= bilities *cap) +{ + return cap->type & ARM64_CPUCAP_MATCH_ALL_EARLY_CPUS; +} + /* * Generic helper for handling capabilities with multiple (match,enable) p= airs * of call backs, sharing the same capability bit. diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index b34044e20128..f9c947166322 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -3370,18 +3370,49 @@ static void update_cpu_capabilities(u16 scope_mask) =20 scope_mask &=3D ARM64_CPUCAP_SCOPE_MASK; for (i =3D 0; i < ARM64_NCAPS; i++) { + bool match_all =3D false; + bool caps_set =3D false; + bool boot_cpu =3D false; + caps =3D cpucap_ptrs[i]; - if (!caps || !(caps->type & scope_mask) || - cpus_have_cap(caps->capability) || - !caps->matches(caps, cpucap_default_scope(caps))) + if (!caps || !(caps->type & scope_mask)) continue; =20 - if (caps->desc && !caps->cpus) + match_all =3D cpucap_match_all_early_cpus(caps); + caps_set =3D cpus_have_cap(caps->capability); + boot_cpu =3D scope_mask & SCOPE_BOOT_CPU; + + /* + * Unless it's a match-all CPUs feature, avoid probing if + * already detected. + */ + if (!match_all && caps_set) + continue; + + /* + * A match-all CPUs capability is only set when probing the + * boot CPU. It may be cleared subsequently if not detected on + * secondary ones. + */ + if (match_all && !caps_set && !boot_cpu) + continue; + + if (!caps->matches(caps, cpucap_default_scope(caps))) { + if (match_all) + __clear_bit(caps->capability, system_cpucaps); + continue; + } + + /* + * Match-all CPUs capabilities are logged later when the + * system capabilities are finalised. + */ + if (!match_all && caps->desc && !caps->cpus) pr_info("detected: %s\n", caps->desc); =20 __set_bit(caps->capability, system_cpucaps); =20 - if ((scope_mask & SCOPE_BOOT_CPU) && (caps->type & SCOPE_BOOT_CPU)) + if (boot_cpu && (caps->type & SCOPE_BOOT_CPU)) set_bit(caps->capability, boot_cpucaps); } } @@ -3782,17 +3813,24 @@ static void __init setup_system_capabilities(void) enable_cpu_capabilities(SCOPE_ALL & ~SCOPE_BOOT_CPU); apply_alternatives_all(); =20 - /* - * Log any cpucaps with a cpumask as these aren't logged by - * update_cpu_capabilities(). - */ for (int i =3D 0; i < ARM64_NCAPS; i++) { const struct arm64_cpu_capabilities *caps =3D cpucap_ptrs[i]; =20 - if (caps && caps->cpus && caps->desc && - cpumask_any(caps->cpus) < nr_cpu_ids) + if (!caps || !caps->desc) + continue; + + /* + * Log any cpucaps with a cpumask as these aren't logged by + * update_cpu_capabilities(). + */ + if (caps->cpus && cpumask_any(caps->cpus) < nr_cpu_ids) pr_info("detected: %s on CPU%*pbl\n", caps->desc, cpumask_pr_args(caps->cpus)); + + /* Log match-all CPUs capabilities */ + if (cpucap_match_all_early_cpus(caps) && + cpus_have_cap(caps->capability)) + pr_info("detected: %s\n", caps->desc); } =20 /* --=20 2.49.0