win-pvdrivers

view xenpci/evtchn.c @ 547:ac614e49832c

Fixed another typo
author James Harper <james.harper@bendigoit.com.au>
date Sun Mar 08 14:37:45 2009 +1100 (2009-03-08)
parents e75bb8d68370
children d56ecda9e61f
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 #define xchg(p1, p2) InterlockedExchange((xen_long_t * volatile)p1, p2)
24 /* rest implemented in mingw_extras.c */
25 #elif defined(_X86_)
26 #define xchg(p1, p2) InterlockedExchange(p1, p2)
27 #define synch_clear_bit(p1, p2) InterlockedBitTestAndReset(p2, p1)
28 #define synch_set_bit(p1, p2) InterlockedBitTestAndSet(p2, p1)
29 #define bit_scan_forward(p1, p2) _BitScanForward(p1, p2)
30 #else
31 #define xchg(p1, p2) InterlockedExchange64(p1, p2)
32 #define synch_clear_bit(p1, p2) _interlockedbittestandreset64(p2, p1)
33 #define synch_set_bit(p1, p2) _interlockedbittestandset64(p2, p1)
34 #define bit_scan_forward(p1, p2) _BitScanForward64(p1, p2)
35 #endif
37 #define BITS_PER_LONG (sizeof(xen_ulong_t) * 8)
38 #define BITS_PER_LONG_SHIFT (5 + (sizeof(xen_ulong_t) >> 3))
40 static DDKAPI VOID
41 EvtChn_DpcBounce(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2)
42 {
43 ev_action_t *action = Context;
45 UNREFERENCED_PARAMETER(Dpc);
46 UNREFERENCED_PARAMETER(SystemArgument1);
47 UNREFERENCED_PARAMETER(SystemArgument2);
49 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
51 if (action->type != EVT_ACTION_TYPE_EMPTY)
52 {
53 action->ServiceRoutine(action->ServiceContext);
54 }
55 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
56 }
58 /* Called at DIRQL */
59 BOOLEAN
60 EvtChn_AckEvent(PVOID context, evtchn_port_t port)
61 {
62 PXENPCI_DEVICE_DATA xpdd = context;
63 ULONG evt_word;
64 ULONG evt_bit;
65 xen_ulong_t val;
67 evt_bit = port & (BITS_PER_LONG - 1);
68 evt_word = port >> BITS_PER_LONG_SHIFT;
70 val = synch_clear_bit(evt_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[evt_word]);
71 //KdPrint((__DRIVER_NAME " EvtChn_AckEvent work[0] = %08x, port %d = %d\n", xpdd->evtchn_pending_pvt[0], port, val));
73 return (BOOLEAN)!!val;
74 }
76 BOOLEAN
77 EvtChn_EvtInterruptIsr(WDFINTERRUPT interrupt, ULONG message_id)
78 {
79 /*
80 For HVM domains, Xen always triggers the event on CPU0. Because the
81 interrupt is delivered via the virtual PCI device it might get delivered
82 to CPU != 0, but we should always use vcpu_info[0]
83 */
84 int cpu = 0;
85 vcpu_info_t *vcpu_info;
86 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfInterruptGetDevice(interrupt));
87 shared_info_t *shared_info_area = xpdd->shared_info_area;
88 xen_ulong_t evt_words;
89 unsigned long evt_word;
90 unsigned long evt_bit;
91 unsigned int port;
92 ev_action_t *ev_action;
93 BOOLEAN handled = FALSE;
94 BOOLEAN deferred = FALSE;
95 int i;
97 UNREFERENCED_PARAMETER(message_id);
99 if (xpdd->interrupts_masked)
100 {
101 KdPrint((__DRIVER_NAME " unhandled interrupt\n"));
102 }
104 if (xpdd->hibernated)
105 {
106 KdPrint((__DRIVER_NAME " interrupt while hibernated\n"));
107 }
109 for (i = 0; i < ARRAY_SIZE(xpdd->evtchn_pending_pvt); i++)
110 {
111 if (xpdd->evtchn_pending_pvt[i])
112 {
113 KdPrint((__DRIVER_NAME " Unacknowledged event word = %d, val = %p\n", i, xpdd->evtchn_pending_pvt[i]));
114 xpdd->evtchn_pending_pvt[i] = 0;
115 }
116 }
118 vcpu_info = &shared_info_area->vcpu_info[cpu];
120 vcpu_info->evtchn_upcall_pending = 0;
122 if (xpdd->interrupts_masked)
123 {
124 return TRUE;
125 }
127 evt_words = (xen_ulong_t)xchg((volatile xen_long_t *)&vcpu_info->evtchn_pending_sel, 0);
129 while (bit_scan_forward(&evt_word, evt_words))
130 {
131 evt_words &= ~(1 << evt_word);
132 while (bit_scan_forward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
133 {
134 synch_clear_bit(evt_bit, (volatile xen_long_t *)&shared_info_area->evtchn_pending[evt_word]);
135 handled = TRUE;
136 port = (evt_word << BITS_PER_LONG_SHIFT) + evt_bit;
137 ev_action = &xpdd->ev_actions[port];
138 ev_action->count++;
139 switch (ev_action->type)
140 {
141 case EVT_ACTION_TYPE_NORMAL:
142 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_NORMAL\n"));
143 ev_action->ServiceRoutine(ev_action->ServiceContext);
144 break;
145 case EVT_ACTION_TYPE_IRQ:
146 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_IRQ\n"));
147 synch_set_bit(evt_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[evt_word]);
148 deferred = TRUE;
149 break;
150 case EVT_ACTION_TYPE_DPC:
151 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_DPC\n"));
152 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
153 break;
154 case EVT_ACTION_TYPE_SUSPEND:
155 KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_SUSPEND\n"));
156 for (i = 0; i < ARRAY_SIZE(xpdd->evtchn_pending_pvt); i++)
157 {
158 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_IRQ)
159 {
160 int suspend_bit = i & (BITS_PER_LONG - 1);
161 int suspend_word = i >> BITS_PER_LONG_SHIFT;
162 synch_set_bit(suspend_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[suspend_word]);
163 }
164 else if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_NORMAL && xpdd->ev_actions[i].ServiceRoutine)
165 {
166 xpdd->ev_actions[i].ServiceRoutine(xpdd->ev_actions[i].ServiceContext);
167 }
168 }
169 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
170 deferred = TRUE;
171 break;
172 default:
173 KdPrint((__DRIVER_NAME " Unhandled Event!!!\n"));
174 break;
175 }
176 }
177 }
179 return handled && !deferred;
180 }
182 NTSTATUS
183 EvtChn_EvtInterruptEnable(WDFINTERRUPT interrupt, WDFDEVICE device)
184 {
185 NTSTATUS status = STATUS_SUCCESS;
187 UNREFERENCED_PARAMETER(interrupt);
188 UNREFERENCED_PARAMETER(device);
190 FUNCTION_ENTER();
191 FUNCTION_EXIT();
193 return status;
194 }
196 NTSTATUS
197 EvtChn_EvtInterruptDisable(WDFINTERRUPT interrupt, WDFDEVICE device)
198 {
199 NTSTATUS status = STATUS_SUCCESS;
201 UNREFERENCED_PARAMETER(interrupt);
202 UNREFERENCED_PARAMETER(device);
204 FUNCTION_ENTER();
205 FUNCTION_EXIT();
207 return status;
208 }
210 NTSTATUS
211 EvtChn_Bind(PVOID Context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
212 {
213 PXENPCI_DEVICE_DATA xpdd = Context;
215 FUNCTION_ENTER();
217 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
218 {
219 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
220 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
221 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
222 }
224 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
225 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
226 xpdd->ev_actions[Port].xpdd = xpdd;
227 KeMemoryBarrier();
228 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_NORMAL;
230 EvtChn_Unmask(Context, Port);
232 FUNCTION_EXIT();
234 return STATUS_SUCCESS;
235 }
237 NTSTATUS
238 EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
239 {
240 PXENPCI_DEVICE_DATA xpdd = Context;
242 FUNCTION_ENTER();
244 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
245 {
246 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
247 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
248 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
249 }
251 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
252 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
253 xpdd->ev_actions[Port].xpdd = xpdd;
254 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
255 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
256 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_DPC;
258 EvtChn_Unmask(Context, Port);
260 FUNCTION_EXIT();
262 return STATUS_SUCCESS;
263 }
265 NTSTATUS
266 EvtChn_BindIrq(PVOID Context, evtchn_port_t Port, ULONG vector, PCHAR description)
267 {
268 PXENPCI_DEVICE_DATA xpdd = Context;
270 FUNCTION_ENTER();
272 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
273 {
274 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
275 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
276 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
277 }
279 xpdd->ev_actions[Port].vector = vector;
280 xpdd->ev_actions[Port].xpdd = xpdd;
281 KeMemoryBarrier();
282 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_IRQ;
283 strncpy(xpdd->ev_actions[Port].description, description, 128);
285 EvtChn_Unmask(Context, Port);
287 FUNCTION_EXIT();
289 return STATUS_SUCCESS;
290 }
292 NTSTATUS
293 EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
294 {
295 PXENPCI_DEVICE_DATA xpdd = Context;
296 int old_type;
298 EvtChn_Mask(Context, Port);
299 old_type = xpdd->ev_actions[Port].type;
300 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
301 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
302 xpdd->ev_actions[Port].ServiceRoutine = NULL;
303 xpdd->ev_actions[Port].ServiceContext = NULL;
305 if (old_type == EVT_ACTION_TYPE_DPC)
306 KeRemoveQueueDpc(&xpdd->ev_actions[Port].Dpc);
308 return STATUS_SUCCESS;
309 }
311 NTSTATUS
312 EvtChn_Mask(PVOID Context, evtchn_port_t port)
313 {
314 PXENPCI_DEVICE_DATA xpdd = Context;
316 synch_set_bit(port & (BITS_PER_LONG - 1),
317 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[port >> BITS_PER_LONG_SHIFT]);
318 return STATUS_SUCCESS;
319 }
321 NTSTATUS
322 EvtChn_Unmask(PVOID context, evtchn_port_t port)
323 {
324 PXENPCI_DEVICE_DATA xpdd = context;
326 synch_clear_bit(port & (BITS_PER_LONG - 1),
327 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[port >> BITS_PER_LONG_SHIFT]);
328 return STATUS_SUCCESS;
329 }
331 NTSTATUS
332 EvtChn_Notify(PVOID Context, evtchn_port_t Port)
333 {
334 PXENPCI_DEVICE_DATA xpdd = Context;
335 struct evtchn_send send;
337 send.port = Port;
338 (void)HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_send, &send);
339 return STATUS_SUCCESS;
340 }
342 evtchn_port_t
343 EvtChn_AllocIpi(PVOID context, ULONG vcpu)
344 {
345 PXENPCI_DEVICE_DATA xpdd = context;
346 evtchn_bind_ipi_t op;
348 FUNCTION_ENTER();
349 op.vcpu = vcpu;
350 op.port = 0;
351 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_bind_ipi, &op);
352 FUNCTION_EXIT();
353 return op.port;
354 }
356 evtchn_port_t
357 EvtChn_AllocUnbound(PVOID Context, domid_t Domain)
358 {
359 PXENPCI_DEVICE_DATA xpdd = Context;
360 evtchn_alloc_unbound_t op;
361 op.dom = DOMID_SELF;
362 op.remote_dom = Domain;
363 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_alloc_unbound, &op);
364 return op.port;
365 }
367 VOID
368 EvtChn_Close(PVOID Context, evtchn_port_t port )
369 {
370 PXENPCI_DEVICE_DATA xpdd = Context;
371 evtchn_close_t op;
372 op.port = port;
373 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_close, &op);
374 return;
375 }
377 VOID
378 EvtChn_PdoEventChannelDpc(PVOID context)
379 {
380 PXENPCI_DEVICE_DATA xpdd = context;
382 FUNCTION_ENTER();
383 KeSetEvent(&xpdd->pdo_suspend_event, IO_NO_INCREMENT, FALSE);
384 FUNCTION_EXIT();
385 }
387 NTSTATUS
388 EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
389 {
390 ULONGLONG result;
391 int i;
393 FUNCTION_ENTER();
395 for (i = 0; i < NR_EVENTS; i++)
396 {
397 EvtChn_Mask(xpdd, i);
398 xpdd->ev_actions[i].type = EVT_ACTION_TYPE_EMPTY;
399 xpdd->ev_actions[i].count = 0;
400 }
402 for (i = 0; i < 8; i++)
403 {
404 xpdd->shared_info_area->evtchn_pending[i] = 0;
405 }
407 for (i = 0; i < MAX_VIRT_CPUS; i++)
408 {
409 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
410 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
411 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1; /* apparantly this doesn't do anything */
412 }
414 KeMemoryBarrier();
416 result = hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, xpdd->irq_number);
417 KdPrint((__DRIVER_NAME " hvm_set_parameter(HVM_PARAM_CALLBACK_IRQ, %d) = %d\n", xpdd->irq_number, (ULONG)result));
419 for (i = 0; i < MAX_VIRT_CPUS; i++)
420 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 0;
421 xpdd->interrupts_masked = FALSE;
422 KeMemoryBarrier();
424 KeInitializeEvent(&xpdd->pdo_suspend_event, SynchronizationEvent, FALSE);
425 xpdd->pdo_event_channel = EvtChn_AllocIpi(xpdd, 0);
426 EvtChn_BindDpc(xpdd, xpdd->pdo_event_channel, EvtChn_PdoEventChannelDpc, xpdd);
427 xpdd->ev_actions[xpdd->pdo_event_channel].type = EVT_ACTION_TYPE_SUSPEND; /* override dpc type */
429 KdPrint((__DRIVER_NAME " pdo_event_channel = %d\n", xpdd->pdo_event_channel));
431 FUNCTION_EXIT();
433 return STATUS_SUCCESS;
434 }
436 NTSTATUS
437 EvtChn_Suspend(PXENPCI_DEVICE_DATA xpdd)
438 {
439 int i;
440 // LARGE_INTEGER wait_time;
442 xpdd->interrupts_masked = TRUE;
443 for (i = 0; i < MAX_VIRT_CPUS; i++)
444 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1;
445 KeMemoryBarrier();
446 hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, 0);
448 for (i = 0; i < NR_EVENTS; i++)
449 {
450 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_DPC)
451 {
452 KeRemoveQueueDpc(&xpdd->ev_actions[i].Dpc);
453 }
454 }
455 #if (NTDDI_VERSION >= NTDDI_WINXP)
456 KeFlushQueuedDpcs();
457 #endif
459 return STATUS_SUCCESS;
460 }
462 NTSTATUS
463 EvtChn_Resume(PXENPCI_DEVICE_DATA xpdd)
464 {
465 return EvtChn_Init(xpdd);