win-pvdrivers

view xennet/xennet.c @ 45:cc2c13724f45

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