win-pvdrivers

view xennet/xennet.c @ 43:59691f2a99f6

xennet: rough-in RX support (compiles, not debugged)
author Andy Grover <andy.grover@oracle.com>
date Wed Dec 12 16:58:09 2007 -0800 (2007-12-12)
parents 5dc3e004cf94
children 01f874217465
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 PMDL pmdl;
256 PVOID start;
258 if (!xi->connected)
259 return NDIS_STATUS_FAILURE;
261 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
262 for (i = 0; i < batch_target; i++)
263 {
264 /*
265 * Allocate a packet, page, and buffer. Hook them up.
266 */
267 NdisAllocatePacket(&status, &packet, xi->packet_pool);
268 if (status != NDIS_STATUS_SUCCESS)
269 {
270 KdPrint(("NdisAllocatePacket Failed! status = 0x%x\n", status));
271 break;
272 }
273 pmdl = AllocatePage();
274 start = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
275 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
276 if (status != NDIS_STATUS_SUCCESS)
277 {
278 KdPrint(("NdisAllocateBuffer Failed! status = 0x%x\n", status));
279 /* TODO: free mdl, page, packet here */
280 break;
281 }
282 NdisChainBufferAtBack(packet, buffer);
284 /* Give to netback */
285 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
286 ASSERT(!xi->rx_pkts[id]);
287 xi->rx_pkts[id] = packet;
288 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
289 ref = xi->GntTblInterface.GrantAccess(
290 xi->GntTblInterface.InterfaceHeader.Context, 0,
291 *MmGetMdlPfnArray(pmdl), FALSE);
292 ASSERT((signed short)ref >= 0);
293 xi->grant_rx_ref[id] = ref;
295 req->id = id;
296 req->gref = ref;
297 }
299 xi->rx.req_prod_pvt = req_prod + i;
300 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
301 if (notify)
302 {
303 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
304 xi->event_channel);
305 }
307 return NDIS_STATUS_SUCCESS;
308 }
310 static NDIS_STATUS
311 XenNet_RxBufferCheck(struct xennet_info *xi)
312 {
313 RING_IDX cons, prod;
315 unsigned short id;
316 PNDIS_PACKET pkt;
317 PNDIS_PACKET packets[1];
318 PNDIS_BUFFER buffer;
319 PVOID buff_va;
320 UINT buff_len;
321 UINT tot_buff_len;
323 ASSERT(xi->connected);
325 do {
326 prod = xi->rx.sring->rsp_prod;
327 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
329 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
330 struct netif_rx_response *rxrsp;
332 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
333 if (rxrsp->status == NETIF_RSP_NULL)
334 continue;
336 id = rxrsp->id;
337 pkt = xi->rx_pkts[id];
338 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
339 xi->grant_rx_ref[id]);
340 xi->grant_rx_ref[id] = GRANT_INVALID_REF;
341 //add_id_to_freelist(xi->rx_pkts, id);
343 NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
344 &tot_buff_len, NormalPagePriority);
345 ASSERT(rxrsp->offset == 0);
346 ASSERT(rxrsp->status > 0);
347 NdisAdjustBufferLength(buffer, rxrsp->status);
348 /* just indicate 1 packet for now */
349 packets[0] = pkt;
351 NdisMIndicateReceivePacket(xi->adapter_handle, packets, 1);
352 }
354 xi->rx.rsp_cons = prod;
356 /*
357 * Set a new event, then check for race with update of rx_cons.
358 * Note that it is essential to schedule a callback, no matter
359 * how few buffers are pending. Even if there is space in the
360 * transmit ring, higher layers may be blocked because too much
361 * data is outstanding: in such cases notification from Xen is
362 * likely to be the only kick that we'll get.
363 */
364 xi->rx.sring->rsp_event =
365 prod + ((xi->rx.sring->req_prod - prod) >> 1) + 1;
366 mb();
367 } while ((cons == prod) && (prod != xi->rx.sring->rsp_prod));
369 /* if queued packets, send them now?
370 network_maybe_wake_tx(dev); */
372 /* Give netback more buffers */
373 XenNet_AllocRXBuffers(xi);
375 return NDIS_STATUS_SUCCESS;
376 }
378 static BOOLEAN
379 XenNet_Interrupt(
380 PKINTERRUPT Interrupt,
381 PVOID ServiceContext
382 )
383 {
384 struct xennet_info *xi = ServiceContext;
385 // KIRQL KIrql;
387 UNREFERENCED_PARAMETER(Interrupt);
389 KdPrint((__DRIVER_NAME " ***XenNet Interrupt***\n"));
391 if (xi->connected)
392 {
393 XenNet_TxBufferGC(xi);
394 XenNet_RxBufferCheck(xi);
395 }
396 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
397 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
398 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
399 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
400 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
402 /* handle RX packets */
404 return TRUE;
405 }
407 static VOID
408 XenNet_BackEndStateHandler(char *Path, PVOID Data)
409 {
410 struct xennet_info *xi = Data;
411 char *Value;
412 int be_state;
413 char TmpPath[128];
414 xenbus_transaction_t xbt = 0;
415 int retry = 0;
416 char *err;
417 int i;
419 struct set_params {
420 char *name;
421 int value;
422 } params[] = {
423 {"tx-ring-ref", 0},
424 {"rx-ring-ref", 0},
425 {"event-channel", 0},
426 {"request-rx-copy", 1},
427 {"feature-rx-notify", 1},
428 {"feature-no-csum-offload", 1},
429 {"feature-sg", 1},
430 {"feature-gso-tcpv4", 0},
431 {NULL, 0},
432 };
434 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
435 XBT_NIL, Path, &Value);
436 be_state = atoi(Value);
437 ExFreePool(Value);
439 switch (be_state)
440 {
441 case XenbusStateUnknown:
442 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
443 break;
445 case XenbusStateInitialising:
446 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
447 break;
449 case XenbusStateInitWait:
450 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
452 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
453 xi->EvtChnInterface.InterfaceHeader.Context, 0);
454 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
455 xi->event_channel, XenNet_Interrupt, xi);
457 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
458 // or, allocate mem and then get mdl, then free mdl
459 xi->tx_mdl = AllocatePage();
460 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
461 NULL, FALSE, NormalPagePriority);
462 SHARED_RING_INIT(xi->tx_pgs);
463 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
464 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
465 xi->GntTblInterface.InterfaceHeader.Context, 0,
466 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
468 xi->rx_mdl = AllocatePage();
469 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
470 NULL, FALSE, NormalPagePriority);
471 SHARED_RING_INIT(xi->rx_pgs);
472 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
473 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
474 xi->GntTblInterface.InterfaceHeader.Context, 0,
475 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
477 /* fixup array for dynamic values */
478 params[0].value = xi->tx_ring_ref;
479 params[1].value = xi->rx_ring_ref;
480 params[2].value = xi->event_channel;
482 xi->XenBusInterface.StartTransaction(
483 xi->XenBusInterface.InterfaceHeader.Context, &xbt);
485 for (i = 0; params[i].name; i++)
486 {
487 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
488 xi->Path, params[i].name);
489 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
490 XBT_NIL, TmpPath, "%d", params[i].value);
491 if (err)
492 {
493 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
494 goto trouble;
495 }
496 }
498 /* commit transaction */
499 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
500 xbt, 0, &retry);
502 /* TODO: prepare tx and rx rings */
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 struct xennet_info *xi = MiniportAdapterContext;
990 xi;
991 UNREFERENCED_PARAMETER(Packet);
992 /* free memory page */
993 /* free buffer */
994 /* free packet */
996 KdPrint((__FUNCTION__ " called\n"));
997 }
999 PMDL
1000 XenNet_Linearize(PNDIS_PACKET Packet)
1002 PMDL pmdl;
1003 char *start;
1004 PNDIS_BUFFER buffer;
1005 PVOID buff_va;
1006 UINT buff_len;
1007 UINT tot_buff_len;
1009 pmdl = AllocatePage();
1011 start = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
1012 if (!start)
1014 return NULL;
1017 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1018 &tot_buff_len, NormalPagePriority);
1019 ASSERT(tot_buff_len <= PAGE_SIZE);
1021 while (buffer)
1023 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1024 RtlCopyMemory(start, buff_va, buff_len);
1025 start += buff_len;
1026 NdisGetNextBuffer(buffer, &buffer);
1029 return pmdl;
1032 VOID
1033 XenNet_SendPackets(
1034 IN NDIS_HANDLE MiniportAdapterContext,
1035 IN PPNDIS_PACKET PacketArray,
1036 IN UINT NumberOfPackets
1039 /* for each packet:
1040 req_prod_pvt is the next entry in the cmd ring to use
1041 add pkt to array of saved packets
1042 fill out tx request for the first part of skb
1043 add to grant table
1044 do flags for csum etc
1045 gso (later)
1046 inc req_prod_pvt
1047 frags
1048 possibly notify
1049 network_tx)buf_gc
1050 stop netif if no more room
1051 */
1052 struct xennet_info *xi = MiniportAdapterContext;
1053 PNDIS_PACKET curr_packet;
1054 UINT i;
1055 struct netif_tx_request *tx;
1056 unsigned short id;
1057 PFN_NUMBER pfn;
1058 int notify;
1059 PMDL pmdl;
1060 UINT pkt_size;
1062 KdPrint((__FUNCTION__ " called, sending %d pkts\n", NumberOfPackets));
1064 for (i = 0; i < NumberOfPackets; i++)
1066 curr_packet = PacketArray[i];
1067 ASSERT(curr_packet);
1069 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
1071 pmdl = XenNet_Linearize(curr_packet);
1072 if (!pmdl)
1074 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1075 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1076 break;
1078 pfn = *MmGetMdlPfnArray(pmdl);
1080 id = get_id_from_freelist(xi->tx_pkts);
1081 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
1082 xi->tx_pkts[id] = curr_packet;
1084 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1085 tx->id = id;
1086 tx->gref = xi->GntTblInterface.GrantAccess(
1087 xi->GntTblInterface.InterfaceHeader.Context,
1088 0,
1089 pfn,
1090 TRUE);
1091 xi->grant_tx_ref[id] = tx->gref;
1092 tx->offset = 0;
1093 tx->size = (UINT16)pkt_size;
1094 tx->flags = NETTXF_csum_blank;
1096 xi->tx.req_prod_pvt++;
1098 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
1099 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
1102 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1103 if (notify)
1105 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
1106 xi->event_channel);
1110 VOID
1111 XenNet_PnPEventNotify(
1112 IN NDIS_HANDLE MiniportAdapterContext,
1113 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1114 IN PVOID InformationBuffer,
1115 IN ULONG InformationBufferLength
1118 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1119 UNREFERENCED_PARAMETER(PnPEvent);
1120 UNREFERENCED_PARAMETER(InformationBuffer);
1121 UNREFERENCED_PARAMETER(InformationBufferLength);
1123 KdPrint((__FUNCTION__ " called\n"));
1126 VOID
1127 XenNet_Shutdown(
1128 IN NDIS_HANDLE MiniportAdapterContext
1131 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1133 KdPrint((__FUNCTION__ " called\n"));
1136 NTSTATUS
1137 DriverEntry(
1138 PDRIVER_OBJECT DriverObject,
1139 PUNICODE_STRING RegistryPath
1142 NTSTATUS status;
1143 WDF_DRIVER_CONFIG config;
1144 NDIS_HANDLE ndis_wrapper_handle;
1145 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1147 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1149 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1150 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1152 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1153 &config, WDF_NO_HANDLE);
1154 if (!NT_SUCCESS(status))
1156 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1157 return status;
1160 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1161 if (!ndis_wrapper_handle)
1163 KdPrint(("NdisMInitializeWrapper failed\n"));
1164 return NDIS_STATUS_FAILURE;
1167 /* NDIS 5.1 driver */
1168 mini_chars.MajorNdisVersion = 5;
1169 mini_chars.MinorNdisVersion = 1;
1171 mini_chars.HaltHandler = XenNet_Halt;
1172 mini_chars.InitializeHandler = XenNet_Init;
1173 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1174 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1175 mini_chars.ResetHandler = NULL; //TODO: fill in
1176 mini_chars.SetInformationHandler = XenNet_SetInformation;
1177 /* added in v.4 -- use multiple pkts interface */
1178 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1179 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1180 /* added in v.5.1 */
1181 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1182 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1184 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1186 /* set up upper-edge interface */
1187 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1188 if (!NT_SUCCESS(status))
1190 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1191 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1192 return status;
1195 return status;