内核协议栈源码阅读(一) ---驱动与内核交互
文章目录
-
- 一、硬中断
-
- 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(