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