win-pvdrivers

view xenpci/evtchn.c @ 1013:43e76afb2398

Fix compiler warnings under 2000
author James Harper <james.harper@bendigoit.com.au>
date Mon Feb 11 20:59:11 2013 +1100 (2013-02-11)
parents 4f7d5a8636bd
children 37c0c84a42e8
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 /* Not really necessary but keeps PREfast happy */
23 #if (VER_PRODUCTBUILD >= 7600)
24 static KDEFERRED_ROUTINE EvtChn_DpcBounce;
25 #endif
27 #if defined(_X86_)
28 #define xchg(p1, p2) InterlockedExchange(p1, p2)
29 #define synch_clear_bit(p1, p2) InterlockedBitTestAndReset(p2, p1)
30 #define synch_set_bit(p1, p2) InterlockedBitTestAndSet(p2, p1)
31 #define bit_scan_forward(p1, p2) _BitScanForward(p1, p2)
32 #else
33 #define xchg(p1, p2) InterlockedExchange64(p1, p2)
34 #define synch_clear_bit(p1, p2) InterlockedBitTestAndReset64(p2, p1)
35 #define synch_set_bit(p1, p2) InterlockedBitTestAndSet64(p2, p1)
36 #define bit_scan_forward(p1, p2) _BitScanForward64(p1, p2)
37 #endif
39 #define BITS_PER_LONG (sizeof(xen_ulong_t) * 8)
40 #define BITS_PER_LONG_SHIFT (5 + (sizeof(xen_ulong_t) >> 3))
42 static VOID
43 EvtChn_DpcBounce(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2) {
44 ev_action_t *action = Context;
46 UNREFERENCED_PARAMETER(Dpc);
47 UNREFERENCED_PARAMETER(SystemArgument1);
48 UNREFERENCED_PARAMETER(SystemArgument2);
50 //FUNCTION_ENTER();
52 if (action->type != EVT_ACTION_TYPE_EMPTY) {
53 action->ServiceRoutine(action->ServiceContext);
54 }
55 //FUNCTION_EXIT();
56 }
58 #if 0
59 /* Called at DIRQL */
60 BOOLEAN
61 EvtChn_AckEvent(PVOID context, evtchn_port_t port, BOOLEAN *last_interrupt) {
62 PXENPCI_DEVICE_DATA xpdd = context;
63 ULONG pcpu = KeGetCurrentProcessorNumber() & 0xff;
64 ULONG evt_word;
65 ULONG evt_bit;
66 xen_ulong_t val;
67 int i;
69 evt_bit = port & (BITS_PER_LONG - 1);
70 evt_word = port >> BITS_PER_LONG_SHIFT;
72 val = synch_clear_bit(evt_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[pcpu][evt_word]);
73 *last_interrupt = TRUE;
74 for (i = 0; i < ARRAY_SIZE(xpdd->evtchn_pending_pvt[pcpu]); i++)
75 {
76 if (xpdd->evtchn_pending_pvt[pcpu][i])
77 {
78 *last_interrupt = FALSE;
79 break;
80 }
81 }
83 return (BOOLEAN)!!val;
84 }
85 #endif
87 //volatile ULONG in_inq = 0;
89 BOOLEAN
90 EvtChn_EvtInterruptIsr(WDFINTERRUPT interrupt, ULONG message_id)
91 {
92 /*
93 For HVM domains, Xen always triggers the event on CPU0. Because the
94 interrupt is delivered via the virtual PCI device it might get delivered
95 to CPU != 0, but we should always use vcpu_info[0]
96 */
97 int vcpu = 0;
98 ULONG pcpu = KeGetCurrentProcessorNumber() & 0xff;
99 vcpu_info_t *vcpu_info;
100 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfInterruptGetDevice(interrupt));
101 shared_info_t *shared_info_area = xpdd->shared_info_area;
102 xen_ulong_t evt_words;
103 unsigned long evt_word;
104 unsigned long evt_bit;
105 unsigned int port;
106 ev_action_t *ev_action;
107 BOOLEAN handled = FALSE;
108 BOOLEAN deferred = FALSE;
109 int i;
111 UNREFERENCED_PARAMETER(message_id);
113 if (xpdd->interrupts_masked) {
114 KdPrint((__DRIVER_NAME " unhandled interrupt\n"));
115 }
117 if (xpdd->hibernated) {
118 KdPrint((__DRIVER_NAME " interrupt while hibernated\n"));
119 }
121 for (i = 0; i < ARRAY_SIZE(xpdd->evtchn_pending_pvt[pcpu]); i++) {
122 if (xpdd->evtchn_pending_pvt[pcpu][i]) {
123 KdPrint((__DRIVER_NAME " Unacknowledged event word = %d, val = %p\n", i, xpdd->evtchn_pending_pvt[pcpu][i]));
124 xpdd->evtchn_pending_pvt[pcpu][i] = 0;
125 }
126 }
128 vcpu_info = &shared_info_area->vcpu_info[vcpu];
130 vcpu_info->evtchn_upcall_pending = 0;
132 if (xpdd->interrupts_masked)
133 {
134 return TRUE;
135 }
137 evt_words = (xen_ulong_t)xchg((volatile xen_long_t *)&vcpu_info->evtchn_pending_sel, 0);
139 while (bit_scan_forward(&evt_word, evt_words))
140 {
141 evt_words &= ~(1 << evt_word);
142 while (bit_scan_forward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
143 {
144 synch_clear_bit(evt_bit, (volatile xen_long_t *)&shared_info_area->evtchn_pending[evt_word]);
145 handled = TRUE;
146 port = (evt_word << BITS_PER_LONG_SHIFT) + evt_bit;
147 ev_action = &xpdd->ev_actions[port];
148 ev_action->count++;
149 switch (ev_action->type)
150 {
151 case EVT_ACTION_TYPE_NORMAL:
152 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_NORMAL port = %d\n", port));
153 ev_action->ServiceRoutine(ev_action->ServiceContext);
154 break;
155 case EVT_ACTION_TYPE_DPC:
156 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_DPC port = %d\n", port));
157 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
158 break;
159 #if 0
160 case EVT_ACTION_TYPE_SUSPEND:
161 KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_SUSPEND\n"));
162 for (i = 0; i < NR_EVENTS; i++)
163 {
164 if (!(xpdd->ev_actions[i].flags & EVT_ACTION_FLAGS_NO_SUSPEND))
165 {
166 switch(xpdd->ev_actions[i].type)
167 {
168 #if 0
169 case EVT_ACTION_TYPE_IRQ:
170 {
171 int suspend_bit = i & (BITS_PER_LONG - 1);
172 int suspend_word = i >> BITS_PER_LONG_SHIFT;
173 synch_set_bit(suspend_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[pcpu][suspend_word]);
174 }
175 break;
176 #endif
177 case EVT_ACTION_TYPE_NORMAL:
178 if (xpdd->ev_actions[i].ServiceRoutine)
179 {
180 xpdd->ev_actions[i].ServiceRoutine(xpdd->ev_actions[i].ServiceContext);
181 }
182 break;
183 case EVT_ACTION_TYPE_DPC:
184 KeInsertQueueDpc(&xpdd->ev_actions[i].Dpc, NULL, NULL);
185 break;
186 }
187 }
188 }
189 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
190 deferred = TRUE;
191 break;
192 #endif
193 default:
194 KdPrint((__DRIVER_NAME " Unhandled Event!!! port=%d\n", port));
195 break;
196 }
197 }
198 }
200 return handled && !deferred;
201 }
203 NTSTATUS
204 EvtChn_EvtInterruptEnable(WDFINTERRUPT interrupt, WDFDEVICE device)
205 {
206 NTSTATUS status = STATUS_SUCCESS;
208 UNREFERENCED_PARAMETER(interrupt);
209 UNREFERENCED_PARAMETER(device);
211 FUNCTION_ENTER();
212 FUNCTION_EXIT();
214 return status;
215 }
217 NTSTATUS
218 EvtChn_EvtInterruptDisable(WDFINTERRUPT interrupt, WDFDEVICE device)
219 {
220 NTSTATUS status = STATUS_SUCCESS;
222 UNREFERENCED_PARAMETER(interrupt);
223 UNREFERENCED_PARAMETER(device);
225 FUNCTION_ENTER();
226 FUNCTION_EXIT();
228 return status;
229 }
231 NTSTATUS
232 EvtChn_Bind(PVOID Context, evtchn_port_t port, PXN_EVENT_CALLBACK ServiceRoutine, PVOID ServiceContext, ULONG flags)
233 {
234 PXENPCI_DEVICE_DATA xpdd = Context;
235 ev_action_t *action = &xpdd->ev_actions[port];
237 FUNCTION_ENTER();
239 if (InterlockedCompareExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_NEW, EVT_ACTION_TYPE_EMPTY) != EVT_ACTION_TYPE_EMPTY)
240 {
241 KdPrint((__DRIVER_NAME " Handler for port %d already registered\n", port));
242 return STATUS_UNSUCCESSFUL;
243 }
245 xpdd->ev_actions[port].ServiceRoutine = ServiceRoutine;
246 xpdd->ev_actions[port].ServiceContext = ServiceContext;
247 xpdd->ev_actions[port].xpdd = xpdd;
248 xpdd->ev_actions[port].flags = flags;
249 KeMemoryBarrier();
250 xpdd->ev_actions[port].type = EVT_ACTION_TYPE_NORMAL;
252 EvtChn_Unmask(Context, port);
254 FUNCTION_EXIT();
256 return STATUS_SUCCESS;
257 }
259 NTSTATUS
260 EvtChn_BindDpc(PVOID Context, evtchn_port_t port, PXN_EVENT_CALLBACK ServiceRoutine, PVOID ServiceContext, ULONG flags)
261 {
262 PXENPCI_DEVICE_DATA xpdd = Context;
263 ev_action_t *action = &xpdd->ev_actions[port];
265 FUNCTION_ENTER();
267 if (InterlockedCompareExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_NEW, EVT_ACTION_TYPE_EMPTY) != EVT_ACTION_TYPE_EMPTY)
268 {
269 KdPrint((__DRIVER_NAME " Handler for port %d already registered\n", port));
270 return STATUS_UNSUCCESSFUL;
271 }
273 xpdd->ev_actions[port].ServiceRoutine = ServiceRoutine;
274 xpdd->ev_actions[port].ServiceContext = ServiceContext;
275 xpdd->ev_actions[port].xpdd = xpdd;
276 xpdd->ev_actions[port].flags = flags;
277 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
278 InterlockedExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_DPC);
280 EvtChn_Unmask(Context, port);
282 FUNCTION_EXIT();
284 return STATUS_SUCCESS;
285 }
287 #if 0
288 NTSTATUS
289 EvtChn_BindIrq(PVOID Context, evtchn_port_t port, ULONG vector, PCHAR description, ULONG flags)
290 {
291 PXENPCI_DEVICE_DATA xpdd = Context;
292 ev_action_t *action = &xpdd->ev_actions[port];
294 FUNCTION_ENTER();
296 if (InterlockedCompareExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_NEW, EVT_ACTION_TYPE_EMPTY) != EVT_ACTION_TYPE_EMPTY)
297 {
298 KdPrint((__DRIVER_NAME " Handler for port %d already registered\n", port));
299 return STATUS_UNSUCCESSFUL;
300 }
302 xpdd->ev_actions[port].vector = vector;
303 xpdd->ev_actions[port].xpdd = xpdd;
304 KeMemoryBarrier();
305 xpdd->ev_actions[port].type = EVT_ACTION_TYPE_IRQ;
306 RtlStringCbCopyA(xpdd->ev_actions[port].description, 128, description);
307 xpdd->ev_actions[port].flags = flags;
309 EvtChn_Unmask(Context, port);
311 FUNCTION_EXIT();
313 return STATUS_SUCCESS;
314 }
315 #endif
317 NTSTATUS
318 EvtChn_Unbind(PVOID Context, evtchn_port_t port) {
319 PXENPCI_DEVICE_DATA xpdd = Context;
320 ev_action_t *action = &xpdd->ev_actions[port];
321 int old_type;
323 EvtChn_Mask(Context, port);
324 old_type = InterlockedExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_EMPTY);
326 if (old_type == EVT_ACTION_TYPE_DPC) { // || old_type == EVT_ACTION_TYPE_SUSPEND) {
327 KeRemoveQueueDpc(&xpdd->ev_actions[port].Dpc);
328 #if (NTDDI_VERSION >= NTDDI_WINXP)
329 KeFlushQueuedDpcs();
330 #endif
331 }
333 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
334 xpdd->ev_actions[port].ServiceRoutine = NULL;
335 xpdd->ev_actions[port].ServiceContext = NULL;
337 return STATUS_SUCCESS;
338 }
340 NTSTATUS
341 EvtChn_Mask(PVOID Context, evtchn_port_t port) {
342 PXENPCI_DEVICE_DATA xpdd = Context;
344 synch_set_bit(port & (BITS_PER_LONG - 1),
345 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[port >> BITS_PER_LONG_SHIFT]);
346 return STATUS_SUCCESS;
347 }
349 NTSTATUS
350 EvtChn_Unmask(PVOID context, evtchn_port_t port) {
351 PXENPCI_DEVICE_DATA xpdd = context;
353 synch_clear_bit(port & (BITS_PER_LONG - 1),
354 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[port >> BITS_PER_LONG_SHIFT]);
355 return STATUS_SUCCESS;
356 }
358 NTSTATUS
359 EvtChn_Notify(PVOID Context, evtchn_port_t port) {
360 PXENPCI_DEVICE_DATA xpdd = Context;
361 struct evtchn_send send;
363 send.port = port;
364 (void)HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_send, &send);
365 return STATUS_SUCCESS;
366 }
368 evtchn_port_t
369 EvtChn_AllocIpi(PVOID context, ULONG vcpu) {
370 PXENPCI_DEVICE_DATA xpdd = context;
371 evtchn_bind_ipi_t op;
373 FUNCTION_ENTER();
374 op.vcpu = vcpu;
375 op.port = 0;
376 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_bind_ipi, &op);
377 FUNCTION_EXIT();
378 return op.port;
379 }
381 evtchn_port_t
382 EvtChn_AllocUnbound(PVOID Context, domid_t Domain) {
383 PXENPCI_DEVICE_DATA xpdd = Context;
384 evtchn_alloc_unbound_t op;
385 op.dom = DOMID_SELF;
386 op.remote_dom = Domain;
387 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_alloc_unbound, &op);
388 return op.port;
389 }
391 VOID
392 EvtChn_Close(PVOID Context, evtchn_port_t port) {
393 PXENPCI_DEVICE_DATA xpdd = Context;
394 evtchn_close_t op;
395 op.port = port;
396 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_close, &op);
397 return;
398 }
400 #if 0
401 VOID
402 EvtChn_PdoEventChannelDpc(PVOID context)
403 {
404 PXENPCI_DEVICE_DATA xpdd = context;
406 FUNCTION_ENTER();
407 KeSetEvent(&xpdd->pdo_suspend_event, IO_NO_INCREMENT, FALSE);
408 FUNCTION_EXIT();
409 }
410 #endif
412 NTSTATUS
413 EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
414 {
415 ULONGLONG result;
416 ev_action_t *action;
417 int i;
419 FUNCTION_ENTER();
421 for (i = 0; i < NR_EVENTS; i++)
422 {
423 EvtChn_Mask(xpdd, i);
424 action = &xpdd->ev_actions[i];
425 action->type = EVT_ACTION_TYPE_EMPTY;
426 //action->port = -1;
427 action->count = 0;
428 KeInitializeDpc(&action->Dpc, EvtChn_DpcBounce, action);
429 }
431 for (i = 0; i < 8; i++) {
432 xpdd->shared_info_area->evtchn_pending[i] = 0;
433 }
435 for (i = 0; i < MAX_VIRT_CPUS; i++) {
436 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
437 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
438 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1; /* apparantly this doesn't do anything */
439 }
441 KeMemoryBarrier();
443 result = hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, xpdd->irq_number);
444 KdPrint((__DRIVER_NAME " hvm_set_parameter(HVM_PARAM_CALLBACK_IRQ, %d) = %d\n", xpdd->irq_number, (ULONG)result));
446 for (i = 0; i < MAX_VIRT_CPUS; i++)
447 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 0;
448 xpdd->interrupts_masked = FALSE;
449 KeMemoryBarrier();
451 #if 0
452 KeInitializeEvent(&xpdd->pdo_suspend_event, SynchronizationEvent, FALSE);
453 xpdd->pdo_event_channel = EvtChn_AllocIpi(xpdd, 0);
454 EvtChn_BindDpc(xpdd, xpdd->pdo_event_channel, EvtChn_PdoEventChannelDpc, xpdd, EVT_ACTION_FLAGS_DEFAULT);
455 xpdd->ev_actions[xpdd->pdo_event_channel].type = EVT_ACTION_TYPE_SUSPEND; /* override dpc type */
456 KdPrint((__DRIVER_NAME " pdo_event_channel = %d\n", xpdd->pdo_event_channel));
457 #endif
459 FUNCTION_EXIT();
461 return STATUS_SUCCESS;
462 }
464 NTSTATUS
465 EvtChn_Suspend(PXENPCI_DEVICE_DATA xpdd)
466 {
467 int i;
469 xpdd->interrupts_masked = TRUE;
470 for (i = 0; i < MAX_VIRT_CPUS; i++)
471 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1;
472 KeMemoryBarrier();
473 hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, 0);
475 for (i = 0; i < NR_EVENTS; i++) {
476 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_DPC) {
477 KeRemoveQueueDpc(&xpdd->ev_actions[i].Dpc);
478 }
479 }
480 #if (NTDDI_VERSION >= NTDDI_WINXP)
481 KeFlushQueuedDpcs();
482 #endif
483 return STATUS_SUCCESS;
484 }
486 NTSTATUS
487 EvtChn_Resume(PXENPCI_DEVICE_DATA xpdd)
488 {
489 return EvtChn_Init(xpdd);