加载中...

17.7. 中断处理


17.7. 中断处理

大部分硬件接口通过一个中断处理来控制. 硬件中断处理器来发出 2 种可能的信号: 一个新报文到了或者一个外出报文的发送完成了. 网络接口也能够产生中断来指示错误, 例如状态改变, 等等.

通常的中断过程能够告知新报文到达中断和发送完成通知的区别, 通过检查物理设备中的状态寄存器. snull 接口类似地工作, 但是它的状态字在软件中实现, 位于 dev->priv. 网络接口的中断处理看来如此:

  1. static void snull_regular_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  2. {
  3. int statusword;
  4. struct snull_priv *priv;
  5. struct snull_packet *pkt = NULL;
  6. /*
  7. *
  8. As usual, check the "device" pointer to be sure it is
  9. *
  10. really interrupting.
  11. *
  12. Then assign "struct device *dev"
  13. */
  14. struct net_device *dev = (struct net_device *)dev_id;
  15. /* ... and check with hw if it's really ours */
  16. /* paranoid */
  17. if (!dev)
  18. return;
  19. /* Lock the device */
  20. priv = netdev_priv(dev);
  21. spin_lock(&priv->lock);
  22. /* retrieve statusword: real netdevices use I/O instructions */
  23. statusword = priv->status;
  24. priv->status = 0;
  25. if (statusword & SNULL_RX_INTR) {
  26. /* send it to snull_rx for handling */
  27. pkt = priv->rx_queue;
  28. if (pkt) {
  29. priv->rx_queue = pkt->next;
  30. snull_rx(dev, pkt);
  31. }
  32. }
  33. if (statusword & SNULL_TX_INTR) {
  34. /* a transmission is over: free the skb */
  35. priv->stats.tx_packets++;
  36. priv->stats.tx_bytes += priv->tx_packetlen;
  37. dev_kfree_skb(priv->skb);
  38. }
  39. /* Unlock the device and we are done */
  40. spin_unlock(&priv->lock);
  41. if (pkt) snull_release_buffer(pkt); /* Do this outside the lock! */
  42. return;
  43. }

中断处理的第一个任务是取一个指向正确 net_device 结构的指针. 这个指针通常来自作为参数收到的 dev_id 指针.

中断处理的有趣部分处理"发送结束"的情况. 在这个情况下, 统计量被更新, 调用 dev_kfree_skb 来返回 socket 缓存给系统. 实际上, 有这个函数的 3 个变体可以调用:

dev_kfree_skb(struct sk_buff *skb);
这个版本应当在你知道你的代码不会在中断上下文中运行时调用. 因为 snull 没有实际的硬件中断, 我们使用这个版本.

dev_kfree_skb_irq(struct sk_buff *skb);
如果你知道会在中断处理中释放缓存, 使用这个版本, 它对这个情况做了优化.

dev_kfree_skb_any(struct sk_buff *skb);
如果相关代码可能在中断或非中断上下文运行时, 使用这个版本.

最后, 如果你的驱动已暂时停止了发送队列, 这常常是用 netif_wake_queue 重启它的地方.

报文的接收, 相比于发送, 不需要特别的中断处理. 调用 snull_rx (我们已经见过)就是全部所需.


还没有评论.