网卡驱动:stmmac DMA接收流程
1. dma?buffer及zero-copy
在打開網卡時,stmmac_init_rx_buffers()函數負責分配dma?buffer。
static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,int i, gfp_t flags, u32 queue) {struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];struct sk_buff *skb;skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags);if (!skb) {netdev_err(priv->dev,"%s: Rx init fails; skb is NULL\n", __func__);return -ENOMEM;}rx_q->rx_skbuff[i] = skb;rx_q->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,priv->dma_buf_sz,DMA_FROM_DEVICE);if (dma_mapping_error(priv->device, rx_q->rx_skbuff_dma[i])) {netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);dev_kfree_skb_any(skb);return -EINVAL;}if (priv->synopsys_id >= DWMAC_CORE_4_00)p->des0 = cpu_to_le32(rx_q->rx_skbuff_dma[i]);elsep->des2 = cpu_to_le32(rx_q->rx_skbuff_dma[i]);if ((priv->hw->mode->init_desc3) &&(priv->dma_buf_sz == BUF_SIZE_16KiB))priv->hw->mode->init_desc3(p);return 0; }1)skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags);?分配skb
2)rx_q->rx_skbuff[i] = skb;?用于zero-copy,以后再接收軟中斷中直接使用rx_q->rx_skbuff[i],并交給上層協議處理
3)rx_q->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, priv->dma_buf_sz, DMA_FROM_DEVICE);?進行dma映射,得到rx_q->rx_skbuff_dma[i]?源地址(即物理地址)
4)p->des0 = cpu_to_le32(rx_q->rx_skbuff_dma[i]);?在des0設置源地址(即填充buffer地址)
?
?
2. 接收數據流程:
2.1.?DMA產生中斷,調用 stmmac_interrupt服務程序
?
2.2. stmmac_interrupt?通過調用?stmmac_dma_interrupt?處理DMA相關中斷(包括發送和接收)。在stmmac_dma_interrupt中,通過NAPI機制觸發軟中斷,調用stmmac_poll接收數據包。
?
2.3. 在stmmac_poll中調用如下代碼收數據包
work_done = stmmac_rx(priv, budget, rx_q->queue_index);if (work_done < budget) {napi_complete_done(napi, work_done);stmmac_enable_dma_irq(priv, chan);}return work_done;1)調用stmmac_rx接收,budget為循環讀取dma?descriptor(通過處理descriptor來獲取數據包,每個descriptor對應一個數據包)的最大次數,work_done為實際循環的次數。
2)if (work_done < budget) 代表實際循環讀取dma?descriptor的次數小于最大次數budget,代表已經處理完所有需要被處理的descriptor,取完所有的數據包。這時,調用stmmac_enable_dma_irq()開啟中斷,再次接收數據。如果work_done = budget,代表可能還有數據包需要處理,那么這些數據包留到net_rx_action再次調用stmmac_poll時處理。
3)return work_done;?該返回值會被net_rx_action使用。
?
2.4. 在stmmac_rx中,循環收包,循環次數while (count < limit)。每次循環以DMA?descriptor為處理單位,即每次循環時從一個descriptor指定的buffer讀取一個數據包,再通過 napi_gro_receive?送給協議層,處理完后count++。這里limit = budget。
?
2.5. 調用 stmmac_rx_refill重新填充descriptor。
在觸發DMA中斷前,DMA已經將網卡收到的數據包搬到descriptor指定的buffer,而這個buffer又采用了zero-copy機制,所以直接將該buffer的地址copy給一個skb,再將此skb送到協議層處理,最后再調用 stmmac_rx_refill重新填充descriptor并設置buffer。之前descriptor指定的buffer地址已經被賦值給skb,由協議層負責該skb(buffer)的管理(釋放內存等)。
?
2.6.?總結:
這里有三種“一次獲取多個數據包”的情況
1)一次軟中斷可能會多次調用net_rx_action
2)net_rx_action可能會多次調用stmmac_poll
3)stmmac_poll處理多個descriptor
?
?
?
總結
以上是生活随笔為你收集整理的网卡驱动:stmmac DMA接收流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 星座屋星盘查询(藤井树12星座一周运势)
- 下一篇: 我的世界僵尸怕什么(汉典我字的基本解释)