win-pvdrivers

changeset 30:bc0ea67acebb

xennet: Start implementing SendPackets
author Andy Grover <andy.grover@oracle.com>
date Mon Dec 03 23:04:07 2007 -0800 (2007-12-03)
parents e4f0a0a21488
children f56c47274c37
files xennet/xennet.c
line diff
     1.1 --- a/xennet/xennet.c	Fri Nov 30 11:45:00 2007 -0800
     1.2 +++ b/xennet/xennet.c	Mon Dec 03 23:04:07 2007 -0800
     1.3 @@ -26,10 +26,16 @@ Foundation, Inc., 51 Franklin Street, Fi
     1.4  #error requires NDIS 5.1 compilation environment
     1.5  #endif
     1.6  
     1.7 -#define GRANT_INVALID_REF	0
     1.8 +#define GRANT_INVALID_REF 0
     1.9  
    1.10 -#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
    1.11 -#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
    1.12 +/* couldn't get regular xen ring macros to work...*/
    1.13 +#define __NET_RING_SIZE(type, _sz) \
    1.14 +    (__RD32( \
    1.15 +    (_sz - sizeof(struct type##_sring) + sizeof(union type##_sring_entry)) \
    1.16 +    / sizeof(union type##_sring_entry)))
    1.17 +
    1.18 +#define NET_TX_RING_SIZE __NET_RING_SIZE(netif_tx, PAGE_SIZE)
    1.19 +#define NET_RX_RING_SIZE __NET_RING_SIZE(netif_rx, PAGE_SIZE)
    1.20  
    1.21  #pragma warning(disable: 4127)
    1.22  
    1.23 @@ -54,13 +60,27 @@ struct xennet_info
    1.24    XEN_IFACE_XEN XenInterface;
    1.25    XEN_IFACE_GNTTBL GntTblInterface;
    1.26  
    1.27 +  /* ring control structures */
    1.28    struct netif_tx_front_ring tx;
    1.29    struct netif_rx_front_ring rx;
    1.30  
    1.31 +  /* ptrs to the actual rings themselvves */
    1.32 +  struct netif_tx_sring *tx_pgs;
    1.33 +  struct netif_rx_sring *rx_pgs;
    1.34 +
    1.35 +  /* MDLs for the above */
    1.36    PMDL tx_mdl;
    1.37    PMDL rx_mdl;
    1.38 -  struct netif_tx_sring *tx_pgs;
    1.39 -  struct netif_rx_sring *rx_pgs;
    1.40 +
    1.41 +  /* Outstanding packets. The first entry in tx_pkts
    1.42 +   * is an index into a chain of free entries. */
    1.43 +  PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE];
    1.44 +  PNDIS_PACKET rx_pkts[NET_RX_RING_SIZE];
    1.45 +
    1.46 +  grant_ref_t gref_tx_head;
    1.47 +  grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
    1.48 +  grant_ref_t gref_rx_head;
    1.49 +  grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
    1.50  
    1.51    UINT irq;
    1.52    evtchn_port_t event_channel;
    1.53 @@ -107,6 +127,21 @@ simple_strtoul(const char *cp,char **end
    1.54    return result;
    1.55   }
    1.56  
    1.57 +static void
    1.58 +add_id_to_freelist(NDIS_PACKET **list, unsigned short id)
    1.59 +{
    1.60 +  list[id] = list[0];
    1.61 +  list[0]  = (void *)(unsigned long)id;
    1.62 +}
    1.63 +
    1.64 +static unsigned short
    1.65 +get_id_from_freelist(NDIS_PACKET **list)
    1.66 +{
    1.67 +  unsigned short id = (unsigned short)(unsigned long)list[0];
    1.68 +  list[0] = list[id];
    1.69 +  return id;
    1.70 +}
    1.71 +
    1.72  static PMDL
    1.73  AllocatePages(int Pages)
    1.74  {
    1.75 @@ -134,18 +169,85 @@ AllocatePage()
    1.76    return AllocatePages(1);
    1.77  }
    1.78  
    1.79 +static NDIS_STATUS
    1.80 +XenNet_TxBufGC(struct xennet_info *xi)
    1.81 +{
    1.82 +  RING_IDX cons, prod;
    1.83 +#if 0
    1.84 +  unsigned short id;
    1.85 +  struct sk_buff *skb;
    1.86 +
    1.87 +  BUG_ON(!netfront_carrier_ok(np));
    1.88 +
    1.89 +  do {
    1.90 +    prod = np->tx.sring->rsp_prod;
    1.91 +    rmb(); /* Ensure we see responses up to 'rp'. */
    1.92 +
    1.93 +    for (cons = np->tx.rsp_cons; cons != prod; cons++) {
    1.94 +      struct netif_tx_response *txrsp;
    1.95 +
    1.96 +      txrsp = RING_GET_RESPONSE(&np->tx, cons);
    1.97 +      if (txrsp->status == NETIF_RSP_NULL)
    1.98 +        continue;
    1.99 +
   1.100 +      id  = txrsp->id;
   1.101 +      skb = np->tx_skbs[id];
   1.102 +      if (unlikely(gnttab_query_foreign_access(
   1.103 +        np->grant_tx_ref[id]) != 0)) {
   1.104 +        printk(KERN_ALERT "network_tx_buf_gc: warning "
   1.105 +               "-- grant still in use by backend "
   1.106 +               "domain.\n");
   1.107 +        BUG();
   1.108 +      }
   1.109 +      gnttab_end_foreign_access_ref(
   1.110 +        np->grant_tx_ref[id], GNTMAP_readonly);
   1.111 +      gnttab_release_grant_reference(
   1.112 +        &np->gref_tx_head, np->grant_tx_ref[id]);
   1.113 +      np->grant_tx_ref[id] = GRANT_INVALID_REF;
   1.114 +      add_id_to_freelist(np->tx_skbs, id);
   1.115 +      dev_kfree_skb_irq(skb);
   1.116 +    }
   1.117 +
   1.118 +    np->tx.rsp_cons = prod;
   1.119 +
   1.120 +    /*
   1.121 +     * Set a new event, then check for race with update of tx_cons.
   1.122 +     * Note that it is essential to schedule a callback, no matter
   1.123 +     * how few buffers are pending. Even if there is space in the
   1.124 +     * transmit ring, higher layers may be blocked because too much
   1.125 +     * data is outstanding: in such cases notification from Xen is
   1.126 +     * likely to be the only kick that we'll get.
   1.127 +     */
   1.128 +    np->tx.sring->rsp_event =
   1.129 +      prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
   1.130 +    mb();
   1.131 +  } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
   1.132 +
   1.133 +  network_maybe_wake_tx(dev);
   1.134 +
   1.135 +
   1.136 +
   1.137 +#endif
   1.138 +
   1.139 +
   1.140 +  return NDIS_STATUS_SUCCESS;
   1.141 +}
   1.142 +
   1.143  static BOOLEAN
   1.144  XenNet_Interrupt(
   1.145    PKINTERRUPT Interrupt,
   1.146    PVOID ServiceContext
   1.147    )
   1.148  {
   1.149 -  // struct xennet_info *xennet_info = ServiceContext;
   1.150 +  struct xennet_info *xi = ServiceContext;
   1.151    // KIRQL KIrql;
   1.152  
   1.153    UNREFERENCED_PARAMETER(Interrupt);
   1.154 -  UNREFERENCED_PARAMETER(ServiceContext);
   1.155  
   1.156 +  if (xi->connected)
   1.157 +  {
   1.158 +    XenNet_TxBufGC(xi);
   1.159 +  }
   1.160    // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
   1.161    // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
   1.162    // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
   1.163 @@ -380,6 +482,17 @@ XenNet_Init(
   1.164    NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
   1.165      &xi->lower_do, NULL, NULL);
   1.166  
   1.167 +  /* Initialise {tx,rx}_pkts as a free chain containing every entry. */
   1.168 +  for (i = 0; i <= NET_TX_RING_SIZE; i++) {
   1.169 +    xi->tx_pkts[i] = (void *)((unsigned long) i+1);
   1.170 +    xi->grant_tx_ref[i] = GRANT_INVALID_REF;
   1.171 +  }
   1.172 +
   1.173 +  for (i = 0; i < NET_RX_RING_SIZE; i++) {
   1.174 +    xi->rx_pkts[i] = NULL;
   1.175 +    xi->grant_rx_ref[i] = GRANT_INVALID_REF;
   1.176 +  }
   1.177 +
   1.178    status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
   1.179      NAME_SIZE, xi->name, &length);
   1.180    if (!NT_SUCCESS(status))
   1.181 @@ -402,7 +515,10 @@ XenNet_Init(
   1.182      status = NDIS_STATUS_FAILURE;
   1.183      goto err;
   1.184    }
   1.185 -  
   1.186 +
   1.187 +  /* TODO: NdisMInitializeScatterGatherDma? */
   1.188 +  // NDIS_PER_PACKET_INFO_FROM_PACKET(ndis_packet, ScatterGatherListPacketInfo)
   1.189 +
   1.190    GetWdfDeviceInfo(xi->wdf_device)->xennet_info = xi;
   1.191  
   1.192    /* get lower (Xen) interfaces */
   1.193 @@ -740,17 +856,47 @@ XenNet_SendPackets(
   1.194      */
   1.195    struct xennet_info *xi = MiniportAdapterContext;
   1.196    PNDIS_PACKET curr_packet;
   1.197 +  PNDIS_BUFFER curr_buff;
   1.198 +  PVOID curr_buff_vaddr;
   1.199 +  UINT curr_buff_len;
   1.200 +  UINT tot_buff_len;
   1.201    UINT i;
   1.202 -  UINT table_entry;
   1.203 +  struct netif_tx_request *tx;
   1.204 +  unsigned short id;
   1.205 +  grant_ref_t ref;
   1.206  
   1.207 -  KdPrint((__FUNCTION__ " called\n"));
   1.208 +  KdPrint((__FUNCTION__ " called, sending %d pkts\n", NumberOfPackets));
   1.209  
   1.210    for (i = 0; i < NumberOfPackets; i++)
   1.211    {
   1.212      curr_packet = PacketArray[i];
   1.213      ASSERT(curr_packet);
   1.214  
   1.215 -    table_entry = xi->tx.req_prod_pvt;
   1.216 +    NdisGetFirstBufferFromPacketSafe(curr_packet, &curr_buff, &curr_buff_vaddr,
   1.217 +      &curr_buff_len, &tot_buff_len, NormalPagePriority);
   1.218 +
   1.219 +    while (curr_buff)
   1.220 +    {
   1.221 +      NdisQueryBufferSafe(curr_buff, &curr_buff_vaddr, &curr_buff_len,
   1.222 +        NormalPagePriority);
   1.223 +
   1.224 +      id = get_id_from_freelist(xi->tx_pkts);
   1.225 +      xi->tx_pkts[id] = curr_packet;
   1.226 +
   1.227 +      // TODO: get pfn/offset for buffer
   1.228 +      // buffers attached to packets with NdisChainBufferAtBack
   1.229 +
   1.230 +      tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
   1.231 +      tx->id = id;
   1.232 +      tx->gref = xi->GntTblInterface.GrantAccess(
   1.233 +        xi->GntTblInterface.InterfaceHeader.Context,
   1.234 +        0,
   1.235 +        0, //FIXME
   1.236 +        FALSE);
   1.237 +
   1.238 +
   1.239 +      NdisGetNextBuffer(curr_buff, &curr_buff);
   1.240 +    }
   1.241    }
   1.242  
   1.243  }