win-pvdrivers

changeset 906:9be11a753ca2

indicate small packets with STATUS_RESOURCES as Windows is lazy about returning them.
checksum fixes
maintian a freelist of packets
author James Harper <james.harper@bendigoit.com.au>
date Fri Apr 15 16:01:34 2011 +1000 (2011-04-15)
parents ece83d8462ea
children ca56da6bd99a
files xennet/xennet.c xennet/xennet.h xennet/xennet.inx xennet/xennet_oid.c xennet/xennet_rx.c
line diff
     1.1 --- a/xennet/xennet.c	Tue Apr 05 22:37:08 2011 +1000
     1.2 +++ b/xennet/xennet.c	Fri Apr 15 16:01:34 2011 +1000
     1.3 @@ -755,6 +755,21 @@ XenNet_Init(
     1.4      xi->config_csum_rx_check = !!config_param->ParameterData.IntegerData;
     1.5    }
     1.6  
     1.7 +  NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadDontFix");
     1.8 +  NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
     1.9 +  if (!NT_SUCCESS(status))
    1.10 +  {
    1.11 +    KdPrint(("Could not read ChecksumOffloadDontFix value (%08x)\n", status));
    1.12 +    xi->config_csum_rx_dont_fix = 0;
    1.13 +  }
    1.14 +  else
    1.15 +  {
    1.16 +    KdPrint(("ChecksumOffloadDontFix = %d\n", config_param->ParameterData.IntegerData));
    1.17 +    xi->config_csum_rx_dont_fix = !!config_param->ParameterData.IntegerData;
    1.18 +  }
    1.19 +  
    1.20 +  
    1.21 +  
    1.22    NdisInitUnicodeString(&config_param_name, L"MTU");
    1.23    NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);  
    1.24    if (!NT_SUCCESS(status))
     2.1 --- a/xennet/xennet.h	Tue Apr 05 22:37:08 2011 +1000
     2.2 +++ b/xennet/xennet.h	Fri Apr 15 16:01:34 2011 +1000
     2.3 @@ -301,6 +301,7 @@ struct xennet_info
     2.4    NDIS_HANDLE rx_packet_pool;
     2.5    NDIS_HANDLE rx_buffer_pool;
     2.6    volatile LONG rx_pb_free;
     2.7 +  struct stack_state *rx_packet_stack;
     2.8    struct stack_state *rx_pb_stack;
     2.9    shared_buffer_t *rx_ring_pbs[NET_RX_RING_SIZE];
    2.10    NPAGED_LOOKASIDE_LIST rx_lookaside_list;
    2.11 @@ -319,6 +320,7 @@ struct xennet_info
    2.12    ULONG config_sg;
    2.13    ULONG config_csum;
    2.14    ULONG config_csum_rx_check;
    2.15 +  ULONG config_csum_rx_dont_fix;
    2.16    ULONG config_gso;
    2.17    ULONG config_mtu;
    2.18    ULONG config_rx_interrupt_moderation;
     3.1 --- a/xennet/xennet.inx	Tue Apr 05 22:37:08 2011 +1000
     3.2 +++ b/xennet/xennet.inx	Fri Apr 15 16:01:34 2011 +1000
     3.3 @@ -51,6 +51,12 @@ HKR, Ndi\Params\ChecksumOffloadRxCheck, 
     3.4  HKR, Ndi\Params\ChecksumOffloadRxCheck\enum, 0, , "Disabled"
     3.5  HKR, Ndi\Params\ChecksumOffloadRxCheck\enum, 1, , "Enabled"
     3.6  
     3.7 +HKR, Ndi\Params\ChecksumOffloadDontFix, ParamDesc, , "Dont fix the blank checksum on offloaded RX packets"
     3.8 +HKR, Ndi\Params\ChecksumOffloadDontFix, default, , "0"
     3.9 +HKR, Ndi\Params\ChecksumOffloadDontFix, type, , "enum"
    3.10 +HKR, Ndi\Params\ChecksumOffloadDontFix\enum, 0, , "Disabled"
    3.11 +HKR, Ndi\Params\ChecksumOffloadDontFix\enum, 1, , "Enabled"
    3.12 +
    3.13  HKR, Ndi\Params\LargeSendOffload, ParamDesc, , "Large Send Offload"
    3.14  HKR, Ndi\Params\LargeSendOffload, default, , "61440"
    3.15  HKR, Ndi\Params\LargeSendOffload, type, , "enum"
     4.1 --- a/xennet/xennet_oid.c	Tue Apr 05 22:37:08 2011 +1000
     4.2 +++ b/xennet/xennet_oid.c	Fri Apr 15 16:01:34 2011 +1000
     4.3 @@ -299,8 +299,8 @@ XenNet_QueryInformation(
     4.4          nttic->V4Transmit.TcpChecksum = 1;
     4.5          nttic->V4Transmit.TcpOptionsSupported = 1;
     4.6          nttic->V4Transmit.UdpChecksum = 1;
     4.7 -        nttic->V4Receive.IpChecksum = 0;
     4.8 -        nttic->V4Receive.IpOptionsSupported = 0;
     4.9 +        nttic->V4Receive.IpChecksum = 1;
    4.10 +        nttic->V4Receive.IpOptionsSupported = 1;
    4.11          nttic->V4Receive.TcpChecksum = 1;
    4.12          nttic->V4Receive.TcpOptionsSupported = 1;
    4.13          nttic->V4Receive.UdpChecksum = 1;
     5.1 --- a/xennet/xennet_rx.c	Tue Apr 05 22:37:08 2011 +1000
     5.2 +++ b/xennet/xennet_rx.c	Fri Apr 15 16:01:34 2011 +1000
     5.3 @@ -20,8 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fi
     5.4  
     5.5  #include "xennet.h"
     5.6  
     5.7 -LONG rx_pb_outstanding = 0;
     5.8 -LONG rx_pb_outstanding_refs = 0;
     5.9 +static LONG rx_pb_outstanding = 0;
    5.10  
    5.11  static __inline shared_buffer_t *
    5.12  get_pb_from_freelist(struct xennet_info *xi)
    5.13 @@ -36,7 +35,6 @@ get_pb_from_freelist(struct xennet_info 
    5.14      pb->ref_count = 1;
    5.15      InterlockedDecrement(&xi->rx_pb_free);
    5.16      InterlockedIncrement(&rx_pb_outstanding);
    5.17 -    InterlockedIncrement(&rx_pb_outstanding_refs);
    5.18      return pb;
    5.19    }
    5.20  
    5.21 @@ -75,7 +73,6 @@ get_pb_from_freelist(struct xennet_info 
    5.22    }
    5.23    InterlockedIncrement(&rx_pb_outstanding);
    5.24    pb->ref_count = 1;
    5.25 -  InterlockedIncrement(&rx_pb_outstanding_refs);
    5.26    return pb;
    5.27  }
    5.28  
    5.29 @@ -84,13 +81,11 @@ ref_pb(struct xennet_info *xi, shared_bu
    5.30  {
    5.31    UNREFERENCED_PARAMETER(xi);
    5.32    InterlockedIncrement(&pb->ref_count);
    5.33 -  InterlockedIncrement(&rx_pb_outstanding_refs);
    5.34  }
    5.35  
    5.36  static __inline VOID
    5.37  put_pb_on_freelist(struct xennet_info *xi, shared_buffer_t *pb)
    5.38  {
    5.39 -  InterlockedDecrement(&rx_pb_outstanding_refs);
    5.40    if (InterlockedDecrement(&pb->ref_count) == 0)
    5.41    {
    5.42      NdisAdjustBufferLength(pb->buffer, PAGE_SIZE);
    5.43 @@ -157,6 +152,7 @@ XenNet_FillRing(struct xennet_info *xi)
    5.44  
    5.45  LONG total_allocated_packets = 0;
    5.46  LONG dpc_limit_hit = 0;
    5.47 +LONG resource_packets = 0;
    5.48  LARGE_INTEGER last_print_time;
    5.49  
    5.50  /* lock free */
    5.51 @@ -165,6 +161,17 @@ get_packet_from_freelist(struct xennet_i
    5.52  {
    5.53    NDIS_STATUS status;
    5.54    PNDIS_PACKET packet;
    5.55 +  PVOID ptr_ref;
    5.56 +
    5.57 +  if (stack_pop(xi->rx_packet_stack, &ptr_ref))
    5.58 +  {
    5.59 +    packet = ptr_ref;
    5.60 +    InterlockedIncrement(&total_allocated_packets);
    5.61 +    return packet;
    5.62 +  }
    5.63 +  
    5.64 +  if (xi->rx_shutting_down) /* don't keep allocating new packets on shutdown */
    5.65 +    return NULL;
    5.66  
    5.67    NdisAllocatePacket(&status, &packet, xi->rx_packet_pool);
    5.68    if (status != NDIS_STATUS_SUCCESS)
    5.69 @@ -183,16 +190,25 @@ static VOID
    5.70  put_packet_on_freelist(struct xennet_info *xi, PNDIS_PACKET packet)
    5.71  {
    5.72    LARGE_INTEGER current_time;
    5.73 +  PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
    5.74  
    5.75    UNREFERENCED_PARAMETER(xi);
    5.76    
    5.77    InterlockedDecrement(&total_allocated_packets);
    5.78 -  NdisFreePacket(packet);
    5.79 +
    5.80 +  NdisReinitializePacket(packet);
    5.81 +  RtlZeroMemory(NDIS_PACKET_EXTENSION_FROM_PACKET(packet), sizeof(NDIS_PACKET_EXTENSION));
    5.82 +  csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
    5.83 +    packet, TcpIpChecksumPacketInfo);
    5.84 +  csum_info->Value = 0;
    5.85 +
    5.86 +  stack_push(xi->rx_packet_stack, packet);
    5.87 +
    5.88    KeQuerySystemTime(&current_time);
    5.89 -  if ((int)total_allocated_packets < 0 || (current_time.QuadPart - last_print_time.QuadPart) / 10000 > 5000)
    5.90 +  if ((current_time.QuadPart - last_print_time.QuadPart) / 10000 > 5000)
    5.91    {
    5.92      last_print_time.QuadPart = current_time.QuadPart;
    5.93 -    KdPrint(("total_allocated_packets = %d, rx_outstanding = %d, dpc_limit_hit = %d, rx_pb_outstanding = %d, rx_pb_outstanding_refs = %d, rx_pb_free = %d\n", total_allocated_packets, xi->rx_outstanding, dpc_limit_hit, rx_pb_outstanding, rx_pb_outstanding_refs, xi->rx_pb_free));
    5.94 +    KdPrint(("total_allocated_packets = %d, rx_outstanding = %d, resource_packets = %d, dpc_limit_hit = %d, rx_pb_outstanding = %d, rx_pb_free = %d\n", total_allocated_packets, xi->rx_outstanding, resource_packets, dpc_limit_hit, rx_pb_outstanding, xi->rx_pb_free));
    5.95    }
    5.96  }
    5.97  
    5.98 @@ -281,12 +297,14 @@ XenNet_MakePacket(struct xennet_info *xi
    5.99    }
   5.100    //KdPrint((__DRIVER_NAME "     before loop - out_remaining = %d\n", out_remaining));
   5.101  
   5.102 +  NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_RESOURCES); /* for packets only containing a header buffer - see Indicate*/
   5.103    while (out_remaining != 0)
   5.104    {
   5.105      ULONG in_buffer_offset;
   5.106      ULONG in_buffer_length;
   5.107      ULONG out_length;
   5.108      
   5.109 +    NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS); /* packet contains additional buffers */
   5.110      //KdPrint((__DRIVER_NAME "     in loop - out_remaining = %d, curr_buffer = %p, curr_pb = %p\n", out_remaining, pi->curr_buffer, pi->curr_pb));
   5.111      if (!pi->curr_buffer || !pi->curr_pb)
   5.112      {
   5.113 @@ -315,7 +333,6 @@ XenNet_MakePacket(struct xennet_info *xi
   5.114    {
   5.115      XenNet_SumIpHeader(header_va, pi->ip4_header_length);
   5.116    }
   5.117 -  NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
   5.118    if (header_extra > 0)
   5.119      pi->header_length -= header_extra;
   5.120    ASSERT(*(shared_buffer_t **)&packet->MiniportReservedEx[0]);
   5.121 @@ -499,21 +516,28 @@ XenNet_MakePackets(
   5.122      }
   5.123      if (parse_result == PARSE_OK)
   5.124      {
   5.125 +      BOOLEAN checksum_offload = FALSE;
   5.126        csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
   5.127          packet, TcpIpChecksumPacketInfo);
   5.128 +      ASSERT(csum_info->Value == 0);
   5.129        if (pi->csum_blank || pi->data_validated)
   5.130        {
   5.131          if (xi->setting_csum.V4Receive.TcpChecksum && pi->ip_proto == 6)
   5.132          {
   5.133            if (!pi->tcp_has_options || xi->setting_csum.V4Receive.TcpOptionsSupported)
   5.134            {
   5.135 +            csum_info->Receive.NdisPacketIpChecksumSucceeded = TRUE;
   5.136              csum_info->Receive.NdisPacketTcpChecksumSucceeded = TRUE;
   5.137 +            checksum_offload = TRUE;
   5.138            }
   5.139 -        } else if (xi->setting_csum.V4Receive.UdpChecksum && pi->ip_proto == 17)
   5.140 +        }
   5.141 +        else if (xi->setting_csum.V4Receive.UdpChecksum && pi->ip_proto == 17)
   5.142          {
   5.143 +          csum_info->Receive.NdisPacketIpChecksumSucceeded = TRUE;
   5.144            csum_info->Receive.NdisPacketUdpChecksumSucceeded = TRUE;
   5.145 +          checksum_offload = TRUE;
   5.146          }
   5.147 -        if (pi->csum_blank)
   5.148 +        if (pi->csum_blank && (!xi->config_csum_rx_dont_fix || !checksum_offload))
   5.149          {
   5.150            XenNet_SumPacketData(pi, packet, TRUE);
   5.151          }
   5.152 @@ -583,6 +607,7 @@ XenNet_MakePackets(
   5.153      {
   5.154        csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(
   5.155          packet, TcpIpChecksumPacketInfo);
   5.156 +      csum_info->Receive.NdisPacketIpChecksumSucceeded = TRUE;
   5.157        csum_info->Receive.NdisPacketTcpChecksumSucceeded = TRUE;
   5.158      }
   5.159      if (psh)
   5.160 @@ -614,6 +639,66 @@ done:
   5.161    return packet_count;
   5.162  }
   5.163  
   5.164 +
   5.165 +/* called at DISPATCH_LEVEL */
   5.166 +/* 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 */
   5.167 +VOID
   5.168 +XenNet_ReturnPacket(
   5.169 +  IN NDIS_HANDLE MiniportAdapterContext,
   5.170 +  IN PNDIS_PACKET Packet
   5.171 +  )
   5.172 +{
   5.173 +  struct xennet_info *xi = MiniportAdapterContext;
   5.174 +  PNDIS_BUFFER buffer;
   5.175 +  shared_buffer_t *page_buf = *(shared_buffer_t **)&Packet->MiniportReservedEx[0];
   5.176 +
   5.177 +  //FUNCTION_ENTER();
   5.178 +
   5.179 +  //KdPrint((__DRIVER_NAME "     page_buf = %p\n", page_buf));
   5.180 +
   5.181 +  NdisUnchainBufferAtFront(Packet, &buffer);
   5.182 +  
   5.183 +  while (buffer)
   5.184 +  {
   5.185 +    shared_buffer_t *next_buf;
   5.186 +    ASSERT(page_buf);
   5.187 +    next_buf = page_buf->next;
   5.188 +    if (!page_buf->virtual)
   5.189 +    {
   5.190 +      /* this isn't actually a share_buffer, it is some memory allocated for the header - just free it */
   5.191 +      PUCHAR va;
   5.192 +      UINT len;
   5.193 +      NdisQueryBufferSafe(buffer, &va, &len, NormalPagePriority);
   5.194 +      NdisFreeToNPagedLookasideList(&xi->rx_lookaside_list, va - sizeof(shared_buffer_t));
   5.195 +      NdisFreeBuffer(buffer);
   5.196 +    }
   5.197 +    else
   5.198 +    {
   5.199 +      //KdPrint((__DRIVER_NAME "     returning page_buf %p with id %d\n", page_buf, page_buf->id));
   5.200 +      if (buffer != page_buf->buffer)
   5.201 +        NdisFreeBuffer(buffer);
   5.202 +      put_pb_on_freelist(xi, page_buf);
   5.203 +    }
   5.204 +    NdisUnchainBufferAtFront(Packet, &buffer);
   5.205 +    page_buf = next_buf;
   5.206 +  }
   5.207 +
   5.208 +  put_packet_on_freelist(xi, Packet);
   5.209 +  InterlockedDecrement(&xi->rx_outstanding);
   5.210 +  
   5.211 +  if (!xi->rx_outstanding && xi->rx_shutting_down)
   5.212 +    KeSetEvent(&xi->packet_returned_event, IO_NO_INCREMENT, FALSE);
   5.213 +
   5.214 +#if 0 /* don't do this as it's called an awful lot */
   5.215 +  KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
   5.216 +
   5.217 +  XenNet_FillRing(xi);
   5.218 +
   5.219 +  KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
   5.220 +#endif
   5.221 +  //FUNCTION_EXIT();
   5.222 +}
   5.223 +
   5.224  #define MAXIMUM_PACKETS_PER_INDICATE 32
   5.225  
   5.226  /* We limit the number of packets per interrupt so that acks get a chance
   5.227 @@ -627,6 +712,7 @@ XenNet_RxBufferCheck(struct xennet_info 
   5.228  {
   5.229    RING_IDX cons, prod;
   5.230    LIST_ENTRY rx_packet_list;
   5.231 +  LIST_ENTRY rx_header_only_packet_list;
   5.232    PLIST_ENTRY entry;
   5.233    PNDIS_PACKET packets[MAXIMUM_PACKETS_PER_INDICATE];
   5.234    ULONG packet_count = 0;
   5.235 @@ -637,7 +723,6 @@ XenNet_RxBufferCheck(struct xennet_info 
   5.236    USHORT id;
   5.237    int more_to_do = FALSE;
   5.238    packet_info_t *pi = &xi->rxpi[KeGetCurrentProcessorNumber() & 0xff];
   5.239 -  //NDIS_STATUS status;
   5.240    shared_buffer_t *page_buf;
   5.241    shared_buffer_t *head_buf = NULL;
   5.242    shared_buffer_t *tail_buf = NULL;
   5.243 @@ -869,83 +954,40 @@ XenNet_RxBufferCheck(struct xennet_info 
   5.244  
   5.245    /* indicate packets to NDIS */
   5.246    entry = RemoveHeadList(&rx_packet_list);
   5.247 +  InitializeListHead(&rx_header_only_packet_list);
   5.248    packet_count = 0;
   5.249 -  while (entry != &rx_packet_list)
   5.250 -  {
   5.251 +
   5.252 +  while (entry != &rx_packet_list) {
   5.253      PNDIS_PACKET packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
   5.254 +    NDIS_STATUS status;
   5.255      ASSERT(*(shared_buffer_t **)&packet->MiniportReservedEx[0]);
   5.256 -
   5.257 +    status = NDIS_GET_PACKET_STATUS(packet);
   5.258 +    if (status == NDIS_STATUS_RESOURCES)
   5.259 +      InsertTailList(&rx_header_only_packet_list, entry);
   5.260      packets[packet_count++] = packet;
   5.261      InterlockedIncrement(&xi->rx_outstanding);
   5.262      entry = RemoveHeadList(&rx_packet_list);
   5.263 -    if (packet_count == MAXIMUM_PACKETS_PER_INDICATE || entry == &rx_packet_list)
   5.264 +    /* if we indicate a packet with NDIS_STATUS_RESOURCES  then any following packet can't be NDIS_STATUS_SUCCESS */
   5.265 +    if (packet_count == MAXIMUM_PACKETS_PER_INDICATE || entry == &rx_packet_list
   5.266 +        || (NDIS_GET_PACKET_STATUS(CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)])) == NDIS_STATUS_SUCCESS
   5.267 +            && status == NDIS_STATUS_RESOURCES))
   5.268      {
   5.269        NdisMIndicateReceivePacket(xi->adapter_handle, packets, packet_count);
   5.270        packet_count = 0;
   5.271      }
   5.272    }
   5.273 +  /* now return the packets for which we indicated NDIS_STATUS_RESOURCES */
   5.274 +  entry = RemoveHeadList(&rx_header_only_packet_list);
   5.275 +  while (entry != &rx_header_only_packet_list) {
   5.276 +    PNDIS_PACKET packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
   5.277 +    entry = RemoveHeadList(&rx_header_only_packet_list);
   5.278 +    InterlockedIncrement(&resource_packets);
   5.279 +    XenNet_ReturnPacket(xi, packet);
   5.280 +  }
   5.281    return dont_set_event;
   5.282    //FUNCTION_EXIT();
   5.283  }
   5.284  
   5.285 -/* called at DISPATCH_LEVEL */
   5.286 -/* 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 */
   5.287 -VOID
   5.288 -XenNet_ReturnPacket(
   5.289 -  IN NDIS_HANDLE MiniportAdapterContext,
   5.290 -  IN PNDIS_PACKET Packet
   5.291 -  )
   5.292 -{
   5.293 -  struct xennet_info *xi = MiniportAdapterContext;
   5.294 -  PNDIS_BUFFER buffer;
   5.295 -  shared_buffer_t *page_buf = *(shared_buffer_t **)&Packet->MiniportReservedEx[0];
   5.296 -
   5.297 -  //FUNCTION_ENTER();
   5.298 -
   5.299 -  //KdPrint((__DRIVER_NAME "     page_buf = %p\n", page_buf));
   5.300 -
   5.301 -  NdisUnchainBufferAtFront(Packet, &buffer);
   5.302 -  
   5.303 -  while (buffer)
   5.304 -  {
   5.305 -    shared_buffer_t *next_buf;
   5.306 -    ASSERT(page_buf);
   5.307 -    next_buf = page_buf->next;
   5.308 -    if (!page_buf->virtual)
   5.309 -    {
   5.310 -      /* this isn't actually a share_buffer, it is some memory allocated for the header - just free it */
   5.311 -      PUCHAR va;
   5.312 -      UINT len;
   5.313 -      NdisQueryBufferSafe(buffer, &va, &len, NormalPagePriority);
   5.314 -      NdisFreeToNPagedLookasideList(&xi->rx_lookaside_list, va - sizeof(shared_buffer_t));
   5.315 -      NdisFreeBuffer(buffer);
   5.316 -    }
   5.317 -    else
   5.318 -    {
   5.319 -      //KdPrint((__DRIVER_NAME "     returning page_buf %p with id %d\n", page_buf, page_buf->id));
   5.320 -      if (buffer != page_buf->buffer)
   5.321 -        NdisFreeBuffer(buffer);
   5.322 -      put_pb_on_freelist(xi, page_buf);
   5.323 -    }
   5.324 -    NdisUnchainBufferAtFront(Packet, &buffer);
   5.325 -    page_buf = next_buf;
   5.326 -  }
   5.327 -
   5.328 -  put_packet_on_freelist(xi, Packet);
   5.329 -  InterlockedDecrement(&xi->rx_outstanding);
   5.330 -  
   5.331 -  if (!xi->rx_outstanding && xi->rx_shutting_down)
   5.332 -    KeSetEvent(&xi->packet_returned_event, IO_NO_INCREMENT, FALSE);
   5.333 -
   5.334 -  KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
   5.335 -
   5.336 -  XenNet_FillRing(xi);
   5.337 -
   5.338 -  KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
   5.339 -
   5.340 -  //FUNCTION_EXIT();
   5.341 -}
   5.342 -
   5.343  /*
   5.344     Free all Rx buffers (on halt, for example) 
   5.345     The ring must be stopped at this point.
   5.346 @@ -1056,6 +1098,7 @@ XenNet_RxInit(xennet_info_t *xi)
   5.347      KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
   5.348      return FALSE;
   5.349    }
   5.350 +  stack_new(&xi->rx_packet_stack, NET_RX_RING_SIZE * 4);
   5.351  
   5.352    NdisInitializeNPagedLookasideList(&xi->rx_lookaside_list, NULL, NULL, 0,
   5.353      MAX_ETH_HEADER_LENGTH + MAX_LOOKAHEAD_LENGTH + sizeof(shared_buffer_t), XENNET_POOL_TAG, 0);
   5.354 @@ -1071,6 +1114,7 @@ BOOLEAN
   5.355  XenNet_RxShutdown(xennet_info_t *xi)
   5.356  {
   5.357    KIRQL old_irql;
   5.358 +  PNDIS_PACKET packet;
   5.359  
   5.360    FUNCTION_ENTER();
   5.361  
   5.362 @@ -1099,6 +1143,10 @@ XenNet_RxShutdown(xennet_info_t *xi)
   5.363  
   5.364    XenNet_BufferFree(xi);
   5.365  
   5.366 +  /* this works because get_packet_from_freelist won't allocate new packets when rx_shutting_down */
   5.367 +  while ((packet = get_packet_from_freelist(xi)) != NULL)
   5.368 +    NdisFreePacket(packet);
   5.369 +  stack_delete(xi->rx_packet_stack, NULL, NULL);
   5.370    NdisFreePacketPool(xi->rx_packet_pool);
   5.371  
   5.372    NdisDeleteNPagedLookasideList(&xi->rx_lookaside_list);