(十四)Linux kernel mmc 框架說明,包括mmc_test使用方法

1.Linux 總線模型linux

        Linux下的任何驅動在內核中最終都抽象爲bus, driver以及device三者間的相互做用。ios

        總線是處理器和一個或多個設備之間的通道,在設備模型中,全部的設備都經過總線相鏈接。總線將設備和驅動綁定,在系統每註冊一個設備的時候,會遍歷該總線上的driver list,經過bus的math函數尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會便利該總線上的device 尋找與之匹配的設備,而匹配由總線的match函數完成。一但匹配,則會調用總線的probe函數。git

        在此模型下,若是存在實際總線固然很好,好比mmc總線,i2c總線和spi總線,相應的device和driver均可以直接註冊在總線上。可是老是有一些設備和總線無關,爲此,linux kernel引入了platform 虛擬總線,框架

Platform總線是一種虛擬的總線,相應的設備則爲platform_device,經過platform_driver_register;而驅動則爲platform_driver,經過platform_driver_register 註冊。內核中該總線定義以下:dom


struct bus_type platform_bus_type = {函數

       .name            = "platform",測試

       .dev_groups= platform_dev_groups,fetch

       .match          = platform_match,spa

       .uevent         = platform_uevent,.net

       .pm        = &platform_dev_pm_ops,

};

    platform_總線match採用名稱匹 配的方式,即driver和device二者的name同樣則認爲該device對應該driver,詳見下圖:

 

 

 

2.MMC 簡介
MMC

MMC全稱MultiMedia Card,由西門子公司和SanDisk公司1997年推出的多媒體記憶卡標準。MMC卡尺寸爲32mm x24mm x 1.4mm,它將存貯單元和控制器一同作到了卡上,智能的控制器使得MMC保證兼容性和靈活性。

MMC卡具備MMC和SPI兩種工做模式,MMC模式是默認工做模式,具備MMC的所有特性。而SPI模式則是MMC協議的一個子集,主要用於低速系統。

 

SD

        SD卡全稱Secure DigitalMemory Card,由松下、東芝和SanDisk公司於1999年8月共同開發的新一代記憶卡標準,已徹底兼容MMC標準。SD卡比MMC卡多了一個進行數據著做權保護的暗號認證功能。

        SD卡尺寸爲32mm x 24mm x2.1mm,長寬和MMC卡同樣,只是比MMC卡厚了0.7mm,以容納更大容量的存貯單元。SD卡與MMC卡保持向上兼容,也就是說,MMC卡能夠被新的設有SD卡插槽的設備存取,可是SD卡卻不能夠被設有MMC插槽的設備存取。

 

SDIO

        SDIO全稱Secure DigitalInput and Output Card,SDIO是在SD標準上定義了一種外設接口,它使用SD的I/O接口來鏈接外圍設備,並經過SD上的I/O數據接口與這些外圍設備傳輸數據。如今已經有不少手持設備支持SDIO功能,並且許多SDIO外設也被開發出來,目前常見的SDIO外設有:WIFI Card、GPS Card、 Bluetooth Card等等。

 

eMMC

        eMMC全稱Embedded MultiMediaCard,是MMC協會所制定的內嵌式存儲器標準規格,主要應用於智能手機和移動嵌入式產品等。eMMC是一種嵌入式非易失性存儲系統,由閃存和閃存控制器兩部分組成,它的一個明顯優點是在封裝中集成了一個閃存控制器,它採用JEDEC標準BGA封裝,並採用統一閃存接口管理閃存。

        eMMC結構由一個嵌入式存儲解決方案組成,帶有MMC接口、快閃存儲設備及主控制器,全部這些由一個小型BGA封裝。因爲採用標準封裝,eMMC也很容易升級,並不用改變硬件結構。

        eMMC的這種將Nand Flash芯片和控制芯片封裝在一塊兒的設計概念,就是爲了簡化產品內存儲器的使用,客戶只須要採購eMMC芯片放進產品中,不須要處理其它複雜的Nand Flash兼容性和管理問題,減小研發成本和研發週期。

