1 /* 2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #ifndef __SDEI_H__ 8 #define __SDEI_H__ 9 10 #include <spinlock.h> 11 #include <utils_def.h> 12 13 /* Range 0xC4000020 - 0xC400003F reserved for SDE 64bit smc calls */ 14 #define SDEI_VERSION 0xC4000020 15 #define SDEI_EVENT_REGISTER 0xC4000021 16 #define SDEI_EVENT_ENABLE 0xC4000022 17 #define SDEI_EVENT_DISABLE 0xC4000023 18 #define SDEI_EVENT_CONTEXT 0xC4000024 19 #define SDEI_EVENT_COMPLETE 0xC4000025 20 #define SDEI_EVENT_COMPLETE_AND_RESUME 0xC4000026 21 22 #define SDEI_EVENT_UNREGISTER 0xC4000027 23 #define SDEI_EVENT_STATUS 0xC4000028 24 #define SDEI_EVENT_GET_INFO 0xC4000029 25 #define SDEI_EVENT_ROUTING_SET 0xC400002A 26 #define SDEI_PE_MASK 0xC400002B 27 #define SDEI_PE_UNMASK 0xC400002C 28 29 #define SDEI_INTERRUPT_BIND 0xC400002D 30 #define SDEI_INTERRUPT_RELEASE 0xC400002E 31 #define SDEI_EVENT_SIGNAL 0xC400002F 32 #define SDEI_FEATURES 0xC4000030 33 #define SDEI_PRIVATE_RESET 0xC4000031 34 #define SDEI_SHARED_RESET 0xC4000032 35 36 /* SDEI_EVENT_REGISTER flags */ 37 #define SDEI_REGF_RM_ANY 0 38 #define SDEI_REGF_RM_PE 1 39 40 /* SDEI_EVENT_COMPLETE status flags */ 41 #define SDEI_EV_HANDLED 0 42 #define SDEI_EV_FAILED 1 43 44 /* SDE event status values in bit position */ 45 #define SDEI_STATF_REGISTERED 0 46 #define SDEI_STATF_ENABLED 1 47 #define SDEI_STATF_RUNNING 2 48 49 /* Internal: SDEI flag bit positions */ 50 #define _SDEI_MAPF_DYNAMIC_SHIFT 1 51 #define _SDEI_MAPF_BOUND_SHIFT 2 52 #define _SDEI_MAPF_SIGNALABLE_SHIFT 3 53 #define _SDEI_MAPF_PRIVATE_SHIFT 4 54 #define _SDEI_MAPF_CRITICAL_SHIFT 5 55 #define _SDEI_MAPF_EXPLICIT_SHIFT 6 56 57 /* SDEI event 0 */ 58 #define SDEI_EVENT_0 0 59 60 /* Placeholder interrupt for dynamic mapping */ 61 #define SDEI_DYN_IRQ 0 62 63 /* SDEI flags */ 64 65 /* 66 * These flags determine whether or not an event can be associated with an 67 * interrupt. Static events are permanently associated with an interrupt, and 68 * can't be changed at runtime. Association of dynamic events with interrupts 69 * can be changed at run time using the SDEI_INTERRUPT_BIND and 70 * SDEI_INTERRUPT_RELEASE calls. 71 * 72 * SDEI_MAPF_DYNAMIC only indicates run time configurability, where as 73 * SDEI_MAPF_BOUND indicates interrupt association. For example: 74 * 75 * - Calling SDEI_INTERRUPT_BIND on a dynamic event will have both 76 * SDEI_MAPF_DYNAMIC and SDEI_MAPF_BOUND set. 77 * 78 * - Statically-bound events will always have SDEI_MAPF_BOUND set, and neither 79 * SDEI_INTERRUPT_BIND nor SDEI_INTERRUPT_RELEASE can be called on them. 80 * 81 * See also the is_map_bound() macro. 82 */ 83 #define SDEI_MAPF_DYNAMIC BIT(_SDEI_MAPF_DYNAMIC_SHIFT) 84 #define SDEI_MAPF_BOUND BIT(_SDEI_MAPF_BOUND_SHIFT) 85 #define SDEI_MAPF_EXPLICIT BIT(_SDEI_MAPF_EXPLICIT_SHIFT) 86 87 #define SDEI_MAPF_SIGNALABLE BIT(_SDEI_MAPF_SIGNALABLE_SHIFT) 88 #define SDEI_MAPF_PRIVATE BIT(_SDEI_MAPF_PRIVATE_SHIFT) 89 90 #define SDEI_MAPF_NORMAL 0 91 #define SDEI_MAPF_CRITICAL BIT(_SDEI_MAPF_CRITICAL_SHIFT) 92 93 /* Indices of private and shared mappings */ 94 #define _SDEI_MAP_IDX_PRIV 0 95 #define _SDEI_MAP_IDX_SHRD 1 96 #define _SDEI_MAP_IDX_MAX 2 97 98 /* The macros below are used to identify SDEI calls from the SMC function ID */ 99 #define SDEI_FID_MASK U(0xffe0) 100 #define SDEI_FID_VALUE U(0x20) 101 #define is_sdei_fid(_fid) \ 102 ((((_fid) & SDEI_FID_MASK) == SDEI_FID_VALUE) && \ 103 (((_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64)) 104 105 #define SDEI_EVENT_MAP(_event, _intr, _flags) \ 106 { \ 107 .ev_num = _event, \ 108 .intr = _intr, \ 109 .map_flags = _flags \ 110 } 111 112 #define SDEI_SHARED_EVENT(_event, _intr, _flags) \ 113 SDEI_EVENT_MAP(_event, _intr, _flags) 114 115 #define SDEI_PRIVATE_EVENT(_event, _intr, _flags) \ 116 SDEI_EVENT_MAP(_event, _intr, _flags | SDEI_MAPF_PRIVATE) 117 118 #define SDEI_DEFINE_EVENT_0(_intr) \ 119 SDEI_PRIVATE_EVENT(SDEI_EVENT_0, _intr, SDEI_MAPF_SIGNALABLE) 120 121 #define SDEI_EXPLICIT_EVENT(_event, _pri) \ 122 SDEI_EVENT_MAP(_event, 0, _pri | SDEI_MAPF_EXPLICIT | SDEI_MAPF_PRIVATE) 123 124 /* 125 * Declare shared and private entries for each core. Also declare a global 126 * structure containing private and share entries. 127 * 128 * This macro must be used in the same file as the platform SDEI mappings are 129 * declared. Only then would ARRAY_SIZE() yield a meaningful value. 130 */ 131 #define REGISTER_SDEI_MAP(_private, _shared) \ 132 sdei_entry_t sdei_private_event_table \ 133 [PLATFORM_CORE_COUNT * ARRAY_SIZE(_private)]; \ 134 sdei_entry_t sdei_shared_event_table[ARRAY_SIZE(_shared)]; \ 135 const sdei_mapping_t sdei_global_mappings[] = { \ 136 [_SDEI_MAP_IDX_PRIV] = { \ 137 .map = _private, \ 138 .num_maps = ARRAY_SIZE(_private) \ 139 }, \ 140 [_SDEI_MAP_IDX_SHRD] = { \ 141 .map = _shared, \ 142 .num_maps = ARRAY_SIZE(_shared) \ 143 }, \ 144 } 145 146 typedef uint8_t sdei_state_t; 147 148 /* Runtime data of SDEI event */ 149 typedef struct sdei_entry { 150 uint64_t ep; /* Entry point */ 151 uint64_t arg; /* Entry point argument */ 152 uint64_t affinity; /* Affinity of shared event */ 153 unsigned int reg_flags; /* Registration flags */ 154 155 /* Event handler states: registered, enabled, running */ 156 sdei_state_t state; 157 } sdei_entry_t; 158 159 /* Mapping of SDEI events to interrupts, and associated data */ 160 typedef struct sdei_ev_map { 161 int32_t ev_num; /* Event number */ 162 unsigned int intr; /* Physical interrupt number for a bound map */ 163 unsigned int map_flags; /* Mapping flags, see SDEI_MAPF_* */ 164 int reg_count; /* Registration count */ 165 spinlock_t lock; /* Per-event lock */ 166 } sdei_ev_map_t; 167 168 typedef struct sdei_mapping { 169 sdei_ev_map_t *map; 170 size_t num_maps; 171 } sdei_mapping_t; 172 173 /* Handler to be called to handle SDEI smc calls */ 174 uint64_t sdei_smc_handler(uint32_t smc_fid, 175 uint64_t x1, 176 uint64_t x2, 177 uint64_t x3, 178 uint64_t x4, 179 void *cookie, 180 void *handle, 181 uint64_t flags); 182 183 void sdei_init(void); 184 185 /* Public API to dispatch an event to Normal world */ 186 int sdei_dispatch_event(int ev_num); 187 188 #endif /* __SDEI_H__ */ 189