Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | #ifndef _M68K_SEMAPHORE_H #define _M68K_SEMAPHORE_H #include <linux/config.h> #include <linux/linkage.h> #include <asm/system.h> #include <asm/atomic.h> /* * SMP- and interrupt-safe semaphores.. * * (C) Copyright 1996 Linus Torvalds * * m68k version by Andreas Schwab */ struct semaphore { atomic_t count; atomic_t waking; struct wait_queue * wait; }; #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL }) asmlinkage void __down_failed(void /* special register calling convention */); asmlinkage int __down_failed_interruptible(void /* params in registers */); asmlinkage void __up_wakeup(void /* special register calling convention */); extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); extern void __up(struct semaphore * sem); #define sema_init(sem, val) atomic_set(&((sem)->count), val) static inline void wake_one_more(struct semaphore * sem) { atomic_inc(&sem->waking); } static inline int waking_non_zero(struct semaphore *sem) { #ifndef CONFIG_RMW_INSNS unsigned long flags; int ret = 0; save_flags(flags); cli(); if (atomic_read(&sem->waking) > 0) { atomic_dec(&sem->waking); ret = 1; } restore_flags(flags); #else int ret, tmp; __asm__ __volatile__ ("1: movel %2,%0\n" " jeq 3f\n" "2: movel %0,%1\n" " subql #1,%1\n" " casl %0,%1,%2\n" " jeq 3f\n" " tstl %0\n" " jne 2b\n" "3:" : "=d" (ret), "=d" (tmp), "=m" (sem->waking)); #endif return ret; } /* * This is ugly, but we want the default case to fall through. * "down_failed" is a special asm handler that calls the C * routine that actually waits. See arch/m68k/lib/semaphore.S */ extern inline void down(struct semaphore * sem) { register struct semaphore *sem1 __asm__ ("%a1") = sem; __asm__ __volatile__( "| atomic down operation\n\t" "subql #1,%0@\n\t" "jmi 2f\n" "1:\n" ".section .text.lock,\"ax\"\n" ".even\n" "2:\tpea 1b\n\t" "jbra __down_failed\n" ".previous" : /* no outputs */ : "a" (sem1) : "memory"); } extern inline int down_interruptible(struct semaphore * sem) { register struct semaphore *sem1 __asm__ ("%a1") = sem; register int result __asm__ ("%d0"); __asm__ __volatile__( "| atomic interruptible down operation\n\t" "subql #1,%1@\n\t" "jmi 2f\n\t" "clrl %0\n" "1:\n" ".section .text.lock,\"ax\"\n" ".even\n" "2:\tpea 1b\n\t" "jbra __down_failed_interruptible\n" ".previous" : "=d" (result) : "a" (sem1) : "%d0", "memory"); return result; } /* * Note! This is subtle. We jump to wake people up only if * the semaphore was negative (== somebody was waiting on it). * The default case (no contention) will result in NO * jumps for both down() and up(). */ extern inline void up(struct semaphore * sem) { register struct semaphore *sem1 __asm__ ("%a1") = sem; __asm__ __volatile__( "| atomic up operation\n\t" "addql #1,%0@\n\t" "jle 2f\n" "1:\n" ".section .text.lock,\"ax\"\n" ".even\n" "2:\tpea 1b\n\t" "jbra __up_wakeup\n" ".previous" : /* no outputs */ : "a" (sem1) : "memory"); } #endif |