win-pvdrivers

annotate xennet/xennet.c @ 44:01f874217465

xennet: tx and rx both work!
author Andy Grover <andy.grover@oracle.com>
date Thu Dec 13 12:30:19 2007 -0800 (2007-12-13)
parents 59691f2a99f6
children cc2c13724f45
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@32 25 #define wmb() KeMemoryBarrier()
andy@32 26 #define mb() KeMemoryBarrier()
andy@32 27
andy@11 28 #if !defined (NDIS51_MINIPORT)
andy@11 29 #error requires NDIS 5.1 compilation environment
andy@11 30 #endif
andy@11 31
andy@30 32 #define GRANT_INVALID_REF 0
andy@11 33
andy@30 34 /* couldn't get regular xen ring macros to work...*/
andy@30 35 #define __NET_RING_SIZE(type, _sz) \
andy@30 36 (__RD32( \
andy@30 37 (_sz - sizeof(struct type##_sring) + sizeof(union type##_sring_entry)) \
andy@30 38 / sizeof(union type##_sring_entry)))
andy@30 39
andy@30 40 #define NET_TX_RING_SIZE __NET_RING_SIZE(netif_tx, PAGE_SIZE)
andy@30 41 #define NET_RX_RING_SIZE __NET_RING_SIZE(netif_rx, PAGE_SIZE)
andy@11 42
andy@32 43 #pragma warning(disable: 4127) // conditional expression is constant
andy@14 44
andy@11 45 struct xennet_info
andy@11 46 {
andy@11 47 PDEVICE_OBJECT pdo;
andy@11 48 PDEVICE_OBJECT fdo;
andy@11 49 PDEVICE_OBJECT lower_do;
andy@14 50 WDFDEVICE wdf_device;
andy@11 51
andy@11 52 WCHAR name[NAME_SIZE];
andy@11 53 NDIS_HANDLE adapter_handle;
andy@11 54 ULONG packet_filter;
andy@23 55 int connected;
andy@22 56 UINT8 perm_mac_addr[ETH_ALEN];
andy@22 57 UINT8 curr_mac_addr[ETH_ALEN];
andy@11 58
andy@11 59 char Path[128];
andy@11 60 char BackendPath[128];
andy@11 61 XEN_IFACE_EVTCHN EvtChnInterface;
andy@11 62 XEN_IFACE_XENBUS XenBusInterface;
andy@11 63 XEN_IFACE_XEN XenInterface;
andy@11 64 XEN_IFACE_GNTTBL GntTblInterface;
andy@11 65
andy@30 66 /* ring control structures */
andy@11 67 struct netif_tx_front_ring tx;
andy@11 68 struct netif_rx_front_ring rx;
andy@11 69
andy@30 70 /* ptrs to the actual rings themselvves */
andy@30 71 struct netif_tx_sring *tx_pgs;
andy@30 72 struct netif_rx_sring *rx_pgs;
andy@30 73
andy@30 74 /* MDLs for the above */
andy@14 75 PMDL tx_mdl;
andy@14 76 PMDL rx_mdl;
andy@30 77
andy@30 78 /* Outstanding packets. The first entry in tx_pkts
andy@30 79 * is an index into a chain of free entries. */
andy@30 80 PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE];
andy@30 81 PNDIS_PACKET rx_pkts[NET_RX_RING_SIZE];
andy@30 82
andy@30 83 grant_ref_t gref_tx_head;
andy@30 84 grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
andy@30 85 grant_ref_t gref_rx_head;
andy@30 86 grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
andy@11 87
andy@11 88 UINT irq;
andy@14 89 evtchn_port_t event_channel;
andy@11 90
andy@11 91 grant_ref_t tx_ring_ref;
andy@11 92 grant_ref_t rx_ring_ref;
andy@43 93
andy@43 94 /* Receive-ring batched refills. */
andy@43 95 #define RX_MIN_TARGET 8
andy@43 96 #define RX_DFL_MIN_TARGET 64
andy@43 97 #define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
andy@43 98 ULONG rx_target;
andy@43 99 ULONG rx_max_target;
andy@43 100 ULONG rx_min_target;
andy@43 101
andy@43 102 NDIS_HANDLE packet_pool;
andy@43 103 NDIS_HANDLE buffer_pool;
andy@11 104 };
andy@11 105
andy@11 106 /* need to do typedef so the DECLARE below works */
andy@11 107 typedef struct _wdf_device_info
andy@11 108 {
andy@11 109 struct xennet_info *xennet_info;
andy@11 110 } wdf_device_info;
andy@11 111
andy@11 112 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info, GetWdfDeviceInfo)
andy@11 113
andy@22 114 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
andy@22 115 static unsigned long
andy@22 116 simple_strtoul(const char *cp,char **endp,unsigned int base)
andy@22 117 {
andy@22 118 unsigned long result = 0,value;
andy@22 119
andy@22 120 if (!base) {
andy@22 121 base = 10;
andy@22 122 if (*cp == '0') {
andy@22 123 base = 8;
andy@22 124 cp++;
andy@22 125 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
andy@22 126 cp++;
andy@22 127 base = 16;
andy@22 128 }
andy@22 129 }
andy@22 130 } else if (base == 16) {
andy@22 131 if (cp[0] == '0' && toupper(cp[1]) == 'X')
andy@22 132 cp += 2;
andy@22 133 }
andy@22 134 while (isxdigit(*cp) &&
andy@22 135 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
andy@22 136 result = result*base + value;
andy@22 137 cp++;
andy@22 138 }
andy@22 139 if (endp)
andy@22 140 *endp = (char *)cp;
andy@22 141 return result;
andy@22 142 }
andy@22 143
andy@30 144 static void
andy@30 145 add_id_to_freelist(NDIS_PACKET **list, unsigned short id)
andy@30 146 {
andy@30 147 list[id] = list[0];
andy@30 148 list[0] = (void *)(unsigned long)id;
andy@30 149 }
andy@30 150
andy@30 151 static unsigned short
andy@30 152 get_id_from_freelist(NDIS_PACKET **list)
andy@30 153 {
andy@30 154 unsigned short id = (unsigned short)(unsigned long)list[0];
andy@30 155 list[0] = list[id];
andy@30 156 return id;
andy@30 157 }
andy@30 158
andy@11 159 static PMDL
andy@11 160 AllocatePages(int Pages)
andy@11 161 {
andy@11 162 PHYSICAL_ADDRESS Min;
andy@11 163 PHYSICAL_ADDRESS Max;
andy@11 164 PHYSICAL_ADDRESS Align;
andy@11 165 PMDL Mdl;
andy@11 166
andy@44 167 // KdPrint((__DRIVER_NAME " --> Allocate Pages\n"));
andy@11 168
andy@11 169 Min.QuadPart = 0;
andy@11 170 Max.QuadPart = 0xFFFFFFFF;
andy@11 171 Align.QuadPart = PAGE_SIZE;
andy@11 172
andy@11 173 Mdl = MmAllocatePagesForMdl(Min, Max, Align, Pages * PAGE_SIZE);
andy@11 174
andy@44 175 // KdPrint((__DRIVER_NAME " <-- Allocate Pages (mdl = %08x)\n", Mdl));
andy@11 176
andy@11 177 return Mdl;
andy@11 178 }
andy@11 179
andy@11 180 static PMDL
andy@11 181 AllocatePage()
andy@11 182 {
andy@11 183 return AllocatePages(1);
andy@11 184 }
andy@11 185
andy@30 186 static NDIS_STATUS
andy@43 187 XenNet_TxBufferGC(struct xennet_info *xi)
andy@30 188 {
andy@42 189 RING_IDX cons, prod;
andy@42 190
andy@30 191 unsigned short id;
andy@42 192 PNDIS_PACKET pkt;
andy@42 193 PMDL pmdl;
andy@30 194
andy@42 195 ASSERT(xi->connected);
andy@30 196
andy@30 197 do {
andy@42 198 prod = xi->tx.sring->rsp_prod;
andy@42 199 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
andy@30 200
andy@42 201 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
andy@30 202 struct netif_tx_response *txrsp;
andy@30 203
andy@42 204 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
andy@30 205 if (txrsp->status == NETIF_RSP_NULL)
andy@30 206 continue;
andy@30 207
andy@30 208 id = txrsp->id;
andy@42 209 pkt = xi->tx_pkts[id];
andy@42 210 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
andy@42 211 xi->grant_tx_ref[id]);
andy@42 212 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
andy@42 213 add_id_to_freelist(xi->tx_pkts, id);
andy@42 214
andy@43 215 /* free linearized data page */
andy@42 216 pmdl = *(PMDL *)pkt->MiniportReservedEx;
andy@42 217 MmFreePagesFromMdl(pmdl);
andy@42 218 IoFreeMdl(pmdl);
andy@42 219
andy@42 220 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
andy@30 221 }
andy@30 222
andy@42 223 xi->tx.rsp_cons = prod;
andy@30 224
andy@30 225 /*
andy@30 226 * Set a new event, then check for race with update of tx_cons.
andy@30 227 * Note that it is essential to schedule a callback, no matter
andy@30 228 * how few buffers are pending. Even if there is space in the
andy@30 229 * transmit ring, higher layers may be blocked because too much
andy@30 230 * data is outstanding: in such cases notification from Xen is
andy@30 231 * likely to be the only kick that we'll get.
andy@30 232 */
andy@42 233 xi->tx.sring->rsp_event =
andy@42 234 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
andy@30 235 mb();
andy@42 236 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
andy@30 237
andy@42 238 /* if queued packets, send them now?
andy@42 239 network_maybe_wake_tx(dev); */
andy@30 240
andy@30 241 return NDIS_STATUS_SUCCESS;
andy@30 242 }
andy@30 243
andy@43 244 static NDIS_STATUS
andy@43 245 XenNet_AllocRXBuffers(struct xennet_info *xi)
andy@43 246 {
andy@43 247 unsigned short id;
andy@43 248 PNDIS_PACKET packet;
andy@43 249 PNDIS_BUFFER buffer;
andy@43 250 int i, batch_target, notify;
andy@43 251 RING_IDX req_prod = xi->rx.req_prod_pvt;
andy@43 252 grant_ref_t ref;
andy@43 253 netif_rx_request_t *req;
andy@43 254 NDIS_STATUS status;
andy@43 255 PVOID start;
andy@43 256
andy@43 257 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
andy@43 258 for (i = 0; i < batch_target; i++)
andy@43 259 {
andy@43 260 /*
andy@43 261 * Allocate a packet, page, and buffer. Hook them up.
andy@43 262 */
andy@44 263 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
andy@44 264 if (status != NDIS_STATUS_SUCCESS)
andy@44 265 {
andy@44 266 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
andy@44 267 break;
andy@44 268 }
andy@44 269 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
andy@44 270 if (status != NDIS_STATUS_SUCCESS)
andy@44 271 {
andy@44 272 KdPrint(("NdisAllocateBuffer Failed! status = 0x%x\n", status));
andy@44 273 NdisFreeMemory(start, 0, 0);
andy@44 274 break;
andy@44 275 }
andy@43 276 NdisAllocatePacket(&status, &packet, xi->packet_pool);
andy@43 277 if (status != NDIS_STATUS_SUCCESS)
andy@43 278 {
andy@43 279 KdPrint(("NdisAllocatePacket Failed! status = 0x%x\n", status));
andy@44 280 NdisFreeMemory(start, 0, 0);
andy@44 281 NdisFreeBuffer(buffer);
andy@43 282 break;
andy@43 283 }
andy@43 284 NdisChainBufferAtBack(packet, buffer);
andy@43 285
andy@43 286 /* Give to netback */
andy@43 287 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
andy@43 288 ASSERT(!xi->rx_pkts[id]);
andy@43 289 xi->rx_pkts[id] = packet;
andy@43 290 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
andy@44 291 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
andy@43 292 ref = xi->GntTblInterface.GrantAccess(
andy@43 293 xi->GntTblInterface.InterfaceHeader.Context, 0,
andy@44 294 *MmGetMdlPfnArray(buffer), FALSE);
andy@43 295 ASSERT((signed short)ref >= 0);
andy@43 296 xi->grant_rx_ref[id] = ref;
andy@43 297
andy@43 298 req->id = id;
andy@43 299 req->gref = ref;
andy@43 300 }
andy@43 301
andy@43 302 xi->rx.req_prod_pvt = req_prod + i;
andy@43 303 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
andy@43 304 if (notify)
andy@43 305 {
andy@43 306 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
andy@43 307 xi->event_channel);
andy@43 308 }
andy@43 309
andy@43 310 return NDIS_STATUS_SUCCESS;
andy@43 311 }
andy@43 312
andy@43 313 static NDIS_STATUS
andy@43 314 XenNet_RxBufferCheck(struct xennet_info *xi)
andy@43 315 {
andy@43 316 RING_IDX cons, prod;
andy@43 317
andy@43 318 unsigned short id;
andy@43 319 PNDIS_PACKET pkt;
andy@43 320 PNDIS_PACKET packets[1];
andy@43 321 PNDIS_BUFFER buffer;
andy@43 322 PVOID buff_va;
andy@43 323 UINT buff_len;
andy@43 324 UINT tot_buff_len;
andy@43 325
andy@43 326 ASSERT(xi->connected);
andy@43 327
andy@43 328 do {
andy@43 329 prod = xi->rx.sring->rsp_prod;
andy@43 330 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
andy@43 331
andy@43 332 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
andy@43 333 struct netif_rx_response *rxrsp;
andy@43 334
andy@43 335 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
andy@43 336 if (rxrsp->status == NETIF_RSP_NULL)
andy@43 337 continue;
andy@43 338
andy@43 339 id = rxrsp->id;
andy@43 340 pkt = xi->rx_pkts[id];
andy@43 341 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
andy@43 342 xi->grant_rx_ref[id]);
andy@43 343 xi->grant_rx_ref[id] = GRANT_INVALID_REF;
andy@43 344 //add_id_to_freelist(xi->rx_pkts, id);
andy@43 345
andy@43 346 NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
andy@43 347 &tot_buff_len, NormalPagePriority);
andy@43 348 ASSERT(rxrsp->offset == 0);
andy@43 349 ASSERT(rxrsp->status > 0);
andy@43 350 NdisAdjustBufferLength(buffer, rxrsp->status);
andy@43 351 /* just indicate 1 packet for now */
andy@43 352 packets[0] = pkt;
andy@43 353
andy@43 354 NdisMIndicateReceivePacket(xi->adapter_handle, packets, 1);
andy@43 355 }
andy@43 356
andy@43 357 xi->rx.rsp_cons = prod;
andy@43 358
andy@43 359 /*
andy@43 360 * Set a new event, then check for race with update of rx_cons.
andy@43 361 * Note that it is essential to schedule a callback, no matter
andy@43 362 * how few buffers are pending. Even if there is space in the
andy@43 363 * transmit ring, higher layers may be blocked because too much
andy@43 364 * data is outstanding: in such cases notification from Xen is
andy@43 365 * likely to be the only kick that we'll get.
andy@43 366 */
andy@43 367 xi->rx.sring->rsp_event =
andy@43 368 prod + ((xi->rx.sring->req_prod - prod) >> 1) + 1;
andy@43 369 mb();
andy@43 370 } while ((cons == prod) && (prod != xi->rx.sring->rsp_prod));
andy@43 371
andy@43 372 /* if queued packets, send them now?
andy@43 373 network_maybe_wake_tx(dev); */
andy@43 374
andy@43 375 /* Give netback more buffers */
andy@43 376 XenNet_AllocRXBuffers(xi);
andy@43 377
andy@43 378 return NDIS_STATUS_SUCCESS;
andy@43 379 }
andy@43 380
andy@11 381 static BOOLEAN
andy@11 382 XenNet_Interrupt(
andy@11 383 PKINTERRUPT Interrupt,
andy@11 384 PVOID ServiceContext
andy@11 385 )
andy@11 386 {
andy@30 387 struct xennet_info *xi = ServiceContext;
andy@14 388 // KIRQL KIrql;
andy@14 389
andy@14 390 UNREFERENCED_PARAMETER(Interrupt);
andy@11 391
andy@32 392 KdPrint((__DRIVER_NAME " ***XenNet Interrupt***\n"));
andy@32 393
andy@30 394 if (xi->connected)
andy@30 395 {
andy@43 396 XenNet_TxBufferGC(xi);
andy@43 397 XenNet_RxBufferCheck(xi);
andy@30 398 }
andy@11 399 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
andy@11 400 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
andy@11 401 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
andy@11 402 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
andy@11 403 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
andy@11 404
andy@42 405 /* handle RX packets */
andy@11 406
andy@11 407 return TRUE;
andy@11 408 }
andy@11 409
andy@22 410 static VOID
andy@22 411 XenNet_BackEndStateHandler(char *Path, PVOID Data)
andy@22 412 {
andy@22 413 struct xennet_info *xi = Data;
andy@22 414 char *Value;
andy@22 415 int be_state;
andy@23 416 char TmpPath[128];
andy@23 417 xenbus_transaction_t xbt = 0;
andy@23 418 int retry = 0;
andy@23 419 char *err;
andy@32 420 int i;
andy@32 421
andy@32 422 struct set_params {
andy@32 423 char *name;
andy@32 424 int value;
andy@32 425 } params[] = {
andy@32 426 {"tx-ring-ref", 0},
andy@32 427 {"rx-ring-ref", 0},
andy@32 428 {"event-channel", 0},
andy@32 429 {"request-rx-copy", 1},
andy@32 430 {"feature-rx-notify", 1},
andy@32 431 {"feature-no-csum-offload", 1},
andy@32 432 {"feature-sg", 1},
andy@32 433 {"feature-gso-tcpv4", 0},
andy@32 434 {NULL, 0},
andy@32 435 };
andy@22 436
andy@22 437 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
andy@22 438 XBT_NIL, Path, &Value);
andy@22 439 be_state = atoi(Value);
andy@22 440 ExFreePool(Value);
andy@22 441
andy@22 442 switch (be_state)
andy@22 443 {
andy@22 444 case XenbusStateUnknown:
andy@22 445 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
andy@22 446 break;
andy@22 447
andy@22 448 case XenbusStateInitialising:
andy@22 449 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
andy@22 450 break;
andy@22 451
andy@22 452 case XenbusStateInitWait:
andy@22 453 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
andy@22 454
andy@23 455 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
andy@23 456 xi->EvtChnInterface.InterfaceHeader.Context, 0);
andy@23 457 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
andy@23 458 xi->event_channel, XenNet_Interrupt, xi);
andy@23 459
andy@23 460 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
andy@23 461 // or, allocate mem and then get mdl, then free mdl
andy@23 462 xi->tx_mdl = AllocatePage();
andy@23 463 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
andy@23 464 NULL, FALSE, NormalPagePriority);
andy@23 465 SHARED_RING_INIT(xi->tx_pgs);
andy@23 466 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
andy@23 467 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
andy@23 468 xi->GntTblInterface.InterfaceHeader.Context, 0,
andy@23 469 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
andy@23 470
andy@23 471 xi->rx_mdl = AllocatePage();
andy@23 472 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
andy@23 473 NULL, FALSE, NormalPagePriority);
andy@23 474 SHARED_RING_INIT(xi->rx_pgs);
andy@23 475 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
andy@23 476 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
andy@23 477 xi->GntTblInterface.InterfaceHeader.Context, 0,
andy@23 478 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
andy@23 479
andy@32 480 /* fixup array for dynamic values */
andy@32 481 params[0].value = xi->tx_ring_ref;
andy@32 482 params[1].value = xi->rx_ring_ref;
andy@32 483 params[2].value = xi->event_channel;
andy@23 484
andy@32 485 xi->XenBusInterface.StartTransaction(
andy@32 486 xi->XenBusInterface.InterfaceHeader.Context, &xbt);
andy@23 487
andy@32 488 for (i = 0; params[i].name; i++)
andy@32 489 {
andy@32 490 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
andy@32 491 xi->Path, params[i].name);
andy@32 492 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
andy@32 493 XBT_NIL, TmpPath, "%d", params[i].value);
andy@32 494 if (err)
andy@32 495 {
andy@32 496 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
andy@32 497 goto trouble;
andy@32 498 }
andy@32 499 }
andy@23 500
andy@23 501 /* commit transaction */
andy@23 502 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
andy@23 503 xbt, 0, &retry);
andy@23 504
andy@43 505 XenNet_AllocRXBuffers(xi);
andy@22 506
andy@33 507 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
andy@23 508 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
andy@23 509 xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
andy@33 510 XBT_NIL, TmpPath, "%d", XenbusStateConnected);
andy@23 511
andy@23 512 /* send fake arp? */
andy@23 513
andy@23 514 xi->connected = TRUE;
andy@23 515
andy@22 516 break;
andy@22 517
andy@22 518 case XenbusStateInitialised:
andy@22 519 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
andy@22 520 // create the device
andy@22 521 break;
andy@22 522
andy@22 523 case XenbusStateConnected:
andy@22 524 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
andy@22 525
andy@22 526 /* do more stuff here */
andy@22 527
andy@22 528 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
andy@22 529 break;
andy@22 530
andy@22 531 case XenbusStateClosing:
andy@22 532 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
andy@22 533 break;
andy@22 534
andy@22 535 case XenbusStateClosed:
andy@22 536 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
andy@22 537 break;
andy@22 538
andy@22 539 default:
andy@22 540 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", be_state));
andy@22 541 break;
andy@22 542 }
andy@22 543
andy@32 544 return;
andy@32 545
andy@23 546 trouble:
andy@23 547 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
andy@23 548 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
andy@23 549 xbt, 1, &retry);
andy@23 550
andy@22 551 }
andy@22 552
andy@11 553 VOID
andy@11 554 XenNet_Halt(
andy@11 555 IN NDIS_HANDLE MiniportAdapterContext
andy@11 556 )
andy@11 557 {
andy@14 558 UNREFERENCED_PARAMETER(MiniportAdapterContext);
andy@11 559 }
andy@11 560
andy@11 561 static NDIS_STATUS
andy@11 562 XenNet_Init(
andy@11 563 OUT PNDIS_STATUS OpenErrorStatus,
andy@11 564 OUT PUINT SelectedMediumIndex,
andy@11 565 IN PNDIS_MEDIUM MediumArray,
andy@11 566 IN UINT MediumArraySize,
andy@11 567 IN NDIS_HANDLE MiniportAdapterHandle,
andy@11 568 IN NDIS_HANDLE WrapperConfigurationContext
andy@11 569 )
andy@11 570 {
andy@11 571 NDIS_STATUS status;
andy@11 572 UINT i;
andy@11 573 BOOLEAN medium_found = FALSE;
andy@11 574 struct xennet_info *xi = NULL;
andy@14 575 ULONG length;
andy@11 576 WDF_OBJECT_ATTRIBUTES wdf_attrs;
andy@21 577 char *msg;
andy@21 578 char *Value;
andy@21 579 char **vif_devs;
andy@21 580 char TmpPath[128];
andy@14 581
andy@14 582 UNREFERENCED_PARAMETER(OpenErrorStatus);
andy@14 583 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
andy@11 584
andy@11 585 /* deal with medium stuff */
andy@11 586 for (i = 0; i < MediumArraySize; i++)
andy@11 587 {
andy@11 588 if (MediumArray[i] == NdisMedium802_3)
andy@11 589 {
andy@11 590 medium_found = TRUE;
andy@11 591 break;
andy@11 592 }
andy@11 593 }
andy@11 594 if (!medium_found)
andy@11 595 {
andy@11 596 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
andy@11 597 return NDIS_STATUS_UNSUPPORTED_MEDIA;
andy@11 598 }
andy@11 599 *SelectedMediumIndex = i;
andy@11 600
andy@11 601 /* Alloc memory for adapter private info */
andy@11 602 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
andy@11 603 if (!NT_SUCCESS(status))
andy@11 604 {
andy@11 605 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
andy@11 606 status = NDIS_STATUS_RESOURCES;
andy@11 607 goto err;
andy@11 608 }
andy@11 609 RtlZeroMemory(xi, sizeof(*xi));
andy@11 610
andy@11 611 /* init xennet_info */
andy@11 612 xi->adapter_handle = MiniportAdapterHandle;
andy@43 613 xi->rx_target = RX_DFL_MIN_TARGET;
andy@43 614 xi->rx_min_target = RX_DFL_MIN_TARGET;
andy@43 615 xi->rx_max_target = RX_MAX_TARGET;
andy@43 616
andy@43 617 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
andy@43 618 PROTOCOL_RESERVED_SIZE_IN_PACKET);
andy@43 619 if (status != NDIS_STATUS_SUCCESS)
andy@43 620 {
andy@43 621 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
andy@43 622 status = NDIS_STATUS_RESOURCES;
andy@43 623 goto err;
andy@43 624 }
andy@43 625
andy@43 626 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
andy@43 627 if (status != NDIS_STATUS_SUCCESS)
andy@43 628 {
andy@43 629 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
andy@43 630 status = NDIS_STATUS_RESOURCES;
andy@43 631 goto err;
andy@43 632 }
andy@43 633
andy@11 634 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
andy@11 635 &xi->lower_do, NULL, NULL);
andy@11 636
andy@30 637 /* Initialise {tx,rx}_pkts as a free chain containing every entry. */
andy@30 638 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
andy@30 639 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
andy@30 640 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
andy@30 641 }
andy@30 642
andy@30 643 for (i = 0; i < NET_RX_RING_SIZE; i++) {
andy@30 644 xi->rx_pkts[i] = NULL;
andy@30 645 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
andy@30 646 }
andy@30 647
andy@11 648 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
andy@11 649 NAME_SIZE, xi->name, &length);
andy@11 650 if (!NT_SUCCESS(status))
andy@11 651 {
andy@11 652 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
andy@11 653 status = NDIS_STATUS_FAILURE;
andy@11 654 goto err;
andy@11 655 }
andy@11 656
andy@11 657 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
andy@32 658 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
andy@32 659 NdisInterfaceInternal);
andy@32 660
andy@32 661 // status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE,
andy@32 662 // XN_MAX_PKT_SIZE);
andy@32 663 // if (!NT_SUCCESS(status))
andy@32 664 // {
andy@32 665 // KdPrint(("NdisMInitializeScatterGatherDma failed with 0x%x\n", status));
andy@32 666 // status = NDIS_STATUS_FAILURE;
andy@32 667 // goto err;
andy@32 668 // }
andy@11 669
andy@11 670 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&wdf_attrs, wdf_device_info);
andy@11 671
andy@11 672 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
andy@11 673 xi->lower_do, xi->pdo, &xi->wdf_device);
andy@11 674 if (!NT_SUCCESS(status))
andy@11 675 {
andy@11 676 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
andy@11 677 status = NDIS_STATUS_FAILURE;
andy@11 678 goto err;
andy@11 679 }
andy@30 680
andy@11 681 GetWdfDeviceInfo(xi->wdf_device)->xennet_info = xi;
andy@11 682
andy@11 683 /* get lower (Xen) interfaces */
andy@11 684
andy@11 685 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
andy@11 686 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
andy@11 687 if(!NT_SUCCESS(status))
andy@11 688 {
andy@11 689 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
andy@11 690 status = NDIS_STATUS_FAILURE;
andy@11 691 goto err;
andy@11 692 }
andy@11 693
andy@11 694 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
andy@11 695 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
andy@11 696 if(!NT_SUCCESS(status))
andy@11 697 {
andy@11 698 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
andy@11 699 status = NDIS_STATUS_FAILURE;
andy@11 700 goto err;
andy@11 701 }
andy@11 702
andy@13 703 #if 0
andy@11 704 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
andy@11 705 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
andy@11 706 if(!NT_SUCCESS(status))
andy@11 707 {
andy@11 708 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
andy@11 709 status = NDIS_STATUS_FAILURE;
andy@11 710 goto err;
andy@11 711 }
andy@13 712 #endif
andy@11 713
andy@11 714 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
andy@11 715 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
andy@11 716 if(!NT_SUCCESS(status))
andy@11 717 {
andy@11 718 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
andy@11 719 status = NDIS_STATUS_FAILURE;
andy@11 720 goto err;
andy@11 721 }
andy@11 722
andy@13 723 msg = xi->XenBusInterface.List(xi->EvtChnInterface.InterfaceHeader.Context,
andy@13 724 XBT_NIL, "device/vif", &vif_devs);
andy@21 725 if (msg)
andy@11 726 {
andy@21 727 KdPrint((__DRIVER_NAME ": " __FUNCTION__ ": List retval is nonzero!\n"));
andy@21 728 status = NDIS_STATUS_FAILURE;
andy@21 729 goto err;
andy@21 730 }
andy@21 731
andy@21 732 for (i = 0; vif_devs[i]; i++)
andy@21 733 {
andy@21 734 if (i > 0)
andy@11 735 {
andy@21 736 KdPrint((__DRIVER_NAME "Can only handle 1 vif so far, ignoring vif %s\n", vif_devs[i]));
andy@21 737 continue;
andy@11 738 }
andy@21 739 RtlStringCbPrintfA(xi->Path, ARRAY_SIZE(xi->Path), "device/vif/%s", vif_devs[i]);
andy@21 740
andy@21 741 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
andy@21 742 "device/vif/%s/state", vif_devs[i]);
andy@21 743 KdPrint(("%s\n", TmpPath));
andy@21 744
andy@21 745 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/backend", xi->Path);
andy@21 746 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
andy@21 747 XBT_NIL, TmpPath, &Value);
andy@21 748 if (!Value)
andy@21 749 {
andy@22 750 KdPrint((__DRIVER_NAME " backend Read Failed\n"));
andy@21 751 }
andy@21 752 else
andy@21 753 {
andy@21 754 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
andy@21 755 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
andy@21 756 }
andy@21 757 ExFreePool(Value);
andy@21 758
andy@22 759 /* Add watch on backend state */
andy@23 760 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
andy@22 761 xi->XenBusInterface.AddWatch(xi->XenBusInterface.InterfaceHeader.Context,
andy@22 762 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
andy@22 763
andy@22 764 /* get mac address */
andy@22 765 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->Path);
andy@22 766 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
andy@22 767 XBT_NIL, TmpPath, &Value);
andy@22 768 if (!Value)
andy@22 769 {
andy@22 770 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
andy@22 771 }
andy@22 772 else
andy@22 773 {
andy@22 774 char *s, *e;
andy@22 775 int i;
andy@22 776
andy@22 777 s = Value;
andy@22 778
andy@22 779 for (i = 0; i < ETH_ALEN; i++) {
andy@22 780 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
andy@22 781 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
andy@22 782 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
andy@22 783 ExFreePool(Value);
andy@22 784 ExFreePool(vif_devs);
andy@22 785 status = NDIS_STATUS_FAILURE;
andy@22 786 goto err;
andy@22 787 }
andy@22 788 s = e + 1;
andy@22 789 }
andy@23 790 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
andy@22 791 }
andy@22 792 ExFreePool(Value);
andy@22 793
andy@21 794 //XenVbd_HotPlugHandler(buffer, NULL);
andy@21 795 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
andy@11 796 }
andy@21 797 ExFreePool(vif_devs);
andy@11 798
andy@11 799 return NDIS_STATUS_SUCCESS;
andy@11 800
andy@11 801 err:
andy@11 802 NdisFreeMemory(xi, 0, 0);
andy@11 803 return status;
andy@11 804 }
andy@11 805
andy@11 806 NDIS_OID supported_oids[] =
andy@11 807 {
andy@11 808 OID_GEN_SUPPORTED_LIST,
andy@11 809 OID_GEN_HARDWARE_STATUS,
andy@11 810 OID_GEN_MEDIA_SUPPORTED,
andy@11 811 OID_GEN_MEDIA_IN_USE,
andy@11 812 OID_GEN_MAXIMUM_LOOKAHEAD,
andy@11 813 OID_GEN_MAXIMUM_FRAME_SIZE,
andy@11 814 OID_GEN_LINK_SPEED,
andy@11 815 OID_GEN_TRANSMIT_BUFFER_SPACE,
andy@11 816 OID_GEN_RECEIVE_BUFFER_SPACE,
andy@11 817 OID_GEN_TRANSMIT_BLOCK_SIZE,
andy@11 818 OID_GEN_RECEIVE_BLOCK_SIZE,
andy@11 819 OID_GEN_VENDOR_ID,
andy@11 820 OID_GEN_VENDOR_DESCRIPTION,
andy@11 821 OID_GEN_CURRENT_PACKET_FILTER,
andy@11 822 OID_GEN_CURRENT_LOOKAHEAD,
andy@11 823 OID_GEN_DRIVER_VERSION,
andy@11 824 OID_GEN_MAXIMUM_TOTAL_SIZE,
andy@11 825 OID_GEN_MAC_OPTIONS,
andy@11 826 OID_GEN_MEDIA_CONNECT_STATUS,
andy@11 827 OID_GEN_MAXIMUM_SEND_PACKETS,
andy@11 828 OID_802_3_PERMANENT_ADDRESS,
andy@11 829 OID_802_3_CURRENT_ADDRESS,
andy@11 830 OID_802_3_MULTICAST_LIST,
andy@11 831 OID_802_3_MAXIMUM_LIST_SIZE,
andy@11 832 };
andy@11 833
andy@11 834 NDIS_STATUS
andy@11 835 XenNet_QueryInformation(
andy@11 836 IN NDIS_HANDLE MiniportAdapterContext,
andy@11 837 IN NDIS_OID Oid,
andy@11 838 IN PVOID InformationBuffer,
andy@11 839 IN ULONG InformationBufferLength,
andy@11 840 OUT PULONG BytesWritten,
andy@11 841 OUT PULONG BytesNeeded)
andy@11 842 {
andy@11 843 struct xennet_info *xi = MiniportAdapterContext;
andy@11 844 UCHAR vendor_desc[] = XN_VENDOR_DESC;
andy@11 845 ULONG temp_data;
andy@11 846 PVOID data = &temp_data;
andy@11 847 UINT len = sizeof(temp_data);
andy@11 848 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
andy@11 849
andy@11 850 switch(Oid)
andy@11 851 {
andy@11 852 case OID_GEN_SUPPORTED_LIST:
andy@11 853 data = supported_oids;
andy@11 854 len = sizeof(supported_oids);
andy@11 855 break;
andy@11 856 case OID_GEN_HARDWARE_STATUS:
andy@11 857 temp_data = NdisHardwareStatusReady;
andy@11 858 break;
andy@11 859 case OID_GEN_MEDIA_SUPPORTED:
andy@11 860 temp_data = NdisMedium802_3;
andy@11 861 break;
andy@11 862 case OID_GEN_MEDIA_IN_USE:
andy@11 863 temp_data = NdisMedium802_3;
andy@11 864 break;
andy@11 865 case OID_GEN_MAXIMUM_LOOKAHEAD:
andy@11 866 temp_data = XN_DATA_SIZE;
andy@11 867 break;
andy@11 868 case OID_GEN_MAXIMUM_FRAME_SIZE:
andy@11 869 temp_data = XN_MAX_PKT_SIZE;
andy@11 870 break;
andy@11 871 case OID_GEN_LINK_SPEED:
andy@11 872 temp_data = 10000000; /* 1Gb */
andy@11 873 break;
andy@11 874 case OID_GEN_TRANSMIT_BUFFER_SPACE:
andy@11 875 /* pkts times sizeof ring, maybe? */
andy@11 876 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
andy@11 877 break;
andy@11 878 case OID_GEN_RECEIVE_BUFFER_SPACE:
andy@11 879 /* pkts times sizeof ring, maybe? */
andy@11 880 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
andy@11 881 break;
andy@11 882 case OID_GEN_TRANSMIT_BLOCK_SIZE:
andy@11 883 temp_data = XN_MAX_PKT_SIZE;
andy@11 884 break;
andy@11 885 case OID_GEN_RECEIVE_BLOCK_SIZE:
andy@11 886 temp_data = XN_MAX_PKT_SIZE;
andy@11 887 break;
andy@11 888 case OID_GEN_VENDOR_ID:
andy@11 889 temp_data = XENSOURCE_MAC_HDR;
andy@11 890 break;
andy@11 891 case OID_GEN_VENDOR_DESCRIPTION:
andy@11 892 data = vendor_desc;
andy@11 893 len = sizeof(vendor_desc);
andy@11 894 break;
andy@11 895 case OID_GEN_CURRENT_PACKET_FILTER:
andy@11 896 temp_data = xi->packet_filter;
andy@11 897 break;
andy@11 898 case OID_GEN_CURRENT_LOOKAHEAD:
andy@11 899 temp_data = XN_MAX_PKT_SIZE;
andy@11 900 break;
andy@11 901 case OID_GEN_DRIVER_VERSION:
andy@11 902 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
andy@11 903 len = 2;
andy@11 904 break;
andy@11 905 case OID_GEN_MAXIMUM_TOTAL_SIZE:
andy@11 906 temp_data = XN_MAX_PKT_SIZE;
andy@11 907 break;
andy@11 908 case OID_GEN_MAC_OPTIONS:
andy@11 909 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
andy@11 910 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
andy@11 911 NDIS_MAC_OPTION_NO_LOOPBACK;
andy@11 912 break;
andy@11 913 case OID_GEN_MEDIA_CONNECT_STATUS:
andy@23 914 if (xi->connected)
andy@23 915 temp_data = NdisMediaStateConnected;
andy@23 916 else
andy@23 917 temp_data = NdisMediaStateDisconnected;
andy@11 918 break;
andy@11 919 case OID_GEN_MAXIMUM_SEND_PACKETS:
andy@11 920 temp_data = XN_MAX_SEND_PKTS;
andy@11 921 break;
andy@11 922 case OID_802_3_PERMANENT_ADDRESS:
andy@11 923 data = xi->perm_mac_addr;
andy@11 924 len = ETH_ALEN;
andy@11 925 break;
andy@11 926 case OID_802_3_CURRENT_ADDRESS:
andy@11 927 data = xi->curr_mac_addr;
andy@11 928 len = ETH_ALEN;
andy@11 929 break;
andy@11 930 case OID_802_3_MULTICAST_LIST:
andy@11 931 data = NULL;
andy@11 932 len = 0;
andy@11 933 case OID_802_3_MAXIMUM_LIST_SIZE:
andy@11 934 temp_data = 0; /* no mcast support */
andy@11 935 break;
andy@11 936 default:
andy@33 937 //KdPrint(("Unknown OID 0x%x\n", Oid));
andy@11 938 status = NDIS_STATUS_NOT_SUPPORTED;
andy@11 939 }
andy@11 940
andy@11 941 if (!NT_SUCCESS(status))
andy@11 942 {
andy@11 943 return status;
andy@11 944 }
andy@11 945
andy@11 946 if (len > InformationBufferLength)
andy@11 947 {
andy@11 948 *BytesNeeded = len;
andy@11 949 return NDIS_STATUS_BUFFER_TOO_SHORT;
andy@11 950 }
andy@11 951
andy@11 952 *BytesWritten = len;
andy@11 953 if (len)
andy@11 954 {
andy@11 955 NdisMoveMemory(InformationBuffer, data, len);
andy@11 956 }
andy@11 957
andy@11 958 KdPrint(("Got OID 0x%x\n", Oid));
andy@11 959
andy@11 960 return status;
andy@11 961 }
andy@11 962
andy@11 963 NDIS_STATUS
andy@11 964 XenNet_SetInformation(
andy@11 965 IN NDIS_HANDLE MiniportAdapterContext,
andy@11 966 IN NDIS_OID Oid,
andy@11 967 IN PVOID InformationBuffer,
andy@11 968 IN ULONG InformationBufferLength,
andy@11 969 OUT PULONG BytesRead,
andy@11 970 OUT PULONG BytesNeeded
andy@11 971 )
andy@11 972 {
andy@14 973 UNREFERENCED_PARAMETER(MiniportAdapterContext);
andy@14 974 UNREFERENCED_PARAMETER(Oid);
andy@14 975 UNREFERENCED_PARAMETER(InformationBuffer);
andy@14 976 UNREFERENCED_PARAMETER(InformationBufferLength);
andy@14 977 UNREFERENCED_PARAMETER(BytesRead);
andy@14 978 UNREFERENCED_PARAMETER(BytesNeeded);
andy@14 979
andy@13 980 KdPrint((__FUNCTION__ " called with OID=0x%x\n", Oid));
andy@11 981 return NDIS_STATUS_SUCCESS;
andy@11 982 }
andy@11 983
andy@11 984 VOID
andy@11 985 XenNet_ReturnPacket(
andy@11 986 IN NDIS_HANDLE MiniportAdapterContext,
andy@11 987 IN PNDIS_PACKET Packet
andy@11 988 )
andy@11 989 {
andy@44 990 PNDIS_BUFFER buffer;
andy@44 991 PVOID buff_va;
andy@44 992 UINT buff_len;
andy@44 993 UINT tot_buff_len;
andy@43 994
andy@44 995 UNREFERENCED_PARAMETER(MiniportAdapterContext);
andy@44 996
andy@44 997 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
andy@44 998 &tot_buff_len, NormalPagePriority);
andy@44 999 ASSERT(buff_len == tot_buff_len);
andy@44 1000
andy@44 1001 NdisFreeMemory(buff_va, 0, 0);
andy@44 1002 NdisFreeBuffer(buffer);
andy@44 1003 NdisFreePacket(Packet);
andy@14 1004
andy@11 1005 KdPrint((__FUNCTION__ " called\n"));
andy@11 1006 }
andy@11 1007
andy@32 1008 PMDL
andy@32 1009 XenNet_Linearize(PNDIS_PACKET Packet)
andy@32 1010 {
andy@32 1011 PMDL pmdl;
andy@32 1012 char *start;
andy@32 1013 PNDIS_BUFFER buffer;
andy@32 1014 PVOID buff_va;
andy@32 1015 UINT buff_len;
andy@32 1016 UINT tot_buff_len;
andy@32 1017
andy@32 1018 pmdl = AllocatePage();
andy@32 1019
andy@32 1020 start = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
andy@32 1021 if (!start)
andy@32 1022 {
andy@32 1023 return NULL;
andy@32 1024 }
andy@32 1025
andy@32 1026 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
andy@32 1027 &tot_buff_len, NormalPagePriority);
andy@32 1028 ASSERT(tot_buff_len <= PAGE_SIZE);
andy@32 1029
andy@32 1030 while (buffer)
andy@32 1031 {
andy@32 1032 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
andy@32 1033 RtlCopyMemory(start, buff_va, buff_len);
andy@32 1034 start += buff_len;
andy@32 1035 NdisGetNextBuffer(buffer, &buffer);
andy@32 1036 }
andy@32 1037
andy@32 1038 return pmdl;
andy@32 1039 }
andy@32 1040
andy@11 1041 VOID
andy@11 1042 XenNet_SendPackets(
andy@11 1043 IN NDIS_HANDLE MiniportAdapterContext,
andy@11 1044 IN PPNDIS_PACKET PacketArray,
andy@11 1045 IN UINT NumberOfPackets
andy@11 1046 )
andy@11 1047 {
andy@11 1048 /* for each packet:
andy@11 1049 req_prod_pvt is the next entry in the cmd ring to use
andy@11 1050 add pkt to array of saved packets
andy@11 1051 fill out tx request for the first part of skb
andy@11 1052 add to grant table
andy@11 1053 do flags for csum etc
andy@11 1054 gso (later)
andy@11 1055 inc req_prod_pvt
andy@11 1056 frags
andy@11 1057 possibly notify
andy@11 1058 network_tx)buf_gc
andy@11 1059 stop netif if no more room
andy@11 1060 */
andy@11 1061 struct xennet_info *xi = MiniportAdapterContext;
andy@11 1062 PNDIS_PACKET curr_packet;
andy@11 1063 UINT i;
andy@30 1064 struct netif_tx_request *tx;
andy@30 1065 unsigned short id;
andy@32 1066 int notify;
andy@32 1067 PMDL pmdl;
andy@32 1068 UINT pkt_size;
andy@11 1069
andy@30 1070 KdPrint((__FUNCTION__ " called, sending %d pkts\n", NumberOfPackets));
andy@11 1071
andy@11 1072 for (i = 0; i < NumberOfPackets; i++)
andy@11 1073 {
andy@11 1074 curr_packet = PacketArray[i];
andy@11 1075 ASSERT(curr_packet);
andy@11 1076
andy@32 1077 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
andy@30 1078
andy@32 1079 pmdl = XenNet_Linearize(curr_packet);
andy@32 1080 if (!pmdl)
andy@32 1081 {
andy@32 1082 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
andy@32 1083 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
andy@32 1084 break;
andy@32 1085 }
andy@44 1086 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
andy@30 1087
andy@32 1088 id = get_id_from_freelist(xi->tx_pkts);
andy@32 1089 xi->tx_pkts[id] = curr_packet;
andy@30 1090
andy@32 1091 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
andy@32 1092 tx->id = id;
andy@32 1093 tx->gref = xi->GntTblInterface.GrantAccess(
andy@32 1094 xi->GntTblInterface.InterfaceHeader.Context,
andy@32 1095 0,
andy@44 1096 *MmGetMdlPfnArray(pmdl),
andy@32 1097 TRUE);
andy@42 1098 xi->grant_tx_ref[id] = tx->gref;
andy@32 1099 tx->offset = 0;
andy@32 1100 tx->size = (UINT16)pkt_size;
andy@32 1101 tx->flags = NETTXF_csum_blank;
andy@30 1102
andy@32 1103 xi->tx.req_prod_pvt++;
andy@32 1104
andy@32 1105 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
andy@32 1106 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
andy@11 1107 }
andy@11 1108
andy@32 1109 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
andy@32 1110 if (notify)
andy@32 1111 {
andy@32 1112 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
andy@32 1113 xi->event_channel);
andy@32 1114 }
andy@11 1115 }
andy@11 1116
andy@11 1117 VOID
andy@11 1118 XenNet_PnPEventNotify(
andy@11 1119 IN NDIS_HANDLE MiniportAdapterContext,
andy@11 1120 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
andy@11 1121 IN PVOID InformationBuffer,
andy@11 1122 IN ULONG InformationBufferLength
andy@11 1123 )
andy@11 1124 {
andy@14 1125 UNREFERENCED_PARAMETER(MiniportAdapterContext);
andy@14 1126 UNREFERENCED_PARAMETER(PnPEvent);
andy@14 1127 UNREFERENCED_PARAMETER(InformationBuffer);
andy@14 1128 UNREFERENCED_PARAMETER(InformationBufferLength);
andy@14 1129
andy@11 1130 KdPrint((__FUNCTION__ " called\n"));
andy@11 1131 }
andy@11 1132
andy@11 1133 VOID
andy@11 1134 XenNet_Shutdown(
andy@11 1135 IN NDIS_HANDLE MiniportAdapterContext
andy@11 1136 )
andy@11 1137 {
andy@14 1138 UNREFERENCED_PARAMETER(MiniportAdapterContext);
andy@14 1139
andy@11 1140 KdPrint((__FUNCTION__ " called\n"));
andy@11 1141 }
andy@11 1142
andy@11 1143 NTSTATUS
andy@11 1144 DriverEntry(
andy@11 1145 PDRIVER_OBJECT DriverObject,
andy@11 1146 PUNICODE_STRING RegistryPath
andy@11 1147 )
andy@11 1148 {
andy@11 1149 NTSTATUS status;
andy@11 1150 WDF_DRIVER_CONFIG config;
andy@11 1151 NDIS_HANDLE ndis_wrapper_handle;
andy@11 1152 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
andy@11 1153
andy@11 1154 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
andy@11 1155
andy@11 1156 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
andy@11 1157 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
andy@11 1158
andy@11 1159 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
andy@11 1160 &config, WDF_NO_HANDLE);
andy@11 1161 if (!NT_SUCCESS(status))
andy@11 1162 {
andy@11 1163 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
andy@11 1164 return status;
andy@11 1165 }
andy@11 1166
andy@11 1167 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
andy@11 1168 if (!ndis_wrapper_handle)
andy@11 1169 {
andy@11 1170 KdPrint(("NdisMInitializeWrapper failed\n"));
andy@11 1171 return NDIS_STATUS_FAILURE;
andy@11 1172 }
andy@11 1173
andy@11 1174 /* NDIS 5.1 driver */
andy@11 1175 mini_chars.MajorNdisVersion = 5;
andy@11 1176 mini_chars.MinorNdisVersion = 1;
andy@11 1177
andy@11 1178 mini_chars.HaltHandler = XenNet_Halt;
andy@11 1179 mini_chars.InitializeHandler = XenNet_Init;
andy@11 1180 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
andy@11 1181 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
andy@11 1182 mini_chars.ResetHandler = NULL; //TODO: fill in
andy@11 1183 mini_chars.SetInformationHandler = XenNet_SetInformation;
andy@11 1184 /* added in v.4 -- use multiple pkts interface */
andy@11 1185 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
andy@11 1186 mini_chars.SendPacketsHandler = XenNet_SendPackets;
andy@11 1187 /* added in v.5.1 */
andy@11 1188 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
andy@11 1189 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
andy@11 1190
andy@11 1191 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
andy@11 1192
andy@11 1193 /* set up upper-edge interface */
andy@11 1194 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
andy@11 1195 if (!NT_SUCCESS(status))
andy@11 1196 {
andy@11 1197 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
andy@11 1198 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
andy@11 1199 return status;
andy@11 1200 }
andy@11 1201
andy@11 1202 return status;
andy@11 1203 }