mmc讀寫中scatterlist用法

2021-07-14 17:36:41 字數 4868 閱讀 2032

在閱讀核心**下mmc模組時,經常會遇到mmc讀寫函式,一般的方式為建立乙個請求佇列,將命令和資料buf新增到請求佇列裡,有mmc塊裝置驅動將請求佇列發下去,但是將資料buf並不是直接帶下去,而是建立了scatterlist結構體,用sg_init_one函式將buf與其繫結,而由這個結構體進行資料的下發或讀取,如下所示,是讀取mmc ext——csd的乙個函式

static int

mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,

u32 opcode, void *buf, unsigned len)

else

mmc_set_data_timeout(&data, card);

mmc_wait_for_req(host, &mrq);

memcpy(buf, data_buf, len);

kfree(data_buf);

if (cmd.error)

return cmd.error;

if (data.error)

return data.error;

return 0;

}

而核心為什麼要這麼做呢而不是直接將乙個buf指標傳下去呢
接下來介紹scatterlist的用法

使用scatterlist

的原因就是系統在執行的時候記憶體會產生很多碎片,比如4k,

100k

的,1m

的,有時候對應磁碟碎片,總之就是碎片。而在網路和磁碟操作中很多時候需要傳送大塊的資料,尤其是使用

dma的時候,因為

dma操作的實體地址必須是連續的。假設要

1m記憶體,此時可以分配乙個整的

1m記憶體, 也可以把10個

10k的和9個

100k

的組成一塊

1m的記憶體,當然這

19個塊可能是不連續的,也可能其中某些或全部是連續的,總之情況不定,為了描述這種情況,就引入了

scatterlist

,其實看成乙個關於記憶體塊構成的鍊錶就ok了。

在sd/mmc

**中,在發起

request

的時候,都是通過

scatterlist

來傳送資料的,定義在

mmc_data

裡面,(mmc core

就是這麼設計的,跟具體的

s3c2410

還是pxa

就沒有關係了)

struct mmc_data

其中struct scatterlist *sg;

就是指向

scatter list

的指標,可以理解為陣列的頭指標,這個陣列的作用就是儲存各個

scatterlist

結構的位址,

sg_len

表示有幾個

scatterlist

結構,相當於陣列元素個數。比如前面提到的那個例子,

sg_len

就應該是

19了,

sg組成的記憶體塊就是

sg_mem0--->sg_mem1--->........->sg_mem18

這樣的記憶體鏈。所以通過

sg就可以遍歷

19塊中的任意一塊記憶體的情況,比如位置和大小。

以下是scatterlist

的定義:

struct scatterlist ;
下面以

dw_mmc.c

裡面的scatter

操作來分析,其實

pxamci.c

裡面也有,不過

pxamci.c

裡面只使用了

dma模式,相對要簡單一點,

dw_mmc.c

裡面還使用pio

模式(其實就是

cpu模式),要複雜一些,所以分析起來更有意義。

1.dma模式下的使用

在使用dma操作這些

scatterlist

之前,先要對

scatterlist

進行一下

map:

int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,

enum dma_data_direction dir)

其中的nents

就是scatterlist

的塊數,

sg是指標陣列的首位址。返回值是

map以後這些位址塊被合併為多少個適合

dma搬運的塊的數量,假設其中一塊的結束位址和另一塊的起始位址挨到一起了,這兩塊是會合二為一的,這就是為什麼說返回的值可能會小於

nents

的原因。

比如上面的例子傳進去的nents=19,

函式的返回值肯定是小於等於

19的,當然肯定大於

0,同時

sg的值也被改寫成了新的塊鍊錶。此時就可以把這些塊放入

dma佇列乙個乙個的進行搬運了。

s3cmci.c

中的**是這樣的。

dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,

rw ? dma_to_device : dma_from_device);

。。。。。。。。。。。。。。。。。。

for (i = 0; i < dma_len; i++)

for迴圈其實就是遍歷記憶體塊了,不過據下面這個**上說的,這種用

for的方式已經

out了,現在要用

for_each_sg,

其實是一樣的:

/* fill in list and pass it to dma_map_sg().  then... */

