天天看点

linux phy napi

概述:

       NAPI是linux新的网卡数据处理API,据说是由于找不到更好的名字,所以就叫NAPI(New API),在2.5之后引入。简单来说,NAPI是综合中断方式与轮询方式的技术。中断的好处是响应及时,如果数据量较小,则不会占用太多的CPU事件;缺点是数据量大时,会产生过多中断,而每个中断都要消耗不少的CPU时间,从而导致效率反而不如轮询高。轮询方式与中断方式相反,它更适合处理大量数据,因为每次轮询不需要消耗过多的CPU时间;缺点是即使只接收很少数据或不接收数据时,也要占用CPU时间。NAPI是两者的结合,数据量低时采用中断,数据量高时采用轮询。平时是中断方式,当有数据到达时,会触发中断处理函数执行,中断处理函数关闭中断开始处理。如果此时有数据到达,则没必要再触发中断了,因为中断处理函数中会轮询处理数据,直到没有新数据时才打开中断。很明显,数据量很低与很高时,NAPI可以发挥中断与轮询方式的优点,性能较好。如果数据量不稳定,且说高不高说低不低,则NAPI则会在两种方式切换上消耗不少时间,效率反而较低一些。

一、phy-napi增加

static int nuc970_ether_probe(struct platform_device *pdev)
{
  ......
  netif_napi_add(dev, ðer->napi, nuc970_poll, 16);
  ......
}      
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
        int (*poll)(struct napi_struct *, int), int weight)
{
  INIT_LIST_HEAD(&napi->poll_list); //初始化链表
  napi->gro_count = 0;
  napi->gro_list = NULL;
  napi->skb = NULL;
  napi->poll = poll;
  if (weight > NAPI_POLL_WEIGHT)
    pr_err_once("netif_napi_add() called with weight %d on device %s\n",
          weight, dev->name);
  napi->weight = weight;
  list_add(&napi->dev_list, &dev->napi_list);
  napi->dev = dev;
#ifdef CONFIG_NETPOLL
  spin_lock_init(&napi->poll_lock);
  napi->poll_owner = -1;
#endif
  set_bit(NAPI_STATE_SCHED, &napi->state); //设置napi的状态为NAPI_STATE_SCHED
}
EXPORT_SYMBOL(netif_napi_add);      

二、phy-napi使能

static int nuc970_ether_open(struct net_device *dev)
{
  ......
  napi_enable(ðer->napi);
  ......
}      
static inline void napi_enable(struct napi_struct *n)
{
  BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
  smp_mb__before_clear_bit();
  clear_bit(NAPI_STATE_SCHED, &n->state);
}      

三、phy-napi调度唤醒

static irqreturn_t nuc970_rx_interrupt(int irq, void *dev_id)
{
  ......
  napi_schedule(&ether->napi);
  ......
}      
static inline void napi_schedule(struct napi_struct *n)
{
  if (napi_schedule_prep(n))
    __napi_schedule(n);
}      
static inline bool napi_schedule_prep(struct napi_struct *n)
{
  return !napi_disable_pending(n) &&
    !test_and_set_bit(NAPI_STATE_SCHED, &n->state);
}      
void __napi_schedule(struct napi_struct *n)
{
  unsigned long flags;

  local_irq_save(flags);
  ____napi_schedule(&__get_cpu_var(softnet_data), n);
  local_irq_restore(flags);
}
EXPORT_SYMBOL(__napi_schedule);      

四、phy-napi调度完成

static int nuc970_poll(struct napi_struct *napi, int budget)
{
        ......
  __napi_complete(napi);
        ......
}      
void __napi_complete(struct napi_struct *n)
{
  BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
  BUG_ON(n->gro_list);

  list_del(&n->poll_list);
  smp_mb__before_clear_bit();
  clear_bit(NAPI_STATE_SCHED, &n->state);
}
EXPORT_SYMBOL(__napi_complete);      

五、phy-napi关闭

static int nuc970_ether_close(struct net_device *dev)
{
        ......
  napi_disable(ðer->napi);
  ......
}      
static inline void napi_disable(struct napi_struct *n)
{
  set_bit(NAPI_STATE_DISABLE, &n->state);
  while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
    msleep(1);
  clear_bit(NAPI_STATE_DISABLE, &n->state);
}      

继续阅读