]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
riscv: misaligned: Fix fast_unaligned_access_speed_key init
authorNam Cao <namcao@linutronix.de>
Thu, 28 May 2026 21:12:30 +0000 (23:12 +0200)
committerPaul Walmsley <pjw@kernel.org>
Mon, 8 Jun 2026 16:47:22 +0000 (10:47 -0600)
When booting with unaligned_scalar_speed=fast,
fast_unaligned_access_speed_key is initialized incorrectly.

The key is currently derived from the fast_misaligned_access cpumask, but
that mask is only populated when the unaligned access speed probe runs.
Specifying unaligned_scalar_speed=fast skips the probe entirely, leaving
the mask uninitialized.

The information tracked by fast_misaligned_access is already available in
the misaligned_access_speed per-CPU variable. Use that to initialize
fast_unaligned_access_speed_key instead and remove the redundant cpumask.

Signed-off-by: Nam Cao <namcao@linutronix.de>
Link: https://patch.msgid.link/2468816ceb433394099a00d7822f819745276b49.1780002199.git.namcao@linutronix.de
Signed-off-by: Paul Walmsley <pjw@kernel.org>
arch/riscv/kernel/unaligned_access_speed.c

index 11c781a4de733ad67a947ce7174ebb6696d498fd..bb57eb5d19dfe355892a88736f4e3698a0b3ad92 100644 (file)
@@ -27,8 +27,6 @@ DEFINE_PER_CPU(long, vector_misaligned_access) = RISCV_HWPROBE_MISALIGNED_VECTOR
 static long unaligned_scalar_speed_param = RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN;
 static long unaligned_vector_speed_param = RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN;
 
-static cpumask_t fast_misaligned_access;
-
 static u64 __maybe_unused
 measure_cycles(void (*func)(void *dst, const void *src, size_t len),
               void *dst, void *src, size_t len)
@@ -131,13 +129,10 @@ static int check_unaligned_access(struct page *page)
         * Set the value of fast_misaligned_access of a CPU. These operations
         * are atomic to avoid race conditions.
         */
-       if (ret) {
+       if (ret)
                per_cpu(misaligned_access_speed, cpu) = RISCV_HWPROBE_MISALIGNED_SCALAR_FAST;
-               cpumask_set_cpu(cpu, &fast_misaligned_access);
-       } else {
+       else
                per_cpu(misaligned_access_speed, cpu) = RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW;
-               cpumask_clear_cpu(cpu, &fast_misaligned_access);
-       }
 
        return 0;
 }
@@ -192,49 +187,24 @@ static void __init check_unaligned_access_speed_all_cpus(void)
 
 DEFINE_STATIC_KEY_FALSE(fast_unaligned_access_speed_key);
 
-static void modify_unaligned_access_branches(cpumask_t *mask, int weight)
+static void modify_unaligned_access_branches(const cpumask_t *mask)
 {
-       if (cpumask_weight(mask) == weight)
+       bool fast = true;
+       int cpu;
+
+       for_each_cpu(cpu, mask) {
+               if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_FAST) {
+                       fast = false;
+                       break;
+               }
+       }
+
+       if (fast)
                static_branch_enable_cpuslocked(&fast_unaligned_access_speed_key);
        else
                static_branch_disable_cpuslocked(&fast_unaligned_access_speed_key);
 }
 
-static void set_unaligned_access_static_branches_except_cpu(int cpu)
-{
-       /*
-        * Same as set_unaligned_access_static_branches, except excludes the
-        * given CPU from the result. When a CPU is hotplugged into an offline
-        * state, this function is called before the CPU is set to offline in
-        * the cpumask, and thus the CPU needs to be explicitly excluded.
-        */
-
-       cpumask_t fast_except_me;
-
-       cpumask_and(&fast_except_me, &fast_misaligned_access, cpu_online_mask);
-       cpumask_clear_cpu(cpu, &fast_except_me);
-
-       modify_unaligned_access_branches(&fast_except_me, num_online_cpus() - 1);
-}
-
-static void set_unaligned_access_static_branches(void)
-{
-       /*
-        * This will be called after check_unaligned_access_all_cpus so the
-        * result of unaligned access speed for all CPUs will be available.
-        *
-        * To avoid the number of online cpus changing between reading
-        * cpu_online_mask and calling num_online_cpus, cpus_read_lock must be
-        * held before calling this function.
-        */
-
-       cpumask_t fast_and_online;
-
-       cpumask_and(&fast_and_online, &fast_misaligned_access, cpu_online_mask);
-
-       modify_unaligned_access_branches(&fast_and_online, num_online_cpus());
-}
-
 static int riscv_online_cpu(unsigned int cpu)
 {
        int ret = cpu_online_unaligned_access_init(cpu);
@@ -266,14 +236,19 @@ static int riscv_online_cpu(unsigned int cpu)
 #endif
 
 exit:
-       set_unaligned_access_static_branches();
+       modify_unaligned_access_branches(cpu_online_mask);
 
        return 0;
 }
 
 static int riscv_offline_cpu(unsigned int cpu)
 {
-       set_unaligned_access_static_branches_except_cpu(cpu);
+       cpumask_t mask;
+
+       cpumask_copy(&mask, cpu_online_mask);
+       cpumask_clear_cpu(cpu, &mask);
+
+       modify_unaligned_access_branches(&mask);
 
        return 0;
 }
@@ -430,7 +405,7 @@ static int __init check_unaligned_access_all_cpus(void)
                                  riscv_online_cpu_vec, NULL);
 
        cpus_read_lock();
-       set_unaligned_access_static_branches();
+       modify_unaligned_access_branches(cpu_online_mask);
        cpus_read_unlock();
 
        return 0;