netdev: dev_watchdog timer(结合stmmac 分析)
分析netdev看門狗定時(shí)器
?
1. dev_watchdog()作為定時(shí)器回調(diào)函數(shù)會被周期執(zhí)行
在dev_watchdog()中,如果 if (netif_xmit_stopped(txq) && time_after(jiffies, (trans_start + dev->watchdog_timeo)))?成立,執(zhí)行some_queue_timedout = 1,?然后便調(diào)用ndo_tx_timeout。
ndo_tx_timeout函數(shù)便是網(wǎng)卡發(fā)送異常(數(shù)據(jù)發(fā)不出去等)時(shí)的超時(shí)處理函數(shù)。它會調(diào)用 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()執(zhí)行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發(fā)送超時(shí)
1)dev->watchdog_timeo為定時(shí)周期
2)在 __netdev_start_xmit中,如果 ndo_start_xmit返回 NETDEV_TX_OK(這并不代表數(shù)據(jù)已經(jīng)通過DMA發(fā)送出去),便調(diào)用 txq_trans_update更新txq->trans_start。在dev_watchdog中,會將txq->trans_start賦值給trans_start。
?
2.2 netif_xmit_stopped(txq)
queue已經(jīng)停止發(fā)送
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發(fā)送完成,在中斷服務(wù)程序 stmmac_dma_interrupt() ->? stmmac_poll() ->? stmmac_tx_clean() ->? netdev_tx_completed_queue() ->? test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state)? 清除
?
設(shè)置__QUEUE_STATE_STACK_XOFF:
發(fā)送時(shí),在stmmac_xmit() ->?netdev_tx_sent_queue() ->?set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state)?設(shè)置
?
所以如果dma中斷沒有被觸發(fā),或是觸發(fā)了但是發(fā)送沒有完成,則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
主要針對網(wǎng)卡queue,當(dāng)queue滿或不足以進(jìn)行下一個(gè)傳輸時(shí),會調(diào)用netif_tx_stop_queue通知上層停止發(fā)送。當(dāng)queue恢復(fù)時(shí),調(diào)用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
?
設(shè)置__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); }?
總結(jié)
以上是生活随笔為你收集整理的netdev: dev_watchdog timer(结合stmmac 分析)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果鼠标怎么充电_“智能”还是“多功能”
- 下一篇: 刺客信条中主角康纳的父亲是谁(中国古代十