win-pvdrivers

view xennet/xennet.c @ 74:06b4321b7068

Created a common AllocagePages routine in xen_windows.h
Updated xennet and xenvbd to use it.
Updated xennet's method of getting the virtual address from the Mdl
author James Harper <james.harper@bendigoit.com.au>
date Thu Dec 20 21:37:20 2007 +1100 (2007-12-20)
parents a41314faf255
children b7863ede7a37
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 NDIS_STATUS
160 XenNet_TxBufferGC(struct xennet_info *xi)
161 {
162 RING_IDX cons, prod;
163 unsigned short id;
164 PNDIS_PACKET pkt;
165 PMDL pmdl;
167 ASSERT(xi->connected);
169 do {
170 prod = xi->tx.sring->rsp_prod;
171 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
173 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
174 struct netif_tx_response *txrsp;
176 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
177 if (txrsp->status == NETIF_RSP_NULL)
178 continue;
180 id = txrsp->id;
181 pkt = xi->tx_pkts[id];
182 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
183 xi->grant_tx_ref[id]);
184 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
185 add_id_to_freelist(xi->tx_pkts, id);
187 /* free linearized data page */
188 pmdl = *(PMDL *)pkt->MiniportReservedEx;
189 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0);
190 IoFreeMdl(pmdl);
192 xi->stat_tx_ok++;
193 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
194 }
196 xi->tx.rsp_cons = prod;
198 /*
199 * Set a new event, then check for race with update of tx_cons.
200 * Note that it is essential to schedule a callback, no matter
201 * how few buffers are pending. Even if there is space in the
202 * transmit ring, higher layers may be blocked because too much
203 * data is outstanding: in such cases notification from Xen is
204 * likely to be the only kick that we'll get.
205 */
206 xi->tx.sring->rsp_event =
207 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
208 KeMemoryBarrier();
209 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
211 /* if queued packets, send them now?
212 network_maybe_wake_tx(dev); */
214 return NDIS_STATUS_SUCCESS;
215 }
217 static NDIS_STATUS
218 XenNet_AllocRXBuffers(struct xennet_info *xi)
219 {
220 unsigned short id;
221 PNDIS_PACKET packet;
222 PNDIS_BUFFER buffer;
223 int i, batch_target, notify;
224 RING_IDX req_prod = xi->rx.req_prod_pvt;
225 grant_ref_t ref;
226 netif_rx_request_t *req;
227 NDIS_STATUS status;
228 PVOID start;
230 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
231 for (i = 0; i < batch_target; i++)
232 {
233 /*
234 * Allocate a packet, page, and buffer. Hook them up.
235 */
236 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
237 if (status != NDIS_STATUS_SUCCESS)
238 {
239 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
240 break;
241 }
242 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
243 if (status != NDIS_STATUS_SUCCESS)
244 {
245 KdPrint(("NdisAllocateBuffer Failed! status = 0x%x\n", status));
246 NdisFreeMemory(start, 0, 0);
247 break;
248 }
249 NdisAllocatePacket(&status, &packet, xi->packet_pool);
250 if (status != NDIS_STATUS_SUCCESS)
251 {
252 KdPrint(("NdisAllocatePacket Failed! status = 0x%x\n", status));
253 NdisFreeMemory(start, 0, 0);
254 NdisFreeBuffer(buffer);
255 break;
256 }
257 NdisChainBufferAtBack(packet, buffer);
258 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
260 /* Give to netback */
261 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
262 ASSERT(!xi->rx_pkts[id]);
263 xi->rx_pkts[id] = packet;
264 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
265 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
266 ref = xi->GntTblInterface.GrantAccess(
267 xi->GntTblInterface.InterfaceHeader.Context, 0,
268 *MmGetMdlPfnArray(buffer), FALSE);
269 ASSERT((signed short)ref >= 0);
270 xi->grant_rx_ref[id] = ref;
272 req->id = id;
273 req->gref = ref;
274 }
276 xi->rx.req_prod_pvt = req_prod + i;
277 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
278 if (notify)
279 {
280 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
281 xi->event_channel);
282 }
284 return NDIS_STATUS_SUCCESS;
285 }
287 static NDIS_STATUS
288 XenNet_RxBufferCheck(struct xennet_info *xi)
289 {
290 RING_IDX cons, prod;
292 PNDIS_PACKET pkt;
293 PNDIS_BUFFER buffer;
294 PVOID buff_va;
295 UINT buff_len;
296 UINT tot_buff_len;
298 ASSERT(xi->connected);
300 do {
301 prod = xi->rx.sring->rsp_prod;
302 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
304 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
305 struct netif_rx_response *rxrsp;
307 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
308 if (rxrsp->status == NETIF_RSP_NULL)
309 continue;
311 pkt = xi->rx_pkts[rxrsp->id];
312 xi->rx_pkts[rxrsp->id] = NULL;
313 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
314 xi->grant_rx_ref[rxrsp->id]);
315 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
317 NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
318 &tot_buff_len, NormalPagePriority);
319 ASSERT(rxrsp->offset == 0);
320 ASSERT(rxrsp->status > 0);
321 NdisAdjustBufferLength(buffer, rxrsp->status);
323 xi->stat_rx_ok++;
324 NDIS_SET_PACKET_STATUS(pkt, NDIS_STATUS_SUCCESS);
326 /* just indicate 1 packet for now */
327 NdisMIndicateReceivePacket(xi->adapter_handle, &pkt, 1);
328 }
330 xi->rx.rsp_cons = prod;
332 /*
333 * Set a new event, then check for race with update of rx_cons.
334 * Note that it is essential to schedule a callback, no matter
335 * how few buffers are pending. Even if there is space in the
336 * transmit ring, higher layers may be blocked because too much
337 * data is outstanding: in such cases notification from Xen is
338 * likely to be the only kick that we'll get.
339 */
340 xi->rx.sring->rsp_event =
341 prod + ((xi->rx.sring->req_prod - prod) >> 1) + 1;
342 KeMemoryBarrier();
343 } while ((cons == prod) && (prod != xi->rx.sring->rsp_prod));
345 /* Give netback more buffers */
346 XenNet_AllocRXBuffers(xi);
348 return NDIS_STATUS_SUCCESS;
349 }
351 static BOOLEAN
352 XenNet_Interrupt(
353 PKINTERRUPT Interrupt,
354 PVOID ServiceContext
355 )
356 {
357 struct xennet_info *xi = ServiceContext;
358 // KIRQL KIrql;
360 UNREFERENCED_PARAMETER(Interrupt);
362 //KdPrint((__DRIVER_NAME " ***XenNet Interrupt***\n"));
364 if (xi->connected)
365 {
366 XenNet_TxBufferGC(xi);
367 XenNet_RxBufferCheck(xi);
368 }
369 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
370 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
371 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
372 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
373 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
375 return TRUE;
376 }
378 static VOID
379 XenNet_BackEndStateHandler(char *Path, PVOID Data)
380 {
381 struct xennet_info *xi = Data;
382 char *Value;
383 int be_state;
384 char TmpPath[128];
385 xenbus_transaction_t xbt = 0;
386 int retry = 0;
387 char *err;
388 int i;
390 struct set_params {
391 char *name;
392 int value;
393 } params[] = {
394 {"tx-ring-ref", 0},
395 {"rx-ring-ref", 0},
396 {"event-channel", 0},
397 {"request-rx-copy", 1},
398 {"feature-rx-notify", 1},
399 {"feature-no-csum-offload", 1},
400 {"feature-sg", 1},
401 {"feature-gso-tcpv4", 0},
402 {NULL, 0},
403 };
405 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
406 XBT_NIL, Path, &Value);
407 be_state = atoi(Value);
408 ExFreePool(Value);
410 switch (be_state)
411 {
412 case XenbusStateUnknown:
413 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
414 break;
416 case XenbusStateInitialising:
417 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
418 break;
420 case XenbusStateInitWait:
421 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
423 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
424 xi->EvtChnInterface.InterfaceHeader.Context, 0);
425 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
426 xi->event_channel, XenNet_Interrupt, xi);
428 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
429 // or, allocate mem and then get mdl, then free mdl
430 xi->tx_mdl = AllocatePage();
431 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
432 NULL, FALSE, NormalPagePriority);
433 SHARED_RING_INIT(xi->tx_pgs);
434 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
435 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
436 xi->GntTblInterface.InterfaceHeader.Context, 0,
437 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
439 xi->rx_mdl = AllocatePage();
440 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
441 NULL, FALSE, NormalPagePriority);
442 SHARED_RING_INIT(xi->rx_pgs);
443 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
444 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
445 xi->GntTblInterface.InterfaceHeader.Context, 0,
446 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
448 /* fixup array for dynamic values */
449 params[0].value = xi->tx_ring_ref;
450 params[1].value = xi->rx_ring_ref;
451 params[2].value = xi->event_channel;
453 xi->XenBusInterface.StartTransaction(
454 xi->XenBusInterface.InterfaceHeader.Context, &xbt);
456 for (i = 0; params[i].name; i++)
457 {
458 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
459 xi->Path, params[i].name);
460 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
461 XBT_NIL, TmpPath, "%d", params[i].value);
462 if (err)
463 {
464 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
465 goto trouble;
466 }
467 }
469 /* commit transaction */
470 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
471 xbt, 0, &retry);
473 XenNet_AllocRXBuffers(xi);
475 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
476 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
477 xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
478 XBT_NIL, TmpPath, "%d", XenbusStateConnected);
480 /* send fake arp? */
482 xi->connected = TRUE;
484 break;
486 case XenbusStateInitialised:
487 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
488 break;
490 case XenbusStateConnected:
491 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
492 break;
494 case XenbusStateClosing:
495 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
496 break;
498 case XenbusStateClosed:
499 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
500 break;
502 default:
503 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", be_state));
504 break;
505 }
507 return;
509 trouble:
510 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
511 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
512 xbt, 1, &retry);
514 }
516 VOID
517 XenNet_Halt(
518 IN NDIS_HANDLE MiniportAdapterContext
519 )
520 {
521 UNREFERENCED_PARAMETER(MiniportAdapterContext);
522 }
524 static NDIS_STATUS
525 XenNet_Init(
526 OUT PNDIS_STATUS OpenErrorStatus,
527 OUT PUINT SelectedMediumIndex,
528 IN PNDIS_MEDIUM MediumArray,
529 IN UINT MediumArraySize,
530 IN NDIS_HANDLE MiniportAdapterHandle,
531 IN NDIS_HANDLE WrapperConfigurationContext
532 )
533 {
534 NDIS_STATUS status;
535 UINT i;
536 BOOLEAN medium_found = FALSE;
537 struct xennet_info *xi = NULL;
538 ULONG length;
539 WDF_OBJECT_ATTRIBUTES wdf_attrs;
540 char *msg;
541 char *Value;
542 char **vif_devs;
543 char TmpPath[128];
545 UNREFERENCED_PARAMETER(OpenErrorStatus);
546 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
548 /* deal with medium stuff */
549 for (i = 0; i < MediumArraySize; i++)
550 {
551 if (MediumArray[i] == NdisMedium802_3)
552 {
553 medium_found = TRUE;
554 break;
555 }
556 }
557 if (!medium_found)
558 {
559 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
560 return NDIS_STATUS_UNSUPPORTED_MEDIA;
561 }
562 *SelectedMediumIndex = i;
564 /* Alloc memory for adapter private info */
565 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
566 if (!NT_SUCCESS(status))
567 {
568 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
569 status = NDIS_STATUS_RESOURCES;
570 goto err;
571 }
572 RtlZeroMemory(xi, sizeof(*xi));
574 /* init xennet_info */
575 xi->adapter_handle = MiniportAdapterHandle;
576 xi->rx_target = RX_DFL_MIN_TARGET;
577 xi->rx_min_target = RX_DFL_MIN_TARGET;
578 xi->rx_max_target = RX_MAX_TARGET;
580 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
581 PROTOCOL_RESERVED_SIZE_IN_PACKET);
582 if (status != NDIS_STATUS_SUCCESS)
583 {
584 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
585 status = NDIS_STATUS_RESOURCES;
586 goto err;
587 }
589 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
590 if (status != NDIS_STATUS_SUCCESS)
591 {
592 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
593 status = NDIS_STATUS_RESOURCES;
594 goto err;
595 }
597 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
598 &xi->lower_do, NULL, NULL);
600 /* Initialize tx_pkts as a free chain containing every entry. */
601 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
602 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
603 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
604 }
606 for (i = 0; i < NET_RX_RING_SIZE; i++) {
607 xi->rx_pkts[i] = NULL;
608 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
609 }
611 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
612 NAME_SIZE, xi->name, &length);
613 if (!NT_SUCCESS(status))
614 {
615 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
616 status = NDIS_STATUS_FAILURE;
617 goto err;
618 }
620 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
621 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
622 NdisInterfaceInternal);
624 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
626 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
627 xi->lower_do, xi->pdo, &xi->wdf_device);
628 if (!NT_SUCCESS(status))
629 {
630 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
631 status = NDIS_STATUS_FAILURE;
632 goto err;
633 }
635 /* get lower (Xen) interfaces */
637 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
638 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
639 if(!NT_SUCCESS(status))
640 {
641 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
642 status = NDIS_STATUS_FAILURE;
643 goto err;
644 }
646 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
647 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
648 if(!NT_SUCCESS(status))
649 {
650 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
651 status = NDIS_STATUS_FAILURE;
652 goto err;
653 }
655 #if 0
656 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
657 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
658 if(!NT_SUCCESS(status))
659 {
660 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
661 status = NDIS_STATUS_FAILURE;
662 goto err;
663 }
664 #endif
666 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
667 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
668 if(!NT_SUCCESS(status))
669 {
670 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
671 status = NDIS_STATUS_FAILURE;
672 goto err;
673 }
675 msg = xi->XenBusInterface.List(xi->EvtChnInterface.InterfaceHeader.Context,
676 XBT_NIL, "device/vif", &vif_devs);
677 if (msg)
678 {
679 KdPrint((__DRIVER_NAME ": " __FUNCTION__ ": List retval is nonzero!\n"));
680 status = NDIS_STATUS_FAILURE;
681 goto err;
682 }
684 for (i = 0; vif_devs[i]; i++)
685 {
686 if (i > 0)
687 {
688 KdPrint((__DRIVER_NAME "Can only handle 1 vif so far, ignoring vif %s\n", vif_devs[i]));
689 continue;
690 }
691 RtlStringCbPrintfA(xi->Path, ARRAY_SIZE(xi->Path), "device/vif/%s", vif_devs[i]);
693 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
694 "device/vif/%s/state", vif_devs[i]);
695 KdPrint(("%s\n", TmpPath));
697 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/backend", xi->Path);
698 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
699 XBT_NIL, TmpPath, &Value);
700 if (!Value)
701 {
702 KdPrint((__DRIVER_NAME " backend Read Failed\n"));
703 }
704 else
705 {
706 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
707 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
708 }
709 ExFreePool(Value);
711 /* Add watch on backend state */
712 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
713 xi->XenBusInterface.AddWatch(xi->XenBusInterface.InterfaceHeader.Context,
714 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
716 /* get mac address */
717 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->Path);
718 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
719 XBT_NIL, TmpPath, &Value);
720 if (!Value)
721 {
722 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
723 }
724 else
725 {
726 char *s, *e;
727 int i;
729 s = Value;
731 for (i = 0; i < ETH_ALEN; i++) {
732 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
733 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
734 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
735 ExFreePool(Value);
736 ExFreePool(vif_devs);
737 status = NDIS_STATUS_FAILURE;
738 goto err;
739 }
740 s = e + 1;
741 }
742 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
743 }
744 ExFreePool(Value);
746 //XenVbd_HotPlugHandler(buffer, NULL);
747 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
748 }
749 ExFreePool(vif_devs);
751 return NDIS_STATUS_SUCCESS;
753 err:
754 NdisFreeMemory(xi, 0, 0);
755 return status;
756 }
758 NDIS_OID supported_oids[] =
759 {
760 /* general OIDs */
761 OID_GEN_SUPPORTED_LIST,
762 OID_GEN_HARDWARE_STATUS,
763 OID_GEN_MEDIA_SUPPORTED,
764 OID_GEN_MEDIA_IN_USE,
765 OID_GEN_MAXIMUM_LOOKAHEAD,
766 OID_GEN_MAXIMUM_FRAME_SIZE,
767 OID_GEN_LINK_SPEED,
768 OID_GEN_TRANSMIT_BUFFER_SPACE,
769 OID_GEN_RECEIVE_BUFFER_SPACE,
770 OID_GEN_TRANSMIT_BLOCK_SIZE,
771 OID_GEN_RECEIVE_BLOCK_SIZE,
772 OID_GEN_VENDOR_ID,
773 OID_GEN_VENDOR_DESCRIPTION,
774 OID_GEN_CURRENT_PACKET_FILTER,
775 OID_GEN_CURRENT_LOOKAHEAD,
776 OID_GEN_DRIVER_VERSION,
777 OID_GEN_MAXIMUM_TOTAL_SIZE,
778 OID_GEN_MAC_OPTIONS,
779 OID_GEN_MEDIA_CONNECT_STATUS,
780 OID_GEN_MAXIMUM_SEND_PACKETS,
781 /* stats */
782 OID_GEN_XMIT_OK,
783 OID_GEN_RCV_OK,
784 OID_GEN_XMIT_ERROR,
785 OID_GEN_RCV_ERROR,
786 OID_GEN_RCV_NO_BUFFER,
787 /* media-specific OIDs */
788 OID_802_3_PERMANENT_ADDRESS,
789 OID_802_3_CURRENT_ADDRESS,
790 OID_802_3_MULTICAST_LIST,
791 OID_802_3_MAXIMUM_LIST_SIZE,
792 };
794 NDIS_STATUS
795 XenNet_QueryInformation(
796 IN NDIS_HANDLE MiniportAdapterContext,
797 IN NDIS_OID Oid,
798 IN PVOID InformationBuffer,
799 IN ULONG InformationBufferLength,
800 OUT PULONG BytesWritten,
801 OUT PULONG BytesNeeded)
802 {
803 struct xennet_info *xi = MiniportAdapterContext;
804 UCHAR vendor_desc[] = XN_VENDOR_DESC;
805 ULONG64 temp_data;
806 PVOID data = &temp_data;
807 UINT len = 4;
808 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
810 switch(Oid)
811 {
812 case OID_GEN_SUPPORTED_LIST:
813 data = supported_oids;
814 len = sizeof(supported_oids);
815 break;
816 case OID_GEN_HARDWARE_STATUS:
817 if (!xi->connected)
818 temp_data = NdisHardwareStatusInitializing;
819 else
820 temp_data = NdisHardwareStatusReady;
821 break;
822 case OID_GEN_MEDIA_SUPPORTED:
823 temp_data = NdisMedium802_3;
824 break;
825 case OID_GEN_MEDIA_IN_USE:
826 temp_data = NdisMedium802_3;
827 break;
828 case OID_GEN_MAXIMUM_LOOKAHEAD:
829 temp_data = XN_DATA_SIZE;
830 break;
831 case OID_GEN_MAXIMUM_FRAME_SIZE:
832 temp_data = XN_MAX_PKT_SIZE;
833 break;
834 case OID_GEN_LINK_SPEED:
835 temp_data = 10000000; /* 1Gb */
836 break;
837 case OID_GEN_TRANSMIT_BUFFER_SPACE:
838 /* pkts times sizeof ring, maybe? */
839 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
840 break;
841 case OID_GEN_RECEIVE_BUFFER_SPACE:
842 /* pkts times sizeof ring, maybe? */
843 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
844 break;
845 case OID_GEN_TRANSMIT_BLOCK_SIZE:
846 temp_data = XN_MAX_PKT_SIZE;
847 break;
848 case OID_GEN_RECEIVE_BLOCK_SIZE:
849 temp_data = XN_MAX_PKT_SIZE;
850 break;
851 case OID_GEN_VENDOR_ID:
852 temp_data = XENSOURCE_MAC_HDR;
853 break;
854 case OID_GEN_VENDOR_DESCRIPTION:
855 data = vendor_desc;
856 len = sizeof(vendor_desc);
857 break;
858 case OID_GEN_CURRENT_PACKET_FILTER:
859 temp_data = xi->packet_filter;
860 break;
861 case OID_GEN_CURRENT_LOOKAHEAD:
862 temp_data = XN_MAX_PKT_SIZE;
863 break;
864 case OID_GEN_DRIVER_VERSION:
865 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
866 len = 2;
867 break;
868 case OID_GEN_MAXIMUM_TOTAL_SIZE:
869 temp_data = XN_MAX_PKT_SIZE;
870 break;
871 case OID_GEN_MAC_OPTIONS:
872 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
873 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
874 NDIS_MAC_OPTION_NO_LOOPBACK;
875 break;
876 case OID_GEN_MEDIA_CONNECT_STATUS:
877 if (xi->connected)
878 temp_data = NdisMediaStateConnected;
879 else
880 temp_data = NdisMediaStateDisconnected;
881 break;
882 case OID_GEN_MAXIMUM_SEND_PACKETS:
883 temp_data = XN_MAX_SEND_PKTS;
884 break;
885 case OID_GEN_XMIT_OK:
886 temp_data = xi->stat_tx_ok;
887 len = sizeof(ULONG64);
888 break;
889 case OID_GEN_RCV_OK:
890 temp_data = xi->stat_rx_ok;
891 len = sizeof(ULONG64);
892 break;
893 case OID_GEN_XMIT_ERROR:
894 temp_data = xi->stat_tx_error;
895 len = sizeof(ULONG64);
896 break;
897 case OID_GEN_RCV_ERROR:
898 temp_data = xi->stat_rx_error;
899 len = sizeof(ULONG64);
900 break;
901 case OID_GEN_RCV_NO_BUFFER:
902 temp_data = xi->stat_rx_no_buffer;
903 len = sizeof(ULONG64);
904 break;
905 case OID_802_3_PERMANENT_ADDRESS:
906 data = xi->perm_mac_addr;
907 len = ETH_ALEN;
908 break;
909 case OID_802_3_CURRENT_ADDRESS:
910 data = xi->curr_mac_addr;
911 len = ETH_ALEN;
912 break;
913 case OID_802_3_MULTICAST_LIST:
914 data = NULL;
915 len = 0;
916 case OID_802_3_MAXIMUM_LIST_SIZE:
917 temp_data = 0; /* no mcast support */
918 break;
919 default:
920 //KdPrint(("Unknown OID 0x%x\n", Oid));
921 status = NDIS_STATUS_NOT_SUPPORTED;
922 }
924 if (!NT_SUCCESS(status))
925 {
926 return status;
927 }
929 if (len > InformationBufferLength)
930 {
931 *BytesNeeded = len;
932 return NDIS_STATUS_BUFFER_TOO_SHORT;
933 }
935 *BytesWritten = len;
936 if (len)
937 {
938 NdisMoveMemory(InformationBuffer, data, len);
939 }
941 //KdPrint(("Got OID 0x%x\n", Oid));
943 return status;
944 }
946 NDIS_STATUS
947 XenNet_SetInformation(
948 IN NDIS_HANDLE MiniportAdapterContext,
949 IN NDIS_OID Oid,
950 IN PVOID InformationBuffer,
951 IN ULONG InformationBufferLength,
952 OUT PULONG BytesRead,
953 OUT PULONG BytesNeeded
954 )
955 {
956 UNREFERENCED_PARAMETER(MiniportAdapterContext);
957 UNREFERENCED_PARAMETER(Oid);
958 UNREFERENCED_PARAMETER(InformationBuffer);
959 UNREFERENCED_PARAMETER(InformationBufferLength);
960 UNREFERENCED_PARAMETER(BytesRead);
961 UNREFERENCED_PARAMETER(BytesNeeded);
963 KdPrint((__FUNCTION__ " called with OID=0x%x\n", Oid));
964 return NDIS_STATUS_SUCCESS;
965 }
967 VOID
968 XenNet_ReturnPacket(
969 IN NDIS_HANDLE MiniportAdapterContext,
970 IN PNDIS_PACKET Packet
971 )
972 {
973 PNDIS_BUFFER buffer;
974 PVOID buff_va;
975 UINT buff_len;
976 UINT tot_buff_len;
978 UNREFERENCED_PARAMETER(MiniportAdapterContext);
980 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
981 &tot_buff_len, NormalPagePriority);
982 ASSERT(buff_len == tot_buff_len);
984 NdisFreeMemory(buff_va, 0, 0);
985 NdisFreeBuffer(buffer);
986 NdisFreePacket(Packet);
988 //KdPrint((__FUNCTION__ " called\n"));
989 }
991 PMDL
992 XenNet_Linearize(PNDIS_PACKET Packet)
993 {
994 NDIS_STATUS status;
995 PMDL pmdl;
996 char *start;
997 PNDIS_BUFFER buffer;
998 PVOID buff_va;
999 UINT buff_len;
1000 UINT tot_buff_len;
1002 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1003 &tot_buff_len, NormalPagePriority);
1004 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1006 status = NdisAllocateMemoryWithTag(&start, tot_buff_len, XENNET_POOL_TAG);
1007 if (!NT_SUCCESS(status))
1009 KdPrint(("Could not allocate memory for linearization\n"));
1010 return NULL;
1012 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, FALSE);
1013 if (!pmdl)
1015 KdPrint(("Could not allocate MDL for linearization\n"));
1016 NdisFreeMemory(start, 0, 0);
1017 return NULL;
1019 MmBuildMdlForNonPagedPool(pmdl);
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 struct xennet_info *xi = MiniportAdapterContext;
1040 PNDIS_PACKET curr_packet;
1041 UINT i;
1042 struct netif_tx_request *tx;
1043 unsigned short id;
1044 int notify;
1045 PMDL pmdl;
1046 UINT pkt_size;
1048 for (i = 0; i < NumberOfPackets; i++)
1050 curr_packet = PacketArray[i];
1051 ASSERT(curr_packet);
1053 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
1055 //KdPrint(("sending pkt, len %d\n", pkt_size));
1057 pmdl = XenNet_Linearize(curr_packet);
1058 if (!pmdl)
1060 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1061 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1062 break;
1064 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
1066 id = get_id_from_freelist(xi->tx_pkts);
1067 xi->tx_pkts[id] = curr_packet;
1069 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1070 tx->id = id;
1071 tx->gref = xi->GntTblInterface.GrantAccess(
1072 xi->GntTblInterface.InterfaceHeader.Context,
1073 0,
1074 *MmGetMdlPfnArray(pmdl),
1075 TRUE);
1076 xi->grant_tx_ref[id] = tx->gref;
1077 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1078 tx->size = (UINT16)pkt_size;
1079 tx->flags = NETTXF_csum_blank;
1081 xi->tx.req_prod_pvt++;
1083 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
1084 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
1087 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1088 if (notify)
1090 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
1091 xi->event_channel);
1095 VOID
1096 XenNet_PnPEventNotify(
1097 IN NDIS_HANDLE MiniportAdapterContext,
1098 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1099 IN PVOID InformationBuffer,
1100 IN ULONG InformationBufferLength
1103 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1104 UNREFERENCED_PARAMETER(PnPEvent);
1105 UNREFERENCED_PARAMETER(InformationBuffer);
1106 UNREFERENCED_PARAMETER(InformationBufferLength);
1108 KdPrint((__FUNCTION__ " called\n"));
1111 VOID
1112 XenNet_Shutdown(
1113 IN NDIS_HANDLE MiniportAdapterContext
1116 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1118 KdPrint((__FUNCTION__ " called\n"));
1121 NTSTATUS
1122 DriverEntry(
1123 PDRIVER_OBJECT DriverObject,
1124 PUNICODE_STRING RegistryPath
1127 NTSTATUS status;
1128 WDF_DRIVER_CONFIG config;
1129 NDIS_HANDLE ndis_wrapper_handle;
1130 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1132 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1134 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1135 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1137 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1138 &config, WDF_NO_HANDLE);
1139 if (!NT_SUCCESS(status))
1141 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1142 return status;
1145 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1146 if (!ndis_wrapper_handle)
1148 KdPrint(("NdisMInitializeWrapper failed\n"));
1149 return NDIS_STATUS_FAILURE;
1152 /* NDIS 5.1 driver */
1153 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1154 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1156 mini_chars.HaltHandler = XenNet_Halt;
1157 mini_chars.InitializeHandler = XenNet_Init;
1158 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1159 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1160 mini_chars.ResetHandler = NULL; //TODO: fill in
1161 mini_chars.SetInformationHandler = XenNet_SetInformation;
1162 /* added in v.4 -- use multiple pkts interface */
1163 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1164 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1165 /* added in v.5.1 */
1166 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1167 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1169 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1171 /* set up upper-edge interface */
1172 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1173 if (!NT_SUCCESS(status))
1175 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1176 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1177 return status;
1180 return status;