netdev: dev_watchdog timer(结合stmmac 分析)
分析netdev看門狗定時器
?
1. dev_watchdog()作為定時器回調函數會被周期執行
在dev_watchdog()中,如果 if (netif_xmit_stopped(txq) && time_after(jiffies, (trans_start + dev->watchdog_timeo)))?成立,執行some_queue_timedout = 1,?然后便調用ndo_tx_timeout。
ndo_tx_timeout函數便是網卡發送異常(數據發不出去等)時的超時處理函數。它會調用 stmmac_tx_timeout重新啟動transmission。
if (some_queue_timedout) {WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n",dev->name, netdev_drivername(dev), i);dev->netdev_ops->ndo_tx_timeout(dev); }?
2. dev_watchdog()執行ndo_tx_timeout的條件
if (netif_xmit_stopped(txq) && time_after(jiffies, (trans_start + dev->watchdog_timeo)))
?
2.1 time_after(jiffies, (trans_start + dev->watchdog_timeo))
即queue發送超時
1)dev->watchdog_timeo為定時周期
2)在 __netdev_start_xmit中,如果 ndo_start_xmit返回 NETDEV_TX_OK(這并不代表數據已經通過DMA發送出去),便調用 txq_trans_update更新txq->trans_start。在dev_watchdog中,會將txq->trans_start賦值給trans_start。
?
2.2 netif_xmit_stopped(txq)
queue已經停止發送
static inline bool netif_xmit_stopped(const struct netdev_queue *dev_queue) {return dev_queue->state & QUEUE_STATE_ANY_XOFF; }#define QUEUE_STATE_ANY_XOFF (QUEUE_STATE_DRV_XOFF | QUEUE_STATE_STACK_XOFF) #define QUEUE_STATE_DRV_XOFF (1 << __QUEUE_STATE_DRV_XOFF) #define QUEUE_STATE_STACK_XOFF (1 << __QUEUE_STATE_STACK_XOFF)1)__QUEUE_STATE_STACK_XOFF
清除__QUEUE_STATE_STACK_XOFF:
如果DMA發送完成,在中斷服務程序 stmmac_dma_interrupt() ->? stmmac_poll() ->? stmmac_tx_clean() ->? netdev_tx_completed_queue() ->? test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state)? 清除
?
設置__QUEUE_STATE_STACK_XOFF:
發送時,在stmmac_xmit() ->?netdev_tx_sent_queue() ->?set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state)?設置
?
所以如果dma中斷沒有被觸發,或是觸發了但是發送沒有完成,則netif_xmit_stopped()返回1
static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,unsigned int bytes) { #ifdef CONFIG_BQLdql_queued(&dev_queue->dql, bytes);if (likely(dql_avail(&dev_queue->dql) >= 0))return;set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state);/* check again in case another CPU has just made room avail */if (unlikely(dql_avail(&dev_queue->dql) >= 0))clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state); #endif }static inline void netdev_tx_reset_queue(struct netdev_queue *q) { #ifdef CONFIG_BQLclear_bit(__QUEUE_STATE_STACK_XOFF, &q->state);dql_reset(&q->dql); #endif }static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue,unsigned int pkts, unsigned int bytes) { #ifdef CONFIG_BQLif (unlikely(!bytes))return;dql_completed(&dev_queue->dql, bytes);if (dql_avail(&dev_queue->dql) < 0)return;if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state))netif_schedule_queue(dev_queue); #endif }2) __QUEUE_STATE_DRV_XOFF
主要針對網卡queue,當queue滿或不足以進行下一個傳輸時,會調用netif_tx_stop_queue通知上層停止發送。當queue恢復時,調用netif_tx_wake_queue通知上層重新開始傳輸。
?
清除__QUEUE_STATE_DRV_XOFF:
stmmac_open ->?stmmac_start_all_queues ->?netif_tx_start_queue ->?clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state)
stmmac_dma_interrupt ->?stmmac_poll -> stmmac_tx_clean ->?netif_tx_wake_queue
?
設置__QUEUE_STATE_DRV_XOFF:
static __always_inline void netif_tx_start_queue(struct netdev_queue *dev_queue) {clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); }void netif_tx_wake_queue(struct netdev_queue *dev_queue) {if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state)) {struct Qdisc *q;rcu_read_lock();q = rcu_dereference(dev_queue->qdisc);__netif_schedule(q);rcu_read_unlock();} }static __always_inline void netif_tx_stop_queue(struct netdev_queue *dev_queue) {set_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); }?
總結
以上是生活随笔為你收集整理的netdev: dev_watchdog timer(结合stmmac 分析)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果鼠标怎么充电_“智能”还是“多功能”
- 下一篇: 刺客信条中主角康纳的父亲是谁(中国古代十