LAN9221网卡驱动之二 NAPI接收

转载请注明出处:http://blog.csdn.net/qq405180763/article/details/8800391

LAN9221采用NAPI方式读取网卡缓存内数据。当接主机收大量网络数据时,网卡中断触发驱动程序接收数据,驱动程序被触发后调用轮询函数,在轮询函数里接收固定个数据包后,固定个数据为budget,一般是轮询注册函数netif_napi_add的第三个参数weight,如果数据还没接收完毕,则中断再次被触发(中断标志位没有被清除),继续轮询接收数据,知道数据被完全接收完毕,则在轮询函数里将中断标志位清楚,关闭轮询函数,重新使能中断接收下一组数据。NAPI的好处就是既避免了在接收大量数据时频繁的中断,又不必因为轮询而耗费大量CPU资源,结合了中断和轮询的优点。

static int smsc911x_poll(struct napi_struct *napi, int budget)
{
 struct smsc911x_data *pdata =
  container_of(napi, struct smsc911x_data, napi);
 struct net_device *dev = pdata->dev;
 int npackets = 0;

 while (npackets < budget) { /*不管数据是否接收完毕,每个中断最多轮询budget=16次,
                                          因为中断被清零,如果还有数据则会再次触发中断*/
  unsigned int pktlength;
  unsigned int pktwords;
  struct sk_buff *skb;
  unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata);

  if (!rxstat) {
   unsigned int temp;
   /* We processed all packets available.  Tell NAPI it can
    * stop polling then re-enable rx interrupts */
   smsc911x_reg_write(pdata, INT_STS, INT_STS_RSFL_); /*清数据接收中断*/
   napi_complete(napi);
   temp = smsc911x_reg_read(pdata, INT_EN);
   temp |= INT_EN_RSFL_EN_;
   smsc911x_reg_write(pdata, INT_EN, temp); /*数据接收完,关闭轮询,从新使能数据接收中断*/
   break;
  }

  /* Count packet for NAPI scheduling, even if it has an error.
   * Error packets still require cycles to discard */
  npackets++;

  pktlength = ((rxstat & 0x3FFF0000) >> 16);
  pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2; /*获取数据包长度,并计算按字读取的长度*/
  smsc911x_rx_counterrors(dev, rxstat);

  if (unlikely(rxstat & RX_STS_ES_)) {
   SMSC_WARNING(RX_ERR,
    "Discarding packet with error bit set");
   /* Packet has an error, discard it and continue with
    * the next */
   smsc911x_rx_fastforward(pdata, pktwords);
   dev->stats.rx_dropped++;
   continue;
  }

  skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN);  /*mac头是14个字节,而紧接着的IP头要求14字节对齐,所以多申请两个字节,保证IP16字节对齐*/
  if (unlikely(!skb)) {
   SMSC_WARNING(RX_ERR,
    "Unable to allocate skb for rx packet");
   /* Drop the packet and stop this polling iteration */
   smsc911x_rx_fastforward(pdata, pktwords);
   dev->stats.rx_dropped++;
   break;
  }

  skb->data = skb->head; /*空头*/ 
  skb_reset_tail_pointer(skb); /*空数据*/ 

  /* Align IP on 16B boundary */
  skb_reserve(skb, NET_IP_ALIGN); /*调节data的位置,使IP按16字节对齐*/
  skb_put(skb, pktlength - 4); /*将tail指针往后拉,接着就把数据拷贝到skb缓存中*/
  smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head, pktwords);/*强制转换成unsigned int,每加一次跳四个字节*/
  skb->protocol = eth_type_trans(skb, dev); /*使skb->mac_header指向mac协议头,
                                                        skb->data后移14字节,剥离mac头*/
  skb->ip_summed = CHECKSUM_NONE;
  netif_receive_skb(skb); /*将skb发往上一层*/

  /* Update counters */
  dev->stats.rx_packets++;
  dev->stats.rx_bytes += (pktlength - 4);
 }

 /* Return total received packets */
 return npackets;
}

发布了26 篇原创文章 · 获赞 21 · 访问量 20万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章