xref: /arm-trusted-firmware/services/std_svc/sdei/sdei_state.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <stdbool.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <lib/cassert.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include "sdei_private.h"
13*91f16700Schasinglulu 
14*91f16700Schasinglulu /* Aliases for SDEI handler states: 'R'unning, 'E'nabled, and re'G'istered */
15*91f16700Schasinglulu #define r_		0U
16*91f16700Schasinglulu #define R_		(1u << SDEI_STATF_RUNNING)
17*91f16700Schasinglulu 
18*91f16700Schasinglulu #define e_		0U
19*91f16700Schasinglulu #define E_		(1u << SDEI_STATF_ENABLED)
20*91f16700Schasinglulu 
21*91f16700Schasinglulu #define g_		0U
22*91f16700Schasinglulu #define G_		(1u << SDEI_STATF_REGISTERED)
23*91f16700Schasinglulu 
24*91f16700Schasinglulu /* All possible composite handler states */
25*91f16700Schasinglulu #define reg_		(r_ | e_ | g_)
26*91f16700Schasinglulu #define reG_		(r_ | e_ | G_)
27*91f16700Schasinglulu #define rEg_		(r_ | E_ | g_)
28*91f16700Schasinglulu #define rEG_		(r_ | E_ | G_)
29*91f16700Schasinglulu #define Reg_		(R_ | e_ | g_)
30*91f16700Schasinglulu #define ReG_		(R_ | e_ | G_)
31*91f16700Schasinglulu #define REg_		(R_ | E_ | g_)
32*91f16700Schasinglulu #define REG_		(R_ | E_ | G_)
33*91f16700Schasinglulu 
34*91f16700Schasinglulu #define MAX_STATES	(REG_ + 1u)
35*91f16700Schasinglulu 
36*91f16700Schasinglulu /* Invalid state */
37*91f16700Schasinglulu #define	SDEI_STATE_INVALID	((sdei_state_t) (-1))
38*91f16700Schasinglulu 
39*91f16700Schasinglulu /* No change in state */
40*91f16700Schasinglulu #define	SDEI_STATE_NOP		((sdei_state_t) (-2))
41*91f16700Schasinglulu 
42*91f16700Schasinglulu #define X___		SDEI_STATE_INVALID
43*91f16700Schasinglulu #define NOP_		SDEI_STATE_NOP
44*91f16700Schasinglulu 
45*91f16700Schasinglulu /* Ensure special states don't overlap with valid ones */
46*91f16700Schasinglulu CASSERT(X___ > REG_, sdei_state_overlap_invalid);
47*91f16700Schasinglulu CASSERT(NOP_ > REG_, sdei_state_overlap_nop);
48*91f16700Schasinglulu 
49*91f16700Schasinglulu /*
50*91f16700Schasinglulu  * SDEI handler state machine: refer to sections 6.1 and 6.1.2 of the SDEI v1.0
51*91f16700Schasinglulu  * specification (ARM DEN0054A).
52*91f16700Schasinglulu  *
53*91f16700Schasinglulu  * Not all calls contribute to handler state transition. This table is also used
54*91f16700Schasinglulu  * to validate whether a call is permissible at a given handler state:
55*91f16700Schasinglulu  *
56*91f16700Schasinglulu  *  - X___ denotes a forbidden transition;
57*91f16700Schasinglulu  *  - NOP_ denotes a permitted transition, but there's no change in state;
58*91f16700Schasinglulu  *  - Otherwise, XXX_ gives the new state.
59*91f16700Schasinglulu  *
60*91f16700Schasinglulu  * DISP[atch] is a transition added for the implementation, but is not mentioned
61*91f16700Schasinglulu  * in the spec.
62*91f16700Schasinglulu  *
63*91f16700Schasinglulu  * Those calls that the spec mentions as can be made any time don't picture in
64*91f16700Schasinglulu  * this table.
65*91f16700Schasinglulu  */
66*91f16700Schasinglulu 
67*91f16700Schasinglulu static const sdei_state_t sdei_state_table[MAX_STATES][DO_MAX] = {
68*91f16700Schasinglulu /*
69*91f16700Schasinglulu  *	Action:		REG     REL	ENA	DISA	UREG	ROUT	CTX	COMP	COMPR	DISP
70*91f16700Schasinglulu  *	Notes:			[3]			[1]	[3]	[3][4]			[2]
71*91f16700Schasinglulu  */
72*91f16700Schasinglulu 	/* Handler unregistered, disabled, and not running. This is the default state. */
73*91f16700Schasinglulu /* 0 */	[reg_] = {	reG_,	NOP_,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	},
74*91f16700Schasinglulu 
75*91f16700Schasinglulu 	/* Handler unregistered and running */
76*91f16700Schasinglulu /* 4 */	[Reg_] = {	X___,	X___,	X___,	X___,	X___,	X___,	NOP_,	reg_,	reg_,	X___,	},
77*91f16700Schasinglulu 
78*91f16700Schasinglulu 	/* Handler registered */
79*91f16700Schasinglulu /* 1 */	[reG_] = {	X___,	X___,	rEG_,	NOP_,	reg_,	NOP_,	X___,	X___,	X___,	X___,	},
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 	/* Handler registered and running */
82*91f16700Schasinglulu /* 5 */	[ReG_] = {	X___,	X___,	REG_,	NOP_,	Reg_,	X___,	NOP_,	reG_,	reG_,	X___,	},
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	/* Handler registered and enabled */
85*91f16700Schasinglulu /* 3 */	[rEG_] = {	X___,	X___,	NOP_,	reG_,	reg_,	X___,	X___,	X___,	X___,	REG_,	},
86*91f16700Schasinglulu 
87*91f16700Schasinglulu 	/* Handler registered, enabled, and running */
88*91f16700Schasinglulu /* 7 */	[REG_] = {	X___,	X___,	NOP_,	ReG_,	Reg_,	X___,	NOP_,	rEG_,	rEG_,	X___,	},
89*91f16700Schasinglulu 
90*91f16700Schasinglulu 	/*
91*91f16700Schasinglulu 	 * Invalid states: no valid transition would leave the handler in these
92*91f16700Schasinglulu 	 * states; and no transition from these states is possible either.
93*91f16700Schasinglulu 	 */
94*91f16700Schasinglulu 
95*91f16700Schasinglulu 	/*
96*91f16700Schasinglulu 	 * Handler can't be enabled without being registered. I.e., XEg is
97*91f16700Schasinglulu 	 * impossible.
98*91f16700Schasinglulu 	 */
99*91f16700Schasinglulu /* 2 */	[rEg_] = {	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	},
100*91f16700Schasinglulu /* 6 */	[REg_] = {	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	},
101*91f16700Schasinglulu };
102*91f16700Schasinglulu 
103*91f16700Schasinglulu /*
104*91f16700Schasinglulu  * [1] Unregister will always also disable the event, so the new state will have
105*91f16700Schasinglulu  *     Xeg.
106*91f16700Schasinglulu  * [2] Event is considered for dispatch only when it's both registered and
107*91f16700Schasinglulu  *     enabled.
108*91f16700Schasinglulu  * [3] Never causes change in state.
109*91f16700Schasinglulu  * [4] Only allowed when running.
110*91f16700Schasinglulu  */
111*91f16700Schasinglulu 
112*91f16700Schasinglulu /*
113*91f16700Schasinglulu  * Given an action, transition the state of an event by looking up the state
114*91f16700Schasinglulu  * table above:
115*91f16700Schasinglulu  *
116*91f16700Schasinglulu  *  - Return false for invalid transition;
117*91f16700Schasinglulu  *  - Return true for valid transition that causes no change in state;
118*91f16700Schasinglulu  *  - Otherwise, update state and return true.
119*91f16700Schasinglulu  *
120*91f16700Schasinglulu  * This function assumes that the caller holds necessary locks. If the
121*91f16700Schasinglulu  * transition has constrains other than the state table describes, the caller is
122*91f16700Schasinglulu  * expected to restore the previous state. See sdei_event_register() for
123*91f16700Schasinglulu  * example.
124*91f16700Schasinglulu  */
125*91f16700Schasinglulu bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act)
126*91f16700Schasinglulu {
127*91f16700Schasinglulu 	sdei_state_t next;
128*91f16700Schasinglulu 
129*91f16700Schasinglulu 	assert(act < DO_MAX);
130*91f16700Schasinglulu 	if (se->state >= MAX_STATES) {
131*91f16700Schasinglulu 		WARN(" event state invalid: %x\n", se->state);
132*91f16700Schasinglulu 		return false;
133*91f16700Schasinglulu 	}
134*91f16700Schasinglulu 
135*91f16700Schasinglulu 	next = sdei_state_table[se->state][act];
136*91f16700Schasinglulu 	switch (next) {
137*91f16700Schasinglulu 	case SDEI_STATE_INVALID:
138*91f16700Schasinglulu 		return false;
139*91f16700Schasinglulu 
140*91f16700Schasinglulu 	case SDEI_STATE_NOP:
141*91f16700Schasinglulu 		return true;
142*91f16700Schasinglulu 
143*91f16700Schasinglulu 	default:
144*91f16700Schasinglulu 		/* Valid transition. Update state. */
145*91f16700Schasinglulu 		SDEI_LOG(" event state 0x%x => 0x%x\n", se->state, next);
146*91f16700Schasinglulu 		se->state = next;
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 		return true;
149*91f16700Schasinglulu 	}
150*91f16700Schasinglulu }
151