win-pvdrivers

view xennet/xennet_rx.c @ 245:1b1f26917b6f

Moved some functions around to make packet handling functions accessible to rx and tx. Untested. Fixed a bug in xenvbd which was preventing xenvbd from booting on XP, but it may break other O/S's
author James Harper <james.harper@bendigoit.com.au>
date Sat Apr 05 14:33:33 2008 +1100 (2008-04-05)
parents d31884ed02a9
children 565483912dc0
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 "xennet.h"
23 static PMDL
24 get_page_from_freelist(struct xennet_info *xi)
25 {
26 PMDL mdl;
28 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
30 if (xi->page_free == 0)
31 {
32 mdl = AllocatePagesExtra(1, sizeof(grant_ref_t));
33 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)) = xi->XenInterface.GntTbl_GrantAccess(
34 xi->XenInterface.InterfaceHeader.Context, 0,
35 *MmGetMdlPfnArray(mdl), FALSE, 0);
36 // KdPrint(("New Mdl = %p, MmGetMdlVirtualAddress = %p, MmGetSystemAddressForMdlSafe = %p\n",
37 // mdl, MmGetMdlVirtualAddress(mdl), MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority)));
38 }
39 else
40 {
41 xi->page_free--;
42 mdl = xi->page_list[xi->page_free];
43 // KdPrint(("Old Mdl = %p, MmGetMdlVirtualAddress = %p, MmGetSystemAddressForMdlSafe = %p\n",
44 // mdl, MmGetMdlVirtualAddress(mdl), MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority)));
45 }
47 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
49 return mdl;
50 }
52 static VOID
53 free_page_freelist(struct xennet_info *xi)
54 {
55 PMDL mdl;
56 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
58 while(xi->page_free != 0)
59 {
60 xi->page_free--;
61 mdl = xi->page_list[xi->page_free];
62 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
63 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)), 0);
64 FreePages(mdl);
65 }
66 }
68 static VOID
69 put_page_on_freelist(struct xennet_info *xi, PMDL mdl)
70 {
71 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
73 // KdPrint(("Mdl = %p\n", mdl));
75 xi->page_list[xi->page_free] = mdl;
76 xi->page_free++;
78 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
79 }
81 static __inline grant_ref_t
82 get_grant_ref(PMDL mdl)
83 {
84 return *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE));
85 }
87 // Called at DISPATCH_LEVEL with rx lock held
88 static NDIS_STATUS
89 XenNet_RxBufferAlloc(struct xennet_info *xi)
90 {
91 unsigned short id;
92 PMDL mdl;
93 int i, batch_target, notify;
94 RING_IDX req_prod = xi->rx.req_prod_pvt;
95 netif_rx_request_t *req;
96 int cycles = 0;
97 #if defined(XEN_PROFILE)
98 LARGE_INTEGER tsc, dummy;
99 #endif
101 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
102 #if defined(XEN_PROFILE)
103 tsc = KeQueryPerformanceCounter(&dummy);
104 #endif
106 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
108 for (i = 0; i < batch_target; i++)
109 {
110 ASSERT(cycles++ < 256);
111 if (xi->rx_id_free == 0)
112 break;
113 mdl = get_page_from_freelist(xi);
114 if (mdl == NULL)
115 {
116 KdPrint((__DRIVER_NAME " Added %d out of %d buffers to rx ring\n", i, batch_target));
117 break;
118 }
119 xi->rx_id_free--;
121 /* Give to netback */
122 id = (USHORT)((req_prod + i) & (NET_RX_RING_SIZE - 1));
123 // KdPrint((__DRIVER_NAME " id = %d\n", id));
124 ASSERT(xi->rx_buffers[id] == NULL);
125 xi->rx_buffers[id] = mdl;
126 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
127 req->gref = get_grant_ref(mdl);
128 req->id = id;
129 }
131 xi->rx.req_prod_pvt = req_prod + i;
132 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
133 if (notify)
134 {
135 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
136 xi->event_channel);
137 }
140 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
142 #if defined(XEN_PROFILE)
143 ProfTime_RxBufferAlloc.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc.QuadPart;
144 ProfCount_RxBufferAlloc++;
145 #endif
147 return NDIS_STATUS_SUCCESS;
148 }
150 /*
151 Windows appears to insist that the checksum on received packets is correct, and won't
152 believe us when we lie about it, which happens when the packet is generated on the
153 same bridge in Dom0. Doh!
154 This is only for TCP and UDP packets. IP checksums appear to be correct anyways.
155 */
156 static VOID
157 XenNet_SumPacketData(
158 packet_info_t *pi,
159 PNDIS_PACKET packet
160 )
161 {
162 USHORT i;
163 PUCHAR buffer;
164 PMDL mdl;
165 UINT total_length;
166 UINT buffer_length;
167 USHORT buffer_offset;
168 ULONG csum;
169 PUSHORT csum_ptr;
170 USHORT remaining;
171 USHORT ip4_length;
173 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
175 #if defined(XEN_PROFILE)
176 ProfCount_RxPacketsCsumOffload++;
177 #endif
179 NdisGetFirstBufferFromPacketSafe(packet, &mdl, &buffer, &buffer_length, &total_length, NormalPagePriority);
180 ASSERT(mdl);
182 ip4_length = GET_NET_USHORT(buffer[XN_HDR_SIZE + 2]);
184 if ((USHORT)(ip4_length + XN_HDR_SIZE) != total_length)
185 {
186 KdPrint((__DRIVER_NAME " Size Mismatch %d (ip4_length + XN_HDR_SIZE) != %d (total_length)\n", ip4_length + XN_HDR_SIZE, total_length));
187 }
189 switch (pi->ip_proto)
190 {
191 case 6:
192 csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + pi->ip4_header_length + 16];
193 break;
194 case 17:
195 csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + pi->ip4_header_length + 6];
196 break;
197 default:
198 KdPrint((__DRIVER_NAME " Don't know how to calc sum for IP Proto %d\n", pi->ip_proto));
199 return;
200 }
202 *csum_ptr = 0;
204 csum = 0;
205 csum += GET_NET_USHORT(buffer[XN_HDR_SIZE + 12]) + GET_NET_USHORT(buffer[XN_HDR_SIZE + 14]); // src
206 csum += GET_NET_USHORT(buffer[XN_HDR_SIZE + 16]) + GET_NET_USHORT(buffer[XN_HDR_SIZE + 18]); // dst
207 csum += ((USHORT)buffer[XN_HDR_SIZE + 9]);
209 remaining = ip4_length - pi->ip4_header_length;
211 csum += remaining;
213 for (buffer_offset = i = XN_HDR_SIZE + pi->ip4_header_length; i < total_length - 1; i += 2, buffer_offset += 2)
214 {
215 if (buffer_offset == buffer_length - 1) // deal with a buffer ending on an odd byte boundary
216 {
217 csum += (USHORT)buffer[buffer_offset] << 8;
218 NdisGetNextBuffer(mdl, &mdl);
219 if (mdl == NULL)
220 {
221 KdPrint((__DRIVER_NAME " Ran out of buffers\n"));
222 return;
223 }
224 NdisQueryBufferSafe(mdl, &buffer, &buffer_length, NormalPagePriority);
225 // KdPrint((__DRIVER_NAME " New buffer - unaligned...\n"));
226 csum += ((USHORT)buffer[0]);
227 buffer_offset = (USHORT)-1;
228 }
229 else
230 {
231 if (buffer_offset == buffer_length)
232 {
233 // KdPrint((__DRIVER_NAME " New buffer - aligned...\n"));
234 NdisGetNextBuffer(mdl, &mdl);
235 if (mdl == NULL)
236 {
237 KdPrint((__DRIVER_NAME " Ran out of buffers\n"));
238 return;
239 }
240 NdisQueryBufferSafe(mdl, &buffer, &buffer_length, NormalPagePriority);
241 buffer_offset = 0;
242 }
243 csum += GET_NET_USHORT(buffer[buffer_offset]);
244 }
245 }
246 if (i != total_length) // last odd byte
247 {
248 csum += ((USHORT)buffer[buffer_offset] << 8);
249 }
250 while (csum & 0xFFFF0000)
251 csum = (csum & 0xFFFF) + (csum >> 16);
252 *csum_ptr = (USHORT)~GET_NET_USHORT(csum);
254 // KdPrint((__DRIVER_NAME " csum = %04x\n", *csum_ptr));
256 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
257 }
259 static PNDIS_PACKET
260 XenNet_MakePacket(
261 struct xennet_info *xi
262 )
263 {
264 PNDIS_PACKET packet;
265 PUCHAR in_buffer;
266 PNDIS_BUFFER out_mdl;
267 PUCHAR out_buffer;
268 USHORT out_offset;
269 USHORT out_remaining;
270 USHORT length;
271 USHORT new_ip4_length;
272 NDIS_STATUS status;
273 USHORT i;
275 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
277 NdisAllocatePacket(&status, &packet, xi->packet_pool);
278 ASSERT(status == NDIS_STATUS_SUCCESS);
279 xi->rx_outstanding++;
280 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
282 if (!xi->rxpi.split_required)
283 {
284 for (i = 0; i < xi->rxpi.mdl_count; i++)
285 NdisChainBufferAtBack(packet, xi->rxpi.mdls[i]);
286 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
287 }
288 else
289 {
290 out_mdl = get_page_from_freelist(xi);
291 out_buffer = MmGetMdlVirtualAddress(out_mdl);
292 out_offset = XN_HDR_SIZE + xi->rxpi.ip4_header_length + xi->rxpi.tcp_header_length;
293 out_remaining = min(xi->rxpi.mss, xi->rxpi.tcp_remaining);
294 NdisAdjustBufferLength(out_mdl, out_offset + out_remaining);
295 memcpy(out_buffer, xi->rxpi.header, out_offset);
296 new_ip4_length = out_remaining + xi->rxpi.ip4_header_length + xi->rxpi.tcp_header_length;
297 SET_NET_USHORT(out_buffer[XN_HDR_SIZE + 2], new_ip4_length);
298 SET_NET_ULONG(out_buffer[XN_HDR_SIZE + xi->rxpi.ip4_header_length + 4], xi->rxpi.tcp_seq);
299 xi->rxpi.tcp_seq += out_remaining;
300 xi->rxpi.tcp_remaining = xi->rxpi.tcp_remaining - out_remaining;
301 do
302 {
303 ASSERT(xi->rxpi.curr_mdl < xi->rxpi.mdl_count);
304 in_buffer = XenNet_GetData(xi, out_remaining, &length);
305 memcpy(&out_buffer[out_offset], in_buffer, length);
306 out_remaining = out_remaining - length;
307 out_offset = out_offset + length;
308 } while (out_remaining != 0); // && in_buffer != NULL);
309 NdisChainBufferAtBack(packet, out_mdl);
310 XenNet_SumIpHeader(xi, packet);
311 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
312 }
314 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (%p)\n", packet));
315 return packet;
316 }
318 static VOID
319 XenNet_MakePackets(
320 struct xennet_info *xi,
321 PNDIS_PACKET *packets,
322 PULONG packet_count_p
323 )
324 {
325 USHORT i;
327 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "(packets = %p, packet_count = %d)\n", packets, *packet_count_p));
329 XenNet_ParsePacketHeader(xi);
330 switch (xi->rxpi.ip_proto)
331 {
332 case 6: // TCP
333 if (xi->rxpi.split_required)
334 break;
335 // fallthrough
336 case 17: // UDP
337 packets[*packet_count_p] = XenNet_MakePacket(xi);
338 if (xi->rxpi.csum_calc_required)
339 XenNet_SumPacketData(xi, packets[*packet_count_p]);
340 (*packet_count_p)++;
341 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (TCP/UDP)\n"));
342 return;
343 default:
344 packets[*packet_count_p] = XenNet_MakePacket(xi);
345 (*packet_count_p)++;
346 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (Other)\n"));
347 return;
348 }
349 // KdPrint((__DRIVER_NAME " splitting packet\n"));
350 xi->rxpi.tcp_remaining = xi->rxpi.tcp_length;
351 if (MmGetMdlByteCount(xi->rxpi.mdls[0]) > (ULONG)(XN_HDR_SIZE + xi->rxpi.ip4_header_length + xi->rxpi.tcp_header_length))
352 xi->rxpi.curr_mdl_offset = XN_HDR_SIZE + xi->rxpi.ip4_header_length + xi->rxpi.tcp_header_length;
353 else
354 xi->rxpi.curr_mdl = 1;
356 while (xi->rxpi.tcp_remaining)
357 {
358 // KdPrint((__DRIVER_NAME " tcp_remaining = %d\n", xi->rxpi.tcp_remaining));
359 packets[*packet_count_p] = XenNet_MakePacket(xi);
360 XenNet_SumPacketData(xi, packets[*packet_count_p]);
361 (*packet_count_p)++;
362 }
363 ASSERT(xi->rxpi.curr_mdl == xi->rxpi.mdl_count);
364 // KdPrint((__DRIVER_NAME " tcp_remaining = %d\n", xi->rxpi.tcp_remaining));
365 // TODO: restore psh status to last packet
366 for (i = 0; i < xi->rxpi.mdl_count; i++)
367 {
368 NdisAdjustBufferLength(xi->rxpi.mdls[i], PAGE_SIZE);
369 put_page_on_freelist(xi, xi->rxpi.mdls[i]);
370 }
371 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (split)\n"));
372 }
374 // Called at DISPATCH_LEVEL
375 NDIS_STATUS
376 XenNet_RxBufferCheck(struct xennet_info *xi)
377 {
378 RING_IDX cons, prod;
379 PNDIS_PACKET packets[NET_RX_RING_SIZE];
380 ULONG packet_count;
381 PMDL mdl;
382 int moretodo;
383 struct netif_rx_response *rxrsp = NULL;
384 struct netif_extra_info *ei;
385 USHORT id;
386 int cycles = 0;
387 #if defined(XEN_PROFILE)
388 LARGE_INTEGER tsc, tsc2, dummy;
389 #endif
391 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
393 #if defined(XEN_PROFILE)
394 tsc = tsc2 = KeQueryPerformanceCounter(&dummy);
395 #endif
397 ASSERT(xi->connected);
399 KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
401 packet_count = 0;
402 do {
403 ASSERT(cycles++ < 256);
404 prod = xi->rx.sring->rsp_prod;
405 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
407 for (cons = xi->rx.rsp_cons; cons != prod; cons++)
408 {
409 ASSERT(cycles++ < 256);
410 id = (USHORT)(cons & (NET_RX_RING_SIZE - 1));
411 mdl = xi->rx_buffers[id];
412 xi->rx_buffers[id] = NULL;
413 xi->rx_id_free++;
414 if (xi->rxpi.extra_info)
415 {
416 put_page_on_freelist(xi, mdl);
417 ei = (struct netif_extra_info *)RING_GET_RESPONSE(&xi->rx, cons);
418 xi->rxpi.extra_info = (BOOLEAN)!!(ei->flags & XEN_NETIF_EXTRA_FLAG_MORE);
419 switch (ei->type)
420 {
421 case XEN_NETIF_EXTRA_TYPE_GSO:
422 switch (ei->u.gso.type)
423 {
424 case XEN_NETIF_GSO_TYPE_TCPV4:
425 xi->rxpi.mss = ei->u.gso.size;
426 // TODO - put this assertion somewhere ASSERT(header_len + xi->rxpi.mss <= PAGE_SIZE); // this limits MTU to PAGE_SIZE - XN_HEADER_LEN
427 break;
428 default:
429 KdPrint((__DRIVER_NAME " Unknown GSO type (%d) detected\n", ei->u.gso.type));
430 break;
431 }
432 break;
433 default:
434 KdPrint((__DRIVER_NAME " Unknown extra info type (%d) detected\n", ei->type));
435 break;
436 }
437 }
438 else
439 {
440 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
441 if (rxrsp->status <= 0
442 || rxrsp->offset + rxrsp->status > PAGE_SIZE)
443 {
444 KdPrint((__DRIVER_NAME ": Error: rxrsp offset %d, size %d\n",
445 rxrsp->offset, rxrsp->status));
446 put_page_on_freelist(xi, mdl);
447 continue;
448 }
449 ASSERT(rxrsp->id == id);
450 if (!xi->rxpi.more_frags) // handling the packet's 1st buffer
451 {
452 if (rxrsp->flags & NETRXF_csum_blank)
453 xi->rxpi.csum_calc_required = TRUE;
454 #if 0
455 if (rxrsp->flags & (NETRXF_csum_blank|NETRXF_data_validated) && xi->config_csum)
456 {
457 //KdPrint((__DRIVER_NAME " RX csum blank = %d, validated = %d\n", !!(rxrsp->flags & NETRXF_csum_blank), !!(rxrsp->flags & NETRXF_data_validated)));
458 if (rxrsp->flags & NETRXF_csum_blank)
459 xi->rxpi.csum_calc_required = TRUE;
460 }
461 #endif
462 }
463 NdisAdjustBufferLength(mdl, rxrsp->status);
464 xi->rxpi.mdls[xi->rxpi.mdl_count++] = mdl;
465 xi->rxpi.extra_info = (BOOLEAN)!!(rxrsp->flags & NETRXF_extra_info);
466 xi->rxpi.more_frags = (BOOLEAN)!!(rxrsp->flags & NETRXF_more_data);
467 xi->rxpi.total_length = xi->rxpi.total_length + rxrsp->status;
468 }
470 /* Packet done, add it to the list */
471 if (!xi->rxpi.more_frags && !xi->rxpi.extra_info)
472 {
473 XenNet_MakePackets(xi, packets, &packet_count);
474 RtlZeroMemory(&xi->rxpi, sizeof(xi->rxpi));
475 }
476 }
477 ASSERT(packet_count < NET_RX_RING_SIZE);
478 xi->rx.rsp_cons = prod;
479 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
480 } while (moretodo);
482 /* Give netback more buffers */
483 XenNet_RxBufferAlloc(xi);
485 KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
487 #if defined(XEN_PROFILE)
488 ProfTime_RxBufferCheckTopHalf.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc2.QuadPart;
489 tsc2 = KeQueryPerformanceCounter(&dummy);
490 #endif
492 if (packet_count > 0)
493 {
494 NdisMIndicateReceivePacket(xi->adapter_handle, packets, packet_count);
495 #if defined(XEN_PROFILE)
496 ProfCount_CallsToIndicateReceive++;
497 #endif
498 }
500 #if defined(XEN_PROFILE)
501 ProfTime_RxBufferCheck.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc.QuadPart;
502 ProfTime_RxBufferCheckBotHalf.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc2.QuadPart;
503 ProfCount_RxBufferCheck++;
504 #endif
506 return NDIS_STATUS_SUCCESS;
507 }
509 /* called at DISPATCH_LEVEL */
511 VOID
512 XenNet_ReturnPacket(
513 IN NDIS_HANDLE MiniportAdapterContext,
514 IN PNDIS_PACKET Packet
515 )
516 {
517 struct xennet_info *xi = MiniportAdapterContext;
518 PMDL mdl;
519 int cycles = 0;
520 #if defined(XEN_PROFILE)
521 LARGE_INTEGER tsc, dummy;
522 #endif
524 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ " (%p)\n", Packet));
526 #if defined(XEN_PROFILE)
527 tsc = KeQueryPerformanceCounter(&dummy);
528 #endif
530 KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
532 NdisUnchainBufferAtBack(Packet, &mdl);
533 while (mdl)
534 {
535 ASSERT(cycles++ < 256);
536 NdisAdjustBufferLength(mdl, PAGE_SIZE);
537 put_page_on_freelist(xi, mdl);
538 NdisUnchainBufferAtBack(Packet, &mdl);
539 }
541 NdisFreePacket(Packet);
542 xi->rx_outstanding--;
544 KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
546 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
548 #if defined(XEN_PROFILE)
549 ProfTime_ReturnPacket.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc.QuadPart;
550 ProfCount_ReturnPacket++;
551 #endif
552 }
554 /*
555 Free all Rx buffers (on halt, for example)
556 The ring must be stopped at this point.
557 */
558 static void
559 XenNet_RxBufferFree(struct xennet_info *xi)
560 {
561 int i;
562 PMDL mdl;
564 ASSERT(!xi->connected);
566 for (i = 0; i < NET_RX_RING_SIZE; i++)
567 {
568 if (!xi->rx_buffers[i])
569 continue;
571 mdl = xi->rx_buffers[i];
572 NdisAdjustBufferLength(mdl, PAGE_SIZE);
573 put_page_on_freelist(xi, mdl);
574 }
575 }
577 BOOLEAN
578 XenNet_RxInit(xennet_info_t *xi)
579 {
580 int i;
582 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
584 xi->rx_mdl = AllocatePage();
585 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl);
586 SHARED_RING_INIT(xi->rx_pgs);
587 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
588 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
589 xi->XenInterface.InterfaceHeader.Context, 0,
590 *MmGetMdlPfnArray(xi->rx_mdl), FALSE, 0);
591 xi->rx_id_free = NET_RX_RING_SIZE;
593 for (i = 0; i < NET_RX_RING_SIZE; i++)
594 {
595 xi->rx_buffers[i] = NULL;
596 }
598 xi->rx_outstanding = 0;
599 XenNet_RxBufferAlloc(xi);
601 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
603 return TRUE;
604 }
606 BOOLEAN
607 XenNet_RxShutdown(xennet_info_t *xi)
608 {
609 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
611 XenNet_RxBufferFree(xi);
613 free_page_freelist(xi);
615 /* free RX resources */
616 if (xi->XenInterface.GntTbl_EndAccess(
617 xi->XenInterface.InterfaceHeader.Context, xi->rx_ring_ref, 0))
618 {
619 xi->rx_ring_ref = GRANT_INVALID_REF;
620 FreePages(xi->rx_mdl);
621 }
622 xi->rx_pgs = NULL;
624 ASSERT(xi->rx_outstanding == 0);
626 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
628 return TRUE;
629 }