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