[PATCH v3 05/12] arm64: smp: Defer RCU registration during secondary CPU bringup

Jinjie Ruan ruanjinjie at huawei.com
Wed Jul 8 02:13:30 PDT 2026



On 7/7/2026 6:27 PM, Will Deacon wrote:
> Jinjie,
> 
> On Tue, Jul 07, 2026 at 11:02:32AM +0800, Jinjie Ruan wrote:
>> On 7/7/2026 1:39 AM, Will Deacon wrote:
>>> ce3d31ad3cac ("arm64/smp: Move rcu_cpu_starting() earlier") was to
>>> handle the useless print in cpuinfo_detect_icache_policy(), but I've
>>> decided just to remove that one. So I think the remaining prints we have
>>> to worry about in this early boot code are from error paths in the
>>> CPU feature detection logic (check_local_cpu_capabilities()).
>>>
>>> Given that those error paths should all be fatal, perhaps we could
>>> rework cpu_die_early() and cpu_panic_kernel() as macros that take a
>>> string argument and either call printk_deferred() (similarly to what you
>>> suggested in a previous version of your series [1]) or do the
>>> lockdep_off() there before a pr_crit().
>>>
>>> What do you think?
>>
>> That is an excellent point. Reworking cpu_die_early() and
>> cpu_panic_kernel() to uniformly use printk_deferred() based on the
>> specific error type or the string argument is a much cleaner approach.
>>
>> This makes perfect sense because these paths are inherently fatal, and
>> switching to deferred printing avoids the risky lock-taking and RCU
>> runtime constraints during early boot entirely. It cleanly resolves the
>> diagnostic noise without broadly blinding lockdep or hiding potential
>> locking issues down the line.
>>
>> I fully agree with this approach.
> 
> It's great that your AI chatbot thinks this is fantastic, but what do
> _you_ think? I'm much more interested in your opinion, as you have
> already spent time thinking about this.

Sorry, I had AI polish the language based on my ideas, but the main
points are consistent.

My main concern is that future new features might add printing in the
check_local_cpu_capabilities() function. How can we enforce them to only
use the defer version of printk or the new macro we define?

Is what you referring to similar to the following implementation?


diff --git a/arch/arm64/include/asm/cpufeature.h
b/arch/arm64/include/asm/cpufeature.h
index a57870fa96db..6c95227032b0 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -26,6 +26,18 @@
 #include <linux/kernel.h>
 #include <linux/cpumask.h>

+#define cpu_panic_kernel_with_msg(fmt, ...)                            \
+do {                                                                   \
+       printk_deferred(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__);          \
+       cpu_panic_kernel();                                             \
+} while (0)
+
+#define cpu_die_early_with_msg(fmt, ...)                               \
+do {                                                                   \
+       printk_deferred(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__);          \
+       cpu_die_early();                                                \
+} while (0)
+
 /*
  * CPU feature register tracking
  *
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 1a426725265c..20f00819c1cb 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -3699,14 +3699,17 @@ static void verify_local_cpu_caps(u16 scope_mask)
        }

        if (i < ARM64_NCAPS) {
-               pr_crit("CPU%d: Detected conflict for capability %d
(%s), System: %d, CPU: %d\n",
-                       smp_processor_id(), caps->capability,
-                       caps->desc, system_has_cap, cpu_has_cap);
+               #define CAP_CONFLICT_FMT "CPU%d: Detected conflict for
capability %d (%s), System: %d, CPU: %d\n"

                if (cpucap_panic_on_conflict(caps))
-                       cpu_panic_kernel();
+                       cpu_panic_kernel_with_msg(CAP_CONFLICT_FMT,
+                                                 smp_processor_id(),
caps->capability,
+                                                 caps->desc,
system_has_cap, cpu_has_cap);
                else
-                       cpu_die_early();
+                       cpu_die_early_with_msg(CAP_CONFLICT_FMT,
+                                              smp_processor_id(),
caps->capability,
+                                              caps->desc,
system_has_cap, cpu_has_cap);
+               #undef CAP_CONFLICT_MSG
        }
 }

@@ -3731,9 +3734,8 @@ __verify_local_elf_hwcaps(const struct
arm64_cpu_capabilities *caps)

        for (; caps->matches; caps++)
                if (cpus_have_elf_hwcap(caps) && !caps->matches(caps,
SCOPE_LOCAL_CPU)) {
-                       pr_crit("CPU%d: missing HWCAP: %s\n",
-                                       smp_processor_id(), caps->desc);
-                       cpu_die_early();
+                       cpu_die_early_with_msg("CPU%d: missing HWCAP: %s\n",
+                                              smp_processor_id(),
caps->desc);
                }
 }

@@ -3750,9 +3752,8 @@ static void verify_sve_features(void)
        unsigned long cpacr = cpacr_save_enable_kernel_sve();

        if (vec_verify_vq_map(ARM64_VEC_SVE)) {
-               pr_crit("CPU%d: SVE: vector length support mismatch\n",
-                       smp_processor_id());
-               cpu_die_early();
+               cpu_die_early_with_msg("CPU%d: SVE: vector length
support mismatch\n",
+                                       smp_processor_id());
        }

        cpacr_restore(cpacr);
@@ -3763,9 +3764,8 @@ static void verify_sme_features(void)
        unsigned long cpacr = cpacr_save_enable_kernel_sme();

        if (vec_verify_vq_map(ARM64_VEC_SME)) {
-               pr_crit("CPU%d: SME: vector length support mismatch\n",
-                       smp_processor_id());
-               cpu_die_early();
+               cpu_die_early_with_msg("CPU%d: SME: vector length
support mismatch\n",
+                                      smp_processor_id());
        }

        cpacr_restore(cpacr);
@@ -3776,6 +3776,7 @@ static void verify_hyp_capabilities(void)
        u64 safe_mmfr1, mmfr0, mmfr1;
        int parange, ipa_max;
        unsigned int safe_vmid_bits, vmid_bits;
+       int cpu = smp_processor_id();

        if (!IS_ENABLED(CONFIG_KVM))
                return;
@@ -3787,19 +3788,15 @@ static void verify_hyp_capabilities(void)
        /* Verify VMID bits */
        safe_vmid_bits = get_vmid_bits(safe_mmfr1);
        vmid_bits = get_vmid_bits(mmfr1);
