summaryrefslogtreecommitdiffstats
path: root/include/asm-m68k/semaphore-helper.h
blob: 1516a642f9a57da31c0585a9f61eb1c9bc6841ed (plain)
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
142
143
#ifndef _M68K_SEMAPHORE_HELPER_H
#define _M68K_SEMAPHORE_HELPER_H

/*
 * SMP- and interrupt-safe semaphores helper functions.
 *
 * (C) Copyright 1996 Linus Torvalds
 *
 * m68k version by Andreas Schwab
 */

#include <linux/config.h>
#include <linux/errno.h>

/*
 * These two _must_ execute atomically wrt each other.
 */
static inline void wake_one_more(struct semaphore * sem)
{
	atomic_inc(&sem->waking);
}

#ifndef CONFIG_RMW_INSNS
extern spinlock_t semaphore_wake_lock;
#endif

static inline int waking_non_zero(struct semaphore *sem)
{
	int ret;
#ifndef CONFIG_RMW_INSNS
	unsigned long flags;

	spin_lock_irqsave(&semaphore_wake_lock, flags);
	ret = 0;
	if (atomic_read(&sem->waking) > 0) {
		atomic_dec(&sem->waking);
		ret = 1;
	}
	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
#else
	int tmp1, tmp2;

	__asm__ __volatile__
	  ("1:	movel	%1,%2\n"
	   "    jle	2f\n"
	   "	subql	#1,%2\n"
	   "	casl	%1,%2,%3\n"
	   "	jne	1b\n"
	   "	moveq	#1,%0\n"
	   "2:"
	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
	   : "m" (sem->waking), "0" (0), "1" (sem->waking));
#endif

	return ret;
}

/*
 * waking_non_zero_interruptible:
 *	1	got the lock
 *	0	go to sleep
 *	-EINTR	interrupted
 */
static inline int waking_non_zero_interruptible(struct semaphore *sem,
						struct task_struct *tsk)
{
	int ret;
#ifndef CONFIG_RMW_INSNS
	unsigned long flags;

	spin_lock_irqsave(&semaphore_wake_lock, flags);
	ret = 0;
	if (atomic_read(&sem->waking) > 0) {
		atomic_dec(&sem->waking);
		ret = 1;
	} else if (signal_pending(tsk)) {
		atomic_inc(&sem->count);
		ret = -EINTR;
	}
	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
#else
	int tmp1, tmp2;

	__asm__ __volatile__
	  ("1:	movel	%1,%2\n"
	   "	jle	2f\n"
	   "	subql	#1,%2\n"
	   "	casl	%1,%2,%3\n"
	   "	jne	1b\n"
	   "	moveq	#1,%0\n"
	   "	jra	%a4\n"
	   "2:"
	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
	   : "m" (sem->waking), "i" (&&next), "0" (0), "1" (sem->waking));
	if (signal_pending(tsk)) {
		atomic_inc(&sem->count);
		ret = -EINTR;
	}
next:
#endif

	return ret;
}

/*
 * waking_non_zero_trylock:
 *	1	failed to lock
 *	0	got the lock
 */
static inline int waking_non_zero_trylock(struct semaphore *sem)
{
	int ret;
#ifndef CONFIG_RMW_INSNS
	unsigned long flags;

	spin_lock_irqsave(&semaphore_wake_lock, flags);
	ret = 1;
	if (atomic_read(&sem->waking) > 0) {
		atomic_dec(&sem->waking);
		ret = 0;
	} else
		atomic_inc(&sem->count);
	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
#else
	int tmp1, tmp2;

	__asm__ __volatile__
	  ("1:	movel	%1,%2\n"
	   "    jle	2f\n"
	   "	subql	#1,%2\n"
	   "	casl	%1,%2,%3\n"
	   "	jne	1b\n"
	   "	moveq	#0,%0\n"
	   "2:"
	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
	   : "m" (sem->waking), "0" (1), "1" (sem->waking));
	if (ret)
		atomic_inc(&sem->count);
#endif
	return ret;
}

#endif