win-pvdrivers

annotate xenpci/evtchn.c @ 651:8b3dae86a7f6

nothing
author James Harper <james.harper@bendigoit.com.au>
date Mon Sep 07 13:31:22 2009 +1000 (2009-09-07)
parents 19b4c4d2b621
children 5bdb7251370c
rev   line source
james@0 1 /*
james@0 2 PV Drivers for Windows Xen HVM Domains
james@0 3 Copyright (C) 2007 James Harper
james@0 4
james@0 5 This program is free software; you can redistribute it and/or
james@0 6 modify it under the terms of the GNU General Public License
james@0 7 as published by the Free Software Foundation; either version 2
james@0 8 of the License, or (at your option) any later version.
james@0 9
james@0 10 This program is distributed in the hope that it will be useful,
james@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@0 13 GNU General Public License for more details.
james@0 14
james@0 15 You should have received a copy of the GNU General Public License
james@0 16 along with this program; if not, write to the Free Software
james@0 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@0 18 */
james@0 19
james@0 20 #include "xenpci.h"
james@0 21
andy@338 22 #if defined(__MINGW32__)
andy@338 23 #define xchg(p1, p2) InterlockedExchange((xen_long_t * volatile)p1, p2)
andy@398 24 /* rest implemented in mingw_extras.c */
james@360 25 #elif defined(_X86_)
james@432 26 #define xchg(p1, p2) InterlockedExchange(p1, p2)
james@432 27 #define synch_clear_bit(p1, p2) InterlockedBitTestAndReset(p2, p1)
james@432 28 #define synch_set_bit(p1, p2) InterlockedBitTestAndSet(p2, p1)
james@147 29 #define bit_scan_forward(p1, p2) _BitScanForward(p1, p2)
james@147 30 #else
james@432 31 #define xchg(p1, p2) InterlockedExchange64(p1, p2)
james@579 32 #define synch_clear_bit(p1, p2) InterlockedBitTestAndReset64(p2, p1)
james@579 33 #define synch_set_bit(p1, p2) InterlockedBitTestAndSet64(p2, p1)
james@147 34 #define bit_scan_forward(p1, p2) _BitScanForward64(p1, p2)
james@147 35 #endif
james@147 36
james@432 37 #define BITS_PER_LONG (sizeof(xen_ulong_t) * 8)
james@432 38 #define BITS_PER_LONG_SHIFT (5 + (sizeof(xen_ulong_t) >> 3))
james@432 39
andy@338 40 static DDKAPI VOID
james@258 41 EvtChn_DpcBounce(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2)
james@73 42 {
james@258 43 ev_action_t *action = Context;
james@73 44
james@258 45 UNREFERENCED_PARAMETER(Dpc);
james@258 46 UNREFERENCED_PARAMETER(SystemArgument1);
james@258 47 UNREFERENCED_PARAMETER(SystemArgument2);
james@258 48
james@651 49 //FUNCTION_ENTER();
james@341 50
james@536 51 if (action->type != EVT_ACTION_TYPE_EMPTY)
james@364 52 {
james@515 53 action->ServiceRoutine(action->ServiceContext);
james@364 54 }
james@651 55 //FUNCTION_EXIT();
james@73 56 }
james@73 57
james@416 58 /* Called at DIRQL */
james@416 59 BOOLEAN
james@561 60 EvtChn_AckEvent(PVOID context, evtchn_port_t port, BOOLEAN *last_interrupt)
james@416 61 {
james@416 62 PXENPCI_DEVICE_DATA xpdd = context;
james@575 63 ULONG pcpu = KeGetCurrentProcessorNumber() & 0xff;
james@416 64 ULONG evt_word;
james@416 65 ULONG evt_bit;
james@416 66 xen_ulong_t val;
james@561 67 int i;
james@432 68
james@432 69 evt_bit = port & (BITS_PER_LONG - 1);
james@432 70 evt_word = port >> BITS_PER_LONG_SHIFT;
james@416 71
james@575 72 val = synch_clear_bit(evt_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[pcpu][evt_word]);
james@575 73 *last_interrupt = TRUE;
james@561 74 for (i = 0; i < sizeof(xen_ulong_t) * 8; i++)
james@561 75 {
james@575 76 if (xpdd->evtchn_pending_pvt[pcpu][i])
james@561 77 {
james@575 78 *last_interrupt = FALSE;
james@561 79 break;
james@561 80 }
james@561 81 }
james@416 82
james@416 83 return (BOOLEAN)!!val;
james@416 84 }
james@416 85
james@575 86 volatile ULONG in_inq = 0;
james@575 87
james@536 88 BOOLEAN
james@536 89 EvtChn_EvtInterruptIsr(WDFINTERRUPT interrupt, ULONG message_id)
james@0 90 {
james@417 91 /*
james@417 92 For HVM domains, Xen always triggers the event on CPU0. Because the
james@417 93 interrupt is delivered via the virtual PCI device it might get delivered
james@417 94 to CPU != 0, but we should always use vcpu_info[0]
james@417 95 */
james@575 96 int vcpu = 0;
james@575 97 ULONG pcpu = KeGetCurrentProcessorNumber() & 0xff;
james@0 98 vcpu_info_t *vcpu_info;
james@536 99 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfInterruptGetDevice(interrupt));
andy@68 100 shared_info_t *shared_info_area = xpdd->shared_info_area;
james@147 101 xen_ulong_t evt_words;
james@147 102 unsigned long evt_word;
james@73 103 unsigned long evt_bit;
james@147 104 unsigned int port;
james@73 105 ev_action_t *ev_action;
james@364 106 BOOLEAN handled = FALSE;
james@416 107 BOOLEAN deferred = FALSE;
james@422 108 int i;
andy@68 109
james@536 110 UNREFERENCED_PARAMETER(message_id);
james@536 111
james@536 112 if (xpdd->interrupts_masked)
james@406 113 {
james@536 114 KdPrint((__DRIVER_NAME " unhandled interrupt\n"));
james@406 115 }
james@450 116
james@538 117 if (xpdd->hibernated)
james@538 118 {
james@538 119 KdPrint((__DRIVER_NAME " interrupt while hibernated\n"));
james@538 120 }
james@538 121
james@575 122 for (i = 0; i < ARRAY_SIZE(xpdd->evtchn_pending_pvt[pcpu]); i++)
james@432 123 {
james@575 124 if (xpdd->evtchn_pending_pvt[pcpu][i])
james@432 125 {
james@575 126 KdPrint((__DRIVER_NAME " Unacknowledged event word = %d, val = %p\n", i, xpdd->evtchn_pending_pvt[pcpu][i]));
james@575 127 xpdd->evtchn_pending_pvt[pcpu][i] = 0;
james@432 128 }
james@432 129 }
james@432 130
james@575 131 vcpu_info = &shared_info_area->vcpu_info[vcpu];
andy@68 132
andy@68 133 vcpu_info->evtchn_upcall_pending = 0;
andy@68 134
james@450 135 if (xpdd->interrupts_masked)
james@450 136 {
james@450 137 return TRUE;
james@450 138 }
james@450 139
james@157 140 evt_words = (xen_ulong_t)xchg((volatile xen_long_t *)&vcpu_info->evtchn_pending_sel, 0);
james@432 141
james@147 142 while (bit_scan_forward(&evt_word, evt_words))
james@0 143 {
james@0 144 evt_words &= ~(1 << evt_word);
james@147 145 while (bit_scan_forward(&evt_bit, shared_info_area->evtchn_pending[evt_word] & ~shared_info_area->evtchn_mask[evt_word]))
james@0 146 {
james@432 147 synch_clear_bit(evt_bit, (volatile xen_long_t *)&shared_info_area->evtchn_pending[evt_word]);
james@364 148 handled = TRUE;
james@432 149 port = (evt_word << BITS_PER_LONG_SHIFT) + evt_bit;
andy@16 150 ev_action = &xpdd->ev_actions[port];
james@411 151 ev_action->count++;
james@267 152 switch (ev_action->type)
james@0 153 {
james@267 154 case EVT_ACTION_TYPE_NORMAL:
james@486 155 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_NORMAL\n"));
james@515 156 ev_action->ServiceRoutine(ev_action->ServiceContext);
james@267 157 break;
james@411 158 case EVT_ACTION_TYPE_IRQ:
james@486 159 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_IRQ\n"));
james@575 160 synch_set_bit(evt_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[pcpu][evt_word]);
james@416 161 deferred = TRUE;
james@411 162 break;
james@267 163 case EVT_ACTION_TYPE_DPC:
james@486 164 //KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_DPC\n"));
james@267 165 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
james@267 166 break;
james@422 167 case EVT_ACTION_TYPE_SUSPEND:
james@536 168 KdPrint((__DRIVER_NAME " EVT_ACTION_TYPE_SUSPEND\n"));
james@575 169 for (i = 0; i < ARRAY_SIZE(xpdd->evtchn_pending_pvt[pcpu]); i++)
james@422 170 {
james@422 171 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_IRQ)
james@422 172 {
james@432 173 int suspend_bit = i & (BITS_PER_LONG - 1);
james@432 174 int suspend_word = i >> BITS_PER_LONG_SHIFT;
james@575 175 synch_set_bit(suspend_bit, (volatile xen_long_t *)&xpdd->evtchn_pending_pvt[pcpu][suspend_word]);
james@422 176 }
james@515 177 else if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_NORMAL && xpdd->ev_actions[i].ServiceRoutine)
james@515 178 {
james@515 179 xpdd->ev_actions[i].ServiceRoutine(xpdd->ev_actions[i].ServiceContext);
james@515 180 }
james@422 181 }
james@536 182 KeInsertQueueDpc(&ev_action->Dpc, NULL, NULL);
james@422 183 deferred = TRUE;
james@422 184 break;
james@267 185 default:
james@267 186 KdPrint((__DRIVER_NAME " Unhandled Event!!!\n"));
james@267 187 break;
james@0 188 }
james@0 189 }
james@0 190 }
james@73 191
james@536 192 return handled && !deferred;
james@536 193 }
james@515 194
james@536 195 NTSTATUS
james@536 196 EvtChn_EvtInterruptEnable(WDFINTERRUPT interrupt, WDFDEVICE device)
james@536 197 {
james@536 198 NTSTATUS status = STATUS_SUCCESS;
james@536 199
james@536 200 UNREFERENCED_PARAMETER(interrupt);
james@536 201 UNREFERENCED_PARAMETER(device);
james@536 202
james@536 203 FUNCTION_ENTER();
james@536 204 FUNCTION_EXIT();
james@536 205
james@536 206 return status;
james@536 207 }
james@536 208
james@536 209 NTSTATUS
james@536 210 EvtChn_EvtInterruptDisable(WDFINTERRUPT interrupt, WDFDEVICE device)
james@536 211 {
james@536 212 NTSTATUS status = STATUS_SUCCESS;
james@536 213
james@536 214 UNREFERENCED_PARAMETER(interrupt);
james@536 215 UNREFERENCED_PARAMETER(device);
james@536 216
james@536 217 FUNCTION_ENTER();
james@536 218 FUNCTION_EXIT();
james@536 219
james@536 220 return status;
james@0 221 }
james@0 222
andy@13 223 NTSTATUS
james@515 224 EvtChn_Bind(PVOID Context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
james@0 225 {
james@258 226 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 227
andy@398 228 FUNCTION_ENTER();
james@267 229
james@267 230 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
james@0 231 {
james@267 232 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
james@73 233 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
james@0 234 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
james@0 235 }
james@0 236
james@267 237 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
andy@16 238 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
james@341 239 xpdd->ev_actions[Port].xpdd = xpdd;
james@0 240 KeMemoryBarrier();
james@267 241 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_NORMAL;
james@0 242
james@258 243 EvtChn_Unmask(Context, Port);
james@0 244
andy@398 245 FUNCTION_EXIT();
james@0 246
james@0 247 return STATUS_SUCCESS;
james@0 248 }
james@0 249
andy@120 250 NTSTATUS
james@515 251 EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
james@73 252 {
james@258 253 PXENPCI_DEVICE_DATA xpdd = Context;
james@73 254
andy@398 255 FUNCTION_ENTER();
james@73 256
james@267 257 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
james@73 258 {
james@267 259 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
james@267 260 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
james@73 261 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
james@73 262 }
james@73 263
james@267 264 xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
james@73 265 xpdd->ev_actions[Port].ServiceContext = ServiceContext;
james@341 266 xpdd->ev_actions[Port].xpdd = xpdd;
james@258 267 KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
james@73 268 KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
james@267 269 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_DPC;
james@73 270
james@258 271 EvtChn_Unmask(Context, Port);
james@73 272
andy@398 273 FUNCTION_EXIT();
james@73 274
james@267 275 return STATUS_SUCCESS;
james@267 276 }
james@73 277
james@267 278 NTSTATUS
james@416 279 EvtChn_BindIrq(PVOID Context, evtchn_port_t Port, ULONG vector, PCHAR description)
james@267 280 {
james@267 281 PXENPCI_DEVICE_DATA xpdd = Context;
james@267 282
andy@398 283 FUNCTION_ENTER();
james@267 284
james@267 285 if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
james@267 286 {
james@267 287 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
james@267 288 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
james@267 289 KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
james@267 290 }
james@267 291
james@267 292 xpdd->ev_actions[Port].vector = vector;
james@341 293 xpdd->ev_actions[Port].xpdd = xpdd;
james@267 294 KeMemoryBarrier();
james@267 295 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_IRQ;
james@416 296 strncpy(xpdd->ev_actions[Port].description, description, 128);
james@267 297
james@267 298 EvtChn_Unmask(Context, Port);
james@267 299
andy@398 300 FUNCTION_EXIT();
james@73 301
james@73 302 return STATUS_SUCCESS;
james@73 303 }
james@73 304
james@0 305 NTSTATUS
andy@13 306 EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
james@0 307 {
james@258 308 PXENPCI_DEVICE_DATA xpdd = Context;
james@432 309 int old_type;
james@258 310
andy@13 311 EvtChn_Mask(Context, Port);
james@432 312 old_type = xpdd->ev_actions[Port].type;
james@432 313 xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
james@432 314 KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
james@115 315 xpdd->ev_actions[Port].ServiceRoutine = NULL;
andy@16 316 xpdd->ev_actions[Port].ServiceContext = NULL;
james@0 317
james@432 318 if (old_type == EVT_ACTION_TYPE_DPC)
james@585 319 {
james@258 320 KeRemoveQueueDpc(&xpdd->ev_actions[Port].Dpc);
james@585 321 KeFlushQueuedDpcs();
james@585 322 }
james@115 323
james@0 324 return STATUS_SUCCESS;
james@0 325 }
james@0 326
james@0 327 NTSTATUS
james@408 328 EvtChn_Mask(PVOID Context, evtchn_port_t port)
james@0 329 {
andy@338 330 PXENPCI_DEVICE_DATA xpdd = Context;
andy@338 331
james@432 332 synch_set_bit(port & (BITS_PER_LONG - 1),
james@432 333 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[port >> BITS_PER_LONG_SHIFT]);
james@0 334 return STATUS_SUCCESS;
james@0 335 }
james@0 336
james@0 337 NTSTATUS
james@408 338 EvtChn_Unmask(PVOID context, evtchn_port_t port)
james@0 339 {
james@408 340 PXENPCI_DEVICE_DATA xpdd = context;
andy@338 341
james@432 342 synch_clear_bit(port & (BITS_PER_LONG - 1),
james@432 343 (volatile xen_long_t *)&xpdd->shared_info_area->evtchn_mask[port >> BITS_PER_LONG_SHIFT]);
james@0 344 return STATUS_SUCCESS;
james@0 345 }
james@0 346
james@0 347 NTSTATUS
andy@338 348 EvtChn_Notify(PVOID Context, evtchn_port_t Port)
james@0 349 {
andy@338 350 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 351 struct evtchn_send send;
james@0 352
james@0 353 send.port = Port;
james@258 354 (void)HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_send, &send);
james@0 355 return STATUS_SUCCESS;
james@0 356 }
james@0 357
andy@13 358 evtchn_port_t
james@464 359 EvtChn_AllocIpi(PVOID context, ULONG vcpu)
james@422 360 {
james@422 361 PXENPCI_DEVICE_DATA xpdd = context;
james@422 362 evtchn_bind_ipi_t op;
james@422 363
james@422 364 FUNCTION_ENTER();
james@422 365 op.vcpu = vcpu;
james@422 366 op.port = 0;
james@422 367 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_bind_ipi, &op);
james@422 368 FUNCTION_EXIT();
james@422 369 return op.port;
james@422 370 }
james@422 371
james@422 372 evtchn_port_t
andy@13 373 EvtChn_AllocUnbound(PVOID Context, domid_t Domain)
andy@13 374 {
james@258 375 PXENPCI_DEVICE_DATA xpdd = Context;
andy@13 376 evtchn_alloc_unbound_t op;
andy@13 377 op.dom = DOMID_SELF;
andy@13 378 op.remote_dom = Domain;
james@258 379 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_alloc_unbound, &op);
andy@13 380 return op.port;
andy@13 381 }
james@0 382
james@408 383 VOID
james@408 384 EvtChn_Close(PVOID Context, evtchn_port_t port )
james@408 385 {
james@408 386 PXENPCI_DEVICE_DATA xpdd = Context;
james@408 387 evtchn_close_t op;
james@408 388 op.port = port;
james@408 389 HYPERVISOR_event_channel_op(xpdd, EVTCHNOP_close, &op);
james@408 390 return;
james@408 391 }
james@408 392
james@536 393 VOID
james@536 394 EvtChn_PdoEventChannelDpc(PVOID context)
james@536 395 {
james@536 396 PXENPCI_DEVICE_DATA xpdd = context;
james@536 397
james@536 398 FUNCTION_ENTER();
james@536 399 KeSetEvent(&xpdd->pdo_suspend_event, IO_NO_INCREMENT, FALSE);
james@536 400 FUNCTION_EXIT();
james@536 401 }
james@536 402
james@389 403 NTSTATUS
james@389 404 EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
james@0 405 {
james@536 406 ULONGLONG result;
james@258 407 int i;
james@0 408
andy@398 409 FUNCTION_ENTER();
james@0 410
james@0 411 for (i = 0; i < NR_EVENTS; i++)
james@0 412 {
james@258 413 EvtChn_Mask(xpdd, i);
james@267 414 xpdd->ev_actions[i].type = EVT_ACTION_TYPE_EMPTY;
james@411 415 xpdd->ev_actions[i].count = 0;
james@0 416 }
james@0 417
andy@13 418 for (i = 0; i < 8; i++)
andy@13 419 {
andy@16 420 xpdd->shared_info_area->evtchn_pending[i] = 0;
james@0 421 }
james@92 422
james@92 423 for (i = 0; i < MAX_VIRT_CPUS; i++)
james@92 424 {
james@92 425 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_pending = 0;
james@92 426 xpdd->shared_info_area->vcpu_info[i].evtchn_pending_sel = 0;
james@408 427 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1; /* apparantly this doesn't do anything */
james@92 428 }
james@0 429
james@406 430 KeMemoryBarrier();
james@406 431
james@536 432 result = hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, xpdd->irq_number);
james@536 433 KdPrint((__DRIVER_NAME " hvm_set_parameter(HVM_PARAM_CALLBACK_IRQ, %d) = %d\n", xpdd->irq_number, (ULONG)result));
james@258 434
james@258 435 for (i = 0; i < MAX_VIRT_CPUS; i++)
james@407 436 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 0;
james@407 437 xpdd->interrupts_masked = FALSE;
james@407 438 KeMemoryBarrier();
james@406 439
james@536 440 KeInitializeEvent(&xpdd->pdo_suspend_event, SynchronizationEvent, FALSE);
james@480 441 xpdd->pdo_event_channel = EvtChn_AllocIpi(xpdd, 0);
james@536 442 EvtChn_BindDpc(xpdd, xpdd->pdo_event_channel, EvtChn_PdoEventChannelDpc, xpdd);
james@536 443 xpdd->ev_actions[xpdd->pdo_event_channel].type = EVT_ACTION_TYPE_SUSPEND; /* override dpc type */
james@258 444
james@480 445 KdPrint((__DRIVER_NAME " pdo_event_channel = %d\n", xpdd->pdo_event_channel));
james@422 446
andy@398 447 FUNCTION_EXIT();
james@389 448
james@389 449 return STATUS_SUCCESS;
james@342 450 }
james@258 451
james@342 452 NTSTATUS
james@536 453 EvtChn_Suspend(PXENPCI_DEVICE_DATA xpdd)
james@258 454 {
james@359 455 int i;
james@406 456 // LARGE_INTEGER wait_time;
james@359 457
james@407 458 xpdd->interrupts_masked = TRUE;
james@406 459 for (i = 0; i < MAX_VIRT_CPUS; i++)
james@406 460 xpdd->shared_info_area->vcpu_info[i].evtchn_upcall_mask = 1;
james@406 461 KeMemoryBarrier();
james@407 462 hvm_set_parameter(xpdd, HVM_PARAM_CALLBACK_IRQ, 0);
james@258 463
james@359 464 for (i = 0; i < NR_EVENTS; i++)
james@359 465 {
james@432 466 if (xpdd->ev_actions[i].type == EVT_ACTION_TYPE_DPC)
james@359 467 {
james@359 468 KeRemoveQueueDpc(&xpdd->ev_actions[i].Dpc);
james@359 469 }
james@359 470 }
james@432 471 KeFlushQueuedDpcs();
james@359 472
james@0 473 return STATUS_SUCCESS;
james@0 474 }
james@536 475
james@536 476 NTSTATUS
james@536 477 EvtChn_Resume(PXENPCI_DEVICE_DATA xpdd)
james@536 478 {
james@536 479 return EvtChn_Init(xpdd);
james@536 480 }