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