smp.h revision 2b04d8ab
1/*
2 * Copyright 2002-2005, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
8#ifndef KERNEL_SMP_H
9#define KERNEL_SMP_H
10
11
12#include <boot/kernel_args.h>
13#include <kernel.h>
14
15#include <KernelExport.h>
16
17#include <string.h>
18
19
20#define SMP_MAX_CPUS MAX_BOOT_CPUS
21
22
23struct kernel_args;
24
25
26// intercpu messages
27enum {
28	SMP_MSG_INVALIDATE_PAGE_RANGE = 0,
29	SMP_MSG_INVALIDATE_PAGE_LIST,
30	SMP_MSG_USER_INVALIDATE_PAGES,
31	SMP_MSG_GLOBAL_INVALIDATE_PAGES,
32	SMP_MSG_CPU_HALT,
33	SMP_MSG_CALL_FUNCTION,
34	SMP_MSG_RESCHEDULE
35};
36
37enum {
38	SMP_MSG_FLAG_ASYNC		= 0x0,
39	SMP_MSG_FLAG_SYNC		= 0x1,
40	SMP_MSG_FLAG_FREE_ARG	= 0x2,
41};
42
43typedef void (*smp_call_func)(addr_t data1, int32 currentCPU, addr_t data2, addr_t data3);
44
45class CPUSet {
46public:
47						CPUSet() { ClearAll(); }
48
49	inline	void		ClearAll();
50	inline	void		SetAll();
51
52	inline	void		SetBit(int32 cpu);
53	inline	void		ClearBit(int32 cpu);
54
55	inline	bool		GetBit(int32 cpu) const;
56
57	inline	bool		IsEmpty() const;
58
59private:
60	static	const int	kArraySize = ROUNDUP(SMP_MAX_CPUS, 32) / 32;
61
62			uint32		fBitmap[kArraySize];
63};
64
65
66#ifdef __cplusplus
67extern "C" {
68#endif
69
70bool try_acquire_spinlock(spinlock* lock);
71
72status_t smp_init(struct kernel_args *args);
73status_t smp_per_cpu_init(struct kernel_args *args, int32 cpu);
74status_t smp_init_post_generic_syscalls(void);
75bool smp_trap_non_boot_cpus(int32 cpu, uint32* rendezVous);
76void smp_wake_up_non_boot_cpus(void);
77void smp_cpu_rendezvous(uint32* var);
78void smp_send_ici(int32 targetCPU, int32 message, addr_t data, addr_t data2, addr_t data3,
79		void *data_ptr, uint32 flags);
80void smp_send_multicast_ici(CPUSet& cpuMask, int32 message, addr_t data,
81		addr_t data2, addr_t data3, void *data_ptr, uint32 flags);
82void smp_send_broadcast_ici(int32 message, addr_t data, addr_t data2, addr_t data3,
83		void *data_ptr, uint32 flags);
84void smp_send_broadcast_ici_interrupts_disabled(int32 currentCPU, int32 message,
85		addr_t data, addr_t data2, addr_t data3, void *data_ptr, uint32 flags);
86
87int32 smp_get_num_cpus(void);
88void smp_set_num_cpus(int32 numCPUs);
89int32 smp_get_current_cpu(void);
90
91int smp_intercpu_int_handler(int32 cpu);
92
93#ifdef __cplusplus
94}
95#endif
96
97
98inline void
99CPUSet::ClearAll()
100{
101	memset(fBitmap, 0, sizeof(fBitmap));
102}
103
104
105inline void
106CPUSet::SetAll()
107{
108	memset(fBitmap, ~uint8(0), sizeof(fBitmap));
109}
110
111
112inline void
113CPUSet::SetBit(int32 cpu)
114{
115	uint32* element = &fBitmap[cpu % kArraySize];
116	atomic_or(element, 1u << (cpu / kArraySize));
117}
118
119
120inline void
121CPUSet::ClearBit(int32 cpu)
122{
123	uint32* element = &fBitmap[cpu % kArraySize];
124	atomic_and(element, ~uint32(1u << (cpu / kArraySize)));
125}
126
127
128inline bool
129CPUSet::GetBit(int32 cpu) const
130{
131	int32* element = (int32*)&fBitmap[cpu % kArraySize];
132	return ((uint32)atomic_get(element) & (1u << (cpu / kArraySize))) != 0;
133}
134
135
136inline bool
137CPUSet::IsEmpty() const
138{
139	for (int i = 0; i < kArraySize; i++) {
140		if (fBitmap[i] != 0)
141			return false;
142	}
143
144	return true;
145}
146
147
148// Unless spinlock debug features are enabled, try to inline
149// {acquire,release}_spinlock().
150#if !DEBUG_SPINLOCKS && !B_DEBUG_SPINLOCK_CONTENTION
151
152
153static inline bool
154try_acquire_spinlock_inline(spinlock* lock)
155{
156	return atomic_get_and_set((int32*)lock, 1) == 0;
157}
158
159
160static inline void
161acquire_spinlock_inline(spinlock* lock)
162{
163	if (try_acquire_spinlock_inline(lock))
164		return;
165	acquire_spinlock(lock);
166}
167
168
169static inline void
170release_spinlock_inline(spinlock* lock)
171{
172	atomic_set((int32*)lock, 0);
173}
174
175
176#define try_acquire_spinlock(lock)	try_acquire_spinlock_inline(lock)
177#define acquire_spinlock(lock)		acquire_spinlock_inline(lock)
178#define release_spinlock(lock)		release_spinlock_inline(lock)
179
180
181static inline bool
182try_acquire_write_spinlock_inline(rw_spinlock* lock)
183{
184	return atomic_test_and_set(&lock->lock, 1 << 31, 0) == 0;
185}
186
187
188static inline void
189acquire_write_spinlock_inline(rw_spinlock* lock)
190{
191	if (try_acquire_write_spinlock(lock))
192		return;
193	acquire_write_spinlock(lock);
194}
195
196
197static inline void
198release_write_spinlock_inline(rw_spinlock* lock)
199{
200	atomic_set(&lock->lock, 0);
201}
202
203
204static inline bool
205try_acquire_read_spinlock_inline(rw_spinlock* lock)
206{
207	uint32 previous = atomic_add(&lock->lock, 1);
208	if ((previous & (1 << 31)) == 0)
209		return true;
210	atomic_test_and_set(&lock->lock, 1 << 31, previous);
211	return false;
212}
213
214
215static inline void
216acquire_read_spinlock_inline(rw_spinlock* lock)
217{
218	if (try_acquire_read_spinlock(lock))
219		return;
220	acquire_read_spinlock(lock);
221}
222
223
224static inline void
225release_read_spinlock_inline(rw_spinlock* lock)
226{
227	atomic_add(&lock->lock, -1);
228}
229
230
231#define try_acquire_read_spinlock(lock)	try_acquire_read_spinlock_inline(lock)
232#define acquire_read_spinlock(lock)		acquire_read_spinlock_inline(lock)
233#define release_read_spinlock(lock)		release_read_spinlock_inline(lock)
234#define try_acquire_write_spinlock(lock) \
235	try_acquire_write_spinlock(lock)
236#define acquire_write_spinlock(lock)	acquire_write_spinlock_inline(lock)
237#define release_write_spinlock(lock)	release_write_spinlock_inline(lock)
238
239
240static inline bool
241try_acquire_write_seqlock_inline(seqlock* lock) {
242	bool succeed = try_acquire_spinlock(&lock->lock);
243	if (succeed)
244		atomic_add((int32*)&lock->count, 1);
245	return succeed;
246}
247
248
249static inline void
250acquire_write_seqlock_inline(seqlock* lock) {
251	acquire_spinlock(&lock->lock);
252	atomic_add((int32*)&lock->count, 1);
253}
254
255
256static inline void
257release_write_seqlock_inline(seqlock* lock) {
258	atomic_add((int32*)&lock->count, 1);
259	release_spinlock(&lock->lock);
260}
261
262
263static inline uint32
264acquire_read_seqlock_inline(seqlock* lock) {
265	return atomic_get((int32*)&lock->count);
266}
267
268
269static inline bool
270release_read_seqlock_inline(seqlock* lock, uint32 count) {
271	uint32 current = atomic_get((int32*)&lock->count);
272
273	return count % 2 == 0 && current == count;
274}
275
276
277#define try_acquire_write_seqlock(lock)	try_acquire_write_seqlock_inline(lock)
278#define acquire_write_seqlock(lock)		acquire_write_seqlock_inline(lock)
279#define release_write_seqlock(lock)		release_write_seqlock_inline(lock)
280#define acquire_read_seqlock(lock)		acquire_read_seqlock_inline(lock)
281#define release_read_seqlock(lock, count)	\
282	release_read_seqlock_inline(lock, count)
283
284
285#endif	// !DEBUG_SPINLOCKS && !B_DEBUG_SPINLOCK_CONTENTION
286
287
288#endif	/* KERNEL_SMP_H */
289