summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/intel/ifs/runtest.c
diff options
context:
space:
mode:
authorJithu Joseph <jithu.joseph@intel.com>2023-03-21 17:33:57 -0700
committerHans de Goede <hdegoede@redhat.com>2023-03-27 16:10:20 +0200
commitfed696ce13662de882c8708ea7d0664d8e9e178b (patch)
tree2537c2bd4b4675b3d7e0e588269faa7f5c0e8167 /drivers/platform/x86/intel/ifs/runtest.c
parent5210fb4e18806648b5e87ecc206f1b35e1253401 (diff)
platform/x86/intel/ifs: Implement Array BIST test
Array BIST test (for a particular core) is triggered by writing to MSR_ARRAY_BIST from one sibling of the core. This will initiate a test for all supported arrays on that CPU. Array BIST test may be aborted before completing all the arrays in the event of an interrupt or other reasons. In this case, kernel will restart the test from that point onwards. Array test will also be aborted when the test fails, in which case the test is stopped immediately without further retry. Signed-off-by: Jithu Joseph <jithu.joseph@intel.com> Reviewed-by: Tony Luck <tony.luck@intel.com> Link: https://lore.kernel.org/r/20230322003359.213046-8-jithu.joseph@intel.com Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'drivers/platform/x86/intel/ifs/runtest.c')
-rw-r--r--drivers/platform/x86/intel/ifs/runtest.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c
index 323752fe5034..1061eb7ec399 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -229,6 +229,85 @@ static void ifs_test_core(int cpu, struct device *dev)
}
}
+#define SPINUNIT 100 /* 100 nsec */
+static atomic_t array_cpus_out;
+
+/*
+ * Simplified cpu sibling rendezvous loop based on microcode loader __wait_for_cpus()
+ */
+static void wait_for_sibling_cpu(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);
+
+ atomic_inc(t);
+ while (atomic_read(t) < all_cpus) {
+ if (timeout < SPINUNIT)
+ return;
+ ndelay(SPINUNIT);
+ timeout -= SPINUNIT;
+ touch_nmi_watchdog();
+ }
+}
+
+static int do_array_test(void *data)
+{
+ union ifs_array *command = data;
+ int cpu = smp_processor_id();
+ int first;
+
+ /*
+ * Only one logical CPU on a core needs to trigger the Array test via MSR write.
+ */
+ first = cpumask_first(cpu_smt_mask(cpu));
+
+ if (cpu == first) {
+ wrmsrl(MSR_ARRAY_BIST, command->data);
+ /* Pass back the result of the test */
+ rdmsrl(MSR_ARRAY_BIST, command->data);
+ }
+
+ /* Tests complete faster if the sibling is spinning here */
+ wait_for_sibling_cpu(&array_cpus_out, NSEC_PER_SEC);
+
+ return 0;
+}
+
+static void ifs_array_test_core(int cpu, struct device *dev)
+{
+ union ifs_array command = {};
+ bool timed_out = false;
+ struct ifs_data *ifsd;
+ unsigned long timeout;
+
+ ifsd = ifs_get_data(dev);
+
+ command.array_bitmask = ~0U;
+ timeout = jiffies + HZ / 2;
+
+ do {
+ if (time_after(jiffies, timeout)) {
+ timed_out = true;
+ break;
+ }
+ atomic_set(&array_cpus_out, 0);
+ stop_core_cpuslocked(cpu, do_array_test, &command);
+
+ if (command.ctrl_result)
+ break;
+ } while (command.array_bitmask);
+
+ ifsd->scan_details = command.data;
+
+ if (command.ctrl_result)
+ ifsd->status = SCAN_TEST_FAIL;
+ else if (timed_out || command.array_bitmask)
+ ifsd->status = SCAN_NOT_TESTED;
+ else
+ ifsd->status = SCAN_TEST_PASS;
+}
+
/*
* 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
@@ -256,6 +335,8 @@ int do_core_test(int cpu, struct device *dev)
ifs_test_core(cpu, dev);
break;
case IFS_TYPE_ARRAY_BIST:
+ ifs_array_test_core(cpu, dev);
+ break;
default:
return -EINVAL;
}