win-pvdrivers

view xennet/xennet.c @ 65:fd2827973086

xennet: set field in packet which kept rx from working; turn off some kdprints
author Andy Grover <andy.grover@oracle.com>
date Tue Dec 18 20:44:13 2007 -0800 (2007-12-18)
parents 1acf9205fc43
children a41314faf255
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;
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 xi->stat_tx_ok++;
221 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
222 }
224 xi->tx.rsp_cons = prod;
226 /*
227 * Set a new event, then check for race with update of tx_cons.
228 * Note that it is essential to schedule a callback, no matter
229 * how few buffers are pending. Even if there is space in the
230 * transmit ring, higher layers may be blocked because too much
231 * data is outstanding: in such cases notification from Xen is
232 * likely to be the only kick that we'll get.
233 */
234 xi->tx.sring->rsp_event =
235 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
236 KeMemoryBarrier();
237 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
239 /* if queued packets, send them now?
240 network_maybe_wake_tx(dev); */
242 return NDIS_STATUS_SUCCESS;
243 }
245 static NDIS_STATUS
246 XenNet_AllocRXBuffers(struct xennet_info *xi)
247 {
248 unsigned short id;
249 PNDIS_PACKET packet;
250 PNDIS_BUFFER buffer;
251 int i, batch_target, notify;
252 RING_IDX req_prod = xi->rx.req_prod_pvt;
253 grant_ref_t ref;
254 netif_rx_request_t *req;
255 NDIS_STATUS status;
256 PVOID start;
258 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
259 for (i = 0; i < batch_target; i++)
260 {
261 /*
262 * Allocate a packet, page, and buffer. Hook them up.
263 */
264 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
265 if (status != NDIS_STATUS_SUCCESS)
266 {
267 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
268 break;
269 }
270 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
271 if (status != NDIS_STATUS_SUCCESS)
272 {
273 KdPrint(("NdisAllocateBuffer Failed! status = 0x%x\n", status));
274 NdisFreeMemory(start, 0, 0);
275 break;
276 }
277 NdisAllocatePacket(&status, &packet, xi->packet_pool);
278 if (status != NDIS_STATUS_SUCCESS)
279 {
280 KdPrint(("NdisAllocatePacket Failed! status = 0x%x\n", status));
281 NdisFreeMemory(start, 0, 0);
282 NdisFreeBuffer(buffer);
283 break;
284 }
285 NdisChainBufferAtBack(packet, buffer);
286 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
288 /* Give to netback */
289 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
290 ASSERT(!xi->rx_pkts[id]);
291 xi->rx_pkts[id] = packet;
292 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
293 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
294 ref = xi->GntTblInterface.GrantAccess(
295 xi->GntTblInterface.InterfaceHeader.Context, 0,
296 *MmGetMdlPfnArray(buffer), FALSE);
297 ASSERT((signed short)ref >= 0);
298 xi->grant_rx_ref[id] = ref;
300 req->id = id;
301 req->gref = ref;
302 }
304 xi->rx.req_prod_pvt = req_prod + i;
305 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
306 if (notify)
307 {
308 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
309 xi->event_channel);
310 }
312 return NDIS_STATUS_SUCCESS;
313 }
315 static NDIS_STATUS
316 XenNet_RxBufferCheck(struct xennet_info *xi)
317 {
318 RING_IDX cons, prod;
320 PNDIS_PACKET pkt;
321 PNDIS_BUFFER buffer;
322 PVOID buff_va;
323 UINT buff_len;
324 UINT tot_buff_len;
326 ASSERT(xi->connected);
328 do {
329 prod = xi->rx.sring->rsp_prod;
330 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
332 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
333 struct netif_rx_response *rxrsp;
335 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
336 if (rxrsp->status == NETIF_RSP_NULL)
337 continue;
339 pkt = xi->rx_pkts[rxrsp->id];
340 xi->rx_pkts[rxrsp->id] = NULL;
341 xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
342 xi->grant_rx_ref[rxrsp->id]);
343 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
345 NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
346 &tot_buff_len, NormalPagePriority);
347 ASSERT(rxrsp->offset == 0);
348 ASSERT(rxrsp->status > 0);
349 NdisAdjustBufferLength(buffer, rxrsp->status);
351 xi->stat_rx_ok++;
352 NDIS_SET_PACKET_STATUS(pkt, NDIS_STATUS_SUCCESS);
354 /* just indicate 1 packet for now */
355 NdisMIndicateReceivePacket(xi->adapter_handle, &pkt, 1);
356 }
358 xi->rx.rsp_cons = prod;
360 /*
361 * Set a new event, then check for race with update of rx_cons.
362 * Note that it is essential to schedule a callback, no matter
363 * how few buffers are pending. Even if there is space in the
364 * transmit ring, higher layers may be blocked because too much
365 * data is outstanding: in such cases notification from Xen is
366 * likely to be the only kick that we'll get.
367 */
368 xi->rx.sring->rsp_event =
369 prod + ((xi->rx.sring->req_prod - prod) >> 1) + 1;
370 KeMemoryBarrier();
371 } while ((cons == prod) && (prod != xi->rx.sring->rsp_prod));
373 /* Give netback more buffers */
374 XenNet_AllocRXBuffers(xi);
376 return NDIS_STATUS_SUCCESS;
377 }
379 static BOOLEAN
380 XenNet_Interrupt(
381 PKINTERRUPT Interrupt,
382 PVOID ServiceContext
383 )
384 {
385 struct xennet_info *xi = ServiceContext;
386 // KIRQL KIrql;
388 UNREFERENCED_PARAMETER(Interrupt);
390 //KdPrint((__DRIVER_NAME " ***XenNet Interrupt***\n"));
392 if (xi->connected)
393 {
394 XenNet_TxBufferGC(xi);
395 XenNet_RxBufferCheck(xi);
396 }
397 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
398 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
399 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
400 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
401 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
403 return TRUE;
404 }
406 static VOID
407 XenNet_BackEndStateHandler(char *Path, PVOID Data)
408 {
409 struct xennet_info *xi = Data;
410 char *Value;
411 int be_state;
412 char TmpPath[128];
413 xenbus_transaction_t xbt = 0;
414 int retry = 0;
415 char *err;
416 int i;
418 struct set_params {
419 char *name;
420 int value;
421 } params[] = {
422 {"tx-ring-ref", 0},
423 {"rx-ring-ref", 0},
424 {"event-channel", 0},
425 {"request-rx-copy", 1},
426 {"feature-rx-notify", 1},
427 {"feature-no-csum-offload", 1},
428 {"feature-sg", 1},
429 {"feature-gso-tcpv4", 0},
430 {NULL, 0},
431 };
433 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
434 XBT_NIL, Path, &Value);
435 be_state = atoi(Value);
436 ExFreePool(Value);
438 switch (be_state)
439 {
440 case XenbusStateUnknown:
441 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
442 break;
444 case XenbusStateInitialising:
445 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
446 break;
448 case XenbusStateInitWait:
449 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
451 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
452 xi->EvtChnInterface.InterfaceHeader.Context, 0);
453 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
454 xi->event_channel, XenNet_Interrupt, xi);
456 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
457 // or, allocate mem and then get mdl, then free mdl
458 xi->tx_mdl = AllocatePage();
459 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
460 NULL, FALSE, NormalPagePriority);
461 SHARED_RING_INIT(xi->tx_pgs);
462 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
463 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
464 xi->GntTblInterface.InterfaceHeader.Context, 0,
465 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
467 xi->rx_mdl = AllocatePage();
468 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
469 NULL, FALSE, NormalPagePriority);
470 SHARED_RING_INIT(xi->rx_pgs);
471 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
472 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
473 xi->GntTblInterface.InterfaceHeader.Context, 0,
474 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
476 /* fixup array for dynamic values */
477 params[0].value = xi->tx_ring_ref;
478 params[1].value = xi->rx_ring_ref;
479 params[2].value = xi->event_channel;
481 xi->XenBusInterface.StartTransaction(
482 xi->XenBusInterface.InterfaceHeader.Context, &xbt);
484 for (i = 0; params[i].name; i++)
485 {
486 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
487 xi->Path, params[i].name);
488 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
489 XBT_NIL, TmpPath, "%d", params[i].value);
490 if (err)
491 {
492 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
493 goto trouble;
494 }
495 }
497 /* commit transaction */
498 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
499 xbt, 0, &retry);
501 XenNet_AllocRXBuffers(xi);
503 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
504 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
505 xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
506 XBT_NIL, TmpPath, "%d", XenbusStateConnected);
508 /* send fake arp? */
510 xi->connected = TRUE;
512 break;
514 case XenbusStateInitialised:
515 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
516 break;
518 case XenbusStateConnected:
519 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
520 break;
522 case XenbusStateClosing:
523 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
524 break;
526 case XenbusStateClosed:
527 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
528 break;
530 default:
531 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", be_state));
532 break;
533 }
535 return;
537 trouble:
538 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
539 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
540 xbt, 1, &retry);
542 }
544 VOID
545 XenNet_Halt(
546 IN NDIS_HANDLE MiniportAdapterContext
547 )
548 {
549 UNREFERENCED_PARAMETER(MiniportAdapterContext);
550 }
552 static NDIS_STATUS
553 XenNet_Init(
554 OUT PNDIS_STATUS OpenErrorStatus,
555 OUT PUINT SelectedMediumIndex,
556 IN PNDIS_MEDIUM MediumArray,
557 IN UINT MediumArraySize,
558 IN NDIS_HANDLE MiniportAdapterHandle,
559 IN NDIS_HANDLE WrapperConfigurationContext
560 )
561 {
562 NDIS_STATUS status;
563 UINT i;
564 BOOLEAN medium_found = FALSE;
565 struct xennet_info *xi = NULL;
566 ULONG length;
567 WDF_OBJECT_ATTRIBUTES wdf_attrs;
568 char *msg;
569 char *Value;
570 char **vif_devs;
571 char TmpPath[128];
573 UNREFERENCED_PARAMETER(OpenErrorStatus);
574 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
576 /* deal with medium stuff */
577 for (i = 0; i < MediumArraySize; i++)
578 {
579 if (MediumArray[i] == NdisMedium802_3)
580 {
581 medium_found = TRUE;
582 break;
583 }
584 }
585 if (!medium_found)
586 {
587 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
588 return NDIS_STATUS_UNSUPPORTED_MEDIA;
589 }
590 *SelectedMediumIndex = i;
592 /* Alloc memory for adapter private info */
593 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
594 if (!NT_SUCCESS(status))
595 {
596 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
597 status = NDIS_STATUS_RESOURCES;
598 goto err;
599 }
600 RtlZeroMemory(xi, sizeof(*xi));
602 /* init xennet_info */
603 xi->adapter_handle = MiniportAdapterHandle;
604 xi->rx_target = RX_DFL_MIN_TARGET;
605 xi->rx_min_target = RX_DFL_MIN_TARGET;
606 xi->rx_max_target = RX_MAX_TARGET;
608 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
609 PROTOCOL_RESERVED_SIZE_IN_PACKET);
610 if (status != NDIS_STATUS_SUCCESS)
611 {
612 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
613 status = NDIS_STATUS_RESOURCES;
614 goto err;
615 }
617 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
618 if (status != NDIS_STATUS_SUCCESS)
619 {
620 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
621 status = NDIS_STATUS_RESOURCES;
622 goto err;
623 }
625 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
626 &xi->lower_do, NULL, NULL);
628 /* Initialize tx_pkts as a free chain containing every entry. */
629 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
630 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
631 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
632 }
634 for (i = 0; i < NET_RX_RING_SIZE; i++) {
635 xi->rx_pkts[i] = NULL;
636 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
637 }
639 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
640 NAME_SIZE, xi->name, &length);
641 if (!NT_SUCCESS(status))
642 {
643 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
644 status = NDIS_STATUS_FAILURE;
645 goto err;
646 }
648 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
649 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
650 NdisInterfaceInternal);
652 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
654 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
655 xi->lower_do, xi->pdo, &xi->wdf_device);
656 if (!NT_SUCCESS(status))
657 {
658 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
659 status = NDIS_STATUS_FAILURE;
660 goto err;
661 }
663 /* get lower (Xen) interfaces */
665 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
666 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
667 if(!NT_SUCCESS(status))
668 {
669 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
670 status = NDIS_STATUS_FAILURE;
671 goto err;
672 }
674 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
675 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
676 if(!NT_SUCCESS(status))
677 {
678 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
679 status = NDIS_STATUS_FAILURE;
680 goto err;
681 }
683 #if 0
684 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
685 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
686 if(!NT_SUCCESS(status))
687 {
688 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
689 status = NDIS_STATUS_FAILURE;
690 goto err;
691 }
692 #endif
694 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
695 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
696 if(!NT_SUCCESS(status))
697 {
698 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
699 status = NDIS_STATUS_FAILURE;
700 goto err;
701 }
703 msg = xi->XenBusInterface.List(xi->EvtChnInterface.InterfaceHeader.Context,
704 XBT_NIL, "device/vif", &vif_devs);
705 if (msg)
706 {
707 KdPrint((__DRIVER_NAME ": " __FUNCTION__ ": List retval is nonzero!\n"));
708 status = NDIS_STATUS_FAILURE;
709 goto err;
710 }
712 for (i = 0; vif_devs[i]; i++)
713 {
714 if (i > 0)
715 {
716 KdPrint((__DRIVER_NAME "Can only handle 1 vif so far, ignoring vif %s\n", vif_devs[i]));
717 continue;
718 }
719 RtlStringCbPrintfA(xi->Path, ARRAY_SIZE(xi->Path), "device/vif/%s", vif_devs[i]);
721 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
722 "device/vif/%s/state", vif_devs[i]);
723 KdPrint(("%s\n", TmpPath));
725 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/backend", xi->Path);
726 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
727 XBT_NIL, TmpPath, &Value);
728 if (!Value)
729 {
730 KdPrint((__DRIVER_NAME " backend Read Failed\n"));
731 }
732 else
733 {
734 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
735 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
736 }
737 ExFreePool(Value);
739 /* Add watch on backend state */
740 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
741 xi->XenBusInterface.AddWatch(xi->XenBusInterface.InterfaceHeader.Context,
742 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
744 /* get mac address */
745 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->Path);
746 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
747 XBT_NIL, TmpPath, &Value);
748 if (!Value)
749 {
750 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
751 }
752 else
753 {
754 char *s, *e;
755 int i;
757 s = Value;
759 for (i = 0; i < ETH_ALEN; i++) {
760 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
761 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
762 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
763 ExFreePool(Value);
764 ExFreePool(vif_devs);
765 status = NDIS_STATUS_FAILURE;
766 goto err;
767 }
768 s = e + 1;
769 }
770 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
771 }
772 ExFreePool(Value);
774 //XenVbd_HotPlugHandler(buffer, NULL);
775 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
776 }
777 ExFreePool(vif_devs);
779 return NDIS_STATUS_SUCCESS;
781 err:
782 NdisFreeMemory(xi, 0, 0);
783 return status;
784 }
786 NDIS_OID supported_oids[] =
787 {
788 /* general OIDs */
789 OID_GEN_SUPPORTED_LIST,
790 OID_GEN_HARDWARE_STATUS,
791 OID_GEN_MEDIA_SUPPORTED,
792 OID_GEN_MEDIA_IN_USE,
793 OID_GEN_MAXIMUM_LOOKAHEAD,
794 OID_GEN_MAXIMUM_FRAME_SIZE,
795 OID_GEN_LINK_SPEED,
796 OID_GEN_TRANSMIT_BUFFER_SPACE,
797 OID_GEN_RECEIVE_BUFFER_SPACE,
798 OID_GEN_TRANSMIT_BLOCK_SIZE,
799 OID_GEN_RECEIVE_BLOCK_SIZE,
800 OID_GEN_VENDOR_ID,
801 OID_GEN_VENDOR_DESCRIPTION,
802 OID_GEN_CURRENT_PACKET_FILTER,
803 OID_GEN_CURRENT_LOOKAHEAD,
804 OID_GEN_DRIVER_VERSION,
805 OID_GEN_MAXIMUM_TOTAL_SIZE,
806 OID_GEN_MAC_OPTIONS,
807 OID_GEN_MEDIA_CONNECT_STATUS,
808 OID_GEN_MAXIMUM_SEND_PACKETS,
809 /* stats */
810 OID_GEN_XMIT_OK,
811 OID_GEN_RCV_OK,
812 OID_GEN_XMIT_ERROR,
813 OID_GEN_RCV_ERROR,
814 OID_GEN_RCV_NO_BUFFER,
815 /* media-specific OIDs */
816 OID_802_3_PERMANENT_ADDRESS,
817 OID_802_3_CURRENT_ADDRESS,
818 OID_802_3_MULTICAST_LIST,
819 OID_802_3_MAXIMUM_LIST_SIZE,
820 };
822 NDIS_STATUS
823 XenNet_QueryInformation(
824 IN NDIS_HANDLE MiniportAdapterContext,
825 IN NDIS_OID Oid,
826 IN PVOID InformationBuffer,
827 IN ULONG InformationBufferLength,
828 OUT PULONG BytesWritten,
829 OUT PULONG BytesNeeded)
830 {
831 struct xennet_info *xi = MiniportAdapterContext;
832 UCHAR vendor_desc[] = XN_VENDOR_DESC;
833 ULONG64 temp_data;
834 PVOID data = &temp_data;
835 UINT len = 4;
836 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
838 switch(Oid)
839 {
840 case OID_GEN_SUPPORTED_LIST:
841 data = supported_oids;
842 len = sizeof(supported_oids);
843 break;
844 case OID_GEN_HARDWARE_STATUS:
845 if (!xi->connected)
846 temp_data = NdisHardwareStatusInitializing;
847 else
848 temp_data = NdisHardwareStatusReady;
849 break;
850 case OID_GEN_MEDIA_SUPPORTED:
851 temp_data = NdisMedium802_3;
852 break;
853 case OID_GEN_MEDIA_IN_USE:
854 temp_data = NdisMedium802_3;
855 break;
856 case OID_GEN_MAXIMUM_LOOKAHEAD:
857 temp_data = XN_DATA_SIZE;
858 break;
859 case OID_GEN_MAXIMUM_FRAME_SIZE:
860 temp_data = XN_MAX_PKT_SIZE;
861 break;
862 case OID_GEN_LINK_SPEED:
863 temp_data = 10000000; /* 1Gb */
864 break;
865 case OID_GEN_TRANSMIT_BUFFER_SPACE:
866 /* pkts times sizeof ring, maybe? */
867 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
868 break;
869 case OID_GEN_RECEIVE_BUFFER_SPACE:
870 /* pkts times sizeof ring, maybe? */
871 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
872 break;
873 case OID_GEN_TRANSMIT_BLOCK_SIZE:
874 temp_data = XN_MAX_PKT_SIZE;
875 break;
876 case OID_GEN_RECEIVE_BLOCK_SIZE:
877 temp_data = XN_MAX_PKT_SIZE;
878 break;
879 case OID_GEN_VENDOR_ID:
880 temp_data = XENSOURCE_MAC_HDR;
881 break;
882 case OID_GEN_VENDOR_DESCRIPTION:
883 data = vendor_desc;
884 len = sizeof(vendor_desc);
885 break;
886 case OID_GEN_CURRENT_PACKET_FILTER:
887 temp_data = xi->packet_filter;
888 break;
889 case OID_GEN_CURRENT_LOOKAHEAD:
890 temp_data = XN_MAX_PKT_SIZE;
891 break;
892 case OID_GEN_DRIVER_VERSION:
893 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
894 len = 2;
895 break;
896 case OID_GEN_MAXIMUM_TOTAL_SIZE:
897 temp_data = XN_MAX_PKT_SIZE;
898 break;
899 case OID_GEN_MAC_OPTIONS:
900 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
901 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
902 NDIS_MAC_OPTION_NO_LOOPBACK;
903 break;
904 case OID_GEN_MEDIA_CONNECT_STATUS:
905 if (xi->connected)
906 temp_data = NdisMediaStateConnected;
907 else
908 temp_data = NdisMediaStateDisconnected;
909 break;
910 case OID_GEN_MAXIMUM_SEND_PACKETS:
911 temp_data = XN_MAX_SEND_PKTS;
912 break;
913 case OID_GEN_XMIT_OK:
914 temp_data = xi->stat_tx_ok;
915 len = sizeof(ULONG64);
916 break;
917 case OID_GEN_RCV_OK:
918 temp_data = xi->stat_rx_ok;
919 len = sizeof(ULONG64);
920 break;
921 case OID_GEN_XMIT_ERROR:
922 temp_data = xi->stat_tx_error;
923 len = sizeof(ULONG64);
924 break;
925 case OID_GEN_RCV_ERROR:
926 temp_data = xi->stat_rx_error;
927 len = sizeof(ULONG64);
928 break;
929 case OID_GEN_RCV_NO_BUFFER:
930 temp_data = xi->stat_rx_no_buffer;
931 len = sizeof(ULONG64);
932 break;
933 case OID_802_3_PERMANENT_ADDRESS:
934 data = xi->perm_mac_addr;
935 len = ETH_ALEN;
936 break;
937 case OID_802_3_CURRENT_ADDRESS:
938 data = xi->curr_mac_addr;
939 len = ETH_ALEN;
940 break;
941 case OID_802_3_MULTICAST_LIST:
942 data = NULL;
943 len = 0;
944 case OID_802_3_MAXIMUM_LIST_SIZE:
945 temp_data = 0; /* no mcast support */
946 break;
947 default:
948 //KdPrint(("Unknown OID 0x%x\n", Oid));
949 status = NDIS_STATUS_NOT_SUPPORTED;
950 }
952 if (!NT_SUCCESS(status))
953 {
954 return status;
955 }
957 if (len > InformationBufferLength)
958 {
959 *BytesNeeded = len;
960 return NDIS_STATUS_BUFFER_TOO_SHORT;
961 }
963 *BytesWritten = len;
964 if (len)
965 {
966 NdisMoveMemory(InformationBuffer, data, len);
967 }
969 //KdPrint(("Got OID 0x%x\n", Oid));
971 return status;
972 }
974 NDIS_STATUS
975 XenNet_SetInformation(
976 IN NDIS_HANDLE MiniportAdapterContext,
977 IN NDIS_OID Oid,
978 IN PVOID InformationBuffer,
979 IN ULONG InformationBufferLength,
980 OUT PULONG BytesRead,
981 OUT PULONG BytesNeeded
982 )
983 {
984 UNREFERENCED_PARAMETER(MiniportAdapterContext);
985 UNREFERENCED_PARAMETER(Oid);
986 UNREFERENCED_PARAMETER(InformationBuffer);
987 UNREFERENCED_PARAMETER(InformationBufferLength);
988 UNREFERENCED_PARAMETER(BytesRead);
989 UNREFERENCED_PARAMETER(BytesNeeded);
991 KdPrint((__FUNCTION__ " called with OID=0x%x\n", Oid));
992 return NDIS_STATUS_SUCCESS;
993 }
995 VOID
996 XenNet_ReturnPacket(
997 IN NDIS_HANDLE MiniportAdapterContext,
998 IN PNDIS_PACKET Packet
999 )
1001 PNDIS_BUFFER buffer;
1002 PVOID buff_va;
1003 UINT buff_len;
1004 UINT tot_buff_len;
1006 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1008 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1009 &tot_buff_len, NormalPagePriority);
1010 ASSERT(buff_len == tot_buff_len);
1012 NdisFreeMemory(buff_va, 0, 0);
1013 NdisFreeBuffer(buffer);
1014 NdisFreePacket(Packet);
1016 //KdPrint((__FUNCTION__ " called\n"));
1019 PMDL
1020 XenNet_Linearize(PNDIS_PACKET Packet)
1022 PMDL pmdl;
1023 char *start;
1024 PNDIS_BUFFER buffer;
1025 PVOID buff_va;
1026 UINT buff_len;
1027 UINT tot_buff_len;
1029 pmdl = AllocatePage();
1031 start = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
1032 if (!start)
1034 return NULL;
1037 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1038 &tot_buff_len, NormalPagePriority);
1039 ASSERT(tot_buff_len <= PAGE_SIZE);
1041 while (buffer)
1043 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1044 RtlCopyMemory(start, buff_va, buff_len);
1045 start += buff_len;
1046 NdisGetNextBuffer(buffer, &buffer);
1049 return pmdl;
1052 VOID
1053 XenNet_SendPackets(
1054 IN NDIS_HANDLE MiniportAdapterContext,
1055 IN PPNDIS_PACKET PacketArray,
1056 IN UINT NumberOfPackets
1059 struct xennet_info *xi = MiniportAdapterContext;
1060 PNDIS_PACKET curr_packet;
1061 UINT i;
1062 struct netif_tx_request *tx;
1063 unsigned short id;
1064 int notify;
1065 PMDL pmdl;
1066 UINT pkt_size;
1068 for (i = 0; i < NumberOfPackets; i++)
1070 curr_packet = PacketArray[i];
1071 ASSERT(curr_packet);
1073 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
1075 //KdPrint(("sending pkt, len %d\n", pkt_size));
1077 pmdl = XenNet_Linearize(curr_packet);
1078 if (!pmdl)
1080 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1081 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1082 break;
1084 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
1086 id = get_id_from_freelist(xi->tx_pkts);
1087 xi->tx_pkts[id] = curr_packet;
1089 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1090 tx->id = id;
1091 tx->gref = xi->GntTblInterface.GrantAccess(
1092 xi->GntTblInterface.InterfaceHeader.Context,
1093 0,
1094 *MmGetMdlPfnArray(pmdl),
1095 TRUE);
1096 xi->grant_tx_ref[id] = tx->gref;
1097 tx->offset = 0;
1098 tx->size = (UINT16)pkt_size;
1099 tx->flags = NETTXF_csum_blank;
1101 xi->tx.req_prod_pvt++;
1103 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
1104 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
1107 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1108 if (notify)
1110 xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
1111 xi->event_channel);
1115 VOID
1116 XenNet_PnPEventNotify(
1117 IN NDIS_HANDLE MiniportAdapterContext,
1118 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1119 IN PVOID InformationBuffer,
1120 IN ULONG InformationBufferLength
1123 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1124 UNREFERENCED_PARAMETER(PnPEvent);
1125 UNREFERENCED_PARAMETER(InformationBuffer);
1126 UNREFERENCED_PARAMETER(InformationBufferLength);
1128 KdPrint((__FUNCTION__ " called\n"));
1131 VOID
1132 XenNet_Shutdown(
1133 IN NDIS_HANDLE MiniportAdapterContext
1136 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1138 KdPrint((__FUNCTION__ " called\n"));
1141 NTSTATUS
1142 DriverEntry(
1143 PDRIVER_OBJECT DriverObject,
1144 PUNICODE_STRING RegistryPath
1147 NTSTATUS status;
1148 WDF_DRIVER_CONFIG config;
1149 NDIS_HANDLE ndis_wrapper_handle;
1150 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1152 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1154 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1155 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1157 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1158 &config, WDF_NO_HANDLE);
1159 if (!NT_SUCCESS(status))
1161 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1162 return status;
1165 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1166 if (!ndis_wrapper_handle)
1168 KdPrint(("NdisMInitializeWrapper failed\n"));
1169 return NDIS_STATUS_FAILURE;
1172 /* NDIS 5.1 driver */
1173 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1174 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1176 mini_chars.HaltHandler = XenNet_Halt;
1177 mini_chars.InitializeHandler = XenNet_Init;
1178 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1179 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1180 mini_chars.ResetHandler = NULL; //TODO: fill in
1181 mini_chars.SetInformationHandler = XenNet_SetInformation;
1182 /* added in v.4 -- use multiple pkts interface */
1183 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1184 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1185 /* added in v.5.1 */
1186 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1187 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1189 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1191 /* set up upper-edge interface */
1192 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1193 if (!NT_SUCCESS(status))
1195 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1196 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1197 return status;
1200 return status;