riscv_locks.c 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2019 Western Digital Corporation or its affiliates.
  5. * Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
  6. */
  7. #include <sbi/riscv_barrier.h>
  8. #include <sbi/riscv_locks.h>
  9. static inline bool spin_lock_unlocked(spinlock_t lock)
  10. {
  11. return lock.owner == lock.next;
  12. }
  13. bool spin_lock_check(spinlock_t *lock)
  14. {
  15. RISCV_FENCE(r, rw);
  16. return !spin_lock_unlocked(*lock);
  17. }
  18. bool spin_trylock(spinlock_t *lock)
  19. {
  20. unsigned long inc = 1u << TICKET_SHIFT;
  21. unsigned long mask = 0xffffu << TICKET_SHIFT;
  22. u32 l0, tmp1, tmp2;
  23. __asm__ __volatile__(
  24. /* Get the current lock counters. */
  25. "1: lr.w.aq %0, %3\n"
  26. " slli %2, %0, %6\n"
  27. " and %2, %2, %5\n"
  28. " and %1, %0, %5\n"
  29. /* Is the lock free right now? */
  30. " bne %1, %2, 2f\n"
  31. " add %0, %0, %4\n"
  32. /* Acquire the lock. */
  33. " sc.w.rl %0, %0, %3\n"
  34. " bnez %0, 1b\n"
  35. "2:"
  36. : "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
  37. : "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
  38. : "memory");
  39. return l0 == 0;
  40. }
  41. void spin_lock(spinlock_t *lock)
  42. {
  43. unsigned long inc = 1u << TICKET_SHIFT;
  44. unsigned long mask = 0xffffu;
  45. u32 l0, tmp1, tmp2;
  46. __asm__ __volatile__(
  47. /* Atomically increment the next ticket. */
  48. " amoadd.w.aqrl %0, %4, %3\n"
  49. /* Did we get the lock? */
  50. " srli %1, %0, %6\n"
  51. " and %1, %1, %5\n"
  52. "1: and %2, %0, %5\n"
  53. " beq %1, %2, 2f\n"
  54. /* If not, then spin on the lock. */
  55. " lw %0, %3\n"
  56. RISCV_ACQUIRE_BARRIER
  57. " j 1b\n"
  58. "2:"
  59. : "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
  60. : "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
  61. : "memory");
  62. }
  63. void spin_unlock(spinlock_t *lock)
  64. {
  65. __smp_store_release(&lock->owner, lock->owner + 1);
  66. }