From: Jithu Joseph <[email protected]>

The current intel_ifs driver selects CPUs from cpu_smt_mask() to run
IFS test simultaneously. This approach works well for processors currently
supported by the intel_ifs driver, where threads in a CPU core share the
same SCAN test engine. However, it will not work for new Intel Xeon
processors, such as Diamond Rapids, where multiple CPU cores in a module
share the same SCAN test engine and must run IFS tests simultaneously.

Starting with Granite Rapids (GNR) and later generations, bit[20:16]
(TID_BIT_SHIFT) of MSR_INTEGRITY_CAPABILITIES register [1] contains the
number of bits to shift right on x2APICID to obtain a unique topology ID
for all logical processors that share a SCAN test engine. In theory,
computing a cpumask by this method and using a stop_machine() variant
with an arbitrary cpumask passed in to rendezvous CPUs for simultaneous
IFS tests should work for both cases where threads in a core or CPU
cores in a module share the same SCAN test engine. However, as per
Tony Luck's feedback and the previous discussion [2], the Linux community
is not in favor of a stop_machine() variant with an arbitrary cpumask.

Observations on existing Intel Xeon processors and the upcoming Diamond
Rapids with IFS capability show that the logical processors sharing the
same SCAN test engine are exactly the logical processors sharing the
same L2 cache.

topology_cluster_cpumask() returns the cpumask for CPUs sharing the same
L2 cache. Therefore, select CPUs from topology_cluster_cpumask() to run
IFS tests if simultaneous testing is required.

[ Qiuxu: Re-wrote the commit message. ]

[1] Vol. 4 "Table 2-56. Additional MSRs Supported by the Intel® Xeon®
    6 P-Core Processors" in the Intel Software Developers' Manual,
    March 2025.

[2] 
https://lore.kernel.org/all/[email protected]/

Suggested-by: Tony Luck <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Signed-off-by: Ehab Ababneh <[email protected]>
---
 drivers/platform/x86/intel/ifs/ifs.h     |  2 +
 drivers/platform/x86/intel/ifs/runtest.c | 48 +++++++++++++++++++-----
 2 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/drivers/platform/x86/intel/ifs/ifs.h 
b/drivers/platform/x86/intel/ifs/ifs.h
index 814ebac10a5d..365429fafe7a 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -285,6 +285,7 @@ struct ifs_test_msrs {
 
 /**
  * struct ifs_data - attributes related to Intel IFS driver
+ * @grp_cpumask: set of CPUs being tested simultaneously
  * @loaded_version: stores the currently loaded ifs image version.
  * @loaded: If a valid test binary has been loaded into the memory
  * @loading_error: Error occurred on another CPU while loading image
@@ -298,6 +299,7 @@ struct ifs_test_msrs {
  * @all_lp_join: all logical processors join test
  */
 struct ifs_data {
+       cpumask_t       grp_cpumask;
        int     loaded_version;
        bool    loaded;
        bool    loading_error;
diff --git a/drivers/platform/x86/intel/ifs/runtest.c 
b/drivers/platform/x86/intel/ifs/runtest.c
index c6a4d6dcccf1..09e7a81e9220 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -156,11 +156,9 @@ static atomic_t scan_cpus_in;
 /*
  * Simplified CPU sibling rendezvous loop based on microcode loader 
wait_for_cpus()
  */
-static void wait_for_sibling_cpu(atomic_t *t, long long timeout)
+static void wait_for_sibling_cpu(struct ifs_data *ifsd, atomic_t *t, long long 
timeout)
 {
-       int cpu = smp_processor_id();
-       const struct cpumask *smt_mask = cpu_smt_mask(cpu);
-       int all_cpus = cpumask_weight(smt_mask);
+       int all_cpus = cpumask_weight(&ifsd->grp_cpumask);
 
        atomic_inc(t);
        while (atomic_read(t) < all_cpus) {
@@ -195,9 +193,9 @@ static int doscan(void *data)
        }
 
        /* Only the first logical CPU on a core reports result */
-       first = cpumask_first(cpu_smt_mask(cpu));
+       first = cpumask_first(&ifsd->grp_cpumask);
 
-       wait_for_sibling_cpu(&scan_cpus_in, NSEC_PER_SEC);
+       wait_for_sibling_cpu(ifsd, &scan_cpus_in, NSEC_PER_SEC);
 
        /*
         * This WRMSR will wait for other HT threads to also write
@@ -265,7 +263,11 @@ static void ifs_test_core(int cpu, struct device *dev)
 
                params.activate = &activate;
                atomic_set(&scan_cpus_in, 0);
-               stop_core_cpuslocked(cpu, doscan, &params);
+
+               if (ifsd->all_lp_join)
+                       stop_cluster_cpuslocked(cpu, doscan, &params);
+               else
+                       stop_core_cpuslocked(cpu, doscan, &params);
 
                status = params.status;
 
@@ -310,15 +312,18 @@ static int do_array_test(void *data)
        struct run_array_params *params = data;
        int cpu = smp_processor_id();
        union ifs_array *command;
+       struct ifs_data *ifsd;
        int first;
 
+       ifsd = params->ifsd;
+
        command = params->command;
-       wait_for_sibling_cpu(&array_cpus_in, NSEC_PER_SEC);
+       wait_for_sibling_cpu(ifsd, &array_cpus_in, NSEC_PER_SEC);
 
        /*
         * Only one logical CPU on a core needs to trigger the Array test via 
MSR write.
         */
-       first = cpumask_first(cpu_smt_mask(cpu));
+       first = cpumask_first(&ifsd->grp_cpumask);
 
        if (cpu == first) {
                wrmsrq(MSR_ARRAY_BIST, command->data);
@@ -350,7 +355,11 @@ static void ifs_array_test_core(int cpu, struct device 
*dev)
                }
                atomic_set(&array_cpus_in, 0);
                params.command = &command;
-               stop_core_cpuslocked(cpu, do_array_test, &params);
+
+               if (ifsd->all_lp_join)
+                       stop_cluster_cpuslocked(cpu, do_array_test, &params);
+               else
+                       stop_core_cpuslocked(cpu, do_array_test, &params);
 
                if (command.ctrl_result)
                        break;
@@ -398,6 +407,24 @@ static void ifs_array_test_gen1(int cpu, struct device 
*dev)
                ifsd->status = SCAN_TEST_PASS;
 }
 
+static void build_cpugroup_mask(struct device *dev, int cpu)
+{
+       struct ifs_data *ifsd = ifs_get_data(dev);
+
+       cpumask_clear(&ifsd->grp_cpumask);
+
+       /*
+        * Some CPUs, such as Sierra Forest and Clearwater Forest, have 
multiple cores
+        * sharing the same SCAN test engine, but they don't require a 
rendezvous.
+        */
+       if (!ifsd->all_lp_join) {
+               cpumask_set_cpu(cpu, &ifsd->grp_cpumask);
+               return;
+       }
+
+       cpumask_copy(&ifsd->grp_cpumask, topology_cluster_cpumask(cpu));
+}
+
 /*
  * Initiate per core test. It wakes up work queue threads on the target CPU and
  * its sibling CPU. Once all sibling threads wake up, the scan test gets 
executed and
@@ -411,6 +438,7 @@ int do_core_test(int cpu, struct device *dev)
 
        /* Prevent CPUs from being taken offline during the scan test */
        cpus_read_lock();
+       build_cpugroup_mask(dev, cpu);
 
        if (!cpu_online(cpu)) {
                dev_info(dev, "cannot test on the offline CPU %d\n", cpu);
-- 
2.43.0


Reply via email to