18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Regents of the University of California 48c2ecf20Sopenharmony_ci * Copyright (C) 2017 SiFive 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#ifndef _ASM_RISCV_SPINLOCK_H 88c2ecf20Sopenharmony_ci#define _ASM_RISCV_SPINLOCK_H 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <asm/current.h> 128c2ecf20Sopenharmony_ci#include <asm/fence.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Simple spin lock operations. These provide no fairness guarantees. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* FIXME: Replace this with a ticket lock, like MIPS. */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define arch_spin_is_locked(x) (READ_ONCE((x)->lock) != 0) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic inline void arch_spin_unlock(arch_spinlock_t *lock) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci smp_store_release(&lock->lock, 0); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic inline int arch_spin_trylock(arch_spinlock_t *lock) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci int tmp = 1, busy; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 328c2ecf20Sopenharmony_ci " amoswap.w %0, %2, %1\n" 338c2ecf20Sopenharmony_ci RISCV_ACQUIRE_BARRIER 348c2ecf20Sopenharmony_ci : "=r" (busy), "+A" (lock->lock) 358c2ecf20Sopenharmony_ci : "r" (tmp) 368c2ecf20Sopenharmony_ci : "memory"); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return !busy; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic inline void arch_spin_lock(arch_spinlock_t *lock) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci while (1) { 448c2ecf20Sopenharmony_ci if (arch_spin_is_locked(lock)) 458c2ecf20Sopenharmony_ci continue; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (arch_spin_trylock(lock)) 488c2ecf20Sopenharmony_ci break; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/***********************************************************/ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic inline void arch_read_lock(arch_rwlock_t *lock) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci int tmp; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci __asm__ __volatile__( 598c2ecf20Sopenharmony_ci "1: lr.w %1, %0\n" 608c2ecf20Sopenharmony_ci " bltz %1, 1b\n" 618c2ecf20Sopenharmony_ci " addi %1, %1, 1\n" 628c2ecf20Sopenharmony_ci " sc.w %1, %1, %0\n" 638c2ecf20Sopenharmony_ci " bnez %1, 1b\n" 648c2ecf20Sopenharmony_ci RISCV_ACQUIRE_BARRIER 658c2ecf20Sopenharmony_ci : "+A" (lock->lock), "=&r" (tmp) 668c2ecf20Sopenharmony_ci :: "memory"); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic inline void arch_write_lock(arch_rwlock_t *lock) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int tmp; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci __asm__ __volatile__( 748c2ecf20Sopenharmony_ci "1: lr.w %1, %0\n" 758c2ecf20Sopenharmony_ci " bnez %1, 1b\n" 768c2ecf20Sopenharmony_ci " li %1, -1\n" 778c2ecf20Sopenharmony_ci " sc.w %1, %1, %0\n" 788c2ecf20Sopenharmony_ci " bnez %1, 1b\n" 798c2ecf20Sopenharmony_ci RISCV_ACQUIRE_BARRIER 808c2ecf20Sopenharmony_ci : "+A" (lock->lock), "=&r" (tmp) 818c2ecf20Sopenharmony_ci :: "memory"); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic inline int arch_read_trylock(arch_rwlock_t *lock) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci int busy; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci __asm__ __volatile__( 898c2ecf20Sopenharmony_ci "1: lr.w %1, %0\n" 908c2ecf20Sopenharmony_ci " bltz %1, 1f\n" 918c2ecf20Sopenharmony_ci " addi %1, %1, 1\n" 928c2ecf20Sopenharmony_ci " sc.w %1, %1, %0\n" 938c2ecf20Sopenharmony_ci " bnez %1, 1b\n" 948c2ecf20Sopenharmony_ci RISCV_ACQUIRE_BARRIER 958c2ecf20Sopenharmony_ci "1:\n" 968c2ecf20Sopenharmony_ci : "+A" (lock->lock), "=&r" (busy) 978c2ecf20Sopenharmony_ci :: "memory"); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return !busy; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline int arch_write_trylock(arch_rwlock_t *lock) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int busy; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci __asm__ __volatile__( 1078c2ecf20Sopenharmony_ci "1: lr.w %1, %0\n" 1088c2ecf20Sopenharmony_ci " bnez %1, 1f\n" 1098c2ecf20Sopenharmony_ci " li %1, -1\n" 1108c2ecf20Sopenharmony_ci " sc.w %1, %1, %0\n" 1118c2ecf20Sopenharmony_ci " bnez %1, 1b\n" 1128c2ecf20Sopenharmony_ci RISCV_ACQUIRE_BARRIER 1138c2ecf20Sopenharmony_ci "1:\n" 1148c2ecf20Sopenharmony_ci : "+A" (lock->lock), "=&r" (busy) 1158c2ecf20Sopenharmony_ci :: "memory"); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return !busy; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline void arch_read_unlock(arch_rwlock_t *lock) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci __asm__ __volatile__( 1238c2ecf20Sopenharmony_ci RISCV_RELEASE_BARRIER 1248c2ecf20Sopenharmony_ci " amoadd.w x0, %1, %0\n" 1258c2ecf20Sopenharmony_ci : "+A" (lock->lock) 1268c2ecf20Sopenharmony_ci : "r" (-1) 1278c2ecf20Sopenharmony_ci : "memory"); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline void arch_write_unlock(arch_rwlock_t *lock) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci smp_store_release(&lock->lock, 0); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#endif /* _ASM_RISCV_SPINLOCK_H */ 136