win-pvdrivers

view xennet/xennet.c @ 266:b88529df8b60

More wdm updates
author James Harper <james.harper@bendigoit.com.au>
date Wed May 07 10:47:03 2008 +1000 (2008-05-07)
parents 58ce01887603
children da9b1e17fbc0
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
21 #include <stdlib.h>
22 #include <io/xenbus.h>
23 #include "xennet.h"
25 LARGE_INTEGER ProfTime_TxBufferGC;
26 LARGE_INTEGER ProfTime_RxBufferAlloc;
27 LARGE_INTEGER ProfTime_ReturnPacket;
28 LARGE_INTEGER ProfTime_RxBufferCheck;
29 LARGE_INTEGER ProfTime_Linearize;
30 LARGE_INTEGER ProfTime_SendPackets;
31 LARGE_INTEGER ProfTime_SendQueuedPackets;
32 LARGE_INTEGER ProfTime_RxBufferCheckTopHalf;
33 LARGE_INTEGER ProfTime_RxBufferCheckBotHalf;
35 int ProfCount_TxBufferGC;
36 int ProfCount_RxBufferAlloc;
37 int ProfCount_ReturnPacket;
38 int ProfCount_RxBufferCheck;
39 int ProfCount_Linearize;
40 int ProfCount_SendPackets;
41 int ProfCount_PacketsPerSendPackets;
42 int ProfCount_SendQueuedPackets;
44 int ProfCount_TxPacketsTotal;
45 int ProfCount_TxPacketsCsumOffload;
46 int ProfCount_TxPacketsLargeOffload;
47 int ProfCount_RxPacketsTotal;
48 int ProfCount_RxPacketsCsumOffload;
49 int ProfCount_CallsToIndicateReceive;
51 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
52 static unsigned long
53 simple_strtoul(const char *cp,char **endp,unsigned int base)
54 {
55 unsigned long result = 0,value;
57 if (!base) {
58 base = 10;
59 if (*cp == '0') {
60 base = 8;
61 cp++;
62 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
63 cp++;
64 base = 16;
65 }
66 }
67 } else if (base == 16) {
68 if (cp[0] == '0' && toupper(cp[1]) == 'X')
69 cp += 2;
70 }
71 while (isxdigit(*cp) &&
72 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
73 result = result*base + value;
74 cp++;
75 }
76 if (endp)
77 *endp = (char *)cp;
78 return result;
79 }
81 // Called at DISPATCH_LEVEL
83 static BOOLEAN
84 XenNet_Interrupt(
85 PKINTERRUPT Interrupt,
86 PVOID ServiceContext
87 )
88 {
89 struct xennet_info *xi = ServiceContext;
91 UNREFERENCED_PARAMETER(Interrupt);
93 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
94 if (xi->connected)
95 {
96 XenNet_TxBufferGC(xi);
97 XenNet_RxBufferCheck(xi);
98 }
99 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
101 return TRUE;
102 }
104 // Called at <= DISPATCH_LEVEL
106 static VOID
107 XenNet_BackEndStateHandler(char *Path, PVOID Data)
108 {
109 struct xennet_info *xi = Data;
110 char *Value;
111 char *err;
112 ULONG new_backend_state;
114 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
115 // KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
117 err = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
118 XBT_NIL, Path, &Value);
119 if (err)
120 {
121 KdPrint(("Failed to read %s\n", Path, err));
122 return;
123 }
124 new_backend_state = atoi(Value);
125 xi->XenInterface.FreeMem(Value);
127 if (xi->backend_state == new_backend_state)
128 {
129 KdPrint((__DRIVER_NAME " state unchanged\n"));
130 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
131 return;
132 }
134 xi->backend_state = new_backend_state;
136 switch (xi->backend_state)
137 {
138 case XenbusStateUnknown:
139 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
140 break;
142 case XenbusStateInitialising:
143 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
144 break;
146 case XenbusStateInitWait:
147 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
148 break;
150 case XenbusStateInitialised:
151 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
152 break;
154 case XenbusStateConnected:
155 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
156 break;
158 case XenbusStateClosing:
159 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
160 break;
162 case XenbusStateClosed:
163 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
164 break;
166 default:
167 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xi->backend_state));
168 break;
169 }
171 KeSetEvent(&xi->backend_state_change_event, 1, FALSE);
173 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
175 return;
176 }
178 static NDIS_STATUS
179 XenNet_Init(
180 OUT PNDIS_STATUS OpenErrorStatus,
181 OUT PUINT SelectedMediumIndex,
182 IN PNDIS_MEDIUM MediumArray,
183 IN UINT MediumArraySize,
184 IN NDIS_HANDLE MiniportAdapterHandle,
185 IN NDIS_HANDLE WrapperConfigurationContext
186 )
187 {
188 NDIS_STATUS status;
189 LARGE_INTEGER timeout;
190 UINT i;
191 BOOLEAN medium_found = FALSE;
192 struct xennet_info *xi = NULL;
193 ULONG length;
194 WDF_OBJECT_ATTRIBUTES wdf_attrs;
195 char *res;
196 char *Value;
197 char TmpPath[MAX_XENBUS_STR_LEN];
198 struct set_params {
199 char *name;
200 int value;
201 } params[] = {
202 {"tx-ring-ref", 0},
203 {"rx-ring-ref", 0},
204 {"event-channel", 0},
205 {"feature-no-csum-offload", 1},
206 {"feature-sg", 1},
207 {"feature-gso-tcpv4", 1},
208 {"request-rx-copy", 1},
209 {"feature-rx-notify", 1},
210 {NULL, 0},
211 };
212 int retry = 0;
213 char *err;
214 xenbus_transaction_t xbt = 0;
215 NDIS_HANDLE config_handle;
216 NDIS_STRING config_param_name;
217 PNDIS_CONFIGURATION_PARAMETER config_param;
219 UNREFERENCED_PARAMETER(OpenErrorStatus);
221 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
222 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
224 /* deal with medium stuff */
225 for (i = 0; i < MediumArraySize; i++)
226 {
227 if (MediumArray[i] == NdisMedium802_3)
228 {
229 medium_found = TRUE;
230 break;
231 }
232 }
233 if (!medium_found)
234 {
235 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
236 return NDIS_STATUS_UNSUPPORTED_MEDIA;
237 }
238 *SelectedMediumIndex = i;
240 /* Alloc memory for adapter private info */
241 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
242 if (!NT_SUCCESS(status))
243 {
244 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
245 status = NDIS_STATUS_RESOURCES;
246 goto err;
247 }
248 RtlZeroMemory(xi, sizeof(*xi));
250 /* init xennet_info */
251 xi->adapter_handle = MiniportAdapterHandle;
252 xi->rx_target = RX_DFL_MIN_TARGET;
253 xi->rx_min_target = RX_DFL_MIN_TARGET;
254 xi->rx_max_target = RX_MAX_TARGET;
256 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
257 if (!NT_SUCCESS(status))
258 {
259 KdPrint(("Could not open config in registry (%08x)\n", status));
260 goto err;
261 }
263 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
264 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
265 if (!NT_SUCCESS(status))
266 {
267 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
268 xi->config_sg = 1;
269 }
270 else
271 {
272 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
273 xi->config_sg = config_param->ParameterData.IntegerData;
274 }
276 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
277 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
278 if (!NT_SUCCESS(status))
279 {
280 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
281 xi->config_gso = 0;
282 }
283 else
284 {
285 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
286 xi->config_gso = config_param->ParameterData.IntegerData;
287 if (xi->config_gso > 61440)
288 {
289 xi->config_gso = 61440;
290 KdPrint(("(clipped to %d)\n", xi->config_gso));
291 }
292 }
294 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
295 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
296 if (!NT_SUCCESS(status))
297 {
298 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
299 xi->config_csum = 1;
300 }
301 else
302 {
303 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
304 xi->config_csum = config_param->ParameterData.IntegerData;
305 }
307 NdisInitUnicodeString(&config_param_name, L"MTU");
308 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
309 if (!NT_SUCCESS(status))
310 {
311 KdPrint(("Could not read MTU value (%08x)\n", status));
312 xi->config_mtu = 1500;
313 }
314 else
315 {
316 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
317 xi->config_mtu = config_param->ParameterData.IntegerData;
318 }
320 xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
322 NdisCloseConfiguration(config_handle);
324 xi->state = XenbusStateUnknown;
325 xi->backend_state = XenbusStateUnknown;
327 KeInitializeSpinLock(&xi->rx_lock);
329 InitializeListHead(&xi->tx_waiting_pkt_list);
331 NdisAllocatePacketPool(&status, &xi->packet_pool, XN_RX_QUEUE_LEN * 8,
332 PROTOCOL_RESERVED_SIZE_IN_PACKET);
333 if (status != NDIS_STATUS_SUCCESS)
334 {
335 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
336 status = NDIS_STATUS_RESOURCES;
337 goto err;
338 }
339 NdisSetPacketPoolProtocolId(xi->packet_pool, NDIS_PROTOCOL_ID_TCP_IP);
341 NdisAllocateBufferPool(&status, &xi->buffer_pool, XN_RX_QUEUE_LEN);
342 if (status != NDIS_STATUS_SUCCESS)
343 {
344 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
345 status = NDIS_STATUS_RESOURCES;
346 goto err;
347 }
349 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
350 &xi->lower_do, NULL, NULL);
351 xi->pdo_data = (PXENPCI_XEN_DEVICE_DATA)xi->pdo->DeviceExtension;
353 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
355 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
356 NAME_SIZE, xi->dev_desc, &length);
357 if (!NT_SUCCESS(status))
358 {
359 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
360 status = NDIS_STATUS_FAILURE;
361 goto err;
362 }
364 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
365 0, NDIS_ATTRIBUTE_DESERIALIZE, // | NDIS_ATTRIBUTE_BUS_MASTER),
366 NdisInterfaceInternal);
368 #if 0
369 if (xi->config_sg)
370 {
371 status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE, xi->config_max_pkt_size);
372 if (!NT_SUCCESS(status))
373 {
374 KdPrint(("NdisMInitializeScatterGatherDma failed with 0x%x\n", status));
375 status = NDIS_STATUS_FAILURE;
376 goto err;
377 }
378 }
379 #endif
381 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
383 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
384 xi->lower_do, xi->pdo, &xi->wdf_device);
385 if (!NT_SUCCESS(status))
386 {
387 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
388 status = NDIS_STATUS_FAILURE;
389 goto err;
390 }
392 /* get lower (Xen) interfaces */
394 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE,
395 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE), 2, NULL);
396 if(!NT_SUCCESS(status))
397 {
398 KdPrint(("WdfFdoQueryForInterface failed with status 0x%08x\n", status));
399 status = NDIS_STATUS_FAILURE;
400 goto err;
401 }
403 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
404 "%s/backend", xi->pdo_data->Path);
405 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
406 XBT_NIL, TmpPath, &Value);
407 if (res)
408 {
409 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
410 xi->XenInterface.FreeMem(res);
411 status = NDIS_STATUS_FAILURE;
412 goto err;
413 }
414 RtlStringCbCopyA(xi->backend_path, ARRAY_SIZE(xi->backend_path), Value);
415 xi->XenInterface.FreeMem(Value);
416 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->backend_path));
418 KeInitializeEvent(&xi->backend_state_change_event, SynchronizationEvent, FALSE);
419 KeInitializeEvent(&xi->shutdown_event, SynchronizationEvent, FALSE);
421 /* Add watch on backend state */
422 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
423 xi->XenInterface.XenBus_AddWatch(xi->XenInterface.InterfaceHeader.Context,
424 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
426 /* Tell backend we're coming up */
427 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
428 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
429 XBT_NIL, TmpPath, "%d", XenbusStateInitialising);
431 // wait here for signal that we are all set up
432 while (xi->backend_state != XenbusStateInitWait)
433 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
435 xi->event_channel = xi->XenInterface.EvtChn_AllocUnbound(
436 xi->XenInterface.InterfaceHeader.Context, 0);
437 xi->XenInterface.EvtChn_BindDpc(xi->XenInterface.InterfaceHeader.Context,
438 xi->event_channel, XenNet_Interrupt, xi);
440 XenNet_TxInit(xi);
441 XenNet_RxInit(xi);
443 /* fixup array for dynamic values */
444 params[0].value = xi->tx_ring_ref;
445 params[1].value = xi->rx_ring_ref;
446 params[2].value = xi->event_channel;
447 params[3].value = !xi->config_csum;
448 params[4].value = xi->config_sg;
449 params[5].value = !!xi->config_gso;
450 xi->XenInterface.XenBus_StartTransaction(
451 xi->XenInterface.InterfaceHeader.Context, &xbt);
453 for (err = NULL, i = 0; params[i].name; i++)
454 {
455 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
456 xi->pdo_data->Path, params[i].name);
457 err = xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
458 XBT_NIL, TmpPath, "%d", params[i].value);
459 if (err)
460 {
461 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
462 break;
463 }
464 }
466 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
467 xbt, 1, &retry);
468 if (err)
469 {
470 status = NDIS_STATUS_FAILURE;
471 goto err;
472 }
474 xi->connected = TRUE;
476 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
478 xi->state = XenbusStateConnected;
479 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
480 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
481 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
482 XBT_NIL, TmpPath, "%d", xi->state);
484 KdPrint((__DRIVER_NAME " Waiting for backend to connect\n"));
486 // wait here for signal that we are all set up
487 while (xi->backend_state != XenbusStateConnected)
488 {
489 timeout.QuadPart = -5 * 1000 * 1000 * 100; // 5 seconds
490 if (KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, &timeout) != STATUS_SUCCESS)
491 KdPrint((__DRIVER_NAME " Still Waiting for Connected...\n"));
492 }
494 KdPrint((__DRIVER_NAME " Backend Connected\n"));
496 /* get mac address */
497 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->backend_path);
498 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
499 XBT_NIL, TmpPath, &Value);
500 if (!Value)
501 {
502 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
503 status = NDIS_STATUS_FAILURE;
504 goto err;
505 }
506 else
507 {
508 char *s, *e;
509 s = Value;
510 for (i = 0; i < ETH_ALEN; i++) {
511 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
512 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
513 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
514 xi->XenInterface.FreeMem(Value);
515 status = NDIS_STATUS_FAILURE;
516 goto err;
517 }
518 s = e + 1;
519 }
520 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
521 xi->XenInterface.FreeMem(Value);
522 }
524 /* send fake arp? */
526 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
528 return NDIS_STATUS_SUCCESS;
530 err:
531 NdisFreeMemory(xi, 0, 0);
532 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
533 return status;
534 }
536 VOID
537 XenNet_PnPEventNotify(
538 IN NDIS_HANDLE MiniportAdapterContext,
539 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
540 IN PVOID InformationBuffer,
541 IN ULONG InformationBufferLength
542 )
543 {
544 UNREFERENCED_PARAMETER(MiniportAdapterContext);
545 UNREFERENCED_PARAMETER(PnPEvent);
546 UNREFERENCED_PARAMETER(InformationBuffer);
547 UNREFERENCED_PARAMETER(InformationBufferLength);
549 KdPrint((__FUNCTION__ " called\n"));
550 }
552 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
553 VOID
554 XenNet_Shutdown(
555 IN NDIS_HANDLE MiniportAdapterContext
556 )
557 {
558 struct xennet_info *xi = MiniportAdapterContext;
560 /* turn off interrupt */
561 xi->XenInterface.EvtChn_Unbind(xi->XenInterface.InterfaceHeader.Context,
562 xi->event_channel);
564 KdPrint((__FUNCTION__ " called\n"));
565 }
567 /* Opposite of XenNet_Init */
568 VOID
569 XenNet_Halt(
570 IN NDIS_HANDLE MiniportAdapterContext
571 )
572 {
573 struct xennet_info *xi = MiniportAdapterContext;
574 CHAR TmpPath[MAX_XENBUS_STR_LEN];
575 PVOID if_cxt = xi->XenInterface.InterfaceHeader.Context;
576 LARGE_INTEGER timeout;
578 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
579 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
581 // set frontend state to 'closing'
582 xi->state = XenbusStateClosing;
583 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
584 xi->XenInterface.XenBus_Printf(if_cxt, XBT_NIL, TmpPath, "%d", xi->state);
586 // wait for backend to set 'Closing' state
588 while (xi->backend_state != XenbusStateClosing)
589 {
590 timeout.QuadPart = -5 * 1000 * 1000 * 100; // 5 seconds
591 if (KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, &timeout) != STATUS_SUCCESS)
592 KdPrint((__DRIVER_NAME " Still Waiting for Closing...\n"));
593 }
595 // set frontend state to 'closed'
596 xi->state = XenbusStateClosed;
597 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
598 xi->XenInterface.XenBus_Printf(if_cxt, XBT_NIL, TmpPath, "%d", xi->state);
600 // wait for backend to set 'Closed' state
601 while (xi->backend_state != XenbusStateClosed)
602 {
603 timeout.QuadPart = -5 * 1000 * 1000 * 100; // 5 seconds
604 if (KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, &timeout) != STATUS_SUCCESS)
605 KdPrint((__DRIVER_NAME " Still Waiting for Closed...\n"));
606 }
608 // set frontend state to 'Initialising'
609 xi->state = XenbusStateInitialising;
610 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
611 xi->XenInterface.XenBus_Printf(if_cxt, XBT_NIL, TmpPath, "%d", xi->state);
613 // wait for backend to set 'InitWait' state
614 while (xi->backend_state != XenbusStateInitWait)
615 {
616 timeout.QuadPart = -5 * 1000 * 1000 * 100; // 5 seconds
617 if (KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, &timeout) != STATUS_SUCCESS)
618 KdPrint((__DRIVER_NAME " Still Waiting for InitWait...\n"));
619 }
621 // Disables the interrupt
622 XenNet_Shutdown(xi);
624 xi->connected = FALSE;
625 KeMemoryBarrier(); /* make sure everyone sees that we are now shut down */
627 // TODO: remove event channel xenbus entry (how?)
629 XenNet_TxShutdown(xi);
630 XenNet_RxShutdown(xi);
632 /* Remove watch on backend state */
633 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
634 xi->XenInterface.XenBus_RemWatch(if_cxt, XBT_NIL, TmpPath,
635 XenNet_BackEndStateHandler, xi);
637 xi->XenInterface.InterfaceHeader.InterfaceDereference(NULL);
639 NdisFreeBufferPool(xi->buffer_pool);
640 NdisFreePacketPool(xi->packet_pool);
642 NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
644 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
645 }
647 VOID
648 XenNet_Unload(
649 PDRIVER_OBJECT DriverObject
650 )
651 {
652 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
654 UNREFERENCED_PARAMETER(DriverObject);
656 WdfDriverMiniportUnload(WdfGetDriver());
658 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
659 }
661 NTSTATUS
662 DriverEntry(
663 PDRIVER_OBJECT DriverObject,
664 PUNICODE_STRING RegistryPath
665 )
666 {
667 NTSTATUS status;
668 WDF_DRIVER_CONFIG config;
669 NDIS_HANDLE ndis_wrapper_handle;
670 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
673 ProfTime_TxBufferGC.QuadPart = 0;
674 ProfTime_RxBufferAlloc.QuadPart = 0;
675 ProfTime_ReturnPacket.QuadPart = 0;
676 ProfTime_RxBufferCheck.QuadPart = 0;
677 ProfTime_RxBufferCheckTopHalf.QuadPart = 0;
678 ProfTime_RxBufferCheckBotHalf.QuadPart = 0;
679 ProfTime_Linearize.QuadPart = 0;
680 ProfTime_SendPackets.QuadPart = 0;
681 ProfTime_SendQueuedPackets.QuadPart = 0;
683 ProfCount_TxBufferGC = 0;
684 ProfCount_RxBufferAlloc = 0;
685 ProfCount_ReturnPacket = 0;
686 ProfCount_RxBufferCheck = 0;
687 ProfCount_Linearize = 0;
688 ProfCount_SendPackets = 0;
689 ProfCount_PacketsPerSendPackets = 0;
690 ProfCount_SendQueuedPackets = 0;
692 ProfCount_TxPacketsTotal = 0;
693 ProfCount_TxPacketsCsumOffload = 0;
694 ProfCount_TxPacketsLargeOffload = 0;
695 ProfCount_RxPacketsTotal = 0;
696 ProfCount_RxPacketsCsumOffload = 0;
697 ProfCount_CallsToIndicateReceive = 0;
699 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
701 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
702 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
704 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
705 &config, WDF_NO_HANDLE);
706 if (!NT_SUCCESS(status))
707 {
708 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
709 return status;
710 }
712 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
713 if (!ndis_wrapper_handle)
714 {
715 KdPrint(("NdisMInitializeWrapper failed\n"));
716 return NDIS_STATUS_FAILURE;
717 }
719 /* NDIS 5.1 driver */
720 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
721 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
723 mini_chars.HaltHandler = XenNet_Halt;
724 mini_chars.InitializeHandler = XenNet_Init;
725 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
726 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
727 mini_chars.ResetHandler = NULL; //TODO: fill in
728 mini_chars.SetInformationHandler = XenNet_SetInformation;
729 /* added in v.4 -- use multiple pkts interface */
730 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
731 mini_chars.SendPacketsHandler = XenNet_SendPackets;
733 #if defined (NDIS51_MINIPORT)
734 /* added in v.5.1 */
735 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
736 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
737 #else
738 // something else here
739 #endif
741 /* set up upper-edge interface */
742 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
743 if (!NT_SUCCESS(status))
744 {
745 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
746 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
747 return status;
748 }
750 NdisMRegisterUnloadHandler(ndis_wrapper_handle, XenNet_Unload);
752 return status;
753 }