我們知道對磁碟的每個io操作就是在磁碟與一些記憶體單元之間相互傳送一些相鄰扇區的內容。塊裝置驅動程式只要向磁碟控制器傳送一些適當的命令(如前面我們所講的scsi命令)就可以觸發一次資料傳送;一旦完成資料的傳送,控制器就會發出乙個中斷通知塊裝置驅動程式。大多數情況,磁碟控制器直接採用dma方式進行資料傳送。
dma全稱就是直接記憶體訪問,是一種硬體機制,它允許外圍裝置和主記憶體直接直接進行資料傳輸而不需要cpu的參與。
老式磁碟控制器在dma傳送時,磁碟必須與連續的記憶體單元相互傳送資料。
新的磁碟控制器支援所謂的分散-聚集dma傳送方式:此種方式,磁碟可以與一些非連續的記憶體區相互傳送資料。
啟動一次分散-聚集dma傳送,塊裝置驅動需要向磁碟控制器傳送:
分散/聚集對映
如果塊裝置驅動程式在實際傳輸過程中需要使用dma,那麼它可以遍歷bio結構,並為
每個bio結構建立dma對映,並將結果傳遞給裝置。如果裝置支援」分散-聚集dma「
則有乙個更簡便高效的方法:
int blk_rq_map_sg(struct request_queue *q, struct request *rq, struct scatterlist *sglist)
從指定請求獲得全部的段(段指bio中的每乙個segment),然後把它們填寫到給定表(list)中。記憶體中相鄰的段將被合併在乙個scatterlist中,返回值表示的是表中入口項的個數(表中有效元素個數),該函式使用第三個引數返回乙個分散表。
在呼叫blk_rq_map_sg前,必須為分散表(list)分配儲存空間,至少與request請求所擁有的(記憶體)物理段同樣多的數量,即req->nr_phys_segments。
許多裝置都能接受乙個指標陣列的分散表,以及它的長度,然後在一次dma操作中把它們全部傳輸走。
對映分散表的第一步是建立並填充乙個描述 被傳送緩衝區的 scatterlist結構的陣列。
scatterlist結構的主要成員:
為了對映乙個分散/聚集dma操作,驅動程式應為傳輸的每個緩衝區在scatterlist結構對應入口項上設定page_link,offset和length成員。(這一步由上述blk_rq_map_sg完成)
然後呼叫:
int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction direction);
這裡的nents是傳入分散表sg入口的數量。返回值是要傳送dma緩衝區數,可能小於nents。
對在分散表中每乙個緩衝區,dma_map_sg返回了指定裝置的正確匯流排位址,匯流排位址和每個緩衝區長度被儲存在scatterlist結構中,驅動程式應該傳輸由dma_map_sg返回的每個緩衝區。
一旦傳輸完畢,使用dma_unmap_sg解除分散/聚集對映。
分散 聚集I O
include include include include include include include int main struct iovec iov 3 int i,nr,j for i 0 i 3 i ftruncate fd,0 nr writev fd,iov,3 close f...
Java NIO 通道(二)通道分散 聚集
基於通道,nio又提供了另乙個重要功能,分散 scatter 和聚集 gather scatter 分散 指的是從通道中讀取 read 資料分散到多個緩衝區buffer中,該過程會將每個緩衝區填滿,直到通道中無資料或者緩衝區沒有空間。gather 聚集 指的是將多個緩衝區buffer聚集起來寫入 w...
Linux下PCIe驅動以及DMA機制
1.驅動程式作用 裝置驅動程式向應用程式遮蔽了硬體在實現上的細節,使得應用程式可以像操作普通檔案一樣操作外部裝置。linux 作業系統抽象了對硬體的處理,可以使用和操作檔案相同的,標準的系統呼叫介面來完成開啟,關閉,讀寫喝 i o控制操作,而驅動程式主要任務也就是實現這些系統呼叫函式。每個裝置檔案對...