win-pvdrivers

view xennet/xennet.c @ 537:2a74ac2f43bb

more big updates
dma now working under xp
author James Harper <james.harper@bendigoit.com.au>
date Wed Feb 18 22:18:23 2009 +1100 (2009-02-18)
parents 1d39de3ab8d6
children e75bb8d68370
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 /* ----- BEGIN Other people's code --------- */
26 /* from linux/include/linux/ctype.h, used under GPLv2 */
27 #define _U 0x01 /* upper */
28 #define _L 0x02 /* lower */
29 #define _D 0x04 /* digit */
30 #define _C 0x08 /* cntrl */
31 #define _P 0x10 /* punct */
32 #define _S 0x20 /* white space (space/lf/tab) */
33 #define _X 0x40 /* hex digit */
34 #define _SP 0x80 /* hard space (0x20) */
36 /* from linux/include/lib/ctype.c, used under GPLv2 */
37 unsigned char _ctype[] = {
38 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
39 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
40 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
41 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
42 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
43 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
44 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
45 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
46 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
47 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
48 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
49 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
50 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
51 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
52 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
53 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
54 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
55 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
56 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
57 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
58 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
59 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
60 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
61 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
63 /* from linux/include/linux/ctype.h, used under GPLv2 */
64 #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
66 #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
67 #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
68 #define iscntrl(c) ((__ismask(c)&(_C)) != 0)
69 #define isdigit(c) ((__ismask(c)&(_D)) != 0)
70 #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
71 #define islower(c) ((__ismask(c)&(_L)) != 0)
72 #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
73 #define ispunct(c) ((__ismask(c)&(_P)) != 0)
74 #define isspace(c) ((__ismask(c)&(_S)) != 0)
75 #define isupper(c) ((__ismask(c)&(_U)) != 0)
76 #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
78 #define TOLOWER(x) ((x) | 0x20)
80 /* from linux/lib/vsprintf.c, used under GPLv2 */
81 /* Copyright (C) 1991, 1992 Linus Torvalds
82 * Wirzenius wrote this portably, Torvalds fucked it up :-)
83 */
84 /**
85 * simple_strtoul - convert a string to an unsigned long
86 * @cp: The start of the string
87 * @endp: A pointer to the end of the parsed string will be placed here
88 * @base: The number base to use
89 */
90 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
91 {
92 unsigned long result = 0,value;
94 if (!base) {
95 base = 10;
96 if (*cp == '0') {
97 base = 8;
98 cp++;
99 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
100 cp++;
101 base = 16;
102 }
103 }
104 } else if (base == 16) {
105 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
106 cp += 2;
107 }
108 while (isxdigit(*cp) &&
109 (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
110 result = result*base + value;
111 cp++;
112 }
113 if (endp)
114 *endp = (char *)cp;
115 return result;
116 }
117 /* end vsprintf.c code */
118 /* ----- END Other people's code --------- */
120 static NDIS_STATUS
121 XenNet_ConnectBackend(struct xennet_info *xi)
122 {
123 PUCHAR ptr;
124 UCHAR type;
125 PCHAR setting, value, value2;
126 UINT i;
128 FUNCTION_ENTER();
130 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
132 ptr = xi->config_page;
133 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
134 {
135 switch(type)
136 {
137 case XEN_INIT_TYPE_RING: /* frontend ring */
138 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
139 if (strcmp(setting, "tx-ring-ref") == 0)
140 {
141 FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
142 } else if (strcmp(setting, "rx-ring-ref") == 0)
143 {
144 FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
145 }
146 break;
147 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
148 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
149 if (strcmp(setting, "event-channel") == 0)
150 {
151 xi->event_channel = PtrToUlong(value);
152 }
153 break;
154 case XEN_INIT_TYPE_READ_STRING_BACK:
155 case XEN_INIT_TYPE_READ_STRING_FRONT:
156 //KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
157 if (strcmp(setting, "mac") == 0)
158 {
159 char *s, *e;
160 s = value;
161 for (i = 0; i < ETH_ALEN; i++) {
162 xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
163 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
164 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
165 }
166 s = e + 1;
167 }
168 if (!(xi->curr_mac_addr[0] & 0x02))
169 {
170 /* only copy if curr_mac_addr is not a LUA */
171 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
172 }
173 }
174 break;
175 case XEN_INIT_TYPE_VECTORS:
176 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
177 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
178 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
179 {
180 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
181 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
182 FUNCTION_ERROR_EXIT();
183 return NDIS_STATUS_ADAPTER_NOT_FOUND;
184 }
185 else
186 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
187 break;
188 case XEN_INIT_TYPE_STATE_PTR:
189 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
190 xi->device_state = (PXENPCI_DEVICE_STATE)value;
191 break;
192 default:
193 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
194 break;
195 }
196 }
197 FUNCTION_EXIT();
199 return NDIS_STATUS_SUCCESS;
200 }
202 static DDKAPI VOID
203 XenNet_Resume(PDEVICE_OBJECT device_object, PVOID context)
204 {
205 struct xennet_info *xi = context;
207 UNREFERENCED_PARAMETER(device_object);
209 FUNCTION_ENTER();
211 XenNet_TxResumeStart(xi);
212 XenNet_RxResumeStart(xi);
213 XenNet_ConnectBackend(xi);
214 XenNet_RxResumeEnd(xi);
215 XenNet_TxResumeEnd(xi);
216 KdPrint((__DRIVER_NAME " *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
217 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
218 KdPrint((__DRIVER_NAME " *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
219 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
221 FUNCTION_EXIT();
223 }
225 static VOID
226 XenNet_SuspendResume(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
227 {
228 struct xennet_info *xi = context;
229 PIO_WORKITEM work_item;
230 KIRQL old_irql;
232 UNREFERENCED_PARAMETER(dpc);
233 UNREFERENCED_PARAMETER(arg1);
234 UNREFERENCED_PARAMETER(arg2);
236 FUNCTION_ENTER();
238 switch (xi->device_state->suspend_resume_state_pdo)
239 {
240 case SR_STATE_SUSPENDING:
241 KdPrint((__DRIVER_NAME " New state SUSPENDING\n"));
242 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
243 if (xi->tx_id_free == NET_TX_RING_SIZE)
244 {
245 xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
246 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
247 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
248 }
249 KeReleaseSpinLock(&xi->rx_lock, old_irql);
250 break;
251 case SR_STATE_RESUMING:
252 KdPrint((__DRIVER_NAME " New state SR_STATE_RESUMING\n"));
253 work_item = IoAllocateWorkItem(xi->fdo);
254 IoQueueWorkItem(work_item, XenNet_Resume, DelayedWorkQueue, xi);
255 break;
256 default:
257 KdPrint((__DRIVER_NAME " New state %d\n", xi->device_state->suspend_resume_state_fdo));
258 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
259 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
260 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
261 break;
262 }
263 KeMemoryBarrier();
265 FUNCTION_EXIT();
266 }
268 static DDKAPI BOOLEAN
269 XenNet_HandleEvent(PVOID context)
270 {
271 struct xennet_info *xi = context;
272 ULONG suspend_resume_state_pdo;
274 //FUNCTION_ENTER();
275 suspend_resume_state_pdo = xi->device_state->suspend_resume_state_pdo;
276 KeMemoryBarrier();
277 // KdPrint((__DRIVER_NAME " connected = %d, inactive = %d, suspend_resume_state_pdo = %d\n",
278 // xi->connected, xi->inactive, suspend_resume_state_pdo));
279 if (suspend_resume_state_pdo != xi->device_state->suspend_resume_state_fdo)
280 {
281 KeInsertQueueDpc(&xi->suspend_dpc, NULL, NULL);
282 }
283 else if (xi->connected && !xi->inactive && suspend_resume_state_pdo != SR_STATE_RESUMING)
284 {
285 KeInsertQueueDpc(&xi->tx_dpc, NULL, NULL);
286 KeInsertQueueDpc(&xi->rx_dpc, NULL, NULL);
287 }
288 //FUNCTION_EXIT();
289 return TRUE;
290 }
292 // Called at <= DISPATCH_LEVEL
293 static DDKAPI NDIS_STATUS
294 XenNet_Init(
295 OUT PNDIS_STATUS OpenErrorStatus,
296 OUT PUINT SelectedMediumIndex,
297 IN PNDIS_MEDIUM MediumArray,
298 IN UINT MediumArraySize,
299 IN NDIS_HANDLE MiniportAdapterHandle,
300 IN NDIS_HANDLE WrapperConfigurationContext
301 )
302 {
303 NDIS_STATUS status;
304 BOOLEAN medium_found = FALSE;
305 struct xennet_info *xi = NULL;
306 UINT nrl_length;
307 PNDIS_RESOURCE_LIST nrl;
308 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
309 KIRQL irq_level = 0;
310 ULONG irq_vector = 0;
311 ULONG irq_mode = 0;
312 NDIS_HANDLE config_handle;
313 NDIS_STRING config_param_name;
314 PNDIS_CONFIGURATION_PARAMETER config_param;
315 ULONG i;
316 PUCHAR ptr;
317 UCHAR type;
318 PCHAR setting, value;
319 ULONG length;
320 CHAR buf[128];
321 PVOID network_address;
322 UINT network_address_length;
324 UNREFERENCED_PARAMETER(OpenErrorStatus);
326 FUNCTION_ENTER();
328 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
330 /* deal with medium stuff */
331 for (i = 0; i < MediumArraySize; i++)
332 {
333 if (MediumArray[i] == NdisMedium802_3)
334 {
335 medium_found = TRUE;
336 break;
337 }
338 }
339 if (!medium_found)
340 {
341 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
342 return NDIS_STATUS_UNSUPPORTED_MEDIA;
343 }
344 *SelectedMediumIndex = i;
346 /* Alloc memory for adapter private info */
347 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
348 if (!NT_SUCCESS(status))
349 {
350 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
351 status = NDIS_STATUS_RESOURCES;
352 goto err;
353 }
354 RtlZeroMemory(xi, sizeof(*xi));
355 xi->adapter_handle = MiniportAdapterHandle;
356 xi->rx_target = RX_DFL_MIN_TARGET;
357 xi->rx_min_target = RX_DFL_MIN_TARGET;
358 xi->rx_max_target = RX_MAX_TARGET;
359 xi->inactive = TRUE;
360 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi, 0,
361 #ifdef NDIS51_MINIPORT
362 NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
363 #endif
364 |NDIS_ATTRIBUTE_DESERIALIZE
365 |NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK
366 |NDIS_ATTRIBUTE_BUS_MASTER,
367 NdisInterfaceInternal);
368 xi->multicast_list_size = 0;
370 nrl_length = 0;
371 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
372 NULL, (PUINT)&nrl_length);
373 KdPrint((__DRIVER_NAME " nrl_length = %d\n", nrl_length));
374 status = NdisAllocateMemoryWithTag((PVOID)&nrl, nrl_length, XENNET_POOL_TAG);
375 if (status != NDIS_STATUS_SUCCESS)
376 {
377 KdPrint((__DRIVER_NAME " Could not get allocate memory for Adapter Resources 0x%x\n", status));
378 return NDIS_STATUS_RESOURCES;
379 }
380 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
381 nrl, (PUINT)&nrl_length);
382 if (status != NDIS_STATUS_SUCCESS)
383 {
384 KdPrint((__DRIVER_NAME " Could not get Adapter Resources 0x%x\n", status));
385 return NDIS_STATUS_RESOURCES;
386 }
387 xi->event_channel = 0;
388 xi->config_csum = 1;
389 xi->config_csum_rx_check = 1;
390 xi->config_sg = 1;
391 xi->config_gso = 61440;
392 xi->config_page = NULL;
393 xi->config_rx_interrupt_moderation = 0;
395 for (i = 0; i < nrl->Count; i++)
396 {
397 prd = &nrl->PartialDescriptors[i];
399 switch(prd->Type)
400 {
401 case CmResourceTypeInterrupt:
402 irq_vector = prd->u.Interrupt.Vector;
403 irq_level = (KIRQL)prd->u.Interrupt.Level;
404 irq_mode = (prd->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?NdisInterruptLatched:NdisInterruptLevelSensitive;
405 KdPrint((__DRIVER_NAME " irq_vector = %03x, irq_level = %03x, irq_mode = %s\n", irq_vector, irq_level,
406 (irq_mode == NdisInterruptLatched)?"NdisInterruptLatched":"NdisInterruptLevelSensitive"));
407 break;
408 case CmResourceTypeMemory:
409 if (xi->config_page)
410 {
411 KdPrint(("More than one memory range\n"));
412 return NDIS_STATUS_RESOURCES;
413 }
414 else
415 {
416 status = NdisMMapIoSpace(&xi->config_page, MiniportAdapterHandle, prd->u.Memory.Start, prd->u.Memory.Length);
417 if (!NT_SUCCESS(status))
418 {
419 KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
420 NdisFreeMemory(nrl, nrl_length, 0);
421 return NDIS_STATUS_RESOURCES;
422 }
423 }
424 break;
425 }
426 }
427 NdisFreeMemory(nrl, nrl_length, 0);
428 if (!xi->config_page)
429 {
430 KdPrint(("No config page given\n"));
431 return NDIS_STATUS_RESOURCES;
432 }
434 KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
436 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
437 &xi->lower_do, NULL, NULL);
438 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
440 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
441 NAME_SIZE, xi->dev_desc, &length);
442 if (!NT_SUCCESS(status))
443 {
444 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
445 status = NDIS_STATUS_FAILURE;
446 goto err;
447 }
449 ptr = xi->config_page;
450 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value)) != XEN_INIT_TYPE_END)
451 {
452 switch(type)
453 {
454 case XEN_INIT_TYPE_VECTORS:
455 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
456 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
457 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
458 {
459 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
460 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
461 FUNCTION_ERROR_EXIT();
462 return NDIS_STATUS_FAILURE;
463 }
464 else
465 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
466 break;
467 case XEN_INIT_TYPE_STATE_PTR:
468 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
469 xi->device_state = (PXENPCI_DEVICE_STATE)value;
470 break;
471 case XEN_INIT_TYPE_ACTIVE:
472 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_ACTIVE\n"));
473 xi->inactive = FALSE;
474 break;
475 default:
476 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
477 break;
478 }
479 }
481 // now build config page
483 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
484 if (!NT_SUCCESS(status))
485 {
486 KdPrint(("Could not open config in registry (%08x)\n", status));
487 status = NDIS_STATUS_RESOURCES;
488 goto err;
489 }
491 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
492 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
493 if (!NT_SUCCESS(status))
494 {
495 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
496 xi->config_sg = 1;
497 }
498 else
499 {
500 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
501 xi->config_sg = config_param->ParameterData.IntegerData;
502 }
504 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
505 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
506 if (!NT_SUCCESS(status))
507 {
508 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
509 xi->config_gso = 0;
510 }
511 else
512 {
513 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
514 xi->config_gso = config_param->ParameterData.IntegerData;
515 if (xi->config_gso > 61440)
516 {
517 xi->config_gso = 61440;
518 KdPrint(("(clipped to %d)\n", xi->config_gso));
519 }
520 }
522 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
523 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
524 if (!NT_SUCCESS(status))
525 {
526 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
527 xi->config_csum = 1;
528 }
529 else
530 {
531 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
532 xi->config_csum = !!config_param->ParameterData.IntegerData;
533 }
535 NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadRxCheck");
536 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
537 if (!NT_SUCCESS(status))
538 {
539 KdPrint(("Could not read ChecksumOffloadRxCheck value (%08x)\n", status));
540 xi->config_csum_rx_check = 1;
541 }
542 else
543 {
544 KdPrint(("ChecksumOffloadRxCheck = %d\n", config_param->ParameterData.IntegerData));
545 xi->config_csum_rx_check = !!config_param->ParameterData.IntegerData;
546 }
548 NdisInitUnicodeString(&config_param_name, L"MTU");
549 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
550 if (!NT_SUCCESS(status))
551 {
552 KdPrint(("Could not read MTU value (%08x)\n", status));
553 xi->config_mtu = 1500;
554 }
555 else
556 {
557 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
558 xi->config_mtu = config_param->ParameterData.IntegerData;
559 }
561 NdisInitUnicodeString(&config_param_name, L"RxInterruptModeration");
562 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
563 if (!NT_SUCCESS(status))
564 {
565 KdPrint(("Could not read RxInterruptModeration value (%08x)\n", status));
566 xi->config_rx_interrupt_moderation = 1500;
567 }
568 else
569 {
570 KdPrint(("RxInterruptModeration = %d\n", config_param->ParameterData.IntegerData));
571 xi->config_rx_interrupt_moderation = config_param->ParameterData.IntegerData;
572 }
575 NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
576 if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || !(((PUCHAR)network_address)[0] & 0x02))
577 {
578 KdPrint(("Could not read NetworkAddress value (%08x)\n", status));
579 memset(xi->curr_mac_addr, 0, ETH_ALEN);
580 }
581 else
582 {
583 memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
584 KdPrint((" Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
585 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
586 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]));
587 }
589 xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
591 NdisCloseConfiguration(config_handle);
593 ptr = xi->config_page;
594 // two XEN_INIT_TYPE_RUNs means go straight to XenbusStateConnected - skip XenbusStateInitialised
595 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
596 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
597 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
598 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
599 #pragma warning(suppress:4054)
600 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
601 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
602 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
603 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
604 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
605 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
606 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
607 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
608 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
609 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
610 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
612 status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
613 if (!NT_SUCCESS(status))
614 {
615 KdPrint(("Failed to complete device configuration (%08x)\n", status));
616 goto err;
617 }
619 status = XenNet_ConnectBackend(xi);
621 if (!NT_SUCCESS(status))
622 {
623 KdPrint(("Failed to complete device configuration (%08x)\n", status));
624 goto err;
625 }
627 status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE, xi->config_gso);
628 if (!NT_SUCCESS(status))
629 {
630 KdPrint(("NdisMInitializeScatterGatherDma failed (%08x)\n", status));
631 goto err;
632 }
634 XenNet_TxInit(xi);
635 XenNet_RxInit(xi);
637 xi->connected = TRUE;
639 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
641 #if 0
642 status = NdisMRegisterInterrupt(&xi->interrupt, MiniportAdapterHandle, irq_vector, irq_level,
643 TRUE, TRUE, irq_mode);
644 if (!NT_SUCCESS(status))
645 {
646 KdPrint(("NdisMRegisterInterrupt failed with 0x%x\n", status));
647 status = NDIS_STATUS_RESOURCES;
648 xi->connected = FALSE;
649 XenNet_TxShutdown(xi);
650 XenNet_RxShutdown(xi);
651 goto err;
652 }
653 #endif
654 //xi->vectors.EvtChn_Bind(xi->vectors.context, xi->event_channel, XenNet_HandleEvent, xi);
656 FUNCTION_EXIT();
658 return NDIS_STATUS_SUCCESS;
660 err:
661 NdisFreeMemory(xi, 0, 0);
662 *OpenErrorStatus = status;
663 FUNCTION_ERROR_EXIT();
664 return status;
665 }
667 VOID
668 XenNet_PnPEventNotify(
669 IN NDIS_HANDLE MiniportAdapterContext,
670 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
671 IN PVOID InformationBuffer,
672 IN ULONG InformationBufferLength
673 )
674 {
675 UNREFERENCED_PARAMETER(MiniportAdapterContext);
676 UNREFERENCED_PARAMETER(PnPEvent);
677 UNREFERENCED_PARAMETER(InformationBuffer);
678 UNREFERENCED_PARAMETER(InformationBufferLength);
680 FUNCTION_CALLED();
681 }
683 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
684 VOID DDKAPI
685 XenNet_Shutdown(
686 IN NDIS_HANDLE MiniportAdapterContext
687 )
688 {
689 UNREFERENCED_PARAMETER(MiniportAdapterContext);
691 FUNCTION_CALLED();
693 /* can't do this as shutdown might be called at DIRQL or higher */
694 /* NdisMDeregisterInterrupt(&xi->interrupt); */
695 }
697 /* Opposite of XenNet_Init */
698 VOID DDKAPI
699 XenNet_Halt(
700 IN NDIS_HANDLE MiniportAdapterContext
701 )
702 {
703 struct xennet_info *xi = MiniportAdapterContext;
705 FUNCTION_ENTER();
706 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
708 NdisMDeregisterInterrupt(&xi->interrupt);
710 xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
712 xi->connected = FALSE;
713 KeMemoryBarrier(); /* make sure everyone sees that we are now shut down */
715 // TODO: remove event channel xenbus entry (how?)
717 XenNet_TxShutdown(xi);
718 XenNet_RxShutdown(xi);
720 NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
722 FUNCTION_EXIT();
723 }
725 NDIS_STATUS
726 XenNet_Reset(
727 PBOOLEAN AddressingReset,
728 NDIS_HANDLE MiniportAdapterContext
729 )
730 {
731 UNREFERENCED_PARAMETER(MiniportAdapterContext);
733 *AddressingReset = FALSE;
734 return NDIS_STATUS_SUCCESS;
735 }
737 NTSTATUS DDKAPI
738 DriverEntry(
739 PDRIVER_OBJECT DriverObject,
740 PUNICODE_STRING RegistryPath
741 )
742 {
743 NTSTATUS status;
744 NDIS_HANDLE ndis_wrapper_handle = NULL;
745 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
747 FUNCTION_ENTER();
749 KdPrint((__DRIVER_NAME " DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
750 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
752 KdPrint((__DRIVER_NAME " NdisGetVersion = %x\n", NdisGetVersion()));
754 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
755 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
756 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
757 if (!ndis_wrapper_handle)
758 {
759 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper failed\n"));
760 return NDIS_STATUS_FAILURE;
761 }
762 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper succeeded\n"));
764 /* NDIS 5.1 driver */
765 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
766 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
768 KdPrint((__DRIVER_NAME " MajorNdisVersion = %d, MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
770 mini_chars.HaltHandler = XenNet_Halt;
771 mini_chars.InitializeHandler = XenNet_Init;
772 //mini_chars.ISRHandler = XenNet_InterruptIsr;
773 //mini_chars.HandleInterruptHandler = XenNet_InterruptDpc;
774 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
775 mini_chars.ResetHandler = XenNet_Reset;
776 mini_chars.SetInformationHandler = XenNet_SetInformation;
777 /* added in v.4 -- use multiple pkts interface */
778 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
779 mini_chars.SendPacketsHandler = XenNet_SendPackets;
781 #ifdef NDIS51_MINIPORT
782 /* added in v.5.1 */
783 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
784 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
785 #else
786 // something else here
787 #endif
789 /* set up upper-edge interface */
790 KdPrint((__DRIVER_NAME " about to call NdisMRegisterMiniport\n"));
791 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
792 KdPrint((__DRIVER_NAME " called NdisMRegisterMiniport\n"));
793 if (!NT_SUCCESS(status))
794 {
795 KdPrint((__DRIVER_NAME " NdisMRegisterMiniport failed, status = 0x%x\n", status));
796 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
797 return status;
798 }
800 FUNCTION_EXIT();
802 return status;
803 }