1 /*
2 * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8
9 #include <lib/utils.h>
10
11 #include "sdei_private.h"
12
13 #define MAP_OFF(_map, _mapping) ((_map) - (_mapping)->map)
14
15 /*
16 * Get SDEI entry with the given mapping: on success, returns pointer to SDEI
17 * entry. On error, returns NULL.
18 *
19 * Both shared and private maps are stored in single-dimensional array. Private
20 * event entries are kept for each PE forming a 2D array.
21 */
get_event_entry(const sdei_ev_map_t * map)22 sdei_entry_t *get_event_entry(const sdei_ev_map_t *map)
23 {
24 const sdei_mapping_t *mapping;
25 sdei_entry_t *cpu_priv_base;
26 unsigned int base_idx;
27 long int idx;
28
29 if ((map->map_flags & BIT_32(SDEI_MAPF_PRIVATE_SHIFT_)) != 0U) {
30 /*
31 * For a private map, find the index of the mapping in the
32 * array.
33 */
34 mapping = SDEI_PRIVATE_MAPPING();
35 idx = MAP_OFF(map, mapping);
36
37 /* Base of private mappings for this CPU */
38 base_idx = plat_my_core_pos() * ((unsigned int) mapping->num_maps);
39 cpu_priv_base = &sdei_private_event_table[base_idx];
40
41 /*
42 * Return the address of the entry at the same index in the
43 * per-CPU event entry.
44 */
45 return &cpu_priv_base[idx];
46 } else {
47 mapping = SDEI_SHARED_MAPPING();
48 idx = MAP_OFF(map, mapping);
49
50 return &sdei_shared_event_table[idx];
51 }
52 }
53
54 /*
55 * Retrieve the SDEI entry for the given mapping and target PE.
56 *
57 * on success : Returns a pointer to the SDEI entry
58 *
59 * On error, returns NULL
60 *
61 * Both shared and private maps are stored in single-dimensional array. Private
62 * event entries are kept for each PE forming a 2D array.
63 */
get_event_entry_target_pe(long int mapsub,size_t nm,uint64_t target_pe)64 sdei_entry_t *get_event_entry_target_pe(long int mapsub, size_t nm,
65 uint64_t target_pe)
66 {
67 size_t base, uidx;
68 int target_pos;
69 const size_t table_len = (size_t)PLATFORM_CORE_COUNT * nm;
70
71 /* Base of private mappings for this CPU */
72 target_pos = plat_core_pos_by_mpidr(target_pe);
73 if ((target_pos < 0) || ((unsigned int)target_pos >= PLATFORM_CORE_COUNT)) {
74 return NULL;
75 }
76
77 if (mapsub < 0) {
78 return NULL;
79 }
80
81 uidx = (unsigned int)mapsub;
82 if (uidx >= nm) {
83 return NULL;
84 }
85
86 base = (size_t)target_pos * nm + uidx;
87 /* ensure base is in-bounds of the actual table */
88 if (base >= table_len) {
89 return NULL;
90 }
91
92 /*
93 * Return the address of the entry at the same index in the
94 * per-CPU event entry.
95 */
96 return &sdei_private_event_table[base];
97 }
98
99 /*
100 * Find event mapping for a given interrupt number: On success, returns pointer
101 * to the event mapping. On error, returns NULL.
102 */
find_event_map_by_intr(unsigned int intr_num,bool shared)103 sdei_ev_map_t *find_event_map_by_intr(unsigned int intr_num, bool shared)
104 {
105 const sdei_mapping_t *mapping;
106 sdei_ev_map_t *map;
107 unsigned int i;
108
109 /*
110 * Look for a match in private and shared mappings, as requested. This
111 * is a linear search. However, if the mappings are required to be
112 * sorted, for large maps, we could consider binary search.
113 */
114 mapping = shared ? SDEI_SHARED_MAPPING() : SDEI_PRIVATE_MAPPING();
115 iterate_mapping(mapping, i, map) {
116 if (map->intr == intr_num)
117 return map;
118 }
119
120 return NULL;
121 }
122
123 /*
124 * Find event mapping for a given event number: On success returns pointer to
125 * the event mapping. On error, returns NULL.
126 */
find_event_map(int ev_num)127 sdei_ev_map_t *find_event_map(int ev_num)
128 {
129 const sdei_mapping_t *mapping;
130 sdei_ev_map_t *map;
131 unsigned int i, j;
132
133 /*
134 * Iterate through mappings to find a match. This is a linear search.
135 * However, if the mappings are required to be sorted, for large maps,
136 * we could consider binary search.
137 */
138 for_each_mapping_type(i, mapping) {
139 iterate_mapping(mapping, j, map) {
140 if (map->ev_num == ev_num)
141 return map;
142 }
143 }
144
145 return NULL;
146 }
147
148 /*
149 * Return the total number of currently registered SDEI events.
150 */
sdei_get_registered_event_count(void)151 int sdei_get_registered_event_count(void)
152 {
153 const sdei_mapping_t *mapping;
154 sdei_ev_map_t *map;
155 unsigned int i;
156 unsigned int j;
157 int count = 0;
158
159 /* Add up reg counts for each mapping. */
160 for_each_mapping_type(i, mapping) {
161 iterate_mapping(mapping, j, map) {
162 count += map->reg_count;
163 }
164 }
165
166 return count;
167 }
168