win-pvdrivers

changeset 596:214866b0a8fd

Make xennet work in the case where SG is not available. Limit GSO to PAGE_SIZE in such a case. Also Disable SG and GSO if disabled in the backend.
author James Harper <james.harper@bendigoit.com.au>
date Fri Jun 26 14:45:54 2009 +1000 (2009-06-26)
parents 63a4d934929f
children 1ca6f17ebc47
files xennet/xennet.c xennet/xennet.h xennet/xennet_common.c xennet/xennet_rx.c xennet/xennet_tx.c
line diff
     1.1 --- a/xennet/xennet.c	Thu Jun 25 21:09:37 2009 +1000
     1.2 +++ b/xennet/xennet.c	Fri Jun 26 14:45:54 2009 +1000
     1.3 @@ -125,6 +125,7 @@ XenNet_ConnectBackend(struct xennet_info
     1.4    PCHAR setting, value, value2;
     1.5    UINT i;
     1.6    ULONG backend_sg = 0;
     1.7 +  ULONG backend_gso = 0;
     1.8  
     1.9    FUNCTION_ENTER();
    1.10    
    1.11 @@ -180,6 +181,13 @@ XenNet_ConnectBackend(struct xennet_info
    1.12            backend_sg = 1;
    1.13          }
    1.14        }
    1.15 +      else if (strcmp(setting, "feature-gso-tcpv4") == 0)
    1.16 +      {
    1.17 +        if (atoi(value))
    1.18 +        {
    1.19 +          backend_gso = 1;
    1.20 +        }
    1.21 +      }
    1.22        break;
    1.23      case XEN_INIT_TYPE_VECTORS:
    1.24        KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_VECTORS\n"));
    1.25 @@ -206,6 +214,12 @@ XenNet_ConnectBackend(struct xennet_info
    1.26    if (xi->config_sg && !backend_sg)
    1.27    {
    1.28      KdPrint((__DRIVER_NAME "     SG not supported by backend - disabling\n"));
    1.29 +    xi->config_sg = 0;
    1.30 +  }
    1.31 +  if (xi->config_gso && !backend_gso)
    1.32 +  {
    1.33 +    KdPrint((__DRIVER_NAME "     GSO not supported by backend - disabling\n"));
    1.34 +    xi->config_gso = 0;
    1.35    }
    1.36    FUNCTION_EXIT();
    1.37    
    1.38 @@ -622,6 +636,7 @@ XenNet_Init(
    1.39    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
    1.40    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
    1.41    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
    1.42 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
    1.43    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
    1.44    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
    1.45    RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
    1.46 @@ -647,11 +662,24 @@ XenNet_Init(
    1.47      goto err;
    1.48    }
    1.49  
    1.50 -  status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE, xi->config_gso);
    1.51 -  if (!NT_SUCCESS(status))
    1.52 +  if (xi->config_sg)
    1.53    {
    1.54 -    KdPrint(("NdisMInitializeScatterGatherDma failed (%08x)\n", status));
    1.55 -    goto err;
    1.56 +    status = NdisMInitializeScatterGatherDma(xi->adapter_handle, TRUE, xi->config_gso);
    1.57 +    if (!NT_SUCCESS(status))
    1.58 +    {
    1.59 +      KdPrint(("NdisMInitializeScatterGatherDma failed (%08x), disabling\n", status));
    1.60 +      xi->config_sg = 0;
    1.61 +    }
    1.62 +  }
    1.63 +  else
    1.64 +  {
    1.65 +    status = NdisMAllocateMapRegisters(xi->adapter_handle, 0, NDIS_DMA_64BITS, 64, PAGE_SIZE);
    1.66 +    if (status != NDIS_STATUS_SUCCESS)
    1.67 +    {
    1.68 +      KdPrint((__DRIVER_NAME "     Cannot allocate Map Registers\n"));
    1.69 +    }
    1.70 +    /* without SG, GSO can be a maximum of PAGE_SIZE */
    1.71 +    xi->config_gso = min(xi->config_gso, PAGE_SIZE);
    1.72    }
    1.73  
    1.74    XenNet_TxInit(xi);
    1.75 @@ -722,9 +750,12 @@ XenNet_Halt(
    1.76  
    1.77    xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
    1.78  
    1.79 -  // TODO: remove event channel xenbus entry (how?)
    1.80 +  if (!xi->config_sg)
    1.81 +  {
    1.82 +    NdisMFreeMapRegisters(xi->adapter_handle);
    1.83 +  }
    1.84  
    1.85 -  NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
    1.86 +  NdisFreeMemory(xi, 0, 0);
    1.87  
    1.88    FUNCTION_EXIT();
    1.89  }
    1.90 @@ -791,6 +822,7 @@ DriverEntry(
    1.91    /* added in v.4 -- use multiple pkts interface */
    1.92    mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
    1.93    mini_chars.SendPacketsHandler = XenNet_SendPackets;
    1.94 +  mini_chars.CancelSendPacketsHandler = XenNet_CancelSendPackets;
    1.95  
    1.96  #ifdef NDIS51_MINIPORT
    1.97    /* added in v.5.1 */
     2.1 --- a/xennet/xennet.h	Thu Jun 25 21:09:37 2009 +1000
     2.2 +++ b/xennet/xennet.h	Fri Jun 26 14:45:54 2009 +1000
     2.3 @@ -201,6 +201,7 @@ typedef struct {
     2.4    PNDIS_BUFFER curr_buffer;
     2.5    shared_buffer_t *first_pb;
     2.6    shared_buffer_t *curr_pb;
     2.7 +  PUCHAR first_buffer_virtual;
     2.8    UCHAR header_data[132]; /* maximum possible size of ETH + IP + TCP/UDP headers */
     2.9    ULONG mdl_count;
    2.10    USHORT curr_mdl_offset;
    2.11 @@ -367,6 +368,11 @@ XenNet_SendPackets(
    2.12    IN UINT NumberOfPackets
    2.13    );
    2.14  
    2.15 +VOID
    2.16 +XenNet_CancelSendPackets(
    2.17 +  NDIS_HANDLE MiniportAdapterContext,
    2.18 +  PVOID CancelId);
    2.19 +  
    2.20  BOOLEAN
    2.21  XenNet_TxInit(xennet_info_t *xi);
    2.22  
    2.23 @@ -398,7 +404,7 @@ XenNet_SetInformation(
    2.24  #define PARSE_UNKNOWN_TYPE 2
    2.25  
    2.26  ULONG
    2.27 -XenNet_ParsePacketHeader(packet_info_t *pi);
    2.28 +XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR buffer, ULONG min_header_size);
    2.29  
    2.30  VOID
    2.31  XenNet_SumIpHeader(
     3.1 --- a/xennet/xennet_common.c	Thu Jun 25 21:09:37 2009 +1000
     3.2 +++ b/xennet/xennet_common.c	Fri Jun 26 14:45:54 2009 +1000
     3.3 @@ -33,39 +33,35 @@ XenNet_BuildHeader(packet_info_t *pi, UL
     3.4  
     3.5    if (new_header_size <= pi->header_length)
     3.6    {
     3.7 -    //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " new_header_size <= pi->header_length\n"));
     3.8 -    return TRUE;
     3.9 +    return TRUE; /* header is already at least the required size */
    3.10    }
    3.11  
    3.12 -  if (new_header_size > ARRAY_SIZE(pi->header_data))
    3.13 +  if (pi->header == pi->first_buffer_virtual)
    3.14    {
    3.15 -    //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " new_header_size > ARRAY_SIZE(pi->header_data)\n"));
    3.16 -    return FALSE;
    3.17 -  }
    3.18 -  
    3.19 -  if (new_header_size <= pi->first_buffer_length)
    3.20 -  {
    3.21 -    //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " new_header_size <= pi->first_buffer_length\n"));
    3.22 -    pi->header_length = new_header_size;
    3.23 -    if (pi->header_length == pi->first_buffer_length)
    3.24 +    /* still working in the first buffer */
    3.25 +    if (new_header_size <= pi->first_buffer_length)
    3.26      {
    3.27 -      NdisGetNextBuffer(pi->curr_buffer, &pi->curr_buffer);
    3.28 -      pi->curr_mdl_offset = 0;
    3.29 +      //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " new_header_size <= pi->first_buffer_length\n"));
    3.30 +      pi->header_length = new_header_size;
    3.31 +      if (pi->header_length == pi->first_buffer_length)
    3.32 +      {
    3.33 +        NdisGetNextBuffer(pi->curr_buffer, &pi->curr_buffer);
    3.34 +        pi->curr_mdl_offset = 0;
    3.35 +      }
    3.36 +      else
    3.37 +      {
    3.38 +        pi->curr_mdl_offset = (USHORT)new_header_size;
    3.39 +        if (pi->curr_pb)
    3.40 +          pi->curr_pb = pi->curr_pb->next;
    3.41 +      }      
    3.42 +      return TRUE;
    3.43      }
    3.44      else
    3.45      {
    3.46 -      pi->curr_mdl_offset = (USHORT)new_header_size;
    3.47 -      if (pi->curr_pb)
    3.48 -        pi->curr_pb = pi->curr_pb->next;
    3.49 +      //KdPrint((__DRIVER_NAME "     Switching to header_data\n"));
    3.50 +      memcpy(pi->header_data, pi->header, pi->header_length);
    3.51 +      pi->header = pi->header_data;
    3.52      }
    3.53 -    
    3.54 -    return TRUE;
    3.55 -  }
    3.56 -  else if (pi->header != pi->header_data)
    3.57 -  {
    3.58 -    //KdPrint((__DRIVER_NAME "     Switching to header_data\n"));
    3.59 -    memcpy(pi->header_data, pi->header, pi->header_length);
    3.60 -    pi->header = pi->header_data;
    3.61    }
    3.62    
    3.63    bytes_remaining = new_header_size - pi->header_length;
    3.64 @@ -110,19 +106,23 @@ XenNet_BuildHeader(packet_info_t *pi, UL
    3.65  }
    3.66  
    3.67  ULONG
    3.68 -XenNet_ParsePacketHeader(packet_info_t *pi)
    3.69 +XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR alt_buffer, ULONG min_header_size)
    3.70  {
    3.71    //FUNCTION_ENTER();
    3.72  
    3.73    ASSERT(pi->first_buffer);
    3.74    
    3.75 -  NdisQueryBufferSafe(pi->first_buffer, (PVOID)&pi->header, &pi->first_buffer_length, NormalPagePriority);
    3.76 +  NdisQueryBufferSafe(pi->first_buffer, (PVOID)&pi->first_buffer_virtual, &pi->first_buffer_length, NormalPagePriority);
    3.77    pi->curr_buffer = pi->first_buffer;
    3.78 +  if (alt_buffer)
    3.79 +    pi->header = alt_buffer;
    3.80 +  else
    3.81 +    pi->header = pi->first_buffer_virtual;
    3.82  
    3.83    pi->header_length = 0;
    3.84    pi->curr_mdl_offset = 0;
    3.85      
    3.86 -  if (!XenNet_BuildHeader(pi, (ULONG)XN_HDR_SIZE))
    3.87 +  if (!XenNet_BuildHeader(pi, max((ULONG)XN_HDR_SIZE, min_header_size)))
    3.88    {
    3.89      KdPrint((__DRIVER_NAME "     packet too small (Ethernet Header)\n"));
    3.90      return PARSE_TOO_SMALL;
     4.1 --- a/xennet/xennet_rx.c	Thu Jun 25 21:09:37 2009 +1000
     4.2 +++ b/xennet/xennet_rx.c	Fri Jun 26 14:45:54 2009 +1000
     4.3 @@ -435,7 +435,7 @@ XenNet_MakePackets(
     4.4  
     4.5    //FUNCTION_ENTER();
     4.6  
     4.7 -  parse_result = XenNet_ParsePacketHeader(pi);
     4.8 +  parse_result = XenNet_ParsePacketHeader(pi, NULL, 0);
     4.9  
    4.10    if ((xi->packet_filter & NDIS_PACKET_TYPE_MULTICAST)
    4.11      && !(xi->packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST)
     5.1 --- a/xennet/xennet_tx.c	Thu Jun 25 21:09:37 2009 +1000
     5.2 +++ b/xennet/xennet_tx.c	Fri Jun 26 14:45:54 2009 +1000
     5.3 @@ -71,6 +71,7 @@ put_cb_on_freelist(struct xennet_info *x
     5.4  
     5.5  #define SWAP_USHORT(x) (USHORT)((((x & 0xFF) << 8)|((x >> 8) & 0xFF)))
     5.6  
     5.7 +
     5.8  /* Called at DISPATCH_LEVEL with tx_lock held */
     5.9  /*
    5.10   * Send one NDIS_PACKET. This may involve multiple entries on TX ring.
    5.11 @@ -89,11 +90,11 @@ XenNet_HWSendPacket(struct xennet_info *
    5.12    BOOLEAN ndis_lso = FALSE;
    5.13    BOOLEAN xen_gso = FALSE;
    5.14    //ULONG remaining;
    5.15 -  PSCATTER_GATHER_LIST sg;
    5.16 +  PSCATTER_GATHER_LIST sg = NULL;
    5.17    ULONG sg_element = 0;
    5.18    ULONG sg_offset = 0;
    5.19    ULONG parse_result;
    5.20 -  shared_buffer_t *header_buf = NULL;
    5.21 +  shared_buffer_t *coalesce_buf = NULL;
    5.22    ULONG chunks = 0;
    5.23    
    5.24    //FUNCTION_ENTER();
    5.25 @@ -102,7 +103,21 @@ XenNet_HWSendPacket(struct xennet_info *
    5.26    NdisQueryPacket(packet, NULL, (PUINT)&pi.mdl_count, &pi.first_buffer, (PUINT)&pi.total_length);
    5.27    //KdPrint((__DRIVER_NAME "     A - packet = %p, mdl_count = %d, total_length = %d\n", packet, pi.mdl_count, pi.total_length));
    5.28  
    5.29 -  parse_result = XenNet_ParsePacketHeader(&pi);  
    5.30 +  if (xi->config_sg)
    5.31 +  {
    5.32 +    parse_result = XenNet_ParsePacketHeader(&pi, NULL, 0);
    5.33 +  }
    5.34 +  else
    5.35 +  {
    5.36 +    coalesce_buf = get_cb_from_freelist(xi);
    5.37 +    if (!coalesce_buf)
    5.38 +    {
    5.39 +      KdPrint((__DRIVER_NAME "     Full on send - no free cb's\n"));
    5.40 +      return FALSE;
    5.41 +    }
    5.42 +    parse_result = XenNet_ParsePacketHeader(&pi, coalesce_buf->virtual, pi.total_length);
    5.43 +  }
    5.44 +  
    5.45    //KdPrint((__DRIVER_NAME "     B\n"));
    5.46  
    5.47    if (NDIS_GET_PACKET_PROTOCOL_TYPE(packet) == NDIS_PROTOCOL_ID_TCP_IP)
    5.48 @@ -170,32 +185,33 @@ XenNet_HWSendPacket(struct xennet_info *
    5.49      }
    5.50    }
    5.51  
    5.52 -  sg = (PSCATTER_GATHER_LIST)NDIS_PER_PACKET_INFO_FROM_PACKET(packet, ScatterGatherListPacketInfo);
    5.53 -  ASSERT(sg != NULL);
    5.54 -
    5.55 -  if (sg->NumberOfElements > 19)
    5.56 -  {
    5.57 -    KdPrint((__DRIVER_NAME "     sg->NumberOfElements = %d\n", sg->NumberOfElements));
    5.58 -    NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_SUCCESS);
    5.59 -    return TRUE; // we'll pretend we sent the packet here for now...
    5.60 -  }
    5.61 -  //ASSERT(sg->NumberOfElements <= 19);
    5.62 -  if (sg->NumberOfElements + !!ndis_lso > xi->tx_ring_free)
    5.63 +  if (xi->config_sg)
    5.64    {
    5.65 -    KdPrint((__DRIVER_NAME "     Full on send - required = %d, available = %d\n", sg->NumberOfElements + !!ndis_lso, xi->tx_ring_free));
    5.66 -    //FUNCTION_EXIT();
    5.67 -    return FALSE;
    5.68 -  }
    5.69 -
    5.70 +    sg = (PSCATTER_GATHER_LIST)NDIS_PER_PACKET_INFO_FROM_PACKET(packet, ScatterGatherListPacketInfo);
    5.71 +    ASSERT(sg != NULL);
    5.72  
    5.73 -  if (ndis_lso || (pi.header_length && pi.header_length > sg->Elements[sg_element].Length && pi.header == pi.header_data))
    5.74 -  {
    5.75 -    header_buf = get_cb_from_freelist(xi);
    5.76 -    if (!header_buf)
    5.77 +    if (sg->NumberOfElements > 19)
    5.78      {
    5.79 -      KdPrint((__DRIVER_NAME "     Full on send - no free cb's\n"));
    5.80 +      KdPrint((__DRIVER_NAME "     sg->NumberOfElements = %d\n", sg->NumberOfElements));
    5.81 +      NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_SUCCESS);
    5.82 +      return TRUE; // we'll pretend we sent the packet here for now...
    5.83 +    }
    5.84 +    if (sg->NumberOfElements + !!ndis_lso > xi->tx_ring_free)
    5.85 +    {
    5.86 +      KdPrint((__DRIVER_NAME "     Full on send - required = %d, available = %d\n", sg->NumberOfElements + !!ndis_lso, xi->tx_ring_free));
    5.87 +      //FUNCTION_EXIT();
    5.88        return FALSE;
    5.89      }
    5.90 +
    5.91 +    if (ndis_lso || (pi.header_length && pi.header_length > sg->Elements[sg_element].Length && pi.header == pi.header_data))
    5.92 +    {
    5.93 +      coalesce_buf = get_cb_from_freelist(xi);
    5.94 +      if (!coalesce_buf)
    5.95 +      {
    5.96 +        KdPrint((__DRIVER_NAME "     Full on send - no free cb's\n"));
    5.97 +        return FALSE;
    5.98 +      }
    5.99 +    }
   5.100    }
   5.101    
   5.102    if (ndis_lso)
   5.103 @@ -231,45 +247,45 @@ XenNet_HWSendPacket(struct xennet_info *
   5.104    chunks++;
   5.105    xi->tx_ring_free--;
   5.106    tx0->id = 0xFFFF;
   5.107 -  if (header_buf)
   5.108 +  if (coalesce_buf)
   5.109    {
   5.110      ULONG remaining = pi.header_length;
   5.111 -    ASSERT(pi.header_length < TX_HEADER_BUFFER_SIZE);
   5.112 +    //ASSERT(pi.header_length < TX_HEADER_BUFFER_SIZE);
   5.113      //KdPrint((__DRIVER_NAME "     D - header_length = %d\n", pi.header_length));
   5.114 -    memcpy(header_buf->virtual, pi.header, pi.header_length);
   5.115 +    memcpy(coalesce_buf->virtual, pi.header, pi.header_length);
   5.116      /* even though we haven't reported that we are capable of it, LSO demands that we calculate the IP Header checksum */
   5.117      if (ndis_lso)
   5.118      {
   5.119 -      XenNet_SumIpHeader(header_buf->virtual, pi.ip4_header_length);
   5.120 +      XenNet_SumIpHeader(coalesce_buf->virtual, pi.ip4_header_length);
   5.121      }
   5.122 -    tx0->gref = (grant_ref_t)(header_buf->logical.QuadPart >> PAGE_SHIFT);
   5.123 -    tx0->offset = (USHORT)header_buf->logical.LowPart & (PAGE_SIZE - 1);
   5.124 +    tx0->gref = (grant_ref_t)(coalesce_buf->logical.QuadPart >> PAGE_SHIFT);
   5.125 +    tx0->offset = (USHORT)coalesce_buf->logical.LowPart & (PAGE_SIZE - 1);
   5.126      tx0->size = (USHORT)pi.header_length;
   5.127      ASSERT(tx0->offset + tx0->size <= PAGE_SIZE);
   5.128      ASSERT(tx0->size);
   5.129 -    /* TODO: if the next buffer contains only a small amount of data then put it on too */
   5.130 -    while (remaining)
   5.131 +    if (xi->config_sg)
   5.132      {
   5.133 -      //KdPrint((__DRIVER_NAME "     D - remaining = %d\n", remaining));
   5.134 -      //KdPrint((__DRIVER_NAME "     Da - sg_element = %d, sg->Elements[sg_element].Length = %d\n", sg_element, sg->Elements[sg_element].Length));
   5.135 -      if (sg->Elements[sg_element].Length <= remaining)
   5.136 +      /* TODO: if the next buffer contains only a small amount of data then put it on too */
   5.137 +      while (remaining)
   5.138        {
   5.139 -        remaining -= sg->Elements[sg_element].Length;
   5.140 -        sg_element++;
   5.141 -      }
   5.142 -      else
   5.143 -      {
   5.144 -        sg_offset = remaining;
   5.145 -        remaining = 0;
   5.146 +        //KdPrint((__DRIVER_NAME "     D - remaining = %d\n", remaining));
   5.147 +        //KdPrint((__DRIVER_NAME "     Da - sg_element = %d, sg->Elements[sg_element].Length = %d\n", sg_element, sg->Elements[sg_element].Length));
   5.148 +        if (sg->Elements[sg_element].Length <= remaining)
   5.149 +        {
   5.150 +          remaining -= sg->Elements[sg_element].Length;
   5.151 +          sg_element++;
   5.152 +        }
   5.153 +        else
   5.154 +        {
   5.155 +          sg_offset = remaining;
   5.156 +          remaining = 0;
   5.157 +        }
   5.158        }
   5.159      }
   5.160    }
   5.161    else
   5.162    {
   5.163 -    //KdPrint((__DRIVER_NAME "     E\n"));
   5.164 -    //KdPrint((__DRIVER_NAME "     Eg - sg_element = %d, sg_offset = %d\n", sg_element, sg_offset));
   5.165 -    //KdPrint((__DRIVER_NAME "     Eh - address = %p, length = %d\n",
   5.166 -    //  sg->Elements[sg_element].Address.LowPart, sg->Elements[sg_element].Length));
   5.167 +    ASSERT(xi->config_sg);
   5.168      tx0->gref = (grant_ref_t)(sg->Elements[sg_element].Address.QuadPart >> PAGE_SHIFT);
   5.169      tx0->offset = (USHORT)sg->Elements[sg_element].Address.LowPart & (PAGE_SIZE - 1);
   5.170      tx0->size = (USHORT)sg->Elements[sg_element].Length;
   5.171 @@ -297,38 +313,41 @@ XenNet_HWSendPacket(struct xennet_info *
   5.172    }
   5.173  
   5.174    //KdPrint((__DRIVER_NAME "     F\n"));
   5.175 -  /* (C) */
   5.176 -  while (sg_element < sg->NumberOfElements)
   5.177 +  if (xi->config_sg)
   5.178    {
   5.179 -    //KdPrint((__DRIVER_NAME "     G - sg_element = %d, sg_offset = %d\n", sg_element, sg_offset));
   5.180 -    //KdPrint((__DRIVER_NAME "     H - address = %p, length = %d\n",
   5.181 -    //  sg->Elements[sg_element].Address.LowPart + sg_offset, sg->Elements[sg_element].Length - sg_offset));
   5.182 -    txN = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   5.183 -    chunks++;
   5.184 -    xi->tx_ring_free--;
   5.185 -    txN->id = 0xFFFF;
   5.186 -    txN->gref = (grant_ref_t)(sg->Elements[sg_element].Address.QuadPart >> PAGE_SHIFT);
   5.187 -    ASSERT((sg->Elements[sg_element].Address.LowPart & (PAGE_SIZE - 1)) + sg_offset <= PAGE_SIZE);
   5.188 -    txN->offset = (USHORT)(sg->Elements[sg_element].Address.LowPart + sg_offset) & (PAGE_SIZE - 1);
   5.189 -    ASSERT(sg->Elements[sg_element].Length > sg_offset);
   5.190 -    txN->size = (USHORT)(sg->Elements[sg_element].Length - sg_offset);
   5.191 -    ASSERT(txN->offset + txN->size <= PAGE_SIZE);
   5.192 -    ASSERT(txN->size);
   5.193 -    tx0->size = tx0->size + txN->size;
   5.194 -    txN->flags = NETTXF_more_data;
   5.195 -    sg_offset = 0;
   5.196 -    sg_element++;
   5.197 -    xi->tx.req_prod_pvt++;
   5.198 +    /* (C) - only if sg otherwise it was all sent on the first buffer */
   5.199 +    while (sg_element < sg->NumberOfElements)
   5.200 +    {
   5.201 +      //KdPrint((__DRIVER_NAME "     G - sg_element = %d, sg_offset = %d\n", sg_element, sg_offset));
   5.202 +      //KdPrint((__DRIVER_NAME "     H - address = %p, length = %d\n",
   5.203 +      //  sg->Elements[sg_element].Address.LowPart + sg_offset, sg->Elements[sg_element].Length - sg_offset));
   5.204 +      txN = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   5.205 +      chunks++;
   5.206 +      xi->tx_ring_free--;
   5.207 +      txN->id = 0xFFFF;
   5.208 +      txN->gref = (grant_ref_t)(sg->Elements[sg_element].Address.QuadPart >> PAGE_SHIFT);
   5.209 +      ASSERT((sg->Elements[sg_element].Address.LowPart & (PAGE_SIZE - 1)) + sg_offset <= PAGE_SIZE);
   5.210 +      txN->offset = (USHORT)(sg->Elements[sg_element].Address.LowPart + sg_offset) & (PAGE_SIZE - 1);
   5.211 +      ASSERT(sg->Elements[sg_element].Length > sg_offset);
   5.212 +      txN->size = (USHORT)(sg->Elements[sg_element].Length - sg_offset);
   5.213 +      ASSERT(txN->offset + txN->size <= PAGE_SIZE);
   5.214 +      ASSERT(txN->size);
   5.215 +      tx0->size = tx0->size + txN->size;
   5.216 +      txN->flags = NETTXF_more_data;
   5.217 +      sg_offset = 0;
   5.218 +      sg_element++;
   5.219 +      xi->tx.req_prod_pvt++;
   5.220 +    }
   5.221    }
   5.222    txN->flags &= ~NETTXF_more_data;
   5.223    txN->id = get_id_from_freelist(xi);
   5.224  //KdPrint((__DRIVER_NAME "     send - id = %d\n", tx0->id));
   5.225 -  //KdPrint((__DRIVER_NAME "     TX: id = %d, cb = %p, xi->tx_shadows[txN->id].cb = %p\n", txN->id, header_buf, xi->tx_shadows[txN->id].cb));
   5.226 +  //KdPrint((__DRIVER_NAME "     TX: id = %d, cb = %p, xi->tx_shadows[txN->id].cb = %p\n", txN->id, coalesce_buf, xi->tx_shadows[txN->id].cb));
   5.227    ASSERT(tx0->size == pi.total_length);
   5.228    ASSERT(!xi->tx_shadows[txN->id].cb);
   5.229    ASSERT(!xi->tx_shadows[txN->id].packet);
   5.230    xi->tx_shadows[txN->id].packet = packet;
   5.231 -  xi->tx_shadows[txN->id].cb = header_buf;
   5.232 +  xi->tx_shadows[txN->id].cb = coalesce_buf;
   5.233  
   5.234    if (ndis_lso)
   5.235    {
   5.236 @@ -528,6 +547,50 @@ XenNet_SendPackets(
   5.237  }
   5.238  
   5.239  VOID
   5.240 +XenNet_CancelSendPackets(
   5.241 +  NDIS_HANDLE MiniportAdapterContext,
   5.242 +  PVOID CancelId)
   5.243 +{
   5.244 +  struct xennet_info *xi = MiniportAdapterContext;
   5.245 +  KIRQL old_irql;
   5.246 +  PLIST_ENTRY entry;
   5.247 +  PNDIS_PACKET packet;
   5.248 +  PNDIS_PACKET head = NULL, tail = NULL;
   5.249 +
   5.250 +  FUNCTION_ENTER();
   5.251 +
   5.252 +  KeAcquireSpinLock(&xi->tx_lock, &old_irql);
   5.253 +
   5.254 +  entry = xi->tx_waiting_pkt_list.Flink;
   5.255 +  while (entry != &xi->tx_waiting_pkt_list)
   5.256 +  {
   5.257 +    packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
   5.258 +    entry = entry->Flink;
   5.259 +    if (NDIS_GET_PACKET_CANCEL_ID(packet) == CancelId)
   5.260 +    {
   5.261 +      RemoveEntryList((PLIST_ENTRY)&packet->MiniportReservedEx[sizeof(PVOID)]);
   5.262 +      *(PNDIS_PACKET *)&packet->MiniportReservedEx[0] = NULL;
   5.263 +      if (head)
   5.264 +        *(PNDIS_PACKET *)&tail->MiniportReservedEx[0] = packet;
   5.265 +      else
   5.266 +        head = packet;
   5.267 +      tail = packet;
   5.268 +    }
   5.269 +  }
   5.270 +
   5.271 +  KeReleaseSpinLock(&xi->tx_lock, old_irql);
   5.272 +
   5.273 +  while (head)
   5.274 +  {
   5.275 +    packet = (PNDIS_PACKET)head;
   5.276 +    head = *(PNDIS_PACKET *)&packet->MiniportReservedEx[0];
   5.277 +    NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_REQUEST_ABORTED);
   5.278 +  }
   5.279 +  
   5.280 +  FUNCTION_EXIT();
   5.281 +}
   5.282 +
   5.283 +VOID
   5.284  XenNet_TxResumeStart(xennet_info_t *xi)
   5.285  {
   5.286    UNREFERENCED_PARAMETER(xi);
   5.287 @@ -555,6 +618,7 @@ BOOLEAN
   5.288  XenNet_TxInit(xennet_info_t *xi)
   5.289  {
   5.290    USHORT i, j;
   5.291 +  ULONG cb_size;
   5.292  
   5.293    KeInitializeSpinLock(&xi->tx_lock);
   5.294    KeInitializeDpc(&xi->tx_dpc, XenNet_TxBufferGC, xi);
   5.295 @@ -566,21 +630,29 @@ XenNet_TxInit(xennet_info_t *xi)
   5.296    KeInitializeEvent(&xi->tx_idle_event, SynchronizationEvent, FALSE);
   5.297    xi->tx_outstanding = 0;
   5.298    xi->tx_ring_free = NET_TX_RING_SIZE;
   5.299 +  
   5.300 +  if (xi->config_sg)
   5.301 +  {
   5.302 +    cb_size = TX_HEADER_BUFFER_SIZE;
   5.303 +  }
   5.304 +  else
   5.305 +  {
   5.306 +    cb_size = PAGE_SIZE;
   5.307 +  }
   5.308  
   5.309 -  for (i = 0; i < TX_COALESCE_BUFFERS / (PAGE_SIZE / TX_HEADER_BUFFER_SIZE); i++)
   5.310 +  for (i = 0; i < TX_COALESCE_BUFFERS / (PAGE_SIZE / cb_size); i++)
   5.311    {
   5.312      PVOID virtual;
   5.313      NDIS_PHYSICAL_ADDRESS logical;
   5.314      NdisMAllocateSharedMemory(xi->adapter_handle, PAGE_SIZE, TRUE, &virtual, &logical);
   5.315      if (virtual == NULL)
   5.316 -      continue;
   5.317 -    //KdPrint((__DRIVER_NAME "     Allocated SharedMemory at %p\n", virtual));
   5.318 -    for (j = 0; j < PAGE_SIZE / TX_HEADER_BUFFER_SIZE; j++)
   5.319 +      break;
   5.320 +    for (j = 0; j < PAGE_SIZE / cb_size; j++)
   5.321      {
   5.322 -      USHORT index = i * (PAGE_SIZE / TX_HEADER_BUFFER_SIZE) + j;
   5.323 +      USHORT index = (USHORT)(i * (PAGE_SIZE / cb_size) + j);
   5.324        xi->tx_cbs[index].id = index;
   5.325 -      xi->tx_cbs[index].virtual = (PUCHAR)virtual + j * TX_HEADER_BUFFER_SIZE;
   5.326 -      xi->tx_cbs[index].logical.QuadPart = logical.QuadPart + j * TX_HEADER_BUFFER_SIZE;
   5.327 +      xi->tx_cbs[index].virtual = (PUCHAR)virtual + j * cb_size;
   5.328 +      xi->tx_cbs[index].logical.QuadPart = logical.QuadPart + j * cb_size;
   5.329        put_cb_on_freelist(xi, &xi->tx_cbs[index]);
   5.330      }
   5.331    }