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