win-pvdrivers

view xennet/xennet.c @ 32:d5df0038627d

xennet: rough-in sendPackets

currently allocates an extra page per packet
not seeing interrupts, why not?
updated copyright notices with my work email address
author Andy Grover <andy.grover@oracle.com>
date Tue Dec 04 17:29:26 2007 -0800 (2007-12-04)
parents bc0ea67acebb
children b0870e38eaab
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;
179 UNREFERENCED_PARAMETER(xi);
180 #if 0
181 unsigned short id;
182 struct sk_buff *skb;
184 BUG_ON(!netfront_carrier_ok(np));
186 do {
187 prod = np->tx.sring->rsp_prod;
188 rmb(); /* Ensure we see responses up to 'rp'. */
190 for (cons = np->tx.rsp_cons; cons != prod; cons++) {
191 struct netif_tx_response *txrsp;
193 txrsp = RING_GET_RESPONSE(&np->tx, cons);
194 if (txrsp->status == NETIF_RSP_NULL)
195 continue;
197 id = txrsp->id;
198 skb = np->tx_skbs[id];
199 if (unlikely(gnttab_query_foreign_access(
200 np->grant_tx_ref[id]) != 0)) {
201 printk(KERN_ALERT "network_tx_buf_gc: warning "
202 "-- grant still in use by backend "
203 "domain.\n");
204 BUG();
205 }
206 gnttab_end_foreign_access_ref(
207 np->grant_tx_ref[id], GNTMAP_readonly);
208 gnttab_release_grant_reference(
209 &np->gref_tx_head, np->grant_tx_ref[id]);
210 np->grant_tx_ref[id] = GRANT_INVALID_REF;
211 add_id_to_freelist(np->tx_skbs, id);
212 dev_kfree_skb_irq(skb);
213 }
215 np->tx.rsp_cons = prod;
217 /*
218 * Set a new event, then check for race with update of tx_cons.
219 * Note that it is essential to schedule a callback, no matter
220 * how few buffers are pending. Even if there is space in the
221 * transmit ring, higher layers may be blocked because too much
222 * data is outstanding: in such cases notification from Xen is
223 * likely to be the only kick that we'll get.
224 */
225 np->tx.sring->rsp_event =
226 prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
227 mb();
228 } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
230 network_maybe_wake_tx(dev);
234 #endif
237 return NDIS_STATUS_SUCCESS;
238 }
240 static BOOLEAN
241 XenNet_Interrupt(
242 PKINTERRUPT Interrupt,
243 PVOID ServiceContext
244 )
245 {
246 struct xennet_info *xi = ServiceContext;
247 // KIRQL KIrql;
249 UNREFERENCED_PARAMETER(Interrupt);
251 KdPrint((__DRIVER_NAME " ***XenNet Interrupt***\n"));
253 if (xi->connected)
254 {
255 XenNet_TxBufGC(xi);
256 }
257 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
258 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
259 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
260 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
261 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
263 /* do something */
265 return TRUE;
266 }
268 static VOID
269 XenNet_BackEndStateHandler(char *Path, PVOID Data)
270 {
271 struct xennet_info *xi = Data;
272 char *Value;
273 int be_state;
274 char TmpPath[128];
275 xenbus_transaction_t xbt = 0;
276 int retry = 0;
277 char *err;
278 int i;
280 struct set_params {
281 char *name;
282 int value;
283 } params[] = {
284 {"tx-ring-ref", 0},
285 {"rx-ring-ref", 0},
286 {"event-channel", 0},
287 {"request-rx-copy", 1},
288 {"feature-rx-notify", 1},
289 {"feature-no-csum-offload", 1},
290 {"feature-sg", 1},
291 {"feature-gso-tcpv4", 0},
292 {NULL, 0},
293 };
295 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
296 XBT_NIL, Path, &Value);
297 be_state = atoi(Value);
298 ExFreePool(Value);
300 switch (be_state)
301 {
302 case XenbusStateUnknown:
303 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
304 break;
306 case XenbusStateInitialising:
307 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
308 break;
310 case XenbusStateInitWait:
311 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
313 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
314 xi->EvtChnInterface.InterfaceHeader.Context, 0);
315 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
316 xi->event_channel, XenNet_Interrupt, xi);
318 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
319 // or, allocate mem and then get mdl, then free mdl
320 xi->tx_mdl = AllocatePage();
321 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
322 NULL, FALSE, NormalPagePriority);
323 SHARED_RING_INIT(xi->tx_pgs);
324 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
325 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
326 xi->GntTblInterface.InterfaceHeader.Context, 0,
327 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
329 xi->rx_mdl = AllocatePage();
330 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
331 NULL, FALSE, NormalPagePriority);
332 SHARED_RING_INIT(xi->rx_pgs);
333 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
334 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
335 xi->GntTblInterface.InterfaceHeader.Context, 0,
336 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
338 /* fixup array for dynamic values */
339 params[0].value = xi->tx_ring_ref;
340 params[1].value = xi->rx_ring_ref;
341 params[2].value = xi->event_channel;
343 xi->XenBusInterface.StartTransaction(
344 xi->XenBusInterface.InterfaceHeader.Context, &xbt);
346 for (i = 0; params[i].name; i++)
347 {
348 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
349 xi->Path, params[i].name);
350 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
351 XBT_NIL, TmpPath, "%d", params[i].value);
352 if (err)
353 {
354 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
355 goto trouble;
356 }
357 }
359 /* commit transaction */
360 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
361 xbt, 0, &retry);
363 /* TODO: prepare tx and rx rings */
365 KdPrint((__DRIVER_NAME " Set Frontend state to Initialised\n"));
366 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
367 xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
368 XBT_NIL, TmpPath, "%d", XenbusStateInitialised);
370 /* send fake arp? */
372 xi->connected = TRUE;
374 break;
376 case XenbusStateInitialised:
377 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
378 // create the device
379 break;
381 case XenbusStateConnected:
382 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
384 /* do more stuff here */
386 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
387 break;
389 case XenbusStateClosing:
390 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
391 break;
393 case XenbusStateClosed:
394 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
395 break;
397 default:
398 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", be_state));
399 break;
400 }
402 return;
404 trouble:
405 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
406 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
407 xbt, 1, &retry);
409 }
412 VOID
413 XenNet_Halt(
414 IN NDIS_HANDLE MiniportAdapterContext
415 )
416 {
417 UNREFERENCED_PARAMETER(MiniportAdapterContext);
418 }
420 static NDIS_STATUS
421 XenNet_Init(
422 OUT PNDIS_STATUS OpenErrorStatus,
423 OUT PUINT SelectedMediumIndex,
424 IN PNDIS_MEDIUM MediumArray,
425 IN UINT MediumArraySize,
426 IN NDIS_HANDLE MiniportAdapterHandle,
427 IN NDIS_HANDLE WrapperConfigurationContext
428 )
429 {
430 NDIS_STATUS status;
431 UINT i;
432 BOOLEAN medium_found = FALSE;
433 struct xennet_info *xi = NULL;
434 ULONG length;
435 WDF_OBJECT_ATTRIBUTES wdf_attrs;
436 char *msg;
437 char *Value;
438 char **vif_devs;
439 char TmpPath[128];
441 UNREFERENCED_PARAMETER(OpenErrorStatus);
442 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
444 /* deal with medium stuff */
445 for (i = 0; i < MediumArraySize; i++)
446 {
447 if (MediumArray[i] == NdisMedium802_3)
448 {
449 medium_found = TRUE;
450 break;
451 }
452 }
453 if (!medium_found)
454 {
455 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
456 return NDIS_STATUS_UNSUPPORTED_MEDIA;
457 }
458 *SelectedMediumIndex = i;
460 /* Alloc memory for adapter private info */
461 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
462 if (!NT_SUCCESS(status))
463 {
464 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
465 status = NDIS_STATUS_RESOURCES;
466 goto err;
467 }
468 RtlZeroMemory(xi, sizeof(*xi));
470 /* init xennet_info */
471 xi->adapter_handle = MiniportAdapterHandle;
472 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
473 &xi->lower_do, NULL, NULL);
475 /* Initialise {tx,rx}_pkts as a free chain containing every entry. */
476 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
477 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
478 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
479 }
481 for (i = 0; i < NET_RX_RING_SIZE; i++) {
482 xi->rx_pkts[i] = NULL;
483 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
484 }
486 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
487 NAME_SIZE, xi->name, &length);
488 if (!NT_SUCCESS(status))
489 {
490 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
491 status = NDIS_STATUS_FAILURE;
492 goto err;
493 }
495 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
496 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
497 NdisInterfaceInternal);
499 // status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE,
500 // XN_MAX_PKT_SIZE);
501 // if (!NT_SUCCESS(status))
502 // {
503 // KdPrint(("NdisMInitializeScatterGatherDma failed with 0x%x\n", status));
504 // status = NDIS_STATUS_FAILURE;
505 // goto err;
506 // }
508 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&wdf_attrs, wdf_device_info);
510 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
511 xi->lower_do, xi->pdo, &xi->wdf_device);
512 if (!NT_SUCCESS(status))
513 {
514 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
515 status = NDIS_STATUS_FAILURE;
516 goto err;
517 }
519 GetWdfDeviceInfo(xi->wdf_device)->xennet_info = xi;
521 /* get lower (Xen) interfaces */
523 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
524 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
525 if(!NT_SUCCESS(status))
526 {
527 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
528 status = NDIS_STATUS_FAILURE;
529 goto err;
530 }
532 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
533 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
534 if(!NT_SUCCESS(status))
535 {
536 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
537 status = NDIS_STATUS_FAILURE;
538 goto err;
539 }
541 #if 0
542 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
543 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
544 if(!NT_SUCCESS(status))
545 {
546 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
547 status = NDIS_STATUS_FAILURE;
548 goto err;
549 }
550 #endif
552 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
553 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
554 if(!NT_SUCCESS(status))
555 {
556 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
557 status = NDIS_STATUS_FAILURE;
558 goto err;
559 }
561 msg = xi->XenBusInterface.List(xi->EvtChnInterface.InterfaceHeader.Context,
562 XBT_NIL, "device/vif", &vif_devs);
563 if (msg)
564 {
565 KdPrint((__DRIVER_NAME ": " __FUNCTION__ ": List retval is nonzero!\n"));
566 status = NDIS_STATUS_FAILURE;
567 goto err;
568 }
570 for (i = 0; vif_devs[i]; i++)
571 {
572 if (i > 0)
573 {
574 KdPrint((__DRIVER_NAME "Can only handle 1 vif so far, ignoring vif %s\n", vif_devs[i]));
575 continue;
576 }
577 RtlStringCbPrintfA(xi->Path, ARRAY_SIZE(xi->Path), "device/vif/%s", vif_devs[i]);
579 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
580 "device/vif/%s/state", vif_devs[i]);
581 KdPrint(("%s\n", TmpPath));
583 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/backend", xi->Path);
584 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
585 XBT_NIL, TmpPath, &Value);
586 if (!Value)
587 {
588 KdPrint((__DRIVER_NAME " backend Read Failed\n"));
589 }
590 else
591 {
592 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
593 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
594 }
595 ExFreePool(Value);
597 /* Add watch on backend state */
598 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
599 xi->XenBusInterface.AddWatch(xi->XenBusInterface.InterfaceHeader.Context,
600 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
602 /* get mac address */
603 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->Path);
604 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
605 XBT_NIL, TmpPath, &Value);
606 if (!Value)
607 {
608 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
609 }
610 else
611 {
612 char *s, *e;
613 int i;
615 s = Value;
617 for (i = 0; i < ETH_ALEN; i++) {
618 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
619 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
620 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
621 ExFreePool(Value);
622 ExFreePool(vif_devs);
623 status = NDIS_STATUS_FAILURE;
624 goto err;
625 }
626 s = e + 1;
627 }
628 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
629 }
630 ExFreePool(Value);
632 //XenVbd_HotPlugHandler(buffer, NULL);
633 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
634 }
635 ExFreePool(vif_devs);
637 return NDIS_STATUS_SUCCESS;
639 err:
640 NdisFreeMemory(xi, 0, 0);
641 return status;
642 }
644 NDIS_OID supported_oids[] =
645 {
646 OID_GEN_SUPPORTED_LIST,
647 OID_GEN_HARDWARE_STATUS,
648 OID_GEN_MEDIA_SUPPORTED,
649 OID_GEN_MEDIA_IN_USE,
650 OID_GEN_MAXIMUM_LOOKAHEAD,
651 OID_GEN_MAXIMUM_FRAME_SIZE,
652 OID_GEN_LINK_SPEED,
653 OID_GEN_TRANSMIT_BUFFER_SPACE,
654 OID_GEN_RECEIVE_BUFFER_SPACE,
655 OID_GEN_TRANSMIT_BLOCK_SIZE,
656 OID_GEN_RECEIVE_BLOCK_SIZE,
657 OID_GEN_VENDOR_ID,
658 OID_GEN_VENDOR_DESCRIPTION,
659 OID_GEN_CURRENT_PACKET_FILTER,
660 OID_GEN_CURRENT_LOOKAHEAD,
661 OID_GEN_DRIVER_VERSION,
662 OID_GEN_MAXIMUM_TOTAL_SIZE,
663 OID_GEN_MAC_OPTIONS,
664 OID_GEN_MEDIA_CONNECT_STATUS,
665 OID_GEN_MAXIMUM_SEND_PACKETS,
666 OID_802_3_PERMANENT_ADDRESS,
667 OID_802_3_CURRENT_ADDRESS,
668 OID_802_3_MULTICAST_LIST,
669 OID_802_3_MAXIMUM_LIST_SIZE,
670 };
672 NDIS_STATUS
673 XenNet_QueryInformation(
674 IN NDIS_HANDLE MiniportAdapterContext,
675 IN NDIS_OID Oid,
676 IN PVOID InformationBuffer,
677 IN ULONG InformationBufferLength,
678 OUT PULONG BytesWritten,
679 OUT PULONG BytesNeeded)
680 {
681 struct xennet_info *xi = MiniportAdapterContext;
682 UCHAR vendor_desc[] = XN_VENDOR_DESC;
683 ULONG temp_data;
684 PVOID data = &temp_data;
685 UINT len = sizeof(temp_data);
686 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
688 switch(Oid)
689 {
690 case OID_GEN_SUPPORTED_LIST:
691 data = supported_oids;
692 len = sizeof(supported_oids);
693 break;
694 case OID_GEN_HARDWARE_STATUS:
695 temp_data = NdisHardwareStatusReady;
696 break;
697 case OID_GEN_MEDIA_SUPPORTED:
698 temp_data = NdisMedium802_3;
699 break;
700 case OID_GEN_MEDIA_IN_USE:
701 temp_data = NdisMedium802_3;
702 break;
703 case OID_GEN_MAXIMUM_LOOKAHEAD:
704 temp_data = XN_DATA_SIZE;
705 break;
706 case OID_GEN_MAXIMUM_FRAME_SIZE:
707 temp_data = XN_MAX_PKT_SIZE;
708 break;
709 case OID_GEN_LINK_SPEED:
710 temp_data = 10000000; /* 1Gb */
711 break;
712 case OID_GEN_TRANSMIT_BUFFER_SPACE:
713 /* pkts times sizeof ring, maybe? */
714 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
715 break;
716 case OID_GEN_RECEIVE_BUFFER_SPACE:
717 /* pkts times sizeof ring, maybe? */
718 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
719 break;
720 case OID_GEN_TRANSMIT_BLOCK_SIZE:
721 temp_data = XN_MAX_PKT_SIZE;
722 break;
723 case OID_GEN_RECEIVE_BLOCK_SIZE:
724 temp_data = XN_MAX_PKT_SIZE;
725 break;
726 case OID_GEN_VENDOR_ID:
727 temp_data = XENSOURCE_MAC_HDR;
728 break;
729 case OID_GEN_VENDOR_DESCRIPTION:
730 data = vendor_desc;
731 len = sizeof(vendor_desc);
732 break;
733 case OID_GEN_CURRENT_PACKET_FILTER:
734 temp_data = xi->packet_filter;
735 break;
736 case OID_GEN_CURRENT_LOOKAHEAD:
737 temp_data = XN_MAX_PKT_SIZE;
738 break;
739 case OID_GEN_DRIVER_VERSION:
740 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
741 len = 2;
742 break;
743 case OID_GEN_MAXIMUM_TOTAL_SIZE:
744 temp_data = XN_MAX_PKT_SIZE;
745 break;
746 case OID_GEN_MAC_OPTIONS:
747 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
748 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
749 NDIS_MAC_OPTION_NO_LOOPBACK;
750 break;
751 case OID_GEN_MEDIA_CONNECT_STATUS:
752 if (xi->connected)
753 temp_data = NdisMediaStateConnected;
754 else
755 temp_data = NdisMediaStateDisconnected;
756 break;
757 case OID_GEN_MAXIMUM_SEND_PACKETS:
758 temp_data = XN_MAX_SEND_PKTS;
759 break;
760 case OID_802_3_PERMANENT_ADDRESS:
761 data = xi->perm_mac_addr;
762 len = ETH_ALEN;
763 break;
764 case OID_802_3_CURRENT_ADDRESS:
765 data = xi->curr_mac_addr;
766 len = ETH_ALEN;
767 break;
768 case OID_802_3_MULTICAST_LIST:
769 data = NULL;
770 len = 0;
771 case OID_802_3_MAXIMUM_LIST_SIZE:
772 temp_data = 0; /* no mcast support */
773 break;
774 default:
775 KdPrint(("Unknown OID 0x%x\n", Oid));
776 status = NDIS_STATUS_NOT_SUPPORTED;
777 }
779 if (!NT_SUCCESS(status))
780 {
781 return status;
782 }
784 if (len > InformationBufferLength)
785 {
786 *BytesNeeded = len;
787 return NDIS_STATUS_BUFFER_TOO_SHORT;
788 }
790 *BytesWritten = len;
791 if (len)
792 {
793 NdisMoveMemory(InformationBuffer, data, len);
794 }
796 KdPrint(("Got OID 0x%x\n", Oid));
798 return status;
799 }
801 NDIS_STATUS
802 XenNet_SetInformation(
803 IN NDIS_HANDLE MiniportAdapterContext,
804 IN NDIS_OID Oid,
805 IN PVOID InformationBuffer,
806 IN ULONG InformationBufferLength,
807 OUT PULONG BytesRead,
808 OUT PULONG BytesNeeded
809 )
810 {
811 UNREFERENCED_PARAMETER(MiniportAdapterContext);
812 UNREFERENCED_PARAMETER(Oid);
813 UNREFERENCED_PARAMETER(InformationBuffer);
814 UNREFERENCED_PARAMETER(InformationBufferLength);
815 UNREFERENCED_PARAMETER(BytesRead);
816 UNREFERENCED_PARAMETER(BytesNeeded);
818 KdPrint((__FUNCTION__ " called with OID=0x%x\n", Oid));
819 return NDIS_STATUS_SUCCESS;
820 }
822 VOID
823 XenNet_ReturnPacket(
824 IN NDIS_HANDLE MiniportAdapterContext,
825 IN PNDIS_PACKET Packet
826 )
827 {
828 UNREFERENCED_PARAMETER(MiniportAdapterContext);
829 UNREFERENCED_PARAMETER(Packet);
831 KdPrint((__FUNCTION__ " called\n"));
832 }
834 PMDL
835 XenNet_Linearize(PNDIS_PACKET Packet)
836 {
837 PMDL pmdl;
838 char *start;
839 PNDIS_BUFFER buffer;
840 PVOID buff_va;
841 UINT buff_len;
842 UINT tot_buff_len;
844 pmdl = AllocatePage();
846 start = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
847 if (!start)
848 {
849 return NULL;
850 }
852 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
853 &tot_buff_len, NormalPagePriority);
854 ASSERT(tot_buff_len <= PAGE_SIZE);
856 while (buffer)
857 {
858 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
859 RtlCopyMemory(start, buff_va, buff_len);
860 start += buff_len;
861 NdisGetNextBuffer(buffer, &buffer);
862 }
864 return pmdl;
865 }
867 VOID
868 XenNet_SendPackets(
869 IN NDIS_HANDLE MiniportAdapterContext,
870 IN PPNDIS_PACKET PacketArray,
871 IN UINT NumberOfPackets
872 )
873 {
874 /* for each packet:
875 req_prod_pvt is the next entry in the cmd ring to use
876 add pkt to array of saved packets
877 fill out tx request for the first part of skb
878 add to grant table
879 do flags for csum etc
880 gso (later)
881 inc req_prod_pvt
882 frags
883 possibly notify
884 network_tx)buf_gc
885 stop netif if no more room
886 */
887 struct xennet_info *xi = MiniportAdapterContext;
888 PNDIS_PACKET curr_packet;
889 UINT i;
890 struct netif_tx_request *tx;
891 unsigned short id;
892 PFN_NUMBER pfn;
893 int notify;
894 PMDL pmdl;
895 UINT pkt_size;
897 KdPrint((__FUNCTION__ " called, sending %d pkts\n", NumberOfPackets));
899 for (i = 0; i < NumberOfPackets; i++)
900 {
901 curr_packet = PacketArray[i];
902 ASSERT(curr_packet);
904 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
906 pmdl = XenNet_Linearize(curr_packet);
907 if (!pmdl)
908 {
909 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
910 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
911 break;
912 }
913 pfn = *MmGetMdlPfnArray(pmdl);
915 id = get_id_from_freelist(xi->tx_pkts);
916 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
917 xi->tx_pkts[id] = curr_packet;
919 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
920 tx->id = id;
921 tx->gref = xi->GntTblInterface.GrantAccess(
922 xi->GntTblInterface.InterfaceHeader.Context,
923 0,
924 pfn,
925 TRUE);
926 tx->offset = 0;
927 tx->size = (UINT16)pkt_size;
928 tx->flags = NETTXF_csum_blank;
930 xi->tx.req_prod_pvt++;
932 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
933 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
934 }
936 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
937 if (notify)
938 {
939 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
940 xi->event_channel);
941 }
942 }
944 VOID
945 XenNet_PnPEventNotify(
946 IN NDIS_HANDLE MiniportAdapterContext,
947 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
948 IN PVOID InformationBuffer,
949 IN ULONG InformationBufferLength
950 )
951 {
952 UNREFERENCED_PARAMETER(MiniportAdapterContext);
953 UNREFERENCED_PARAMETER(PnPEvent);
954 UNREFERENCED_PARAMETER(InformationBuffer);
955 UNREFERENCED_PARAMETER(InformationBufferLength);
957 KdPrint((__FUNCTION__ " called\n"));
958 }
960 VOID
961 XenNet_Shutdown(
962 IN NDIS_HANDLE MiniportAdapterContext
963 )
964 {
965 UNREFERENCED_PARAMETER(MiniportAdapterContext);
967 KdPrint((__FUNCTION__ " called\n"));
968 }
970 NTSTATUS
971 DriverEntry(
972 PDRIVER_OBJECT DriverObject,
973 PUNICODE_STRING RegistryPath
974 )
975 {
976 NTSTATUS status;
977 WDF_DRIVER_CONFIG config;
978 NDIS_HANDLE ndis_wrapper_handle;
979 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
981 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
983 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
984 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
986 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
987 &config, WDF_NO_HANDLE);
988 if (!NT_SUCCESS(status))
989 {
990 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
991 return status;
992 }
994 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
995 if (!ndis_wrapper_handle)
996 {
997 KdPrint(("NdisMInitializeWrapper failed\n"));
998 return NDIS_STATUS_FAILURE;
999 }
1001 /* NDIS 5.1 driver */
1002 mini_chars.MajorNdisVersion = 5;
1003 mini_chars.MinorNdisVersion = 1;
1005 mini_chars.HaltHandler = XenNet_Halt;
1006 mini_chars.InitializeHandler = XenNet_Init;
1007 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1008 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1009 mini_chars.ResetHandler = NULL; //TODO: fill in
1010 mini_chars.SetInformationHandler = XenNet_SetInformation;
1011 /* added in v.4 -- use multiple pkts interface */
1012 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1013 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1014 /* added in v.5.1 */
1015 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1016 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1018 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1020 /* set up upper-edge interface */
1021 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1022 if (!NT_SUCCESS(status))
1024 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1025 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1026 return status;
1029 return status;