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 */ 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