3.MMC 模塊總線模型
mmc子系統涉及到三條總線,以下:

Host驅動相應的driver和device掛載在Linux內核內置的虛擬抽象總線platform_bus_type。二者的匹配採用名稱匹配的方式,即driver和device二者的name同樣則認爲該device對應該driver,這裏是」rda,hsmmc」。

Card驅動相應的driver和device掛載在mmc本身建立的虛擬總線mmc_bus_type下,直接匹配。

Sdio驅動相應的driver和device掛載在mmc本身建立的虛擬總線sdio_bus_type下,ID匹配。

 

按照時間前後順序,mmc模塊中bus,device和driver的註冊順序以下:

3.1.host device
linux kernel 經過下圖所示流程,解析dts文件mmc模塊相關配置,生成名爲rda,hsmmc的platformdevice,掛在platform平臺總線上。

 

 

 

3.2.mmc_bus, sdio_bus
mmc core初始化時,文件core.c中的subsys_initcall(mmc_init), 調用mmc_register_bus和sdio_register_bus註冊mmc bus 和sdio bus,具體如圖下圖所示。

 

 

 

由上圖能夠看出,任何掛在mmc總線上的device 和driver都會匹配,而掛在sdio總線上的設備和deriver須要經過id進行匹配。

3.3.card driver
    card目錄下,block.c中module_init(mmc_blk_init)調用mmc_register_driver函數建立mmcblk driver,並將之掛載到mmc_bus_type總線的driver list鏈表上。

    注意:mmc core提供了mmc_test.c做爲mmc driver的測試文件。mmc_test.c中,module_init(mmc_test_init)函數中,調用mmc_register_driver函數建立了mmc_test driver,而且將之掛載在mmc_bus_type總線的driver list鏈表上。

mmc模塊若是須要使用mmc_test功能,須要把CONFIG_MMC_BLOKC宏關閉,而後把CONFIG_MMC_BLOCK=y。不然,card將會匹配blockdreiver,不會再次匹配mmc_test  driver,具體見下圖。

 

 

 

3.4.host driver
    host目錄下,rda_sgmmc.c文件中,module_init(rda_mmc_init),把rda_mmc_init連接到相應的init字段中。在初始化時候,執行rda_mmc_init(),調用platform_driver_register註冊名爲rda,hsmmc的host driver,此driver掛在platform虛擬總線上。

 

3.5. card device
在第四步中,hostdriver註冊成功後,platform總線會把此driver和1中註冊的host dev匹配,而後執行host driver的probe 函數rda_mmc_probe。該函數中完成mmc_alloc_host申請mmc host 結構體,而後完成初始化,以及中斷等的申請等,最後調用mmc_add_host完成card 的探測,若是card存在,生成card device。

由於sd卡支持熱插拔,因此在probe階段,sd卡沒有插入的狀況下,不會生成card device。而是在後期插入sd卡時候,產生中斷,中斷處理函數中調用mmc_detect_change函數探測sd card是否存在,完成初始化而且生成card device。具體見下圖。

 

從上圖中,咱們並無看到card設備的生成。這是由於咱們經過detect work完成了sd,mmc,或sdio設備的初始化,而且生成相應的block設備,具體見下圖:

 

 

 

3.6. card driver執行
    在第五步中,card device已經掛到mmc總線上,此時會匹配到carddriver,自動執行driver 的probe函數。若是在3中,CONFIG_MMC_BLOCK=y,則會執行mmc_blk_probe,生成block設備。若是CONFIG_MMC_BLOCK=n, CONFIG_MMC_TEST=y,則會自動執行mmc_test_probe。

綜上所述,設備經過dts文件把mmc host dev(platform設備)掛在虛擬平臺總線上,而後註冊sdio和mmc總線,緊接着註冊card driver,掛在mmc總線上。其後,在host目錄下,咱們本身的driver中,調用platform_driver_register註冊platform平臺驅動,即host driver。此時,platform會匹配host dev 和driver,執行driver的probe函數,經過mmc_add_host註冊card

