aboutsummaryrefslogtreecommitdiff
path: root/include/services/sdei.h
blob: 4d0fd3fd34ace9209ab27e0e341b05427fdf0fe3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef SDEI_H
#define SDEI_H

#include <spinlock.h>
#include <utils_def.h>

/* Range 0xC4000020 - 0xC400003F reserved for SDE 64bit smc calls */
#define SDEI_VERSION				0xC4000020U
#define SDEI_EVENT_REGISTER			0xC4000021U
#define SDEI_EVENT_ENABLE			0xC4000022U
#define SDEI_EVENT_DISABLE			0xC4000023U
#define SDEI_EVENT_CONTEXT			0xC4000024U
#define SDEI_EVENT_COMPLETE			0xC4000025U
#define SDEI_EVENT_COMPLETE_AND_RESUME		0xC4000026U

#define SDEI_EVENT_UNREGISTER			0xC4000027U
#define SDEI_EVENT_STATUS			0xC4000028U
#define SDEI_EVENT_GET_INFO			0xC4000029U
#define SDEI_EVENT_ROUTING_SET			0xC400002AU
#define SDEI_PE_MASK				0xC400002BU
#define SDEI_PE_UNMASK				0xC400002CU

#define SDEI_INTERRUPT_BIND			0xC400002DU
#define SDEI_INTERRUPT_RELEASE			0xC400002EU
#define SDEI_EVENT_SIGNAL			0xC400002FU
#define SDEI_FEATURES				0xC4000030U
#define SDEI_PRIVATE_RESET			0xC4000031U
#define SDEI_SHARED_RESET			0xC4000032U

/* SDEI_EVENT_REGISTER flags */
#define SDEI_REGF_RM_ANY	0ULL
#define SDEI_REGF_RM_PE		1ULL

/* SDEI_EVENT_COMPLETE status flags */
#define SDEI_EV_HANDLED		0U
#define SDEI_EV_FAILED		1U

/* Internal: SDEI flag bit positions */
#define SDEI_MAPF_DYNAMIC_SHIFT_	1U
#define SDEI_MAPF_BOUND_SHIFT_		2U
#define SDEI_MAPF_SIGNALABLE_SHIFT_	3U
#define SDEI_MAPF_PRIVATE_SHIFT_	4U
#define SDEI_MAPF_CRITICAL_SHIFT_	5U
#define SDEI_MAPF_EXPLICIT_SHIFT_	6U

/* SDEI event 0 */
#define SDEI_EVENT_0	0

/* Placeholder interrupt for dynamic mapping */
#define SDEI_DYN_IRQ	0U

/* SDEI flags */

/*
 * These flags determine whether or not an event can be associated with an
 * interrupt. Static events are permanently associated with an interrupt, and
 * can't be changed at runtime.  Association of dynamic events with interrupts
 * can be changed at run time using the SDEI_INTERRUPT_BIND and
 * SDEI_INTERRUPT_RELEASE calls.
 *
 * SDEI_MAPF_DYNAMIC only indicates run time configurability, where as
 * SDEI_MAPF_BOUND indicates interrupt association. For example:
 *
 *  - Calling SDEI_INTERRUPT_BIND on a dynamic event will have both
 *    SDEI_MAPF_DYNAMIC and SDEI_MAPF_BOUND set.
 *
 *  - Statically-bound events will always have SDEI_MAPF_BOUND set, and neither
 *    SDEI_INTERRUPT_BIND nor SDEI_INTERRUPT_RELEASE can be called on them.
 *
 * See also the is_map_bound() macro.
 */
#define SDEI_MAPF_DYNAMIC	BIT(SDEI_MAPF_DYNAMIC_SHIFT_)
#define SDEI_MAPF_BOUND		BIT(SDEI_MAPF_BOUND_SHIFT_)
#define SDEI_MAPF_EXPLICIT	BIT(SDEI_MAPF_EXPLICIT_SHIFT_)

#define SDEI_MAPF_SIGNALABLE	BIT(SDEI_MAPF_SIGNALABLE_SHIFT_)
#define SDEI_MAPF_PRIVATE	BIT(SDEI_MAPF_PRIVATE_SHIFT_)

