win-pvdrivers

changeset 43:59691f2a99f6

xennet: rough-in RX support (compiles, not debugged)
author Andy Grover <andy.grover@oracle.com>
date Wed Dec 12 16:58:09 2007 -0800 (2007-12-12)
parents 5dc3e004cf94
children 01f874217465
files xennet/xennet.c
line diff
     1.1 --- a/xennet/xennet.c	Wed Dec 05 14:56:01 2007 -0800
     1.2 +++ b/xennet/xennet.c	Wed Dec 12 16:58:09 2007 -0800
     1.3 @@ -90,6 +90,17 @@ struct xennet_info
     1.4  
     1.5    grant_ref_t tx_ring_ref;
     1.6    grant_ref_t rx_ring_ref;
     1.7 +
     1.8 +	/* Receive-ring batched refills. */
     1.9 +#define RX_MIN_TARGET 8
    1.10 +#define RX_DFL_MIN_TARGET 64
    1.11 +#define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
    1.12 +  ULONG rx_target;
    1.13 +  ULONG rx_max_target;
    1.14 +  ULONG rx_min_target;
    1.15 +
    1.16 +  NDIS_HANDLE packet_pool;
    1.17 +  NDIS_HANDLE buffer_pool;
    1.18  };
    1.19  
    1.20  /* need to do typedef so the DECLARE below works */
    1.21 @@ -173,7 +184,7 @@ AllocatePage()
    1.22  }
    1.23  
    1.24  static NDIS_STATUS
    1.25 -XenNet_TxBufGC(struct xennet_info *xi)
    1.26 +XenNet_TxBufferGC(struct xennet_info *xi)
    1.27  {
    1.28    RING_IDX cons, prod;
    1.29  
    1.30 @@ -201,7 +212,7 @@ XenNet_TxBufGC(struct xennet_info *xi)
    1.31        xi->grant_tx_ref[id] = GRANT_INVALID_REF;
    1.32        add_id_to_freelist(xi->tx_pkts, id);
    1.33  
    1.34 -      /* free page for linearized data */
    1.35 +      /* free linearized data page */
    1.36        pmdl = *(PMDL *)pkt->MiniportReservedEx;
    1.37        MmFreePagesFromMdl(pmdl);
    1.38        IoFreeMdl(pmdl);
    1.39 @@ -230,6 +241,140 @@ XenNet_TxBufGC(struct xennet_info *xi)
    1.40    return NDIS_STATUS_SUCCESS;
    1.41  }
    1.42  
    1.43 +static NDIS_STATUS
    1.44 +XenNet_AllocRXBuffers(struct xennet_info *xi)
    1.45 +{
    1.46 +  unsigned short id;
    1.47 +  PNDIS_PACKET packet;
    1.48 +  PNDIS_BUFFER buffer;
    1.49 +  int i, batch_target, notify;
    1.50 +  RING_IDX req_prod = xi->rx.req_prod_pvt;
    1.51 +  grant_ref_t ref;
    1.52 +  netif_rx_request_t *req;
    1.53 +  NDIS_STATUS status;
    1.54 +  PMDL pmdl;
    1.55 +  PVOID start;
    1.56 +
    1.57 +  if (!xi->connected)
    1.58 +    return NDIS_STATUS_FAILURE;
    1.59 +
    1.60 +  batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
    1.61 +  for (i = 0; i < batch_target; i++)
    1.62 +  {
    1.63 +    /*
    1.64 +     * Allocate a packet, page, and buffer. Hook them up.
    1.65 +     */
    1.66 +    NdisAllocatePacket(&status, &packet, xi->packet_pool);
    1.67 +    if (status != NDIS_STATUS_SUCCESS)
    1.68 +    {
    1.69 +      KdPrint(("NdisAllocatePacket Failed! status = 0x%x\n", status));
    1.70 +      break;
    1.71 +    }
    1.72 +    pmdl = AllocatePage();
    1.73 +    start = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
    1.74 +    NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
    1.75 +    if (status != NDIS_STATUS_SUCCESS)
    1.76 +    {
    1.77 +      KdPrint(("NdisAllocateBuffer Failed! status = 0x%x\n", status));
    1.78 +      /* TODO: free mdl, page, packet here */
    1.79 +      break;
    1.80 +    }
    1.81 +    NdisChainBufferAtBack(packet, buffer);
    1.82 +
    1.83 +    /* Give to netback */
    1.84 +    id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
    1.85 +    ASSERT(!xi->rx_pkts[id]);
    1.86 +    xi->rx_pkts[id] = packet;
    1.87 +    req = RING_GET_REQUEST(&xi->rx, req_prod + i);
    1.88 +    ref = xi->GntTblInterface.GrantAccess(
    1.89 +      xi->GntTblInterface.InterfaceHeader.Context, 0,
    1.90 +      *MmGetMdlPfnArray(pmdl), FALSE);
    1.91 +    ASSERT((signed short)ref >= 0);
    1.92 +    xi->grant_rx_ref[id] = ref;
    1.93 +
    1.94 +    req->id = id;
    1.95 +    req->gref = ref;
    1.96 +  }
    1.97 +
    1.98 +  xi->rx.req_prod_pvt = req_prod + i;
    1.99 +  RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
   1.100 +  if (notify)
   1.101 +  {
   1.102 +    xi->EvtChnInterface.Notify(xi->EvtChnInterface.InterfaceHeader.Context,
   1.103 +      xi->event_channel);
   1.104 +  }
   1.105 +
   1.106 +  return NDIS_STATUS_SUCCESS;
   1.107 +}
   1.108 +
   1.109 +static NDIS_STATUS
   1.110 +XenNet_RxBufferCheck(struct xennet_info *xi)
   1.111 +{
   1.112 +  RING_IDX cons, prod;
   1.113 +
   1.114 +  unsigned short id;
   1.115 +  PNDIS_PACKET pkt;
   1.116 +  PNDIS_PACKET packets[1];
   1.117 +  PNDIS_BUFFER buffer;
   1.118 +  PVOID buff_va;
   1.119 +  UINT buff_len;
   1.120 +  UINT tot_buff_len;
   1.121 +
   1.122 +  ASSERT(xi->connected);
   1.123 +
   1.124 +  do {
   1.125 +    prod = xi->rx.sring->rsp_prod;
   1.126 +    KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
   1.127 +
   1.128 +    for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
   1.129 +      struct netif_rx_response *rxrsp;
   1.130 +
   1.131 +      rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
   1.132 +      if (rxrsp->status == NETIF_RSP_NULL)
   1.133 +        continue;
   1.134 +
   1.135 +      id  = rxrsp->id;
   1.136 +      pkt = xi->rx_pkts[id];
   1.137 +      xi->GntTblInterface.EndAccess(xi->GntTblInterface.InterfaceHeader.Context,
   1.138 +        xi->grant_rx_ref[id]);
   1.139 +      xi->grant_rx_ref[id] = GRANT_INVALID_REF;
   1.140 +      //add_id_to_freelist(xi->rx_pkts, id);
   1.141 +
   1.142 +      NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
   1.143 +        &tot_buff_len, NormalPagePriority);
   1.144 +      ASSERT(rxrsp->offset == 0);
   1.145 +      ASSERT(rxrsp->status > 0);
   1.146 +      NdisAdjustBufferLength(buffer, rxrsp->status);
   1.147 +      /* just indicate 1 packet for now */
   1.148 +      packets[0] = pkt;
   1.149 +
   1.150 +      NdisMIndicateReceivePacket(xi->adapter_handle, packets, 1);
   1.151 +    }
   1.152 +
   1.153 +    xi->rx.rsp_cons = prod;
   1.154 +
   1.155 +    /*
   1.156 +     * Set a new event, then check for race with update of rx_cons.
   1.157 +     * Note that it is essential to schedule a callback, no matter
   1.158 +     * how few buffers are pending. Even if there is space in the
   1.159 +     * transmit ring, higher layers may be blocked because too much
   1.160 +     * data is outstanding: in such cases notification from Xen is
   1.161 +     * likely to be the only kick that we'll get.
   1.162 +     */
   1.163 +    xi->rx.sring->rsp_event =
   1.164 +      prod + ((xi->rx.sring->req_prod - prod) >> 1) + 1;
   1.165 +    mb();
   1.166 +  } while ((cons == prod) && (prod != xi->rx.sring->rsp_prod));
   1.167 +
   1.168 +  /* if queued packets, send them now?
   1.169 +  network_maybe_wake_tx(dev); */
   1.170 +
   1.171 +  /* Give netback more buffers */
   1.172 +  XenNet_AllocRXBuffers(xi);
   1.173 +
   1.174 +  return NDIS_STATUS_SUCCESS;
   1.175 +}
   1.176 +
   1.177  static BOOLEAN
   1.178  XenNet_Interrupt(
   1.179    PKINTERRUPT Interrupt,
   1.180 @@ -245,7 +390,8 @@ XenNet_Interrupt(
   1.181  
   1.182    if (xi->connected)
   1.183    {
   1.184 -    XenNet_TxBufGC(xi);
   1.185 +    XenNet_TxBufferGC(xi);
   1.186 +    XenNet_RxBufferCheck(xi);
   1.187    }
   1.188    // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
   1.189    // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
   1.190 @@ -354,6 +500,7 @@ XenNet_BackEndStateHandler(char *Path, P
   1.191        xbt, 0, &retry);
   1.192  
   1.193      /* TODO: prepare tx and rx rings */
   1.194 +    XenNet_AllocRXBuffers(xi);
   1.195  
   1.196      KdPrint((__DRIVER_NAME "     Set Frontend state to Connected\n"));
   1.197      RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
   1.198 @@ -401,7 +548,6 @@ trouble:
   1.199  
   1.200  }
   1.201  
   1.202 -
   1.203  VOID
   1.204  XenNet_Halt(
   1.205    IN NDIS_HANDLE MiniportAdapterContext
   1.206 @@ -462,6 +608,27 @@ XenNet_Init(
   1.207  
   1.208    /* init xennet_info */
   1.209    xi->adapter_handle = MiniportAdapterHandle;
   1.210 +  xi->rx_target     = RX_DFL_MIN_TARGET;
   1.211 +  xi->rx_min_target = RX_DFL_MIN_TARGET;
   1.212 +  xi->rx_max_target = RX_MAX_TARGET;
   1.213 +
   1.214 +  NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
   1.215 +    PROTOCOL_RESERVED_SIZE_IN_PACKET);
   1.216 +  if (status != NDIS_STATUS_SUCCESS)
   1.217 +  {
   1.218 +    KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
   1.219 +    status = NDIS_STATUS_RESOURCES;
   1.220 +    goto err;
   1.221 +  }
   1.222 +
   1.223 +  NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
   1.224 +  if (status != NDIS_STATUS_SUCCESS)
   1.225 +  {
   1.226 +    KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
   1.227 +    status = NDIS_STATUS_RESOURCES;
   1.228 +    goto err;
   1.229 +  }
   1.230 +
   1.231    NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
   1.232      &xi->lower_do, NULL, NULL);
   1.233  
   1.234 @@ -818,8 +985,13 @@ XenNet_ReturnPacket(
   1.235    IN PNDIS_PACKET Packet
   1.236    )
   1.237  {
   1.238 -  UNREFERENCED_PARAMETER(MiniportAdapterContext);
   1.239 +  struct xennet_info *xi = MiniportAdapterContext;
   1.240 +
   1.241 +  xi;
   1.242    UNREFERENCED_PARAMETER(Packet);
   1.243 +  /* free memory page */
   1.244 +  /* free buffer */
   1.245 +  /* free packet */
   1.246  
   1.247    KdPrint((__FUNCTION__ " called\n"));
   1.248  }