1// Copyright 2016 The Fuchsia Authors 2// Copyright (c) 2014 Travis Geiselbrecht 3// 4// Use of this source code is governed by a MIT-style 5// license that can be found in the LICENSE file or at 6// https://opensource.org/licenses/MIT 7 8#pragma once 9 10#include <arch/arm64/interrupt.h> 11#include <arch/arm64/mp.h> 12#include <stdbool.h> 13#include <sys/types.h> 14#include <zircon/compiler.h> 15#include <zircon/thread_annotations.h> 16 17__BEGIN_CDECLS 18 19#define SPIN_LOCK_INITIAL_VALUE \ 20 (spin_lock_t) { 0 } 21 22typedef struct TA_CAP("mutex") spin_lock { 23 unsigned long value; 24} spin_lock_t; 25 26typedef unsigned int spin_lock_saved_state_t; 27typedef unsigned int spin_lock_save_flags_t; 28 29void arch_spin_lock(spin_lock_t* lock) TA_ACQ(lock); 30int arch_spin_trylock(spin_lock_t* lock) TA_TRY_ACQ(false, lock); 31void arch_spin_unlock(spin_lock_t* lock) TA_REL(lock); 32 33static inline void arch_spin_lock_init(spin_lock_t* lock) { 34 *lock = SPIN_LOCK_INITIAL_VALUE; 35} 36 37static inline uint arch_spin_lock_holder_cpu(spin_lock_t* lock) { 38 return (uint)__atomic_load_n(&lock->value, __ATOMIC_RELAXED) - 1; 39} 40 41static inline bool arch_spin_lock_held(spin_lock_t* lock) { 42 return arch_spin_lock_holder_cpu(lock) == arch_curr_cpu_num(); 43} 44 45enum { 46 /* Possible future flags: 47 * SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff, 48 * SPIN_LOCK_FLAG_PREEMPTION = 0x10000000, 49 * SPIN_LOCK_FLAG_SET_PMR = 0x20000000, 50 */ 51 52 /* ARM specific flags */ 53 SPIN_LOCK_FLAG_IRQ = 0x40000000, 54 SPIN_LOCK_FLAG_FIQ = 0x80000000, /* Do not use unless IRQs are already disabled */ 55 SPIN_LOCK_FLAG_IRQ_FIQ = SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ, 56 57 /* default arm flag is to just disable plain irqs */ 58 ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS = SPIN_LOCK_FLAG_IRQ 59}; 60 61enum { 62 /* private */ 63 SPIN_LOCK_STATE_RESTORE_IRQ = 1, 64 SPIN_LOCK_STATE_RESTORE_FIQ = 2, 65}; 66 67static inline void 68arch_interrupt_save(spin_lock_saved_state_t* statep, spin_lock_save_flags_t flags) { 69 spin_lock_saved_state_t state = 0; 70 if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) { 71 state |= SPIN_LOCK_STATE_RESTORE_IRQ; 72 arch_disable_ints(); 73 } 74 if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) { 75 state |= SPIN_LOCK_STATE_RESTORE_FIQ; 76 arch_disable_fiqs(); 77 } 78 *statep = state; 79} 80 81static inline void 82arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) { 83 if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ)) 84 arch_enable_fiqs(); 85 if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ)) 86 arch_enable_ints(); 87} 88 89__END_CDECLS 90