blob: b1007003da4b0046ae9ba8b495eb8e03903904f4 [file] [log] [blame]
Omkar Anand Kulkarni43525c42023-05-31 12:14:10 +05301/*
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 */
25typedef 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 */
35struct 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 */
41int 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}