for_each_sg(i, list, sgentry, nentries)

2.cpu方式

cpu方式就不用呼叫

map了,這些

list

本來就是

cpu自己產生自己消化。在

dw_mmc.c

中是通過函式:

static inline int get_data_buffer(struct dw

_host *host,

u32 *bytes, u32 **pointer)

來實現的,

它使用了乙個計數host->pio_sgptr

來記錄現在使用的是記憶體鏈中的第幾塊,這個值在每次

request

後prepare_pio

的時候被清零,每次呼叫

get_data_buffer

就加 一,直到等於

sg_len

,表示所有的記憶體塊都用過了。

對於乙個scatterlist

指標sg

,是如下這樣獲取它代表的記憶體塊的大小和位置的:

*bytes = sg->length;/*記憶體塊長度

*/*pointer = sg_virt(sg);/*記憶體塊起始位址*/在

dw_mmc.c

中使用了一點點小技巧來操作scatterlist

和sd/mmc fifo傳送/

接收,比如在

do_pio_write

中while ((fifo = fifo_free(host)) > 3)

。。。。。。。。。。。。。。。。。。。。。。。。

if (fifo >= host->pio_bytes)

fifo = host->pio_bytes;

else

fifo -= fifo & 3;

host->pio_bytes -= fifo;

host->pio_count += fifo;

fifo = (fifo + 3) >> 2;

ptr = host->pio_ptr;

while (fifo--)

writel(*ptr++, to_ptr);

host->pio_ptr = ptr;}

它通過host->pio_bytes

來記錄當前的記憶體塊還有多少資料沒有發,如果

fifo

裡面的空間夠用,那就直接都發了,如果不夠呢,則先把

fifo

填滿,然後等著下一次中斷的時候再發。如果這個記憶體塊的資料都發完了,則

host->pio_bytes為0

,此時呼叫

get_data_buffer

來獲取記憶體鏈中的下一塊記憶體資料,在

get_data_bu

中host->pio_bytes

會被置為新塊的長度:

*bytes = sg->length

其中的*bytes

就是指向

host->pio_bytes的。

fifo-=fifo&3 是因為

2410

每次必須發四個位元組,所以要把零頭去掉,

evb也有這個問題。 其實

scatterlist

這個東東蠻有意思的,俺們的

nucleus

上其實也可以借鑑的,由於記憶體太少,在解

jpeg

檔案時不一定能分到那麼大的一塊連續記憶體,可以通過

scatterlist

來把檔案分塊讀取,然後解碼的時候

dma再一塊一塊的搬,總比分不到記憶體就返回失敗來的強。不過對於應用來講如果沒有

mmu支援,還是有點杯具的,如果有

mmu支援,讓應用層看到的是一整塊的記憶體,估計要爽的多,甚至在檔案系統層也是這樣的,只要到

dma搬數之前把

scatterlist

的記憶體鏈分清楚就ok了

mmc讀寫中scatterlist用法

在閱讀核心 下mmc模組時,經常會遇到mmc讀寫函式,一般的方式為建立乙個請求佇列,將命令和資料buf新增到請求佇列裡,有mmc塊裝置驅動將請求佇列發下去,但是將資料buf並不是直接帶下去,而是建立了scatterlist結構體,用sg init one函式將buf與其繫結,而由這個結構體進行資料的...

讀寫SharedPreferences中的資料

很多時候我們開發的軟體需要向使用者提供軟體引數設定功能,例如我們常用的 qq,使用者可以設定是否允許陌生人新增自己為好友。對於軟體配置引數的儲存,如果是 window軟體通常我們會採用 ini檔案進行儲存,如果是 j2se應用,我們會採用 properties屬性檔案進行儲存。如果是 android...

asp 中讀寫檔案

維護專案中看到用到生成檔案時竟然出現錯誤了,以前沒有出現過錯誤的 不過上次生成檔案是英文版本的,這次生成的檔案是日文版的,一共生成了三個檔案,前兩個檔案通過 adodb.stream 儲存檔案的一點檔案也沒有 其實生成的三個檔案有兩個的內容來子同一張 的,用 adodb.stream 的沒有問題,可...