在正文開始之前需要先搞明白以下幾個問題:
1. 什么是DMA?
DMA的中文名稱叫做 直接內存訪問,是一種不需要CPU參與,就能實現數據搬移的技術(從一個地址空間到另一個地址空間)。
2. DMA有什么用?
一定程度上解放CPU,對於實現 高效嵌入式系統 與 加速網絡數據處理 有極其重要的作用。
3. DMA的實現簡述
在實現DMA傳輸時,是由DMA控制器直接掌管總線,因此,存在着一個總線控制權轉移問題。即DMA傳輸前,CPU要把總線控制權交給DMA控制器,而在結束DMA傳輸后,DMA控制器應立即把總線控制權再交回給CPU。一個完整的DMA傳輸過程必須經過DMA請求、DMA響應、DMA傳輸、DMA結束 4個步驟。
scatter-gather DMA 與 block DMA
傳統的block DMA 一次只能傳輸物理上連續的一個塊的數據, 完成傳輸后發起中斷。而scatter-gather DMA允許一次傳輸多個物理上不連續的塊,完成傳輸后只發起一次中斷。
傳統的block DMA像這樣:
先進的scatter-gather DMA像這樣:
這樣做的好處是直觀的,大大減少了中斷的次數,提高了數據傳輸的效率。
scatter-gather DMA的應用
dpdk在ip分片的實現中,采用了一種稱作零拷貝的技術。而這種實現方式的底層,正是由scatter-gather DMA支撐的。dpdk的分片包采用了鏈式管理,同一個數據包的數據,分散存儲在不連續的塊中(mbuf結構)。這就要求DMA一次操作,需要從不連續的多個塊中搬移數據。附上e1000驅動發包部分代碼:
uint16_t eth_em_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) { //e1000驅動部分代碼 ... m_seg = tx_pkt; do { txd = &txr[tx_id]; txn = &sw_ring[txe->next_id]; if (txe->mbuf != NULL) rte_pktmbuf_free_seg(txe->mbuf); txe->mbuf = m_seg; /* * Set up Transmit Data Descriptor. */ slen = m_seg->data_len; buf_dma_addr = rte_mbuf_data_iova(m_seg); txd->buffer_addr = rte_cpu_to_le_64(buf_dma_addr); txd->lower.data = rte_cpu_to_le_32(cmd_type_len | slen); txd->upper.data = rte_cpu_to_le_32(popts_spec); txe->last_id = tx_last; tx_id = txe->next_id; txe = txn; m_seg = m_seg->next; } while (m_seg != NULL); /* * The last packet data descriptor needs End Of Packet (EOP) */ cmd_type_len |= E1000_TXD_CMD_EOP; txq->nb_tx_used = (uint16_t)(txq->nb_tx_used + nb_used); txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_used); ... }
---------------------
版權聲明:本文為CSDN博主「Alan. W」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_38006908/article/details/87375404