win-pvdrivers

view xennet/xennet5.c @ 979:8f483a2b2991

Fix up PREfast warnings
author James Harper <james.harper@bendigoit.com.au>
date Sun Apr 15 19:47:10 2012 +1000 (2012-04-15)
parents 99023e044544
children
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 "xennet5.h"
25 /* Not really necessary but keeps PREfast happy */
26 DRIVER_INITIALIZE DriverEntry;
27 static IO_WORKITEM_ROUTINE XenNet_ResumeWorkItem;
28 #if (VER_PRODUCTBUILD >= 7600)
29 static KDEFERRED_ROUTINE XenNet_SuspendResume;
30 static KDEFERRED_ROUTINE XenNet_RxTxDpc;
31 #endif
33 #pragma NDIS_INIT_FUNCTION(DriverEntry)
35 /* ----- BEGIN Other people's code --------- */
36 /* from linux/include/linux/ctype.h, used under GPLv2 */
37 #define _U 0x01 /* upper */
38 #define _L 0x02 /* lower */
39 #define _D 0x04 /* digit */
40 #define _C 0x08 /* cntrl */
41 #define _P 0x10 /* punct */
42 #define _S 0x20 /* white space (space/lf/tab) */
43 #define _X 0x40 /* hex digit */
44 #define _SP 0x80 /* hard space (0x20) */
46 /* from linux/include/lib/ctype.c, used under GPLv2 */
47 unsigned char _ctype[] = {
48 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
49 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
50 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
51 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
52 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
53 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
54 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
55 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
56 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
57 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
58 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
59 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
60 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
61 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
62 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
63 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
64 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
65 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
66 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
67 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
68 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
69 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
70 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
71 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
73 /* from linux/include/linux/ctype.h, used under GPLv2 */
74 #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
76 #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
77 #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
78 #define iscntrl(c) ((__ismask(c)&(_C)) != 0)
79 #define isdigit(c) ((__ismask(c)&(_D)) != 0)
80 #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
81 #define islower(c) ((__ismask(c)&(_L)) != 0)
82 #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
83 #define ispunct(c) ((__ismask(c)&(_P)) != 0)
84 #define isspace(c) ((__ismask(c)&(_S)) != 0)
85 #define isupper(c) ((__ismask(c)&(_U)) != 0)
86 #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
88 #define TOLOWER(x) ((x) | 0x20)
90 /* from linux/lib/vsprintf.c, used under GPLv2 */
91 /* Copyright (C) 1991, 1992 Linus Torvalds
92 * Wirzenius wrote this portably, Torvalds fucked it up :-)
93 */
94 /**
95 * simple_strtoul - convert a string to an unsigned long
96 * @cp: The start of the string
97 * @endp: A pointer to the end of the parsed string will be placed here
98 * @base: The number base to use
99 */
100 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
101 {
102 unsigned long result = 0,value;
104 if (!base) {
105 base = 10;
106 if (*cp == '0') {
107 base = 8;
108 cp++;
109 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
110 cp++;
111 base = 16;
112 }
113 }
114 } else if (base == 16) {
115 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
116 cp += 2;
117 }
118 while (isxdigit(*cp) &&
119 (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
120 result = result*base + value;
121 cp++;
122 }
123 if (endp)
124 *endp = (char *)cp;
125 return result;
126 }
127 /* end vsprintf.c code */
128 /* ----- END Other people's code --------- */
130 static NDIS_STATUS
131 XenNet_ConnectBackend(struct xennet_info *xi)
132 {
133 PUCHAR ptr;
134 UCHAR type;
135 PCHAR setting, value, value2;
136 UINT i;
137 ULONG backend_sg = 0;
138 ULONG backend_gso = 0;
140 FUNCTION_ENTER();
142 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
144 ptr = xi->config_page;
145 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
146 {
147 switch(type)
148 {
149 case XEN_INIT_TYPE_RING: /* frontend ring */
150 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
151 if (strcmp(setting, "tx-ring-ref") == 0)
152 {
153 FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
154 } else if (strcmp(setting, "rx-ring-ref") == 0)
155 {
156 FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
157 }
158 break;
159 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
160 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
161 if (strcmp(setting, "event-channel") == 0)
162 {
163 xi->event_channel = PtrToUlong(value);
164 }
165 break;
166 case XEN_INIT_TYPE_READ_STRING_FRONT:
167 break;
168 case XEN_INIT_TYPE_READ_STRING_BACK:
169 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
170 if (strcmp(setting, "mac") == 0)
171 {
172 char *s, *e;
173 s = value;
174 for (i = 0; i < ETH_ALEN; i++) {
175 xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
176 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
177 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
178 }
179 s = e + 1;
180 }
181 if ((xi->curr_mac_addr[0] & 0x03) != 0x02)
182 {
183 /* only copy if curr_mac_addr is not a LUA */
184 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
185 }
186 }
187 else if (strcmp(setting, "feature-sg") == 0)
188 {
189 if (atoi(value))
190 {
191 backend_sg = 1;
192 }
193 }
194 else if (strcmp(setting, "feature-gso-tcpv4") == 0)
195 {
196 if (atoi(value))
197 {
198 backend_gso = 1;
199 }
200 }
201 break;
202 case XEN_INIT_TYPE_VECTORS:
203 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
204 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
205 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
206 {
207 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
208 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
209 FUNCTION_EXIT();
210 return NDIS_STATUS_ADAPTER_NOT_FOUND;
211 }
212 else
213 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
214 break;
215 case XEN_INIT_TYPE_STATE_PTR:
216 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
217 xi->device_state = (PXENPCI_DEVICE_STATE)value;
218 break;
219 default:
220 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
221 break;
222 }
223 }
224 if (xi->config_sg && !backend_sg)
225 {
226 KdPrint((__DRIVER_NAME " SG not supported by backend - disabling\n"));
227 xi->config_sg = 0;
228 }
229 if (xi->config_gso && !backend_gso)
230 {
231 KdPrint((__DRIVER_NAME " GSO not supported by backend - disabling\n"));
232 xi->config_gso = 0;
233 }
234 FUNCTION_EXIT();
236 return NDIS_STATUS_SUCCESS;
237 }
239 static VOID
240 XenNet_ResumeWorkItem(PDEVICE_OBJECT device_object, PVOID context)
241 {
242 struct xennet_info *xi = context;
243 KIRQL old_irql;
245 UNREFERENCED_PARAMETER(device_object);
247 FUNCTION_ENTER();
249 ASSERT(xi->resume_work_item);
251 IoFreeWorkItem(xi->resume_work_item);
253 XenNet_TxResumeStart(xi);
254 XenNet_RxResumeStart(xi);
255 XenNet_ConnectBackend(xi);
256 XenNet_RxResumeEnd(xi);
257 XenNet_TxResumeEnd(xi);
259 KeAcquireSpinLock(&xi->resume_lock, &old_irql);
260 xi->resume_work_item = NULL;
261 KdPrint((__DRIVER_NAME " *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
262 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
263 KdPrint((__DRIVER_NAME " *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
264 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
265 KeReleaseSpinLock(&xi->resume_lock, old_irql);
267 FUNCTION_EXIT();
269 }
271 static VOID
272 XenNet_SuspendResume(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
273 {
274 struct xennet_info *xi = context;
275 KIRQL old_irql;
276 PIO_WORKITEM resume_work_item;
278 UNREFERENCED_PARAMETER(dpc);
279 UNREFERENCED_PARAMETER(arg1);
280 UNREFERENCED_PARAMETER(arg2);
282 FUNCTION_ENTER();
284 switch (xi->device_state->suspend_resume_state_pdo)
285 {
286 case SR_STATE_SUSPENDING:
287 KdPrint((__DRIVER_NAME " New state SUSPENDING\n"));
288 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
289 if (xi->rx_id_free == NET_RX_RING_SIZE)
290 {
291 xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
292 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
293 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
294 }
295 KeReleaseSpinLock(&xi->rx_lock, old_irql);
296 break;
297 case SR_STATE_RESUMING:
298 KdPrint((__DRIVER_NAME " New state SR_STATE_RESUMING\n"));
299 /* do it like this so we don't race and double-free the work item */
300 resume_work_item = IoAllocateWorkItem(xi->fdo);
301 KeAcquireSpinLock(&xi->resume_lock, &old_irql);
302 if (xi->resume_work_item || xi->device_state->suspend_resume_state_fdo == SR_STATE_RESUMING)
303 {
304 KeReleaseSpinLock(&xi->resume_lock, old_irql);
305 IoFreeWorkItem(resume_work_item);
306 return;
307 }
308 xi->resume_work_item = resume_work_item;
309 KeReleaseSpinLock(&xi->resume_lock, old_irql);
310 IoQueueWorkItem(xi->resume_work_item, XenNet_ResumeWorkItem, DelayedWorkQueue, xi);
311 break;
312 default:
313 KdPrint((__DRIVER_NAME " New state %d\n", xi->device_state->suspend_resume_state_fdo));
314 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
315 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
316 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
317 break;
318 }
319 KeMemoryBarrier();
321 FUNCTION_EXIT();
322 }
324 static VOID
325 XenNet_RxTxDpc(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
326 {
327 struct xennet_info *xi = context;
328 BOOLEAN dont_set_event;
330 UNREFERENCED_PARAMETER(dpc);
331 UNREFERENCED_PARAMETER(arg1);
332 UNREFERENCED_PARAMETER(arg2);
334 /* if Rx goes over its per-dpc quota then make sure TxBufferGC doesn't set an event as we are already guaranteed to be called again */
335 dont_set_event = XenNet_RxBufferCheck(xi);
336 XenNet_TxBufferGC(xi, dont_set_event);
337 }
339 static BOOLEAN
340 XenNet_HandleEvent(PVOID context)
341 {
342 struct xennet_info *xi = context;
343 ULONG suspend_resume_state_pdo;
345 //FUNCTION_ENTER();
346 suspend_resume_state_pdo = xi->device_state->suspend_resume_state_pdo;
347 KeMemoryBarrier();
348 // KdPrint((__DRIVER_NAME " connected = %d, inactive = %d, suspend_resume_state_pdo = %d\n",
349 // xi->connected, xi->inactive, suspend_resume_state_pdo));
350 if (!xi->shutting_down && suspend_resume_state_pdo != xi->device_state->suspend_resume_state_fdo)
351 {
352 KeInsertQueueDpc(&xi->suspend_dpc, NULL, NULL);
353 }
354 if (xi->connected && !xi->inactive && suspend_resume_state_pdo != SR_STATE_RESUMING)
355 {
356 KeInsertQueueDpc(&xi->rxtx_dpc, NULL, NULL);
357 }
358 //FUNCTION_EXIT();
359 return TRUE;
360 }
362 VOID
363 XenNet_SetPower(PDEVICE_OBJECT device_object, PVOID context)
364 {
365 NTSTATUS status = STATUS_SUCCESS;
366 KIRQL old_irql;
367 struct xennet_info *xi = context;
369 FUNCTION_ENTER();
370 UNREFERENCED_PARAMETER(device_object);
372 switch (xi->new_power_state)
373 {
374 case NdisDeviceStateD0:
375 KdPrint((" NdisDeviceStateD0\n"));
376 status = XenNet_D0Entry(xi);
377 break;
378 case NdisDeviceStateD1:
379 KdPrint((" NdisDeviceStateD1\n"));
380 if (xi->power_state == NdisDeviceStateD0)
381 status = XenNet_D0Exit(xi);
382 break;
383 case NdisDeviceStateD2:
384 KdPrint((" NdisDeviceStateD2\n"));
385 if (xi->power_state == NdisDeviceStateD0)
386 status = XenNet_D0Exit(xi);
387 break;
388 case NdisDeviceStateD3:
389 KdPrint((" NdisDeviceStateD3\n"));
390 if (xi->power_state == NdisDeviceStateD0)
391 status = XenNet_D0Exit(xi);
392 break;
393 default:
394 KdPrint((" NdisDeviceState??\n"));
395 status = NDIS_STATUS_NOT_SUPPORTED;
396 break;
397 }
398 xi->power_state = xi->new_power_state;
400 old_irql = KeRaiseIrqlToDpcLevel();
401 NdisMSetInformationComplete(xi->adapter_handle, status);
402 KeLowerIrql(old_irql);
404 FUNCTION_EXIT();
405 }
407 NDIS_STATUS
408 XenNet_D0Entry(struct xennet_info *xi)
409 {
410 NDIS_STATUS status;
411 PUCHAR ptr;
412 CHAR buf[128];
414 FUNCTION_ENTER();
416 xi->shutting_down = FALSE;
418 ptr = xi->config_page;
419 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
420 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
421 #pragma warning(suppress:4054)
422 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
423 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
424 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
425 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
426 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
427 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
428 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
429 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
430 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
431 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
432 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
433 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
434 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_PRE_CONNECT, NULL, NULL, NULL);
435 __ADD_XEN_INIT_UCHAR(&ptr, 0); /* no pre-connect required */
436 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_POST_CONNECT, NULL, NULL, NULL);
437 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
438 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
439 __ADD_XEN_INIT_UCHAR(&ptr, 20);
440 __ADD_XEN_INIT_UCHAR(&ptr, 0);
441 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_SHUTDOWN, NULL, NULL, NULL);
442 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
443 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
444 __ADD_XEN_INIT_UCHAR(&ptr, 50);
445 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
446 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
447 __ADD_XEN_INIT_UCHAR(&ptr, 50);
448 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitialising);
449 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitWait);
450 __ADD_XEN_INIT_UCHAR(&ptr, 50);
451 __ADD_XEN_INIT_UCHAR(&ptr, 0);
452 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
454 status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
455 if (!NT_SUCCESS(status))
456 {
457 KdPrint(("Failed to complete device configuration (%08x)\n", status));
458 return status;
459 }
461 status = XenNet_ConnectBackend(xi);
463 if (!NT_SUCCESS(status))
464 {
465 KdPrint(("Failed to complete device configuration (%08x)\n", status));
466 return status;
467 }
469 if (!xi->config_sg)
470 {
471 /* without SG, GSO can be a maximum of PAGE_SIZE */
472 xi->config_gso = min(xi->config_gso, PAGE_SIZE);
473 }
475 XenNet_TxInit(xi);
476 XenNet_RxInit(xi);
478 xi->connected = TRUE;
480 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
482 FUNCTION_EXIT();
484 return status;
485 }
487 // Called at <= DISPATCH_LEVEL
488 static NDIS_STATUS
489 XenNet_Init(
490 OUT PNDIS_STATUS OpenErrorStatus,
491 OUT PUINT SelectedMediumIndex,
492 IN PNDIS_MEDIUM MediumArray,
493 IN UINT MediumArraySize,
494 IN NDIS_HANDLE MiniportAdapterHandle,
495 IN NDIS_HANDLE WrapperConfigurationContext
496 )
497 {
498 NDIS_STATUS status;
499 BOOLEAN medium_found = FALSE;
500 struct xennet_info *xi = NULL;
501 UINT nrl_length;
502 PNDIS_RESOURCE_LIST nrl;
503 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
504 KIRQL irq_level = 0;
505 ULONG irq_vector = 0;
506 ULONG irq_mode = 0;
507 NDIS_HANDLE config_handle;
508 NDIS_STRING config_param_name;
509 PNDIS_CONFIGURATION_PARAMETER config_param;
510 ULONG i;
511 PUCHAR ptr;
512 UCHAR type;
513 PCHAR setting, value;
514 ULONG length;
515 //CHAR buf[128];
516 PVOID network_address;
517 UINT network_address_length;
518 BOOLEAN qemu_hide_filter = FALSE;
519 ULONG qemu_hide_flags_value = 0;
521 UNREFERENCED_PARAMETER(OpenErrorStatus);
523 FUNCTION_ENTER();
525 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
527 /* deal with medium stuff */
528 for (i = 0; i < MediumArraySize; i++)
529 {
530 if (MediumArray[i] == NdisMedium802_3)
531 {
532 medium_found = TRUE;
533 break;
534 }
535 }
536 if (!medium_found)
537 {
538 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
539 return NDIS_STATUS_UNSUPPORTED_MEDIA;
540 }
541 *SelectedMediumIndex = i;
543 /* Alloc memory for adapter private info */
544 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
545 if (!NT_SUCCESS(status))
546 {
547 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
548 status = NDIS_STATUS_RESOURCES;
549 goto err;
550 }
551 RtlZeroMemory(xi, sizeof(*xi));
552 xi->adapter_handle = MiniportAdapterHandle;
553 xi->rx_target = RX_DFL_MIN_TARGET;
554 xi->rx_min_target = RX_DFL_MIN_TARGET;
555 xi->rx_max_target = RX_MAX_TARGET;
556 xi->inactive = TRUE;
557 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi, 0, 0 /* the last zero is to give the next | something to | with */
558 #ifdef NDIS51_MINIPORT
559 |NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
560 #endif
561 |NDIS_ATTRIBUTE_DESERIALIZE
562 |NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK,
563 NdisInterfaceInternal); /* PnpBus option doesn't exist... */
564 xi->multicast_list_size = 0;
565 xi->current_lookahead = MIN_LOOKAHEAD_LENGTH;
567 nrl_length = 0;
568 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
569 NULL, (PUINT)&nrl_length);
570 KdPrint((__DRIVER_NAME " nrl_length = %d\n", nrl_length));
571 status = NdisAllocateMemoryWithTag((PVOID)&nrl, nrl_length, XENNET_POOL_TAG);
572 if (status != NDIS_STATUS_SUCCESS)
573 {
574 KdPrint((__DRIVER_NAME " Could not get allocate memory for Adapter Resources 0x%x\n", status));
575 return NDIS_STATUS_RESOURCES;
576 }
577 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
578 nrl, (PUINT)&nrl_length);
579 if (status != NDIS_STATUS_SUCCESS)
580 {
581 KdPrint((__DRIVER_NAME " Could not get Adapter Resources 0x%x\n", status));
582 return NDIS_STATUS_RESOURCES;
583 }
584 xi->event_channel = 0;
585 xi->config_csum = 1;
586 xi->config_csum_rx_check = 1;
587 xi->config_sg = 1;
588 xi->config_gso = 61440;
589 xi->config_page = NULL;
590 xi->config_rx_interrupt_moderation = 0;
592 for (i = 0; i < nrl->Count; i++)
593 {
594 prd = &nrl->PartialDescriptors[i];
596 switch(prd->Type)
597 {
598 case CmResourceTypeInterrupt:
599 irq_vector = prd->u.Interrupt.Vector;
600 irq_level = (KIRQL)prd->u.Interrupt.Level;
601 irq_mode = (prd->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?NdisInterruptLatched:NdisInterruptLevelSensitive;
602 KdPrint((__DRIVER_NAME " irq_vector = %03x, irq_level = %03x, irq_mode = %s\n", irq_vector, irq_level,
603 (irq_mode == NdisInterruptLatched)?"NdisInterruptLatched":"NdisInterruptLevelSensitive"));
604 break;
605 case CmResourceTypeMemory:
606 if (xi->config_page)
607 {
608 KdPrint(("More than one memory range\n"));
609 return NDIS_STATUS_RESOURCES;
610 }
611 else
612 {
613 status = NdisMMapIoSpace(&xi->config_page, MiniportAdapterHandle, prd->u.Memory.Start, prd->u.Memory.Length);
614 if (!NT_SUCCESS(status))
615 {
616 KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
617 NdisFreeMemory(nrl, nrl_length, 0);
618 return NDIS_STATUS_RESOURCES;
619 }
620 }
621 break;
622 }
623 }
624 NdisFreeMemory(nrl, nrl_length, 0);
625 if (!xi->config_page)
626 {
627 KdPrint(("No config page given\n"));
628 return NDIS_STATUS_RESOURCES;
629 }
631 KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
632 KeInitializeSpinLock(&xi->resume_lock);
634 KeInitializeDpc(&xi->rxtx_dpc, XenNet_RxTxDpc, xi);
635 KeSetTargetProcessorDpc(&xi->rxtx_dpc, 0);
636 KeSetImportanceDpc(&xi->rxtx_dpc, HighImportance);
638 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
639 &xi->lower_do, NULL, NULL);
640 xi->packet_filter = 0;
642 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
643 NAME_SIZE, xi->dev_desc, &length);
644 if (!NT_SUCCESS(status))
645 {
646 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
647 status = NDIS_STATUS_FAILURE;
648 goto err;
649 }
651 ptr = xi->config_page;
652 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value)) != XEN_INIT_TYPE_END)
653 {
654 switch(type)
655 {
656 case XEN_INIT_TYPE_VECTORS:
657 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
658 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
659 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
660 {
661 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
662 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
663 FUNCTION_EXIT();
664 return NDIS_STATUS_FAILURE;
665 }
666 else
667 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
668 break;
669 case XEN_INIT_TYPE_STATE_PTR:
670 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
671 xi->device_state = (PXENPCI_DEVICE_STATE)value;
672 break;
673 case XEN_INIT_TYPE_QEMU_HIDE_FLAGS:
674 qemu_hide_flags_value = PtrToUlong(value);
675 break;
676 case XEN_INIT_TYPE_QEMU_HIDE_FILTER:
677 qemu_hide_filter = TRUE;
678 break;
679 default:
680 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
681 break;
682 }
683 }
685 if ((qemu_hide_flags_value & QEMU_UNPLUG_ALL_IDE_DISKS) || qemu_hide_filter)
686 xi->inactive = FALSE;
688 xi->power_state = NdisDeviceStateD0;
689 xi->power_workitem = IoAllocateWorkItem(xi->fdo);
691 // now build config page
693 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
694 if (!NT_SUCCESS(status))
695 {
696 KdPrint(("Could not open config in registry (%08x)\n", status));
697 status = NDIS_STATUS_RESOURCES;
698 goto err;
699 }
701 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
702 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
703 if (!NT_SUCCESS(status))
704 {
705 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
706 xi->config_sg = 1;
707 }
708 else
709 {
710 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
711 xi->config_sg = config_param->ParameterData.IntegerData;
712 }
714 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
715 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
716 if (!NT_SUCCESS(status))
717 {
718 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
719 xi->config_gso = 0;
720 }
721 else
722 {
723 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
724 xi->config_gso = config_param->ParameterData.IntegerData;
725 if (xi->config_gso > 61440)
726 {
727 xi->config_gso = 61440;
728 KdPrint(("(clipped to %d)\n", xi->config_gso));
729 }
730 }
732 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
733 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
734 if (!NT_SUCCESS(status))
735 {
736 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
737 xi->config_csum = 1;
738 }
739 else
740 {
741 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
742 xi->config_csum = !!config_param->ParameterData.IntegerData;
743 }
745 NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadRxCheck");
746 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
747 if (!NT_SUCCESS(status))
748 {
749 KdPrint(("Could not read ChecksumOffloadRxCheck value (%08x)\n", status));
750 xi->config_csum_rx_check = 1;
751 }
752 else
753 {
754 KdPrint(("ChecksumOffloadRxCheck = %d\n", config_param->ParameterData.IntegerData));
755 xi->config_csum_rx_check = !!config_param->ParameterData.IntegerData;
756 }
758 NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadDontFix");
759 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
760 if (!NT_SUCCESS(status))
761 {
762 KdPrint(("Could not read ChecksumOffloadDontFix value (%08x)\n", status));
763 xi->config_csum_rx_dont_fix = 0;
764 }
765 else
766 {
767 KdPrint(("ChecksumOffloadDontFix = %d\n", config_param->ParameterData.IntegerData));
768 xi->config_csum_rx_dont_fix = !!config_param->ParameterData.IntegerData;
769 }
773 NdisInitUnicodeString(&config_param_name, L"MTU");
774 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
775 if (!NT_SUCCESS(status))
776 {
777 KdPrint(("Could not read MTU value (%08x)\n", status));
778 xi->config_mtu = 1500;
779 }
780 else
781 {
782 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
783 xi->config_mtu = config_param->ParameterData.IntegerData;
784 }
786 NdisInitUnicodeString(&config_param_name, L"RxInterruptModeration");
787 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
788 if (!NT_SUCCESS(status))
789 {
790 KdPrint(("Could not read RxInterruptModeration value (%08x)\n", status));
791 xi->config_rx_interrupt_moderation = 1500;
792 }
793 else
794 {
795 KdPrint(("RxInterruptModeration = %d\n", config_param->ParameterData.IntegerData));
796 xi->config_rx_interrupt_moderation = config_param->ParameterData.IntegerData;
797 }
800 NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
801 if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || ((((PUCHAR)network_address)[0] & 0x03) != 0x02))
802 {
803 KdPrint(("Could not read NetworkAddress value (%08x) or value is invalid\n", status));
804 memset(xi->curr_mac_addr, 0, ETH_ALEN);
805 }
806 else
807 {
808 memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
809 KdPrint((" Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
810 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
811 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]));
812 }
814 xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
816 NdisCloseConfiguration(config_handle);
818 status = XenNet_D0Entry(xi);
819 if (!NT_SUCCESS(status))
820 {
821 KdPrint(("Failed to go to D0 (%08x)\n", status));
822 goto err;
823 }
824 return NDIS_STATUS_SUCCESS;
826 err:
827 NdisFreeMemory(xi, 0, 0);
828 *OpenErrorStatus = status;
829 FUNCTION_EXIT_STATUS(status);
830 return status;
831 }
833 VOID
834 XenNet_PnPEventNotify(
835 IN NDIS_HANDLE MiniportAdapterContext,
836 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
837 IN PVOID InformationBuffer,
838 IN ULONG InformationBufferLength
839 )
840 {
841 UNREFERENCED_PARAMETER(MiniportAdapterContext);
842 UNREFERENCED_PARAMETER(PnPEvent);
843 UNREFERENCED_PARAMETER(InformationBuffer);
844 UNREFERENCED_PARAMETER(InformationBufferLength);
846 FUNCTION_ENTER();
847 switch (PnPEvent)
848 {
849 case NdisDevicePnPEventSurpriseRemoved:
850 KdPrint((__DRIVER_NAME " NdisDevicePnPEventSurpriseRemoved\n"));
851 break;
852 case NdisDevicePnPEventPowerProfileChanged :
853 KdPrint((__DRIVER_NAME " NdisDevicePnPEventPowerProfileChanged\n"));
854 break;
855 default:
856 KdPrint((__DRIVER_NAME " %d\n", PnPEvent));
857 break;
858 }
859 FUNCTION_EXIT();
860 }
862 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
863 VOID
864 XenNet_Shutdown(
865 IN NDIS_HANDLE MiniportAdapterContext
866 )
867 {
868 UNREFERENCED_PARAMETER(MiniportAdapterContext);
870 /* remember we are called at >= DIRQL here */
871 FUNCTION_ENTER();
872 FUNCTION_EXIT();
873 }
875 /* Opposite of XenNet_Init */
876 VOID
877 XenNet_Halt(
878 IN NDIS_HANDLE MiniportAdapterContext
879 )
880 {
881 struct xennet_info *xi = MiniportAdapterContext;
883 FUNCTION_ENTER();
884 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
886 XenNet_D0Exit(xi);
888 NdisFreeMemory(xi, 0, 0);
890 FUNCTION_EXIT();
891 }
893 NDIS_STATUS
894 XenNet_D0Exit(struct xennet_info *xi)
895 {
896 FUNCTION_ENTER();
897 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
899 xi->shutting_down = TRUE;
900 KeMemoryBarrier(); /* make sure everyone sees that we are now shutting down */
902 XenNet_TxShutdown(xi);
903 XenNet_RxShutdown(xi);
905 xi->connected = FALSE;
906 KeMemoryBarrier(); /* make sure everyone sees that we are now disconnected */
908 xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
910 FUNCTION_EXIT();
912 return STATUS_SUCCESS;
913 }
915 NDIS_STATUS
916 XenNet_Reset(
917 PBOOLEAN AddressingReset,
918 NDIS_HANDLE MiniportAdapterContext
919 )
920 {
921 UNREFERENCED_PARAMETER(MiniportAdapterContext);
923 *AddressingReset = FALSE;
924 return NDIS_STATUS_SUCCESS;
925 }
927 NTSTATUS
928 DriverEntry(
929 PDRIVER_OBJECT DriverObject,
930 PUNICODE_STRING RegistryPath
931 )
932 {
933 NTSTATUS status;
934 NDIS_HANDLE ndis_wrapper_handle = NULL;
935 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
937 FUNCTION_ENTER();
939 KdPrint((__DRIVER_NAME " DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
941 NdisZeroMemory(&mini_chars, sizeof(mini_chars));
943 KdPrint((__DRIVER_NAME " NdisGetVersion = %x\n", NdisGetVersion()));
945 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
946 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
947 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
948 if (!ndis_wrapper_handle)
949 {
950 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper failed\n"));
951 return NDIS_STATUS_FAILURE;
952 }
953 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper succeeded\n"));
955 /* NDIS 5.1 driver */
956 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
957 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
959 KdPrint((__DRIVER_NAME " MajorNdisVersion = %d, MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
961 mini_chars.HaltHandler = XenNet_Halt;
962 mini_chars.InitializeHandler = XenNet_Init;
963 //mini_chars.ISRHandler = XenNet_InterruptIsr;
964 //mini_chars.HandleInterruptHandler = XenNet_InterruptDpc;
965 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
966 mini_chars.ResetHandler = XenNet_Reset;
967 mini_chars.SetInformationHandler = XenNet_SetInformation;
968 /* added in v.4 -- use multiple pkts interface */
969 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
970 mini_chars.SendPacketsHandler = XenNet_SendPackets;
971 /* don't support cancel - no point as packets are never queued for long */
972 //mini_chars.CancelSendPacketsHandler = XenNet_CancelSendPackets;
974 #ifdef NDIS51_MINIPORT
975 /* added in v.5.1 */
976 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
977 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
978 #else
979 // something else here
980 #endif
982 /* set up upper-edge interface */
983 KdPrint((__DRIVER_NAME " about to call NdisMRegisterMiniport\n"));
984 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
985 KdPrint((__DRIVER_NAME " called NdisMRegisterMiniport\n"));
986 if (!NT_SUCCESS(status))
987 {
988 KdPrint((__DRIVER_NAME " NdisMRegisterMiniport failed, status = 0x%x\n", status));
989 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
990 return status;
991 }
993 FUNCTION_EXIT();
995 return status;