win-pvdrivers

view xennet/xennet.c @ 749:233c06b133e9

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