#define SDEI_MAPF_NORMAL	0
#define SDEI_MAPF_CRITICAL	BIT(SDEI_MAPF_CRITICAL_SHIFT_)

/* Indices of private and shared mappings */
#define SDEI_MAP_IDX_PRIV_	0U
#define SDEI_MAP_IDX_SHRD_	1U
#define SDEI_MAP_IDX_MAX_	2U

/* The macros below are used to identify SDEI calls from the SMC function ID */
#define SDEI_FID_MASK		U(0xffe0)
#define SDEI_FID_VALUE		U(0x20)
#define is_sdei_fid(_fid) \
	((((_fid) & SDEI_FID_MASK) == SDEI_FID_VALUE) && \
	 (((_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64))

#define SDEI_EVENT_MAP(_event, _intr, _flags) \
	{ \
		.ev_num = (_event), \
		.intr = (_intr), \
		.map_flags = (_flags) \
	}

#define SDEI_SHARED_EVENT(_event, _intr, _flags) \
	SDEI_EVENT_MAP(_event, _intr, _flags)

#define SDEI_PRIVATE_EVENT(_event, _intr, _flags) \
	SDEI_EVENT_MAP(_event, _intr, (_flags) | SDEI_MAPF_PRIVATE)

#define SDEI_DEFINE_EVENT_0(_intr) \
	SDEI_PRIVATE_EVENT(SDEI_EVENT_0, (_intr), SDEI_MAPF_SIGNALABLE)

#define SDEI_EXPLICIT_EVENT(_event, _pri) \
	SDEI_EVENT_MAP((_event), 0, (_pri) | SDEI_MAPF_EXPLICIT | SDEI_MAPF_PRIVATE)

/*
 * Declare shared and private entries for each core. Also declare a global
 * structure containing private and share entries.
 *
 * This macro must be used in the same file as the platform SDEI mappings are
 * declared. Only then would ARRAY_SIZE() yield a meaningful value.
 */
#define REGISTER_SDEI_MAP(_private, _shared) \
	sdei_entry_t sdei_private_event_table \
		[PLATFORM_CORE_COUNT * ARRAY_SIZE(_private)]; \
	sdei_entry_t sdei_shared_event_table[ARRAY_SIZE(_shared)]; \
	const sdei_mapping_t sdei_global_mappings[] = { \
		[SDEI_MAP_IDX_PRIV_] = { \
			.map = (_private), \
			.num_maps = ARRAY_SIZE(_private) \
		}, \
		[SDEI_MAP_IDX_SHRD_] = { \
			.map = (_shared), \
			.num_maps = ARRAY_SIZE(_shared) \
		}, \
	}

typedef uint8_t sdei_state_t;

/* Runtime data of SDEI event */
typedef struct sdei_entry {
	uint64_t ep;		/* Entry point */
	uint64_t arg;		/* Entry point argument */
	uint64_t affinity;	/* Affinity of shared event */
	unsigned int reg_flags;	/* Registration flags */

	/* Event handler states: registered, enabled, running */
	sdei_state_t state;
} sdei_entry_t;

/* Mapping of SDEI events to interrupts, and associated data */
typedef struct sdei_ev_map {
	int32_t ev_num;		/* Event number */
	unsigned int intr;	/* Physical interrupt number for a bound map */
	unsigned int map_flags;	/* Mapping flags, see SDEI_MAPF_* */
	int reg_count;		/* Registration count */
	spinlock_t lock;	/* Per-event lock */
} sdei_ev_map_t;

typedef struct sdei_mapping {
	sdei_ev_map_t *map;
	size_t num_maps;
} sdei_mapping_t;

/* Handler to be called to handle SDEI smc calls */
uint64_t sdei_smc_handler(uint32_t smc_fid,
		uint64_t x1,
		uint64_t x2,
		uint64_t x3,
		uint64_t x4,
		void *cookie,
		void *handle,
		uint64_t flags);

void sdei_init(void);

/* Public API to dispatch an event to Normal world */
int sdei_dispatch_event(int ev_num);

#endif /* SDEI_H */