win-pvdrivers

view xennet/xennet_rx.c @ 433:b1da81cc9868

updates
author James Harper <james.harper@bendigoit.com.au>
date Tue Oct 14 10:45:56 2008 +1100 (2008-10-14)
parents 68565fbe4425
children c4204f69c506
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 // Called at DISPATCH_LEVEL with rx lock held
24 static NDIS_STATUS
25 XenNet_RxBufferAlloc(struct xennet_info *xi)
26 {
27 unsigned short id;
28 PMDL mdl;
29 ULONG i, notify;
30 ULONG batch_target;
31 RING_IDX req_prod = xi->rx.req_prod_pvt;
32 netif_rx_request_t *req;
34 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
36 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
38 if (batch_target < (xi->rx_target >> 2))
39 return NDIS_STATUS_SUCCESS; /* only refill if we are less than 3/4 full already */
41 for (i = 0; i < batch_target; i++)
42 {
43 if (xi->rx_id_free == 0)
44 {
45 KdPrint((__DRIVER_NAME " Added %d out of %d buffers to rx ring (ran out of id's)\n", i, batch_target));
46 break;
47 }
48 mdl = XenFreelist_GetPage(&xi->rx_freelist);
49 if (!mdl)
50 {
51 KdPrint((__DRIVER_NAME " Added %d out of %d buffers to rx ring (no free pages)\n", i, batch_target));
52 break;
53 }
54 xi->rx_id_free--;
56 /* Give to netback */
57 id = (USHORT)((req_prod + i) & (NET_RX_RING_SIZE - 1));
58 ASSERT(xi->rx_mdls[id] == NULL);
59 xi->rx_mdls[id] = mdl;
60 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
61 req->gref = get_grant_ref(mdl);
62 ASSERT(req->gref != INVALID_GRANT_REF);
63 req->id = id;
64 }
66 xi->rx.req_prod_pvt = req_prod + i;
67 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
68 if (notify)
69 {
70 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->event_channel);
71 }
73 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
75 return NDIS_STATUS_SUCCESS;
76 }
78 static PNDIS_PACKET
79 get_packet_from_freelist(struct xennet_info *xi)
80 {
81 NDIS_STATUS status;
82 PNDIS_PACKET packet;
84 //ASSERT(!KeTestSpinLock(&xi->rx_lock));
86 if (!xi->rx_packet_free)
87 {
88 NdisAllocatePacket(&status, &packet, xi->packet_pool);
89 if (status != NDIS_STATUS_SUCCESS)
90 return NULL;
91 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
92 }
93 else
94 {
95 xi->rx_packet_free--;
96 packet = xi->rx_packet_list[xi->rx_packet_free];
97 }
98 return packet;
99 }
101 static VOID
102 put_packet_on_freelist(struct xennet_info *xi, PNDIS_PACKET packet)
103 {
104 //ASSERT(!KeTestSpinLock(&xi->rx_lock));
106 if (xi->rx_packet_free == NET_RX_RING_SIZE * 2)
107 {
108 KdPrint((__DRIVER_NAME " packet free list full - releasing packet\n"));
109 NdisFreePacket(packet);
110 return;
111 }
112 NdisReinitializePacket(packet);
113 xi->rx_packet_list[xi->rx_packet_free] = packet;
114 xi->rx_packet_free++;
115 }
117 static VOID
118 packet_freelist_dispose(struct xennet_info *xi)
119 {
120 while(xi->rx_packet_free != 0)
121 {
122 xi->rx_packet_free--;
123 NdisFreePacket(xi->rx_packet_list[xi->rx_packet_free]);
124 }
125 }
127 static PNDIS_PACKET
128 XenNet_MakePacket(struct xennet_info *xi)
129 {
130 PNDIS_PACKET packet;
131 PUCHAR in_buffer;
132 PNDIS_BUFFER out_mdl;
133 PUCHAR out_buffer;
134 USHORT out_offset;
135 USHORT out_remaining;
136 USHORT length;
137 USHORT new_ip4_length;
138 //NDIS_STATUS status;
139 USHORT i;
141 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
143 if (!xi->rxpi.split_required)
144 {
145 packet = get_packet_from_freelist(xi);
146 if (packet == NULL)
147 {
148 /* buffers will be freed in MakePackets */
149 return NULL;
150 }
151 xi->rx_outstanding++;
152 for (i = 0; i < xi->rxpi.mdl_count; i++)
153 NdisChainBufferAtBack(packet, xi->rxpi.mdls[i]);
155 NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpLargeSendPacketInfo) = UlongToPtr(xi->rxpi.mss);
157 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
158 }
159 else
160 {
161 out_mdl = XenFreelist_GetPage(&xi->rx_freelist);
162 if (!out_mdl)
163 return NULL;
164 packet = get_packet_from_freelist(xi);
165 if (packet == NULL)
166 {
167 XenFreelist_PutPage(&xi->rx_freelist, out_mdl);
168 return NULL;
169 }
170 xi->rx_outstanding++;
171 out_buffer = MmGetMdlVirtualAddress(out_mdl);
172 out_offset = XN_HDR_SIZE + xi->rxpi.ip4_header_length + xi->rxpi.tcp_header_length;
173 out_remaining = min(xi->rxpi.mss, xi->rxpi.tcp_remaining);
174 NdisAdjustBufferLength(out_mdl, out_offset + out_remaining);
175 memcpy(out_buffer, xi->rxpi.header, out_offset);
176 new_ip4_length = out_remaining + xi->rxpi.ip4_header_length + xi->rxpi.tcp_header_length;
177 SET_NET_USHORT(&out_buffer[XN_HDR_SIZE + 2], new_ip4_length);
178 SET_NET_ULONG(&out_buffer[XN_HDR_SIZE + xi->rxpi.ip4_header_length + 4], xi->rxpi.tcp_seq);
179 xi->rxpi.tcp_seq += out_remaining;
180 xi->rxpi.tcp_remaining = xi->rxpi.tcp_remaining - out_remaining;
181 do
182 {
183 ASSERT(xi->rxpi.curr_mdl < xi->rxpi.mdl_count);
184 in_buffer = XenNet_GetData(&xi->rxpi, out_remaining, &length);
185 memcpy(&out_buffer[out_offset], in_buffer, length);
186 out_remaining = out_remaining - length;
187 out_offset = out_offset + length;
188 } while (out_remaining != 0);
189 NdisChainBufferAtBack(packet, out_mdl);
190 XenNet_SumIpHeader(out_buffer, xi->rxpi.ip4_header_length);
191 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
192 }
193 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (%p)\n", packet));
194 return packet;
195 }
197 /*
198 Windows appears to insist that the checksum on received packets is correct, and won't
199 believe us when we lie about it, which happens when the packet is generated on the
200 same bridge in Dom0. Doh!
201 This is only for TCP and UDP packets. IP checksums appear to be correct anyways.
202 */
203 static VOID
204 XenNet_SumPacketData(
205 packet_info_t *pi,
206 PNDIS_PACKET packet
207 )
208 {
209 USHORT i;
210 PUCHAR buffer;
211 PMDL mdl;
212 UINT total_length;
213 UINT buffer_length;
214 USHORT buffer_offset;
215 ULONG csum;
216 PUSHORT csum_ptr;
217 USHORT remaining;
218 USHORT ip4_length;
220 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
222 NdisGetFirstBufferFromPacketSafe(packet, &mdl, &buffer, &buffer_length, &total_length, NormalPagePriority);
223 ASSERT(mdl);
225 ip4_length = GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 2]);
227 if ((USHORT)(ip4_length + XN_HDR_SIZE) != total_length)
228 {
229 KdPrint((__DRIVER_NAME " Size Mismatch %d (ip4_length + XN_HDR_SIZE) != %d (total_length)\n", ip4_length + XN_HDR_SIZE, total_length));
230 }
232 switch (pi->ip_proto)
233 {
234 case 6:
235 csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + pi->ip4_header_length + 16];
236 break;
237 case 17:
238 csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + pi->ip4_header_length + 6];
239 break;
240 default:
241 KdPrint((__DRIVER_NAME " Don't know how to calc sum for IP Proto %d\n", pi->ip_proto));
242 return;
243 }
245 *csum_ptr = 0;
247 csum = 0;
248 csum += GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 12]) + GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 14]); // src
249 csum += GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 16]) + GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 18]); // dst
250 csum += ((USHORT)buffer[XN_HDR_SIZE + 9]);
252 remaining = ip4_length - pi->ip4_header_length;
254 csum += remaining;
256 for (buffer_offset = i = XN_HDR_SIZE + pi->ip4_header_length; i < total_length - 1; i += 2, buffer_offset += 2)
257 {
258 if (buffer_offset == buffer_length - 1) // deal with a buffer ending on an odd byte boundary
259 {
260 csum += (USHORT)buffer[buffer_offset] << 8;
261 NdisGetNextBuffer(mdl, &mdl);
262 if (mdl == NULL)
263 {
264 KdPrint((__DRIVER_NAME " Ran out of buffers\n"));
265 return;
266 }
267 NdisQueryBufferSafe(mdl, &buffer, &buffer_length, NormalPagePriority);
268 csum += ((USHORT)buffer[0]);
269 buffer_offset = (USHORT)-1;
270 }
271 else
272 {
273 if (buffer_offset == buffer_length)
274 {
275 // KdPrint((__DRIVER_NAME " New buffer - aligned...\n"));
276 NdisGetNextBuffer(mdl, &mdl);
277 if (mdl == NULL)
278 {
279 KdPrint((__DRIVER_NAME " Ran out of buffers\n"));
280 return;
281 }
282 NdisQueryBufferSafe(mdl, (PVOID) &buffer, &buffer_length, NormalPagePriority);
283 buffer_offset = 0;
284 }
285 csum += GET_NET_PUSHORT(&buffer[buffer_offset]);
286 }
287 }
288 if (i != total_length) // last odd byte
289 {
290 csum += ((USHORT)buffer[buffer_offset] << 8);
291 }
292 while (csum & 0xFFFF0000)
293 csum = (csum & 0xFFFF) + (csum >> 16);
294 *csum_ptr = (USHORT)~GET_NET_USHORT((USHORT)csum);
296 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
297 }
299 static ULONG
300 XenNet_MakePackets(
301 struct xennet_info *xi,
302 PLIST_ENTRY rx_packet_list
303 )
304 {
305 USHORT i;
306 ULONG packet_count = 0;
307 PNDIS_PACKET packet;
308 PLIST_ENTRY entry;
309 UCHAR psh;
310 PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
312 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "(packets = %p, packet_count = %d)\n", packets, *packet_count_p));
314 XenNet_ParsePacketHeader(&xi->rxpi);
315 switch (xi->rxpi.ip_proto)
316 {
317 case 6: // TCP
318 if (xi->rxpi.split_required)
319 break;
320 // fallthrough
321 case 17: // UDP
322 packet = XenNet_MakePacket(xi);
323 if (packet == NULL)
324 {
325 KdPrint((__DRIVER_NAME " Ran out of packets\n"));
326 xi->stat_rx_no_buffer++;
327 packet_count = 0;
328 goto done;
329 }
330 if (xi->rxpi.csum_blank)
331 XenNet_SumPacketData(&xi->rxpi, packet);
332 if (xi->rxpi.csum_blank || xi->rxpi.data_validated)
333 {
334 csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
335 packet, TcpIpChecksumPacketInfo);
336 csum_info->Receive.NdisPacketTcpChecksumSucceeded = TRUE;
337 }
338 entry = (PLIST_ENTRY)&packet->MiniportReservedEx[sizeof(PVOID)];
339 InsertTailList(rx_packet_list, entry);
340 RtlZeroMemory(&xi->rxpi, sizeof(xi->rxpi));
341 return 1;
342 default:
343 packet = XenNet_MakePacket(xi);
344 if (packet == NULL)
345 {
346 KdPrint((__DRIVER_NAME " Ran out of packets\n"));
347 xi->stat_rx_no_buffer++;
348 packet_count = 0;
349 goto done;
350 }
351 entry = (PLIST_ENTRY)&packet->MiniportReservedEx[sizeof(PVOID)];
352 InsertTailList(rx_packet_list, entry);
353 RtlZeroMemory(&xi->rxpi, sizeof(xi->rxpi));
354 return 1;
355 }
357 xi->rxpi.tcp_remaining = xi->rxpi.tcp_length;
358 if (MmGetMdlByteCount(xi->rxpi.mdls[0]) > (ULONG)(XN_HDR_SIZE + xi->rxpi.ip4_header_length + xi->rxpi.tcp_header_length))
359 xi->rxpi.curr_mdl_offset = XN_HDR_SIZE + xi->rxpi.ip4_header_length + xi->rxpi.tcp_header_length;
360 else
361 xi->rxpi.curr_mdl = 1;
363 /* we can make certain assumptions here as the following code is only for tcp4 */
364 psh = xi->rxpi.header[XN_HDR_SIZE + xi->rxpi.ip4_header_length + 13] & 8;
365 while (xi->rxpi.tcp_remaining)
366 {
367 PUCHAR buffer;
368 PMDL mdl;
369 UINT total_length;
370 UINT buffer_length;
371 packet = XenNet_MakePacket(xi);
372 if (!packet)
373 {
374 KdPrint((__DRIVER_NAME " Ran out of packets\n"));
375 xi->stat_rx_no_buffer++;
376 break; /* we are out of memory - just drop the packets */
377 }
378 csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
379 packet, TcpIpChecksumPacketInfo);
380 csum_info->Receive.NdisPacketTcpChecksumSucceeded = TRUE;
381 if (psh)
382 {
383 NdisGetFirstBufferFromPacketSafe(packet, &mdl, &buffer, &buffer_length, &total_length, NormalPagePriority);
384 if (xi->rxpi.tcp_remaining)
385 {
386 buffer[XN_HDR_SIZE + xi->rxpi.ip4_header_length + 13] &= ~8;
387 }
388 else
389 {
390 buffer[XN_HDR_SIZE + xi->rxpi.ip4_header_length + 13] |= 8;
391 }
392 }
393 XenNet_SumPacketData(&xi->rxpi, packet);
394 entry = (PLIST_ENTRY)&packet->MiniportReservedEx[sizeof(PVOID)];
395 InsertTailList(rx_packet_list, entry);
396 packet_count++;
397 }
399 done:
400 for (i = 0; i < xi->rxpi.mdl_count; i++)
401 {
402 NdisAdjustBufferLength(xi->rxpi.mdls[i], PAGE_SIZE);
403 XenFreelist_PutPage(&xi->rx_freelist, xi->rxpi.mdls[i]);
404 }
405 RtlZeroMemory(&xi->rxpi, sizeof(xi->rxpi));
406 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (split)\n"));
407 return packet_count;
408 }
410 #define MAXIMUM_PACKETS_PER_INDICATE 256
412 // Called at DISPATCH_LEVEL
413 NDIS_STATUS
414 XenNet_RxBufferCheck(struct xennet_info *xi)
415 {
416 RING_IDX cons, prod;
417 LIST_ENTRY rx_packet_list;
418 PLIST_ENTRY entry;
419 PNDIS_PACKET packets[MAXIMUM_PACKETS_PER_INDICATE];
420 ULONG packet_count = 0;
421 PMDL mdl;
422 struct netif_rx_response *rxrsp = NULL;
423 struct netif_extra_info *ei;
424 USHORT id;
425 int more_to_do;
427 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
429 ASSERT(xi->connected);
431 KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
433 InitializeListHead(&rx_packet_list);
435 do {
436 prod = xi->rx.sring->rsp_prod;
437 KeMemoryBarrier(); /* Ensure we see responses up to 'prod'. */
439 for (cons = xi->rx.rsp_cons; cons != prod; cons++)
440 {
441 id = (USHORT)(cons & (NET_RX_RING_SIZE - 1));
442 ASSERT(xi->rx_mdls[id]);
443 mdl = xi->rx_mdls[id];
444 xi->rx_mdls[id] = NULL;
445 xi->rx_id_free++;
446 if (xi->rxpi.extra_info)
447 {
448 XenFreelist_PutPage(&xi->rx_freelist, mdl);
449 ei = (struct netif_extra_info *)RING_GET_RESPONSE(&xi->rx, cons);
450 xi->rxpi.extra_info = (BOOLEAN)!!(ei->flags & XEN_NETIF_EXTRA_FLAG_MORE);
451 switch (ei->type)
452 {
453 case XEN_NETIF_EXTRA_TYPE_GSO:
454 switch (ei->u.gso.type)
455 {
456 case XEN_NETIF_GSO_TYPE_TCPV4:
457 xi->rxpi.mss = ei->u.gso.size;
458 // TODO - put this assertion somewhere ASSERT(header_len + xi->rxpi.mss <= PAGE_SIZE); // this limits MTU to PAGE_SIZE - XN_HEADER_LEN
459 break;
460 default:
461 KdPrint((__DRIVER_NAME " Unknown GSO type (%d) detected\n", ei->u.gso.type));
462 break;
463 }
464 break;
465 default:
466 KdPrint((__DRIVER_NAME " Unknown extra info type (%d) detected\n", ei->type));
467 break;
468 }
469 }
470 else
471 {
472 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
473 if (rxrsp->status <= 0
474 || rxrsp->offset + rxrsp->status > PAGE_SIZE)
475 {
476 KdPrint((__DRIVER_NAME ": Error: rxrsp offset %d, size %d\n",
477 rxrsp->offset, rxrsp->status));
478 ASSERT(!xi->rxpi.extra_info);
479 XenFreelist_PutPage(&xi->rx_freelist, mdl);
480 continue;
481 }
482 ASSERT(rxrsp->id == id);
483 if (!xi->rxpi.more_frags) // handling the packet's 1st buffer
484 {
485 if (rxrsp->flags & NETRXF_csum_blank)
486 xi->rxpi.csum_blank = TRUE;
487 if (rxrsp->flags & NETRXF_data_validated)
488 xi->rxpi.data_validated = TRUE;
489 }
490 NdisAdjustBufferLength(mdl, rxrsp->status);
491 xi->rxpi.mdls[xi->rxpi.mdl_count++] = mdl;
492 xi->rxpi.extra_info = (BOOLEAN)!!(rxrsp->flags & NETRXF_extra_info);
493 xi->rxpi.more_frags = (BOOLEAN)!!(rxrsp->flags & NETRXF_more_data);
494 xi->rxpi.total_length = xi->rxpi.total_length + rxrsp->status;
495 }
497 /* Packet done, add it to the list */
498 if (!xi->rxpi.more_frags && !xi->rxpi.extra_info)
499 {
500 packet_count += XenNet_MakePackets(xi, &rx_packet_list);
501 }
502 }
503 xi->rx.rsp_cons = cons;
504 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, more_to_do);
505 } while (more_to_do);
507 if (xi->rxpi.more_frags || xi->rxpi.extra_info)
508 KdPrint((__DRIVER_NAME " Partial receive (more_frags = %d, extra_info = %d, total_length = %d, mdl_count = %d)\n", xi->rxpi.more_frags, xi->rxpi.extra_info, xi->rxpi.total_length, xi->rxpi.mdl_count));
510 /* Give netback more buffers */
511 XenNet_RxBufferAlloc(xi);
513 KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
515 entry = RemoveHeadList(&rx_packet_list);
516 packet_count = 0;
517 while (entry != &rx_packet_list)
518 {
519 packets[packet_count++] = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
520 entry = RemoveHeadList(&rx_packet_list);
521 if (packet_count == MAXIMUM_PACKETS_PER_INDICATE || entry == &rx_packet_list)
522 {
523 NdisMIndicateReceivePacket(xi->adapter_handle, packets, packet_count);
524 packet_count = 0;
525 }
526 }
527 return NDIS_STATUS_SUCCESS;
528 }
530 /* called at DISPATCH_LEVEL */
531 /* it's okay for return packet to be called while resume_state != RUNNING as the packet will simply be added back to the freelist, the grants will be fixed later */
532 VOID DDKAPI
533 XenNet_ReturnPacket(
534 IN NDIS_HANDLE MiniportAdapterContext,
535 IN PNDIS_PACKET Packet
536 )
537 {
538 struct xennet_info *xi = MiniportAdapterContext;
539 PMDL mdl;
540 KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
542 NdisUnchainBufferAtBack(Packet, &mdl);
543 while (mdl)
544 {
545 NdisAdjustBufferLength(mdl, PAGE_SIZE);
546 XenFreelist_PutPage(&xi->rx_freelist, mdl);
547 NdisUnchainBufferAtBack(Packet, &mdl);
548 }
550 put_packet_on_freelist(xi, Packet);
551 xi->rx_outstanding--;
553 KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
555 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
556 }
558 /*
559 Free all Rx buffers (on halt, for example)
560 The ring must be stopped at this point.
561 */
563 static void
564 XenNet_RxBufferFree(struct xennet_info *xi)
565 {
566 int i;
567 PMDL mdl;
569 XenFreelist_Dispose(&xi->rx_freelist);
571 ASSERT(!xi->connected);
573 for (i = 0; i < NET_RX_RING_SIZE; i++)
574 {
575 if (!xi->rx_mdls[i])
576 continue;
578 mdl = xi->rx_mdls[i];
579 NdisAdjustBufferLength(mdl, PAGE_SIZE);
580 XenFreelist_PutPage(&xi->rx_freelist, mdl);
581 }
582 }
584 VOID
585 XenNet_RxResumeStart(xennet_info_t *xi)
586 {
587 int i;
588 KIRQL old_irql;
590 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
591 for (i = 0; i < NET_RX_RING_SIZE; i++)
592 {
593 if (xi->rx_mdls[i])
594 {
595 XenFreelist_PutPage(&xi->rx_freelist, xi->rx_mdls[i]);
596 xi->rx_mdls[i] = NULL;
597 }
598 }
599 XenFreelist_ResumeStart(&xi->rx_freelist);
600 xi->rx_id_free = NET_RX_RING_SIZE;
601 xi->rx_outstanding = 0;
602 KeReleaseSpinLock(&xi->rx_lock, old_irql);
603 }
605 VOID
606 XenNet_RxResumeEnd(xennet_info_t *xi)
607 {
608 KIRQL old_irql;
610 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
611 XenFreelist_ResumeEnd(&xi->rx_freelist);
612 XenNet_RxBufferAlloc(xi);
613 KeReleaseSpinLock(&xi->rx_lock, old_irql);
614 }
616 BOOLEAN
617 XenNet_RxInit(xennet_info_t *xi)
618 {
619 int i;
621 FUNCTION_ENTER();
623 xi->rx_id_free = NET_RX_RING_SIZE;
625 for (i = 0; i < NET_RX_RING_SIZE; i++)
626 {
627 xi->rx_mdls[i] = NULL;
628 }
630 xi->rx_outstanding = 0;
631 XenFreelist_Init(xi, &xi->rx_freelist, &xi->rx_lock);
633 XenNet_RxBufferAlloc(xi);
635 FUNCTION_EXIT();
637 return TRUE;
638 }
640 BOOLEAN
641 XenNet_RxShutdown(xennet_info_t *xi)
642 {
643 KIRQL OldIrql;
645 FUNCTION_ENTER();
647 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
649 XenNet_RxBufferFree(xi);
651 XenFreelist_Dispose(&xi->rx_freelist);
653 packet_freelist_dispose(xi);
655 /* free RX resources */
657 ASSERT(xi->rx_outstanding == 0);
659 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
661 FUNCTION_EXIT();
663 return TRUE;
664 }