| /* |
| * SPDX-License-Identifier: BSD-2-Clause |
| * |
| * Copyright (c) 2019 Western Digital Corporation or its affiliates. |
| * Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com> |
| */ |
| |
| #include <sbi/riscv_barrier.h> |
| #include <sbi/riscv_locks.h> |
| |
| static inline bool spin_lock_unlocked(spinlock_t lock) |
| { |
| return lock.owner == lock.next; |
| } |
| |
| bool spin_lock_check(spinlock_t *lock) |
| { |
| RISCV_FENCE(r, rw); |
| return !spin_lock_unlocked(*lock); |
| } |
| |
| bool spin_trylock(spinlock_t *lock) |
| { |
| unsigned long inc = 1u << TICKET_SHIFT; |
| unsigned long mask = 0xffffu << TICKET_SHIFT; |
| u32 l0, tmp1, tmp2; |
| |
| __asm__ __volatile__( |
| /* Get the current lock counters. */ |
| "1: lr.w.aq %0, %3\n" |
| " slli %2, %0, %6\n" |
| " and %2, %2, %5\n" |
| " and %1, %0, %5\n" |
| /* Is the lock free right now? */ |
| " bne %1, %2, 2f\n" |
| " add %0, %0, %4\n" |
| /* Acquire the lock. */ |
| " sc.w.rl %0, %0, %3\n" |
| " bnez %0, 1b\n" |
| "2:" |
| : "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock) |
| : "r"(inc), "r"(mask), "I"(TICKET_SHIFT) |
| : "memory"); |
| |
| return l0 == 0; |
| } |
| |
| void spin_lock(spinlock_t *lock) |
| { |
| unsigned long inc = 1u << TICKET_SHIFT; |
| unsigned long mask = 0xffffu; |
| u32 l0, tmp1, tmp2; |
| |
| __asm__ __volatile__( |
| /* Atomically increment the next ticket. */ |
| " amoadd.w.aqrl %0, %4, %3\n" |
| |
| /* Did we get the lock? */ |
| " srli %1, %0, %6\n" |
| " and %1, %1, %5\n" |
| "1: and %2, %0, %5\n" |
| " beq %1, %2, 2f\n" |
| |
| /* If not, then spin on the lock. */ |
| " lw %0, %3\n" |
| RISCV_ACQUIRE_BARRIER |
| " j 1b\n" |
| "2:" |
| : "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock) |
| : "r"(inc), "r"(mask), "I"(TICKET_SHIFT) |
| : "memory"); |
| } |
| |
| void spin_unlock(spinlock_t *lock) |
| { |
| __smp_store_release(&lock->owner, lock->owner + 1); |
| } |