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関数は,NICが異常を送信した場合(データが送信できない場合など)のタイムアウト処理関数である.stmmac_が呼び出されますtx_timeoutはtransmissionを再起動します.
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は送信を停止しました
クリア_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を返します.
主にNIC 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:
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関数は,NICが異常を送信した場合(データが送信できない場合など)のタイムアウト処理関数である.stmmac_が呼び出されますtx_timeoutはtransmissionを再起動します.
if (some_queue_timedout) {
WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out
",
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_BQL
dql_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_BQL
clear_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_BQL
if (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主にNIC 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);
}