]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/kernel/v2_0/include/smp.hxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / kernel / v2_0 / include / smp.hxx
1 #ifndef CYGONCE_KERNEL_SMP_HXX
2 #define CYGONCE_KERNEL_SMP_HXX
3
4 //==========================================================================
5 //
6 //      smp.hxx
7 //
8 //      SMP kernel support
9 //
10 //==========================================================================
11 //####ECOSGPLCOPYRIGHTBEGIN####
12 // -------------------------------------------
13 // This file is part of eCos, the Embedded Configurable Operating System.
14 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
15 //
16 // eCos is free software; you can redistribute it and/or modify it under
17 // the terms of the GNU General Public License as published by the Free
18 // Software Foundation; either version 2 or (at your option) any later version.
19 //
20 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
21 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 // for more details.
24 //
25 // You should have received a copy of the GNU General Public License along
26 // with eCos; if not, write to the Free Software Foundation, Inc.,
27 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 //
29 // As a special exception, if other files instantiate templates or use macros
30 // or inline functions from this file, or you compile this file and link it
31 // with other works to produce a work based on this file, this file does not
32 // by itself cause the resulting work to be covered by the GNU General Public
33 // License. However the source code for this file must still be made available
34 // in accordance with section (3) of the GNU General Public License.
35 //
36 // This exception does not invalidate any other reasons why a work based on
37 // this file might be covered by the GNU General Public License.
38 //
39 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
40 // at http://sources.redhat.com/ecos/ecos-license/
41 // -------------------------------------------
42 //####ECOSGPLCOPYRIGHTEND####
43 //==========================================================================
44 //#####DESCRIPTIONBEGIN####
45 //
46 // Author(s):   nickg
47 // Contributors:nickg
48 // Date:        2001-02-10
49 // Purpose:     Kernel SMP support
50 // Description: If SMP support is configured into the kernel, then this file
51 //              translates HAL defined macros into C and C++ classes and methods
52 //              that can be called from the rest of the kernel. If SMP is not
53 //              configured in, then the same classes and methods are defined here
54 //              to operate correctly in a single CPU configuration.
55 //              
56 // Usage:       #include <cyg/kernel/smp.hxx>
57 //
58 //####DESCRIPTIONEND####
59 //
60 //==========================================================================
61
62 #include <cyg/kernel/ktypes.h>
63 #include <cyg/infra/cyg_ass.h>          // assertion macros
64
65 #include <cyg/hal/hal_intr.h>           // HAL_DISABLE_INTERRUPTS() etc.
66
67 #include <cyg/kernel/instrmnt.h>
68
69 //==========================================================================
70
71 #if defined(CYGPKG_KERNEL_SMP_SUPPORT) && (CYGPKG_HAL_SMP_SUPPORT)
72
73 //==========================================================================
74 // SMP support is included
75
76 #define CYG_KERNEL_SMP_ENABLED
77
78 // -------------------------------------------------------------------------
79 // Get HAL support
80
81 #include <cyg/hal/hal_smp.h>
82
83 // -------------------------------------------------------------------------
84 // Defined values
85 // These all just map straight through to the HAL.
86
87 #define CYGNUM_KERNEL_CPU_MAX           HAL_SMP_CPU_MAX
88
89 #define CYG_KERNEL_CPU_COUNT()          HAL_SMP_CPU_COUNT()
90
91 #define CYG_KERNEL_CPU_THIS()           HAL_SMP_CPU_THIS()
92
93 #define CYG_KERNEL_CPU_NONE             HAL_SMP_CPU_NONE
94
95 // -------------------------------------------------------------------------
96 // CPU control
97
98 #define CYG_KERNEL_CPU_START( __cpu ) HAL_SMP_CPU_START( __cpu )
99
100 #define CYG_KERNEL_CPU_RESCHEDULE_INTERRUPT( __cpu, __wait ) \
101         HAL_SMP_CPU_RESCHEDULE_INTERRUPT( __cpu, __wait )
102
103 #define CYG_KERNEL_CPU_TIMESLICE_INTERRUPT( __cpu, __wait ) \
104         HAL_SMP_CPU_TIMESLICE_INTERRUPT( __cpu, __wait )
105
106 // -------------------------------------------------------------------------
107 // Scheduler lock default implementation.
108
109 // This implementation should serve for most targets. However, some
110 // targets may have hardware or other features that make simple
111 // spinlocks impossible, or allow us to implement the scheduler lock
112 // in a more efficient manner. If that is the case then the HAL will
113 // implement these macros itself.
114
115 #ifndef HAL_SMP_SCHEDLOCK_DATA_TYPE
116
117 #define HAL_SMP_SCHEDLOCK_DATA_TYPE struct hal_smp_schedlock_data_type
118
119 struct hal_smp_schedlock_data_type {
120     HAL_SPINLOCK_TYPE           spinlock;
121     volatile HAL_SMP_CPU_TYPE   holder;
122 };
123
124 #define HAL_SMP_SCHEDLOCK_INIT( __lock, __data )        \
125 CYG_MACRO_START                                         \
126 {                                                       \
127     __lock = 1;                                         \
128     HAL_SPINLOCK_CLEAR(__data.spinlock);                \
129     HAL_SPINLOCK_SPIN(__data.spinlock);                 \
130     __data.holder = HAL_SMP_CPU_THIS();                 \
131 }                                                       \
132 CYG_MACRO_END
133
134
135 #define HAL_SMP_SCHEDLOCK_INC( __lock, __data )                 \
136 CYG_MACRO_START                                                 \
137 {                                                               \
138     CYG_INTERRUPT_STATE __state;                                \
139     HAL_DISABLE_INTERRUPTS(__state);                            \
140     if( __data.holder == HAL_SMP_CPU_THIS() )                   \
141         __lock++;                                               \
142     else                                                        \
143     {                                                           \
144         CYG_INSTRUMENT_SMP(LOCK_WAIT,CYG_KERNEL_CPU_THIS(),0);  \
145         HAL_SPINLOCK_SPIN(__data.spinlock);                     \
146         __data.holder = HAL_SMP_CPU_THIS();                     \
147         __lock++;                                               \
148         CYG_INSTRUMENT_SMP(LOCK_GOT,CYG_KERNEL_CPU_THIS(),0);   \
149     }                                                           \
150     HAL_RESTORE_INTERRUPTS(__state);                            \
151 }                                                               \
152 CYG_MACRO_END
153
154 #define HAL_SMP_SCHEDLOCK_ZERO( __lock, __data )                                                 \
155 CYG_MACRO_START                                                                                  \
156 {                                                                                                \
157     CYG_INTERRUPT_STATE __state;                                                                 \
158     HAL_DISABLE_INTERRUPTS(__state);                                                             \
159     CYG_ASSERT( __data.holder == HAL_SMP_CPU_THIS(), "Zeroing schedlock not owned by me!");      \
160     __lock = 0;                                                                                  \
161     __data.holder = HAL_SMP_CPU_NONE;                                                            \
162     HAL_SPINLOCK_CLEAR(__data.spinlock);                                                         \
163     HAL_RESTORE_INTERRUPTS(__state);                                                             \
164 }                                                                                                \
165 CYG_MACRO_END
166
167 #define HAL_SMP_SCHEDLOCK_SET( __lock, __data, __new )                                          \
168 CYG_MACRO_START                                                                                 \
169 {                                                                                               \
170     CYG_ASSERT( __data.holder == HAL_SMP_CPU_THIS(), "Setting schedlock not owned by me!");     \
171     __lock = __new;                                                                             \
172 }                                                                                               \
173 CYG_MACRO_END
174
175 #endif
176
177 // -------------------------------------------------------------------------
178 // SpinLock class
179 // This class supplies a C++ wrapper for the HAL spinlock API.
180
181 #ifdef __cplusplus
182
183 #ifdef HAL_SPINLOCK_SPIN
184
185 class Cyg_SpinLock
186 {
187     HAL_SPINLOCK_TYPE   lock;
188
189 public:
190
191     // Constructor, initialize the lock to clear
192     Cyg_SpinLock() { lock = HAL_SPINLOCK_INIT_CLEAR; };
193
194     ~Cyg_SpinLock()
195     {
196 //        CYG_ASSERT( !test(), "spinlock still claimed");
197     };
198     
199     // Spin on the lock.
200     void spin()
201     {
202         HAL_SPINLOCK_SPIN(lock);
203     };
204
205     // Clear the lock.
206     void clear()
207     {
208         HAL_SPINLOCK_CLEAR(lock);
209     };
210
211     // Try to claim the lock. Return true if successful, false if not.
212     cyg_bool trylock()
213     {
214         cyg_bool testval;
215         HAL_SPINLOCK_TRY(lock,testval);
216         return testval;
217     };
218
219     // Test the current value of the lock
220     cyg_bool test()
221     {
222         cyg_bool testval;
223         HAL_SPINLOCK_TEST(lock, testval);
224         return testval;
225     };
226
227
228     // The following two member functions are only necessary if the
229     // spinlock is to be used in an ISR. 
230     
231     // Claim the spinlock, but also mask this CPU's interrupts while
232     // we have it.
233     void spin_intsave(CYG_INTERRUPT_STATE *state)
234     {
235         CYG_INTERRUPT_STATE s;
236         HAL_DISABLE_INTERRUPTS(s);
237         *state = s;
238         spin();
239     };
240
241     // Clear the lock, and restore the interrupt state saved in
242     // spin_intsave().
243     void clear_intsave(CYG_INTERRUPT_STATE state)
244     {
245         clear();
246         HAL_RESTORE_INTERRUPTS(state);
247     };
248 };
249
250 #endif
251
252 // -------------------------------------------------------------------------
253 // Scheduler lock class
254 // This uses the scheduler lock API defined by the HAL, or the defaults
255 // defined above.
256
257 class Cyg_Scheduler_SchedLock
258 {
259     static volatile cyg_ucount32 sched_lock         // lock counter
260                     CYGBLD_ATTRIB_ASM_ALIAS( cyg_scheduler_sched_lock )
261                     CYGBLD_ANNOTATE_VARIABLE_SCHED
262                     ;
263     
264     static HAL_SMP_SCHEDLOCK_DATA_TYPE lock_data
265                                        CYGBLD_ANNOTATE_VARIABLE_SCHED;
266     
267 protected:
268
269     Cyg_Scheduler_SchedLock()
270     {
271         HAL_SMP_SCHEDLOCK_INIT( sched_lock, lock_data );
272     };
273     
274     // Increment the scheduler lock. If this takes the lock from zero
275     // to one then this code must also do whatever is necessary to
276     // serialize CPUs through the scheduler.
277     static void inc_sched_lock()
278     {
279         CYG_INSTRUMENT_SMP(LOCK_INC,CYG_KERNEL_CPU_THIS(),0);
280         HAL_SMP_SCHEDLOCK_INC( sched_lock, lock_data );
281     };
282
283     // Zero the scheduler lock. This will release the CPU serializing
284     // lock and allow another CPU in.
285     static void zero_sched_lock()
286     {
287         CYG_INSTRUMENT_SMP(LOCK_ZERO,CYG_KERNEL_CPU_THIS(),0);
288         CYG_ASSERT( sched_lock != 0, "Scheduler lock already zero");
289         HAL_SMP_SCHEDLOCK_ZERO( sched_lock, lock_data );
290     };
291     
292     // Set the scheduler lock to a non-zero value. Both the scheduler
293     // lock and the new value must be non-zero.
294     static void set_sched_lock(cyg_uint32 new_lock)
295     {
296         CYG_INSTRUMENT_SMP(LOCK_SET,CYG_KERNEL_CPU_THIS(),new_lock);        
297         CYG_ASSERT( new_lock > 0, "New scheduler lock value == 0");
298         CYG_ASSERT( sched_lock > 0, "Scheduler lock == 0");
299         HAL_SMP_SCHEDLOCK_SET( sched_lock, lock_data, new_lock );        
300     };
301
302     static cyg_ucount32 get_sched_lock()
303     {
304         return sched_lock;
305     };
306 };
307
308 #define CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS                    \
309 volatile cyg_ucount32 Cyg_Scheduler_SchedLock::sched_lock = 1;  \
310 HAL_SMP_SCHEDLOCK_DATA_TYPE Cyg_Scheduler_SchedLock::lock_data;
311
312 #endif // __cplusplus
313
314 // -------------------------------------------------------------------------
315
316 #else // defined(CYGSEM_KERNEL_SMP_SUPPORT) && (CYGSEM_HAL_SMP_SUPPORT)
317
318 //==========================================================================
319 // SMP support is NOT included.
320
321 #undef CYG_KERNEL_SMP_ENABLED
322
323 // -------------------------------------------------------------------------
324 // Defined values
325 // Supply a set of values that describe a single CPU system.
326
327 #ifndef HAL_SMP_CPU_TYPE
328 #define HAL_SMP_CPU_TYPE                cyg_uint32
329 #endif
330
331 #define CYGNUM_KERNEL_CPU_MAX           1
332
333 #define CYG_KERNEL_CPU_COUNT()          1
334
335 #define CYG_KERNEL_CPU_THIS()           0
336
337 #define CYG_KERNEL_CPU_NONE             -1
338
339 #define CYG_KERNEL_CPU_LOWPRI()         CYG_KERNEL_CPU_THIS()
340
341 // -------------------------------------------------------------------------
342 // SpinLock class
343 // This single CPU version simply goes through the motions of setting
344 // and clearing the lock variable for debugging purposes. 
345
346 #ifdef __cplusplus
347
348 class Cyg_SpinLock
349 {
350     volatile cyg_uint32 lock;
351
352 public:
353
354     // Constructor, initialize the lock to clear
355     Cyg_SpinLock() { lock = 0; };
356
357     ~Cyg_SpinLock()
358     {
359         CYG_ASSERT( lock == 0, "spinlock still claimed");
360     };
361     
362     // Spin on the lock. In this case we just set it to 1 and proceed.
363     void spin()
364     {
365         CYG_ASSERT( lock == 0, "spinlock already claimed!");
366         lock = 1;
367     };
368
369     // Clear the lock. Again, just set the value.
370     void clear()
371     {
372         CYG_ASSERT( lock != 0, "spinlock already cleared!");
373         lock = 0;
374     };
375
376     // Try to claim the lock. Return true if successful, false if not.
377     cyg_bool trylock()
378     {
379         if( lock ) return false;
380         else { lock = 1; return true; }
381     };
382
383     // Test the current value of the lock
384     cyg_bool test() { return lock; };
385
386
387     // The following two member functions are only necessary if the
388     // spinlock is to be used in an ISR. 
389     
390     // Claim the spinlock, but also mask this CPU's interrupts while
391     // we have it.
392     void spin_intsave(CYG_INTERRUPT_STATE *state)
393     {
394         CYG_INTERRUPT_STATE s;
395         HAL_DISABLE_INTERRUPTS(s);
396         *state = s;
397         spin();
398     };
399
400     // Clear the lock, and restore the interrupt state saved in
401     // spin_intsave().
402     void clear_intsave(CYG_INTERRUPT_STATE state)
403     {
404         clear();
405         HAL_RESTORE_INTERRUPTS(state);
406     };
407
408 };
409
410 // -------------------------------------------------------------------------
411 // Scheduler lock class
412
413 class Cyg_Scheduler_SchedLock
414 {
415     static volatile cyg_ucount32 sched_lock         // lock counter
416                     CYGBLD_ATTRIB_ASM_ALIAS( cyg_scheduler_sched_lock )
417                     CYGBLD_ANNOTATE_VARIABLE_SCHED
418                     ;
419     
420     // For non-SMP versions, the code here does the basic and obvious things.
421 protected:
422
423     Cyg_Scheduler_SchedLock()
424     {
425         sched_lock = 1;
426     };
427     
428     // Increment the scheduler lock, possibly taking it from zero to
429     // one.
430     static void inc_sched_lock()
431     {
432         sched_lock++;
433     };
434
435     static void zero_sched_lock()
436     {
437         CYG_ASSERT( sched_lock != 0, "Scheduler lock already zero");
438         sched_lock = 0;
439     };
440     
441     // Set the scheduler lock to a non-zero value. Both the scheduler
442     // lock and the new value must be non-zero.
443     static void set_sched_lock(cyg_uint32 new_lock)
444     {
445         CYG_ASSERT( new_lock > 0, "New scheduler lock value == 0");
446         CYG_ASSERT( sched_lock > 0, "Scheduler lock == 0");
447         sched_lock = new_lock;
448     };
449
450     static cyg_ucount32 get_sched_lock()
451     {
452         return sched_lock;
453     };
454 };
455
456 #define CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS                    \
457 volatile cyg_ucount32 Cyg_Scheduler_SchedLock::sched_lock = 1;
458
459 #endif // __cplusplus
460
461 #endif // defined(CYGSEM_KERNEL_SMP_SUPPORT) && (CYGSEM_HAL_SMP_SUPPORT)
462
463 // -------------------------------------------------------------------------
464 #endif // ifndef CYGONCE_KERNEL_SMP_HXX
465
466 // EOF smp.hxx