win-pvdrivers

view 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
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 unsigned short id;
319 PNDIS_PACKET pkt;
320 PNDIS_PACKET packets[1];
321 PNDIS_BUFFER buffer;
322 PVOID buff_va;
323 UINT buff_len;
324 UINT tot_buff_len;
326 ASSERT(xi->connected);
328 do {
329 prod = xi->rx.sring->rsp_prod;
330 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
332 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
333 struct netif_rx_response *rxrsp;
335 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
336 if (rxrsp->status == NETIF_RSP_NULL)
337 continue;
339 id = rxrsp->id;
340 pkt = xi->rx_pkts[id];
341 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
342 xi->grant_rx_ref[id]);
343 xi->grant_rx_ref[id] = GRANT_INVALID_REF;
344 //add_id_to_freelist(xi->rx_pkts, id);
346 NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
347 &tot_buff_len, NormalPagePriority);
348 ASSERT(rxrsp->offset == 0);
349 ASSERT(rxrsp->status > 0);
350 NdisAdjustBufferLength(buffer, rxrsp->status);
351 /* just indicate 1 packet for now */
352 packets[0] = pkt;
354 NdisMIndicateReceivePacket(xi->adapter_handle, packets, 1);
355 }
357 xi->rx.rsp_cons = prod;
359 /*
360 * Set a new event, then check for race with update of rx_cons.
361 * Note that it is essential to schedule a callback, no matter
362 * how few buffers are pending. Even if there is space in the
363 * transmit ring, higher layers may be blocked because too much
364 * data is outstanding: in such cases notification from Xen is
365 * likely to be the only kick that we'll get.
366 */
367 xi->rx.sring->rsp_event =
368 prod + ((xi->rx.sring->req_prod - prod) >> 1) + 1;
369 mb();
370 } while ((cons == prod) && (prod != xi->rx.sring->rsp_prod));
372 /* if queued packets, send them now?
373 network_maybe_wake_tx(dev); */
375 /* Give netback more buffers */
376 XenNet_AllocRXBuffers(xi);
378 return NDIS_STATUS_SUCCESS;
379 }
381 static BOOLEAN
382 XenNet_Interrupt(
383 PKINTERRUPT Interrupt,
384 PVOID ServiceContext
385 )
386 {
387 struct xennet_info *xi = ServiceContext;
388 // KIRQL KIrql;
390 UNREFERENCED_PARAMETER(Interrupt);
392 KdPrint((__DRIVER_NAME " ***XenNet Interrupt***\n"));
394 if (xi->connected)
395 {
396 XenNet_TxBufferGC(xi);
397 XenNet_RxBufferCheck(xi);
398 }
399 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
400 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
401 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
402 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
403 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
405 /* handle RX packets */
407 return TRUE;
408 }
410 static VOID
411 XenNet_BackEndStateHandler(char *Path, PVOID Data)
412 {
413 struct xennet_info *xi = Data;
414 char *Value;
415 int be_state;
416 char TmpPath[128];
417 xenbus_transaction_t xbt = 0;
418 int retry = 0;
419 char *err;
420 int i;
422 struct set_params {
423 char *name;
424 int value;
425 } params[] = {
426 {"tx-ring-ref", 0},
427 {"rx-ring-ref", 0},
428 {"event-channel", 0},
429 {"request-rx-copy", 1},
430 {"feature-rx-notify", 1},
431 {"feature-no-csum-offload", 1},
432 {"feature-sg", 1},
433 {"feature-gso-tcpv4", 0},
434 {NULL, 0},
435 };
437 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
438 XBT_NIL, Path, &Value);
439 be_state = atoi(Value);
440 ExFreePool(Value);
442 switch (be_state)
443 {
444 case XenbusStateUnknown:
445 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
446 break;
448 case XenbusStateInitialising:
449 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
450 break;
452 case XenbusStateInitWait:
453 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
455 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
456 xi->EvtChnInterface.InterfaceHeader.Context, 0);
457 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
458 xi->event_channel, XenNet_Interrupt, xi);
460 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
461 // or, allocate mem and then get mdl, then free mdl
462 xi->tx_mdl = AllocatePage();
463 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
464 NULL, FALSE, NormalPagePriority);
465 SHARED_RING_INIT(xi->tx_pgs);
466 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
467 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
468 xi->GntTblInterface.InterfaceHeader.Context, 0,
469 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
471 xi->rx_mdl = AllocatePage();
472 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
473 NULL, FALSE, NormalPagePriority);
474 SHARED_RING_INIT(xi->rx_pgs);
475 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
476 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
477 xi->GntTblInterface.InterfaceHeader.Context, 0,
478 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
480 /* fixup array for dynamic values */
481 params[0].value = xi->tx_ring_ref;
482 params[1].value = xi->rx_ring_ref;
483 params[2].value = xi->event_channel;
485 xi->XenBusInterface.StartTransaction(
486 xi->XenBusInterface.InterfaceHeader.Context, &xbt);
488 for (i = 0; params[i].name; i++)
489 {
490 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
491 xi->Path, params[i].name);
492 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
493 XBT_NIL, TmpPath, "%d", params[i].value);
494 if (err)
495 {
496 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
497 goto trouble;
498 }
499 }
501 /* commit transaction */
502 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
503 xbt, 0, &retry);
505 XenNet_AllocRXBuffers(xi);
507 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
508 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
509 xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
510 XBT_NIL, TmpPath, "%d", XenbusStateConnected);
512 /* send fake arp? */
514 xi->connected = TRUE;
516 break;
518 case XenbusStateInitialised:
519 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
520 // create the device
521 break;
523 case XenbusStateConnected:
524 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
526 /* do more stuff here */
528 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
529 break;
531 case XenbusStateClosing:
532 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
533 break;
535 case XenbusStateClosed:
536 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
537 break;
539 default:
540 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", be_state));
541 break;
542 }
544 return;
546 trouble:
547 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
548 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
549 xbt, 1, &retry);
551 }
553 VOID
554 XenNet_Halt(
555 IN NDIS_HANDLE MiniportAdapterContext
556 )
557 {
558 UNREFERENCED_PARAMETER(MiniportAdapterContext);
559 }
561 static NDIS_STATUS
562 XenNet_Init(
563 OUT PNDIS_STATUS OpenErrorStatus,
564 OUT PUINT SelectedMediumIndex,
565 IN PNDIS_MEDIUM MediumArray,
566 IN UINT MediumArraySize,
567 IN NDIS_HANDLE MiniportAdapterHandle,
568 IN NDIS_HANDLE WrapperConfigurationContext
569 )
570 {
571 NDIS_STATUS status;
572 UINT i;
573 BOOLEAN medium_found = FALSE;
574 struct xennet_info *xi = NULL;
575 ULONG length;
576 WDF_OBJECT_ATTRIBUTES wdf_attrs;
577 char *msg;
578 char *Value;
579 char **vif_devs;
580 char TmpPath[128];
582 UNREFERENCED_PARAMETER(OpenErrorStatus);
583 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
585 /* deal with medium stuff */
586 for (i = 0; i < MediumArraySize; i++)
587 {
588 if (MediumArray[i] == NdisMedium802_3)
589 {
590 medium_found = TRUE;
591 break;
592 }
593 }
594 if (!medium_found)
595 {
596 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
597 return NDIS_STATUS_UNSUPPORTED_MEDIA;
598 }
599 *SelectedMediumIndex = i;
601 /* Alloc memory for adapter private info */
602 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
603 if (!NT_SUCCESS(status))
604 {
605 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
606 status = NDIS_STATUS_RESOURCES;
607 goto err;
608 }
609 RtlZeroMemory(xi, sizeof(*xi));
611 /* init xennet_info */
612 xi->adapter_handle = MiniportAdapterHandle;
613 xi->rx_target = RX_DFL_MIN_TARGET;
614 xi->rx_min_target = RX_DFL_MIN_TARGET;
615 xi->rx_max_target = RX_MAX_TARGET;
617 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
618 PROTOCOL_RESERVED_SIZE_IN_PACKET);
619 if (status != NDIS_STATUS_SUCCESS)
620 {
621 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
622 status = NDIS_STATUS_RESOURCES;
623 goto err;
624 }
626 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
627 if (status != NDIS_STATUS_SUCCESS)
628 {
629 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
630 status = NDIS_STATUS_RESOURCES;
631 goto err;
632 }
634 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
635 &xi->lower_do, NULL, NULL);
637 /* Initialise {tx,rx}_pkts as a free chain containing every entry. */
638 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
639 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
640 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
641 }
643 for (i = 0; i < NET_RX_RING_SIZE; i++) {
644 xi->rx_pkts[i] = NULL;
645 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
646 }
648 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
649 NAME_SIZE, xi->name, &length);
650 if (!NT_SUCCESS(status))
651 {
652 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
653 status = NDIS_STATUS_FAILURE;
654 goto err;
655 }
657 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
658 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
659 NdisInterfaceInternal);
661 // status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE,
662 // XN_MAX_PKT_SIZE);
663 // if (!NT_SUCCESS(status))
664 // {
665 // KdPrint(("NdisMInitializeScatterGatherDma failed with 0x%x\n", status));
666 // status = NDIS_STATUS_FAILURE;
667 // goto err;
668 // }
670 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&wdf_attrs, wdf_device_info);
672 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
673 xi->lower_do, xi->pdo, &xi->wdf_device);
674 if (!NT_SUCCESS(status))
675 {
676 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
677 status = NDIS_STATUS_FAILURE;
678 goto err;
679 }
681 GetWdfDeviceInfo(xi->wdf_device)->xennet_info = xi;
683 /* get lower (Xen) interfaces */
685 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
686 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
687 if(!NT_SUCCESS(status))
688 {
689 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
690 status = NDIS_STATUS_FAILURE;
691 goto err;
692 }
694 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
695 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
696 if(!NT_SUCCESS(status))
697 {
698 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
699 status = NDIS_STATUS_FAILURE;
700 goto err;
701 }
703 #if 0
704 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
705 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
706 if(!NT_SUCCESS(status))
707 {
708 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
709 status = NDIS_STATUS_FAILURE;
710 goto err;
711 }
712 #endif
714 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
715 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
716 if(!NT_SUCCESS(status))
717 {
718 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
719 status = NDIS_STATUS_FAILURE;
720 goto err;
721 }
723 msg = xi->XenBusInterface.List(xi->EvtChnInterface.InterfaceHeader.Context,
724 XBT_NIL, "device/vif", &vif_devs);
725 if (msg)
726 {
727 KdPrint((__DRIVER_NAME ": " __FUNCTION__ ": List retval is nonzero!\n"));
728 status = NDIS_STATUS_FAILURE;
729 goto err;
730 }
732 for (i = 0; vif_devs[i]; i++)
733 {
734 if (i > 0)
735 {
736 KdPrint((__DRIVER_NAME "Can only handle 1 vif so far, ignoring vif %s\n", vif_devs[i]));
737 continue;
738 }
739 RtlStringCbPrintfA(xi->Path, ARRAY_SIZE(xi->Path), "device/vif/%s", vif_devs[i]);
741 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
742 "device/vif/%s/state", vif_devs[i]);
743 KdPrint(("%s\n", TmpPath));
745 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/backend", xi->Path);
746 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
747 XBT_NIL, TmpPath, &Value);
748 if (!Value)
749 {
750 KdPrint((__DRIVER_NAME " backend Read Failed\n"));
751 }
752 else
753 {
754 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
755 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
756 }
757 ExFreePool(Value);
759 /* Add watch on backend state */
760 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
761 xi->XenBusInterface.AddWatch(xi->XenBusInterface.InterfaceHeader.Context,
762 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
764 /* get mac address */
765 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->Path);
766 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
767 XBT_NIL, TmpPath, &Value);
768 if (!Value)
769 {
770 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
771 }
772 else
773 {
774 char *s, *e;
775 int i;
777 s = Value;
779 for (i = 0; i < ETH_ALEN; i++) {
780 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
781 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
782 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
783 ExFreePool(Value);
784 ExFreePool(vif_devs);
785 status = NDIS_STATUS_FAILURE;
786 goto err;
787 }
788 s = e + 1;
789 }
790 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
791 }
792 ExFreePool(Value);
794 //XenVbd_HotPlugHandler(buffer, NULL);
795 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
796 }
797 ExFreePool(vif_devs);
799 return NDIS_STATUS_SUCCESS;
801 err:
802 NdisFreeMemory(xi, 0, 0);
803 return status;
804 }
806 NDIS_OID supported_oids[] =
807 {
808 OID_GEN_SUPPORTED_LIST,
809 OID_GEN_HARDWARE_STATUS,
810 OID_GEN_MEDIA_SUPPORTED,
811 OID_GEN_MEDIA_IN_USE,
812 OID_GEN_MAXIMUM_LOOKAHEAD,
813 OID_GEN_MAXIMUM_FRAME_SIZE,
814 OID_GEN_LINK_SPEED,
815 OID_GEN_TRANSMIT_BUFFER_SPACE,
816 OID_GEN_RECEIVE_BUFFER_SPACE,
817 OID_GEN_TRANSMIT_BLOCK_SIZE,
818 OID_GEN_RECEIVE_BLOCK_SIZE,
819 OID_GEN_VENDOR_ID,
820 OID_GEN_VENDOR_DESCRIPTION,
821 OID_GEN_CURRENT_PACKET_FILTER,
822 OID_GEN_CURRENT_LOOKAHEAD,
823 OID_GEN_DRIVER_VERSION,
824 OID_GEN_MAXIMUM_TOTAL_SIZE,
825 OID_GEN_MAC_OPTIONS,
826 OID_GEN_MEDIA_CONNECT_STATUS,
827 OID_GEN_MAXIMUM_SEND_PACKETS,
828 OID_802_3_PERMANENT_ADDRESS,
829 OID_802_3_CURRENT_ADDRESS,
830 OID_802_3_MULTICAST_LIST,
831 OID_802_3_MAXIMUM_LIST_SIZE,
832 };
834 NDIS_STATUS
835 XenNet_QueryInformation(
836 IN NDIS_HANDLE MiniportAdapterContext,
837 IN NDIS_OID Oid,
838 IN PVOID InformationBuffer,
839 IN ULONG InformationBufferLength,
840 OUT PULONG BytesWritten,
841 OUT PULONG BytesNeeded)
842 {
843 struct xennet_info *xi = MiniportAdapterContext;
844 UCHAR vendor_desc[] = XN_VENDOR_DESC;
845 ULONG temp_data;
846 PVOID data = &temp_data;
847 UINT len = sizeof(temp_data);
848 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
850 switch(Oid)
851 {
852 case OID_GEN_SUPPORTED_LIST:
853 data = supported_oids;
854 len = sizeof(supported_oids);
855 break;
856 case OID_GEN_HARDWARE_STATUS:
857 temp_data = NdisHardwareStatusReady;
858 break;
859 case OID_GEN_MEDIA_SUPPORTED:
860 temp_data = NdisMedium802_3;
861 break;
862 case OID_GEN_MEDIA_IN_USE:
863 temp_data = NdisMedium802_3;
864 break;
865 case OID_GEN_MAXIMUM_LOOKAHEAD:
866 temp_data = XN_DATA_SIZE;
867 break;
868 case OID_GEN_MAXIMUM_FRAME_SIZE:
869 temp_data = XN_MAX_PKT_SIZE;
870 break;
871 case OID_GEN_LINK_SPEED:
872 temp_data = 10000000; /* 1Gb */
873 break;
874 case OID_GEN_TRANSMIT_BUFFER_SPACE:
875 /* pkts times sizeof ring, maybe? */
876 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
877 break;
878 case OID_GEN_RECEIVE_BUFFER_SPACE:
879 /* pkts times sizeof ring, maybe? */
880 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
881 break;
882 case OID_GEN_TRANSMIT_BLOCK_SIZE:
883 temp_data = XN_MAX_PKT_SIZE;
884 break;
885 case OID_GEN_RECEIVE_BLOCK_SIZE:
886 temp_data = XN_MAX_PKT_SIZE;
887 break;
888 case OID_GEN_VENDOR_ID:
889 temp_data = XENSOURCE_MAC_HDR;
890 break;
891 case OID_GEN_VENDOR_DESCRIPTION:
892 data = vendor_desc;
893 len = sizeof(vendor_desc);
894 break;
895 case OID_GEN_CURRENT_PACKET_FILTER:
896 temp_data = xi->packet_filter;
897 break;
898 case OID_GEN_CURRENT_LOOKAHEAD:
899 temp_data = XN_MAX_PKT_SIZE;
900 break;
901 case OID_GEN_DRIVER_VERSION:
902 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
903 len = 2;
904 break;
905 case OID_GEN_MAXIMUM_TOTAL_SIZE:
906 temp_data = XN_MAX_PKT_SIZE;
907 break;
908 case OID_GEN_MAC_OPTIONS:
909 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
910 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
911 NDIS_MAC_OPTION_NO_LOOPBACK;
912 break;
913 case OID_GEN_MEDIA_CONNECT_STATUS:
914 if (xi->connected)
915 temp_data = NdisMediaStateConnected;
916 else
917 temp_data = NdisMediaStateDisconnected;
918 break;
919 case OID_GEN_MAXIMUM_SEND_PACKETS:
920 temp_data = XN_MAX_SEND_PKTS;
921 break;
922 case OID_802_3_PERMANENT_ADDRESS:
923 data = xi->perm_mac_addr;
924 len = ETH_ALEN;
925 break;
926 case OID_802_3_CURRENT_ADDRESS:
927 data = xi->curr_mac_addr;
928 len = ETH_ALEN;
929 break;
930 case OID_802_3_MULTICAST_LIST:
931 data = NULL;
932 len = 0;
933 case OID_802_3_MAXIMUM_LIST_SIZE:
934 temp_data = 0; /* no mcast support */
935 break;
936 default:
937 //KdPrint(("Unknown OID 0x%x\n", Oid));
938 status = NDIS_STATUS_NOT_SUPPORTED;
939 }
941 if (!NT_SUCCESS(status))
942 {
943 return status;
944 }
946 if (len > InformationBufferLength)
947 {
948 *BytesNeeded = len;
949 return NDIS_STATUS_BUFFER_TOO_SHORT;
950 }
952 *BytesWritten = len;
953 if (len)
954 {
955 NdisMoveMemory(InformationBuffer, data, len);
956 }
958 KdPrint(("Got OID 0x%x\n", Oid));
960 return status;
961 }
963 NDIS_STATUS
964 XenNet_SetInformation(
965 IN NDIS_HANDLE MiniportAdapterContext,
966 IN NDIS_OID Oid,
967 IN PVOID InformationBuffer,
968 IN ULONG InformationBufferLength,
969 OUT PULONG BytesRead,
970 OUT PULONG BytesNeeded
971 )
972 {
973 UNREFERENCED_PARAMETER(MiniportAdapterContext);
974 UNREFERENCED_PARAMETER(Oid);
975 UNREFERENCED_PARAMETER(InformationBuffer);
976 UNREFERENCED_PARAMETER(InformationBufferLength);
977 UNREFERENCED_PARAMETER(BytesRead);
978 UNREFERENCED_PARAMETER(BytesNeeded);
980 KdPrint((__FUNCTION__ " called with OID=0x%x\n", Oid));
981 return NDIS_STATUS_SUCCESS;
982 }
984 VOID
985 XenNet_ReturnPacket(
986 IN NDIS_HANDLE MiniportAdapterContext,
987 IN PNDIS_PACKET Packet
988 )
989 {
990 PNDIS_BUFFER buffer;
991 PVOID buff_va;
992 UINT buff_len;
993 UINT tot_buff_len;
995 UNREFERENCED_PARAMETER(MiniportAdapterContext);
997 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
998 &tot_buff_len, NormalPagePriority);
999 ASSERT(buff_len == tot_buff_len);
1001 NdisFreeMemory(buff_va, 0, 0);
1002 NdisFreeBuffer(buffer);
1003 NdisFreePacket(Packet);
1005 KdPrint((__FUNCTION__ " called\n"));
1008 PMDL
1009 XenNet_Linearize(PNDIS_PACKET Packet)
1011 PMDL pmdl;
1012 char *start;
1013 PNDIS_BUFFER buffer;
1014 PVOID buff_va;
1015 UINT buff_len;
1016 UINT tot_buff_len;
1018 pmdl = AllocatePage();
1020 start = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
1021 if (!start)
1023 return NULL;
1026 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1027 &tot_buff_len, NormalPagePriority);
1028 ASSERT(tot_buff_len <= PAGE_SIZE);
1030 while (buffer)
1032 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1033 RtlCopyMemory(start, buff_va, buff_len);
1034 start += buff_len;
1035 NdisGetNextBuffer(buffer, &buffer);
1038 return pmdl;
1041 VOID
1042 XenNet_SendPackets(
1043 IN NDIS_HANDLE MiniportAdapterContext,
1044 IN PPNDIS_PACKET PacketArray,
1045 IN UINT NumberOfPackets
1048 /* for each packet:
1049 req_prod_pvt is the next entry in the cmd ring to use
1050 add pkt to array of saved packets
1051 fill out tx request for the first part of skb
1052 add to grant table
1053 do flags for csum etc
1054 gso (later)
1055 inc req_prod_pvt
1056 frags
1057 possibly notify
1058 network_tx)buf_gc
1059 stop netif if no more room
1060 */
1061 struct xennet_info *xi = MiniportAdapterContext;
1062 PNDIS_PACKET curr_packet;
1063 UINT i;
1064 struct netif_tx_request *tx;
1065 unsigned short id;
1066 int notify;
1067 PMDL pmdl;
1068 UINT pkt_size;
1070 KdPrint((__FUNCTION__ " called, sending %d pkts\n", NumberOfPackets));
1072 for (i = 0; i < NumberOfPackets; i++)
1074 curr_packet = PacketArray[i];
1075 ASSERT(curr_packet);
1077 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
1079 pmdl = XenNet_Linearize(curr_packet);
1080 if (!pmdl)
1082 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1083 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1084 break;
1086 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
1088 id = get_id_from_freelist(xi->tx_pkts);
1089 xi->tx_pkts[id] = curr_packet;
1091 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1092 tx->id = id;
1093 tx->gref = xi->GntTblInterface.GrantAccess(
1094 xi->GntTblInterface.InterfaceHeader.Context,
1095 0,
1096 *MmGetMdlPfnArray(pmdl),
1097 TRUE);
1098 xi->grant_tx_ref[id] = tx->gref;
1099 tx->offset = 0;
1100 tx->size = (UINT16)pkt_size;
1101 tx->flags = NETTXF_csum_blank;
1103 xi->tx.req_prod_pvt++;
1105 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
1106 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
1109 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1110 if (notify)
1112 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
1113 xi->event_channel);
1117 VOID
1118 XenNet_PnPEventNotify(
1119 IN NDIS_HANDLE MiniportAdapterContext,
1120 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1121 IN PVOID InformationBuffer,
1122 IN ULONG InformationBufferLength
1125 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1126 UNREFERENCED_PARAMETER(PnPEvent);
1127 UNREFERENCED_PARAMETER(InformationBuffer);
1128 UNREFERENCED_PARAMETER(InformationBufferLength);
1130 KdPrint((__FUNCTION__ " called\n"));
1133 VOID
1134 XenNet_Shutdown(
1135 IN NDIS_HANDLE MiniportAdapterContext
1138 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1140 KdPrint((__FUNCTION__ " called\n"));
1143 NTSTATUS
1144 DriverEntry(
1145 PDRIVER_OBJECT DriverObject,
1146 PUNICODE_STRING RegistryPath
1149 NTSTATUS status;
1150 WDF_DRIVER_CONFIG config;
1151 NDIS_HANDLE ndis_wrapper_handle;
1152 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1154 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1156 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1157 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1159 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1160 &config, WDF_NO_HANDLE);
1161 if (!NT_SUCCESS(status))
1163 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1164 return status;
1167 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1168 if (!ndis_wrapper_handle)
1170 KdPrint(("NdisMInitializeWrapper failed\n"));
1171 return NDIS_STATUS_FAILURE;
1174 /* NDIS 5.1 driver */
1175 mini_chars.MajorNdisVersion = 5;
1176 mini_chars.MinorNdisVersion = 1;
1178 mini_chars.HaltHandler = XenNet_Halt;
1179 mini_chars.InitializeHandler = XenNet_Init;
1180 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1181 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1182 mini_chars.ResetHandler = NULL; //TODO: fill in
1183 mini_chars.SetInformationHandler = XenNet_SetInformation;
1184 /* added in v.4 -- use multiple pkts interface */
1185 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1186 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1187 /* added in v.5.1 */
1188 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1189 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1191 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1193 /* set up upper-edge interface */
1194 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1195 if (!NT_SUCCESS(status))
1197 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1198 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1199 return status;
1202 return status;