Ticket #1787: SpinlockPatch_v2.txt

File SpinlockPatch_v2.txt, 9.5 KB (added by Jennifer Averett, on 05/09/11 at 16:38:06)

Add nesting support to smp spinlock

Line 
1Index: cpukit/score/include/rtems/score/percpu.h
2===================================================================
3RCS file: /usr1/CVS/rtems/cpukit/score/include/rtems/score/percpu.h,v
4retrieving revision 1.5
5diff -u -r1.5 percpu.h
6--- cpukit/score/include/rtems/score/percpu.h   16 Mar 2011 20:05:06 -0000      1.5
7+++ cpukit/score/include/rtems/score/percpu.h   9 May 2011 16:24:57 -0000
8@@ -84,18 +84,17 @@
9 typedef struct {
10   #if defined(RTEMS_SMP)
11     /** This element is used to lock this structure */
12-    SMP_lock_Control  lock;
13+    SMP_lock_spinlock_simple_Control  lock;
14 
15     /** This indicates that the CPU is online. */
16-    uint32_t          state;
17+    uint32_t                          state;
18 
19     /**
20      *  This is the request for the interrupt.
21      * 
22      *  @note This may become a chain protected by atomic instructions.
23      */
24-    uint32_t          message;
25-
26+    uint32_t                          message;
27   #endif
28 
29 #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
30Index: cpukit/score/include/rtems/score/smplock.h
31===================================================================
32RCS file: /usr1/CVS/rtems/cpukit/score/include/rtems/score/smplock.h,v
33retrieving revision 1.1
34diff -u -r1.1 smplock.h
35--- cpukit/score/include/rtems/score/smplock.h  16 Mar 2011 20:05:06 -0000      1.1
36+++ cpukit/score/include/rtems/score/smplock.h  9 May 2011 16:24:57 -0000
37@@ -34,10 +34,23 @@
38 
39 /**
40  *  This type is used to lock elements for atomic access.
41- *
42- *  @note This type may move to RTEMS.
43+ *  This spinlock is a simple non-nesting spinlock, and
44+ *  may be used for short non-nesting accesses. 
45  */
46-typedef volatile uint32_t SMP_lock_Control;
47+typedef int SMP_lock_spinlock_simple_Control;
48+
49+/**
50+ *  This type is used to lock elements for atomic access.
51+ *  This spinlock supports nesting, but is slightly more
52+ *  complicated to use.  Please see the descriptions of
53+ *  obtain and release prior to using in order to understand
54+ *  the callers responsibilty of managing short interupt disable
55+ *  times.
56+ */
57+typedef struct {
58+  uint32_t  count;
59+  int       cpu_id;
60+} SMP_lock_spinlock_nested_Control;
61 
62 /**
63  *  @brief Initialize a Lock
64@@ -45,12 +58,9 @@
65  *  This method is used to initialize the lock at @a lock.
66  *
67  *  @param [in] lock is the address of the lock to obtain.
68- *
69- *  @note This lock may be "too low" here.  It may need to move
70- *         out of the BSP area.
71  */
72-void _SMP_lock_Spinlock_Initialize(
73-  SMP_lock_Control *lock
74+void _SMP_lock_spinlock_simple_Initialize(
75+  SMP_lock_spinlock_simple_Control *lock
76 );
77 
78 /**
79@@ -62,12 +72,9 @@
80  *
81  *  @return This method returns with processor interrupts disabled.
82  *          The previous level is returned.
83- *
84- *  @note This lock may be "too low" here.  It may need to move
85- *         out of the BSP area.
86  */
87-ISR_Level _SMP_lock_Spinlock_Obtain(
88-  SMP_lock_Control *lock
89+ISR_Level _SMP_lock_spinlock_simple_Obtain(
90+  SMP_lock_spinlock_simple_Control *lock
91 );
92 
93 /**
94@@ -76,13 +83,55 @@
95  *  This method is used to release the lock at @a lock.
96  *
97  *  @param [in] lock is the address of the lock to obtain.
98+ */
99+void _SMP_lock_spinlock_simple_Release(
100+  SMP_lock_spinlock_simple_Control  *lock,
101+  ISR_Level                         level
102+);
103+
104+/**
105+ *  @brief Initialize a Lock
106+ *
107+ *  This method is used to initialize the lock at @a lock.
108  *
109- *  @note This lock may be "too low" here.  It may need to move
110- *         out of the BSP area.
111+ *  @param [in] lock is the address of the lock to obtain.
112+ */
113+void _SMP_lock_spinlock_nested_Spinlock_Initialize(
114+  SMP_lock_spinlock_nested_Control *lock
115+);
116+
117+/**
118+ *  @brief Obtain a Lock
119+ *
120+ *  This method is used to obtain the lock at @a lock.  ISR's are
121+ *  disabled when this routine returns and it is the callers responsibility
122+ *  to either:
123+ *   1) Do something very short and then call
124+ *      _SMP_lock_spinlock_nested_Spinlock_Release  or
125+ *   2) Do something very sort, call isr enable, then when ready
126+ *      call isr_disable and _SMP_lock_spinlock_nested_Spinlock_Release
127+ *
128+ *  @param [in] lock is the address of the lock to obtain.
129+ *
130+ *  @return This method returns with processor interrupts disabled.
131+ *          The previous level is returned.
132+ */
133+ISR_Level _SMP_lock_spinlock_nested_Spinlock_Obtain(
134+  SMP_lock_spinlock_nested_Control *lock
135+);
136+
137+/**
138+ *  @brief Release a Lock
139+ *
140+ *  This method is used to release the lock at @a lock.  Note:
141+ *  ISR's are reenabled by this method and are expected to be
142+ *  disabled upon entry to the method.
143+ *
144+ *  @param [in] lock is the address of the lock to obtain.
145  */
146-void _SMP_lock_Spinlock_Release(
147-  SMP_lock_Control  *lock,
148-  ISR_Level         level
149+void _SMP_lock_spinlock_nested_Spinlock_Release(
150+  SMP_lock_spinlock_nested_Control  *lock,
151+  ISR_Level                         level
152 );
153 
154 #ifdef __cplusplus
155Index: cpukit/score/src/smp.c
156===================================================================
157RCS file: /usr1/CVS/rtems/cpukit/score/src/smp.c,v
158retrieving revision 1.3
159diff -u -r1.3 smp.c
160--- cpukit/score/src/smp.c      27 Apr 2011 17:18:59 -0000      1.3
161+++ cpukit/score/src/smp.c      9 May 2011 16:24:57 -0000
162@@ -80,10 +80,10 @@
163 
164   cpu = bsp_smp_processor_id();
165 
166-  level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
167+  level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock );
168     message = _Per_CPU_Information[cpu].message;
169     _Per_CPU_Information[cpu].message &= ~message;
170-  _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
171+  _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level );
172 
173   #if defined(SMP_DEBUG)
174     {
175@@ -126,9 +126,9 @@
176 {
177   ISR_Level level;
178 
179-  level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
180+  level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock );
181     _Per_CPU_Information[cpu].message |= message;
182-  _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
183+  _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level );
184   bsp_smp_interrupt_cpu( cpu );
185 }
186 
187@@ -145,9 +145,9 @@
188   for ( dest_cpu=0 ; dest_cpu <  _SMP_Processor_count; dest_cpu++ ) {
189     if ( cpu == dest_cpu )
190       continue;
191-    level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
192+    level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock );
193       _Per_CPU_Information[dest_cpu].message |= message;
194-    _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
195+    _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level );
196   }
197   bsp_smp_broadcast_interrupt();
198 }
199Index: cpukit/score/src/smplock.c
200===================================================================
201RCS file: /usr1/CVS/rtems/cpukit/score/src/smplock.c,v
202retrieving revision 1.1
203diff -u -r1.1 smplock.c
204--- cpukit/score/src/smplock.c  16 Mar 2011 20:05:06 -0000      1.1
205+++ cpukit/score/src/smplock.c  9 May 2011 16:24:57 -0000
206@@ -15,35 +15,95 @@
207 
208 #include <rtems/system.h>
209 #include <rtems/score/smplock.h>
210+#include <rtems/score/smp.h>
211 
212-void _SMP_lock_Spinlock_Initialize(
213-  SMP_lock_Control *lock
214+#define SMPLOCK_DEBUG
215+
216+#if defined(SMPLOCK_DEBUG)
217+  #include <rtems/bspIo.h>
218+#endif
219+
220+void _SMP_lock_spinlock_simple_Initialize(
221+  SMP_lock_spinlock_simple_Control *lock
222 )
223 {
224   *lock = 0;
225 }
226 
227-ISR_Level _SMP_lock_Spinlock_Obtain(
228-  SMP_lock_Control *lock
229+ISR_Level _SMP_lock_spinlock_simple_Obtain(
230+  SMP_lock_spinlock_simple_Control *lock
231+)
232+{
233+   ISR_Level  level;
234+   uint32_t   value = 1;
235+   uint32_t   previous;
236+
237+   /* Note: Disable provides an implicit memory barrier. */
238+  _ISR_Disable( level );
239+   do {
240+     SMP_CPU_SWAP( lock, value, previous );
241+   } while (previous == 1);
242+
243+  return level;
244+}
245+
246+void _SMP_lock_spinlock_simple_Release(
247+  SMP_lock_spinlock_simple_Control *lock,
248+  ISR_Level                        level
249 )
250 {
251-  ISR_Level  level;
252+   *lock = 0;
253+   _ISR_Enable( level );
254+}
255+
256+void _SMP_lock_spinlock_nested_Spinlock_Initialize(
257+  SMP_lock_spinlock_nested_Control *lock
258+)
259+{
260+  lock->count = 0;
261+  lock->cpu_id = 0;
262+}
263+
264+ISR_Level _SMP_lock_spinlock_nested_Spinlock_Obtain(
265+  SMP_lock_spinlock_nested_Control *lock
266+)
267+{
268+  ISR_Level  level = 0;
269   uint32_t   value = 1;
270   uint32_t   previous;
271+  int        cpu_id;
272 
273   /* Note: Disable provides an implicit memory barrier. */
274-  _ISR_Disable( level );
275-    do {
276-      SMP_CPU_SWAP( lock, value, previous );
277-    } while (previous == 1);
278+  _ISR_Disable( level );
279+
280+  cpu_id = bsp_smp_processor_id();
281+
282+  /* Deal with nested calls from one cpu */
283+  if ( (lock->count > 0) && (cpu_id == lock->cpu_id) ) {
284+    lock->count++;
285+    return level;
286+  }
287+   
288+  do {
289+    SMP_CPU_SWAP( lock, value, previous );
290+  } while (previous == 1);
291+
292+  lock->count++;
293+  lock->cpu_id = cpu_id;
294+
295   return level;
296 }
297 
298-void _SMP_lock_Spinlock_Release(
299-  SMP_lock_Control *lock,
300-  ISR_Level        level
301+void _SMP_lock_spinlock_nested_Spinlock_Release(
302+  SMP_lock_spinlock_nested_Control *lock,
303+  ISR_Level                        level
304 )
305 {
306-  *lock = 0;
307-  _ISR_Enable( level );
308+#if defined(SMPLOCK_DEBUG)
309+  if ( lock->count == 0 )
310+    printk ("Releasing spinlock when count is already zero?!?!\n");
311+#endif
312+  lock->count--;
313
314+  _ISR_Enable( level );
315 }