win-pvdrivers

annotate xennet/xennet.c @ 370:d76831a77d19

merge
author Andy Grover <andy.grover@oracle.com>
date Wed Jul 09 00:26:05 2008 -0700 (2008-07-09)
parents 5a762fd1fba9 cb12e8b450a8
children 8e10579159a0
rev   line source
andy@11 1 /*
andy@11 2 PV Net Driver for Windows Xen HVM Domains
andy@11 3 Copyright (C) 2007 James Harper
andy@32 4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
andy@11 5
andy@11 6 This program is free software; you can redistribute it and/or
andy@11 7 modify it under the terms of the GNU General Public License
andy@11 8 as published by the Free Software Foundation; either version 2
andy@11 9 of the License, or (at your option) any later version.
andy@11 10
andy@11 11 This program is distributed in the hope that it will be useful,
andy@11 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
andy@11 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andy@11 14 GNU General Public License for more details.
andy@11 15
andy@11 16 You should have received a copy of the GNU General Public License
andy@11 17 along with this program; if not, write to the Free Software
andy@11 18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
andy@11 19 */
andy@11 20
andy@22 21 #include <stdlib.h>
andy@22 22 #include <io/xenbus.h>
andy@11 23 #include "xennet.h"
andy@11 24
andy@369 25 /* ----- BEGIN Other people's code --------- */
andy@369 26 /* from linux/include/linux/ctype.h, used under GPLv2 */
andy@369 27 #define _U 0x01 /* upper */
andy@369 28 #define _L 0x02 /* lower */
andy@369 29 #define _D 0x04 /* digit */
andy@369 30 #define _C 0x08 /* cntrl */
andy@369 31 #define _P 0x10 /* punct */
andy@369 32 #define _S 0x20 /* white space (space/lf/tab) */
andy@369 33 #define _X 0x40 /* hex digit */
andy@369 34 #define _SP 0x80 /* hard space (0x20) */
andy@369 35
andy@369 36 /* from linux/include/lib/ctype.c, used under GPLv2 */
andy@369 37 unsigned char _ctype[] = {
andy@369 38 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
andy@369 39 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
andy@369 40 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
andy@369 41 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
andy@369 42 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
andy@369 43 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
andy@369 44 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
andy@369 45 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
andy@369 46 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
andy@369 47 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
andy@369 48 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
andy@369 49 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
andy@369 50 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
andy@369 51 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
andy@369 52 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
andy@369 53 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
andy@369 54 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
andy@369 55 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
andy@369 56 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
andy@369 57 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
andy@369 58 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
andy@369 59 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
andy@369 60 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
andy@369 61 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
andy@369 62
andy@369 63 /* from linux/include/linux/ctype.h, used under GPLv2 */
andy@369 64 #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
andy@369 65
andy@369 66 #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
andy@369 67 #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
andy@369 68 #define iscntrl(c) ((__ismask(c)&(_C)) != 0)
andy@369 69 #define isdigit(c) ((__ismask(c)&(_D)) != 0)
andy@369 70 #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
andy@369 71 #define islower(c) ((__ismask(c)&(_L)) != 0)
andy@369 72 #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
andy@369 73 #define ispunct(c) ((__ismask(c)&(_P)) != 0)
andy@369 74 #define isspace(c) ((__ismask(c)&(_S)) != 0)
andy@369 75 #define isupper(c) ((__ismask(c)&(_U)) != 0)
andy@369 76 #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
andy@369 77
andy@369 78 #define TOLOWER(x) ((x) | 0x20)
andy@369 79
andy@369 80 /* from linux/lib/vsprintf.c, used under GPLv2 */
andy@369 81 /* Copyright (C) 1991, 1992 Linus Torvalds
andy@369 82 * Wirzenius wrote this portably, Torvalds fucked it up :-)
andy@369 83 */
andy@369 84 /**
andy@369 85 * simple_strtoul - convert a string to an unsigned long
andy@369 86 * @cp: The start of the string
andy@369 87 * @endp: A pointer to the end of the parsed string will be placed here
andy@369 88 * @base: The number base to use
andy@369 89 */
andy@369 90 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
andy@22 91 {
andy@22 92 unsigned long result = 0,value;
andy@22 93
andy@22 94 if (!base) {
andy@22 95 base = 10;
andy@22 96 if (*cp == '0') {
andy@22 97 base = 8;
andy@22 98 cp++;
andy@369 99 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
andy@22 100 cp++;
andy@22 101 base = 16;
andy@22 102 }
andy@22 103 }
andy@22 104 } else if (base == 16) {
andy@369 105 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
andy@369 106 cp += 2;
andy@22 107 }
andy@22 108 while (isxdigit(*cp) &&
andy@369 109 (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
andy@22 110 result = result*base + value;
andy@22 111 cp++;
andy@22 112 }
andy@22 113 if (endp)
andy@369 114 *endp = (char *)cp;
andy@22 115 return result;
james@138 116 }
andy@369 117 /* end vsprintf.c code */
andy@369 118 /* ----- END Other people's code --------- */
andy@22 119
james@80 120 // Called at DISPATCH_LEVEL
james@138 121
andy@369 122 static DDKAPI VOID
james@271 123 XenNet_InterruptIsr(
james@271 124 PBOOLEAN InterruptRecognized,
james@271 125 PBOOLEAN QueueMiniportHandleInterrupt,
james@271 126 NDIS_HANDLE MiniportAdapterContext)
andy@11 127 {
james@271 128 struct xennet_info *xi = MiniportAdapterContext;
james@271 129
james@271 130 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
andy@14 131
james@271 132 *QueueMiniportHandleInterrupt = (BOOLEAN)!!xi->connected;
james@271 133 *InterruptRecognized = FALSE; /* we can't be sure here... */
andy@11 134
james@271 135 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@271 136 }
james@271 137
andy@369 138 static DDKAPI VOID
james@271 139 XenNet_InterruptDpc(NDIS_HANDLE MiniportAdapterContext)
james@271 140 {
james@271 141 struct xennet_info *xi = MiniportAdapterContext;
james@271 142
james@271 143 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
andy@30 144 if (xi->connected)
andy@30 145 {
andy@43 146 XenNet_TxBufferGC(xi);
andy@43 147 XenNet_RxBufferCheck(xi);
andy@30 148 }
james@271 149 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
andy@11 150 }
andy@11 151
james@343 152 static NDIS_STATUS
james@343 153 XenNet_ConnectBackend(struct xennet_info *xi)
james@343 154 {
james@343 155 PUCHAR ptr;
james@343 156 UCHAR type;
james@343 157 PCHAR setting, value;
james@343 158 UINT i;
james@343 159
james@343 160 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@343 161
james@343 162 ptr = xi->config_page;
andy@369 163 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value)) != XEN_INIT_TYPE_END)
james@343 164 {
james@343 165 switch(type)
james@343 166 {
james@343 167 case XEN_INIT_TYPE_RING: /* frontend ring */
james@343 168 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
james@343 169 if (strcmp(setting, "tx-ring-ref") == 0)
james@343 170 {
james@343 171 FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
james@343 172 } else if (strcmp(setting, "rx-ring-ref") == 0)
james@343 173 {
james@343 174 FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
james@343 175 }
james@343 176 break;
james@343 177 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel */
james@343 178 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
james@343 179 if (strcmp(setting, "event-channel") == 0)
james@343 180 {
james@343 181 xi->event_channel = PtrToUlong(value);
james@343 182 }
james@343 183 break;
james@343 184 case XEN_INIT_TYPE_READ_STRING_BACK:
james@343 185 case XEN_INIT_TYPE_READ_STRING_FRONT:
james@343 186 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
james@343 187 if (strcmp(setting, "mac") == 0)
james@343 188 {
james@343 189 char *s, *e;
james@343 190 s = value;
james@343 191 for (i = 0; i < ETH_ALEN; i++) {
andy@369 192 xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
james@343 193 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
james@343 194 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
james@343 195 }
james@343 196 s = e + 1;
james@343 197 }
james@343 198 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
james@343 199 }
james@343 200 break;
james@343 201 case XEN_INIT_TYPE_VECTORS:
james@343 202 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
james@343 203 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
james@343 204 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
james@343 205 {
james@343 206 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
james@343 207 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
james@343 208 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
andy@369 209 return NDIS_STATUS_ADAPTER_NOT_FOUND;
james@343 210 }
james@343 211 else
james@343 212 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
james@343 213 break;
james@353 214 case XEN_INIT_TYPE_STATE_PTR:
james@353 215 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
james@353 216 xi->device_state = (PXENPCI_DEVICE_STATE)value;
james@353 217 break;
james@343 218 default:
james@343 219 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
james@343 220 break;
james@343 221 }
james@343 222 }
james@343 223 return NDIS_STATUS_SUCCESS;
james@343 224 }
james@343 225
andy@369 226 static DDKAPI VOID
james@343 227 XenNet_Resume(PDEVICE_OBJECT device_object, PVOID context)
james@343 228 {
james@343 229 struct xennet_info *xi = context;
james@343 230
james@343 231 UNREFERENCED_PARAMETER(device_object);
james@343 232
james@343 233 XenNet_RxResumeStart(xi);
james@343 234 XenNet_TxResumeStart(xi);
james@343 235 XenNet_ConnectBackend(xi);
james@343 236 xi->device_state->resume_state = RESUME_STATE_RUNNING;
james@343 237 XenNet_RxResumeEnd(xi);
james@343 238 XenNet_TxResumeEnd(xi);
james@343 239 NdisMSetPeriodicTimer(&xi->resume_timer, 100);
james@343 240 }
james@343 241
andy@369 242 static DDKAPI VOID
james@343 243 XenResumeCheck_Timer(
james@343 244 PVOID SystemSpecific1,
james@343 245 PVOID FunctionContext,
james@343 246 PVOID SystemSpecific2,
james@343 247 PVOID SystemSpecific3
james@343 248 )
james@343 249 {
james@343 250 struct xennet_info *xi = FunctionContext;
james@343 251 PIO_WORKITEM work_item;
james@343 252 BOOLEAN timer_cancelled;
james@343 253
james@343 254 UNREFERENCED_PARAMETER(SystemSpecific1);
james@343 255 UNREFERENCED_PARAMETER(SystemSpecific2);
james@343 256 UNREFERENCED_PARAMETER(SystemSpecific3);
james@343 257
james@343 258 if (xi->device_state->resume_state == RESUME_STATE_FRONTEND_RESUME)
james@343 259 {
james@343 260 NdisMCancelTimer(&xi->resume_timer, &timer_cancelled);
james@343 261 work_item = IoAllocateWorkItem(xi->fdo);
james@343 262 IoQueueWorkItem(work_item, XenNet_Resume, DelayedWorkQueue, xi);
james@343 263 }
james@343 264 }
james@343 265
james@95 266 // Called at <= DISPATCH_LEVEL
andy@369 267 static DDKAPI NDIS_STATUS
andy@11 268 XenNet_Init(
andy@11 269 OUT PNDIS_STATUS OpenErrorStatus,
andy@11 270 OUT PUINT SelectedMediumIndex,
andy@11 271 IN PNDIS_MEDIUM MediumArray,
andy@11 272 IN UINT MediumArraySize,
andy@11 273 IN NDIS_HANDLE MiniportAdapterHandle,
andy@11 274 IN NDIS_HANDLE WrapperConfigurationContext
andy@11 275 )
andy@11 276 {
andy@11 277 NDIS_STATUS status;
andy@11 278 BOOLEAN medium_found = FALSE;
andy@11 279 struct xennet_info *xi = NULL;
james@275 280 ULONG nrl_length;
james@271 281 PNDIS_RESOURCE_LIST nrl;
james@271 282 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
james@272 283 KIRQL irq_level = 0;
james@272 284 ULONG irq_vector = 0;
james@314 285 NDIS_HANDLE config_handle;
james@314 286 NDIS_STRING config_param_name;
james@314 287 PNDIS_CONFIGURATION_PARAMETER config_param;
james@343 288 ULONG i;
james@343 289 PUCHAR ptr;
james@343 290 UCHAR type;
james@343 291 PCHAR setting, value;
james@343 292 ULONG length;
james@318 293 CHAR buf[128];
james@271 294
andy@14 295 UNREFERENCED_PARAMETER(OpenErrorStatus);
andy@11 296
james@95 297 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 298 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
james@95 299
andy@11 300 /* deal with medium stuff */
andy@11 301 for (i = 0; i < MediumArraySize; i++)
andy@11 302 {
andy@11 303 if (MediumArray[i] == NdisMedium802_3)
andy@11 304 {
andy@11 305 medium_found = TRUE;
andy@11 306 break;
andy@11 307 }
andy@11 308 }
andy@11 309 if (!medium_found)
andy@11 310 {
andy@11 311 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
andy@11 312 return NDIS_STATUS_UNSUPPORTED_MEDIA;
andy@11 313 }
andy@11 314 *SelectedMediumIndex = i;
andy@11 315
andy@11 316 /* Alloc memory for adapter private info */
andy@369 317 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
andy@11 318 if (!NT_SUCCESS(status))
andy@11 319 {
andy@11 320 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
andy@11 321 status = NDIS_STATUS_RESOURCES;
andy@11 322 goto err;
andy@11 323 }
andy@11 324 RtlZeroMemory(xi, sizeof(*xi));
andy@11 325 xi->adapter_handle = MiniportAdapterHandle;
andy@43 326 xi->rx_target = RX_DFL_MIN_TARGET;
andy@43 327 xi->rx_min_target = RX_DFL_MIN_TARGET;
andy@43 328 xi->rx_max_target = RX_MAX_TARGET;
james@271 329 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
james@271 330 0, NDIS_ATTRIBUTE_DESERIALIZE, // | NDIS_ATTRIBUTE_BUS_MASTER),
james@271 331 NdisInterfaceInternal);
andy@43 332
james@275 333 nrl_length = 0;
james@271 334 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
james@275 335 NULL, (PUINT)&nrl_length);
james@275 336 KdPrint((__DRIVER_NAME " nrl_length = %d\n", nrl_length));
andy@369 337 status = NdisAllocateMemoryWithTag((PVOID)&nrl, nrl_length, XENNET_POOL_TAG);
james@274 338 if (status != NDIS_STATUS_SUCCESS)
james@274 339 {
james@274 340 KdPrint((__DRIVER_NAME " Could not get allocate memory for Adapter Resources 0x%x\n", status));
andy@369 341 return NDIS_STATUS_RESOURCES;
james@274 342 }
james@271 343 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
james@275 344 nrl, (PUINT)&nrl_length);
james@271 345 if (status != NDIS_STATUS_SUCCESS)
james@271 346 {
james@274 347 KdPrint((__DRIVER_NAME " Could not get Adapter Resources 0x%x\n", status));
andy@369 348 return NDIS_STATUS_RESOURCES;
james@271 349 }
james@271 350 xi->event_channel = 0;
james@271 351 xi->config_csum = 1;
james@271 352 xi->config_sg = 1;
james@274 353 xi->config_gso = 61440;
james@314 354 xi->config_page = NULL;
james@314 355
james@271 356 for (i = 0; i < nrl->Count; i++)
james@271 357 {
james@271 358 prd = &nrl->PartialDescriptors[i];
james@271 359
james@271 360 switch(prd->Type)
james@271 361 {
james@271 362 case CmResourceTypeInterrupt:
james@271 363 irq_vector = prd->u.Interrupt.Vector;
james@271 364 irq_level = (KIRQL)prd->u.Interrupt.Level;
james@271 365 KdPrint((__DRIVER_NAME " irq_vector = %03x, irq_level = %03x\n", irq_vector, irq_level));
james@271 366 break;
james@271 367
james@271 368 case CmResourceTypeMemory:
james@314 369 status = NdisMMapIoSpace(&xi->config_page, MiniportAdapterHandle, prd->u.Memory.Start, prd->u.Memory.Length);
james@314 370 if (!NT_SUCCESS(status))
james@271 371 {
james@314 372 KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
james@314 373 NdisFreeMemory(nrl, nrl_length, 0);
james@314 374 return NDIS_STATUS_RESOURCES;
james@271 375 }
james@271 376 break;
james@271 377 }
james@275 378 }
james@275 379 NdisFreeMemory(nrl, nrl_length, 0);
james@314 380 if (!xi->config_page)
james@314 381 {
james@314 382 KdPrint(("No config page given\n"));
james@314 383 return NDIS_STATUS_RESOURCES;
james@314 384 }
james@271 385
james@271 386 KeInitializeSpinLock(&xi->rx_lock);
james@271 387
james@271 388 InitializeListHead(&xi->tx_waiting_pkt_list);
james@271 389
james@271 390 NdisAllocatePacketPool(&status, &xi->packet_pool, XN_RX_QUEUE_LEN * 8,
james@271 391 PROTOCOL_RESERVED_SIZE_IN_PACKET);
james@271 392 if (status != NDIS_STATUS_SUCCESS)
james@271 393 {
james@271 394 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
james@271 395 status = NDIS_STATUS_RESOURCES;
james@271 396 goto err;
james@271 397 }
james@271 398 NdisSetPacketPoolProtocolId(xi->packet_pool, NDIS_PROTOCOL_ID_TCP_IP);
james@271 399
james@271 400 NdisAllocateBufferPool(&status, &xi->buffer_pool, XN_RX_QUEUE_LEN);
james@271 401 if (status != NDIS_STATUS_SUCCESS)
james@271 402 {
james@271 403 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
james@271 404 status = NDIS_STATUS_RESOURCES;
james@271 405 goto err;
james@271 406 }
james@271 407
james@271 408 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
james@271 409 &xi->lower_do, NULL, NULL);
james@271 410 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
james@271 411
james@271 412 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
james@271 413 NAME_SIZE, xi->dev_desc, &length);
james@271 414 if (!NT_SUCCESS(status))
james@271 415 {
james@271 416 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
james@271 417 status = NDIS_STATUS_FAILURE;
james@271 418 goto err;
james@271 419 }
james@271 420
james@314 421 ptr = xi->config_page;
andy@369 422 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value)) != XEN_INIT_TYPE_END)
james@314 423 {
james@314 424 switch(type)
james@314 425 {
james@314 426 case XEN_INIT_TYPE_VECTORS:
james@314 427 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
james@314 428 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
james@314 429 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
james@314 430 {
james@314 431 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
james@314 432 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
james@314 433 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
andy@369 434 return NDIS_STATUS_FAILURE;
james@314 435 }
james@314 436 else
james@314 437 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
james@314 438 break;
james@343 439 case XEN_INIT_TYPE_STATE_PTR:
james@343 440 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
james@343 441 xi->device_state = (PXENPCI_DEVICE_STATE)value;
james@343 442 break;
james@314 443 default:
james@314 444 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
james@314 445 break;
james@314 446 }
james@314 447 }
james@353 448
james@314 449 // now build config page
james@314 450
james@314 451 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
james@314 452 if (!NT_SUCCESS(status))
james@314 453 {
james@314 454 KdPrint(("Could not open config in registry (%08x)\n", status));
james@314 455 goto err;
james@314 456 }
james@314 457
james@314 458 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
james@314 459 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
james@314 460 if (!NT_SUCCESS(status))
james@314 461 {
james@314 462 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
james@314 463 xi->config_sg = 1;
james@314 464 }
james@314 465 else
james@314 466 {
james@314 467 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
james@314 468 xi->config_sg = config_param->ParameterData.IntegerData;
james@314 469 }
james@314 470
james@314 471 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
james@314 472 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
james@314 473 if (!NT_SUCCESS(status))
james@314 474 {
james@314 475 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
james@314 476 xi->config_gso = 0;
james@314 477 }
james@314 478 else
james@314 479 {
james@314 480 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
james@314 481 xi->config_gso = config_param->ParameterData.IntegerData;
james@314 482 if (xi->config_gso > 61440)
james@314 483 {
james@314 484 xi->config_gso = 61440;
james@314 485 KdPrint(("(clipped to %d)\n", xi->config_gso));
james@314 486 }
james@314 487 }
james@314 488
james@314 489 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
james@314 490 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
james@314 491 if (!NT_SUCCESS(status))
james@314 492 {
james@314 493 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
james@314 494 xi->config_csum = 1;
james@314 495 }
james@314 496 else
james@314 497 {
james@314 498 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
james@318 499 xi->config_csum = !!config_param->ParameterData.IntegerData;
james@314 500 }
james@314 501
james@314 502 NdisInitUnicodeString(&config_param_name, L"MTU");
james@314 503 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
james@314 504 if (!NT_SUCCESS(status))
james@314 505 {
james@314 506 KdPrint(("Could not read MTU value (%08x)\n", status));
james@314 507 xi->config_mtu = 1500;
james@314 508 }
james@314 509 else
james@314 510 {
james@314 511 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
james@314 512 xi->config_mtu = config_param->ParameterData.IntegerData;
james@314 513 }
james@314 514
james@314 515 xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
james@314 516
james@314 517 NdisCloseConfiguration(config_handle);
james@314 518
james@314 519 ptr = xi->config_page;
james@314 520 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL);
james@314 521 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL);
james@314 522 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL);
james@314 523 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL_IRQ, "event-channel", NULL);
james@314 524 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL);
james@318 525 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
james@318 526 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf);
andy@369 527 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
james@318 528 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf);
james@318 529 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
james@318 530 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf);
james@314 531 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1");
james@314 532 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1");
james@314 533 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL);
james@314 534
james@314 535 status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
james@314 536 // check return value
james@314 537
james@343 538 status = XenNet_ConnectBackend(xi);
james@314 539
james@271 540 KeInitializeEvent(&xi->shutdown_event, SynchronizationEvent, FALSE);
james@271 541
james@271 542 XenNet_TxInit(xi);
james@271 543 XenNet_RxInit(xi);
james@271 544
james@271 545 xi->connected = TRUE;
james@271 546
james@271 547 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
james@271 548
james@271 549 status = NdisMRegisterInterrupt(&xi->interrupt, MiniportAdapterHandle, irq_vector, irq_level,
james@271 550 TRUE, TRUE, NdisInterruptLatched);
james@271 551 /* send fake arp? */
james@271 552 if (!NT_SUCCESS(status))
james@271 553 {
james@271 554 KdPrint(("NdisMRegisterInterrupt failed with 0x%x\n", status));
james@271 555 //status = NDIS_STATUS_FAILURE;
james@271 556 //goto err;
james@271 557 }
james@271 558
james@343 559 NdisMInitializeTimer(&xi->resume_timer, xi->adapter_handle, XenResumeCheck_Timer, xi);
james@343 560 NdisMSetPeriodicTimer(&xi->resume_timer, 100);
james@343 561
james@271 562 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@271 563
james@271 564 return NDIS_STATUS_SUCCESS;
james@271 565
james@271 566 err:
james@271 567 NdisFreeMemory(xi, 0, 0);
james@271 568 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (error path)\n"));
james@271 569 return status;
james@271 570 }
james@271 571
james@271 572 VOID
james@271 573 XenNet_PnPEventNotify(
james@271 574 IN NDIS_HANDLE MiniportAdapterContext,
james@271 575 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
james@271 576 IN PVOID InformationBuffer,
james@271 577 IN ULONG InformationBufferLength
james@271 578 )
james@271 579 {
james@271 580 UNREFERENCED_PARAMETER(MiniportAdapterContext);
james@271 581 UNREFERENCED_PARAMETER(PnPEvent);
james@271 582 UNREFERENCED_PARAMETER(InformationBuffer);
james@271 583 UNREFERENCED_PARAMETER(InformationBufferLength);
james@271 584
james@271 585 KdPrint((__FUNCTION__ " called\n"));
james@271 586 }
james@271 587
james@271 588 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
andy@369 589 VOID DDKAPI
james@271 590 XenNet_Shutdown(
james@271 591 IN NDIS_HANDLE MiniportAdapterContext
james@271 592 )
james@271 593 {
james@274 594 struct xennet_info *xi = MiniportAdapterContext;
james@271 595
james@271 596 KdPrint((__FUNCTION__ " called\n"));
james@274 597
james@274 598 NdisMDeregisterInterrupt(&xi->interrupt);
james@271 599 }
james@271 600
james@271 601 /* Opposite of XenNet_Init */
andy@369 602 VOID DDKAPI
james@271 603 XenNet_Halt(
james@271 604 IN NDIS_HANDLE MiniportAdapterContext
james@271 605 )
james@271 606 {
james@271 607 struct xennet_info *xi = MiniportAdapterContext;
james@271 608 // CHAR TmpPath[MAX_XENBUS_STR_LEN];
james@271 609 // PVOID if_cxt = xi->XenInterface.InterfaceHeader.Context;
james@271 610 // LARGE_INTEGER timeout;
james@271 611
james@271 612 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@271 613 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
james@271 614
james@271 615 // Disables the interrupt
james@271 616 XenNet_Shutdown(xi);
james@271 617
james@314 618 xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
james@275 619
james@271 620 xi->connected = FALSE;
james@271 621 KeMemoryBarrier(); /* make sure everyone sees that we are now shut down */
james@271 622
james@271 623 // TODO: remove event channel xenbus entry (how?)
james@271 624
james@271 625 XenNet_TxShutdown(xi);
james@271 626 XenNet_RxShutdown(xi);
james@271 627
james@271 628 NdisFreeBufferPool(xi->buffer_pool);
james@271 629 NdisFreePacketPool(xi->packet_pool);
james@271 630
james@271 631 NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
james@271 632
james@271 633 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@271 634 }
james@271 635
andy@11 636 NTSTATUS
andy@11 637 DriverEntry(
andy@11 638 PDRIVER_OBJECT DriverObject,
andy@11 639 PUNICODE_STRING RegistryPath
andy@11 640 )
andy@11 641 {
andy@11 642 NTSTATUS status;
andy@11 643 NDIS_HANDLE ndis_wrapper_handle;
andy@11 644 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
andy@11 645
andy@11 646 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
andy@11 647
andy@11 648 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
andy@11 649 if (!ndis_wrapper_handle)
andy@11 650 {
andy@11 651 KdPrint(("NdisMInitializeWrapper failed\n"));
andy@11 652 return NDIS_STATUS_FAILURE;
andy@11 653 }
andy@11 654
andy@11 655 /* NDIS 5.1 driver */
james@195 656 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
james@195 657 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
andy@11 658
andy@11 659 mini_chars.HaltHandler = XenNet_Halt;
andy@11 660 mini_chars.InitializeHandler = XenNet_Init;
james@271 661 mini_chars.ISRHandler = XenNet_InterruptIsr;
james@271 662 mini_chars.HandleInterruptHandler = XenNet_InterruptDpc;
andy@11 663 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
andy@11 664 mini_chars.ResetHandler = NULL; //TODO: fill in
andy@11 665 mini_chars.SetInformationHandler = XenNet_SetInformation;
andy@11 666 /* added in v.4 -- use multiple pkts interface */
andy@11 667 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
andy@11 668 mini_chars.SendPacketsHandler = XenNet_SendPackets;
james@195 669
james@195 670 #if defined (NDIS51_MINIPORT)
andy@11 671 /* added in v.5.1 */
andy@11 672 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
andy@11 673 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
james@195 674 #else
james@195 675 // something else here
james@195 676 #endif
andy@11 677
andy@11 678 /* set up upper-edge interface */
andy@11 679 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
andy@11 680 if (!NT_SUCCESS(status))
andy@11 681 {
andy@11 682 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
andy@11 683 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
andy@11 684 return status;
andy@11 685 }
andy@11 686
andy@11 687 return status;
andy@11 688 }