1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <lib/extensions/ras_arch.h> 8*91f16700Schasinglulu #include <lib/utils_def.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu /* 11*91f16700Schasinglulu * Probe for error in memory-mapped registers containing error records 12*91f16700Schasinglulu * implemented Standard Error Record format. Upon detecting an error, set probe 13*91f16700Schasinglulu * data to the index of the record in error, and return 1; otherwise, return 0. 14*91f16700Schasinglulu */ 15*91f16700Schasinglulu int ser_probe_memmap(uintptr_t base, unsigned int size_num_k, int *probe_data) 16*91f16700Schasinglulu { 17*91f16700Schasinglulu unsigned int num_records, num_group_regs, i; 18*91f16700Schasinglulu uint64_t gsr; 19*91f16700Schasinglulu 20*91f16700Schasinglulu assert(base != 0UL); 21*91f16700Schasinglulu 22*91f16700Schasinglulu /* Only 4K supported for now */ 23*91f16700Schasinglulu assert(size_num_k == STD_ERR_NODE_SIZE_NUM_K); 24*91f16700Schasinglulu 25*91f16700Schasinglulu num_records = (unsigned int) 26*91f16700Schasinglulu (mmio_read_32(ERR_DEVID(base, size_num_k)) & ERR_DEVID_MASK); 27*91f16700Schasinglulu 28*91f16700Schasinglulu /* A group register shows error status for 2^6 error records */ 29*91f16700Schasinglulu num_group_regs = (num_records >> 6U) + 1U; 30*91f16700Schasinglulu 31*91f16700Schasinglulu /* Iterate through group registers to find a record in error */ 32*91f16700Schasinglulu for (i = 0; i < num_group_regs; i++) { 33*91f16700Schasinglulu gsr = mmio_read_64(ERR_GSR(base, size_num_k, i)); 34*91f16700Schasinglulu if (gsr == 0ULL) 35*91f16700Schasinglulu continue; 36*91f16700Schasinglulu 37*91f16700Schasinglulu /* Return the index of the record in error */ 38*91f16700Schasinglulu if (probe_data != NULL) 39*91f16700Schasinglulu *probe_data = (((int) (i << 6U)) + __builtin_ctzll(gsr)); 40*91f16700Schasinglulu 41*91f16700Schasinglulu return 1; 42*91f16700Schasinglulu } 43*91f16700Schasinglulu 44*91f16700Schasinglulu return 0; 45*91f16700Schasinglulu } 46*91f16700Schasinglulu 47*91f16700Schasinglulu /* 48*91f16700Schasinglulu * Probe for error in System Registers where error records are implemented in 49*91f16700Schasinglulu * Standard Error Record format. Upon detecting an error, set probe data to the 50*91f16700Schasinglulu * index of the record in error, and return 1; otherwise, return 0. 51*91f16700Schasinglulu */ 52*91f16700Schasinglulu int ser_probe_sysreg(unsigned int idx_start, unsigned int num_idx, int *probe_data) 53*91f16700Schasinglulu { 54*91f16700Schasinglulu unsigned int i; 55*91f16700Schasinglulu uint64_t status; 56*91f16700Schasinglulu unsigned int max_idx __unused = 57*91f16700Schasinglulu ((unsigned int) read_erridr_el1()) & ERRIDR_MASK; 58*91f16700Schasinglulu 59*91f16700Schasinglulu assert(idx_start < max_idx); 60*91f16700Schasinglulu assert(check_u32_overflow(idx_start, num_idx) == 0); 61*91f16700Schasinglulu assert((idx_start + num_idx - 1U) < max_idx); 62*91f16700Schasinglulu 63*91f16700Schasinglulu for (i = 0; i < num_idx; i++) { 64*91f16700Schasinglulu /* Select the error record */ 65*91f16700Schasinglulu ser_sys_select_record(idx_start + i); 66*91f16700Schasinglulu 67*91f16700Schasinglulu /* Retrieve status register from the error record */ 68*91f16700Schasinglulu status = read_erxstatus_el1(); 69*91f16700Schasinglulu 70*91f16700Schasinglulu /* Check for valid field in status */ 71*91f16700Schasinglulu if (ERR_STATUS_GET_FIELD(status, V) != 0U) { 72*91f16700Schasinglulu if (probe_data != NULL) 73*91f16700Schasinglulu *probe_data = (int) i; 74*91f16700Schasinglulu return 1; 75*91f16700Schasinglulu } 76*91f16700Schasinglulu } 77*91f16700Schasinglulu 78*91f16700Schasinglulu return 0; 79*91f16700Schasinglulu } 80