blob: 874fc22db8337d6e7e3074c90feb0be9eca557cd [file] [log] [blame]
Jeenu Viswambharan04e3a7f2017-10-16 08:43:14 +01001/*
Jeenu Viswambharan34392302018-01-17 12:30:11 +00002 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
Jeenu Viswambharan04e3a7f2017-10-16 08:43:14 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef __SDEI_PRIVATE_H__
8#define __SDEI_PRIVATE_H__
9
10#include <arch_helpers.h>
Jeenu Viswambharan061e9f52018-06-21 08:47:42 +010011#include <context_mgmt.h>
Jeenu Viswambharan04e3a7f2017-10-16 08:43:14 +010012#include <debug.h>
13#include <errno.h>
14#include <interrupt_mgmt.h>
15#include <platform.h>
16#include <sdei.h>
Jeenu Viswambharan8b7e6bc2018-02-16 12:07:48 +000017#include <setjmp.h>
Jeenu Viswambharan04e3a7f2017-10-16 08:43:14 +010018#include <spinlock.h>
19#include <stdbool.h>
20#include <types.h>
21#include <utils_def.h>
22
23#ifdef AARCH32
24# error SDEI is implemented only for AArch64 systems
25#endif
26
27#ifndef PLAT_SDEI_CRITICAL_PRI
28# error Platform must define SDEI critical priority value
29#endif
30
31#ifndef PLAT_SDEI_NORMAL_PRI
32# error Platform must define SDEI normal priority value
33#endif
34
35/* Output SDEI logs as verbose */
36#define SDEI_LOG(...) VERBOSE("SDEI: " __VA_ARGS__)
37
38/* SDEI handler unregistered state. This is the default state. */
39#define SDEI_STATE_UNREGISTERED 0
40
41/* SDE event status values in bit position */
42#define SDEI_STATF_REGISTERED 0
43#define SDEI_STATF_ENABLED 1
44#define SDEI_STATF_RUNNING 2
45
46/* SDEI SMC error codes */
47#define SDEI_EINVAL (-2)
48#define SDEI_EDENY (-3)
49#define SDEI_EPEND (-5)
50#define SDEI_ENOMEM (-10)
51
52/*
53 * 'info' parameter to SDEI_EVENT_GET_INFO SMC.
54 *
55 * Note that the SDEI v1.0 speification mistakenly enumerates the
56 * SDEI_INFO_EV_SIGNALED as SDEI_INFO_SIGNALED. This will be corrected in a
57 * future version.
58 */
59#define SDEI_INFO_EV_TYPE 0
60#define SDEI_INFO_EV_NOT_SIGNALED 1
61#define SDEI_INFO_EV_PRIORITY 2
62#define SDEI_INFO_EV_ROUTING_MODE 3
63#define SDEI_INFO_EV_ROUTING_AFF 4
64
65#define SDEI_PRIVATE_MAPPING() (&sdei_global_mappings[_SDEI_MAP_IDX_PRIV])
66#define SDEI_SHARED_MAPPING() (&sdei_global_mappings[_SDEI_MAP_IDX_SHRD])
67
68#define for_each_mapping_type(_i, _mapping) \
69 for (_i = 0, _mapping = &sdei_global_mappings[i]; \
70 _i < _SDEI_MAP_IDX_MAX; \
71 _i++, _mapping = &sdei_global_mappings[i])
72
73#define iterate_mapping(_mapping, _i, _map) \
74 for (_map = (_mapping)->map, _i = 0; \
75 _i < (_mapping)->num_maps; \
76 _i++, _map++)
77
78#define for_each_private_map(_i, _map) \
79 iterate_mapping(SDEI_PRIVATE_MAPPING(), _i, _map)
80
81#define for_each_shared_map(_i, _map) \
82 iterate_mapping(SDEI_SHARED_MAPPING(), _i, _map)
83
84/* SDEI_FEATURES */
85#define SDEI_FEATURE_BIND_SLOTS 0
86#define BIND_SLOTS_MASK 0xffff
87#define FEATURES_SHARED_SLOTS_SHIFT 16
88#define FEATURES_PRIVATE_SLOTS_SHIFT 0
89#define FEATURE_BIND_SLOTS(_priv, _shrd) \
90 ((((_priv) & BIND_SLOTS_MASK) << FEATURES_PRIVATE_SLOTS_SHIFT) | \
91 (((_shrd) & BIND_SLOTS_MASK) << FEATURES_SHARED_SLOTS_SHIFT))
92
93#define GET_EV_STATE(_e, _s) get_ev_state_bit(_e, SDEI_STATF_##_s)
94#define SET_EV_STATE(_e, _s) clr_ev_state_bit(_e->state, SDEI_STATF_##_s)
95
96static inline int is_event_private(sdei_ev_map_t *map)
97{
98 return ((map->map_flags & BIT(_SDEI_MAPF_PRIVATE_SHIFT)) != 0);
99}
100
101static inline int is_event_shared(sdei_ev_map_t *map)
102{
103 return !is_event_private(map);
104}
105
106static inline int is_event_critical(sdei_ev_map_t *map)
107{
108 return ((map->map_flags & BIT(_SDEI_MAPF_CRITICAL_SHIFT)) != 0);
109}
110
111static inline int is_event_normal(sdei_ev_map_t *map)
112{
113 return !is_event_critical(map);
114}
115
116static inline int is_event_signalable(sdei_ev_map_t *map)
117{
118 return ((map->map_flags & BIT(_SDEI_MAPF_SIGNALABLE_SHIFT)) != 0);
119}
120
121static inline int is_map_dynamic(sdei_ev_map_t *map)
122{
123 return ((map->map_flags & BIT(_SDEI_MAPF_DYNAMIC_SHIFT)) != 0);
124}
125
126/*
127 * Checks whether an event is associated with an interrupt. Static events always
128 * return true, and dynamic events return whether SDEI_INTERRUPT_BIND had been
129 * called on them. This can be used on both static or dynamic events to check
130 * for an associated interrupt.
131 */
132static inline int is_map_bound(sdei_ev_map_t *map)
133{
134 return ((map->map_flags & BIT(_SDEI_MAPF_BOUND_SHIFT)) != 0);
135}
136
137static inline void set_map_bound(sdei_ev_map_t *map)
138{
139 map->map_flags |= BIT(_SDEI_MAPF_BOUND_SHIFT);
140}
141
Jeenu Viswambharan34392302018-01-17 12:30:11 +0000142static inline int is_map_explicit(sdei_ev_map_t *map)
143{
144 return ((map->map_flags & BIT(_SDEI_MAPF_EXPLICIT_SHIFT)) != 0);
145}
146
Jeenu Viswambharan04e3a7f2017-10-16 08:43:14 +0100147static inline void clr_map_bound(sdei_ev_map_t *map)
148{
149 map->map_flags &= ~(BIT(_SDEI_MAPF_BOUND_SHIFT));
150}
151
152static inline int is_secure_sgi(unsigned int intr)
153{
154 return (plat_ic_is_sgi(intr) &&
155 (plat_ic_get_interrupt_type(intr) == INTR_TYPE_EL3));
156}
157
158/*
159 * Determine EL of the client. If EL2 is implemented (hence the enabled HCE
160 * bit), deem EL2; otherwise, deem EL1.
161 */
162static inline unsigned int sdei_client_el(void)
163{
Jeenu Viswambharan061e9f52018-06-21 08:47:42 +0100164 cpu_context_t *ns_ctx = cm_get_context(NON_SECURE);
165 el3_state_t *el3_ctx = get_el3state_ctx(ns_ctx);
166
Jeenu Viswambharane1027652018-06-22 12:00:20 +0100167 return read_ctx_reg(el3_ctx, CTX_SCR_EL3) & SCR_HCE_BIT ? MODE_EL2 :
Jeenu Viswambharan061e9f52018-06-21 08:47:42 +0100168 MODE_EL1;
Jeenu Viswambharan04e3a7f2017-10-16 08:43:14 +0100169}
170
171static inline unsigned int sdei_event_priority(sdei_ev_map_t *map)
172{
173 return is_event_critical(map) ? PLAT_SDEI_CRITICAL_PRI :
174 PLAT_SDEI_NORMAL_PRI;
175}
176
177static inline int get_ev_state_bit(sdei_entry_t *se, unsigned int bit_no)
178{
179 return ((se->state & BIT(bit_no)) != 0);
180}
181
182static inline void clr_ev_state_bit(sdei_entry_t *se, unsigned int bit_no)
183{
184 se->state &= ~BIT(bit_no);
185}
186
187/* SDEI actions for state transition */
188typedef enum {
189 /*
190 * Actions resulting from client requests. These directly map to SMC
191 * calls. Note that the state table columns are listed in this order
192 * too.
193 */
194 DO_REGISTER = 0,
195 DO_RELEASE = 1,
196 DO_ENABLE = 2,
197 DO_DISABLE = 3,
198 DO_UNREGISTER = 4,
199 DO_ROUTING = 5,
200 DO_CONTEXT = 6,
201 DO_COMPLETE = 7,
202 DO_COMPLETE_RESUME = 8,
203
204 /* Action for event dispatch */
205 DO_DISPATCH = 9,
206
207 DO_MAX,
208} sdei_action_t;
209
210typedef enum {
211 SDEI_NORMAL,
212 SDEI_CRITICAL
213} sdei_class_t;
214
215static inline void sdei_map_lock(sdei_ev_map_t *map)
216{
217 spin_lock(&map->lock);
218}
219
220static inline void sdei_map_unlock(sdei_ev_map_t *map)
221{
222 spin_unlock(&map->lock);
223}
224
225extern const sdei_mapping_t sdei_global_mappings[];
226extern sdei_entry_t sdei_private_event_table[];
227extern sdei_entry_t sdei_shared_event_table[];
228
229void init_sdei_state(void);
230
231sdei_ev_map_t *find_event_map_by_intr(int intr_num, int shared);
232sdei_ev_map_t *find_event_map(int ev_num);
233sdei_entry_t *get_event_entry(sdei_ev_map_t *map);
234
235int sdei_event_context(void *handle, unsigned int param);
236int sdei_event_complete(int resume, uint64_t arg);
237
238void sdei_pe_unmask(void);
239unsigned int sdei_pe_mask(void);
240
241int sdei_intr_handler(uint32_t intr, uint32_t flags, void *handle,
242 void *cookie);
243bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act);
Jeenu Viswambharan8b7e6bc2018-02-16 12:07:48 +0000244void begin_sdei_synchronous_dispatch(struct jmpbuf *buffer);
Jeenu Viswambharan04e3a7f2017-10-16 08:43:14 +0100245
246#endif /* __SDEI_PRIVATE_H__ */