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