Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 1 | /* |
Rohit Mathew | a0dd307 | 2024-02-03 17:22:54 +0000 | [diff] [blame] | 2 | * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved. |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 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> |
Rohit Mathew | a0dd307 | 2024-02-03 17:22:54 +0000 | [diff] [blame] | 14 | #include <nrd_ras.h> |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 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 | */ |
Rohit Mathew | 0ec6ed9 | 2024-02-03 18:39:10 +0000 | [diff] [blame] | 25 | typedef struct nrd_sram_err_info { |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 26 | uint32_t err_status; |
| 27 | uint32_t err_code; |
| 28 | uint32_t err_addr; |
Rohit Mathew | 0ec6ed9 | 2024-02-03 18:39:10 +0000 | [diff] [blame] | 29 | } nrd_sram_err_info_t; |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 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 */ |
Rohit Mathew | 0ec6ed9 | 2024-02-03 18:39:10 +0000 | [diff] [blame] | 41 | int nrd_ras_sram_intr_handler(const struct err_record_info *err_rec, |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 42 | int probe_data, |
| 43 | const struct err_handler_data *const data) |
| 44 | { |
Rohit Mathew | 0ec6ed9 | 2024-02-03 18:39:10 +0000 | [diff] [blame] | 45 | struct nrd_ras_ev_map *ras_map; |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 46 | mm_communicate_header_t *header; |
Rohit Mathew | 0ec6ed9 | 2024-02-03 18:39:10 +0000 | [diff] [blame] | 47 | nrd_sram_err_info_t sram_info; |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 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 | |
Rohit Mathew | 6521c1d | 2024-02-03 22:23:25 +0000 | [diff] [blame^] | 55 | INFO("NRD: Base element RAM interrupt [%d] handler\n", intr); |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 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 | */ |
Rohit Mathew | 0ec6ed9 | 2024-02-03 18:39:10 +0000 | [diff] [blame] | 90 | ras_map = nrd_find_ras_event_map_by_intr(intr); |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 91 | if (ras_map == NULL) { |
Rohit Mathew | 6521c1d | 2024-02-03 22:23:25 +0000 | [diff] [blame^] | 92 | ERROR("NRD: RAS error info for interrupt id: %d not found\n", |
Omkar Anand Kulkarni | 43525c4 | 2023-05-31 12:14:10 +0530 | [diff] [blame] | 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 | } |