update for HEAD-2003091401
[reactos.git] / hal / halx86 / mpsirql.c
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/hal/x86/mpsirql.c
5  * PURPOSE:         Implements IRQLs for multiprocessor systems
6  * PROGRAMMERS:     David Welch (welch@cwcom.net)
7  *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
8  * UPDATE HISTORY:
9  *     12/04/2001  CSH  Created
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/ke.h>
16 #include <internal/ps.h>
17 #include <ntos/minmax.h>
18 #include <mps.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 /* GLOBALS ******************************************************************/;
24
25 #define IRQ_BASE    (0x30)
26 #define NR_VECTORS  (0x100 - IRQ_BASE)
27
28 extern IMPORTED ULONG DpcQueueSize;
29
30 static ULONG HalpPendingInterruptCount[NR_VECTORS];
31
32 static VOID KeSetCurrentIrql (KIRQL newlvl);
33
34 VOID STDCALL
35 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level);
36
37 #define IRQL2TPR(irql) (FIRST_DEVICE_VECTOR + ((irql - DISPATCH_LEVEL /* 2 */ - 1) * 8))
38
39 /* FUNCTIONS ****************************************************************/
40
41 KIRQL STDCALL KeGetCurrentIrql (VOID)
42 /*
43  * PURPOSE: Returns the current irq level
44  * RETURNS: The current irq level
45  */
46 {
47   if (KeGetCurrentKPCR ()->Irql > HIGH_LEVEL)
48     {
49       DPRINT1 ("CurrentIrql %x\n", KeGetCurrentKPCR ()->Irql);
50       KEBUGCHECK (0);
51       for(;;);
52     }
53
54    return(KeGetCurrentKPCR ()->Irql);
55 }
56
57
58 static VOID KeSetCurrentIrql (KIRQL NewIrql)
59 /*
60  * PURPOSE: Sets the current irq level without taking any action
61  */
62 {
63   if (NewIrql > HIGH_LEVEL)
64     {
65       DPRINT1 ("NewIrql %x\n", NewIrql);
66       KEBUGCHECK (0);
67       for(;;);
68     }
69
70    KeGetCurrentKPCR ()->Irql = NewIrql;
71 }
72
73
74 VOID HalpEndSystemInterrupt (KIRQL Irql)
75 /*
76  * FUNCTION: Enable all irqs with higher priority.
77  */
78 {
79   /* Interrupts should be disabled while enabling irqs */
80   __asm__("pushf\n\t");
81   __asm__("cli\n\t");
82   APICWrite (APIC_TPR, IRQL2TPR (Irql) & APIC_TPR_PRI);
83   __asm__("popf\n\t");
84 }
85
86
87 VOID STATIC
88 HalpExecuteIrqs(KIRQL NewIrql)
89 {
90   ULONG VectorLimit, i;
91   
92   VectorLimit = min(IRQL2VECTOR (NewIrql), NR_VECTORS);
93
94   /*
95    * For each vector if there have been any deferred interrupts then now
96    * dispatch them.
97    */
98   for (i = 0; i < VectorLimit; i++)
99     {
100       if (HalpPendingInterruptCount[i] > 0)
101         {
102            KeSetCurrentIrql (VECTOR2IRQL (i));
103
104            while (HalpPendingInterruptCount[i] > 0)
105              {
106                /*
107                 * For each deferred interrupt execute all the handlers at DIRQL.
108                 */
109                KiInterruptDispatch2 (i, NewIrql);
110                HalpPendingInterruptCount[i]--;
111              }
112            KeSetCurrentIrql (KeGetCurrentIrql () - 1);
113            HalpEndSystemInterrupt (KeGetCurrentIrql ());
114         }
115     }
116
117 }
118
119
120 VOID STATIC
121 HalpLowerIrql(KIRQL NewIrql)
122 {
123   if (NewIrql >= PROFILE_LEVEL)
124     {
125       KeSetCurrentIrql (NewIrql);
126       return;
127     }
128   HalpExecuteIrqs (NewIrql);
129   if (NewIrql >= DISPATCH_LEVEL)
130     {
131       KeSetCurrentIrql (NewIrql);
132       return;
133     }
134   KeSetCurrentIrql (DISPATCH_LEVEL);
135   if (DpcQueueSize > 0)
136     {
137       KiDispatchInterrupt ();
138     }
139   KeSetCurrentIrql (APC_LEVEL);
140   if (NewIrql == APC_LEVEL)
141     {
142       return;
143     }
144   if (KeGetCurrentThread () != NULL && 
145       KeGetCurrentThread ()->ApcState.KernelApcPending)
146     {
147       KiDeliverApc (0, 0, 0);
148     }
149   KeSetCurrentIrql (PASSIVE_LEVEL);
150 }
151
152
153 /**********************************************************************
154  * NAME                                                 EXPORTED
155  *      KfLowerIrql
156  *
157  * DESCRIPTION
158  *      Restores the irq level on the current processor
159  *
160  * ARGUMENTS
161  *      NewIrql = Irql to lower to
162  *
163  * RETURN VALUE
164  *      None
165  *
166  * NOTES
167  *      Uses fastcall convention
168  */
169 VOID FASTCALL
170 KfLowerIrql (KIRQL      NewIrql)
171 {
172   KIRQL OldIrql;
173
174   if (NewIrql > KeGetCurrentIrql ())
175     {
176       DPRINT1 ("NewIrql %x CurrentIrql %x\n", NewIrql, KeGetCurrentIrql ());
177       KEBUGCHECK (0);
178       for(;;);
179     }
180   
181   HalpLowerIrql (NewIrql);
182 }
183
184
185 /**********************************************************************
186  * NAME                                                 EXPORTED
187  *      KeLowerIrql
188  *
189  * DESCRIPTION
190  *      Restores the irq level on the current processor
191  *
192  * ARGUMENTS
193  *      NewIrql = Irql to lower to
194  *
195  * RETURN VALUE
196  *      None
197  *
198  * NOTES
199  */
200
201 VOID STDCALL
202 KeLowerIrql (KIRQL NewIrql)
203 {
204   KfLowerIrql (NewIrql);
205 }
206
207
208 /**********************************************************************
209  * NAME                                                 EXPORTED
210  *      KfRaiseIrql
211  *
212  * DESCRIPTION
213  *      Raises the hardware priority (irql)
214  *
215  * ARGUMENTS
216  *      NewIrql = Irql to raise to
217  *
218  * RETURN VALUE
219  *      previous irq level
220  *
221  * NOTES
222  *      Uses fastcall convention
223  */
224
225 KIRQL FASTCALL
226 KfRaiseIrql (KIRQL      NewIrql)
227 {
228   KIRQL OldIrql;
229   
230   if (NewIrql < KeGetCurrentIrql ())
231     {
232       DPRINT1 ("CurrentIrql %x NewIrql %x\n", KeGetCurrentIrql (), NewIrql);
233       KEBUGCHECK (0);
234       for(;;);
235     }
236   
237   OldIrql = KeGetCurrentIrql ();
238   KeSetCurrentIrql (NewIrql);
239   return OldIrql;
240 }
241
242
243 /**********************************************************************
244  * NAME                                                 EXPORTED
245  *      KeRaiseIrql
246  *
247  * DESCRIPTION
248  *      Raises the hardware priority (irql)
249  *
250  * ARGUMENTS
251  *      NewIrql = Irql to raise to
252  *      OldIrql (OUT) = Caller supplied storage for the previous irql
253  *
254  * RETURN VALUE
255  *      None
256  *
257  * NOTES
258  *      Calls KfRaiseIrql
259  */
260 VOID STDCALL
261 KeRaiseIrql (KIRQL      NewIrql,
262         PKIRQL  OldIrql)
263 {
264   *OldIrql = KfRaiseIrql (NewIrql);
265 }
266
267
268 /**********************************************************************
269  * NAME                                                 EXPORTED
270  *      KeRaiseIrqlToDpcLevel
271  *
272  * DESCRIPTION
273  *      Raises the hardware priority (irql) to DISPATCH level
274  *
275  * ARGUMENTS
276  *      None
277  *
278  * RETURN VALUE
279  *      Previous irq level
280  *
281  * NOTES
282  *      Calls KfRaiseIrql
283  */
284
285 KIRQL STDCALL
286 KeRaiseIrqlToDpcLevel (VOID)
287 {
288   return KfRaiseIrql (DISPATCH_LEVEL);
289 }
290
291
292 /**********************************************************************
293  * NAME                                                 EXPORTED
294  *      KeRaiseIrqlToSynchLevel
295  *
296  * DESCRIPTION
297  *      Raises the hardware priority (irql) to CLOCK2 level
298  *
299  * ARGUMENTS
300  *      None
301  *
302  * RETURN VALUE
303  *      Previous irq level
304  *
305  * NOTES
306  *      Calls KfRaiseIrql
307  */
308
309 KIRQL STDCALL
310 KeRaiseIrqlToSynchLevel (VOID)
311 {
312   return KfRaiseIrql (CLOCK2_LEVEL);
313 }
314
315
316 BOOLEAN STDCALL
317 HalBeginSystemInterrupt (ULONG Vector,
318         KIRQL Irql,
319         PKIRQL OldIrql)
320 {
321   DPRINT("Vector (0x%X)  Irql (0x%X)\n", Vector, Irql);
322
323   if (Vector < FIRST_DEVICE_VECTOR ||
324     Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
325     DPRINT("Not a device interrupt\n");
326           return FALSE;
327   }
328
329   HalDisableSystemInterrupt (Vector, 0);
330
331   APICSendEOI();
332
333   if (KeGetCurrentIrql () >= Irql)
334     {
335       HalpPendingInterruptCount[Vector]++;
336       return(FALSE);
337     }
338   *OldIrql = KeGetCurrentIrql ();
339   KeSetCurrentIrql (Irql);
340
341   return(TRUE);
342 }
343
344
345 VOID STDCALL
346 HalEndSystemInterrupt (KIRQL Irql,
347         ULONG Unknown2)
348 /*
349  * FUNCTION: Finish a system interrupt and restore the specified irq level.
350  */
351 {
352   HalpLowerIrql (Irql);
353   HalpEndSystemInterrupt (Irql);
354 }
355   
356 BOOLEAN STDCALL
357 HalDisableSystemInterrupt (ULONG Vector,
358         ULONG Unknown2)
359 {
360   ULONG irq;
361
362   DPRINT ("Vector (0x%X)\n", Vector);
363
364   if (Vector < FIRST_DEVICE_VECTOR ||
365     Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)  {
366     DPRINT("Not a device interrupt\n");
367           return FALSE;
368   }
369
370   irq = VECTOR2IRQ (Vector);
371   IOAPICMaskIrq (ThisCPU (), irq);
372
373   return TRUE;  
374 }
375
376
377 BOOLEAN STDCALL
378 HalEnableSystemInterrupt (ULONG Vector,
379         ULONG Unknown2,
380         ULONG Unknown3)
381 {
382   ULONG irq;
383
384   DPRINT ("Vector (0x%X)\n", Vector);
385
386   if (Vector < FIRST_DEVICE_VECTOR ||
387     Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
388     DPRINT("Not a device interrupt\n");
389           return FALSE;
390   }
391
392   irq = VECTOR2IRQ (Vector);
393   IOAPICUnmaskIrq (ThisCPU (), irq);
394
395   return TRUE;
396 }