win-pvdrivers

view xennet/xennet.c @ 42:5dc3e004cf94

xennet: implement tx ring cleanup on xen interrupt
author Andy Grover <andy.grover@oracle.com>
date Wed Dec 05 14:56:01 2007 -0800 (2007-12-05)
parents b0870e38eaab
children 59691f2a99f6
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;
93 };
95 /* need to do typedef so the DECLARE below works */
96 typedef struct _wdf_device_info
97 {
98 struct xennet_info *xennet_info;
99 } wdf_device_info;
101 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info, GetWdfDeviceInfo)
103 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
104 static unsigned long
105 simple_strtoul(const char *cp,char **endp,unsigned int base)
106 {
107 unsigned long result = 0,value;
109 if (!base) {
110 base = 10;
111 if (*cp == '0') {
112 base = 8;
113 cp++;
114 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
115 cp++;
116 base = 16;
117 }
118 }
119 } else if (base == 16) {
120 if (cp[0] == '0' && toupper(cp[1]) == 'X')
121 cp += 2;
122 }
123 while (isxdigit(*cp) &&
124 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
125 result = result*base + value;
126 cp++;
127 }
128 if (endp)
129 *endp = (char *)cp;
130 return result;
131 }
133 static void
134 add_id_to_freelist(NDIS_PACKET **list, unsigned short id)
135 {
136 list[id] = list[0];
137 list[0] = (void *)(unsigned long)id;
138 }
140 static unsigned short
141 get_id_from_freelist(NDIS_PACKET **list)
142 {
143 unsigned short id = (unsigned short)(unsigned long)list[0];
144 list[0] = list[id];
145 return id;
146 }
148 static PMDL
149 AllocatePages(int Pages)
150 {
151 PHYSICAL_ADDRESS Min;
152 PHYSICAL_ADDRESS Max;
153 PHYSICAL_ADDRESS Align;
154 PMDL Mdl;
156 KdPrint((__DRIVER_NAME " --> Allocate Pages\n"));
158 Min.QuadPart = 0;
159 Max.QuadPart = 0xFFFFFFFF;
160 Align.QuadPart = PAGE_SIZE;
162 Mdl = MmAllocatePagesForMdl(Min, Max, Align, Pages * PAGE_SIZE);
164 KdPrint((__DRIVER_NAME " <-- Allocate Pages (mdl = %08x)\n", Mdl));
166 return Mdl;
167 }
169 static PMDL
170 AllocatePage()
171 {
172 return AllocatePages(1);
173 }
175 static NDIS_STATUS
176 XenNet_TxBufGC(struct xennet_info *xi)
177 {
178 RING_IDX cons, prod;
180 unsigned short id;
181 PNDIS_PACKET pkt;
182 PMDL pmdl;
184 ASSERT(xi->connected);
186 do {
187 prod = xi->tx.sring->rsp_prod;
188 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
190 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
191 struct netif_tx_response *txrsp;
193 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
194 if (txrsp->status == NETIF_RSP_NULL)
195 continue;
197 id = txrsp->id;
198 pkt = xi->tx_pkts[id];
199 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
200 xi->grant_tx_ref[id]);
201 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
202 add_id_to_freelist(xi->tx_pkts, id);
204 /* free page for linearized data */
205 pmdl = *(PMDL *)pkt->MiniportReservedEx;
206 MmFreePagesFromMdl(pmdl);
207 IoFreeMdl(pmdl);
209 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
210 }
212 xi->tx.rsp_cons = prod;
214 /*
215 * Set a new event, then check for race with update of tx_cons.
216 * Note that it is essential to schedule a callback, no matter
217 * how few buffers are pending. Even if there is space in the
218 * transmit ring, higher layers may be blocked because too much
219 * data is outstanding: in such cases notification from Xen is
220 * likely to be the only kick that we'll get.
221 */
222 xi->tx.sring->rsp_event =
223 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
224 mb();
225 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
227 /* if queued packets, send them now?
228 network_maybe_wake_tx(dev); */
230 return NDIS_STATUS_SUCCESS;
231 }
233 static BOOLEAN
234 XenNet_Interrupt(
235 PKINTERRUPT Interrupt,
236 PVOID ServiceContext
237 )
238 {
239 struct xennet_info *xi = ServiceContext;
240 // KIRQL KIrql;
242 UNREFERENCED_PARAMETER(Interrupt);
244 KdPrint((__DRIVER_NAME " ***XenNet Interrupt***\n"));
246 if (xi->connected)
247 {
248 XenNet_TxBufGC(xi);
249 }
250 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
251 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
252 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
253 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
254 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
256 /* handle RX packets */
258 return TRUE;
259 }
261 static VOID
262 XenNet_BackEndStateHandler(char *Path, PVOID Data)
263 {
264 struct xennet_info *xi = Data;
265 char *Value;
266 int be_state;
267 char TmpPath[128];
268 xenbus_transaction_t xbt = 0;
269 int retry = 0;
270 char *err;
271 int i;
273 struct set_params {
274 char *name;
275 int value;
276 } params[] = {
277 {"tx-ring-ref", 0},
278 {"rx-ring-ref", 0},
279 {"event-channel", 0},
280 {"request-rx-copy", 1},
281 {"feature-rx-notify", 1},
282 {"feature-no-csum-offload", 1},
283 {"feature-sg", 1},
284 {"feature-gso-tcpv4", 0},
285 {NULL, 0},
286 };
288 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
289 XBT_NIL, Path, &Value);
290 be_state = atoi(Value);
291 ExFreePool(Value);
293 switch (be_state)
294 {
295 case XenbusStateUnknown:
296 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
297 break;
299 case XenbusStateInitialising:
300 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
301 break;
303 case XenbusStateInitWait:
304 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
306 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
307 xi->EvtChnInterface.InterfaceHeader.Context, 0);
308 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
309 xi->event_channel, XenNet_Interrupt, xi);
311 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
312 // or, allocate mem and then get mdl, then free mdl
313 xi->tx_mdl = AllocatePage();
314 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
315 NULL, FALSE, NormalPagePriority);
316 SHARED_RING_INIT(xi->tx_pgs);
317 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
318 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
319 xi->GntTblInterface.InterfaceHeader.Context, 0,
320 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
322 xi->rx_mdl = AllocatePage();
323 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
324 NULL, FALSE, NormalPagePriority);
325 SHARED_RING_INIT(xi->rx_pgs);
326 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
327 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
328 xi->GntTblInterface.InterfaceHeader.Context, 0,
329 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
331 /* fixup array for dynamic values */
332 params[0].value = xi->tx_ring_ref;
333 params[1].value = xi->rx_ring_ref;
334 params[2].value = xi->event_channel;
336 xi->XenBusInterface.StartTransaction(
337 xi->XenBusInterface.InterfaceHeader.Context, &xbt);
339 for (i = 0; params[i].name; i++)
340 {
341 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
342 xi->Path, params[i].name);
343 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
344 XBT_NIL, TmpPath, "%d", params[i].value);
345 if (err)
346 {
347 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
348 goto trouble;
349 }
350 }
352 /* commit transaction */
353 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
354 xbt, 0, &retry);
356 /* TODO: prepare tx and rx rings */
358 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
359 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
360 xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
361 XBT_NIL, TmpPath, "%d", XenbusStateConnected);
363 /* send fake arp? */
365 xi->connected = TRUE;
367 break;
369 case XenbusStateInitialised:
370 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
371 // create the device
372 break;
374 case XenbusStateConnected:
375 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
377 /* do more stuff here */
379 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
380 break;
382 case XenbusStateClosing:
383 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
384 break;
386 case XenbusStateClosed:
387 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
388 break;
390 default:
391 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", be_state));
392 break;
393 }
395 return;
397 trouble:
398 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
399 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
400 xbt, 1, &retry);
402 }
405 VOID
406 XenNet_Halt(
407 IN NDIS_HANDLE MiniportAdapterContext
408 )
409 {
410 UNREFERENCED_PARAMETER(MiniportAdapterContext);
411 }
413 static NDIS_STATUS
414 XenNet_Init(
415 OUT PNDIS_STATUS OpenErrorStatus,
416 OUT PUINT SelectedMediumIndex,
417 IN PNDIS_MEDIUM MediumArray,
418 IN UINT MediumArraySize,
419 IN NDIS_HANDLE MiniportAdapterHandle,
420 IN NDIS_HANDLE WrapperConfigurationContext
421 )
422 {
423 NDIS_STATUS status;
424 UINT i;
425 BOOLEAN medium_found = FALSE;
426 struct xennet_info *xi = NULL;
427 ULONG length;
428 WDF_OBJECT_ATTRIBUTES wdf_attrs;
429 char *msg;
430 char *Value;
431 char **vif_devs;
432 char TmpPath[128];
434 UNREFERENCED_PARAMETER(OpenErrorStatus);
435 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
437 /* deal with medium stuff */
438 for (i = 0; i < MediumArraySize; i++)
439 {
440 if (MediumArray[i] == NdisMedium802_3)
441 {
442 medium_found = TRUE;
443 break;
444 }
445 }
446 if (!medium_found)
447 {
448 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
449 return NDIS_STATUS_UNSUPPORTED_MEDIA;
450 }
451 *SelectedMediumIndex = i;
453 /* Alloc memory for adapter private info */
454 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
455 if (!NT_SUCCESS(status))
456 {
457 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
458 status = NDIS_STATUS_RESOURCES;
459 goto err;
460 }
461 RtlZeroMemory(xi, sizeof(*xi));
463 /* init xennet_info */
464 xi->adapter_handle = MiniportAdapterHandle;
465 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
466 &xi->lower_do, NULL, NULL);
468 /* Initialise {tx,rx}_pkts as a free chain containing every entry. */
469 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
470 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
471 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
472 }
474 for (i = 0; i < NET_RX_RING_SIZE; i++) {
475 xi->rx_pkts[i] = NULL;
476 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
477 }
479 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
480 NAME_SIZE, xi->name, &length);
481 if (!NT_SUCCESS(status))
482 {
483 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
484 status = NDIS_STATUS_FAILURE;
485 goto err;
486 }
488 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
489 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
490 NdisInterfaceInternal);
492 // status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE,
493 // XN_MAX_PKT_SIZE);
494 // if (!NT_SUCCESS(status))
495 // {
496 // KdPrint(("NdisMInitializeScatterGatherDma failed with 0x%x\n", status));
497 // status = NDIS_STATUS_FAILURE;
498 // goto err;
499 // }
501 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&wdf_attrs, wdf_device_info);
503 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
504 xi->lower_do, xi->pdo, &xi->wdf_device);
505 if (!NT_SUCCESS(status))
506 {
507 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
508 status = NDIS_STATUS_FAILURE;
509 goto err;
510 }
512 GetWdfDeviceInfo(xi->wdf_device)->xennet_info = xi;
514 /* get lower (Xen) interfaces */
516 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
517 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
518 if(!NT_SUCCESS(status))
519 {
520 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
521 status = NDIS_STATUS_FAILURE;
522 goto err;
523 }
525 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
526 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
527 if(!NT_SUCCESS(status))
528 {
529 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
530 status = NDIS_STATUS_FAILURE;
531 goto err;
532 }
534 #if 0
535 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
536 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
537 if(!NT_SUCCESS(status))
538 {
539 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
540 status = NDIS_STATUS_FAILURE;
541 goto err;
542 }
543 #endif
545 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
546 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
547 if(!NT_SUCCESS(status))
548 {
549 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
550 status = NDIS_STATUS_FAILURE;
551 goto err;
552 }
554 msg = xi->XenBusInterface.List(xi->EvtChnInterface.InterfaceHeader.Context,
555 XBT_NIL, "device/vif", &vif_devs);
556 if (msg)
557 {
558 KdPrint((__DRIVER_NAME ": " __FUNCTION__ ": List retval is nonzero!\n"));
559 status = NDIS_STATUS_FAILURE;
560 goto err;
561 }
563 for (i = 0; vif_devs[i]; i++)
564 {
565 if (i > 0)
566 {
567 KdPrint((__DRIVER_NAME "Can only handle 1 vif so far, ignoring vif %s\n", vif_devs[i]));
568 continue;
569 }
570 RtlStringCbPrintfA(xi->Path, ARRAY_SIZE(xi->Path), "device/vif/%s", vif_devs[i]);
572 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
573 "device/vif/%s/state", vif_devs[i]);
574 KdPrint(("%s\n", TmpPath));
576 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/backend", xi->Path);
577 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
578 XBT_NIL, TmpPath, &Value);
579 if (!Value)
580 {
581 KdPrint((__DRIVER_NAME " backend Read Failed\n"));
582 }
583 else
584 {
585 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
586 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
587 }
588 ExFreePool(Value);
590 /* Add watch on backend state */
591 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
592 xi->XenBusInterface.AddWatch(xi->XenBusInterface.InterfaceHeader.Context,
593 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
595 /* get mac address */
596 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->Path);
597 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
598 XBT_NIL, TmpPath, &Value);
599 if (!Value)
600 {
601 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
602 }
603 else
604 {
605 char *s, *e;
606 int i;
608 s = Value;
610 for (i = 0; i < ETH_ALEN; i++) {
611 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
612 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
613 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
614 ExFreePool(Value);
615 ExFreePool(vif_devs);
616 status = NDIS_STATUS_FAILURE;
617 goto err;
618 }
619 s = e + 1;
620 }
621 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
622 }
623 ExFreePool(Value);
625 //XenVbd_HotPlugHandler(buffer, NULL);
626 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
627 }
628 ExFreePool(vif_devs);
630 return NDIS_STATUS_SUCCESS;
632 err:
633 NdisFreeMemory(xi, 0, 0);
634 return status;
635 }
637 NDIS_OID supported_oids[] =
638 {
639 OID_GEN_SUPPORTED_LIST,
640 OID_GEN_HARDWARE_STATUS,
641 OID_GEN_MEDIA_SUPPORTED,
642 OID_GEN_MEDIA_IN_USE,
643 OID_GEN_MAXIMUM_LOOKAHEAD,
644 OID_GEN_MAXIMUM_FRAME_SIZE,
645 OID_GEN_LINK_SPEED,
646 OID_GEN_TRANSMIT_BUFFER_SPACE,
647 OID_GEN_RECEIVE_BUFFER_SPACE,
648 OID_GEN_TRANSMIT_BLOCK_SIZE,
649 OID_GEN_RECEIVE_BLOCK_SIZE,
650 OID_GEN_VENDOR_ID,
651 OID_GEN_VENDOR_DESCRIPTION,
652 OID_GEN_CURRENT_PACKET_FILTER,
653 OID_GEN_CURRENT_LOOKAHEAD,
654 OID_GEN_DRIVER_VERSION,
655 OID_GEN_MAXIMUM_TOTAL_SIZE,
656 OID_GEN_MAC_OPTIONS,
657 OID_GEN_MEDIA_CONNECT_STATUS,
658 OID_GEN_MAXIMUM_SEND_PACKETS,
659 OID_802_3_PERMANENT_ADDRESS,
660 OID_802_3_CURRENT_ADDRESS,
661 OID_802_3_MULTICAST_LIST,
662 OID_802_3_MAXIMUM_LIST_SIZE,
663 };
665 NDIS_STATUS
666 XenNet_QueryInformation(
667 IN NDIS_HANDLE MiniportAdapterContext,
668 IN NDIS_OID Oid,
669 IN PVOID InformationBuffer,
670 IN ULONG InformationBufferLength,
671 OUT PULONG BytesWritten,
672 OUT PULONG BytesNeeded)
673 {
674 struct xennet_info *xi = MiniportAdapterContext;
675 UCHAR vendor_desc[] = XN_VENDOR_DESC;
676 ULONG temp_data;
677 PVOID data = &temp_data;
678 UINT len = sizeof(temp_data);
679 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
681 switch(Oid)
682 {
683 case OID_GEN_SUPPORTED_LIST:
684 data = supported_oids;
685 len = sizeof(supported_oids);
686 break;
687 case OID_GEN_HARDWARE_STATUS:
688 temp_data = NdisHardwareStatusReady;
689 break;
690 case OID_GEN_MEDIA_SUPPORTED:
691 temp_data = NdisMedium802_3;
692 break;
693 case OID_GEN_MEDIA_IN_USE:
694 temp_data = NdisMedium802_3;
695 break;
696 case OID_GEN_MAXIMUM_LOOKAHEAD:
697 temp_data = XN_DATA_SIZE;
698 break;
699 case OID_GEN_MAXIMUM_FRAME_SIZE:
700 temp_data = XN_MAX_PKT_SIZE;
701 break;
702 case OID_GEN_LINK_SPEED:
703 temp_data = 10000000; /* 1Gb */
704 break;
705 case OID_GEN_TRANSMIT_BUFFER_SPACE:
706 /* pkts times sizeof ring, maybe? */
707 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
708 break;
709 case OID_GEN_RECEIVE_BUFFER_SPACE:
710 /* pkts times sizeof ring, maybe? */
711 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
712 break;
713 case OID_GEN_TRANSMIT_BLOCK_SIZE:
714 temp_data = XN_MAX_PKT_SIZE;
715 break;
716 case OID_GEN_RECEIVE_BLOCK_SIZE:
717 temp_data = XN_MAX_PKT_SIZE;
718 break;
719 case OID_GEN_VENDOR_ID:
720 temp_data = XENSOURCE_MAC_HDR;
721 break;
722 case OID_GEN_VENDOR_DESCRIPTION:
723 data = vendor_desc;
724 len = sizeof(vendor_desc);
725 break;
726 case OID_GEN_CURRENT_PACKET_FILTER:
727 temp_data = xi->packet_filter;
728 break;
729 case OID_GEN_CURRENT_LOOKAHEAD:
730 temp_data = XN_MAX_PKT_SIZE;
731 break;
732 case OID_GEN_DRIVER_VERSION:
733 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
734 len = 2;
735 break;
736 case OID_GEN_MAXIMUM_TOTAL_SIZE:
737 temp_data = XN_MAX_PKT_SIZE;
738 break;
739 case OID_GEN_MAC_OPTIONS:
740 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
741 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
742 NDIS_MAC_OPTION_NO_LOOPBACK;
743 break;
744 case OID_GEN_MEDIA_CONNECT_STATUS:
745 if (xi->connected)
746 temp_data = NdisMediaStateConnected;
747 else
748 temp_data = NdisMediaStateDisconnected;
749 break;
750 case OID_GEN_MAXIMUM_SEND_PACKETS:
751 temp_data = XN_MAX_SEND_PKTS;
752 break;
753 case OID_802_3_PERMANENT_ADDRESS:
754 data = xi->perm_mac_addr;
755 len = ETH_ALEN;
756 break;
757 case OID_802_3_CURRENT_ADDRESS:
758 data = xi->curr_mac_addr;
759 len = ETH_ALEN;
760 break;
761 case OID_802_3_MULTICAST_LIST:
762 data = NULL;
763 len = 0;
764 case OID_802_3_MAXIMUM_LIST_SIZE:
765 temp_data = 0; /* no mcast support */
766 break;
767 default:
768 //KdPrint(("Unknown OID 0x%x\n", Oid));
769 status = NDIS_STATUS_NOT_SUPPORTED;
770 }
772 if (!NT_SUCCESS(status))
773 {
774 return status;
775 }
777 if (len > InformationBufferLength)
778 {
779 *BytesNeeded = len;
780 return NDIS_STATUS_BUFFER_TOO_SHORT;
781 }
783 *BytesWritten = len;
784 if (len)
785 {
786 NdisMoveMemory(InformationBuffer, data, len);
787 }
789 KdPrint(("Got OID 0x%x\n", Oid));
791 return status;
792 }
794 NDIS_STATUS
795 XenNet_SetInformation(
796 IN NDIS_HANDLE MiniportAdapterContext,
797 IN NDIS_OID Oid,
798 IN PVOID InformationBuffer,
799 IN ULONG InformationBufferLength,
800 OUT PULONG BytesRead,
801 OUT PULONG BytesNeeded
802 )
803 {
804 UNREFERENCED_PARAMETER(MiniportAdapterContext);
805 UNREFERENCED_PARAMETER(Oid);
806 UNREFERENCED_PARAMETER(InformationBuffer);
807 UNREFERENCED_PARAMETER(InformationBufferLength);
808 UNREFERENCED_PARAMETER(BytesRead);
809 UNREFERENCED_PARAMETER(BytesNeeded);
811 KdPrint((__FUNCTION__ " called with OID=0x%x\n", Oid));
812 return NDIS_STATUS_SUCCESS;
813 }
815 VOID
816 XenNet_ReturnPacket(
817 IN NDIS_HANDLE MiniportAdapterContext,
818 IN PNDIS_PACKET Packet
819 )
820 {
821 UNREFERENCED_PARAMETER(MiniportAdapterContext);
822 UNREFERENCED_PARAMETER(Packet);
824 KdPrint((__FUNCTION__ " called\n"));
825 }
827 PMDL
828 XenNet_Linearize(PNDIS_PACKET Packet)
829 {
830 PMDL pmdl;
831 char *start;
832 PNDIS_BUFFER buffer;
833 PVOID buff_va;
834 UINT buff_len;
835 UINT tot_buff_len;
837 pmdl = AllocatePage();
839 start = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
840 if (!start)
841 {
842 return NULL;
843 }
845 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
846 &tot_buff_len, NormalPagePriority);
847 ASSERT(tot_buff_len <= PAGE_SIZE);
849 while (buffer)
850 {
851 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
852 RtlCopyMemory(start, buff_va, buff_len);
853 start += buff_len;
854 NdisGetNextBuffer(buffer, &buffer);
855 }
857 return pmdl;
858 }
860 VOID
861 XenNet_SendPackets(
862 IN NDIS_HANDLE MiniportAdapterContext,
863 IN PPNDIS_PACKET PacketArray,
864 IN UINT NumberOfPackets
865 )
866 {
867 /* for each packet:
868 req_prod_pvt is the next entry in the cmd ring to use
869 add pkt to array of saved packets
870 fill out tx request for the first part of skb
871 add to grant table
872 do flags for csum etc
873 gso (later)
874 inc req_prod_pvt
875 frags
876 possibly notify
877 network_tx)buf_gc
878 stop netif if no more room
879 */
880 struct xennet_info *xi = MiniportAdapterContext;
881 PNDIS_PACKET curr_packet;
882 UINT i;
883 struct netif_tx_request *tx;
884 unsigned short id;
885 PFN_NUMBER pfn;
886 int notify;
887 PMDL pmdl;
888 UINT pkt_size;
890 KdPrint((__FUNCTION__ " called, sending %d pkts\n", NumberOfPackets));
892 for (i = 0; i < NumberOfPackets; i++)
893 {
894 curr_packet = PacketArray[i];
895 ASSERT(curr_packet);
897 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
899 pmdl = XenNet_Linearize(curr_packet);
900 if (!pmdl)
901 {
902 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
903 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
904 break;
905 }
906 pfn = *MmGetMdlPfnArray(pmdl);
908 id = get_id_from_freelist(xi->tx_pkts);
909 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
910 xi->tx_pkts[id] = curr_packet;
912 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
913 tx->id = id;
914 tx->gref = xi->GntTblInterface.GrantAccess(
915 xi->GntTblInterface.InterfaceHeader.Context,
916 0,
917 pfn,
918 TRUE);
919 xi->grant_tx_ref[id] = tx->gref;
920 tx->offset = 0;
921 tx->size = (UINT16)pkt_size;
922 tx->flags = NETTXF_csum_blank;
924 xi->tx.req_prod_pvt++;
926 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
927 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
928 }
930 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
931 if (notify)
932 {
933 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
934 xi->event_channel);
935 }
936 }
938 VOID
939 XenNet_PnPEventNotify(
940 IN NDIS_HANDLE MiniportAdapterContext,
941 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
942 IN PVOID InformationBuffer,
943 IN ULONG InformationBufferLength
944 )
945 {
946 UNREFERENCED_PARAMETER(MiniportAdapterContext);
947 UNREFERENCED_PARAMETER(PnPEvent);
948 UNREFERENCED_PARAMETER(InformationBuffer);
949 UNREFERENCED_PARAMETER(InformationBufferLength);
951 KdPrint((__FUNCTION__ " called\n"));
952 }
954 VOID
955 XenNet_Shutdown(
956 IN NDIS_HANDLE MiniportAdapterContext
957 )
958 {
959 UNREFERENCED_PARAMETER(MiniportAdapterContext);
961 KdPrint((__FUNCTION__ " called\n"));
962 }
964 NTSTATUS
965 DriverEntry(
966 PDRIVER_OBJECT DriverObject,
967 PUNICODE_STRING RegistryPath
968 )
969 {
970 NTSTATUS status;
971 WDF_DRIVER_CONFIG config;
972 NDIS_HANDLE ndis_wrapper_handle;
973 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
975 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
977 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
978 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
980 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
981 &config, WDF_NO_HANDLE);
982 if (!NT_SUCCESS(status))
983 {
984 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
985 return status;
986 }
988 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
989 if (!ndis_wrapper_handle)
990 {
991 KdPrint(("NdisMInitializeWrapper failed\n"));
992 return NDIS_STATUS_FAILURE;
993 }
995 /* NDIS 5.1 driver */
996 mini_chars.MajorNdisVersion = 5;
997 mini_chars.MinorNdisVersion = 1;
999 mini_chars.HaltHandler = XenNet_Halt;
1000 mini_chars.InitializeHandler = XenNet_Init;
1001 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1002 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1003 mini_chars.ResetHandler = NULL; //TODO: fill in
1004 mini_chars.SetInformationHandler = XenNet_SetInformation;
1005 /* added in v.4 -- use multiple pkts interface */
1006 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1007 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1008 /* added in v.5.1 */
1009 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1010 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1012 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1014 /* set up upper-edge interface */
1015 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1016 if (!NT_SUCCESS(status))
1018 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1019 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1020 return status;
1023 return status;