device,掛載到mmc總線上。最後,mmc總線會匹配card dev 和driver,執行card driver的probe函數,生成block設備或者mmc_test相關的屬性文件。

4.MMC 協議實現
到此爲止,mmc 的相關框架已經介紹清楚了。由於在框架明瞭的狀況下,驅動已經很簡單了,因此後面僅僅會簡單介紹一下mmc驅動。

sd,sdio或者mmc的協議實如今哪裏呢?能夠在圖5中看到,初始化就是在mmc_attach_sdio, mmc_attach_sd或者mmc_attach_mmc函數中。

1.初始化時候,首先發送cmd0使卡進入idle狀態;

2.接着發送cmd8,檢測卡是否SD2.0。SD1.1不支持cmd8,所以若是發送cmd8無迴應,則卡爲SD1.1,不然就是SD2.0;

3. mmc_attach_sdio發送cmd5讀取OCR 寄存器,判斷是否爲sdio,若是是就綁定sdio總線;

4. mmc_attach_sd發送命令acmd5五、cmd41,使卡進入工做狀態。若是經過,則認爲是sd卡,綁定sd總線。mmc卡不支持acmd55,和cmd41,因此若是無迴應,則認爲卡是mmc卡;

5. mmc_attach_mmc中發送命令1,判斷是否爲mmc卡,若是迴應,則綁定mmc總線。若是cmd1無迴應,則不是mmc卡。

具體實現和協議強相關,只要對照協議來看,很簡單,就再也不多述了。
    ls kernel/drivers/mmc,能夠看到以下三個目錄:

card core host

card目錄下主要是完成了上章中所述的mmc總線driver,也就是2.3所述的card driver,

core目錄主要是完成了上章中sdio bus和mmc bus註冊,card device的添加,host目錄就是具體的host driver的添加了。

 

在mmc driver中,須要作的很重要的一部就是實現mmc_host_ops,在probe函數中把其賦值給mmc_host 結構體的ops變量,rda_sgmmc.c的mmc_host_ops實現以下:

static const struct mmc_host_ops rda_mmc_ops= {

       .request        = rda_mmc_request,

       .get_ro         = rda_mmc_get_ro,

       .get_cd         = rda_mmc_get_cd,

       .set_ios        = rda_mmc_set_ios,

        .enable_sdio_irq =rda_mmc_enable_sdio_irq,

};

 

其中,request函數,主要實現命令發送,數據的讀寫;set_ios主要用來設置數據速度,mmc相位,power mode 和data bus width;get_cd用來檢測設備是否存在;get_ro用來判斷mmc是否爲read-only card;enable_sdio_irq是用來使能或者關閉sdio中斷。

 

mmc dev正常讀寫的時候調用流程是怎麼樣呢?怎麼和上面註冊的mmc_host_ops關聯起來呢?塊設備的讀寫會被放入request_queue。見下圖:

 

其中,blk_fetch_request等涉及到block文件的讀寫實現方式,這裏再也不敘述,有興趣的話你們能夠看看代碼。

由此,mmc card dev就和上面註冊的mmc_host_ops關聯起來了。

5.MMC test driver 使用
在第二章介紹card driver時候已經介紹到了mmc test driver了。若是要使用mmc_test function,能夠按照以下步驟:

1.CONFIG_MMC_BLOCK=n,CONFIG_MMC_TEST=y。或者CONFIG_MMC_BLOCK=y, CONFIG_MMC_TEST=y。若是選用後一種配置,須要再系統起來後,在總線driver中手動bind和unbind,見後面;

2.CONFIG_DEBUG_FS=y,CONFIG_DEBUG_KERNEL=y,這兩項在咱們項目的kernel的defconfig中已經配置,因此不須要進行改動;

3. mount -t debugfs none /sys/kernel/debug,這個咱們的project中已經掛載了,不須要進行改動;

