win-pvdrivers

changeset 108:fb19fc778b9d

xennet: add support for queueing packets to send if tx ring is full.
author Andy Grover <andy.grover@oracle.com>
date Thu Jan 10 20:45:16 2008 -0800 (2008-01-10)
parents 1937a3bf6f64
children f45e6538a5e2
files xennet/xennet.c
line diff
     1.1 --- a/xennet/xennet.c	Thu Jan 10 10:59:49 2008 -0800
     1.2 +++ b/xennet/xennet.c	Thu Jan 10 20:45:16 2008 -0800
     1.3 @@ -74,6 +74,7 @@ struct xennet_info
     1.4    KSPIN_LOCK rx_lock;
     1.5    KSPIN_LOCK tx_lock;
     1.6  
     1.7 +  LIST_ENTRY tx_waiting_pkt_list;
     1.8    LIST_ENTRY rx_free_pkt_list;
     1.9  
    1.10    struct netif_tx_front_ring tx;
    1.11 @@ -91,6 +92,7 @@ struct xennet_info
    1.12  
    1.13    /* Outstanding packets. The first entry in tx_pkts
    1.14     * is an index into a chain of free entries. */
    1.15 +  int tx_pkt_ids_used;
    1.16    PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE+1];
    1.17    PNDIS_PACKET rx_pkts[NET_RX_RING_SIZE];
    1.18  
    1.19 @@ -146,20 +148,27 @@ simple_strtoul(const char *cp,char **end
    1.20   }
    1.21  
    1.22  static void
    1.23 -add_id_to_freelist(NDIS_PACKET **list, unsigned short id)
    1.24 +add_id_to_freelist(struct xennet_info *xi, unsigned short id)
    1.25  {
    1.26 -  list[id] = list[0];
    1.27 -  list[0]  = (void *)(unsigned long)id;
    1.28 +  xi->tx_pkts[id] = xi->tx_pkts[0];
    1.29 +  xi->tx_pkts[0]  = (void *)(unsigned long)id;
    1.30 +  xi->tx_pkt_ids_used--;
    1.31  }
    1.32  
    1.33  static unsigned short
    1.34 -get_id_from_freelist(NDIS_PACKET **list)
    1.35 +get_id_from_freelist(struct xennet_info *xi)
    1.36  {
    1.37 -  unsigned short id = (unsigned short)(unsigned long)list[0];
    1.38 -  list[0] = list[id];
    1.39 +  unsigned short id;
    1.40 +  if (xi->tx_pkt_ids_used >= NET_TX_RING_SIZE)
    1.41 +    return 0;
    1.42 +  id = (unsigned short)(unsigned long)xi->tx_pkts[0];
    1.43 +  xi->tx_pkts[0] = xi->tx_pkts[id];
    1.44 +  xi->tx_pkt_ids_used++;
    1.45    return id;
    1.46  }
    1.47  
    1.48 +VOID XenNet_SendQueuedPackets(struct xennet_info *xi);
    1.49 +
    1.50  // Called at DISPATCH_LEVEL
    1.51  static NDIS_STATUS
    1.52  XenNet_TxBufferGC(struct xennet_info *xi)
    1.53 @@ -192,7 +201,7 @@ XenNet_TxBufferGC(struct xennet_info *xi
    1.54        xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
    1.55          xi->grant_tx_ref[id]);
    1.56        xi->grant_tx_ref[id] = GRANT_INVALID_REF;
    1.57 -      add_id_to_freelist(xi->tx_pkts, id);
    1.58 +      add_id_to_freelist(xi, id);
    1.59  
    1.60        /* free linearized data page */
    1.61        pmdl = *(PMDL *)pkt->MiniportReservedEx;
    1.62 @@ -218,10 +227,10 @@ XenNet_TxBufferGC(struct xennet_info *xi
    1.63      KeMemoryBarrier();
    1.64    } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
    1.65  
    1.66 -  /* if queued packets, send them now?
    1.67 -  network_maybe_wake_tx(dev); */
    1.68 +  KeReleaseSpinLock(&xi->tx_lock, OldIrql);
    1.69  
    1.70 -  KeReleaseSpinLock(&xi->tx_lock, OldIrql);
    1.71 +  /* if queued packets, send them now */
    1.72 +  XenNet_SendQueuedPackets(xi);
    1.73  
    1.74  //  KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
    1.75  
    1.76 @@ -245,7 +254,7 @@ static void XenNet_TxBufferFree(struct x
    1.77      xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
    1.78        xi->grant_tx_ref[id]);
    1.79      xi->grant_tx_ref[id] = GRANT_INVALID_REF;
    1.80 -    add_id_to_freelist(xi->tx_pkts, id);
    1.81 +    add_id_to_freelist(xi, id);
    1.82  
    1.83      /* free linearized data page */
    1.84      pmdl = *(PMDL *)packet->MiniportReservedEx;
    1.85 @@ -702,7 +711,9 @@ XenNet_Init(
    1.86  
    1.87    KeInitializeSpinLock(&xi->tx_lock);
    1.88    KeInitializeSpinLock(&xi->rx_lock);
    1.89 -  NdisInitializeListHead(&xi->rx_free_pkt_list);
    1.90 +  InitializeListHead(&xi->rx_free_pkt_list);
    1.91 +  InitializeListHead(&xi->tx_waiting_pkt_list);
    1.92 +  
    1.93  
    1.94    NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
    1.95      PROTOCOL_RESERVED_SIZE_IN_PACKET);
    1.96 @@ -1430,48 +1441,36 @@ XenNet_Linearize(PNDIS_PACKET Packet)
    1.97  }
    1.98  
    1.99  VOID
   1.100 -XenNet_SendPackets(
   1.101 -  IN NDIS_HANDLE MiniportAdapterContext,
   1.102 -  IN PPNDIS_PACKET PacketArray,
   1.103 -  IN UINT NumberOfPackets
   1.104 -  )
   1.105 +XenNet_SendQueuedPackets(struct xennet_info *xi)
   1.106  {
   1.107 -  struct xennet_info *xi = MiniportAdapterContext;
   1.108 -  PNDIS_PACKET curr_packet;
   1.109 -  UINT i;
   1.110 +  PLIST_ENTRY entry;
   1.111 +  PNDIS_PACKET packet;
   1.112 +  KIRQL OldIrql;
   1.113    struct netif_tx_request *tx;
   1.114    unsigned short id;
   1.115    int notify;
   1.116    PMDL pmdl;
   1.117    UINT pkt_size;
   1.118 -  KIRQL OldIrql;
   1.119 -
   1.120 -//  KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
   1.121  
   1.122    KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
   1.123  
   1.124 -  for (i = 0; i < NumberOfPackets; i++)
   1.125 +  entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
   1.126 +  /* if empty, the above returns head*, not NULL */
   1.127 +  while (entry != &xi->tx_waiting_pkt_list)
   1.128    {
   1.129 -    curr_packet = PacketArray[i];
   1.130 -    ASSERT(curr_packet);
   1.131 -
   1.132 -    NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
   1.133 +    packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[4]);
   1.134  
   1.135 -    //KdPrint(("sending pkt, len %d\n", pkt_size));
   1.136 -
   1.137 -    /* TODO: check if freelist is full */
   1.138 +    NdisQueryPacket(packet, NULL, NULL, NULL, &pkt_size);
   1.139 +    pmdl = *(PMDL *)packet->MiniportReservedEx;
   1.140  
   1.141 -    pmdl = XenNet_Linearize(curr_packet);
   1.142 -    if (!pmdl)
   1.143 +    id = get_id_from_freelist(xi);
   1.144 +    if (!id)
   1.145      {
   1.146 -      KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
   1.147 -      NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
   1.148 +      /* whups, out of space on the ring. requeue and get out */
   1.149 +      InsertHeadList(&xi->tx_waiting_pkt_list, entry);
   1.150        break;
   1.151      }
   1.152 -    *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
   1.153 -
   1.154 -    id = get_id_from_freelist(xi->tx_pkts);
   1.155 -    xi->tx_pkts[id] = curr_packet;
   1.156 +    xi->tx_pkts[id] = packet;
   1.157  
   1.158      tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   1.159      tx->id = id;
   1.160 @@ -1488,18 +1487,61 @@ XenNet_SendPackets(
   1.161  
   1.162      xi->tx.req_prod_pvt++;
   1.163  
   1.164 -    // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
   1.165 -    // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
   1.166 +    entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
   1.167    }
   1.168  
   1.169 +  KeReleaseSpinLock(&xi->tx_lock, OldIrql);
   1.170 +
   1.171    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
   1.172    if (notify)
   1.173    {
   1.174      xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
   1.175        xi->event_channel);
   1.176    }
   1.177 +}
   1.178  
   1.179 -  KeReleaseSpinLock(&xi->tx_lock, OldIrql);
   1.180 +VOID
   1.181 +XenNet_SendPackets(
   1.182 +  IN NDIS_HANDLE MiniportAdapterContext,
   1.183 +  IN PPNDIS_PACKET PacketArray,
   1.184 +  IN UINT NumberOfPackets
   1.185 +  )
   1.186 +{
   1.187 +  struct xennet_info *xi = MiniportAdapterContext;
   1.188 +  PNDIS_PACKET curr_packet;
   1.189 +  UINT i;
   1.190 +  PMDL pmdl;
   1.191 +  PLIST_ENTRY entry;
   1.192 +
   1.193 +//  KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
   1.194 +
   1.195 +  for (i = 0; i < NumberOfPackets; i++)
   1.196 +  {
   1.197 +    curr_packet = PacketArray[i];
   1.198 +    ASSERT(curr_packet);
   1.199 +
   1.200 +    //KdPrint(("sending pkt, len %d\n", pkt_size));
   1.201 +
   1.202 +    pmdl = XenNet_Linearize(curr_packet);
   1.203 +    if (!pmdl)
   1.204 +    {
   1.205 +      KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
   1.206 +      NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
   1.207 +      break;
   1.208 +    }
   1.209 +
   1.210 +    /* NOTE: 
   1.211 +     * We use the UCHAR[12] array in each packet's MiniportReservedEx thusly:
   1.212 +     * 0-3: PMDL to linearized data
   1.213 +     * 4-11: LIST_ENTRY for placing packet on the waiting pkt list
   1.214 +     */
   1.215 +    *(PMDL *)&curr_packet->MiniportReservedEx = pmdl;
   1.216 +
   1.217 +    entry = (PLIST_ENTRY)&curr_packet->MiniportReservedEx[4];
   1.218 +    ExInterlockedInsertTailList(&xi->tx_waiting_pkt_list, entry, &xi->tx_lock);
   1.219 +  }
   1.220 +
   1.221 +  XenNet_SendQueuedPackets(xi);
   1.222  
   1.223  //  KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
   1.224  }