]> Git Repo - J-linux.git/blob - drivers/platform/x86/intel/ifs/runtest.c
Merge tag 'platform-drivers-x86-v6.13-3' of git://git.kernel.org/pub/scm/linux/kernel...
[J-linux.git] / drivers / platform / x86 / intel / ifs / runtest.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2022 Intel Corporation. */
3
4 #include <linux/cpu.h>
5 #include <linux/delay.h>
6 #include <linux/fs.h>
7 #include <linux/nmi.h>
8 #include <linux/slab.h>
9 #include <linux/stop_machine.h>
10
11 #include "ifs.h"
12
13 /*
14  * Note all code and data in this file is protected by
15  * ifs_sem. On HT systems all threads on a core will
16  * execute together, but only the first thread on the
17  * core will update results of the test.
18  */
19
20 #define CREATE_TRACE_POINTS
21 #include <trace/events/intel_ifs.h>
22
23 /* Max retries on the same chunk */
24 #define MAX_IFS_RETRIES  5
25
26 struct run_params {
27         struct ifs_data *ifsd;
28         union ifs_scan *activate;
29         union ifs_status status;
30 };
31
32 struct sbaf_run_params {
33         struct ifs_data *ifsd;
34         int *retry_cnt;
35         union ifs_sbaf *activate;
36         union ifs_sbaf_status status;
37 };
38
39 /*
40  * Number of TSC cycles that a logical CPU will wait for the other
41  * logical CPU on the core in the WRMSR(ACTIVATE_SCAN).
42  */
43 #define IFS_THREAD_WAIT 100000
44
45 enum ifs_status_err_code {
46         IFS_NO_ERROR                            = 0,
47         IFS_OTHER_THREAD_COULD_NOT_JOIN         = 1,
48         IFS_INTERRUPTED_BEFORE_RENDEZVOUS       = 2,
49         IFS_POWER_MGMT_INADEQUATE_FOR_SCAN      = 3,
50         IFS_INVALID_CHUNK_RANGE                 = 4,
51         IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS  = 5,
52         IFS_CORE_NOT_CAPABLE_CURRENTLY          = 6,
53         IFS_UNASSIGNED_ERROR_CODE               = 7,
54         IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT = 8,
55         IFS_INTERRUPTED_DURING_EXECUTION        = 9,
56         IFS_UNASSIGNED_ERROR_CODE_0xA           = 0xA,
57         IFS_CORRUPTED_CHUNK             = 0xB,
58 };
59
60 static const char * const scan_test_status[] = {
61         [IFS_NO_ERROR] = "SCAN no error",
62         [IFS_OTHER_THREAD_COULD_NOT_JOIN] = "Other thread could not join.",
63         [IFS_INTERRUPTED_BEFORE_RENDEZVOUS] = "Interrupt occurred prior to SCAN coordination.",
64         [IFS_POWER_MGMT_INADEQUATE_FOR_SCAN] =
65         "Core Abort SCAN Response due to power management condition.",
66         [IFS_INVALID_CHUNK_RANGE] = "Non valid chunks in the range",
67         [IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS] = "Mismatch in arguments between threads T0/T1.",
68         [IFS_CORE_NOT_CAPABLE_CURRENTLY] = "Core not capable of performing SCAN currently",
69         [IFS_UNASSIGNED_ERROR_CODE] = "Unassigned error code 0x7",
70         [IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT] =
71         "Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently",
72         [IFS_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SCAN start",
73         [IFS_UNASSIGNED_ERROR_CODE_0xA] = "Unassigned error code 0xA",
74         [IFS_CORRUPTED_CHUNK] = "Scan operation aborted due to corrupted image. Try reloading",
75 };
76
77 static void message_not_tested(struct device *dev, int cpu, union ifs_status status)
78 {
79         struct ifs_data *ifsd = ifs_get_data(dev);
80
81         /*
82          * control_error is set when the microcode runs into a problem
83          * loading the image from the reserved BIOS memory, or it has
84          * been corrupted. Reloading the image may fix this issue.
85          */
86         if (status.control_error) {
87                 dev_warn(dev, "CPU(s) %*pbl: Scan controller error. Batch: %02x version: 0x%x\n",
88                          cpumask_pr_args(cpu_smt_mask(cpu)), ifsd->cur_batch, ifsd->loaded_version);
89                 return;
90         }
91
92         if (status.error_code < ARRAY_SIZE(scan_test_status)) {
93                 dev_info(dev, "CPU(s) %*pbl: SCAN operation did not start. %s\n",
94                          cpumask_pr_args(cpu_smt_mask(cpu)),
95                          scan_test_status[status.error_code]);
96         } else if (status.error_code == IFS_SW_TIMEOUT) {
97                 dev_info(dev, "CPU(s) %*pbl: software timeout during scan\n",
98                          cpumask_pr_args(cpu_smt_mask(cpu)));
99         } else if (status.error_code == IFS_SW_PARTIAL_COMPLETION) {
100                 dev_info(dev, "CPU(s) %*pbl: %s\n",
101                          cpumask_pr_args(cpu_smt_mask(cpu)),
102                          "Not all scan chunks were executed. Maximum forward progress retries exceeded");
103         } else {
104                 dev_info(dev, "CPU(s) %*pbl: SCAN unknown status %llx\n",
105                          cpumask_pr_args(cpu_smt_mask(cpu)), status.data);
106         }
107 }
108
109 static void message_fail(struct device *dev, int cpu, union ifs_status status)
110 {
111         struct ifs_data *ifsd = ifs_get_data(dev);
112
113         /*
114          * signature_error is set when the output from the scan chains does not
115          * match the expected signature. This might be a transient problem (e.g.
116          * due to a bit flip from an alpha particle or neutron). If the problem
117          * repeats on a subsequent test, then it indicates an actual problem in
118          * the core being tested.
119          */
120         if (status.signature_error) {
121                 dev_err(dev, "CPU(s) %*pbl: test signature incorrect. Batch: %02x version: 0x%x\n",
122                         cpumask_pr_args(cpu_smt_mask(cpu)), ifsd->cur_batch, ifsd->loaded_version);
123         }
124 }
125
126 static bool can_restart(union ifs_status status)
127 {
128         enum ifs_status_err_code err_code = status.error_code;
129
130         /* Signature for chunk is bad, or scan test failed */
131         if (status.signature_error || status.control_error)
132                 return false;
133
134         switch (err_code) {
135         case IFS_NO_ERROR:
136         case IFS_OTHER_THREAD_COULD_NOT_JOIN:
137         case IFS_INTERRUPTED_BEFORE_RENDEZVOUS:
138         case IFS_POWER_MGMT_INADEQUATE_FOR_SCAN:
139         case IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT:
140         case IFS_INTERRUPTED_DURING_EXECUTION:
141                 return true;
142         case IFS_INVALID_CHUNK_RANGE:
143         case IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS:
144         case IFS_CORE_NOT_CAPABLE_CURRENTLY:
145         case IFS_UNASSIGNED_ERROR_CODE:
146         case IFS_UNASSIGNED_ERROR_CODE_0xA:
147         case IFS_CORRUPTED_CHUNK:
148                 break;
149         }
150         return false;
151 }
152
153 #define SPINUNIT 100 /* 100 nsec */
154 static atomic_t array_cpus_in;
155 static atomic_t scan_cpus_in;
156 static atomic_t sbaf_cpus_in;
157
158 /*
159  * Simplified cpu sibling rendezvous loop based on microcode loader __wait_for_cpus()
160  */
161 static void wait_for_sibling_cpu(atomic_t *t, long long timeout)
162 {
163         int cpu = smp_processor_id();
164         const struct cpumask *smt_mask = cpu_smt_mask(cpu);
165         int all_cpus = cpumask_weight(smt_mask);
166
167         atomic_inc(t);
168         while (atomic_read(t) < all_cpus) {
169                 if (timeout < SPINUNIT)
170                         return;
171                 ndelay(SPINUNIT);
172                 timeout -= SPINUNIT;
173                 touch_nmi_watchdog();
174         }
175 }
176
177 /*
178  * Execute the scan. Called "simultaneously" on all threads of a core
179  * at high priority using the stop_cpus mechanism.
180  */
181 static int doscan(void *data)
182 {
183         int cpu = smp_processor_id(), start, stop;
184         struct run_params *params = data;
185         union ifs_status status;
186         struct ifs_data *ifsd;
187         int first;
188
189         ifsd = params->ifsd;
190
191         if (ifsd->generation) {
192                 start = params->activate->gen2.start;
193                 stop = params->activate->gen2.stop;
194         } else {
195                 start = params->activate->gen0.start;
196                 stop = params->activate->gen0.stop;
197         }
198
199         /* Only the first logical CPU on a core reports result */
200         first = cpumask_first(cpu_smt_mask(cpu));
201
202         wait_for_sibling_cpu(&scan_cpus_in, NSEC_PER_SEC);
203
204         /*
205          * This WRMSR will wait for other HT threads to also write
206          * to this MSR (at most for activate.delay cycles). Then it
207          * starts scan of each requested chunk. The core scan happens
208          * during the "execution" of the WRMSR. This instruction can
209          * take up to 200 milliseconds (in the case where all chunks
210          * are processed in a single pass) before it retires.
211          */
212         wrmsrl(MSR_ACTIVATE_SCAN, params->activate->data);
213         rdmsrl(MSR_SCAN_STATUS, status.data);
214
215         trace_ifs_status(ifsd->cur_batch, start, stop, status.data);
216
217         /* Pass back the result of the scan */
218         if (cpu == first)
219                 params->status = status;
220
221         return 0;
222 }
223
224 /*
225  * Use stop_core_cpuslocked() to synchronize writing to MSR_ACTIVATE_SCAN
226  * on all threads of the core to be tested. Loop if necessary to complete
227  * run of all chunks. Include some defensive tests to make sure forward
228  * progress is made, and that the whole test completes in a reasonable time.
229  */
230 static void ifs_test_core(int cpu, struct device *dev)
231 {
232         union ifs_status status = {};
233         union ifs_scan activate;
234         unsigned long timeout;
235         struct ifs_data *ifsd;
236         int to_start, to_stop;
237         int status_chunk;
238         struct run_params params;
239         int retries;
240
241         ifsd = ifs_get_data(dev);
242
243         activate.gen0.rsvd = 0;
244         activate.delay = IFS_THREAD_WAIT;
245         activate.sigmce = 0;
246         to_start = 0;
247         to_stop = ifsd->valid_chunks - 1;
248
249         params.ifsd = ifs_get_data(dev);
250
251         if (ifsd->generation) {
252                 activate.gen2.start = to_start;
253                 activate.gen2.stop = to_stop;
254         } else {
255                 activate.gen0.start = to_start;
256                 activate.gen0.stop = to_stop;
257         }
258
259         timeout = jiffies + HZ / 2;
260         retries = MAX_IFS_RETRIES;
261
262         while (to_start <= to_stop) {
263                 if (time_after(jiffies, timeout)) {
264                         status.error_code = IFS_SW_TIMEOUT;
265                         break;
266                 }
267
268                 params.activate = &activate;
269                 atomic_set(&scan_cpus_in, 0);
270                 stop_core_cpuslocked(cpu, doscan, &params);
271
272                 status = params.status;
273
274                 /* Some cases can be retried, give up for others */
275                 if (!can_restart(status))
276                         break;
277
278                 status_chunk = ifsd->generation ? status.gen2.chunk_num : status.gen0.chunk_num;
279                 if (status_chunk == to_start) {
280                         /* Check for forward progress */
281                         if (--retries == 0) {
282                                 if (status.error_code == IFS_NO_ERROR)
283                                         status.error_code = IFS_SW_PARTIAL_COMPLETION;
284                                 break;
285                         }
286                 } else {
287                         retries = MAX_IFS_RETRIES;
288                         if (ifsd->generation)
289                                 activate.gen2.start = status_chunk;
290                         else
291                                 activate.gen0.start = status_chunk;
292                         to_start = status_chunk;
293                 }
294         }
295
296         /* Update status for this core */
297         ifsd->scan_details = status.data;
298
299         if (status.signature_error) {
300                 ifsd->status = SCAN_TEST_FAIL;
301                 message_fail(dev, cpu, status);
302         } else if (status.control_error || status.error_code) {
303                 ifsd->status = SCAN_NOT_TESTED;
304                 message_not_tested(dev, cpu, status);
305         } else {
306                 ifsd->status = SCAN_TEST_PASS;
307         }
308 }
309
310 static int do_array_test(void *data)
311 {
312         union ifs_array *command = data;
313         int cpu = smp_processor_id();
314         int first;
315
316         wait_for_sibling_cpu(&array_cpus_in, NSEC_PER_SEC);
317
318         /*
319          * Only one logical CPU on a core needs to trigger the Array test via MSR write.
320          */
321         first = cpumask_first(cpu_smt_mask(cpu));
322
323         if (cpu == first) {
324                 wrmsrl(MSR_ARRAY_BIST, command->data);
325                 /* Pass back the result of the test */
326                 rdmsrl(MSR_ARRAY_BIST, command->data);
327         }
328
329         return 0;
330 }
331
332 static void ifs_array_test_core(int cpu, struct device *dev)
333 {
334         union ifs_array command = {};
335         bool timed_out = false;
336         struct ifs_data *ifsd;
337         unsigned long timeout;
338
339         ifsd = ifs_get_data(dev);
340
341         command.array_bitmask = ~0U;
342         timeout = jiffies + HZ / 2;
343
344         do {
345                 if (time_after(jiffies, timeout)) {
346                         timed_out = true;
347                         break;
348                 }
349                 atomic_set(&array_cpus_in, 0);
350                 stop_core_cpuslocked(cpu, do_array_test, &command);
351
352                 if (command.ctrl_result)
353                         break;
354         } while (command.array_bitmask);
355
356         ifsd->scan_details = command.data;
357
358         if (command.ctrl_result)
359                 ifsd->status = SCAN_TEST_FAIL;
360         else if (timed_out || command.array_bitmask)
361                 ifsd->status = SCAN_NOT_TESTED;
362         else
363                 ifsd->status = SCAN_TEST_PASS;
364 }
365
366 #define ARRAY_GEN1_TEST_ALL_ARRAYS      0x0ULL
367 #define ARRAY_GEN1_STATUS_FAIL          0x1ULL
368
369 static int do_array_test_gen1(void *status)
370 {
371         int cpu = smp_processor_id();
372         int first;
373
374         first = cpumask_first(cpu_smt_mask(cpu));
375
376         if (cpu == first) {
377                 wrmsrl(MSR_ARRAY_TRIGGER, ARRAY_GEN1_TEST_ALL_ARRAYS);
378                 rdmsrl(MSR_ARRAY_STATUS, *((u64 *)status));
379         }
380
381         return 0;
382 }
383
384 static void ifs_array_test_gen1(int cpu, struct device *dev)
385 {
386         struct ifs_data *ifsd = ifs_get_data(dev);
387         u64 status = 0;
388
389         stop_core_cpuslocked(cpu, do_array_test_gen1, &status);
390         ifsd->scan_details = status;
391
392         if (status & ARRAY_GEN1_STATUS_FAIL)
393                 ifsd->status = SCAN_TEST_FAIL;
394         else
395                 ifsd->status = SCAN_TEST_PASS;
396 }
397
398 #define SBAF_STATUS_PASS                        0
399 #define SBAF_STATUS_SIGN_FAIL                   1
400 #define SBAF_STATUS_INTR                        2
401 #define SBAF_STATUS_TEST_FAIL                   3
402
403 enum sbaf_status_err_code {
404         IFS_SBAF_NO_ERROR                               = 0,
405         IFS_SBAF_OTHER_THREAD_COULD_NOT_JOIN            = 1,
406         IFS_SBAF_INTERRUPTED_BEFORE_RENDEZVOUS          = 2,
407         IFS_SBAF_UNASSIGNED_ERROR_CODE3                 = 3,
408         IFS_SBAF_INVALID_BUNDLE_INDEX                   = 4,
409         IFS_SBAF_MISMATCH_ARGS_BETWEEN_THREADS          = 5,
410         IFS_SBAF_CORE_NOT_CAPABLE_CURRENTLY             = 6,
411         IFS_SBAF_UNASSIGNED_ERROR_CODE7                 = 7,
412         IFS_SBAF_EXCEED_NUMBER_OF_THREADS_CONCURRENT    = 8,
413         IFS_SBAF_INTERRUPTED_DURING_EXECUTION           = 9,
414         IFS_SBAF_INVALID_PROGRAM_INDEX                  = 0xA,
415         IFS_SBAF_CORRUPTED_CHUNK                        = 0xB,
416         IFS_SBAF_DID_NOT_START                          = 0xC,
417 };
418
419 static const char * const sbaf_test_status[] = {
420         [IFS_SBAF_NO_ERROR] = "SBAF no error",
421         [IFS_SBAF_OTHER_THREAD_COULD_NOT_JOIN] = "Other thread could not join.",
422         [IFS_SBAF_INTERRUPTED_BEFORE_RENDEZVOUS] = "Interrupt occurred prior to SBAF coordination.",
423         [IFS_SBAF_UNASSIGNED_ERROR_CODE3] = "Unassigned error code 0x3",
424         [IFS_SBAF_INVALID_BUNDLE_INDEX] = "Non-valid sbaf bundles. Reload test image",
425         [IFS_SBAF_MISMATCH_ARGS_BETWEEN_THREADS] = "Mismatch in arguments between threads T0/T1.",
426         [IFS_SBAF_CORE_NOT_CAPABLE_CURRENTLY] = "Core not capable of performing SBAF currently",
427         [IFS_SBAF_UNASSIGNED_ERROR_CODE7] = "Unassigned error code 0x7",
428         [IFS_SBAF_EXCEED_NUMBER_OF_THREADS_CONCURRENT] = "Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently",
429         [IFS_SBAF_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SBAF start",
430         [IFS_SBAF_INVALID_PROGRAM_INDEX] = "SBAF program index not valid",
431         [IFS_SBAF_CORRUPTED_CHUNK] = "SBAF operation aborted due to corrupted chunk",
432         [IFS_SBAF_DID_NOT_START] = "SBAF operation did not start",
433 };
434
435 static void sbaf_message_not_tested(struct device *dev, int cpu, u64 status_data)
436 {
437         union ifs_sbaf_status status = (union ifs_sbaf_status)status_data;
438
439         if (status.error_code < ARRAY_SIZE(sbaf_test_status)) {
440                 dev_info(dev, "CPU(s) %*pbl: SBAF operation did not start. %s\n",
441                          cpumask_pr_args(cpu_smt_mask(cpu)),
442                          sbaf_test_status[status.error_code]);
443         } else if (status.error_code == IFS_SW_TIMEOUT) {
444                 dev_info(dev, "CPU(s) %*pbl: software timeout during scan\n",
445                          cpumask_pr_args(cpu_smt_mask(cpu)));
446         } else if (status.error_code == IFS_SW_PARTIAL_COMPLETION) {
447                 dev_info(dev, "CPU(s) %*pbl: %s\n",
448                          cpumask_pr_args(cpu_smt_mask(cpu)),
449                          "Not all SBAF bundles executed. Maximum forward progress retries exceeded");
450         } else {
451                 dev_info(dev, "CPU(s) %*pbl: SBAF unknown status %llx\n",
452                          cpumask_pr_args(cpu_smt_mask(cpu)), status.data);
453         }
454 }
455
456 static void sbaf_message_fail(struct device *dev, int cpu, union ifs_sbaf_status status)
457 {
458         /* Failed signature check is set when SBAF signature did not match the expected value */
459         if (status.sbaf_status == SBAF_STATUS_SIGN_FAIL) {
460                 dev_err(dev, "CPU(s) %*pbl: Failed signature check\n",
461                         cpumask_pr_args(cpu_smt_mask(cpu)));
462         }
463
464         /* Failed to reach end of test */
465         if (status.sbaf_status == SBAF_STATUS_TEST_FAIL) {
466                 dev_err(dev, "CPU(s) %*pbl: Failed to complete test\n",
467                         cpumask_pr_args(cpu_smt_mask(cpu)));
468         }
469 }
470
471 static bool sbaf_bundle_completed(union ifs_sbaf_status status)
472 {
473         return !(status.sbaf_status || status.error_code);
474 }
475
476 static bool sbaf_can_restart(union ifs_sbaf_status status)
477 {
478         enum sbaf_status_err_code err_code = status.error_code;
479
480         /* Signature for chunk is bad, or scan test failed */
481         if (status.sbaf_status == SBAF_STATUS_SIGN_FAIL ||
482             status.sbaf_status == SBAF_STATUS_TEST_FAIL)
483                 return false;
484
485         switch (err_code) {
486         case IFS_SBAF_NO_ERROR:
487         case IFS_SBAF_OTHER_THREAD_COULD_NOT_JOIN:
488         case IFS_SBAF_INTERRUPTED_BEFORE_RENDEZVOUS:
489         case IFS_SBAF_EXCEED_NUMBER_OF_THREADS_CONCURRENT:
490         case IFS_SBAF_INTERRUPTED_DURING_EXECUTION:
491                 return true;
492         case IFS_SBAF_UNASSIGNED_ERROR_CODE3:
493         case IFS_SBAF_INVALID_BUNDLE_INDEX:
494         case IFS_SBAF_MISMATCH_ARGS_BETWEEN_THREADS:
495         case IFS_SBAF_CORE_NOT_CAPABLE_CURRENTLY:
496         case IFS_SBAF_UNASSIGNED_ERROR_CODE7:
497         case IFS_SBAF_INVALID_PROGRAM_INDEX:
498         case IFS_SBAF_CORRUPTED_CHUNK:
499         case IFS_SBAF_DID_NOT_START:
500                 break;
501         }
502         return false;
503 }
504
505 /*
506  * Execute the SBAF test. Called "simultaneously" on all threads of a core
507  * at high priority using the stop_cpus mechanism.
508  */
509 static int dosbaf(void *data)
510 {
511         struct sbaf_run_params *run_params = data;
512         int cpu = smp_processor_id();
513         union ifs_sbaf_status status;
514         struct ifs_data *ifsd;
515         int first;
516
517         ifsd = run_params->ifsd;
518
519         /* Only the first logical CPU on a core reports result */
520         first = cpumask_first(cpu_smt_mask(cpu));
521         wait_for_sibling_cpu(&sbaf_cpus_in, NSEC_PER_SEC);
522
523         /*
524          * This WRMSR will wait for other HT threads to also write
525          * to this MSR (at most for activate.delay cycles). Then it
526          * starts scan of each requested bundle. The core test happens
527          * during the "execution" of the WRMSR.
528          */
529         wrmsrl(MSR_ACTIVATE_SBAF, run_params->activate->data);
530         rdmsrl(MSR_SBAF_STATUS, status.data);
531         trace_ifs_sbaf(ifsd->cur_batch, *run_params->activate, status);
532
533         /* Pass back the result of the test */
534         if (cpu == first)
535                 run_params->status = status;
536
537         return 0;
538 }
539
540 static void ifs_sbaf_test_core(int cpu, struct device *dev)
541 {
542         struct sbaf_run_params run_params;
543         union ifs_sbaf_status status = {};
544         union ifs_sbaf activate;
545         unsigned long timeout;
546         struct ifs_data *ifsd;
547         int stop_bundle;
548         int retries;
549
550         ifsd = ifs_get_data(dev);
551
552         activate.data = 0;
553         activate.delay = IFS_THREAD_WAIT;
554
555         timeout = jiffies + 2 * HZ;
556         retries = MAX_IFS_RETRIES;
557         activate.bundle_idx = 0;
558         stop_bundle = ifsd->max_bundle;
559
560         while (activate.bundle_idx <= stop_bundle) {
561                 if (time_after(jiffies, timeout)) {
562                         status.error_code = IFS_SW_TIMEOUT;
563                         break;
564                 }
565
566                 atomic_set(&sbaf_cpus_in, 0);
567
568                 run_params.ifsd = ifsd;
569                 run_params.activate = &activate;
570                 run_params.retry_cnt = &retries;
571                 stop_core_cpuslocked(cpu, dosbaf, &run_params);
572
573                 status = run_params.status;
574
575                 if (sbaf_bundle_completed(status)) {
576                         activate.bundle_idx = status.bundle_idx + 1;
577                         activate.pgm_idx = 0;
578                         retries = MAX_IFS_RETRIES;
579                         continue;
580                 }
581
582                 /* Some cases can be retried, give up for others */
583                 if (!sbaf_can_restart(status))
584                         break;
585
586                 if (status.pgm_idx == activate.pgm_idx) {
587                         /* If no progress retry */
588                         if (--retries == 0) {
589                                 if (status.error_code == IFS_NO_ERROR)
590                                         status.error_code = IFS_SW_PARTIAL_COMPLETION;
591                                 break;
592                         }
593                 } else {
594                         /* if some progress, more pgms remaining in bundle, reset retries */
595                         retries = MAX_IFS_RETRIES;
596                         activate.bundle_idx = status.bundle_idx;
597                         activate.pgm_idx = status.pgm_idx;
598                 }
599         }
600
601         /* Update status for this core */
602         ifsd->scan_details = status.data;
603
604         if (status.sbaf_status == SBAF_STATUS_SIGN_FAIL ||
605             status.sbaf_status == SBAF_STATUS_TEST_FAIL) {
606                 ifsd->status = SCAN_TEST_FAIL;
607                 sbaf_message_fail(dev, cpu, status);
608         } else if (status.error_code || status.sbaf_status == SBAF_STATUS_INTR ||
609                    (activate.bundle_idx < stop_bundle)) {
610                 ifsd->status = SCAN_NOT_TESTED;
611                 sbaf_message_not_tested(dev, cpu, status.data);
612         } else {
613                 ifsd->status = SCAN_TEST_PASS;
614         }
615 }
616
617 /*
618  * Initiate per core test. It wakes up work queue threads on the target cpu and
619  * its sibling cpu. Once all sibling threads wake up, the scan test gets executed and
620  * wait for all sibling threads to finish the scan test.
621  */
622 int do_core_test(int cpu, struct device *dev)
623 {
624         const struct ifs_test_caps *test = ifs_get_test_caps(dev);
625         struct ifs_data *ifsd = ifs_get_data(dev);
626         int ret = 0;
627
628         /* Prevent CPUs from being taken offline during the scan test */
629         cpus_read_lock();
630
631         if (!cpu_online(cpu)) {
632                 dev_info(dev, "cannot test on the offline cpu %d\n", cpu);
633                 ret = -EINVAL;
634                 goto out;
635         }
636
637         switch (test->test_num) {
638         case IFS_TYPE_SAF:
639                 if (!ifsd->loaded)
640                         ret = -EPERM;
641                 else
642                         ifs_test_core(cpu, dev);
643                 break;
644         case IFS_TYPE_ARRAY_BIST:
645                 if (ifsd->array_gen == ARRAY_GEN0)
646                         ifs_array_test_core(cpu, dev);
647                 else
648                         ifs_array_test_gen1(cpu, dev);
649                 break;
650         case IFS_TYPE_SBAF:
651                 if (!ifsd->loaded)
652                         ret = -EPERM;
653                 else
654                         ifs_sbaf_test_core(cpu, dev);
655                 break;
656         default:
657                 ret = -EINVAL;
658         }
659 out:
660         cpus_read_unlock();
661         return ret;
662 }
This page took 0.065463 seconds and 4 git commands to generate.