win-pvdrivers

view xennet/xennet_rx.c @ 217:f315522a2a3e

This won't work.
author James Harper <james.harper@bendigoit.com.au>
date Fri Mar 21 17:51:32 2008 +1100 (2008-03-21)
parents 6f57a4124ab7
children 6974a4ace9d3
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 break;
116 xi->rx_id_free--;
118 /* Give to netback */
119 id = (USHORT)((req_prod + i) & (NET_RX_RING_SIZE - 1));
120 // KdPrint((__DRIVER_NAME " id = %d\n", id));
121 ASSERT(xi->rx_buffers[id] == NULL);
122 xi->rx_buffers[id] = mdl;
123 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
124 req->gref = get_grant_ref(mdl);
125 req->id = id;
126 }
128 xi->rx.req_prod_pvt = req_prod + i;
129 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
130 if (notify)
131 {
132 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
133 xi->event_channel);
134 }
136 //KdPrint((__DRIVER_NAME " Added %d out of %d buffers to rx ring\n", i, batch_target));
138 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
140 #if defined(XEN_PROFILE)
141 ProfTime_RxBufferAlloc.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc.QuadPart;
142 ProfCount_RxBufferAlloc++;
143 #endif
145 return NDIS_STATUS_SUCCESS;
146 }
148 static VOID
149 XenNet_SplitRxPacket(
150 PNDIS_PACKET *packets,
151 PULONG packet_count,
152 ULONG total_packet_length
153 )
154 {
155 ULONG mss = PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(packets[*packet_count], TcpLargeSendPacketInfo));
156 ULONG header_length = 54; //TODO: actually calculate this from the TCP header
157 ULONG tcp_length = total_packet_length - header_length;
158 ULONG remaining = tcp_length;
160 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
162 KdPrint((__DRIVER_NAME " mss = %d\n", mss));
164 while (remaining)
165 {
166 // take the buffers off of the current packet
167 KdPrint((__DRIVER_NAME " Remaining = %d\n", remaining));
169 if (remaining > mss)
170 {
171 // tcp length = mss;
172 remaining -= mss;
173 }
174 else
175 {
176 // tcp length = remaining
177 remaining = 0;
178 }
179 // do some creative stuff here... clone the header of the previous packet and update the various fields
180 // append the remaining data buffers
181 // increment the packet count
182 }
184 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
186 return;
187 }
189 #define __NET_USHORT_BYTE_0(x) ((USHORT)(x & 0xFF))
190 #define __NET_USHORT_BYTE_1(x) ((USHORT)((PUCHAR)&x)[1] & 0xFF)
191 #define NET_USHORT(x) ((__NET_USHORT_BYTE_0(x) << 8) | __NET_USHORT_BYTE_1(x))
193 static VOID
194 XenNet_SplitLargePackets(
195 PNDIS_PACKET *packets,
196 ULONG packet_count,
197 PULONG new_packets,
198 USHORT ip4_length,
199 USHORT ip4_header_length,
200 USHORT tcp_header_length
201 )
202 {
203 PUCHAR header;
204 PNDIS_PACKET first_packet;
205 PNDIS_PACKET curr_packet;
207 new_packets = 0;
209 header = buffer;
210 remaining = ip4_length - ip4_header_length - tcp_header_length;
211 // save psh status of packet
212 while (remaining)
213 {
214 *((PUSHORT)&buffer[XN_HDR_SIZE + 2]) = NET_USHORT(mss);
215 tcp_length = min(remaining, mss);
216 remaining -= tcp_length;
218 // clear psh of old packet
220 NdisAllocatePacket(&status, &packets[packet_count + 1], xi->packet_pool);
221 ASSERT(status == NDIS_STATUS_SUCCESS);
222 NDIS_SET_PACKET_HEADER_SIZE(packets[packet_count + 1], XN_HDR_SIZE);
224 new_buffer_mdl = get_page_from_freelist(xi);
225 new_buffer = MmGetMdlVirtualAddress(new_buffer_mdl);
226 memcpy(new_buffer, buffer, XN_HDR_SIZE + ip4_header_length + tcp_header_length);
227 *((PUSHORT)&new_header[XN_HDR_SIZE + 2]) = NET_USHORT(tcp_length);
228 // fix tcp sequence of new packet
229 new_remaining = tcp_length;
230 while (new_remaining > 0)
231 {
233 if (buffer_offset != 0)
234 {
235 new_buffer =
236 // allocate a new buffer
237 // copy remaining data to new buffer
238 // set length of current buffer
239 // set length of new buffer
240 }
242 // I was up to here...
243 NdisUnchainBufferAtBack(packets[packet_count], &mdl);
244 NdisChainBufferAtFront(packets[packet_count + 1], mdl);
245 NdisChainBufferAtFront(packets[packet_count + 1], new_header_mdl);
248 // copy all buffers to new packet
249 packet_count++;
250 }
251 // restore psh status to last packet
252 }
254 /*
255 Windows appears to insist that the checksum on received packets is correct, and won't
256 believe us when we lie about it, which happens when the packet is generated on the
257 same bridge in Dom0. Doh!
258 This is only for TCP and UDP packets. IP checksums appear to be correct anyways.
259 */
260 static VOID
261 XenNet_SumData(
262 PNDIS_PACKET packet
263 )
264 {
265 USHORT i;
266 PUCHAR buffer;
267 PMDL mdl;
268 UINT total_length;
269 UINT buffer_length;
270 ULONG csum, pre_csum;
271 PUSHORT csum_ptr;
272 UCHAR ip_version;
273 USHORT ip4_header_length;
274 USHORT ip4_length;
275 USHORT tcp_header_length;
276 USHORT tcp_length;
277 USHORT buffer_offset;
278 USHORT mss;
279 PNDIS_PACKET packet;
281 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
283 mss = PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo);
284 NdisGetFirstBufferFromPacketSafe(packet, &mdl, &buffer, &buffer_length, &total_length, NormalPagePriority);
285 if (mdl == NULL)
286 {
287 KdPrint((__DRIVER_NAME " Cannot get first buffer\n"));
288 return;
289 }
291 if (buffer_length < XN_HDR_SIZE + 20 + 20) // minimum size of ETH + IP + TCP header
292 {
293 KdPrint((__DRIVER_NAME " %d is not enough data for the first buffer\n", buffer_length));
294 return;
295 }
297 switch (NET_USHORT(buffer[12])) // L2 protocol field
298 {
299 case 0x0800:
300 ip_version = (buffer[XN_HDR_SIZE + 0] & 0xF0) >> 4;
301 if (ip_version != 4)
302 {
303 KdPrint((__DRIVER_NAME " ip_version = %d\n", ip_version));
304 return;
305 }
306 ip4_header_length = (buffer[XN_HDR_SIZE + 0] & 0x0F) << 2;
307 if (buffer_length < (ULONG)(ip4_header_length + 20))
308 {
309 KdPrint((__DRIVER_NAME " first packet is only %d long, must be >= %d\n", XN_HDR_SIZE + buffer_length, (ULONG)(XN_HDR_SIZE + ip4_header_length + 20)));
310 return;
311 }
312 break;
313 default:
314 KdPrint((__DRIVER_NAME " Not IP\n"));
315 return;
316 }
317 switch (buffer[XN_HDR_SIZE + 9])
318 {
319 case 6: // TCP
320 case 17: // UDP
321 break;
322 default:
323 KdPrint((__DRIVER_NAME " Not TCP or UDP\n"));
324 return;
325 }
326 ip4_length = NET_USHORT(buffer[XN_HDR_SIZE + 2]);
327 tcp_header_length = (buffer[XN_HDR_SIZE + ip4_header_length + 12] & 0xf0) >> 2;
328 csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + ip4_header_length + 16];
329 *csum_ptr = 0;
331 KdPrint((__DRIVER_NAME " buffer_length = %d, total_length = %d, ip4_length = %d, ip4_header_length = %d, tcp_header_length = %d\n", buffer_length, total_length, ip4_length, ip4_header_length, tcp_header_length));
333 ASSERT((USHORT)(ip4_length + XN_HDR_SIZE) == total_length);
335 remaining = ip4_length - ip4_header_length - tcp_header_length;
336 if (mss && remaining > mss)
337 {
338 ASSERT(mss <= PAGE_SIZE); // maybe fix this one day, but its a good assumption for now
339 SplitLargePackets(packets, current_packet, &new_packets);
340 }
342 pre_csum = 0;
343 pre_csum += NET_USHORT(buffer[XN_HDR_SIZE + 12]) + NET_USHORT(buffer[XN_HDR_SIZE + 14]);
344 pre_csum += NET_USHORT(buffer[XN_HDR_SIZE + 16]) + NET_USHORT(buffer[XN_HDR_SIZE + 18]);
345 pre_csum += ((USHORT)buffer[XN_HDR_SIZE + 9]);
347 remaining = ip4_length - ip4_header_length;
349 while (remaining > 0)
350 {
351 if (mss == 0)
352 tcp_length = remaining;
353 else
354 tcp_length = min(remaining, mss);
355 remaining -= tcp_length;
357 csum = pre_csum + tcp_length;
358 for (buffer_offset = i = XN_HDR_SIZE + ip4_header_length; i < tcp_length - 1; i += 2, buffer_offset += 2)
359 {
360 if (buffer_offset == buffer_length - 1) // deal with a buffer ending on an odd byte boundary
361 {
362 csum += (USHORT)buffer[buffer_offset] << 8;
363 NdisGetNextBuffer(mdl, &mdl);
364 if (mdl == NULL)
365 {
366 KdPrint((__DRIVER_NAME " Ran out of buffers\n"));
367 return;
368 }
369 NdisQueryBufferSafe(mdl, &buffer, &buffer_length, NormalPagePriority);
370 KdPrint((__DRIVER_NAME " New buffer - unaligned...\n"));
371 csum += ((USHORT)buffer[0]);
372 buffer_offset = -1;
373 }
374 else
375 {
376 if (buffer_offset == buffer_length)
377 {
378 KdPrint((__DRIVER_NAME " New buffer - aligned...\n"));
379 NdisGetNextBuffer(mdl, &mdl);
380 if (mdl == NULL)
381 {
382 KdPrint((__DRIVER_NAME " Ran out of buffers\n"));
383 return;
384 }
385 NdisQueryBufferSafe(mdl, &buffer, &buffer_length, NormalPagePriority);
386 buffer_offset = 0;
387 }
388 csum += NET_USHORT(buffer[buffer_offset]);
389 //KdPrint((__DRIVER_NAME " %04X\n", NET_USHORT(buffer[buffer_offset])));
390 }
391 }
392 if (i != ip4_length) // last odd byte
393 {
394 //KdPrint((__DRIVER_NAME " *%04X\n", (USHORT)buffer[buffer_offset] << 8));
395 csum += ((USHORT)buffer[buffer_offset] << 8);
396 }
397 while (csum & 0xFFFF0000)
398 csum = (csum & 0xFFFF) + (csum >> 16);
399 *csum_ptr = (USHORT)~NET_USHORT(csum);
401 if (remaining != 0)
402 {
403 // create a new packet
404 // copy the header to a new buffer
405 // if we are not at the start of the current buffer, copy the remaining data from the current buffer into a new buffer
407 }
409 KdPrint((__DRIVER_NAME " csum = %04x\n", *csum_ptr));
410 }
412 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
413 }
415 // Called at DISPATCH_LEVEL
416 NDIS_STATUS
417 XenNet_RxBufferCheck(struct xennet_info *xi)
418 {
419 RING_IDX cons, prod;
420 PNDIS_PACKET packets[NET_RX_RING_SIZE];
421 ULONG packet_count;
422 PMDL mdl;
423 int moretodo;
424 struct netif_rx_response *rxrsp = NULL;
425 struct netif_extra_info *ei;
426 int more_frags = 0;
427 NDIS_STATUS status;
428 USHORT id;
429 PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
430 USHORT total_packet_length = 0;
431 BOOLEAN csum_calc_required;
432 int cycles = 0;
433 #if defined(XEN_PROFILE)
434 LARGE_INTEGER tsc, tsc2, dummy;
435 #endif
437 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
439 #if defined(XEN_PROFILE)
440 tsc = tsc2 = KeQueryPerformanceCounter(&dummy);
441 #endif
443 ASSERT(xi->connected);
445 KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
447 packet_count = 0;
448 csum_calc_required = FALSE;
449 if (xi->rx_current_packet)
450 {
451 packets[packet_count] = xi->rx_current_packet;
452 xi->rx_current_packet = NULL;
453 more_frags = NETRXF_more_data;
454 }
455 do {
456 ASSERT(cycles++ < 256);
457 prod = xi->rx.sring->rsp_prod;
458 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
460 for (cons = xi->rx.rsp_cons; cons != prod; cons++)
461 {
462 ASSERT(cycles++ < 256);
463 id = (USHORT)(cons & (NET_RX_RING_SIZE - 1));
464 mdl = xi->rx_buffers[id];
465 xi->rx_buffers[id] = NULL;
466 xi->rx_id_free++;
467 if (xi->rx_extra_info)
468 {
469 KdPrint((__DRIVER_NAME " RX extra info packet detected\n"));
470 put_page_on_freelist(xi, mdl);
471 ei = (struct netif_extra_info *)RING_GET_RESPONSE(&xi->rx, cons);
472 xi->rx_extra_info = ei->flags & XEN_NETIF_EXTRA_FLAG_MORE;
473 switch (ei->type)
474 {
475 case XEN_NETIF_EXTRA_TYPE_GSO:
476 KdPrint((__DRIVER_NAME " GSO detected - size = %d\n", ei->u.gso.size));
477 switch (ei->u.gso.type)
478 {
479 case XEN_NETIF_GSO_TYPE_TCPV4:
480 KdPrint((__DRIVER_NAME " GSO_TYPE_TCPV4 detected\n"));
481 NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo) = (PVOID)(xen_ulong_t)(ei->u.gso.size);
482 break;
483 default:
484 KdPrint((__DRIVER_NAME " Unknown GSO type (%d) detected\n", ei->u.gso.type));
485 break;
486 }
487 break;
488 default:
489 KdPrint((__DRIVER_NAME " Unknown extra info type (%d) detected\n", ei->type));
490 break;
491 }
492 }
493 else
494 {
495 //KdPrint((__DRIVER_NAME " normal packet detected\n"));
496 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
497 if (rxrsp->status <= 0
498 || rxrsp->offset + rxrsp->status > PAGE_SIZE)
499 {
500 KdPrint((__DRIVER_NAME ": Error: rxrsp offset %d, size %d\n",
501 rxrsp->offset, rxrsp->status));
502 continue;
503 }
504 ASSERT(rxrsp->id == id);
505 if (!more_frags) // handling the packet's 1st buffer
506 {
507 NdisAllocatePacket(&status, &packets[packet_count], xi->packet_pool);
508 ASSERT(status == NDIS_STATUS_SUCCESS);
509 NDIS_SET_PACKET_HEADER_SIZE(packets[packet_count], XN_HDR_SIZE);
510 NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo) = 0;
511 total_packet_length = 0;
512 if (rxrsp->flags & (NETRXF_csum_blank|NETRXF_data_validated) && xi->config_csum) // and we are enabled for offload...
513 {
514 //KdPrint((__DRIVER_NAME " RX csum blank = %d, validated = %d\n", !!(rxrsp->flags & NETRXF_csum_blank), !!(rxrsp->flags & NETRXF_data_validated)));
515 if (rxrsp->flags & NETRXF_csum_blank)
516 csum_calc_required = TRUE;
517 csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpIpChecksumPacketInfo);
518 csum_info->Receive.NdisPacketTcpChecksumSucceeded = 1;
519 csum_info->Receive.NdisPacketUdpChecksumSucceeded = 0;
520 csum_info->Receive.NdisPacketIpChecksumSucceeded = 1;
521 #if defined(XEN_PROFILE)
522 ProfCount_RxPacketsCsumOffload++;
523 #endif
524 //KdPrint((__DRIVER_NAME " RX csum offload TcpFailed = %d, UdpFailed = %d\n", csum_info->Receive.NdisPacketTcpChecksumFailed, csum_info->Receive.NdisPacketUdpChecksumFailed));
525 }
526 }
527 total_packet_length = total_packet_length + rxrsp->status;
528 NdisAdjustBufferLength(mdl, rxrsp->status);
529 NdisChainBufferAtBack(packets[packet_count], mdl);
531 xi->rx_extra_info = rxrsp->flags & NETRXF_extra_info;
532 more_frags = rxrsp->flags & NETRXF_more_data;
533 }
535 if (more_frags)
536 KdPrint((__DRIVER_NAME " more frags\n"));
537 /* Packet done, add it to the list */
538 if (!more_frags && !xi->rx_extra_info)
539 {
540 if (PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo)))
541 KdPrint((__DRIVER_NAME " total length = %d, mss = %d\n", total_packet_length, PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo))));
542 #if defined(XEN_PROFILE)
543 ProfCount_RxPacketsTotal++;
544 #endif
545 xi->stat_rx_ok++;
546 NDIS_SET_PACKET_STATUS(packets[packet_count], NDIS_STATUS_SUCCESS);
548 /*
549 if (total_packet_length > xi->config_mtu + XN_HDR_SIZE)
550 {
551 KdPrint((__DRIVER_NAME " total_packet_length %d, config_mtu = %d\n", total_packet_length, xi->config_mtu));
552 XenNet_SplitRxPacket(packets, &packet_count, total_packet_length);
553 }
554 else */ if (csum_calc_required)
555 {
556 XenNet_SumData(packets[packet_count]);
557 csum_calc_required = FALSE;
558 }
560 packet_count++;
561 }
562 }
563 xi->rx.rsp_cons = prod;
565 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
566 } while (moretodo);
568 /* Give netback more buffers */
569 XenNet_RxBufferAlloc(xi);
571 if (more_frags)
572 {
573 KdPrint((__DRIVER_NAME " leftover frags\n"));
574 xi->rx_current_packet = packets[packet_count];
575 }
577 KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
579 #if defined(XEN_PROFILE)
580 ProfTime_RxBufferCheckTopHalf.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc2.QuadPart;
581 tsc2 = KeQueryPerformanceCounter(&dummy);
582 #endif
584 if (packet_count > 0)
585 {
586 NdisMIndicateReceivePacket(xi->adapter_handle, packets, packet_count);
587 #if defined(XEN_PROFILE)
588 ProfCount_CallsToIndicateReceive++;
589 #endif
590 }
592 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
594 #if defined(XEN_PROFILE)
595 ProfTime_RxBufferCheck.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc.QuadPart;
596 ProfTime_RxBufferCheckBotHalf.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc2.QuadPart;
597 ProfCount_RxBufferCheck++;
598 #endif
600 return NDIS_STATUS_SUCCESS;
601 }
603 /* called at DISPATCH_LEVEL */
605 VOID
606 XenNet_ReturnPacket(
607 IN NDIS_HANDLE MiniportAdapterContext,
608 IN PNDIS_PACKET Packet
609 )
610 {
611 struct xennet_info *xi = MiniportAdapterContext;
612 PMDL mdl;
613 int cycles = 0;
614 #if defined(XEN_PROFILE)
615 LARGE_INTEGER tsc, dummy;
616 #endif
618 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
620 #if defined(XEN_PROFILE)
621 tsc = KeQueryPerformanceCounter(&dummy);
622 #endif
624 KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
626 NdisUnchainBufferAtBack(Packet, &mdl);
627 while (mdl)
628 {
629 ASSERT(cycles++ < 256);
630 NdisAdjustBufferLength(mdl, PAGE_SIZE);
631 put_page_on_freelist(xi, mdl);
632 NdisUnchainBufferAtBack(Packet, &mdl);
633 }
635 NdisFreePacket(Packet);
637 KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
639 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
641 #if defined(XEN_PROFILE)
642 ProfTime_ReturnPacket.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc.QuadPart;
643 ProfCount_ReturnPacket++;
644 #endif
645 }
647 /*
648 Free all Rx buffers (on halt, for example)
649 The ring must be stopped at this point.
650 */
651 static void
652 XenNet_RxBufferFree(struct xennet_info *xi)
653 {
654 int i;
655 PMDL mdl;
657 ASSERT(!xi->connected);
659 for (i = 0; i < NET_RX_RING_SIZE; i++)
660 {
661 if (!xi->rx_buffers[i])
662 continue;
664 mdl = xi->rx_buffers[i];
665 NdisAdjustBufferLength(mdl, PAGE_SIZE);
666 put_page_on_freelist(xi, mdl);
667 }
668 }
670 BOOLEAN
671 XenNet_RxInit(xennet_info_t *xi)
672 {
673 int i;
675 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
677 xi->page_free = 0;
678 xi->rx_current_packet = NULL;
679 xi->rx_extra_info = 0;
681 xi->rx_mdl = AllocatePage();
682 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl);
683 SHARED_RING_INIT(xi->rx_pgs);
684 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
685 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
686 xi->XenInterface.InterfaceHeader.Context, 0,
687 *MmGetMdlPfnArray(xi->rx_mdl), FALSE, 0);
688 xi->rx_id_free = NET_RX_RING_SIZE;
690 for (i = 0; i < NET_RX_RING_SIZE; i++)
691 {
692 xi->rx_buffers[i] = NULL;
693 }
695 XenNet_RxBufferAlloc(xi);
697 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
699 return TRUE;
700 }
702 BOOLEAN
703 XenNet_RxShutdown(xennet_info_t *xi)
704 {
705 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
707 XenNet_RxBufferFree(xi);
709 free_page_freelist(xi);
711 /* free RX resources */
712 if (xi->XenInterface.GntTbl_EndAccess(
713 xi->XenInterface.InterfaceHeader.Context, xi->rx_ring_ref, 0))
714 {
715 xi->rx_ring_ref = GRANT_INVALID_REF;
716 FreePages(xi->rx_mdl);
717 }
718 xi->rx_pgs = NULL;
720 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
722 return TRUE;
723 }