linux/drivers/firmware/efi/cper-arm.c
<<
>>
Prefs
   1/*
   2 * UEFI Common Platform Error Record (CPER) support
   3 *
   4 * Copyright (C) 2017, The Linux Foundation. All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License version
   8 * 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 */
  19
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22#include <linux/time.h>
  23#include <linux/cper.h>
  24#include <linux/dmi.h>
  25#include <linux/acpi.h>
  26#include <linux/pci.h>
  27#include <linux/aer.h>
  28#include <linux/printk.h>
  29#include <linux/bcd.h>
  30#include <acpi/ghes.h>
  31#include <ras/ras_event.h>
  32
  33#define INDENT_SP       " "
  34
  35static const char * const arm_reg_ctx_strs[] = {
  36        "AArch32 general purpose registers",
  37        "AArch32 EL1 context registers",
  38        "AArch32 EL2 context registers",
  39        "AArch32 secure context registers",
  40        "AArch64 general purpose registers",
  41        "AArch64 EL1 context registers",
  42        "AArch64 EL2 context registers",
  43        "AArch64 EL3 context registers",
  44        "Misc. system register structure",
  45};
  46
  47static const char * const arm_err_trans_type_strs[] = {
  48        "Instruction",
  49        "Data Access",
  50        "Generic",
  51};
  52
  53static const char * const arm_bus_err_op_strs[] = {
  54        "Generic error (type cannot be determined)",
  55        "Generic read (type of instruction or data request cannot be determined)",
  56        "Generic write (type of instruction of data request cannot be determined)",
  57        "Data read",
  58        "Data write",
  59        "Instruction fetch",
  60        "Prefetch",
  61};
  62
  63static const char * const arm_cache_err_op_strs[] = {
  64        "Generic error (type cannot be determined)",
  65        "Generic read (type of instruction or data request cannot be determined)",
  66        "Generic write (type of instruction of data request cannot be determined)",
  67        "Data read",
  68        "Data write",
  69        "Instruction fetch",
  70        "Prefetch",
  71        "Eviction",
  72        "Snooping (processor initiated a cache snoop that resulted in an error)",
  73        "Snooped (processor raised a cache error caused by another processor or device snooping its cache)",
  74        "Management",
  75};
  76
  77static const char * const arm_tlb_err_op_strs[] = {
  78        "Generic error (type cannot be determined)",
  79        "Generic read (type of instruction or data request cannot be determined)",
  80        "Generic write (type of instruction of data request cannot be determined)",
  81        "Data read",
  82        "Data write",
  83        "Instruction fetch",
  84        "Prefetch",
  85        "Local management operation (processor initiated a TLB management operation that resulted in an error)",
  86        "External management operation (processor raised a TLB error caused by another processor or device broadcasting TLB operations)",
  87};
  88
  89static const char * const arm_bus_err_part_type_strs[] = {
  90        "Local processor originated request",
  91        "Local processor responded to request",
  92        "Local processor observed",
  93        "Generic",
  94};
  95
  96static const char * const arm_bus_err_addr_space_strs[] = {
  97        "External Memory Access",
  98        "Internal Memory Access",
  99        "Unknown",
 100        "Device Memory Access",
 101};
 102
 103static void cper_print_arm_err_info(const char *pfx, u32 type,
 104                                    u64 error_info)
 105{
 106        u8 trans_type, op_type, level, participation_type, address_space;
 107        u16 mem_attributes;
 108        bool proc_context_corrupt, corrected, precise_pc, restartable_pc;
 109        bool time_out, access_mode;
 110
 111        /* If the type is unknown, bail. */
 112        if (type > CPER_ARM_MAX_TYPE)
 113                return;
 114
 115        /*
 116         * Vendor type errors have error information values that are vendor
 117         * specific.
 118         */
 119        if (type == CPER_ARM_VENDOR_ERROR)
 120                return;
 121
 122        if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
 123                trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT)
 124                              & CPER_ARM_ERR_TRANSACTION_MASK);
 125                if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) {
 126                        printk("%stransaction type: %s\n", pfx,
 127                               arm_err_trans_type_strs[trans_type]);
 128                }
 129        }
 130
 131        if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
 132                op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
 133                           & CPER_ARM_ERR_OPERATION_MASK);
 134                switch (type) {
 135                case CPER_ARM_CACHE_ERROR:
 136                        if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
 137                                printk("%soperation type: %s\n", pfx,
 138                                       arm_cache_err_op_strs[op_type]);
 139                        }
 140                        break;
 141                case CPER_ARM_TLB_ERROR:
 142                        if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
 143                                printk("%soperation type: %s\n", pfx,
 144                                       arm_tlb_err_op_strs[op_type]);
 145                        }
 146                        break;
 147                case CPER_ARM_BUS_ERROR:
 148                        if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
 149                                printk("%soperation type: %s\n", pfx,
 150                                       arm_bus_err_op_strs[op_type]);
 151                        }
 152                        break;
 153                }
 154        }
 155
 156        if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
 157                level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
 158                         & CPER_ARM_ERR_LEVEL_MASK);
 159                switch (type) {
 160                case CPER_ARM_CACHE_ERROR:
 161                        printk("%scache level: %d\n", pfx, level);
 162                        break;
 163                case CPER_ARM_TLB_ERROR:
 164                        printk("%sTLB level: %d\n", pfx, level);
 165                        break;
 166                case CPER_ARM_BUS_ERROR:
 167                        printk("%saffinity level at which the bus error occurred: %d\n",
 168                               pfx, level);
 169                        break;
 170                }
 171        }
 172
 173        if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
 174                proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT)
 175                                        & CPER_ARM_ERR_PC_CORRUPT_MASK);
 176                if (proc_context_corrupt)
 177                        printk("%sprocessor context corrupted\n", pfx);
 178                else
 179                        printk("%sprocessor context not corrupted\n", pfx);
 180        }
 181
 182        if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
 183                corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
 184                             & CPER_ARM_ERR_CORRECTED_MASK);
 185                if (corrected)
 186                        printk("%sthe error has been corrected\n", pfx);
 187                else
 188                        printk("%sthe error has not been corrected\n", pfx);
 189        }
 190
 191        if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) {
 192                precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT)
 193                              & CPER_ARM_ERR_PRECISE_PC_MASK);
 194                if (precise_pc)
 195                        printk("%sPC is precise\n", pfx);
 196                else
 197                        printk("%sPC is imprecise\n", pfx);
 198        }
 199
 200        if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) {
 201                restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT)
 202                                  & CPER_ARM_ERR_RESTARTABLE_PC_MASK);
 203                if (restartable_pc)
 204                        printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
 205        }
 206
 207        /* The rest of the fields are specific to bus errors */
 208        if (type != CPER_ARM_BUS_ERROR)
 209                return;
 210
 211        if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) {
 212                participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT)
 213                                      & CPER_ARM_ERR_PARTICIPATION_TYPE_MASK);
 214                if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) {
 215                        printk("%sparticipation type: %s\n", pfx,
 216                               arm_bus_err_part_type_strs[participation_type]);
 217                }
 218        }
 219
 220        if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) {
 221                time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT)
 222                            & CPER_ARM_ERR_TIME_OUT_MASK);
 223                if (time_out)
 224                        printk("%srequest timed out\n", pfx);
 225        }
 226
 227        if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) {
 228                address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT)
 229                                 & CPER_ARM_ERR_ADDRESS_SPACE_MASK);
 230                if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) {
 231                        printk("%saddress space: %s\n", pfx,
 232                               arm_bus_err_addr_space_strs[address_space]);
 233                }
 234        }
 235
 236        if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) {
 237                mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT)
 238                                  & CPER_ARM_ERR_MEM_ATTRIBUTES_MASK);
 239                printk("%smemory access attributes:0x%x\n", pfx, mem_attributes);
 240        }
 241
 242        if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) {
 243                access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT)
 244                               & CPER_ARM_ERR_ACCESS_MODE_MASK);
 245                if (access_mode)
 246                        printk("%saccess mode: normal\n", pfx);
 247                else
 248                        printk("%saccess mode: secure\n", pfx);
 249        }
 250}
 251
 252void cper_print_proc_arm(const char *pfx,
 253                         const struct cper_sec_proc_arm *proc)
 254{
 255        int i, len, max_ctx_type;
 256        struct cper_arm_err_info *err_info;
 257        struct cper_arm_ctx_info *ctx_info;
 258        char newpfx[64], infopfx[64];
 259
 260        printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
 261
 262        len = proc->section_length - (sizeof(*proc) +
 263                proc->err_info_num * (sizeof(*err_info)));
 264        if (len < 0) {
 265                printk("%ssection length: %d\n", pfx, proc->section_length);
 266                printk("%ssection length is too small\n", pfx);
 267                printk("%sfirmware-generated error record is incorrect\n", pfx);
 268                printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
 269                return;
 270        }
 271
 272        if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
 273                printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
 274                        pfx, proc->mpidr);
 275
 276        if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
 277                printk("%serror affinity level: %d\n", pfx,
 278                        proc->affinity_level);
 279
 280        if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
 281                printk("%srunning state: 0x%x\n", pfx, proc->running_state);
 282                printk("%sPower State Coordination Interface state: %d\n",
 283                        pfx, proc->psci_state);
 284        }
 285
 286        snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
 287
 288        err_info = (struct cper_arm_err_info *)(proc + 1);
 289        for (i = 0; i < proc->err_info_num; i++) {
 290                printk("%sError info structure %d:\n", pfx, i);
 291
 292                printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
 293
 294                if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
 295                        if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
 296                                printk("%sfirst error captured\n", newpfx);
 297                        if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
 298                                printk("%slast error captured\n", newpfx);
 299                        if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
 300                                printk("%spropagated error captured\n",
 301                                       newpfx);
 302                        if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
 303                                printk("%soverflow occurred, error info is incomplete\n",
 304                                       newpfx);
 305                }
 306
 307                printk("%serror_type: %d, %s\n", newpfx, err_info->type,
 308                        err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ?
 309                        cper_proc_error_type_strs[err_info->type] : "unknown");
 310                if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
 311                        printk("%serror_info: 0x%016llx\n", newpfx,
 312                               err_info->error_info);
 313                        snprintf(infopfx, sizeof(infopfx), "%s%s", newpfx, INDENT_SP);
 314                        cper_print_arm_err_info(infopfx, err_info->type,
 315                                                err_info->error_info);
 316                }
 317                if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
 318                        printk("%svirtual fault address: 0x%016llx\n",
 319                                newpfx, err_info->virt_fault_addr);
 320                if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
 321                        printk("%sphysical fault address: 0x%016llx\n",
 322                                newpfx, err_info->physical_fault_addr);
 323                err_info += 1;
 324        }
 325
 326        ctx_info = (struct cper_arm_ctx_info *)err_info;
 327        max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
 328        for (i = 0; i < proc->context_info_num; i++) {
 329                int size = sizeof(*ctx_info) + ctx_info->size;
 330
 331                printk("%sContext info structure %d:\n", pfx, i);
 332                if (len < size) {
 333                        printk("%ssection length is too small\n", newpfx);
 334                        printk("%sfirmware-generated error record is incorrect\n", pfx);
 335                        return;
 336                }
 337                if (ctx_info->type > max_ctx_type) {
 338                        printk("%sInvalid context type: %d (max: %d)\n",
 339                                newpfx, ctx_info->type, max_ctx_type);
 340                        return;
 341                }
 342                printk("%sregister context type: %s\n", newpfx,
 343                        arm_reg_ctx_strs[ctx_info->type]);
 344                print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
 345                                (ctx_info + 1), ctx_info->size, 0);
 346                len -= size;
 347                ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
 348        }
 349
 350        if (len > 0) {
 351                printk("%sVendor specific error info has %u bytes:\n", pfx,
 352                       len);
 353                print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
 354                                len, true);
 355        }
 356}
 357