Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jithu Joseph and committed by
Hans de Goede
fed696ce 5210fb4e

+93
+12
drivers/platform/x86/intel/ifs/ifs.h
··· 127 127 #include <linux/device.h> 128 128 #include <linux/miscdevice.h> 129 129 130 + #define MSR_ARRAY_BIST 0x00000105 130 131 #define MSR_COPY_SCAN_HASHES 0x000002c2 131 132 #define MSR_SCAN_HASHES_STATUS 0x000002c3 132 133 #define MSR_AUTHENTICATE_AND_COPY_CHUNK 0x000002c4 ··· 190 189 u32 rsvd2 :22; 191 190 u32 control_error :1; 192 191 u32 signature_error :1; 192 + }; 193 + }; 194 + 195 + /* MSR_ARRAY_BIST bit fields */ 196 + union ifs_array { 197 + u64 data; 198 + struct { 199 + u32 array_bitmask; 200 + u16 array_bank; 201 + u16 rsvd :15; 202 + u16 ctrl_result :1; 193 203 }; 194 204 }; 195 205
+81
drivers/platform/x86/intel/ifs/runtest.c
··· 229 229 } 230 230 } 231 231 232 + #define SPINUNIT 100 /* 100 nsec */ 233 + static atomic_t array_cpus_out; 234 + 235 + /* 236 + * Simplified cpu sibling rendezvous loop based on microcode loader __wait_for_cpus() 237 + */ 238 + static void wait_for_sibling_cpu(atomic_t *t, long long timeout) 239 + { 240 + int cpu = smp_processor_id(); 241 + const struct cpumask *smt_mask = cpu_smt_mask(cpu); 242 + int all_cpus = cpumask_weight(smt_mask); 243 + 244 + atomic_inc(t); 245 + while (atomic_read(t) < all_cpus) { 246 + if (timeout < SPINUNIT) 247 + return; 248 + ndelay(SPINUNIT); 249 + timeout -= SPINUNIT; 250 + touch_nmi_watchdog(); 251 + } 252 + } 253 + 254 + static int do_array_test(void *data) 255 + { 256 + union ifs_array *command = data; 257 + int cpu = smp_processor_id(); 258 + int first; 259 + 260 + /* 261 + * Only one logical CPU on a core needs to trigger the Array test via MSR write. 262 + */ 263 + first = cpumask_first(cpu_smt_mask(cpu)); 264 + 265 + if (cpu == first) { 266 + wrmsrl(MSR_ARRAY_BIST, command->data); 267 + /* Pass back the result of the test */ 268 + rdmsrl(MSR_ARRAY_BIST, command->data); 269 + } 270 + 271 + /* Tests complete faster if the sibling is spinning here */ 272 + wait_for_sibling_cpu(&array_cpus_out, NSEC_PER_SEC); 273 + 274 + return 0; 275 + } 276 + 277 + static void ifs_array_test_core(int cpu, struct device *dev) 278 + { 279 + union ifs_array command = {}; 280 + bool timed_out = false; 281 + struct ifs_data *ifsd; 282 + unsigned long timeout; 283 + 284 + ifsd = ifs_get_data(dev); 285 + 286 + command.array_bitmask = ~0U; 287 + timeout = jiffies + HZ / 2; 288 + 289 + do { 290 + if (time_after(jiffies, timeout)) { 291 + timed_out = true; 292 + break; 293 + } 294 + atomic_set(&array_cpus_out, 0); 295 + stop_core_cpuslocked(cpu, do_array_test, &command); 296 + 297 + if (command.ctrl_result) 298 + break; 299 + } while (command.array_bitmask); 300 + 301 + ifsd->scan_details = command.data; 302 + 303 + if (command.ctrl_result) 304 + ifsd->status = SCAN_TEST_FAIL; 305 + else if (timed_out || command.array_bitmask) 306 + ifsd->status = SCAN_NOT_TESTED; 307 + else 308 + ifsd->status = SCAN_TEST_PASS; 309 + } 310 + 232 311 /* 233 312 * Initiate per core test. It wakes up work queue threads on the target cpu and 234 313 * its sibling cpu. Once all sibling threads wake up, the scan test gets executed and ··· 335 256 ifs_test_core(cpu, dev); 336 257 break; 337 258 case IFS_TYPE_ARRAY_BIST: 259 + ifs_array_test_core(cpu, dev); 260 + break; 338 261 default: 339 262 return -EINVAL; 340 263 }