win-pvdrivers

view xennet/xennet.c @ 668:cfee9cb572cc

rc version info
author James Harper <james.harper@bendigoit.com.au>
date Wed Sep 23 17:05:21 2009 +1000 (2009-09-23)
parents ee9c59a5a06c
children f1bb26495379
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;
127 ULONG backend_sg = 0;
128 ULONG backend_gso = 0;
130 FUNCTION_ENTER();
132 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
134 ptr = xi->config_page;
135 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
136 {
137 switch(type)
138 {
139 case XEN_INIT_TYPE_RING: /* frontend ring */
140 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
141 if (strcmp(setting, "tx-ring-ref") == 0)
142 {
143 FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
144 } else if (strcmp(setting, "rx-ring-ref") == 0)
145 {
146 FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
147 }
148 break;
149 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
150 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
151 if (strcmp(setting, "event-channel") == 0)
152 {
153 xi->event_channel = PtrToUlong(value);
154 }
155 break;
156 case XEN_INIT_TYPE_READ_STRING_FRONT:
157 break;
158 case XEN_INIT_TYPE_READ_STRING_BACK:
159 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
160 if (strcmp(setting, "mac") == 0)
161 {
162 char *s, *e;
163 s = value;
164 for (i = 0; i < ETH_ALEN; i++) {
165 xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
166 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
167 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
168 }
169 s = e + 1;
170 }
171 if (!(xi->curr_mac_addr[0] & 0x02))
172 {
173 /* only copy if curr_mac_addr is not a LUA */
174 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
175 }
176 }
177 else if (strcmp(setting, "feature-sg") == 0)
178 {
179 if (atoi(value))
180 {
181 backend_sg = 1;
182 }
183 }
184 else if (strcmp(setting, "feature-gso-tcpv4") == 0)
185 {
186 if (atoi(value))
187 {
188 backend_gso = 1;
189 }
190 }
191 break;
192 case XEN_INIT_TYPE_VECTORS:
193 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
194 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
195 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
196 {
197 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
198 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
199 FUNCTION_ERROR_EXIT();
200 return NDIS_STATUS_ADAPTER_NOT_FOUND;
201 }
202 else
203 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
204 break;
205 case XEN_INIT_TYPE_STATE_PTR:
206 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
207 xi->device_state = (PXENPCI_DEVICE_STATE)value;
208 break;
209 default:
210 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
211 break;
212 }
213 }
214 if (xi->config_sg && !backend_sg)
215 {
216 KdPrint((__DRIVER_NAME " SG not supported by backend - disabling\n"));
217 xi->config_sg = 0;
218 }
219 if (xi->config_gso && !backend_gso)
220 {
221 KdPrint((__DRIVER_NAME " GSO not supported by backend - disabling\n"));
222 xi->config_gso = 0;
223 }
224 FUNCTION_EXIT();
226 return NDIS_STATUS_SUCCESS;
227 }
229 static DDKAPI VOID
230 XenNet_Resume(PDEVICE_OBJECT device_object, PVOID context)
231 {
232 struct xennet_info *xi = context;
234 UNREFERENCED_PARAMETER(device_object);
236 FUNCTION_ENTER();
238 ASSERT(xi->resume_work_item);
239 IoFreeWorkItem(xi->resume_work_item);
240 xi->resume_work_item = NULL;
242 XenNet_TxResumeStart(xi);
243 XenNet_RxResumeStart(xi);
244 XenNet_ConnectBackend(xi);
245 XenNet_RxResumeEnd(xi);
246 XenNet_TxResumeEnd(xi);
247 KdPrint((__DRIVER_NAME " *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
248 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
249 KdPrint((__DRIVER_NAME " *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
250 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
252 FUNCTION_EXIT();
254 }
256 static VOID
257 XenNet_SuspendResume(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
258 {
259 struct xennet_info *xi = context;
260 KIRQL old_irql;
262 UNREFERENCED_PARAMETER(dpc);
263 UNREFERENCED_PARAMETER(arg1);
264 UNREFERENCED_PARAMETER(arg2);
266 FUNCTION_ENTER();
268 switch (xi->device_state->suspend_resume_state_pdo)
269 {
270 case SR_STATE_SUSPENDING:
271 KdPrint((__DRIVER_NAME " New state SUSPENDING\n"));
272 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
273 if (xi->tx_id_free == NET_TX_RING_SIZE)
274 {
275 xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
276 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
277 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
278 }
279 KeReleaseSpinLock(&xi->rx_lock, old_irql);
280 break;
281 case SR_STATE_RESUMING:
282 KdPrint((__DRIVER_NAME " New state SR_STATE_RESUMING\n"));
283 ASSERT(!xi->resume_work_item);
284 xi->resume_work_item = IoAllocateWorkItem(xi->fdo);
285 IoQueueWorkItem(xi->resume_work_item, XenNet_Resume, DelayedWorkQueue, xi);
286 break;
287 default:
288 KdPrint((__DRIVER_NAME " New state %d\n", xi->device_state->suspend_resume_state_fdo));
289 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
290 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
291 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
292 break;
293 }
294 KeMemoryBarrier();
296 FUNCTION_EXIT();
297 }
299 static DDKAPI BOOLEAN
300 XenNet_HandleEvent(PVOID context)
301 {
302 struct xennet_info *xi = context;
303 ULONG suspend_resume_state_pdo;
305 //FUNCTION_ENTER();
306 suspend_resume_state_pdo = xi->device_state->suspend_resume_state_pdo;
307 KeMemoryBarrier();
308 // KdPrint((__DRIVER_NAME " connected = %d, inactive = %d, suspend_resume_state_pdo = %d\n",
309 // xi->connected, xi->inactive, suspend_resume_state_pdo));
310 if (!xi->shutting_down && suspend_resume_state_pdo != xi->device_state->suspend_resume_state_fdo)
311 {
312 KeInsertQueueDpc(&xi->suspend_dpc, NULL, NULL);
313 }
314 if (xi->connected && !xi->inactive && suspend_resume_state_pdo != SR_STATE_RESUMING)
315 {
316 KeInsertQueueDpc(&xi->tx_dpc, NULL, NULL);
317 KeInsertQueueDpc(&xi->rx_dpc, NULL, NULL);
318 }
319 //FUNCTION_EXIT();
320 return TRUE;
321 }
323 // Called at <= DISPATCH_LEVEL
324 static DDKAPI NDIS_STATUS
325 XenNet_Init(
326 OUT PNDIS_STATUS OpenErrorStatus,
327 OUT PUINT SelectedMediumIndex,
328 IN PNDIS_MEDIUM MediumArray,
329 IN UINT MediumArraySize,
330 IN NDIS_HANDLE MiniportAdapterHandle,
331 IN NDIS_HANDLE WrapperConfigurationContext
332 )
333 {
334 NDIS_STATUS status;
335 BOOLEAN medium_found = FALSE;
336 struct xennet_info *xi = NULL;
337 UINT nrl_length;
338 PNDIS_RESOURCE_LIST nrl;
339 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
340 KIRQL irq_level = 0;
341 ULONG irq_vector = 0;
342 ULONG irq_mode = 0;
343 NDIS_HANDLE config_handle;
344 NDIS_STRING config_param_name;
345 PNDIS_CONFIGURATION_PARAMETER config_param;
346 ULONG i;
347 PUCHAR ptr;
348 UCHAR type;
349 PCHAR setting, value;
350 ULONG length;
351 CHAR buf[128];
352 PVOID network_address;
353 UINT network_address_length;
355 UNREFERENCED_PARAMETER(OpenErrorStatus);
357 FUNCTION_ENTER();
359 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
361 length = NdisReadPciSlotInformation(MiniportAdapterHandle, 0, 0, &buf, 128);
362 KdPrint((__DRIVER_NAME " NdisReadPciSlotInformation = %d\n", length));
363 /* deal with medium stuff */
364 for (i = 0; i < MediumArraySize; i++)
365 {
366 if (MediumArray[i] == NdisMedium802_3)
367 {
368 medium_found = TRUE;
369 break;
370 }
371 }
372 if (!medium_found)
373 {
374 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
375 return NDIS_STATUS_UNSUPPORTED_MEDIA;
376 }
377 *SelectedMediumIndex = i;
379 /* Alloc memory for adapter private info */
380 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
381 if (!NT_SUCCESS(status))
382 {
383 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
384 status = NDIS_STATUS_RESOURCES;
385 goto err;
386 }
387 RtlZeroMemory(xi, sizeof(*xi));
388 xi->adapter_handle = MiniportAdapterHandle;
389 xi->rx_target = RX_DFL_MIN_TARGET;
390 xi->rx_min_target = RX_DFL_MIN_TARGET;
391 xi->rx_max_target = RX_MAX_TARGET;
392 xi->inactive = TRUE;
393 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi, 0,
394 #ifdef NDIS51_MINIPORT
395 NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
396 #endif
397 |NDIS_ATTRIBUTE_DESERIALIZE
398 |NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK
399 |NDIS_ATTRIBUTE_BUS_MASTER,
400 NdisInterfaceInternal);
401 xi->multicast_list_size = 0;
403 nrl_length = 0;
404 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
405 NULL, (PUINT)&nrl_length);
406 KdPrint((__DRIVER_NAME " nrl_length = %d\n", nrl_length));
407 status = NdisAllocateMemoryWithTag((PVOID)&nrl, nrl_length, XENNET_POOL_TAG);
408 if (status != NDIS_STATUS_SUCCESS)
409 {
410 KdPrint((__DRIVER_NAME " Could not get allocate memory for Adapter Resources 0x%x\n", status));
411 return NDIS_STATUS_RESOURCES;
412 }
413 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
414 nrl, (PUINT)&nrl_length);
415 if (status != NDIS_STATUS_SUCCESS)
416 {
417 KdPrint((__DRIVER_NAME " Could not get Adapter Resources 0x%x\n", status));
418 return NDIS_STATUS_RESOURCES;
419 }
420 xi->event_channel = 0;
421 xi->config_csum = 1;
422 xi->config_csum_rx_check = 1;
423 xi->config_sg = 1;
424 xi->config_gso = 61440;
425 xi->config_page = NULL;
426 xi->config_rx_interrupt_moderation = 0;
428 for (i = 0; i < nrl->Count; i++)
429 {
430 prd = &nrl->PartialDescriptors[i];
432 switch(prd->Type)
433 {
434 case CmResourceTypeInterrupt:
435 irq_vector = prd->u.Interrupt.Vector;
436 irq_level = (KIRQL)prd->u.Interrupt.Level;
437 irq_mode = (prd->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?NdisInterruptLatched:NdisInterruptLevelSensitive;
438 KdPrint((__DRIVER_NAME " irq_vector = %03x, irq_level = %03x, irq_mode = %s\n", irq_vector, irq_level,
439 (irq_mode == NdisInterruptLatched)?"NdisInterruptLatched":"NdisInterruptLevelSensitive"));
440 break;
441 case CmResourceTypeMemory:
442 if (xi->config_page)
443 {
444 KdPrint(("More than one memory range\n"));
445 return NDIS_STATUS_RESOURCES;
446 }
447 else
448 {
449 status = NdisMMapIoSpace(&xi->config_page, MiniportAdapterHandle, prd->u.Memory.Start, prd->u.Memory.Length);
450 if (!NT_SUCCESS(status))
451 {
452 KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
453 NdisFreeMemory(nrl, nrl_length, 0);
454 return NDIS_STATUS_RESOURCES;
455 }
456 }
457 break;
458 }
459 }
460 NdisFreeMemory(nrl, nrl_length, 0);
461 if (!xi->config_page)
462 {
463 KdPrint(("No config page given\n"));
464 return NDIS_STATUS_RESOURCES;
465 }
467 KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
469 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
470 &xi->lower_do, NULL, NULL);
471 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
473 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
474 NAME_SIZE, xi->dev_desc, &length);
475 if (!NT_SUCCESS(status))
476 {
477 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
478 status = NDIS_STATUS_FAILURE;
479 goto err;
480 }
482 ptr = xi->config_page;
483 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value)) != XEN_INIT_TYPE_END)
484 {
485 switch(type)
486 {
487 case XEN_INIT_TYPE_VECTORS:
488 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
489 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
490 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
491 {
492 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
493 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
494 FUNCTION_ERROR_EXIT();
495 return NDIS_STATUS_FAILURE;
496 }
497 else
498 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
499 break;
500 case XEN_INIT_TYPE_STATE_PTR:
501 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
502 xi->device_state = (PXENPCI_DEVICE_STATE)value;
503 break;
504 case XEN_INIT_TYPE_ACTIVE:
505 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_ACTIVE\n"));
506 xi->inactive = FALSE;
507 break;
508 default:
509 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
510 break;
511 }
512 }
514 // now build config page
516 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
517 if (!NT_SUCCESS(status))
518 {
519 KdPrint(("Could not open config in registry (%08x)\n", status));
520 status = NDIS_STATUS_RESOURCES;
521 goto err;
522 }
524 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
525 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
526 if (!NT_SUCCESS(status))
527 {
528 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
529 xi->config_sg = 1;
530 }
531 else
532 {
533 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
534 xi->config_sg = config_param->ParameterData.IntegerData;
535 }
537 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
538 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
539 if (!NT_SUCCESS(status))
540 {
541 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
542 xi->config_gso = 0;
543 }
544 else
545 {
546 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
547 xi->config_gso = config_param->ParameterData.IntegerData;
548 if (xi->config_gso > 61440)
549 {
550 xi->config_gso = 61440;
551 KdPrint(("(clipped to %d)\n", xi->config_gso));
552 }
553 }
555 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
556 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
557 if (!NT_SUCCESS(status))
558 {
559 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
560 xi->config_csum = 1;
561 }
562 else
563 {
564 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
565 xi->config_csum = !!config_param->ParameterData.IntegerData;
566 }
568 NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadRxCheck");
569 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
570 if (!NT_SUCCESS(status))
571 {
572 KdPrint(("Could not read ChecksumOffloadRxCheck value (%08x)\n", status));
573 xi->config_csum_rx_check = 1;
574 }
575 else
576 {
577 KdPrint(("ChecksumOffloadRxCheck = %d\n", config_param->ParameterData.IntegerData));
578 xi->config_csum_rx_check = !!config_param->ParameterData.IntegerData;
579 }
581 NdisInitUnicodeString(&config_param_name, L"MTU");
582 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
583 if (!NT_SUCCESS(status))
584 {
585 KdPrint(("Could not read MTU value (%08x)\n", status));
586 xi->config_mtu = 1500;
587 }
588 else
589 {
590 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
591 xi->config_mtu = config_param->ParameterData.IntegerData;
592 }
594 NdisInitUnicodeString(&config_param_name, L"RxInterruptModeration");
595 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
596 if (!NT_SUCCESS(status))
597 {
598 KdPrint(("Could not read RxInterruptModeration value (%08x)\n", status));
599 xi->config_rx_interrupt_moderation = 1500;
600 }
601 else
602 {
603 KdPrint(("RxInterruptModeration = %d\n", config_param->ParameterData.IntegerData));
604 xi->config_rx_interrupt_moderation = config_param->ParameterData.IntegerData;
605 }
608 NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
609 if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || !(((PUCHAR)network_address)[0] & 0x02))
610 {
611 KdPrint(("Could not read NetworkAddress value (%08x)\n", status));
612 memset(xi->curr_mac_addr, 0, ETH_ALEN);
613 }
614 else
615 {
616 memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
617 KdPrint((" Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
618 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
619 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]));
620 }
622 xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
624 NdisCloseConfiguration(config_handle);
626 ptr = xi->config_page;
627 // two XEN_INIT_TYPE_RUNs means go straight to XenbusStateConnected - skip XenbusStateInitialised
628 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
629 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
630 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
631 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
632 #pragma warning(suppress:4054)
633 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
634 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
635 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
636 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
637 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
638 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
639 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
640 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
641 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
642 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
643 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
644 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
645 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
647 status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
648 if (!NT_SUCCESS(status))
649 {
650 KdPrint(("Failed to complete device configuration (%08x)\n", status));
651 goto err;
652 }
654 status = XenNet_ConnectBackend(xi);
656 if (!NT_SUCCESS(status))
657 {
658 KdPrint(("Failed to complete device configuration (%08x)\n", status));
659 goto err;
660 }
662 if (xi->config_sg)
663 {
664 status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE, xi->config_gso);
665 if (!NT_SUCCESS(status))
666 {
667 KdPrint(("NdisMInitializeScatterGatherDma failed (%08x), disabling\n", status));
668 xi->config_sg = 0;
669 }
670 }
671 else
672 {
673 status = NdisMAllocateMapRegisters(xi->adapter_handle, 0, NDIS_DMA_64BITS, 64, PAGE_SIZE);
674 if (status != NDIS_STATUS_SUCCESS)
675 {
676 KdPrint((__DRIVER_NAME " Cannot allocate Map Registers\n"));
677 }
678 /* without SG, GSO can be a maximum of PAGE_SIZE */
679 xi->config_gso = min(xi->config_gso, PAGE_SIZE);
680 }
682 XenNet_TxInit(xi);
683 XenNet_RxInit(xi);
685 xi->connected = TRUE;
687 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
689 FUNCTION_EXIT();
691 return NDIS_STATUS_SUCCESS;
693 err:
694 NdisFreeMemory(xi, 0, 0);
695 *OpenErrorStatus = status;
696 FUNCTION_ERROR_EXIT();
697 return status;
698 }
700 VOID
701 XenNet_PnPEventNotify(
702 IN NDIS_HANDLE MiniportAdapterContext,
703 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
704 IN PVOID InformationBuffer,
705 IN ULONG InformationBufferLength
706 )
707 {
708 UNREFERENCED_PARAMETER(MiniportAdapterContext);
709 UNREFERENCED_PARAMETER(PnPEvent);
710 UNREFERENCED_PARAMETER(InformationBuffer);
711 UNREFERENCED_PARAMETER(InformationBufferLength);
713 FUNCTION_CALLED();
714 }
716 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
717 VOID DDKAPI
718 XenNet_Shutdown(
719 IN NDIS_HANDLE MiniportAdapterContext
720 )
721 {
722 UNREFERENCED_PARAMETER(MiniportAdapterContext);
724 /* remember we are called at >= DIRQL here */
725 FUNCTION_CALLED();
726 }
728 /* Opposite of XenNet_Init */
729 VOID DDKAPI
730 XenNet_Halt(
731 IN NDIS_HANDLE MiniportAdapterContext
732 )
733 {
734 struct xennet_info *xi = MiniportAdapterContext;
736 FUNCTION_ENTER();
737 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
739 xi->shutting_down = TRUE;
740 KeMemoryBarrier(); /* make sure everyone sees that we are now shutting down */
742 XenNet_TxShutdown(xi);
743 XenNet_RxShutdown(xi);
745 xi->connected = FALSE;
746 KeMemoryBarrier(); /* make sure everyone sees that we are now disconnected */
748 xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
750 if (!xi->config_sg)
751 {
752 NdisMFreeMapRegisters(xi->adapter_handle);
753 }
755 NdisFreeMemory(xi, 0, 0);
757 FUNCTION_EXIT();
758 }
760 NDIS_STATUS
761 XenNet_Reset(
762 PBOOLEAN AddressingReset,
763 NDIS_HANDLE MiniportAdapterContext
764 )
765 {
766 UNREFERENCED_PARAMETER(MiniportAdapterContext);
768 *AddressingReset = FALSE;
769 return NDIS_STATUS_SUCCESS;
770 }
772 dma_driver_extension_t *dma_driver_extension;
774 NTSTATUS DDKAPI
775 DriverEntry(
776 PDRIVER_OBJECT DriverObject,
777 PUNICODE_STRING RegistryPath
778 )
779 {
780 NTSTATUS status;
781 NDIS_HANDLE ndis_wrapper_handle = NULL;
782 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
784 FUNCTION_ENTER();
786 IoAllocateDriverObjectExtension(DriverObject, UlongToPtr(XEN_DMA_DRIVER_EXTENSION_MAGIC), sizeof(dma_driver_extension_t), &dma_driver_extension);
787 dma_driver_extension->need_virtual_address = NULL;
788 dma_driver_extension->get_alignment = NULL;
789 dma_driver_extension->max_sg_elements = 19; /* header + 18 fragments */
791 KdPrint((__DRIVER_NAME " DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
792 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
794 KdPrint((__DRIVER_NAME " NdisGetVersion = %x\n", NdisGetVersion()));
796 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
797 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
798 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
799 if (!ndis_wrapper_handle)
800 {
801 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper failed\n"));
802 return NDIS_STATUS_FAILURE;
803 }
804 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper succeeded\n"));
806 /* NDIS 5.1 driver */
807 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
808 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
810 KdPrint((__DRIVER_NAME " MajorNdisVersion = %d, MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
812 mini_chars.HaltHandler = XenNet_Halt;
813 mini_chars.InitializeHandler = XenNet_Init;
814 //mini_chars.ISRHandler = XenNet_InterruptIsr;
815 //mini_chars.HandleInterruptHandler = XenNet_InterruptDpc;
816 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
817 mini_chars.ResetHandler = XenNet_Reset;
818 mini_chars.SetInformationHandler = XenNet_SetInformation;
819 /* added in v.4 -- use multiple pkts interface */
820 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
821 mini_chars.SendPacketsHandler = XenNet_SendPackets;
822 mini_chars.CancelSendPacketsHandler = XenNet_CancelSendPackets;
824 #ifdef NDIS51_MINIPORT
825 /* added in v.5.1 */
826 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
827 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
828 #else
829 // something else here
830 #endif
832 /* set up upper-edge interface */
833 KdPrint((__DRIVER_NAME " about to call NdisMRegisterMiniport\n"));
834 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
835 KdPrint((__DRIVER_NAME " called NdisMRegisterMiniport\n"));
836 if (!NT_SUCCESS(status))
837 {
838 KdPrint((__DRIVER_NAME " NdisMRegisterMiniport failed, status = 0x%x\n", status));
839 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
840 return status;
841 }
843 FUNCTION_EXIT();
845 return status;
846 }