win-pvdrivers

view xennet/xennet.c @ 69:a41314faf255

xennet: only allocate as much memory as needed for linearization, not a whole page
author Andy Grover <andy.grover@oracle.com>
date Wed Dec 19 13:01:04 2007 -0800 (2007-12-19)
parents fd2827973086
children 06b4321b7068
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 /* Xen macros use these, so they need to be redefined to Win equivs */
26 #define wmb() KeMemoryBarrier()
27 #define mb() KeMemoryBarrier()
29 #if !defined (NDIS51_MINIPORT)
30 #error requires NDIS 5.1 compilation environment
31 #endif
33 #define GRANT_INVALID_REF 0
35 /* couldn't get regular xen ring macros to work...*/
36 #define __NET_RING_SIZE(type, _sz) \
37 (__RD32( \
38 (_sz - sizeof(struct type##_sring) + sizeof(union type##_sring_entry)) \
39 / sizeof(union type##_sring_entry)))
41 #define NET_TX_RING_SIZE __NET_RING_SIZE(netif_tx, PAGE_SIZE)
42 #define NET_RX_RING_SIZE __NET_RING_SIZE(netif_rx, PAGE_SIZE)
44 #pragma warning(disable: 4127) // conditional expression is constant
46 struct xennet_info
47 {
48 PDEVICE_OBJECT pdo;
49 PDEVICE_OBJECT fdo;
50 PDEVICE_OBJECT lower_do;
51 WDFDEVICE wdf_device;
53 WCHAR name[NAME_SIZE];
54 NDIS_HANDLE adapter_handle;
55 ULONG packet_filter;
56 int connected;
57 UINT8 perm_mac_addr[ETH_ALEN];
58 UINT8 curr_mac_addr[ETH_ALEN];
60 char Path[128];
61 char BackendPath[128];
62 XEN_IFACE_EVTCHN EvtChnInterface;
63 XEN_IFACE_XENBUS XenBusInterface;
64 XEN_IFACE_XEN XenInterface;
65 XEN_IFACE_GNTTBL GntTblInterface;
67 /* ring control structures */
68 struct netif_tx_front_ring tx;
69 struct netif_rx_front_ring rx;
71 /* ptrs to the actual rings themselvves */
72 struct netif_tx_sring *tx_pgs;
73 struct netif_rx_sring *rx_pgs;
75 /* MDLs for the above */
76 PMDL tx_mdl;
77 PMDL rx_mdl;
79 /* Outstanding packets. The first entry in tx_pkts
80 * is an index into a chain of free entries. */
81 PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE];
82 PNDIS_PACKET rx_pkts[NET_RX_RING_SIZE];
84 grant_ref_t gref_tx_head;
85 grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
86 grant_ref_t gref_rx_head;
87 grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
89 UINT irq;
90 evtchn_port_t event_channel;
92 grant_ref_t tx_ring_ref;
93 grant_ref_t rx_ring_ref;
95 /* Receive-ring batched refills. */
96 #define RX_MIN_TARGET 8
97 #define RX_DFL_MIN_TARGET 64
98 #define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
99 ULONG rx_target;
100 ULONG rx_max_target;
101 ULONG rx_min_target;
103 NDIS_HANDLE packet_pool;
104 NDIS_HANDLE buffer_pool;
106 /* stats */
107 ULONG64 stat_tx_ok;
108 ULONG64 stat_rx_ok;
109 ULONG64 stat_tx_error;
110 ULONG64 stat_rx_error;
111 ULONG64 stat_rx_no_buffer;
112 };
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;
190 unsigned short id;
191 PNDIS_PACKET pkt;
192 PMDL pmdl;
194 ASSERT(xi->connected);
196 do {
197 prod = xi->tx.sring->rsp_prod;
198 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
200 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
201 struct netif_tx_response *txrsp;
203 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
204 if (txrsp->status == NETIF_RSP_NULL)
205 continue;
207 id = txrsp->id;
208 pkt = xi->tx_pkts[id];
209 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
210 xi->grant_tx_ref[id]);
211 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
212 add_id_to_freelist(xi->tx_pkts, id);
214 /* free linearized data page */
215 pmdl = *(PMDL *)pkt->MiniportReservedEx;
216 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0);
217 IoFreeMdl(pmdl);
219 xi->stat_tx_ok++;
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 KeMemoryBarrier();
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);
285 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
287 /* Give to netback */
288 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
289 ASSERT(!xi->rx_pkts[id]);
290 xi->rx_pkts[id] = packet;
291 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
292 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
293 ref = xi->GntTblInterface.GrantAccess(
294 xi->GntTblInterface.InterfaceHeader.Context, 0,
295 *MmGetMdlPfnArray(buffer), FALSE);
296 ASSERT((signed short)ref >= 0);
297 xi->grant_rx_ref[id] = ref;
299 req->id = id;
300 req->gref = ref;
301 }
303 xi->rx.req_prod_pvt = req_prod + i;
304 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
305 if (notify)
306 {
307 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
308 xi->event_channel);
309 }
311 return NDIS_STATUS_SUCCESS;
312 }
314 static NDIS_STATUS
315 XenNet_RxBufferCheck(struct xennet_info *xi)
316 {
317 RING_IDX cons, prod;
319 PNDIS_PACKET pkt;
320 PNDIS_BUFFER buffer;
321 PVOID buff_va;
322 UINT buff_len;
323 UINT tot_buff_len;
325 ASSERT(xi->connected);
327 do {
328 prod = xi->rx.sring->rsp_prod;
329 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
331 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
332 struct netif_rx_response *rxrsp;
334 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
335 if (rxrsp->status == NETIF_RSP_NULL)
336 continue;
338 pkt = xi->rx_pkts[rxrsp->id];
339 xi->rx_pkts[rxrsp->id] = NULL;
340 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
341 xi->grant_rx_ref[rxrsp->id]);
342 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
344 NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
345 &tot_buff_len, NormalPagePriority);
346 ASSERT(rxrsp->offset == 0);
347 ASSERT(rxrsp->status > 0);
348 NdisAdjustBufferLength(buffer, rxrsp->status);
350 xi->stat_rx_ok++;
351 NDIS_SET_PACKET_STATUS(pkt, NDIS_STATUS_SUCCESS);
353 /* just indicate 1 packet for now */
354 NdisMIndicateReceivePacket(xi->adapter_handle, &pkt, 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 KeMemoryBarrier();
370 } while ((cons == prod) && (prod != xi->rx.sring->rsp_prod));
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 return TRUE;
403 }
405 static VOID
406 XenNet_BackEndStateHandler(char *Path, PVOID Data)
407 {
408 struct xennet_info *xi = Data;
409 char *Value;
410 int be_state;
411 char TmpPath[128];
412 xenbus_transaction_t xbt = 0;
413 int retry = 0;
414 char *err;
415 int i;
417 struct set_params {
418 char *name;
419 int value;
420 } params[] = {
421 {"tx-ring-ref", 0},
422 {"rx-ring-ref", 0},
423 {"event-channel", 0},
424 {"request-rx-copy", 1},
425 {"feature-rx-notify", 1},
426 {"feature-no-csum-offload", 1},
427 {"feature-sg", 1},
428 {"feature-gso-tcpv4", 0},
429 {NULL, 0},
430 };
432 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
433 XBT_NIL, Path, &Value);
434 be_state = atoi(Value);
435 ExFreePool(Value);
437 switch (be_state)
438 {
439 case XenbusStateUnknown:
440 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
441 break;
443 case XenbusStateInitialising:
444 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
445 break;
447 case XenbusStateInitWait:
448 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
450 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
451 xi->EvtChnInterface.InterfaceHeader.Context, 0);
452 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
453 xi->event_channel, XenNet_Interrupt, xi);
455 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
456 // or, allocate mem and then get mdl, then free mdl
457 xi->tx_mdl = AllocatePage();
458 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
459 NULL, FALSE, NormalPagePriority);
460 SHARED_RING_INIT(xi->tx_pgs);
461 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
462 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
463 xi->GntTblInterface.InterfaceHeader.Context, 0,
464 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
466 xi->rx_mdl = AllocatePage();
467 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
468 NULL, FALSE, NormalPagePriority);
469 SHARED_RING_INIT(xi->rx_pgs);
470 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
471 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
472 xi->GntTblInterface.InterfaceHeader.Context, 0,
473 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
475 /* fixup array for dynamic values */
476 params[0].value = xi->tx_ring_ref;
477 params[1].value = xi->rx_ring_ref;
478 params[2].value = xi->event_channel;
480 xi->XenBusInterface.StartTransaction(
481 xi->XenBusInterface.InterfaceHeader.Context, &xbt);
483 for (i = 0; params[i].name; i++)
484 {
485 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
486 xi->Path, params[i].name);
487 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
488 XBT_NIL, TmpPath, "%d", params[i].value);
489 if (err)
490 {
491 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
492 goto trouble;
493 }
494 }
496 /* commit transaction */
497 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
498 xbt, 0, &retry);
500 XenNet_AllocRXBuffers(xi);
502 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
503 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
504 xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
505 XBT_NIL, TmpPath, "%d", XenbusStateConnected);
507 /* send fake arp? */
509 xi->connected = TRUE;
511 break;
513 case XenbusStateInitialised:
514 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
515 break;
517 case XenbusStateConnected:
518 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
519 break;
521 case XenbusStateClosing:
522 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
523 break;
525 case XenbusStateClosed:
526 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
527 break;
529 default:
530 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", be_state));
531 break;
532 }
534 return;
536 trouble:
537 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
538 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
539 xbt, 1, &retry);
541 }
543 VOID
544 XenNet_Halt(
545 IN NDIS_HANDLE MiniportAdapterContext
546 )
547 {
548 UNREFERENCED_PARAMETER(MiniportAdapterContext);
549 }
551 static NDIS_STATUS
552 XenNet_Init(
553 OUT PNDIS_STATUS OpenErrorStatus,
554 OUT PUINT SelectedMediumIndex,
555 IN PNDIS_MEDIUM MediumArray,
556 IN UINT MediumArraySize,
557 IN NDIS_HANDLE MiniportAdapterHandle,
558 IN NDIS_HANDLE WrapperConfigurationContext
559 )
560 {
561 NDIS_STATUS status;
562 UINT i;
563 BOOLEAN medium_found = FALSE;
564 struct xennet_info *xi = NULL;
565 ULONG length;
566 WDF_OBJECT_ATTRIBUTES wdf_attrs;
567 char *msg;
568 char *Value;
569 char **vif_devs;
570 char TmpPath[128];
572 UNREFERENCED_PARAMETER(OpenErrorStatus);
573 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
575 /* deal with medium stuff */
576 for (i = 0; i < MediumArraySize; i++)
577 {
578 if (MediumArray[i] == NdisMedium802_3)
579 {
580 medium_found = TRUE;
581 break;
582 }
583 }
584 if (!medium_found)
585 {
586 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
587 return NDIS_STATUS_UNSUPPORTED_MEDIA;
588 }
589 *SelectedMediumIndex = i;
591 /* Alloc memory for adapter private info */
592 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
593 if (!NT_SUCCESS(status))
594 {
595 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
596 status = NDIS_STATUS_RESOURCES;
597 goto err;
598 }
599 RtlZeroMemory(xi, sizeof(*xi));
601 /* init xennet_info */
602 xi->adapter_handle = MiniportAdapterHandle;
603 xi->rx_target = RX_DFL_MIN_TARGET;
604 xi->rx_min_target = RX_DFL_MIN_TARGET;
605 xi->rx_max_target = RX_MAX_TARGET;
607 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
608 PROTOCOL_RESERVED_SIZE_IN_PACKET);
609 if (status != NDIS_STATUS_SUCCESS)
610 {
611 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
612 status = NDIS_STATUS_RESOURCES;
613 goto err;
614 }
616 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
617 if (status != NDIS_STATUS_SUCCESS)
618 {
619 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
620 status = NDIS_STATUS_RESOURCES;
621 goto err;
622 }
624 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
625 &xi->lower_do, NULL, NULL);
627 /* Initialize tx_pkts as a free chain containing every entry. */
628 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
629 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
630 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
631 }
633 for (i = 0; i < NET_RX_RING_SIZE; i++) {
634 xi->rx_pkts[i] = NULL;
635 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
636 }
638 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
639 NAME_SIZE, xi->name, &length);
640 if (!NT_SUCCESS(status))
641 {
642 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
643 status = NDIS_STATUS_FAILURE;
644 goto err;
645 }
647 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
648 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
649 NdisInterfaceInternal);
651 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
653 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
654 xi->lower_do, xi->pdo, &xi->wdf_device);
655 if (!NT_SUCCESS(status))
656 {
657 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
658 status = NDIS_STATUS_FAILURE;
659 goto err;
660 }
662 /* get lower (Xen) interfaces */
664 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
665 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
666 if(!NT_SUCCESS(status))
667 {
668 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
669 status = NDIS_STATUS_FAILURE;
670 goto err;
671 }
673 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
674 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
675 if(!NT_SUCCESS(status))
676 {
677 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
678 status = NDIS_STATUS_FAILURE;
679 goto err;
680 }
682 #if 0
683 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
684 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
685 if(!NT_SUCCESS(status))
686 {
687 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
688 status = NDIS_STATUS_FAILURE;
689 goto err;
690 }
691 #endif
693 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
694 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
695 if(!NT_SUCCESS(status))
696 {
697 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
698 status = NDIS_STATUS_FAILURE;
699 goto err;
700 }
702 msg = xi->XenBusInterface.List(xi->EvtChnInterface.InterfaceHeader.Context,
703 XBT_NIL, "device/vif", &vif_devs);
704 if (msg)
705 {
706 KdPrint((__DRIVER_NAME ": " __FUNCTION__ ": List retval is nonzero!\n"));
707 status = NDIS_STATUS_FAILURE;
708 goto err;
709 }
711 for (i = 0; vif_devs[i]; i++)
712 {
713 if (i > 0)
714 {
715 KdPrint((__DRIVER_NAME "Can only handle 1 vif so far, ignoring vif %s\n", vif_devs[i]));
716 continue;
717 }
718 RtlStringCbPrintfA(xi->Path, ARRAY_SIZE(xi->Path), "device/vif/%s", vif_devs[i]);
720 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
721 "device/vif/%s/state", vif_devs[i]);
722 KdPrint(("%s\n", TmpPath));
724 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/backend", xi->Path);
725 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
726 XBT_NIL, TmpPath, &Value);
727 if (!Value)
728 {
729 KdPrint((__DRIVER_NAME " backend Read Failed\n"));
730 }
731 else
732 {
733 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
734 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
735 }
736 ExFreePool(Value);
738 /* Add watch on backend state */
739 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
740 xi->XenBusInterface.AddWatch(xi->XenBusInterface.InterfaceHeader.Context,
741 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
743 /* get mac address */
744 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->Path);
745 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
746 XBT_NIL, TmpPath, &Value);
747 if (!Value)
748 {
749 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
750 }
751 else
752 {
753 char *s, *e;
754 int i;
756 s = Value;
758 for (i = 0; i < ETH_ALEN; i++) {
759 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
760 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
761 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
762 ExFreePool(Value);
763 ExFreePool(vif_devs);
764 status = NDIS_STATUS_FAILURE;
765 goto err;
766 }
767 s = e + 1;
768 }
769 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
770 }
771 ExFreePool(Value);
773 //XenVbd_HotPlugHandler(buffer, NULL);
774 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
775 }
776 ExFreePool(vif_devs);
778 return NDIS_STATUS_SUCCESS;
780 err:
781 NdisFreeMemory(xi, 0, 0);
782 return status;
783 }
785 NDIS_OID supported_oids[] =
786 {
787 /* general OIDs */
788 OID_GEN_SUPPORTED_LIST,
789 OID_GEN_HARDWARE_STATUS,
790 OID_GEN_MEDIA_SUPPORTED,
791 OID_GEN_MEDIA_IN_USE,
792 OID_GEN_MAXIMUM_LOOKAHEAD,
793 OID_GEN_MAXIMUM_FRAME_SIZE,
794 OID_GEN_LINK_SPEED,
795 OID_GEN_TRANSMIT_BUFFER_SPACE,
796 OID_GEN_RECEIVE_BUFFER_SPACE,
797 OID_GEN_TRANSMIT_BLOCK_SIZE,
798 OID_GEN_RECEIVE_BLOCK_SIZE,
799 OID_GEN_VENDOR_ID,
800 OID_GEN_VENDOR_DESCRIPTION,
801 OID_GEN_CURRENT_PACKET_FILTER,
802 OID_GEN_CURRENT_LOOKAHEAD,
803 OID_GEN_DRIVER_VERSION,
804 OID_GEN_MAXIMUM_TOTAL_SIZE,
805 OID_GEN_MAC_OPTIONS,
806 OID_GEN_MEDIA_CONNECT_STATUS,
807 OID_GEN_MAXIMUM_SEND_PACKETS,
808 /* stats */
809 OID_GEN_XMIT_OK,
810 OID_GEN_RCV_OK,
811 OID_GEN_XMIT_ERROR,
812 OID_GEN_RCV_ERROR,
813 OID_GEN_RCV_NO_BUFFER,
814 /* media-specific OIDs */
815 OID_802_3_PERMANENT_ADDRESS,
816 OID_802_3_CURRENT_ADDRESS,
817 OID_802_3_MULTICAST_LIST,
818 OID_802_3_MAXIMUM_LIST_SIZE,
819 };
821 NDIS_STATUS
822 XenNet_QueryInformation(
823 IN NDIS_HANDLE MiniportAdapterContext,
824 IN NDIS_OID Oid,
825 IN PVOID InformationBuffer,
826 IN ULONG InformationBufferLength,
827 OUT PULONG BytesWritten,
828 OUT PULONG BytesNeeded)
829 {
830 struct xennet_info *xi = MiniportAdapterContext;
831 UCHAR vendor_desc[] = XN_VENDOR_DESC;
832 ULONG64 temp_data;
833 PVOID data = &temp_data;
834 UINT len = 4;
835 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
837 switch(Oid)
838 {
839 case OID_GEN_SUPPORTED_LIST:
840 data = supported_oids;
841 len = sizeof(supported_oids);
842 break;
843 case OID_GEN_HARDWARE_STATUS:
844 if (!xi->connected)
845 temp_data = NdisHardwareStatusInitializing;
846 else
847 temp_data = NdisHardwareStatusReady;
848 break;
849 case OID_GEN_MEDIA_SUPPORTED:
850 temp_data = NdisMedium802_3;
851 break;
852 case OID_GEN_MEDIA_IN_USE:
853 temp_data = NdisMedium802_3;
854 break;
855 case OID_GEN_MAXIMUM_LOOKAHEAD:
856 temp_data = XN_DATA_SIZE;
857 break;
858 case OID_GEN_MAXIMUM_FRAME_SIZE:
859 temp_data = XN_MAX_PKT_SIZE;
860 break;
861 case OID_GEN_LINK_SPEED:
862 temp_data = 10000000; /* 1Gb */
863 break;
864 case OID_GEN_TRANSMIT_BUFFER_SPACE:
865 /* pkts times sizeof ring, maybe? */
866 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
867 break;
868 case OID_GEN_RECEIVE_BUFFER_SPACE:
869 /* pkts times sizeof ring, maybe? */
870 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
871 break;
872 case OID_GEN_TRANSMIT_BLOCK_SIZE:
873 temp_data = XN_MAX_PKT_SIZE;
874 break;
875 case OID_GEN_RECEIVE_BLOCK_SIZE:
876 temp_data = XN_MAX_PKT_SIZE;
877 break;
878 case OID_GEN_VENDOR_ID:
879 temp_data = XENSOURCE_MAC_HDR;
880 break;
881 case OID_GEN_VENDOR_DESCRIPTION:
882 data = vendor_desc;
883 len = sizeof(vendor_desc);
884 break;
885 case OID_GEN_CURRENT_PACKET_FILTER:
886 temp_data = xi->packet_filter;
887 break;
888 case OID_GEN_CURRENT_LOOKAHEAD:
889 temp_data = XN_MAX_PKT_SIZE;
890 break;
891 case OID_GEN_DRIVER_VERSION:
892 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
893 len = 2;
894 break;
895 case OID_GEN_MAXIMUM_TOTAL_SIZE:
896 temp_data = XN_MAX_PKT_SIZE;
897 break;
898 case OID_GEN_MAC_OPTIONS:
899 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
900 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
901 NDIS_MAC_OPTION_NO_LOOPBACK;
902 break;
903 case OID_GEN_MEDIA_CONNECT_STATUS:
904 if (xi->connected)
905 temp_data = NdisMediaStateConnected;
906 else
907 temp_data = NdisMediaStateDisconnected;
908 break;
909 case OID_GEN_MAXIMUM_SEND_PACKETS:
910 temp_data = XN_MAX_SEND_PKTS;
911 break;
912 case OID_GEN_XMIT_OK:
913 temp_data = xi->stat_tx_ok;
914 len = sizeof(ULONG64);
915 break;
916 case OID_GEN_RCV_OK:
917 temp_data = xi->stat_rx_ok;
918 len = sizeof(ULONG64);
919 break;
920 case OID_GEN_XMIT_ERROR:
921 temp_data = xi->stat_tx_error;
922 len = sizeof(ULONG64);
923 break;
924 case OID_GEN_RCV_ERROR:
925 temp_data = xi->stat_rx_error;
926 len = sizeof(ULONG64);
927 break;
928 case OID_GEN_RCV_NO_BUFFER:
929 temp_data = xi->stat_rx_no_buffer;
930 len = sizeof(ULONG64);
931 break;
932 case OID_802_3_PERMANENT_ADDRESS:
933 data = xi->perm_mac_addr;
934 len = ETH_ALEN;
935 break;
936 case OID_802_3_CURRENT_ADDRESS:
937 data = xi->curr_mac_addr;
938 len = ETH_ALEN;
939 break;
940 case OID_802_3_MULTICAST_LIST:
941 data = NULL;
942 len = 0;
943 case OID_802_3_MAXIMUM_LIST_SIZE:
944 temp_data = 0; /* no mcast support */
945 break;
946 default:
947 //KdPrint(("Unknown OID 0x%x\n", Oid));
948 status = NDIS_STATUS_NOT_SUPPORTED;
949 }
951 if (!NT_SUCCESS(status))
952 {
953 return status;
954 }
956 if (len > InformationBufferLength)
957 {
958 *BytesNeeded = len;
959 return NDIS_STATUS_BUFFER_TOO_SHORT;
960 }
962 *BytesWritten = len;
963 if (len)
964 {
965 NdisMoveMemory(InformationBuffer, data, len);
966 }
968 //KdPrint(("Got OID 0x%x\n", Oid));
970 return status;
971 }
973 NDIS_STATUS
974 XenNet_SetInformation(
975 IN NDIS_HANDLE MiniportAdapterContext,
976 IN NDIS_OID Oid,
977 IN PVOID InformationBuffer,
978 IN ULONG InformationBufferLength,
979 OUT PULONG BytesRead,
980 OUT PULONG BytesNeeded
981 )
982 {
983 UNREFERENCED_PARAMETER(MiniportAdapterContext);
984 UNREFERENCED_PARAMETER(Oid);
985 UNREFERENCED_PARAMETER(InformationBuffer);
986 UNREFERENCED_PARAMETER(InformationBufferLength);
987 UNREFERENCED_PARAMETER(BytesRead);
988 UNREFERENCED_PARAMETER(BytesNeeded);
990 KdPrint((__FUNCTION__ " called with OID=0x%x\n", Oid));
991 return NDIS_STATUS_SUCCESS;
992 }
994 VOID
995 XenNet_ReturnPacket(
996 IN NDIS_HANDLE MiniportAdapterContext,
997 IN PNDIS_PACKET Packet
998 )
999 {
1000 PNDIS_BUFFER buffer;
1001 PVOID buff_va;
1002 UINT buff_len;
1003 UINT tot_buff_len;
1005 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1007 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1008 &tot_buff_len, NormalPagePriority);
1009 ASSERT(buff_len == tot_buff_len);
1011 NdisFreeMemory(buff_va, 0, 0);
1012 NdisFreeBuffer(buffer);
1013 NdisFreePacket(Packet);
1015 //KdPrint((__FUNCTION__ " called\n"));
1018 PMDL
1019 XenNet_Linearize(PNDIS_PACKET Packet)
1021 NDIS_STATUS status;
1022 PMDL pmdl;
1023 char *start;
1024 PNDIS_BUFFER buffer;
1025 PVOID buff_va;
1026 UINT buff_len;
1027 UINT tot_buff_len;
1029 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1030 &tot_buff_len, NormalPagePriority);
1031 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1033 status = NdisAllocateMemoryWithTag(&start, tot_buff_len, XENNET_POOL_TAG);
1034 if (!NT_SUCCESS(status))
1036 KdPrint(("Could not allocate memory for linearization\n"));
1037 return NULL;
1039 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, FALSE);
1040 if (!pmdl)
1042 KdPrint(("Could not allocate MDL for linearization\n"));
1043 NdisFreeMemory(start, 0, 0);
1044 return NULL;
1046 MmBuildMdlForNonPagedPool(pmdl);
1048 while (buffer)
1050 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1051 RtlCopyMemory(start, buff_va, buff_len);
1052 start += buff_len;
1053 NdisGetNextBuffer(buffer, &buffer);
1056 return pmdl;
1059 VOID
1060 XenNet_SendPackets(
1061 IN NDIS_HANDLE MiniportAdapterContext,
1062 IN PPNDIS_PACKET PacketArray,
1063 IN UINT NumberOfPackets
1066 struct xennet_info *xi = MiniportAdapterContext;
1067 PNDIS_PACKET curr_packet;
1068 UINT i;
1069 struct netif_tx_request *tx;
1070 unsigned short id;
1071 int notify;
1072 PMDL pmdl;
1073 UINT pkt_size;
1075 for (i = 0; i < NumberOfPackets; i++)
1077 curr_packet = PacketArray[i];
1078 ASSERT(curr_packet);
1080 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
1082 //KdPrint(("sending pkt, len %d\n", pkt_size));
1084 pmdl = XenNet_Linearize(curr_packet);
1085 if (!pmdl)
1087 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1088 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1089 break;
1091 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
1093 id = get_id_from_freelist(xi->tx_pkts);
1094 xi->tx_pkts[id] = curr_packet;
1096 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1097 tx->id = id;
1098 tx->gref = xi->GntTblInterface.GrantAccess(
1099 xi->GntTblInterface.InterfaceHeader.Context,
1100 0,
1101 *MmGetMdlPfnArray(pmdl),
1102 TRUE);
1103 xi->grant_tx_ref[id] = tx->gref;
1104 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1105 tx->size = (UINT16)pkt_size;
1106 tx->flags = NETTXF_csum_blank;
1108 xi->tx.req_prod_pvt++;
1110 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
1111 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
1114 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1115 if (notify)
1117 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
1118 xi->event_channel);
1122 VOID
1123 XenNet_PnPEventNotify(
1124 IN NDIS_HANDLE MiniportAdapterContext,
1125 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1126 IN PVOID InformationBuffer,
1127 IN ULONG InformationBufferLength
1130 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1131 UNREFERENCED_PARAMETER(PnPEvent);
1132 UNREFERENCED_PARAMETER(InformationBuffer);
1133 UNREFERENCED_PARAMETER(InformationBufferLength);
1135 KdPrint((__FUNCTION__ " called\n"));
1138 VOID
1139 XenNet_Shutdown(
1140 IN NDIS_HANDLE MiniportAdapterContext
1143 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1145 KdPrint((__FUNCTION__ " called\n"));
1148 NTSTATUS
1149 DriverEntry(
1150 PDRIVER_OBJECT DriverObject,
1151 PUNICODE_STRING RegistryPath
1154 NTSTATUS status;
1155 WDF_DRIVER_CONFIG config;
1156 NDIS_HANDLE ndis_wrapper_handle;
1157 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1159 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1161 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1162 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1164 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1165 &config, WDF_NO_HANDLE);
1166 if (!NT_SUCCESS(status))
1168 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1169 return status;
1172 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1173 if (!ndis_wrapper_handle)
1175 KdPrint(("NdisMInitializeWrapper failed\n"));
1176 return NDIS_STATUS_FAILURE;
1179 /* NDIS 5.1 driver */
1180 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1181 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1183 mini_chars.HaltHandler = XenNet_Halt;
1184 mini_chars.InitializeHandler = XenNet_Init;
1185 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1186 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1187 mini_chars.ResetHandler = NULL; //TODO: fill in
1188 mini_chars.SetInformationHandler = XenNet_SetInformation;
1189 /* added in v.4 -- use multiple pkts interface */
1190 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1191 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1192 /* added in v.5.1 */
1193 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1194 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1196 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1198 /* set up upper-edge interface */
1199 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1200 if (!NT_SUCCESS(status))
1202 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1203 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1204 return status;
1207 return status;