Chinaunix首页 | 论坛 | 博客
  • 博客访问: 418007
  • 博文数量: 99
  • 博客积分: 65
  • 博客等级: 民兵
  • 技术积分: 1012
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-20 16:30
个人简介

linux kernel 工程师

文章分类

全部博文(99)

文章存档

2018年(5)

2017年(12)

2016年(27)

2015年(10)

2014年(43)

2012年(2)

我的朋友

分类: LINUX

2014-02-10 16:42:34

e1000网卡NAPI的主要处理函数位于drivers/net/ethernet/intel/e1000_main.c

1. napi初始化
static int __devinit e1000_probe(struct pci_dev *pdev,
     const struct pci_device_id *ent)
{
...
netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);   //poll函数为e1000_clean,weight是64
...
}


2. napi的调度
/**
 * e1000_intr - Interrupt Handler
 * @irq: interrupt number
 * @data: pointer to a network interface device structure
 **/

static irqreturn_t e1000_intr(int irq, void *data)
{
 struct net_device *netdev = data;
 struct e1000_adapter *adapter = netdev_priv(netdev);
 struct e1000_hw *hw = &adapter->hw;
 u32 icr = er32(ICR);

 if (unlikely((!icr)))
  return IRQ_NONE;  /* Not our interrupt */

 /*
  * we might have caused the interrupt, but the above
  * read cleared it, and just in case the driver is
  * down there is nothing to do so return handled
  */
 if (unlikely(test_bit(__E1000_DOWN, &adapter->flags)))
  return IRQ_HANDLED;

 if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) {//link_state的更新
  hw->get_link_status = 1;
  /* guard against interrupt when we're going down */
  if (!test_bit(__E1000_DOWN, &adapter->flags))
   schedule_delayed_work(&adapter->watchdog_task, 1);
 }

 /* disable interrupts, without the synchronize_irq bit */
 ew32(IMC, ~0);//关中断
 E1000_WRITE_FLUSH();

 if (likely(napi_schedule_prep(&adapter->napi))) {   //判断napi是否可以调度
  adapter->total_tx_bytes = 0;
  adapter->total_tx_packets = 0;
  adapter->total_rx_bytes = 0;
  adapter->total_rx_packets = 0;
  __napi_schedule(&adapter->napi);   // napi的调度
 } else {
  /* this really should not happen! if it does it is basically a
   * bug, but not a hard error, so enable ints and continue */
  if (!test_bit(__E1000_DOWN, &adapter->flags))
   e1000_irq_enable(adapter);
 }

 return IRQ_HANDLED;
}

3. NAPI的poll函数

/**
 * e1000_clean - NAPI Rx polling callback
 * @adapter: board private structure
 **/
static int e1000_clean(struct napi_struct *napi, int budget)
{
 struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
 int tx_clean_complete = 0, work_done = 0;

 //发送的处理
 tx_clean_complete = e1000_clean_tx_irq(adapter, &adapter->tx_ring[0]);
 //接收的处理
 adapter->clean_rx(adapter, &adapter->rx_ring[0], &work_done, budget);

 if (!tx_clean_complete)
  work_done = budget;

 /* If budget not fully consumed, exit the polling mode */
 if (work_done < budget) {//work_done
  if (likely(adapter->itr_setting & 3))
   e1000_set_itr(adapter);
  napi_complete(napi);  // 调用napi_complete,将napi从softnet_data的poll_list上摘下来
  if (!test_bit(__E1000_DOWN, &adapter->flags))
   e1000_irq_enable(adapter);  //开中断
 }

 return work_done;
}

4.流程总结
这里可以看到napi的基本流程
中断到来--->关闭中断--->调度softirq--->在softirq里面多设备进行轮询,直到没有包为止--->开启中断

阅读(1318) | 评论(0) | 转发(0) |
0

上一篇:net_rx_action

下一篇:net_rx_action

给主人留下些什么吧!~~