xref: /arm-trusted-firmware/plat/arm/css/sgi/ras/sgi_ras_sram.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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