|
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\nkernsmp\arm\ncirq.cia |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @internalTechnology |
|
21 */ |
|
22 |
|
23 #include "nk_priv.h" |
|
24 #include "nk_plat.h" |
|
25 #include <nk_irq.h> |
|
26 #include <arm.h> |
|
27 #include <arm_gic.h> |
|
28 #include <arm_scu.h> |
|
29 #include <arm_tmr.h> |
|
30 |
|
31 // |
|
32 // Atomically increment run count provided ECount set or count <2. |
|
33 // If originally zero, atomically set CPU field |
|
34 // Wait for EWait to be clear |
|
35 // Return state of iIState immediately before increment |
|
36 // |
|
37 __NAKED__ TUint32 NIrq::EnterIsr() |
|
38 { |
|
39 GET_RWNO_TID(,r12); |
|
40 asm("add r3, r0, #%a0" : : "i" _FOFF(NIrq,iIState)); |
|
41 asm("ldr r12, [r12, #%a0]" : : "i" _FOFF(TSubScheduler,iCpuNum)); |
|
42 |
|
43 asm("1: "); |
|
44 LDREX(0,3); |
|
45 asm("mov r1, r0 "); |
|
46 asm("cmp r0, #0x10000 "); // run count >= 1 ? |
|
47 asm("biclo r1, r1, #0xff00 "); // if not, update CPU |
|
48 asm("orrlo r1, r1, r12, lsl #8 "); |
|
49 asm("add r1, r1, #0x10000 "); // increment run count |
|
50 asm("cmp r1, #0x20000 "); // >= 2 ? |
|
51 asm("bhs 3f "); |
|
52 asm("2: "); |
|
53 STREX(2,1,3); |
|
54 asm("cmp r2, #0 "); |
|
55 asm("bne 1b "); |
|
56 |
|
57 asm("4: "); |
|
58 __DATA_MEMORY_BARRIER__(r2); |
|
59 asm("tst r1, #%a0" : : "i" (NIrq::EWait)); |
|
60 asm("bne 5f "); |
|
61 __JUMP(,lr); |
|
62 |
|
63 asm("3: "); |
|
64 asm("tst r1, #%a0" : : "i" (NIrq::ECount|NIrq::ERaw)); |
|
65 asm("bne 2b "); |
|
66 asm("mov r2, #0 "); |
|
67 asm("b 4b "); |
|
68 |
|
69 asm("5: "); |
|
70 ARM_WFE; |
|
71 asm("ldr r1, [r3] "); |
|
72 asm("b 4b "); |
|
73 } |
|
74 |
|
75 // |
|
76 // Atomically decrement run count |
|
77 // Return TRUE if run count nonzero after decrement |
|
78 // |
|
79 __NAKED__ TBool NIrq::IsrDone() |
|
80 { |
|
81 asm("add r3, r0, #%a0" : : "i" _FOFF(NIrq,iIState)); |
|
82 __DATA_MEMORY_BARRIER_Z__(r2); |
|
83 |
|
84 asm("1: "); |
|
85 LDREX(0,3); |
|
86 asm("subs r1, r0, #0x10000 "); |
|
87 STREX(2,1,3); |
|
88 asm("cmp r2, #0 "); |
|
89 asm("bne 1b "); |
|
90 asm("mov r0, r1, lsr #16 "); // r0 = new run count = TRUE if nonzero |
|
91 __JUMP(,lr); |
|
92 } |
|
93 |
|
94 // |
|
95 // Wait (allowing interrupts and preemption) until run count = 0 and EWait clear |
|
96 // Then atomically set EWait and return with interrupts disabled |
|
97 // |
|
98 __NAKED__ void NIrq::Wait() |
|
99 { |
|
100 asm("add r3, r0, #%a0" : : "i" _FOFF(NIrq,iIState)); |
|
101 |
|
102 asm("0: "); |
|
103 __ASM_CLI(); |
|
104 |
|
105 asm("1: "); |
|
106 LDREX(0,3); |
|
107 asm("mov r1, r0, ror #1 "); // bit 31 = wait, bits 15-30 = run count |
|
108 asm("cmp r1, #0x8000 "); // run count and EWait both zero? |
|
109 asm("bcs 2f "); // if not, must wait |
|
110 asm("orr r1, r0, #1 "); // else try to set EWait |
|
111 STREX(2,1,3); |
|
112 asm("cmp r2, #0 "); |
|
113 asm("bne 1b "); |
|
114 __DATA_MEMORY_BARRIER__(r2); |
|
115 __JUMP(,lr); // success - return with interrupts disabled |
|
116 |
|
117 // spin, allowing interrupts, while we wait for run count and EWait both zero |
|
118 asm("2: "); |
|
119 __ASM_STI(); |
|
120 asm("nop "); |
|
121 ARM_WFE; |
|
122 asm("nop "); |
|
123 asm("b 0b "); |
|
124 } |
|
125 |
|
126 // |
|
127 // Atomically clear EWait and reenable interrupts |
|
128 // |
|
129 __NAKED__ void NIrq::Done() |
|
130 { |
|
131 asm("add r3, r0, #%a0" : : "i" _FOFF(NIrq,iIState)); |
|
132 __DATA_MEMORY_BARRIER_Z__(r2); |
|
133 |
|
134 asm("1: "); |
|
135 LDREX(0,3); |
|
136 asm("bic r0, r0, #1 "); // clear EWait |
|
137 STREX(2,0,3); |
|
138 asm("cmp r2, #0 "); |
|
139 asm("bne 1b "); |
|
140 __DATA_SYNC_BARRIER__(r2); // ensure completion before SEV |
|
141 ARM_SEV; // kick any waiting processors |
|
142 __ASM_STI(); // interrupts back on |
|
143 __JUMP(,lr); |
|
144 } |
|
145 |
|
146 |
|
147 |
|
148 // |
|
149 // atomic { if !EUnbind && !ENotReady clear EDisable } |
|
150 // Return the initial value of iHState |
|
151 // |
|
152 __NAKED__ TUint32 NIrqHandler::DoSetEnabled() |
|
153 { |
|
154 asm("add r3, r0, #%a0" : : "i" _FOFF(NIrqHandler,iHState)); |
|
155 __DATA_MEMORY_BARRIER_Z__(r2); |
|
156 |
|
157 asm("1: "); |
|
158 LDREX(0,3); |
|
159 asm("tst r0, #%a0" : : "i" (NIrqHandler::EUnbind|NIrqHandler::ENotReady)); |
|
160 asm("bne 2f "); // if EUnbind or ENotReady, finished |
|
161 asm("bic r1, r0, #%a0" : : "i" (NIrqHandler::EDisable|NIrqHandler::EBind)); |
|
162 STREX(2,1,3); |
|
163 asm("cmp r2, #0 "); |
|
164 asm("bne 1b "); |
|
165 |
|
166 asm("2: "); |
|
167 __DATA_MEMORY_BARRIER__(r2); |
|
168 __JUMP(,lr); |
|
169 } |
|
170 |
|
171 // |
|
172 // Atomically increment run count by aCount if ECount set or run count initially zero. |
|
173 // If !EDisable and !EUnbind set EActive |
|
174 // Return initial iHState |
|
175 // |
|
176 __NAKED__ TUint32 NIrqHandler::DoActivate(TInt /*aCount*/) |
|
177 { |
|
178 asm("add r3, r0, #%a0" : : "i" _FOFF(NIrqHandler,iHState)); |
|
179 |
|
180 asm("1: "); |
|
181 LDREX(0,3); |
|
182 asm("mov r2, r0 "); |
|
183 asm("cmp r0, #0x10000 "); |
|
184 asm("blo 2f "); // if run count initially zero, skip |
|
185 asm("tst r0, #%a0" : : "i" (NIrqHandler::ECount)); |
|
186 asm("beq 3f "); // else if !ECount, don't increment |
|
187 asm("2: "); |
|
188 asm("add r2, r2, r1, lsl #16 "); // add aCount to run count |
|
189 asm("3: "); |
|
190 asm("tst r2, #%a0" : : "i" (NIrqHandler::EUnbind|NIrqHandler::EDisable)); |
|
191 asm("orreq r2, r2, #%a0" : : "i" (NIrqHandler::EActive)); // if !EUnbind && !EDisable, set EActive |
|
192 STREX(12,2,3); |
|
193 asm("cmp r12, #0 "); |
|
194 asm("bne 1b "); |
|
195 __DATA_MEMORY_BARRIER__(r12); |
|
196 __JUMP(,lr); |
|
197 } |
|
198 |
|
199 // |
|
200 // Decrement run count |
|
201 // Return initial iHState |
|
202 // |
|
203 __NAKED__ TUint32 NIrqHandler::EventBegin() |
|
204 { |
|
205 asm("add r3, r0, #%a0" : : "i" _FOFF(NIrqHandler,iHState)); |
|
206 |
|
207 asm("1: "); |
|
208 LDREX(0,3); |
|
209 asm("sub r2, r0, #0x10000 "); |
|
210 STREX(12,2,3); |
|
211 asm("cmp r12, #0 "); |
|
212 asm("bne 1b "); |
|
213 __DATA_MEMORY_BARRIER__(r12); |
|
214 __JUMP(,lr); |
|
215 } |
|
216 |
|
217 // |
|
218 // If count is zero or EDisable or EUnbind |
|
219 // are set, clear EActive. |
|
220 // Return initial iHState, except for new EActive bit |
|
221 // |
|
222 __NAKED__ TUint32 NIrqHandler::EventDone() |
|
223 { |
|
224 asm("add r3, r0, #%a0" : : "i" _FOFF(NIrqHandler,iHState)); |
|
225 __DATA_MEMORY_BARRIER_Z__(r12); |
|
226 |
|
227 asm("1: "); |
|
228 LDREX(0,3); |
|
229 asm("mov r2, r0 "); |
|
230 asm("cmp r0, #0x10000 "); // run count zero ? |
|
231 asm("tsths r2, #%a0" : : "i" (NIrqHandler::EUnbind|NIrqHandler::EDisable)); // if so, test EUnbind and EDisable |
|
232 asm("bicne r2, r2, #%a0" : : "i" (NIrqHandler::EActive)); // if runcount==0 or EUnbind or EDisable set, clear EActive |
|
233 STREX(12,2,3); |
|
234 asm("cmp r12, #0 "); |
|
235 asm("bne 1b "); |
|
236 asm("tst r2, #%a0" : : "i" (NIrqHandler::EActive)); // EActive now clear in new value ? |
|
237 asm("biceq r0, r0, #%a0" : : "i" (NIrqHandler::EActive)); // if so, clear it in return value |
|
238 __JUMP(,lr); |
|
239 } |
|
240 |