1 /* 2 * Copyright (c) 2017-2023, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* Runtime firmware routines to report errata status for the current CPU. */ 8 9 #include <assert.h> 10 #include <stdbool.h> 11 12 #include <arch_helpers.h> 13 #include <common/debug.h> 14 #include <lib/cpus/cpu_ops.h> 15 #include <lib/cpus/errata.h> 16 #include <lib/el3_runtime/cpu_data.h> 17 #include <lib/spinlock.h> 18 19 #ifdef IMAGE_BL1 20 # define BL_STRING "BL1" 21 #elif defined(__aarch64__) && defined(IMAGE_BL31) 22 # define BL_STRING "BL31" 23 #elif !defined(__aarch64__) && defined(IMAGE_BL32) 24 # define BL_STRING "BL32" 25 #elif defined(IMAGE_BL2) && RESET_TO_BL2 26 # define BL_STRING "BL2" 27 #else 28 # error This image should not be printing errata status 29 #endif 30 31 /* Errata format: BL stage, CPU, errata ID, message */ 32 #define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n" 33 34 #if !REPORT_ERRATA 35 void print_errata_status(void) {} 36 #else /* !REPORT_ERRATA */ 37 /* 38 * Returns whether errata needs to be reported. Passed arguments are private to 39 * a CPU type. 40 */ 41 static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported) 42 { 43 bool report_now; 44 45 /* If already reported, return false. */ 46 if (*reported != 0U) 47 return 0; 48 49 /* 50 * Acquire lock. Determine whether status needs reporting, and then mark 51 * report status to true. 52 */ 53 spin_lock(lock); 54 report_now = (*reported == 0U); 55 if (report_now) 56 *reported = 1; 57 spin_unlock(lock); 58 59 return report_now; 60 } 61 62 /* 63 * Function to print errata status for the calling CPU (and others of the same 64 * type). Must be called only: 65 * - when MMU and data caches are enabled; 66 * - after cpu_ops have been initialized in per-CPU data. 67 */ 68 void print_errata_status(void) 69 { 70 struct cpu_ops *cpu_ops; 71 #ifdef IMAGE_BL1 72 /* 73 * BL1 doesn't have per-CPU data. So retrieve the CPU operations 74 * directly. 75 */ 76 cpu_ops = get_cpu_ops_ptr(); 77 78 if (cpu_ops->errata_func != NULL) { 79 cpu_ops->errata_func(); 80 } 81 #else /* IMAGE_BL1 */ 82 cpu_ops = (void *) get_cpu_data(cpu_ops_ptr); 83 84 assert(cpu_ops != NULL); 85 86 if (cpu_ops->errata_func == NULL) { 87 return; 88 } 89 90 if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) { 91 cpu_ops->errata_func(); 92 } 93 #endif /* IMAGE_BL1 */ 94 } 95 96 /* 97 * Print errata status message. 98 * 99 * Unknown: WARN 100 * Missing: WARN 101 * Applied: INFO 102 * Not applied: VERBOSE 103 */ 104 void errata_print_msg(unsigned int status, const char *cpu, const char *id) 105 { 106 /* Errata status strings */ 107 static const char *const errata_status_str[] = { 108 [ERRATA_NOT_APPLIES] = "not applied", 109 [ERRATA_APPLIES] = "applied", 110 [ERRATA_MISSING] = "missing!" 111 }; 112 static const char *const __unused bl_str = BL_STRING; 113 const char *msg __unused; 114 115 116 assert(status < ARRAY_SIZE(errata_status_str)); 117 assert(cpu != NULL); 118 assert(id != NULL); 119 120 msg = errata_status_str[status]; 121 122 switch (status) { 123 case ERRATA_NOT_APPLIES: 124 VERBOSE(ERRATA_FORMAT, bl_str, cpu, id, msg); 125 break; 126 127 case ERRATA_APPLIES: 128 INFO(ERRATA_FORMAT, bl_str, cpu, id, msg); 129 break; 130 131 case ERRATA_MISSING: 132 WARN(ERRATA_FORMAT, bl_str, cpu, id, msg); 133 break; 134 135 default: 136 WARN(ERRATA_FORMAT, bl_str, cpu, id, "unknown"); 137 break; 138 } 139 } 140 #endif /* !REPORT_ERRATA */ 141