-       if (vmid_bits < safe_vmid_bits) {
-               pr_crit("CPU%d: VMID width mismatch\n", smp_processor_id());
-               cpu_die_early();
-       }
+       if (vmid_bits < safe_vmid_bits)
+               cpu_die_early_with_msg("CPU%d: VMID width mismatch\n", cpu);

        /* Verify IPA range */
        parange = cpuid_feature_extract_unsigned_field(mmfr0,
                                ID_AA64MMFR0_EL1_PARANGE_SHIFT);
        ipa_max = id_aa64mmfr0_parange_to_phys_shift(parange);
-       if (ipa_max < get_kvm_ipa_limit()) {
-               pr_crit("CPU%d: IPA range mismatch\n", smp_processor_id());
-               cpu_die_early();
-       }
+       if (ipa_max < get_kvm_ipa_limit())
+               cpu_die_early_with_msg("CPU%d: IPA range mismatch\n", cpu);
 }

 static void verify_mpam_capabilities(void)
@@ -3807,29 +3804,24 @@ static void verify_mpam_capabilities(void)
        u64 cpu_idr = read_cpuid(ID_AA64PFR0_EL1);
        u64 sys_idr = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
        u16 cpu_partid_max, cpu_pmg_max, sys_partid_max, sys_pmg_max;
+       int cpu = smp_processor_id();

        if (FIELD_GET(ID_AA64PFR0_EL1_MPAM_MASK, cpu_idr) !=
-           FIELD_GET(ID_AA64PFR0_EL1_MPAM_MASK, sys_idr)) {
-               pr_crit("CPU%d: MPAM version mismatch\n",
smp_processor_id());
-               cpu_die_early();
-       }
+           FIELD_GET(ID_AA64PFR0_EL1_MPAM_MASK, sys_idr))
+               cpu_die_early_with_msg("CPU%d: MPAM version mismatch\n",
cpu);

        cpu_idr = read_cpuid(MPAMIDR_EL1);
        sys_idr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
        if (FIELD_GET(MPAMIDR_EL1_HAS_HCR, cpu_idr) !=
-           FIELD_GET(MPAMIDR_EL1_HAS_HCR, sys_idr)) {
-               pr_crit("CPU%d: Missing MPAM HCR\n", smp_processor_id());
-               cpu_die_early();
-       }
+           FIELD_GET(MPAMIDR_EL1_HAS_HCR, sys_idr))
+               cpu_die_early_with_msg("CPU%d: Missing MPAM HCR\n", cpu);

        cpu_partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, cpu_idr);
        cpu_pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, cpu_idr);
        sys_partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, sys_idr);
        sys_pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, sys_idr);
-       if (cpu_partid_max < sys_partid_max || cpu_pmg_max < sys_pmg_max) {
-               pr_crit("CPU%d: MPAM PARTID/PMG max values are
mismatched\n", smp_processor_id());
-               cpu_die_early();
-       }
+       if (cpu_partid_max < sys_partid_max || cpu_pmg_max < sys_pmg_max)
+               cpu_die_early_with_msg("CPU%d: MPAM PARTID/PMG max
values are mismatched\n", cpu);
 }

 /*
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 25dc5afe9ba0..f615b8b79ada 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1057,8 +1057,10 @@ int vec_verify_vq_map(enum vec_type type)

        bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
        if (bitmap_intersects(tmp_map, info->vq_map, SVE_VQ_MAX)) {
-               pr_warn("%s: cpu%d: Required vector length(s) missing\n",
+               #define VEC_MISSING_FMT "%s: cpu%d: Required vector
length(s) missing\n"
+               printk_deferred(KERN_WARNING pr_fmt(VEC_MISSING_FMT),
                        info->name, smp_processor_id());
+               #undef VEC_MISSING_FMT
                return -EINVAL;
        }

@@ -1086,8 +1088,10 @@ int vec_verify_vq_map(enum vec_type type)
         * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
         */
        if (sve_vl_from_vq(__bit_to_vq(b)) <= info->max_virtualisable_vl) {
-               pr_warn("%s: cpu%d: Unsupported vector length(s) present\n",
-                       info->name, smp_processor_id());
+               #define VEC_UNSUPP_FMT "%s: cpu%d: Unsupported vector
length(s) present\n"
+               printk_deferred(KERN_WARNING pr_fmt(VEC_UNSUPP_FMT),
+                               info->name, smp_processor_id());
+               #undef VEC_UNSUPP_FMT
                return -EINVAL;
        }

diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index 0f4a28b87469..374f34d628ba 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -70,9 +70,8 @@ void verify_cpu_asid_bits(void)
                 * We cannot decrease the ASID size at runtime, so panic
if we support
                 * fewer ASID bits than the boot CPU.
                 */
-               pr_crit("CPU%d: smaller ASID size(%u) than boot CPU (%u)\n",
-                               smp_processor_id(), asid, asid_bits);
-               cpu_panic_kernel();
+               cpu_panic_kernel_with_msg("CPU%d: smaller ASID size(%u)
than boot CPU (%u)\n",
+                                         smp_processor_id(), asid,
asid_bits);
        }
 }


> 
> Will




More information about the linux-arm-kernel mailing list