win-pvdrivers

view xenpci/evtchn.c @ 364:2ff96a909c28

Fixed an interrupt problem that was causing hangs on boot.
author James Harper <james.harper@bendigoit.com.au>
date Mon Jul 07 22:46:08 2008 +1000 (2008-07-07)
parents cb12e8b450a8
children 5b2a37528899
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenpci.h"
22 #if defined(__MINGW32__)
23 /* mingw-runtime 3.13 lacks certain lowlevel intrinsics */
24 NTSTATUS BitScanForward(unsigned long *index, unsigned long mask)
25 {
26 int i;
28 for (i = 0; i < sizeof(unsigned long)*8; i++)
29 {
30 if (mask & (1 << i)) {
31 *index = i + 1;
32 KdPrint((__FUNC__ __LINE__ " Check that I work as expected!\n"));
33 return 1;
34 }
35 }
37 KdPrint((__FUNC__ __LINE__ " Check that I work as expected!\n"));
39 return 0;
40 }
42 /**
43 From linux include/asm-i386/bitops.h
44 */
45 static inline int test_and_set_bit(int nr, volatile long * addr)
46 {
47 int oldbit;
49 __asm__ __volatile__( "lock;"
50 "btsl %2,%1\n\tsbbl %0,%0"
51 :"=r" (oldbit),"+m" (*(volatile long *) addr)
52 :"Ir" (nr) : "memory");
54 KdPrint((__FUNC__ " Check that I work as expected!\n"));
56 return oldbit;
57 }
58 static inline int test_and_clear_bit(int nr, volatile long * addr)
59 {
60 int oldbit;
62 __asm__ __volatile__( "lock;"
63 "btrl %2,%1\n\tsbbl %0,%0"
64 :"=r" (oldbit),"+m" (*(volatile long *) addr)
65 :"Ir" (nr) : "memory");
67 KdPrint((__FUNC__ " Check that I work as expected!\n"));
69 return oldbit;
70 }
72 #define xchg(p1, p2) InterlockedExchange((xen_long_t * volatile)p1, p2)
73 #define synch_clear_bit(p1, p2) test_and_clear_bit(p1, p2)
74 #define synch_set_bit(p1, p2) test_and_set_bit(p1, p2)
75 #define bit_scan_forward(p1, p2) BitScanForward(p1, p2)
76 #elif defined(_X86_)
77 #define xchg(p1, p2) _InterlockedExchange(p1, p2)
78 #define synch_clear_bit(p1, p2) _interlockedbittestandreset(p2, p1)
79 #define synch_set_bit(p1, p2) _interlockedbittestandset(p2, p1)
80 #define bit_scan_forward(p1, p2) _BitScanForward(p1, p2)
81 #else
82 #define xchg(p1, p2) _InterlockedExchange64(p1, p2)
83 #define synch_clear_bit(p1, p2) _interlockedbittestandreset64(p2, p1)
84 #define synch_set_bit(p1, p2) _interlockedbittestandset64(p2, p1)
85 #define bit_scan_forward(p1, p2) _BitScanForward64(p1, p2)
86 #endif
88 static DDKAPI VOID
89 EvtChn_DpcBounce(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2)
90 {
91 ev_action_t *action = Context;
93 UNREFERENCED_PARAMETER(Dpc);
94 UNREFERENCED_PARAMETER(SystemArgument1);
95 UNREFERENCED_PARAMETER(SystemArgument2);
97 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
99 if (action->type == EVT_ACTION_TYPE_IRQ)
100 {
101 //KdPrint((__DRIVER_NAME " Calling interrupt vector %02x\n", action->vector));
102 sw_interrupt((UCHAR)action->vector);
103 }
104 else
105 {
106 action->ServiceRoutine(NULL, action->ServiceContext);
107 }
108 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
109 }
111 static DDKAPI BOOLEAN
112 EvtChn_Interrupt(PKINTERRUPT Interrupt, PVOID Context)
113 {
114 int cpu = KeGetCurrentProcessorNumber() & (MAX_VIRT_CPUS - 1);
115 vcpu_info_t *vcpu_info;
116 PXENPCI_DEVICE_DATA xpdd = (PXENPCI_DEVICE_DATA)Context;
117 shared_info_t *shared_info_area = xpdd->shared_info_area;
118 xen_ulong_t evt_words;
119 unsigned long evt_word;
120 unsigned long evt_bit;
121 unsigned int port;
122 ev_action_t *ev_action;
123 BOOLEAN handled = FALSE;
125 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (cpu = %d)\n", cpu));
127 UNREFERENCED_PARAMETER(Interrupt);
129 vcpu_info = &shared_info_area->vcpu_info[cpu];
131 vcpu_info->evtchn_upcall_pending = 0;
133 evt_words = (xen_ulong_t)xchg((volatile xen_long_t *)&vcpu_info->evtchn_pending_sel, 0);
135 while (bit_scan_forward(&evt_word, evt_words))
136 {
137 evt_words &= ~(1 << evt_word);
138 while (bit_scan_forward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
139 {
140 handled = TRUE;
141 port = (evt_word << 5) + evt_bit;
142 ev_action = &xpdd->ev_actions[port];
143 switch (ev_action->type)
144 {
145 case EVT_ACTION_TYPE_NORMAL:
146 ev_action->ServiceRoutine(NULL, ev_action->ServiceContext);
147 break;
148 case EVT_ACTION_TYPE_DPC:
149 case EVT_ACTION_TYPE_IRQ: /* we have to call the IRQ from DPC or we risk mucking up IRQLs */
150 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
151 break;
152 default:
153 KdPrint((__DRIVER_NAME " Unhandled Event!!!\n"));
154 break;
155 }
156 synch_clear_bit(port, (volatile xen_long_t *)&shared_info_area->evtchn_pending[evt_word]);
157 }
158 }
160 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
162 return handled;
163 }
165 NTSTATUS
166 EvtChn_Bind(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
167 {
168 PXENPCI_DEVICE_DATA xpdd = Context;
170 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
172 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
173 {
174 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
175 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
176 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
177 }
179 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
180 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
181 xpdd->ev_actions[Port].xpdd = xpdd;
182 KeMemoryBarrier();
183 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_NORMAL;
185 EvtChn_Unmask(Context, Port);
187 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
189 return STATUS_SUCCESS;
190 }
192 NTSTATUS
193 EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PKSERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
194 {
195 PXENPCI_DEVICE_DATA xpdd = Context;
197 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
199 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
200 {
201 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
202 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
203 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
204 }
206 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
207 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
208 xpdd->ev_actions[Port].xpdd = xpdd;
209 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
210 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
211 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_DPC;
213 EvtChn_Unmask(Context, Port);
215 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
217 return STATUS_SUCCESS;
218 }
220 NTSTATUS
221 EvtChn_BindIrq(PVOID Context, evtchn_port_t Port, ULONG vector)
222 {
223 PXENPCI_DEVICE_DATA xpdd = Context;
225 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
227 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
228 {
229 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
230 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
231 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
232 }
234 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
235 xpdd->ev_actions[Port].vector = vector;
236 xpdd->ev_actions[Port].xpdd = xpdd;
237 KeMemoryBarrier();
238 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_IRQ;
240 EvtChn_Unmask(Context, Port);
242 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
244 return STATUS_SUCCESS;
245 }
247 NTSTATUS
248 EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
249 {
250 PXENPCI_DEVICE_DATA xpdd = Context;
252 EvtChn_Mask(Context, Port);
253 xpdd->ev_actions[Port].ServiceRoutine = NULL;
254 KeMemoryBarrier();
255 xpdd->ev_actions[Port].ServiceContext = NULL;
257 if (xpdd->ev_actions[Port].type == EVT_ACTION_TYPE_DPC)
258 KeRemoveQueueDpc(&xpdd->ev_actions[Port].Dpc);
260 return STATUS_SUCCESS;
261 }
263 NTSTATUS
264 EvtChn_Mask(PVOID Context, evtchn_port_t Port)
265 {
266 PXENPCI_DEVICE_DATA xpdd = Context;
268 synch_set_bit(Port,
269 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[0]);
270 return STATUS_SUCCESS;
271 }
273 NTSTATUS
274 EvtChn_Unmask(PVOID Context, evtchn_port_t Port)
275 {
276 PXENPCI_DEVICE_DATA xpdd = Context;
278 synch_clear_bit(Port,
279 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[0]);
280 return STATUS_SUCCESS;
281 }
283 NTSTATUS
284 EvtChn_Notify(PVOID Context, evtchn_port_t Port)
285 {
286 PXENPCI_DEVICE_DATA xpdd = Context;
287 struct evtchn_send send;
289 send.port = Port;
290 (void)HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_send, &send);
291 return STATUS_SUCCESS;
292 }
294 evtchn_port_t
295 EvtChn_AllocUnbound(PVOID Context, domid_t Domain)
296 {
297 PXENPCI_DEVICE_DATA xpdd = Context;
298 evtchn_alloc_unbound_t op;
299 op.dom = DOMID_SELF;
300 op.remote_dom = Domain;
301 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_alloc_unbound, &op);
302 return op.port;
303 }
305 static VOID
306 EvtChn_Connect(PXENPCI_DEVICE_DATA xpdd)
307 {
308 int i;
310 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
312 for (i = 0; i < NR_EVENTS; i++)
313 {
314 EvtChn_Mask(xpdd, i);
315 xpdd->ev_actions[i].type = EVT_ACTION_TYPE_EMPTY;
316 xpdd->ev_actions[i].Count = 0;
317 }
319 for (i = 0; i < 8; i++)
320 {
321 xpdd->shared_info_area->evtchn_pending[i] = 0;
322 }
324 for (i = 0; i < MAX_VIRT_CPUS; i++)
325 {
326 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
327 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
328 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1;
329 }
331 hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, xpdd->irq_number);
333 for (i = 0; i < MAX_VIRT_CPUS; i++)
334 {
335 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 0;
336 }
338 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
339 }
341 NTSTATUS
342 EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
343 {
344 NTSTATUS status;
346 EvtChn_Connect(xpdd);
348 status = IoConnectInterrupt(
349 &xpdd->interrupt,
350 EvtChn_Interrupt,
351 xpdd,
352 NULL,
353 xpdd->irq_vector,
354 xpdd->irq_level,
355 xpdd->irq_level,
356 LevelSensitive,
357 TRUE,
358 xpdd->irq_affinity,
359 FALSE);
361 if (!NT_SUCCESS(status))
362 {
363 KdPrint((__DRIVER_NAME " IoConnectInterrupt failed 0x%08x\n", status));
364 return status;
365 }
366 return status;
367 }
369 NTSTATUS
370 EvtChn_Shutdown(PXENPCI_DEVICE_DATA xpdd)
371 {
372 #if (NTDDI_VERSION < NTDDI_WINXP)
373 int i;
374 #endif
376 IoDisconnectInterrupt(xpdd->interrupt);
378 #if (NTDDI_VERSION >= NTDDI_WINXP)
379 KeFlushQueuedDpcs();
380 #else
381 for (i = 0; i < NR_EVENTS; i++)
382 {
383 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_DPC || xpdd->ev_actions[i].type == EVT_ACTION_TYPE_IRQ)
384 {
385 KeRemoveQueueDpc(&xpdd->ev_actions[i].Dpc);
386 }
387 }
388 #endif
390 return STATUS_SUCCESS;
391 }