网卡驱动:stmmac DMA发送流程
?
1. 設置DAM?buffer&descriptor,并啟動DMA發送
在stmmac_xmit設置buffe r& descriptor,如下片段:
if (likely(!is_jumbo)) {bool last_segment = (nfrags == 0);des = dma_map_single(priv->device, skb->data,nopaged_len, DMA_TO_DEVICE);if (dma_mapping_error(priv->device, des))goto dma_map_err;tx_q->tx_skbuff_dma[first_entry].buf = des; //在接收中斷中,用于dma_unmap_singleif (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))first->des0 = cpu_to_le32(des);elsefirst->des2 = cpu_to_le32(des);tx_q->tx_skbuff_dma[first_entry].len = nopaged_len;tx_q->tx_skbuff_dma[first_entry].last_segment = last_segment;if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&priv->hwts_tx_en)) {/* declare that device is doing timestamping */skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;priv->hw->desc->enable_tx_timestamp(first);}/* Prepare the first descriptor setting the OWN bit too */priv->hw->desc->prepare_tx_desc(first, 1, nopaged_len,csum_insertion, priv->mode, 1,last_segment, skb->len);/* The own bit must be the latest setting done when prepare the* descriptor and then barrier is needed to make sure that* all is coherent before granting the DMA engine.*/dma_wmb();}if (priv->synopsys_id < DWMAC_CORE_4_00)priv->hw->dma->enable_dma_transmission(priv->ioaddr);else {tx_q->tx_tail_addr = tx_q->dma_tx_phy + (tx_q->cur_tx * sizeof(*desc));priv->hw->dma->set_tx_tail_ptr(priv->ioaddr, tx_q->tx_tail_addr,queue);}?
1)進行DMA映射,得到映射地址des
des = dma_map_single(priv->device, skb->data, nopaged_len, DMA_TO_DEVICE);? ?
2)將映射后的DMA地址填充到DMA描述符的buffer1,即des0
?first->des0 = cpu_to_le32(des);
3)填充描述符其他信息,最重要的是設置OWN bit,讓DMA擁有該描述符
?priv->hw->desc->prepare_tx_desc
4)設置尾指針,啟動DMA發送
priv->hw->dma->set_tx_tail_ptr(priv->ioaddr, tx_q->tx_tail_addr,?queue);
5)接下來DMA會自動讀取descriptor,根據descriptor讀取buffer,然后將buffer數據送往queue。
?
在stmmac_xmit函數中還有對skb?分段的處理,過程與上述類似。
如果有skb frags,則從第二個descriptor開始,用skb_shinfo(skb)->frags[i]進行dma映射,再填充描述符的buffer。循環該過程直到所有的skb?frag被處理完畢。
如果skb沒有分段,則只會處理第一個descriptor,即上述步驟1-4。
?
注:kernel配置 CONFIG_BQL=y
?
?
2.?發送中斷處理:
2.1.?DMA發送完數據后產生中斷,調用 stmmac_interrupt服務程序
?
2.2. stmmac_interrupt?通過調用?stmmac_dma_interrupt?處理DMA相關中斷(包括發送和接收)。在stmmac_dma_interrupt中,通過NAPI機制觸發軟中斷,調用stmmac_poll處理相關事件。
?
2.3.?stmmac_poll調用stmmac_tx_clean回收資源,以及queue操作
1)通過dma_unmap_single解除dma映射
dma_unmap_single(priv->device, tx_q->tx_skbuff_dma[entry].buf, tx_q->tx_skbuff_dma[entry].len, DMA_TO_DEVICE);
2)釋放skb
dev_consume_skb_any(skb);
3)清空descriptor:des2和des3,?將其賦值0
release_tx_desc()
4)設置queue的狀態?,如果queue是停止狀態(__QUEUE_STATE_STACK_XOFF?或?__QUEUE_STATE_DRV_XOFF被置位),但是現在已經滿足開啟條件,則喚醒queue。? ?
在stmmac_xmit發送時如果停止了queue,現在如果條件滿足,會重新恢復queue。
netdev_tx_completed_queue(netdev_get_tx_queue(priv->dev, queue),pkts_compl, bytes_compl);if (unlikely(netif_tx_queue_stopped(netdev_get_tx_queue(priv->dev,queue))) &&stmmac_tx_avail(priv, queue) > STMMAC_TX_THRESH) {netif_dbg(priv, tx_done, priv->dev,"%s: restart transmit\n", __func__);netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, queue));}在netdev_tx_completed_queue中,test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state),如果test_and_clear_bit返回真,調用 netif_schedule_queue(q)重新開始調度queue
在netif_tx_wake_queue中,test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state),如果test_and_clear_bit返回真,調用 __netif_schedule(q)重新開始調度queue
?
?
?
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的网卡驱动:stmmac DMA发送流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新手开奶茶店全部流程(新手开奶茶店全部流
- 下一篇: 星座屋星盘查询(藤井树12星座一周运势)