文章目錄
-
- 一、硬中斷
-
- 1.1 `e100_intr`
- 1.2 `__netif_rx_schedule`
- 1.3 補充:
- 二、軟中斷
-
- 2.1 net_rx_action
- 2.2 e100_poll
- 2.3 補充
- 三、非 NAPI 的軟中斷處理
-
- 3.1 netif_rx
- 3.2 backlog_dev->poll
- 3.3 補充
- 四、總結
以 e100_intr 為例:
一、硬中斷
1.1 e100_intr
網卡觸發中斷,os 進入中斷處理程序 e100_intr
,該函數通過 request_irq
注冊到中斷處理系統中。
static irqreturn_t e100_intr(int irq, void *dev_id)
{struct net_device *netdev = dev_id;struct nic *nic = netdev_priv(netdev);u8 stat_ack = readb(&nic->csr->scb.stat_ack);DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);if(stat_ack == stat_ack_not_ours || /* Not our interrupt */stat_ack == stat_ack_not_present) /* Hardware is ejected */return IRQ_NONE;/* Ack interrupt(s) */writeb(stat_ack, &nic->csr->scb.stat_ack);/* We hit Receive No Resource (RNR); restart RU after cleaning */if(stat_ack & stat_ack_rnr)nic->ru_running = RU_SUSPENDED;if(likely(netif_rx_schedule_prep(netdev))) {e100_disable_irq(nic);__netif_rx_schedule(netdev);}return IRQ_HANDLED;
}
- 首先對硬中斷進行檢查,即是否由網絡設備激活等
netif_rx_schedule_prep
設置網卡 state 的RX_SCHED
標志。如果設置成功,則e100_disable_irq(dev)
關閉網絡設備的硬中斷 (即當前設備再收到包也不會觸發中斷信號,區別于關閉 cpu 的中斷響應。關閉后會在驅動的 poll 函數中重新打開,表示驅動完整的收完一輪包),防止網卡觸發大量硬中斷。如果RX_SCHED
已經設置過了,則直接返回,因為設備已經加入poll_list
且觸發過軟中斷了),然后__netif_rx_schedule
觸發軟中斷。
1.2 __netif_rx_schedule
__netif_rx_schedule
void __netif_rx_schedule(struct net_device *dev)
{unsigned long flags;local_irq_save(flags); // 保存并關閉 cpu 中斷響應dev_hold(dev);list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);if (dev->quota < 0)dev->quota += dev->weight;elsedev->quota = dev->weight;__raise_softirq_irqoff(NET_RX_SOFTIRQ);local_irq_restore(flags);
}
EXPORT_SYMBOL(__netif_rx_schedule);
- 保存當前 cpu 的中斷響應狀態并關閉 cpu 的中斷響應(有可能在中斷處理中遞歸被中斷,所以這里不能簡單的關閉中斷或者開啟中斷,而是保存狀態并關閉:
local_irq_save(flags)
) - 將 dev 插入到當前 cpu 的
softnet_data
的 poll_list 等待軟中斷處理(list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
)- 這里
softnet_data
是 cpu 級別的數據結構,用來記錄有哪些網卡設備將中斷捅給了當前 cpu,或者當前 cpu 有哪些包需要發給哪些網卡
- 這里
- 為
dev->quota
賦值,即分配 napi 可收取的包數 - 發起軟中斷(
__raise_softirq_irqoff(NET_RX_SOFTIRQ)
) - 恢復 cpu 中斷響應狀態(
local_irq_restore(flags);
)
content_copy
1.3 補充:
local_irq_save(flags)
函數實現:
// 保存 cpu 中斷響應標志的函數,保存的同時會關閉 cpu 的中斷響應
#define local_irq_save(flags) \do { raw_local_irq_save(flags); trace_hardirqs_off(); } while (0)// include/asm-x86_64/irqflags.h
#define raw_local_irq_save(flags) \do { (flags) = __raw_local_irq_save(); } while (0)static inline unsigned long __raw_local_irq_save(void)
{unsigned long flags = __raw_local_save_flags();raw_local_irq_disable()