完成上面三項後,啓動系統,若是在步驟1中CONFIG_MMC_BLOCK=y,那麼須要先執行執行以下操做:

etau:/ # ls sys/bus/mmc/devices/                                              

mmc0:aaaa

 

etau:/sys/bus/mmc/drivers # ls

mmc_test/ mmcblk/

 

etau:/sys/bus/mmc/drivers # cd mmcblk/                                         

etau:/sys/bus/mmc/drivers/mmcblk # ls -al

total 0

drwxr-xr-x 2 root root    0 2000-01-01 01:27 .

drwxr-xr-x 4 root root    0 2000-01-01 01:27 ..

--w------- 1 root root 4096 2000-01-01 01:28bind

lrwxrwxrwx 1 root root    0 2000-01-01 01:28 mmc0:aaaa ->../../../../devices/soc0/20a50000.rda-mmc0/mmc_host/mmc0/mmc0:aaaa

--w------- 1 root root 4096 2000-01-01 01:28uevent

--w------- 1 root root 4096 2000-01-01 01:28unbind

 

etau:/sys/bus/mmc/drivers/mmcblk #echo –n mmc0:aaaa> unbind

etau:/sys/bus/mmc/drivers # cdmmc_test/                                      

etau:/sys/bus/mmc/drivers/mmc_test # ls

bind uevent unbind

 

etau:/sys/bus/mmc/drivers/mmc_test #echo –n mmc0:aaaa> bind

 

完成上述操做後,完成了mmc0:aaaa和mmc_test driver的綁定。後續步驟徹底一致,以下:

 

etau:/sys/kernel/debug/mmc0/mmc0:aaaa# cat testlist                          

1:     Basic write (no data verification)

2:     Basic read (no data verification)

3:     Basic write (with data verification)

4:     Basic read (with data verification)

5:     Multi-block write

6:     Multi-block read

7:     Power of two block writes

8:     Power of two block reads

9:     Weird sized block writes

10:    Weird sized block reads

11:    Badly aligned write

12:    Badly aligned read

13:    Badly aligned multi-block write

14:    Badly aligned multi-block read

15:    Correct xfer_size at write (start failure)

16:    Correct xfer_size at read (start failure)

17:    Correct xfer_size at write (midway failure)

18:    Correct xfer_size at read (midway failure)

19:    Highmem write

20:    Highmem read

21:    Multi-block highmem write

22:    Multi-block highmem read

23:    Best-case read performance

24:    Best-case write performance

25:    Best-case read performance into scattered pages

26:     Best-case write performance from scatteredpages

27:    Single read performance by transfer size

28:    Single write performance by transfer size

29:    Single trim performance by transfer size

30:    Consecutive read performance by transfer size

31:    Consecutive write performance by transfer size

32:    Consecutive trim performance by transfer size

33:    Random read performance by transfer size

34:    Random write performance by transfer size

35:    Large sequential read into scattered pages

36:    Large sequential write from scattered pages

37:    Write performance with blocking req 4k to 4MB

38:    Write performance with non-blocking req 4k to 4MB

39:    Read performance with blocking req 4k to 4MB

40:    Read performance with non-blocking req 4k to 4MB

41:    Write performance blocking req 1 to 512 sg elems

42:    Write performance non-blocking req 1 to 512 sg elems

43:    Read performance blocking req 1 to 512 sg elems

44:    Read performance non-blocking req 1 to 512 sg elems

45:    Reset test

而後執行etau:/sys/kernel/debug/mmc0/mmc0:aaaa# echo 1 > test能夠看到測試結果:

[314034.644348] mmc0: Starting tests of cardmmc0:aaaa...

[314034.645080] mmc0: Test case 1. Basicwrite (no data verification)...

[314034.647583] mmc0: Result: OK

[314034.647827] mmc0: Tests completed.

 

至此,mmc模塊就告一段落了。————————————————版權聲明:本文爲CSDN博主「kivy_xian」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/kivy_xian/article/details/53333831

相關文章
相關標籤/搜索