Synchronize up to trunk's revision r57784.
[reactos.git] / ntoskrnl / ke / ipi.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/ipi.c
5 * PURPOSE: Inter-Processor Packet Interface
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 extern KSPIN_LOCK KiReverseStallIpiLock;
18
19 /* PRIVATE FUNCTIONS *********************************************************/
20
21 VOID
22 NTAPI
23 KiIpiGenericCallTarget(IN PKIPI_CONTEXT PacketContext,
24 IN PVOID BroadcastFunction,
25 IN PVOID Argument,
26 IN PVOID Count)
27 {
28 /* FIXME: TODO */
29 ASSERTMSG("Not yet implemented\n", FALSE);
30 }
31
32 VOID
33 FASTCALL
34 KiIpiSend(IN KAFFINITY TargetProcessors,
35 IN ULONG IpiRequest)
36 {
37 /* FIXME: TODO */
38 ASSERTMSG("Not yet implemented\n", FALSE);
39 }
40
41 VOID
42 NTAPI
43 KiIpiSendPacket(IN KAFFINITY TargetProcessors,
44 IN PKIPI_WORKER WorkerFunction,
45 IN PKIPI_BROADCAST_WORKER BroadcastFunction,
46 IN ULONG_PTR Context,
47 IN PULONG Count)
48 {
49 /* FIXME: TODO */
50 ASSERTMSG("Not yet implemented\n", FALSE);
51 }
52
53 VOID
54 FASTCALL
55 KiIpiSignalPacketDone(IN PKIPI_CONTEXT PacketContext)
56 {
57 /* FIXME: TODO */
58 ASSERTMSG("Not yet implemented\n", FALSE);
59 }
60
61 VOID
62 FASTCALL
63 KiIpiSignalPacketDoneAndStall(IN PKIPI_CONTEXT PacketContext,
64 IN volatile PULONG ReverseStall)
65 {
66 /* FIXME: TODO */
67 ASSERTMSG("Not yet implemented\n", FALSE);
68 }
69
70 #if 0
71 VOID
72 NTAPI
73 KiIpiSendRequest(IN KAFFINITY TargetSet,
74 IN ULONG IpiRequest)
75 {
76 #ifdef CONFIG_SMP
77 LONG i;
78 PKPRCB Prcb;
79 KAFFINITY Current;
80
81 for (i = 0, Current = 1; i < KeNumberProcessors; i++, Current <<= 1)
82 {
83 if (TargetSet & Current)
84 {
85 /* Get the PRCB for this CPU */
86 Prcb = KiProcessorBlock[i];
87
88 InterlockedBitTestAndSet((PLONG)&Prcb->IpiFrozen, IpiRequest);
89 HalRequestIpi(i);
90 }
91 }
92 #endif
93 }
94
95 VOID
96 NTAPI
97 KiIpiSendPacket(IN KAFFINITY TargetSet,
98 IN PKIPI_BROADCAST_WORKER WorkerRoutine,
99 IN ULONG_PTR Argument,
100 IN ULONG Count,
101 IN BOOLEAN Synchronize)
102 {
103 #ifdef CONFIG_SMP
104 KAFFINITY Processor;
105 LONG i;
106 PKPRCB Prcb, CurrentPrcb;
107 KIRQL oldIrql;
108
109 ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
110
111 CurrentPrcb = KeGetCurrentPrcb();
112 (void)InterlockedExchangeUL(&CurrentPrcb->TargetSet, TargetSet);
113 (void)InterlockedExchangeUL(&CurrentPrcb->WorkerRoutine, (ULONG_PTR)WorkerRoutine);
114 (void)InterlockedExchangePointer(&CurrentPrcb->CurrentPacket[0], Argument);
115 (void)InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[1], Count);
116 (void)InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[2], Synchronize ? 1 : 0);
117
118 for (i = 0, Processor = 1; i < KeNumberProcessors; i++, Processor <<= 1)
119 {
120 if (TargetSet & Processor)
121 {
122 Prcb = KiProcessorBlock[i];
123 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone, (LONG)CurrentPrcb, 0));
124 InterlockedBitTestAndSet((PLONG)&Prcb->IpiFrozen, IPI_SYNCH_REQUEST);
125 if (Processor != CurrentPrcb->SetMember)
126 {
127 HalRequestIpi(i);
128 }
129 }
130 }
131 if (TargetSet & CurrentPrcb->SetMember)
132 {
133 KeRaiseIrql(IPI_LEVEL, &oldIrql);
134 KiIpiServiceRoutine(NULL, NULL);
135 KeLowerIrql(oldIrql);
136 }
137 #endif
138 }
139 #endif
140
141 /* PUBLIC FUNCTIONS **********************************************************/
142
143 /*
144 * @implemented
145 */
146 BOOLEAN
147 NTAPI
148 KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame,
149 IN PKEXCEPTION_FRAME ExceptionFrame)
150 {
151 #ifdef CONFIG_SMP
152 PKPRCB Prcb;
153 ASSERT(KeGetCurrentIrql() == IPI_LEVEL);
154
155 Prcb = KeGetCurrentPrcb();
156
157 if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_APC))
158 {
159 HalRequestSoftwareInterrupt(APC_LEVEL);
160 }
161
162 if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_DPC))
163 {
164 Prcb->DpcInterruptRequested = TRUE;
165 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
166 }
167
168 if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_SYNCH_REQUEST))
169 {
170 (void)InterlockedDecrementUL(&Prcb->SignalDone->CurrentPacket[1]);
171 if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
172 {
173 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[1], 0, 0));
174 }
175 ((VOID (NTAPI*)(PVOID))(Prcb->SignalDone->WorkerRoutine))(Prcb->SignalDone->CurrentPacket[0]);
176 InterlockedBitTestAndReset((PLONG)&Prcb->SignalDone->TargetSet, KeGetCurrentProcessorNumber());
177 if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
178 {
179 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->TargetSet, 0, 0));
180 }
181 (void)InterlockedExchangePointer(&Prcb->SignalDone, NULL);
182 }
183 #endif
184 return TRUE;
185 }
186
187 /*
188 * @implemented
189 */
190 ULONG_PTR
191 NTAPI
192 KeIpiGenericCall(IN PKIPI_BROADCAST_WORKER Function,
193 IN ULONG_PTR Argument)
194 {
195 ULONG_PTR Status;
196 KIRQL OldIrql, OldIrql2;
197 #ifdef CONFIG_SMP
198 KAFFINITY Affinity;
199 ULONG Count;
200 PKPRCB Prcb = KeGetCurrentPrcb();
201 #endif
202
203 /* Raise to DPC level if required */
204 OldIrql = KeGetCurrentIrql();
205 if (OldIrql < DISPATCH_LEVEL) KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
206
207 #ifdef CONFIG_SMP
208 /* Get current processor count and affinity */
209 Count = KeNumberProcessors;
210 Affinity = KeActiveProcessors;
211
212 /* Exclude ourselves */
213 Affinity &= ~Prcb->SetMember;
214 #endif
215
216 /* Acquire the IPI lock */
217 KeAcquireSpinLockAtDpcLevel(&KiReverseStallIpiLock);
218
219 #ifdef CONFIG_SMP
220 /* Make sure this is MP */
221 if (Affinity)
222 {
223 /* Send an IPI */
224 KiIpiSendPacket(Affinity,
225 KiIpiGenericCallTarget,
226 Function,
227 Argument,
228 &Count);
229
230 /* Spin until the other processors are ready */
231 while ((volatile ULONG)Count != 1) YieldProcessor();
232 }
233 #endif
234
235 /* Raise to IPI level */
236 KeRaiseIrql(IPI_LEVEL, &OldIrql2);
237
238 #ifdef CONFIG_SMP
239 /* Let the other processors know it is time */
240 Count = 0;
241 #endif
242
243 /* Call the function */
244 Status = Function(Argument);
245
246 #ifdef CONFIG_SMP
247 /* If this is MP, wait for the other processors to finish */
248 if (Affinity)
249 {
250 /* Sanity check */
251 ASSERT(Prcb == (volatile PKPRCB)KeGetCurrentPrcb());
252
253 /* FIXME: TODO */
254 ASSERTMSG("Not yet implemented\n", FALSE);
255 }
256 #endif
257
258 /* Release the lock */
259 KeReleaseSpinLockFromDpcLevel(&KiReverseStallIpiLock);
260
261 /* Lower IRQL back */
262 KeLowerIrql(OldIrql);
263 return Status;
264 }