/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __SDEI_PRIVATE_H__ #define __SDEI_PRIVATE_H__ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AARCH32 # error SDEI is implemented only for AArch64 systems #endif #ifndef PLAT_SDEI_CRITICAL_PRI # error Platform must define SDEI critical priority value #endif #ifndef PLAT_SDEI_NORMAL_PRI # error Platform must define SDEI normal priority value #endif /* Output SDEI logs as verbose */ #define SDEI_LOG(...) VERBOSE("SDEI: " __VA_ARGS__) /* SDEI handler unregistered state. This is the default state. */ #define SDEI_STATE_UNREGISTERED 0 /* SDE event status values in bit position */ #define SDEI_STATF_REGISTERED 0 #define SDEI_STATF_ENABLED 1 #define SDEI_STATF_RUNNING 2 /* SDEI SMC error codes */ #define SDEI_EINVAL (-2) #define SDEI_EDENY (-3) #define SDEI_EPEND (-5) #define SDEI_ENOMEM (-10) /* * 'info' parameter to SDEI_EVENT_GET_INFO SMC. * * Note that the SDEI v1.0 speification mistakenly enumerates the * SDEI_INFO_EV_SIGNALED as SDEI_INFO_SIGNALED. This will be corrected in a * future version. */ #define SDEI_INFO_EV_TYPE 0 #define SDEI_INFO_EV_NOT_SIGNALED 1 #define SDEI_INFO_EV_PRIORITY 2 #define SDEI_INFO_EV_ROUTING_MODE 3 #define SDEI_INFO_EV_ROUTING_AFF 4 #define SDEI_PRIVATE_MAPPING() (&sdei_global_mappings[_SDEI_MAP_IDX_PRIV]) #define SDEI_SHARED_MAPPING() (&sdei_global_mappings[_SDEI_MAP_IDX_SHRD]) #define for_each_mapping_type(_i, _mapping) \ for (_i = 0, _mapping = &sdei_global_mappings[i]; \ _i < _SDEI_MAP_IDX_MAX; \ _i++, _mapping = &sdei_global_mappings[i]) #define iterate_mapping(_mapping, _i, _map) \ for (_map = (_mapping)->map, _i = 0; \ _i < (_mapping)->num_maps; \ _i++, _map++) #define for_each_private_map(_i, _map) \ iterate_mapping(SDEI_PRIVATE_MAPPING(), _i, _map) #define for_each_shared_map(_i, _map) \ iterate_mapping(SDEI_SHARED_MAPPING(), _i, _map) /* SDEI_FEATURES */ #define SDEI_FEATURE_BIND_SLOTS 0 #define BIND_SLOTS_MASK 0xffff #define FEATURES_SHARED_SLOTS_SHIFT 16 #define FEATURES_PRIVATE_SLOTS_SHIFT 0 #define FEATURE_BIND_SLOTS(_priv, _shrd) \ ((((_priv) & BIND_SLOTS_MASK) << FEATURES_PRIVATE_SLOTS_SHIFT) | \ (((_shrd) & BIND_SLOTS_MASK) << FEATURES_SHARED_SLOTS_SHIFT)) #define GET_EV_STATE(_e, _s) get_ev_state_bit(_e, SDEI_STATF_##_s) #define SET_EV_STATE(_e, _s) clr_ev_state_bit(_e->state, SDEI_STATF_##_s) static inline int is_event_private(sdei_ev_map_t *map) { return ((map->map_flags & BIT(_SDEI_MAPF_PRIVATE_SHIFT)) != 0); } static inline int is_event_shared(sdei_ev_map_t *map) { return !is_event_private(map); } static inline int is_event_critical(sdei_ev_map_t *map) { return ((map->map_flags & BIT(_SDEI_MAPF_CRITICAL_SHIFT)) != 0); } static inline int is_event_normal(sdei_ev_map_t *map) { return !is_event_critical(map); } static inline int is_event_signalable(sdei_ev_map_t *map) { return ((map->map_flags & BIT(_SDEI_MAPF_SIGNALABLE_SHIFT)) != 0); } static inline int is_map_dynamic(sdei_ev_map_t *map) { return ((map->map_flags & BIT(_SDEI_MAPF_DYNAMIC_SHIFT)) != 0); } /* * Checks whether an event is associated with an interrupt. Static events always * return true, and dynamic events return whether SDEI_INTERRUPT_BIND had been * called on them. This can be used on both static or dynamic events to check * for an associated interrupt. */ static inline int is_map_bound(sdei_ev_map_t *map) { return ((map->map_flags & BIT(_SDEI_MAPF_BOUND_SHIFT)) != 0); } static inline void set_map_bound(sdei_ev_map_t *map) { map->map_flags |= BIT(_SDEI_MAPF_BOUND_SHIFT); } static inline int is_map_explicit(sdei_ev_map_t *map) { return ((map->map_flags & BIT(_SDEI_MAPF_EXPLICIT_SHIFT)) != 0); } static inline void clr_map_bound(sdei_ev_map_t *map) { map->map_flags &= ~(BIT(_SDEI_MAPF_BOUND_SHIFT)); } static inline int is_secure_sgi(unsigned int intr) { return (plat_ic_is_sgi(intr) && (plat_ic_get_interrupt_type(intr) == INTR_TYPE_EL3)); } /* * Determine EL of the client. If EL2 is implemented (hence the enabled HCE * bit), deem EL2; otherwise, deem EL1. */ static inline unsigned int sdei_client_el(void) { cpu_context_t *ns_ctx = cm_get_context(NON_SECURE); el3_state_t *el3_ctx = get_el3state_ctx(ns_ctx); return read_ctx_reg(el3_ctx, CTX_SPSR_EL3) & SCR_HCE_BIT ? MODE_EL2 : MODE_EL1; } static inline unsigned int sdei_event_priority(sdei_ev_map_t *map) { return is_event_critical(map) ? PLAT_SDEI_CRITICAL_PRI : PLAT_SDEI_NORMAL_PRI; } static inline int get_ev_state_bit(sdei_entry_t *se, unsigned int bit_no) { return ((se->state & BIT(bit_no)) != 0); } static inline void clr_ev_state_bit(sdei_entry_t *se, unsigned int bit_no) { se->state &= ~BIT(bit_no); } /* SDEI actions for state transition */ typedef enum { /* * Actions resulting from client requests. These directly map to SMC * calls. Note that the state table columns are listed in this order * too. */ DO_REGISTER = 0, DO_RELEASE = 1, DO_ENABLE = 2, DO_DISABLE = 3, DO_UNREGISTER = 4, DO_ROUTING = 5, DO_CONTEXT = 6, DO_COMPLETE = 7, DO_COMPLETE_RESUME = 8, /* Action for event dispatch */ DO_DISPATCH = 9, DO_MAX, } sdei_action_t; typedef enum { SDEI_NORMAL, SDEI_CRITICAL } sdei_class_t; static inline void sdei_map_lock(sdei_ev_map_t *map) { spin_lock(&map->lock); } static inline void sdei_map_unlock(sdei_ev_map_t *map) { spin_unlock(&map->lock); } extern const sdei_mapping_t sdei_global_mappings[]; extern sdei_entry_t sdei_private_event_table[]; extern sdei_entry_t sdei_shared_event_table[]; void init_sdei_state(void); sdei_ev_map_t *find_event_map_by_intr(int intr_num, int shared); sdei_ev_map_t *find_event_map(int ev_num); sdei_entry_t *get_event_entry(sdei_ev_map_t *map); int sdei_event_context(void *handle, unsigned int param); int sdei_event_complete(int resume, uint64_t arg); void sdei_pe_unmask(void); unsigned int sdei_pe_mask(void); int sdei_intr_handler(uint32_t intr, uint32_t flags, void *handle, void *cookie); bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act); void begin_sdei_synchronous_dispatch(struct jmpbuf *buffer); #endif /* __SDEI_PRIVATE_H__ */