win-pvdrivers

changeset 209:45fdf0d55f31

Large send offload now appears to work correctly...
author James Harper <james.harper@bendigoit.com.au>
date Wed Mar 12 22:44:47 2008 +1100 (2008-03-12)
parents e2939422de10
children 39a97a06e5cd
files common.inc xennet/xennet.c xennet/xennet.h xennet/xennet_oid.c xennet/xennet_rx.c xennet/xennet_tx.c
line diff
     1.1 --- a/common.inc	Thu Mar 06 23:20:12 2008 +1100
     1.2 +++ b/common.inc	Wed Mar 12 22:44:47 2008 +1100
     1.3 @@ -1,4 +1,4 @@
     1.4 -VERSION=0.8.4.82
     1.5 +VERSION=0.8.4.148
     1.6  TARGETPATH=..\Target\$(DDK_TARGET_OS)
     1.7  KMDF_VERSION=1
     1.8  !IF $(_NT_TOOLS_VERSION) > 0x700
     2.1 --- a/xennet/xennet.c	Thu Mar 06 23:20:12 2008 +1100
     2.2 +++ b/xennet/xennet.c	Wed Mar 12 22:44:47 2008 +1100
     2.3 @@ -29,6 +29,8 @@ LARGE_INTEGER ProfTime_RxBufferCheck;
     2.4  LARGE_INTEGER ProfTime_Linearize;
     2.5  LARGE_INTEGER ProfTime_SendPackets;
     2.6  LARGE_INTEGER ProfTime_SendQueuedPackets;
     2.7 +LARGE_INTEGER ProfTime_RxBufferCheckTopHalf;
     2.8 +LARGE_INTEGER ProfTime_RxBufferCheckBotHalf;
     2.9  
    2.10  int ProfCount_TxBufferGC;
    2.11  int ProfCount_RxBufferAlloc;
    2.12 @@ -40,9 +42,10 @@ int ProfCount_PacketsPerSendPackets;
    2.13  int ProfCount_SendQueuedPackets;
    2.14  
    2.15  int ProfCount_TxPacketsTotal;
    2.16 -int ProfCount_TxPacketsOffload;
    2.17 +int ProfCount_TxPacketsCsumOffload;
    2.18 +int ProfCount_TxPacketsLargeOffload;
    2.19  int ProfCount_RxPacketsTotal;
    2.20 -int ProfCount_RxPacketsOffload;
    2.21 +int ProfCount_RxPacketsCsumOffload;
    2.22  int ProfCount_CallsToIndicateReceive;
    2.23  
    2.24  /* This function copied from linux's lib/vsprintf.c, see it for attribution */
    2.25 @@ -202,7 +205,9 @@ XenNet_Init(
    2.26      {"feature-rx-notify", 1},
    2.27  //    {"feature-no-csum-offload", 1},
    2.28      {"feature-sg", 1},
    2.29 -    {"feature-gso-tcpv4", 0},
    2.30 +#if defined(OFFLOAD_LARGE_SEND)
    2.31 +    {"feature-gso-tcpv4", 1},
    2.32 +#endif
    2.33      {NULL, 0},
    2.34    };
    2.35    int retry = 0;
    2.36 @@ -579,6 +584,8 @@ DriverEntry(
    2.37    ProfTime_RxBufferAlloc.QuadPart = 0;
    2.38    ProfTime_ReturnPacket.QuadPart = 0;
    2.39    ProfTime_RxBufferCheck.QuadPart = 0;
    2.40 +  ProfTime_RxBufferCheckTopHalf.QuadPart = 0;
    2.41 +  ProfTime_RxBufferCheckBotHalf.QuadPart = 0;
    2.42    ProfTime_Linearize.QuadPart = 0;
    2.43    ProfTime_SendPackets.QuadPart = 0;
    2.44    ProfTime_SendQueuedPackets.QuadPart = 0;
    2.45 @@ -593,9 +600,10 @@ DriverEntry(
    2.46    ProfCount_SendQueuedPackets = 0;
    2.47  
    2.48    ProfCount_TxPacketsTotal = 0;
    2.49 -  ProfCount_TxPacketsOffload = 0;
    2.50 +  ProfCount_TxPacketsCsumOffload = 0;
    2.51 +  ProfCount_TxPacketsLargeOffload = 0;
    2.52    ProfCount_RxPacketsTotal = 0;
    2.53 -  ProfCount_RxPacketsOffload = 0;
    2.54 +  ProfCount_RxPacketsCsumOffload = 0;
    2.55    ProfCount_CallsToIndicateReceive = 0;
    2.56  
    2.57    RtlZeroMemory(&mini_chars, sizeof(mini_chars));
     3.1 --- a/xennet/xennet.h	Thu Mar 06 23:20:12 2008 +1100
     3.2 +++ b/xennet/xennet.h	Wed Mar 12 22:44:47 2008 +1100
     3.3 @@ -73,12 +73,20 @@ Foundation, Inc., 51 Franklin Street, Fi
     3.4  #pragma warning(disable: 4127) // conditional expression is constant
     3.5  
     3.6  //#define XEN_PROFILE
     3.7 +#define OFFLOAD_LARGE_SEND
     3.8 +#define MIN_LARGE_SEND_SEGMENTS 4
     3.9 +#define MAX_LARGE_SEND_OFFLOAD 65535
    3.10 +
    3.11  
    3.12  /* TODO: crank this up if we support higher mtus? */
    3.13  #define XN_DATA_SIZE 1500
    3.14  #define XN_HDR_SIZE 14
    3.15  #define XN_MIN_PKT_SIZE 60
    3.16 -#define XN_MAX_PKT_SIZE (XN_HDR_SIZE + XN_DATA_SIZE)
    3.17 +#if !defined(OFFLOAD_LARGE_SEND)
    3.18 +  #define XN_MAX_PKT_SIZE (XN_HDR_SIZE + XN_DATA_SIZE)
    3.19 +#else
    3.20 +  #define XN_MAX_PKT_SIZE MAX_LARGE_SEND_OFFLOAD
    3.21 +#endif
    3.22  
    3.23  #define XN_MAX_SEND_PKTS 16
    3.24  
    3.25 @@ -87,6 +95,11 @@ Foundation, Inc., 51 Franklin Street, Fi
    3.26  #define XN_VENDOR_DESC "Xensource"
    3.27  #define MAX_XENBUS_STR_LEN 128
    3.28  
    3.29 +
    3.30 +#define RX_MIN_TARGET 8
    3.31 +#define RX_DFL_MIN_TARGET 128
    3.32 +#define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
    3.33 +
    3.34  struct xennet_info
    3.35  {
    3.36    /* Base device vars */
    3.37 @@ -126,6 +139,7 @@ struct xennet_info
    3.38    struct netif_tx_sring *tx_pgs;
    3.39    PMDL tx_mdl;
    3.40    ULONG tx_id_free;
    3.41 +  ULONG tx_no_id_free;
    3.42    USHORT tx_id_list[NET_TX_RING_SIZE];
    3.43    ULONG tx_gref_free;
    3.44    grant_ref_t tx_gref_list[NET_TX_RING_SIZE];
    3.45 @@ -137,16 +151,16 @@ struct xennet_info
    3.46    grant_ref_t rx_ring_ref;
    3.47    struct netif_rx_sring *rx_pgs;
    3.48    PMDL rx_mdl;
    3.49 -  USHORT rx_id_list[NET_RX_RING_SIZE];
    3.50    ULONG rx_id_free;
    3.51    PNDIS_BUFFER rx_buffers[NET_RX_RING_SIZE];
    3.52    PMDL page_list[NET_RX_RING_SIZE];
    3.53    ULONG page_free;
    3.54 +  PNDIS_PACKET rx_current_packet;
    3.55 +  PMDL rx_first_mdl;
    3.56 +  USHORT rx_extra_info;
    3.57 +  USHORT rx_first_buffer_length;
    3.58  
    3.59    /* Receive-ring batched refills. */
    3.60 -#define RX_MIN_TARGET 8
    3.61 -#define RX_DFL_MIN_TARGET 64
    3.62 -#define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
    3.63    ULONG rx_target;
    3.64    ULONG rx_max_target;
    3.65    ULONG rx_min_target;
    3.66 @@ -170,6 +184,8 @@ extern LARGE_INTEGER ProfTime_RxBufferAl
    3.67  extern LARGE_INTEGER ProfTime_RxBufferFree;
    3.68  extern LARGE_INTEGER ProfTime_ReturnPacket;
    3.69  extern LARGE_INTEGER ProfTime_RxBufferCheck;
    3.70 +extern LARGE_INTEGER ProfTime_RxBufferCheckTopHalf;
    3.71 +extern LARGE_INTEGER ProfTime_RxBufferCheckBotHalf;
    3.72  extern LARGE_INTEGER ProfTime_Linearize;
    3.73  extern LARGE_INTEGER ProfTime_SendPackets;
    3.74  extern LARGE_INTEGER ProfTime_SendQueuedPackets;
    3.75 @@ -186,9 +202,10 @@ extern int ProfCount_PacketsPerSendPacke
    3.76  extern int ProfCount_SendQueuedPackets;
    3.77  
    3.78  extern int ProfCount_TxPacketsTotal;
    3.79 -extern int ProfCount_TxPacketsOffload;
    3.80 +extern int ProfCount_TxPacketsCsumOffload;
    3.81 +extern int ProfCount_TxPacketsLargeOffload;
    3.82  extern int ProfCount_RxPacketsTotal;
    3.83 -extern int ProfCount_RxPacketsOffload;
    3.84 +extern int ProfCount_RxPacketsCsumOffload;
    3.85  extern int ProfCount_CallsToIndicateReceive;
    3.86  
    3.87  NDIS_STATUS
     4.1 --- a/xennet/xennet_oid.c	Thu Mar 06 23:20:12 2008 +1100
     4.2 +++ b/xennet/xennet_oid.c	Wed Mar 12 22:44:47 2008 +1100
     4.3 @@ -68,8 +68,6 @@ NDIS_OID supported_oids[] =
     4.4      len = 8; \
     4.5      } }
     4.6  
     4.7 -//#define OFFLOAD_LARGE_SEND
     4.8 -
     4.9  NDIS_STATUS 
    4.10  XenNet_QueryInformation(
    4.11    IN NDIS_HANDLE MiniportAdapterContext,
    4.12 @@ -119,24 +117,26 @@ XenNet_QueryInformation(
    4.13      case OID_GEN_MAXIMUM_FRAME_SIZE:
    4.14        // According to the specs, OID_GEN_MAXIMUM_FRAME_SIZE does not include the header, so
    4.15        // it is XN_DATA_SIZE not XN_MAX_PKT_SIZE
    4.16 -      temp_data = XN_DATA_SIZE; // XN_MAX_PKT_SIZE;
    4.17 +      temp_data = XN_DATA_SIZE;
    4.18        break;
    4.19      case OID_GEN_LINK_SPEED:
    4.20        temp_data = 10000000; /* 1Gb */
    4.21        break;
    4.22      case OID_GEN_TRANSMIT_BUFFER_SPACE:
    4.23        /* pkts times sizeof ring, maybe? */
    4.24 -      temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
    4.25 +//      temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
    4.26 +      temp_data = PAGE_SIZE * NET_TX_RING_SIZE;
    4.27        break;
    4.28      case OID_GEN_RECEIVE_BUFFER_SPACE:
    4.29        /* pkts times sizeof ring, maybe? */
    4.30 -      temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
    4.31 +//      temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
    4.32 +      temp_data = PAGE_SIZE * NET_RX_RING_SIZE;
    4.33        break;
    4.34      case OID_GEN_TRANSMIT_BLOCK_SIZE:
    4.35 -      temp_data = XN_MAX_PKT_SIZE;
    4.36 +      temp_data = PAGE_SIZE; //XN_MAX_PKT_SIZE;
    4.37        break;
    4.38      case OID_GEN_RECEIVE_BLOCK_SIZE:
    4.39 -      temp_data = XN_MAX_PKT_SIZE;
    4.40 +      temp_data = PAGE_SIZE; //XN_MAX_PKT_SIZE;
    4.41        break;
    4.42      case OID_GEN_VENDOR_ID:
    4.43        temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
    4.44 @@ -157,7 +157,11 @@ XenNet_QueryInformation(
    4.45        len = 2;
    4.46        break;
    4.47      case OID_GEN_MAXIMUM_TOTAL_SIZE:
    4.48 +#if !defined(OFFLOAD_LARGE_SEND)
    4.49        temp_data = XN_MAX_PKT_SIZE;
    4.50 +#else
    4.51 +      temp_data = MAX_LARGE_SEND_OFFLOAD;
    4.52 +#endif
    4.53        break;
    4.54      case OID_GEN_MAC_OPTIONS:
    4.55        temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | 
    4.56 @@ -269,7 +273,7 @@ XenNet_QueryInformation(
    4.57          + nto->TaskBufferLength;
    4.58  
    4.59        /* fill in second nto */
    4.60 -      nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + nto->OffsetNextTask);
    4.61 +      nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(nto) + nto->OffsetNextTask);
    4.62        nto->Version = NDIS_TASK_OFFLOAD_VERSION;
    4.63        nto->Size = sizeof(NDIS_TASK_OFFLOAD);
    4.64        nto->Task = TcpLargeSendNdisTask;
    4.65 @@ -278,10 +282,10 @@ XenNet_QueryInformation(
    4.66        /* fill in large send struct */
    4.67        nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
    4.68        nttls->Version = 0;
    4.69 -      nttls->MaxOffLoadSize = 1024*64; /* made up, fixme */
    4.70 -      nttls->MinSegmentCount = 4; /* also made up */
    4.71 -      nttls->TcpOptions = FALSE;
    4.72 -      nttls->IpOptions = FALSE;
    4.73 +      nttls->MaxOffLoadSize = MAX_LARGE_SEND_OFFLOAD;
    4.74 +      nttls->MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
    4.75 +      nttls->TcpOptions = TRUE;
    4.76 +      nttls->IpOptions = TRUE;
    4.77  #endif
    4.78        nto->OffsetNextTask = 0; /* last one */
    4.79  
    4.80 @@ -333,6 +337,9 @@ XenNet_SetInformation(
    4.81    PNDIS_TASK_OFFLOAD_HEADER ntoh;
    4.82    PNDIS_TASK_OFFLOAD nto;
    4.83    PNDIS_TASK_TCP_IP_CHECKSUM nttic;
    4.84 +#ifdef OFFLOAD_LARGE_SEND
    4.85 +  PNDIS_TASK_TCP_LARGE_SEND nttls;
    4.86 +#endif
    4.87    int offset;
    4.88  
    4.89  //  KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
    4.90 @@ -505,6 +512,15 @@ XenNet_SetInformation(
    4.91            KdPrint(("  V6Receive.TcpChecksum          = %d\n", nttic->V6Receive.TcpChecksum));
    4.92            KdPrint(("  V6Receive.UdpChecksum          = %d\n", nttic->V6Receive.UdpChecksum));
    4.93            break;
    4.94 +        case TcpLargeSendNdisTask:
    4.95 +          *BytesRead += sizeof(NDIS_TASK_TCP_LARGE_SEND);
    4.96 +          KdPrint(("TcpLargeSendNdisTask\n"));
    4.97 +          nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
    4.98 +          KdPrint(("  MaxOffLoadSize                 = %d\n", nttls->MaxOffLoadSize));
    4.99 +          KdPrint(("  MinSegmentCount                = %d\n", nttls->MinSegmentCount));
   4.100 +          KdPrint(("  TcpOptions                     = %d\n", nttls->TcpOptions));
   4.101 +          KdPrint(("  IpOptions                      = %d\n", nttls->IpOptions));
   4.102 +          break;
   4.103          default:
   4.104            KdPrint(("  Unknown Task %d\n", nto->Task));
   4.105          }
     5.1 --- a/xennet/xennet_rx.c	Thu Mar 06 23:20:12 2008 +1100
     5.2 +++ b/xennet/xennet_rx.c	Wed Mar 12 22:44:47 2008 +1100
     5.3 @@ -20,22 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fi
     5.4  
     5.5  #include "xennet.h"
     5.6  
     5.7 -static USHORT
     5.8 -get_rx_id_from_freelist(struct xennet_info *xi)
     5.9 -{
    5.10 -  if (xi->rx_id_free == 0)
    5.11 -    return 0xFFFF;
    5.12 -  xi->rx_id_free--;
    5.13 -  return xi->rx_id_list[xi->rx_id_free];
    5.14 -}
    5.15 -
    5.16 -static VOID
    5.17 -put_rx_id_on_freelist(struct xennet_info *xi, USHORT id)
    5.18 -{
    5.19 -  xi->rx_id_list[xi->rx_id_free] = id;
    5.20 -  xi->rx_id_free++;
    5.21 -}
    5.22 -
    5.23  static PMDL
    5.24  get_page_from_freelist(struct xennet_info *xi)
    5.25  {
    5.26 @@ -114,7 +98,7 @@ XenNet_RxBufferAlloc(struct xennet_info 
    5.27    LARGE_INTEGER tsc, dummy;
    5.28  #endif
    5.29  
    5.30 -//  KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
    5.31 +//KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
    5.32  #if defined(XEN_PROFILE)
    5.33    tsc = KeQueryPerformanceCounter(&dummy);
    5.34  #endif
    5.35 @@ -124,17 +108,15 @@ XenNet_RxBufferAlloc(struct xennet_info 
    5.36    for (i = 0; i < batch_target; i++)
    5.37    {
    5.38      ASSERT(cycles++ < 256);
    5.39 +    if (xi->rx_id_free == 0)
    5.40 +      break;
    5.41      mdl = get_page_from_freelist(xi);
    5.42      if (mdl == NULL)
    5.43        break;
    5.44 +    xi->rx_id_free--;
    5.45  
    5.46      /* Give to netback */
    5.47 -    id = get_rx_id_from_freelist(xi);
    5.48 -    if (id == 0xFFFF)
    5.49 -    {
    5.50 -      put_page_on_freelist(xi, mdl);
    5.51 -      break;
    5.52 -    }
    5.53 +    id = (USHORT)((req_prod + i) & (NET_RX_RING_SIZE - 1));
    5.54  //    KdPrint((__DRIVER_NAME "     id = %d\n", id));
    5.55      ASSERT(xi->rx_buffers[id] == NULL);
    5.56      xi->rx_buffers[id] = mdl;
    5.57 @@ -151,6 +133,8 @@ XenNet_RxBufferAlloc(struct xennet_info 
    5.58        xi->event_channel);
    5.59    }
    5.60  
    5.61 +//KdPrint((__DRIVER_NAME "     Added %d out of %d buffers to rx ring\n", i, batch_target));
    5.62 +
    5.63  //  KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
    5.64  
    5.65  #if defined(XEN_PROFILE)
    5.66 @@ -169,21 +153,25 @@ XenNet_RxBufferCheck(struct xennet_info 
    5.67    PNDIS_PACKET packets[NET_RX_RING_SIZE];
    5.68    ULONG packet_count;
    5.69    PMDL mdl;
    5.70 +  PMDL first_mdl = NULL;
    5.71    int moretodo;
    5.72    struct netif_rx_response *rxrsp = NULL;
    5.73 +  struct netif_extra_info *ei;
    5.74    int more_frags = 0;
    5.75    NDIS_STATUS status;
    5.76    USHORT id;
    5.77    PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
    5.78 +  USHORT total_packet_length = 0;
    5.79 +  USHORT first_buffer_length = 0;
    5.80    int cycles = 0;
    5.81  #if defined(XEN_PROFILE)
    5.82 -  LARGE_INTEGER tsc, dummy;
    5.83 +  LARGE_INTEGER tsc, tsc2, dummy;
    5.84  #endif
    5.85    
    5.86  //  KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
    5.87  
    5.88  #if defined(XEN_PROFILE)
    5.89 -  tsc = KeQueryPerformanceCounter(&dummy);
    5.90 +  tsc = tsc2 = KeQueryPerformanceCounter(&dummy);
    5.91  #endif
    5.92  
    5.93    ASSERT(xi->connected);
    5.94 @@ -191,6 +179,14 @@ XenNet_RxBufferCheck(struct xennet_info 
    5.95    KeAcquireSpinLockAtDpcLevel(&xi->rx_lock);
    5.96  
    5.97    packet_count = 0;
    5.98 +  if (xi->rx_current_packet)
    5.99 +  {
   5.100 +    packets[0] = xi->rx_current_packet;
   5.101 +    xi->rx_current_packet = NULL;
   5.102 +    first_mdl = xi->rx_first_mdl;
   5.103 +    more_frags = NETRXF_more_data;
   5.104 +    first_buffer_length = xi->rx_first_buffer_length;
   5.105 +  }
   5.106    do {
   5.107      ASSERT(cycles++ < 256);
   5.108      prod = xi->rx.sring->rsp_prod;
   5.109 @@ -198,46 +194,85 @@ XenNet_RxBufferCheck(struct xennet_info 
   5.110  
   5.111      for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
   5.112        ASSERT(cycles++ < 256);
   5.113 -
   5.114 -      rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
   5.115 -      id = rxrsp->id;
   5.116 +      id = (USHORT)(cons & (NET_RX_RING_SIZE - 1));
   5.117        mdl = xi->rx_buffers[id];
   5.118        xi->rx_buffers[id] = NULL;
   5.119 -      put_rx_id_on_freelist(xi, id);
   5.120 -      if (rxrsp->status <= 0
   5.121 -        || rxrsp->offset + rxrsp->status > PAGE_SIZE)
   5.122 -      {
   5.123 -        KdPrint((__DRIVER_NAME ": Error: rxrsp offset %d, size %d\n",
   5.124 -          rxrsp->offset, rxrsp->status));
   5.125 -        continue;
   5.126 -      }
   5.127 -      if (!more_frags) // handling the packet's 1st buffer
   5.128 +      xi->rx_id_free++;
   5.129 +      if (xi->rx_extra_info)
   5.130        {
   5.131 -        NdisAllocatePacket(&status, &packets[packet_count], xi->packet_pool);
   5.132 -        ASSERT(status == NDIS_STATUS_SUCCESS);
   5.133 -        NDIS_SET_PACKET_HEADER_SIZE(packets[packet_count], XN_HDR_SIZE);
   5.134 -        if (rxrsp->flags & (NETRXF_csum_blank|NETRXF_data_validated)) // and we are enabled for offload...
   5.135 +KdPrint((__DRIVER_NAME "     RX extra info detected\n"));
   5.136 +        put_page_on_freelist(xi, mdl);
   5.137 +        ei = (struct netif_extra_info *)RING_GET_RESPONSE(&xi->rx, cons);
   5.138 +        xi->rx_extra_info = ei->flags & XEN_NETIF_EXTRA_FLAG_MORE;
   5.139 +        switch (ei->type)
   5.140          {
   5.141 -          csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpIpChecksumPacketInfo);
   5.142 -          csum_info->Receive.NdisPacketTcpChecksumSucceeded = 1;
   5.143 -          csum_info->Receive.NdisPacketUdpChecksumSucceeded = 1;
   5.144 -          csum_info->Receive.NdisPacketIpChecksumSucceeded = 1;
   5.145 -#if defined(XEN_PROFILE)
   5.146 -          ProfCount_RxPacketsOffload++;
   5.147 -#endif
   5.148 +        case XEN_NETIF_EXTRA_TYPE_GSO:
   5.149 +KdPrint((__DRIVER_NAME "     GSO detected - size = %d\n", ei->u.gso.size));
   5.150 +          switch (ei->u.gso.type)
   5.151 +          {
   5.152 +          case XEN_NETIF_GSO_TYPE_TCPV4:
   5.153 +KdPrint((__DRIVER_NAME "     GSO_TYPE_TCPV4 detected\n"));
   5.154 +            NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo) = (PVOID)(xen_ulong_t)(ei->u.gso.size);
   5.155 +            break;
   5.156 +          default:
   5.157 +            KdPrint((__DRIVER_NAME "     Unknown GSO type (%d) detected\n", ei->u.gso.type));
   5.158 +            break;
   5.159 +          }
   5.160 +          break;
   5.161 +        default:
   5.162 +KdPrint((__DRIVER_NAME "     Unknown extra info type (%d) detected\n", ei->type));
   5.163 +          break;
   5.164          }
   5.165        }
   5.166 -
   5.167 -      NdisAdjustBufferLength(mdl, rxrsp->status);
   5.168 -      NdisChainBufferAtBack(packets[packet_count], mdl);
   5.169 +      else
   5.170 +      {
   5.171 +//KdPrint((__DRIVER_NAME "     normal packet detected\n"));
   5.172 +        rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
   5.173 +        if (rxrsp->status <= 0
   5.174 +          || rxrsp->offset + rxrsp->status > PAGE_SIZE)
   5.175 +        {
   5.176 +          KdPrint((__DRIVER_NAME ": Error: rxrsp offset %d, size %d\n",
   5.177 +            rxrsp->offset, rxrsp->status));
   5.178 +          continue;
   5.179 +        }
   5.180 +        ASSERT(rxrsp->id == id);
   5.181 +        if (!more_frags) // handling the packet's 1st buffer
   5.182 +        {
   5.183 +          first_buffer_length = total_packet_length = rxrsp->status;
   5.184 +          first_mdl = mdl;
   5.185 +          NdisAllocatePacket(&status, &packets[packet_count], xi->packet_pool);
   5.186 +          ASSERT(status == NDIS_STATUS_SUCCESS);
   5.187 +          NDIS_SET_PACKET_HEADER_SIZE(packets[packet_count], XN_HDR_SIZE);
   5.188 +          if (rxrsp->flags & (NETRXF_csum_blank|NETRXF_data_validated)) // and we are enabled for offload...
   5.189 +          {
   5.190 +            csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpIpChecksumPacketInfo);
   5.191 +            csum_info->Receive.NdisPacketTcpChecksumSucceeded = 1;
   5.192 +            csum_info->Receive.NdisPacketUdpChecksumSucceeded = 1;
   5.193 +            csum_info->Receive.NdisPacketIpChecksumSucceeded = 1;
   5.194 +#if defined(XEN_PROFILE)
   5.195 +            ProfCount_RxPacketsCsumOffload++;
   5.196 +#endif
   5.197 +          }
   5.198 +        }
   5.199 +        else
   5.200 +        {
   5.201 +          NdisAdjustBufferLength(mdl, rxrsp->status);
   5.202 +          NdisChainBufferAtBack(packets[packet_count], mdl);
   5.203 +          first_buffer_length = first_buffer_length  - (USHORT)rxrsp->status;
   5.204 +        }
   5.205 +        
   5.206 +        xi->rx_extra_info = rxrsp->flags & NETRXF_extra_info;
   5.207 +        more_frags = rxrsp->flags & NETRXF_more_data;
   5.208 +      }
   5.209  
   5.210 -      ASSERT(!(rxrsp->flags & NETRXF_extra_info)); // not used on RX
   5.211 +      /* Packet done, add it to the list */
   5.212 +      if (!more_frags && !xi->rx_extra_info)
   5.213 +      {
   5.214 +        NdisAdjustBufferLength(first_mdl, first_buffer_length);
   5.215 +        NdisChainBufferAtFront(packets[packet_count], first_mdl);
   5.216  
   5.217 -      more_frags = rxrsp->flags & NETRXF_more_data;
   5.218 -
   5.219 -      /* Packet done, pass it up */
   5.220 -      if (!more_frags)
   5.221 -      {
   5.222 +//if (PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo)))
   5.223 +//  KdPrint((__DRIVER_NAME "     first_buffer_length = %d, total length = %d\n", first_buffer_length, total_packet_length));
   5.224  #if defined(XEN_PROFILE)
   5.225          ProfCount_RxPacketsTotal++;
   5.226  #endif
   5.227 @@ -254,18 +289,21 @@ XenNet_RxBufferCheck(struct xennet_info 
   5.228    /* Give netback more buffers */
   5.229    XenNet_RxBufferAlloc(xi);
   5.230  
   5.231 +  if (more_frags)
   5.232 +  {
   5.233 +    xi->rx_current_packet = packets[packet_count];
   5.234 +    xi->rx_first_mdl = first_mdl;
   5.235 +    xi->rx_first_buffer_length = first_buffer_length;
   5.236 +  }
   5.237 +
   5.238    KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
   5.239  
   5.240 -  ASSERT(!more_frags);
   5.241 -#if 0
   5.242 -  /* this must be called at DESPATCH_LEVEL */
   5.243 -  if (more_frags)
   5.244 -  {
   5.245 -    KdPrint((__DRIVER_NAME "     Missing fragments\n"));
   5.246 -    XenNet_ReturnPacket(xi, packets[packet_count]);
   5.247 -  }
   5.248 +#if defined(XEN_PROFILE)
   5.249 +  ProfTime_RxBufferCheckTopHalf.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc2.QuadPart;
   5.250 +  tsc2 = KeQueryPerformanceCounter(&dummy);
   5.251  #endif
   5.252 -  if (packet_count != 0)
   5.253 +
   5.254 +  if (packet_count > 0)
   5.255    {
   5.256      NdisMIndicateReceivePacket(xi->adapter_handle, packets, packet_count);
   5.257  #if defined(XEN_PROFILE)
   5.258 @@ -277,6 +315,7 @@ XenNet_RxBufferCheck(struct xennet_info 
   5.259  
   5.260  #if defined(XEN_PROFILE)
   5.261    ProfTime_RxBufferCheck.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc.QuadPart;
   5.262 +  ProfTime_RxBufferCheckBotHalf.QuadPart += KeQueryPerformanceCounter(&dummy).QuadPart - tsc2.QuadPart;
   5.263    ProfCount_RxBufferCheck++;
   5.264  #endif
   5.265  
   5.266 @@ -353,11 +392,13 @@ XenNet_RxBufferFree(struct xennet_info *
   5.267  BOOLEAN
   5.268  XenNet_RxInit(xennet_info_t *xi)
   5.269  {
   5.270 -  USHORT i;
   5.271 +  int i;
   5.272  
   5.273    KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
   5.274  
   5.275    xi->page_free = 0;
   5.276 +  xi->rx_current_packet = NULL;
   5.277 +  xi->rx_extra_info = 0;
   5.278    
   5.279    xi->rx_mdl = AllocatePage();
   5.280    xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl);
   5.281 @@ -366,12 +407,13 @@ XenNet_RxInit(xennet_info_t *xi)
   5.282    xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
   5.283      xi->XenInterface.InterfaceHeader.Context, 0,
   5.284      *MmGetMdlPfnArray(xi->rx_mdl), FALSE, 0);
   5.285 -  xi->rx_id_free = 0;
   5.286 +  xi->rx_id_free = NET_RX_RING_SIZE;
   5.287 +
   5.288    for (i = 0; i < NET_RX_RING_SIZE; i++)
   5.289    {
   5.290      xi->rx_buffers[i] = NULL;
   5.291 -    put_rx_id_on_freelist(xi, i);
   5.292    }
   5.293 +
   5.294    XenNet_RxBufferAlloc(xi);
   5.295  
   5.296    KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
     6.1 --- a/xennet/xennet_tx.c	Thu Mar 06 23:20:12 2008 +1100
     6.2 +++ b/xennet/xennet_tx.c	Wed Mar 12 22:44:47 2008 +1100
     6.3 @@ -23,12 +23,21 @@ Foundation, Inc., 51 Franklin Street, Fi
     6.4  static USHORT
     6.5  get_id_from_freelist(struct xennet_info *xi)
     6.6  {
     6.7 -  if (xi->tx_id_free == 0)
     6.8 +  if (xi->tx_id_free - xi->tx_no_id_free == 0)
     6.9      return 0xFFFF;
    6.10    xi->tx_id_free--;
    6.11    return xi->tx_id_list[xi->tx_id_free];
    6.12  }
    6.13  
    6.14 +static USHORT
    6.15 +get_no_id_from_freelist(struct xennet_info *xi)
    6.16 +{
    6.17 +  if (xi->tx_id_free - xi->tx_no_id_free == 0)
    6.18 +    return 0xFFFF;
    6.19 +  xi->tx_no_id_free--;
    6.20 +  return 0;
    6.21 +}
    6.22 +
    6.23  static VOID
    6.24  put_id_on_freelist(struct xennet_info *xi, USHORT id)
    6.25  {
    6.26 @@ -36,6 +45,12 @@ put_id_on_freelist(struct xennet_info *x
    6.27    xi->tx_id_free++;
    6.28  }
    6.29  
    6.30 +static VOID
    6.31 +put_no_id_on_freelist(struct xennet_info *xi)
    6.32 +{
    6.33 +  xi->tx_no_id_free++;
    6.34 +}
    6.35 +
    6.36  static grant_ref_t
    6.37  get_gref_from_freelist(struct xennet_info *xi)
    6.38  {
    6.39 @@ -52,6 +67,47 @@ put_gref_on_freelist(struct xennet_info 
    6.40    xi->tx_gref_free++;
    6.41  }
    6.42  
    6.43 +
    6.44 +#define SWAP_USHORT(x) (USHORT)((((x & 0xFF) << 8)|((x >> 8) & 0xFF)))
    6.45 +
    6.46 +/*
    6.47 + * Windows assumes that if we can do large send offload then we can
    6.48 + * do IP header csum offload, so we have to fake it!
    6.49 + */
    6.50 +VOID
    6.51 +XenNet_SumHeader(
    6.52 + PMDL mdl /* first buffer of the packet - containing the header */
    6.53 +)
    6.54 +{
    6.55 +  PVOID buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
    6.56 +  PUSHORT ushorts = (PUSHORT)buffer;
    6.57 +
    6.58 +  USHORT length_in_ushorts;
    6.59 +  USHORT i;
    6.60 +  ULONG csum = 0;
    6.61 +
    6.62 +  ASSERT(buffer);
    6.63 +  switch (SWAP_USHORT(ushorts[6]))
    6.64 +  {
    6.65 +  case 0x0800:
    6.66 +    /* check if buffer is long enough to contain ethernet header + minimum ip header */
    6.67 +    ushorts = &ushorts[0x07];
    6.68 +    length_in_ushorts = ((SWAP_USHORT(ushorts[0]) >> 8) & 0x0F) * 2;
    6.69 +    /* check if buffer is long enough to contain options too */
    6.70 +    break;
    6.71 +  default:
    6.72 +    return;
    6.73 +  }
    6.74 +  ushorts[5] = 0;
    6.75 +  for (i = 0; i < length_in_ushorts; i++)
    6.76 +  {
    6.77 +    csum += SWAP_USHORT(ushorts[i]);
    6.78 +  }
    6.79 +  while (csum & 0xFFFF0000)
    6.80 +    csum = (csum & 0xFFFF) + (csum >> 16);
    6.81 +  ushorts[5] = SWAP_USHORT(~csum);
    6.82 +}
    6.83 +
    6.84  /* Called at DISPATCH_LEVEL with tx_lock held */
    6.85  
    6.86  static VOID
    6.87 @@ -60,12 +116,14 @@ XenNet_SendQueuedPackets(struct xennet_i
    6.88    PLIST_ENTRY entry;
    6.89    PNDIS_PACKET packet;
    6.90    struct netif_tx_request *tx;
    6.91 +  struct netif_extra_info *ei;
    6.92    unsigned short id;
    6.93    int notify;
    6.94  #if defined(XEN_PROFILE)
    6.95    LARGE_INTEGER tsc, dummy;
    6.96  #endif
    6.97    PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
    6.98 +  
    6.99    ULONG i;
   6.100    PSCATTER_GATHER_LIST sg_list;
   6.101    UINT total_packet_length;
   6.102 @@ -75,6 +133,8 @@ XenNet_SendQueuedPackets(struct xennet_i
   6.103    ULONGLONG curr_addr;
   6.104    ULONG sg_num;
   6.105    ULONG pfn;
   6.106 +  ULONG mss;
   6.107 +  PMDL first_buffer;
   6.108    int cycles = 0;
   6.109  
   6.110  #if defined(XEN_PROFILE)
   6.111 @@ -88,88 +148,150 @@ XenNet_SendQueuedPackets(struct xennet_i
   6.112      ASSERT(cycles++ < 256);
   6.113  //KdPrint((__DRIVER_NAME "     Packet ready to send\n"));
   6.114      packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
   6.115 +    NdisQueryPacket(packet, NULL, NULL, &first_buffer, &total_packet_length);
   6.116      sg_list = NDIS_PER_PACKET_INFO_FROM_PACKET(packet, ScatterGatherListPacketInfo);
   6.117 -
   6.118 +/*
   6.119 +    for (i = 0; i < sg_list->NumberOfElements; i++)
   6.120 +    {
   6.121 +      KdPrint((__DRIVER_NAME "     sg entry %d - start = %08x, length = %d\n", i, sg_list->Elements[i].Address.LowPart, sg_list->Elements[i].Length));
   6.122 +    }
   6.123 +*/
   6.124      i = 0;
   6.125      sg_num = 0;
   6.126      remaining = 0;
   6.127      curr_addr = 0;
   6.128      id = 0;
   6.129 -    while (sg_num < sg_list->NumberOfElements || remaining > 0)
   6.130 +    mss = 0;
   6.131 +    offset = 0;
   6.132 +    while (sg_num < sg_list->NumberOfElements || remaining || (i == 1 && mss))
   6.133      {
   6.134 +//KdPrint((__DRIVER_NAME "     i = %d\n", i));
   6.135        ASSERT(cycles++ < 256);
   6.136 -      if (remaining == 0)
   6.137 +      if (i == 1 && mss)
   6.138        {
   6.139 -//KdPrint((__DRIVER_NAME "     First Frag in sg...\n"));
   6.140 +//KdPrint((__DRIVER_NAME "     Start of loop - Large Send...\n"));
   6.141 +        length = 0;
   6.142 +      }
   6.143 +      else if (remaining == 0)
   6.144 +      {
   6.145 +        mss = PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpLargeSendPacketInfo));
   6.146 +        if (total_packet_length <= mss)
   6.147 +          mss = 0;
   6.148 +//if (mss)
   6.149 +//KdPrint((__DRIVER_NAME "     Start of loop - First Frag in sg...\n"));
   6.150          curr_addr = sg_list->Elements[sg_num].Address.QuadPart;
   6.151          offset = (USHORT)(sg_list->Elements[sg_num].Address.QuadPart & (PAGE_SIZE - 1));
   6.152          remaining = (USHORT)sg_list->Elements[sg_num].Length;
   6.153          length = min(remaining, PAGE_SIZE - offset);
   6.154 +//if (mss)
   6.155 +//KdPrint((__DRIVER_NAME "     sg entry %d - start = %08x, length = %d\n", sg_num, (ULONG)curr_addr, length));
   6.156          sg_num++;
   6.157        }
   6.158        else
   6.159        {
   6.160 -//KdPrint((__DRIVER_NAME "     Subsequent Frag in sg...\n"));
   6.161 +//if (mss)
   6.162 +//KdPrint((__DRIVER_NAME "     Start of loop - Subsequent Frag in sg...\n"));
   6.163          offset = 0;
   6.164          length = min(remaining, PAGE_SIZE);
   6.165 +//if (mss)
   6.166 +//KdPrint((__DRIVER_NAME "     sg entry %d - start = %08x, length = %d\n", sg_num, (ULONG)curr_addr, length));
   6.167        }
   6.168 +      remaining = remaining - length;
   6.169        pfn = (ULONG)(curr_addr >> PAGE_SHIFT);
   6.170 -      remaining = remaining - length;
   6.171        curr_addr += length;
   6.172 +
   6.173        if (i++ < *(ULONG *)&packet->MiniportReservedEx)
   6.174          continue;
   6.175 -      id = get_id_from_freelist(xi);
   6.176 -      if (id == 0xFFFF)
   6.177 +      if (length > 0)
   6.178        {
   6.179 -//KdPrint((__DRIVER_NAME "     But out of space...\n"));
   6.180 -        /* whups, out of space on the ring. requeue and get out */
   6.181 -        InsertHeadList(&xi->tx_waiting_pkt_list, entry);
   6.182 -        break;
   6.183 -      }
   6.184 -      ASSERT(xi->tx_pkts[id] == NULL);
   6.185 -      (*(ULONG *)&packet->MiniportReservedEx)++;
   6.186 -      tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   6.187 -      tx->gref = get_gref_from_freelist(xi);
   6.188 -      ASSERT(tx->gref != 0);
   6.189 -      ASSERT(xi->tx_grefs[id] == 0);
   6.190 -      xi->tx_grefs[id] = tx->gref;
   6.191 -      xi->XenInterface.GntTbl_GrantAccess(
   6.192 -        xi->XenInterface.InterfaceHeader.Context, 0,
   6.193 -        pfn, FALSE, tx->gref);
   6.194 -      tx->id = id;
   6.195 -      tx->offset = offset;
   6.196 -      tx->flags = 0;
   6.197 -      if (i == 1) // we have already incremented i!!!
   6.198 -      {
   6.199 +        id = get_id_from_freelist(xi);
   6.200 +        if (id == 0xFFFF)
   6.201 +        {
   6.202 +KdPrint((__DRIVER_NAME "     Out of space...\n"));
   6.203 +          /* whups, out of space on the ring. requeue and get out */
   6.204 +          InsertHeadList(&xi->tx_waiting_pkt_list, entry);
   6.205 +          break;
   6.206 +        }
   6.207 +        ASSERT(xi->tx_pkts[id] == NULL);
   6.208 +        (*(ULONG *)&packet->MiniportReservedEx)++;
   6.209 +        tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   6.210 +
   6.211 +        tx->gref = get_gref_from_freelist(xi);
   6.212 +        ASSERT(tx->gref != 0);
   6.213 +        ASSERT(xi->tx_grefs[id] == 0);
   6.214 +        xi->tx_grefs[id] = tx->gref;
   6.215 +  
   6.216 +        xi->XenInterface.GntTbl_GrantAccess(
   6.217 +          xi->XenInterface.InterfaceHeader.Context, 0,
   6.218 +          pfn, FALSE, tx->gref);
   6.219 +        tx->id = id;
   6.220 +        tx->offset = offset;
   6.221 +        tx->flags = 0;
   6.222 +        if (i == 1) // we have already incremented i!!!
   6.223 +        {
   6.224 +//if (mss)
   6.225  //KdPrint((__DRIVER_NAME "     First Frag in packet...\n"));
   6.226 -        NdisQueryPacket(packet, NULL, NULL, NULL, &total_packet_length);
   6.227 -        tx->size = (USHORT)total_packet_length;
   6.228 +          tx->size = (USHORT)total_packet_length;
   6.229  #if defined(XEN_PROFILE)
   6.230 -        ProfCount_TxPacketsTotal++;
   6.231 +          ProfCount_TxPacketsTotal++;
   6.232  #endif
   6.233 -        csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpIpChecksumPacketInfo);
   6.234 -        if (csum_info->Transmit.NdisPacketTcpChecksum || csum_info->Transmit.NdisPacketUdpChecksum)
   6.235 +          csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpIpChecksumPacketInfo);
   6.236 +          if (csum_info->Transmit.NdisPacketTcpChecksum || csum_info->Transmit.NdisPacketUdpChecksum)
   6.237 +          {
   6.238 +            tx->flags |= NETTXF_csum_blank|NETTXF_data_validated;
   6.239 +#if defined(XEN_PROFILE)
   6.240 +            ProfCount_TxPacketsCsumOffload++;
   6.241 +#endif
   6.242 +          }
   6.243 +          if (mss)
   6.244 +          {
   6.245 +            XenNet_SumHeader(first_buffer);
   6.246 +//KdPrint((__DRIVER_NAME "     Large Send Offload - mss = %d, length = %d\n", mss, total_packet_length));
   6.247 +            tx->flags |= NETTXF_extra_info|NETTXF_csum_blank|NETTXF_data_validated;
   6.248 +#if defined(XEN_PROFILE)
   6.249 +            ProfCount_TxPacketsLargeOffload++;
   6.250 +#endif
   6.251 +          }
   6.252 +        }
   6.253 +        else
   6.254          {
   6.255 -          tx->flags |= NETTXF_csum_blank|NETTXF_data_validated;
   6.256 -#if defined(XEN_PROFILE)
   6.257 -          ProfCount_TxPacketsOffload++;
   6.258 -#endif
   6.259 +//if (mss)
   6.260 +//KdPrint((__DRIVER_NAME "     Subsequent Frag in packet...\n"));
   6.261 +          tx->size = length;
   6.262 +        }
   6.263 +        if (sg_num == sg_list->NumberOfElements && remaining == 0)
   6.264 +        {
   6.265 +//if (mss)
   6.266 +//KdPrint((__DRIVER_NAME "     No more frags\n"));
   6.267 +          xi->tx_pkts[id] = packet; /* only set the packet on the last buffer */
   6.268 +        }
   6.269 +        else
   6.270 +        {
   6.271 +//if (mss)
   6.272 +//KdPrint((__DRIVER_NAME "     More frags\n"));
   6.273 +          tx->flags |= NETTXF_more_data;
   6.274          }
   6.275        }
   6.276        else
   6.277        {
   6.278 -//KdPrint((__DRIVER_NAME "     Subsequent Frag in packet...\n"));
   6.279 -        tx->size = length;
   6.280 -      }
   6.281 -      if (sg_num == sg_list->NumberOfElements && remaining == 0)
   6.282 -      {
   6.283 -//KdPrint((__DRIVER_NAME "     No more frags\n"));
   6.284 -        xi->tx_pkts[id] = packet; /* only set the packet on the last buffer */
   6.285 -      }
   6.286 -      else
   6.287 -      {
   6.288 -//KdPrint((__DRIVER_NAME "     More frags\n"));
   6.289 -        tx->flags |= NETTXF_more_data;
   6.290 +        id = get_no_id_from_freelist(xi);
   6.291 +        if (id == 0xFFFF)
   6.292 +        {
   6.293 +KdPrint((__DRIVER_NAME "     Out of space...\n"));
   6.294 +          /* whups, out of space on the ring. requeue and get out */
   6.295 +          InsertHeadList(&xi->tx_waiting_pkt_list, entry);
   6.296 +          break;
   6.297 +        }
   6.298 +//if (mss)
   6.299 +//KdPrint((__DRIVER_NAME "     Extra Info...\n"));
   6.300 +        (*(ULONG *)&packet->MiniportReservedEx)++;
   6.301 +        ei = (struct netif_extra_info *)RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   6.302 +        ei->type = XEN_NETIF_EXTRA_TYPE_GSO;
   6.303 +        ei->flags = 0;
   6.304 +        ei->u.gso.size = (USHORT)mss;
   6.305 +        ei->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
   6.306 +        ei->u.gso.pad = 0;
   6.307 +        ei->u.gso.features = 0;
   6.308        }
   6.309        xi->tx.req_prod_pvt++;
   6.310      }
   6.311 @@ -201,6 +323,7 @@ XenNet_TxBufferGC(struct xennet_info *xi
   6.312    ULONG packet_count = 0;
   6.313    int moretodo;
   6.314    ULONG i;
   6.315 +  UINT total_packet_length;
   6.316    int cycles = 0;
   6.317  #if defined(XEN_PROFILE)
   6.318    LARGE_INTEGER tsc, dummy;
   6.319 @@ -230,20 +353,30 @@ XenNet_TxBufferGC(struct xennet_info *xi
   6.320  
   6.321        txrsp = RING_GET_RESPONSE(&xi->tx, cons);
   6.322        if (txrsp->status == NETIF_RSP_NULL)
   6.323 -        continue; // should this happen? what about the page?
   6.324 +      {
   6.325 +//        KdPrint((__DRIVER_NAME "     NETIF_RSP_NULL\n"));
   6.326 +        put_no_id_on_freelist(xi);
   6.327 +        continue; // This would be the response to an extra_info packet
   6.328 +      }
   6.329 +
   6.330        id  = txrsp->id;
   6.331        packets[packet_count] = xi->tx_pkts[id];
   6.332        if (packets[packet_count])
   6.333        {
   6.334 +        NdisQueryPacket(packets[packet_count], NULL, NULL, NULL, &total_packet_length);
   6.335 +        if (NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo) != 0)
   6.336 +        {
   6.337 +          NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo) = UlongToPtr(total_packet_length);
   6.338 +//KdPrint((__DRIVER_NAME "     Large Send Response = %d\n", NDIS_PER_PACKET_INFO_FROM_PACKET(packets[packet_count], TcpLargeSendPacketInfo)));
   6.339 +        }
   6.340          xi->tx_pkts[id] = NULL;
   6.341          packet_count++;
   6.342 +        xi->stat_tx_ok++;
   6.343        }
   6.344        put_gref_on_freelist(xi, xi->tx_grefs[id]);
   6.345        xi->tx_grefs[id] = 0;
   6.346        put_id_on_freelist(xi, id);
   6.347 -
   6.348 -      InterlockedDecrement(&xi->tx_outstanding);
   6.349 -      xi->stat_tx_ok++;
   6.350 +      xi->tx_outstanding++;
   6.351      }
   6.352  
   6.353      xi->tx.rsp_cons = prod;
   6.354 @@ -305,7 +438,7 @@ XenNet_SendPackets(
   6.355      *(ULONG *)&packet->MiniportReservedEx = 0;
   6.356      entry = (PLIST_ENTRY)&packet->MiniportReservedEx[sizeof(PVOID)];
   6.357      InsertTailList(&xi->tx_waiting_pkt_list, entry);
   6.358 -    InterlockedIncrement(&xi->tx_outstanding);
   6.359 +    xi->tx_outstanding--;
   6.360  #if defined(XEN_PROFILE)
   6.361      ProfCount_PacketsPerSendPackets++;
   6.362  #endif
   6.363 @@ -325,16 +458,18 @@ XenNet_SendPackets(
   6.364    if ((ProfCount_SendPackets & 1023) == 0)
   6.365    {
   6.366      KdPrint((__DRIVER_NAME "     ***\n"));
   6.367 -    KdPrint((__DRIVER_NAME "     RxBufferAlloc     Count = %10d, Avg Time = %10ld\n", ProfCount_RxBufferAlloc, (ProfCount_RxBufferAlloc == 0)?0:(ProfTime_RxBufferAlloc.QuadPart / ProfCount_RxBufferAlloc)));
   6.368 -    KdPrint((__DRIVER_NAME "     ReturnPacket      Count = %10d, Avg Time = %10ld\n", ProfCount_ReturnPacket, (ProfCount_ReturnPacket == 0)?0:(ProfTime_ReturnPacket.QuadPart / ProfCount_ReturnPacket)));
   6.369 -    KdPrint((__DRIVER_NAME "     RxBufferCheck     Count = %10d, Avg Time = %10ld\n", ProfCount_RxBufferCheck, (ProfCount_RxBufferCheck == 0)?0:(ProfTime_RxBufferCheck.QuadPart / ProfCount_RxBufferCheck)));
   6.370 -    KdPrint((__DRIVER_NAME "     Linearize         Count = %10d, Avg Time = %10ld\n", ProfCount_Linearize, (ProfCount_Linearize == 0)?0:(ProfTime_Linearize.QuadPart / ProfCount_Linearize)));
   6.371 -    KdPrint((__DRIVER_NAME "     SendPackets       Count = %10d, Avg Time = %10ld\n", ProfCount_SendPackets, (ProfCount_SendPackets == 0)?0:(ProfTime_SendPackets.QuadPart / ProfCount_SendPackets)));
   6.372 +    KdPrint((__DRIVER_NAME "     RxBufferAlloc     Count = %10d, Avg Time     = %10ld\n", ProfCount_RxBufferAlloc, (ProfCount_RxBufferAlloc == 0)?0:(ProfTime_RxBufferAlloc.QuadPart / ProfCount_RxBufferAlloc)));
   6.373 +    KdPrint((__DRIVER_NAME "     ReturnPacket      Count = %10d, Avg Time     = %10ld\n", ProfCount_ReturnPacket, (ProfCount_ReturnPacket == 0)?0:(ProfTime_ReturnPacket.QuadPart / ProfCount_ReturnPacket)));
   6.374 +    KdPrint((__DRIVER_NAME "     RxBufferCheck     Count = %10d, Avg Time     = %10ld\n", ProfCount_RxBufferCheck, (ProfCount_RxBufferCheck == 0)?0:(ProfTime_RxBufferCheck.QuadPart / ProfCount_RxBufferCheck)));
   6.375 +    KdPrint((__DRIVER_NAME "     RxBufferCheckTop                      Avg Time     = %10ld\n", (ProfCount_RxBufferCheck == 0)?0:(ProfTime_RxBufferCheckTopHalf.QuadPart / ProfCount_RxBufferCheck)));
   6.376 +    KdPrint((__DRIVER_NAME "     RxBufferCheckBot                      Avg Time     = %10ld\n", (ProfCount_RxBufferCheck == 0)?0:(ProfTime_RxBufferCheckBotHalf.QuadPart / ProfCount_RxBufferCheck)));
   6.377 +    KdPrint((__DRIVER_NAME "     Linearize         Count = %10d, Avg Time     = %10ld\n", ProfCount_Linearize, (ProfCount_Linearize == 0)?0:(ProfTime_Linearize.QuadPart / ProfCount_Linearize)));
   6.378 +    KdPrint((__DRIVER_NAME "     SendPackets       Count = %10d, Avg Time     = %10ld\n", ProfCount_SendPackets, (ProfCount_SendPackets == 0)?0:(ProfTime_SendPackets.QuadPart / ProfCount_SendPackets)));
   6.379      KdPrint((__DRIVER_NAME "     Packets per SendPackets = %10d\n", (ProfCount_SendPackets == 0)?0:(ProfCount_PacketsPerSendPackets / ProfCount_SendPackets)));
   6.380 -    KdPrint((__DRIVER_NAME "     SendQueuedPackets Count = %10d, Avg Time = %10ld\n", ProfCount_SendQueuedPackets, (ProfCount_SendQueuedPackets == 0)?0:(ProfTime_SendQueuedPackets.QuadPart / ProfCount_SendQueuedPackets)));
   6.381 -    KdPrint((__DRIVER_NAME "     TxBufferGC        Count = %10d, Avg Time = %10ld\n", ProfCount_TxBufferGC, (ProfCount_TxBufferGC == 0)?0:(ProfTime_TxBufferGC.QuadPart / ProfCount_TxBufferGC)));
   6.382 -    KdPrint((__DRIVER_NAME "     RxPackets         Total = %10d, Offload  = %10d, CallsToReceive = %10d\n", ProfCount_RxPacketsTotal, ProfCount_RxPacketsOffload, ProfCount_CallsToIndicateReceive));
   6.383 -    KdPrint((__DRIVER_NAME "     TxPackets         Total = %10d, Offload  = %10d\n", ProfCount_TxPacketsTotal, ProfCount_TxPacketsOffload));
   6.384 +    KdPrint((__DRIVER_NAME "     SendQueuedPackets Count = %10d, Avg Time     = %10ld\n", ProfCount_SendQueuedPackets, (ProfCount_SendQueuedPackets == 0)?0:(ProfTime_SendQueuedPackets.QuadPart / ProfCount_SendQueuedPackets)));
   6.385 +    KdPrint((__DRIVER_NAME "     TxBufferGC        Count = %10d, Avg Time     = %10ld\n", ProfCount_TxBufferGC, (ProfCount_TxBufferGC == 0)?0:(ProfTime_TxBufferGC.QuadPart / ProfCount_TxBufferGC)));
   6.386 +    KdPrint((__DRIVER_NAME "     RxPackets         Total = %10d, Csum Offload = %10d, Calls To Receive = %10d\n", ProfCount_RxPacketsTotal, ProfCount_RxPacketsCsumOffload, ProfCount_CallsToIndicateReceive));
   6.387 +    KdPrint((__DRIVER_NAME "     TxPackets         Total = %10d, Csum Offload = %10d, Large Offload    = %10d\n", ProfCount_TxPacketsTotal, ProfCount_TxPacketsCsumOffload, ProfCount_TxPacketsLargeOffload));
   6.388    }
   6.389  #endif
   6.390    //  KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
   6.391 @@ -385,6 +520,7 @@ XenNet_TxInit(xennet_info_t *xi)
   6.392      xi->XenInterface.InterfaceHeader.Context, 0,
   6.393      *MmGetMdlPfnArray(xi->tx_mdl), FALSE, 0);
   6.394    xi->tx_id_free = 0;
   6.395 +  xi->tx_no_id_free = 0;
   6.396    for (i = 0; i < NET_TX_RING_SIZE; i++)
   6.397    {
   6.398      xi->tx_pkts[i] = NULL;