at v5.0 143 lines 2.9 kB view raw
1/* 2 * Copyright (C) 2015 Regents of the University of California 3 * Copyright (C) 2017 SiFive 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation, version 2. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15#ifndef _ASM_RISCV_SPINLOCK_H 16#define _ASM_RISCV_SPINLOCK_H 17 18#include <linux/kernel.h> 19#include <asm/current.h> 20#include <asm/fence.h> 21 22/* 23 * Simple spin lock operations. These provide no fairness guarantees. 24 */ 25 26/* FIXME: Replace this with a ticket lock, like MIPS. */ 27 28#define arch_spin_is_locked(x) (READ_ONCE((x)->lock) != 0) 29 30static inline void arch_spin_unlock(arch_spinlock_t *lock) 31{ 32 smp_store_release(&lock->lock, 0); 33} 34 35static inline int arch_spin_trylock(arch_spinlock_t *lock) 36{ 37 int tmp = 1, busy; 38 39 __asm__ __volatile__ ( 40 " amoswap.w %0, %2, %1\n" 41 RISCV_ACQUIRE_BARRIER 42 : "=r" (busy), "+A" (lock->lock) 43 : "r" (tmp) 44 : "memory"); 45 46 return !busy; 47} 48 49static inline void arch_spin_lock(arch_spinlock_t *lock) 50{ 51 while (1) { 52 if (arch_spin_is_locked(lock)) 53 continue; 54 55 if (arch_spin_trylock(lock)) 56 break; 57 } 58} 59 60/***********************************************************/ 61 62static inline void arch_read_lock(arch_rwlock_t *lock) 63{ 64 int tmp; 65 66 __asm__ __volatile__( 67 "1: lr.w %1, %0\n" 68 " bltz %1, 1b\n" 69 " addi %1, %1, 1\n" 70 " sc.w %1, %1, %0\n" 71 " bnez %1, 1b\n" 72 RISCV_ACQUIRE_BARRIER 73 : "+A" (lock->lock), "=&r" (tmp) 74 :: "memory"); 75} 76 77static inline void arch_write_lock(arch_rwlock_t *lock) 78{ 79 int tmp; 80 81 __asm__ __volatile__( 82 "1: lr.w %1, %0\n" 83 " bnez %1, 1b\n" 84 " li %1, -1\n" 85 " sc.w %1, %1, %0\n" 86 " bnez %1, 1b\n" 87 RISCV_ACQUIRE_BARRIER 88 : "+A" (lock->lock), "=&r" (tmp) 89 :: "memory"); 90} 91 92static inline int arch_read_trylock(arch_rwlock_t *lock) 93{ 94 int busy; 95 96 __asm__ __volatile__( 97 "1: lr.w %1, %0\n" 98 " bltz %1, 1f\n" 99 " addi %1, %1, 1\n" 100 " sc.w %1, %1, %0\n" 101 " bnez %1, 1b\n" 102 RISCV_ACQUIRE_BARRIER 103 "1:\n" 104 : "+A" (lock->lock), "=&r" (busy) 105 :: "memory"); 106 107 return !busy; 108} 109 110static inline int arch_write_trylock(arch_rwlock_t *lock) 111{ 112 int busy; 113 114 __asm__ __volatile__( 115 "1: lr.w %1, %0\n" 116 " bnez %1, 1f\n" 117 " li %1, -1\n" 118 " sc.w %1, %1, %0\n" 119 " bnez %1, 1b\n" 120 RISCV_ACQUIRE_BARRIER 121 "1:\n" 122 : "+A" (lock->lock), "=&r" (busy) 123 :: "memory"); 124 125 return !busy; 126} 127 128static inline void arch_read_unlock(arch_rwlock_t *lock) 129{ 130 __asm__ __volatile__( 131 RISCV_RELEASE_BARRIER 132 " amoadd.w x0, %1, %0\n" 133 : "+A" (lock->lock) 134 : "r" (-1) 135 : "memory"); 136} 137 138static inline void arch_write_unlock(arch_rwlock_t *lock) 139{ 140 smp_store_release(&lock->lock, 0); 141} 142 143#endif /* _ASM_RISCV_SPINLOCK_H */