linux kernel 工程师
全部博文(99)
分类: 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里面多设备进行轮询,直到没有包为止--->开启中断