1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <bl31/interrupt_mgmt.h> 8*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h> 9*91f16700Schasinglulu #include <plat/common/platform.h> 10*91f16700Schasinglulu #include <services/sdei.h> 11*91f16700Schasinglulu #include <services/spm_mm_svc.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <platform_def.h> 14*91f16700Schasinglulu #include <sgi_ras.h> 15*91f16700Schasinglulu 16*91f16700Schasinglulu /* Base Element RAM Error Record offsets. */ 17*91f16700Schasinglulu #define ERRSTATUS U(0) 18*91f16700Schasinglulu #define ERRCODE U(8) 19*91f16700Schasinglulu #define ERRADDR U(12) 20*91f16700Schasinglulu 21*91f16700Schasinglulu /* 22*91f16700Schasinglulu * Base Element RAM error information data structure communicated as part of MM 23*91f16700Schasinglulu * Communication data payload. 24*91f16700Schasinglulu */ 25*91f16700Schasinglulu typedef struct sgi_sram_err_info { 26*91f16700Schasinglulu uint32_t err_status; 27*91f16700Schasinglulu uint32_t err_code; 28*91f16700Schasinglulu uint32_t err_addr; 29*91f16700Schasinglulu } sgi_sram_err_info_t; 30*91f16700Schasinglulu 31*91f16700Schasinglulu /* 32*91f16700Schasinglulu * MM Communicate message header GUID to indicate the payload is intended for 33*91f16700Schasinglulu * base element RAM MM driver. 34*91f16700Schasinglulu */ 35*91f16700Schasinglulu struct efi_guid sram_ecc_event_guid = { 36*91f16700Schasinglulu 0x7312db4f, 0xd0c4, 0x4fb5, 37*91f16700Schasinglulu { 0x81, 0x2c, 0xb7, 0x4b, 0xc6, 0xc4, 0xa9, 0x38 } 38*91f16700Schasinglulu }; 39*91f16700Schasinglulu 40*91f16700Schasinglulu /* Base element RAM RAS error interrupt handler */ 41*91f16700Schasinglulu int sgi_ras_sram_intr_handler(const struct err_record_info *err_rec, 42*91f16700Schasinglulu int probe_data, 43*91f16700Schasinglulu const struct err_handler_data *const data) 44*91f16700Schasinglulu { 45*91f16700Schasinglulu struct sgi_ras_ev_map *ras_map; 46*91f16700Schasinglulu mm_communicate_header_t *header; 47*91f16700Schasinglulu sgi_sram_err_info_t sram_info; 48*91f16700Schasinglulu uintptr_t base_addr; 49*91f16700Schasinglulu uint32_t clear_status, intr; 50*91f16700Schasinglulu int ret; 51*91f16700Schasinglulu 52*91f16700Schasinglulu cm_el1_sysregs_context_save(NON_SECURE); 53*91f16700Schasinglulu intr = data->interrupt; 54*91f16700Schasinglulu 55*91f16700Schasinglulu INFO("SGI: Base element RAM interrupt [%d] handler\n", intr); 56*91f16700Schasinglulu 57*91f16700Schasinglulu /* Determine error record base address to read. */ 58*91f16700Schasinglulu base_addr = 0; 59*91f16700Schasinglulu if (intr == NS_RAM_ECC_CE_INT || intr == NS_RAM_ECC_UE_INT) { 60*91f16700Schasinglulu base_addr = SOC_NS_RAM_ERR_REC_BASE; 61*91f16700Schasinglulu } 62*91f16700Schasinglulu sram_info.err_status = mmio_read_32(base_addr + ERRSTATUS); 63*91f16700Schasinglulu sram_info.err_code = mmio_read_32(base_addr + ERRCODE); 64*91f16700Schasinglulu sram_info.err_addr = mmio_read_32(base_addr + ERRADDR); 65*91f16700Schasinglulu 66*91f16700Schasinglulu /* Clear the interrupt. */ 67*91f16700Schasinglulu clear_status = mmio_read_32(base_addr + ERRSTATUS); 68*91f16700Schasinglulu mmio_write_32((base_addr + ERRSTATUS), clear_status); 69*91f16700Schasinglulu 70*91f16700Schasinglulu /* 71*91f16700Schasinglulu * Prepare the MM Communication buffer to pass the base element RAM 72*91f16700Schasinglulu * error information to Secure Partition. 73*91f16700Schasinglulu */ 74*91f16700Schasinglulu header = (void *)PLAT_SPM_BUF_BASE; 75*91f16700Schasinglulu memset(header, 0, sizeof(*header)); 76*91f16700Schasinglulu memcpy(&header->data, &sram_info, sizeof(sram_info)); 77*91f16700Schasinglulu header->message_len = sizeof(sram_info); 78*91f16700Schasinglulu memcpy(&header->header_guid, (void *)&sram_ecc_event_guid, 79*91f16700Schasinglulu sizeof(struct efi_guid)); 80*91f16700Schasinglulu 81*91f16700Schasinglulu spm_mm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0, 82*91f16700Schasinglulu plat_my_core_pos()); 83*91f16700Schasinglulu 84*91f16700Schasinglulu plat_ic_end_of_interrupt(intr); 85*91f16700Schasinglulu 86*91f16700Schasinglulu /* 87*91f16700Schasinglulu * Find if this is a RAS interrupt. There must be an event against 88*91f16700Schasinglulu * this interrupt 89*91f16700Schasinglulu */ 90*91f16700Schasinglulu ras_map = sgi_find_ras_event_map_by_intr(intr); 91*91f16700Schasinglulu if (ras_map == NULL) { 92*91f16700Schasinglulu ERROR("SGI: RAS error info for interrupt id: %d not found\n", 93*91f16700Schasinglulu intr); 94*91f16700Schasinglulu return -1; 95*91f16700Schasinglulu } 96*91f16700Schasinglulu 97*91f16700Schasinglulu /* Dispatch the event to the SDEI client */ 98*91f16700Schasinglulu ret = sdei_dispatch_event(ras_map->sdei_ev_num); 99*91f16700Schasinglulu if (ret != 0) { 100*91f16700Schasinglulu /* 101*91f16700Schasinglulu * sdei_dispatch_event() may return failing result in some 102*91f16700Schasinglulu * cases, for example kernel may not have registered a handler 103*91f16700Schasinglulu * or RAS event may happen early during boot. We restore the NS 104*91f16700Schasinglulu * context when sdei_dispatch_event() returns failing result. 105*91f16700Schasinglulu */ 106*91f16700Schasinglulu ERROR("SDEI dispatch failed: %d", ret); 107*91f16700Schasinglulu cm_el1_sysregs_context_restore(NON_SECURE); 108*91f16700Schasinglulu cm_set_next_eret_context(NON_SECURE); 109*91f16700Schasinglulu } 110*91f16700Schasinglulu 111*91f16700Schasinglulu return ret; 112*91f16700Schasinglulu } 113