blob: 21fb0e36a2771af136aaa1859c4214067007c9d7 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2014 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#pragma once
#include <arch/arm64/interrupt.h>
#include <arch/arm64/mp.h>
#include <stdbool.h>
#include <sys/types.h>
#include <zircon/compiler.h>
#include <zircon/thread_annotations.h>
__BEGIN_CDECLS
#define SPIN_LOCK_INITIAL_VALUE \
(spin_lock_t) { 0 }
typedef struct TA_CAP("mutex") spin_lock {
unsigned long value;
} spin_lock_t;
typedef unsigned int spin_lock_saved_state_t;
typedef unsigned int spin_lock_save_flags_t;
void arch_spin_lock(spin_lock_t* lock) TA_ACQ(lock);
int arch_spin_trylock(spin_lock_t* lock) TA_TRY_ACQ(false, lock);
void arch_spin_unlock(spin_lock_t* lock) TA_REL(lock);
static inline uint arch_spin_lock_holder_cpu(spin_lock_t* lock) {
return (uint)__atomic_load_n(&lock->value, __ATOMIC_RELAXED) - 1;
}
static inline bool arch_spin_lock_held(spin_lock_t* lock) {
return arch_spin_lock_holder_cpu(lock) == arch_curr_cpu_num();
}
enum {
/* Possible future flags:
* SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff,
* SPIN_LOCK_FLAG_PREEMPTION = 0x10000000,
* SPIN_LOCK_FLAG_SET_PMR = 0x20000000,
*/
/* ARM specific flags */
SPIN_LOCK_FLAG_IRQ = 0x40000000,
SPIN_LOCK_FLAG_FIQ = 0x80000000, /* Do not use unless IRQs are already disabled */
SPIN_LOCK_FLAG_IRQ_FIQ = SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ,
/* default arm flag is to just disable plain irqs */
ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS = SPIN_LOCK_FLAG_IRQ
};
enum {
/* private */
SPIN_LOCK_STATE_RESTORE_IRQ = 1,
SPIN_LOCK_STATE_RESTORE_FIQ = 2,
};
static inline void
arch_interrupt_save(spin_lock_saved_state_t* statep, spin_lock_save_flags_t flags) {
spin_lock_saved_state_t state = 0;
if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) {
state |= SPIN_LOCK_STATE_RESTORE_IRQ;
arch_disable_ints();
}
if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) {
state |= SPIN_LOCK_STATE_RESTORE_FIQ;
arch_disable_fiqs();
}
*statep = state;
}
static inline void
arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) {
if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ))
arch_enable_fiqs();
if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ))
arch_enable_ints();
}
__END_CDECLS