Linux mtd子系統專欄分析之四 NANDFLASH驅動模型概述

      在上幾篇文章中,基本上理清了mtd子系統的架構,並將mtd子系統對上的抽象及相應的函數接口進行了說明。從本章開始,主要以nandflash爲例,介紹具體類型的閃存設備驅動模型是如何銜接mtd的抽象層,並完成對閃存芯片的讀寫操作。

 

 

nandflash概念

    針對一個nandflash,包括塊、頁;一個flash包含多個塊;而一個塊又包含多個頁。針對每一個頁而言,又包含對應的spare area,主要用於存儲數據校驗信息(即ecc信息),用於糾錯;也存儲壞塊標誌(一個塊中僅有一個頁對應oob存儲壞塊標誌)。而針對文件系統而言,具體到yaffs2文件系統,也會將其文件系統的組織信息信息存儲到oob中。

 

nandlfash及nand controller的特點

針對nandflash,我們需要從nandflash自身特性關注以下幾點:

  1. nandflash存在bit翻轉的情況,因此需要相應的糾錯算法,而糾錯與檢測操作由具體的nandflash controller實現,可以實現硬件糾錯(如漢明糾錯、bch4、bch8糾錯算法等),也可使用軟件糾錯算法;
  2. Nandflash controller與nandflash之間通信命令是統一的,即針對一個nandflash controller可以與任意一個nandflash通信;
  3. 針對每一個nandflash controller,訪問該nandflash controller的方式有所不同,如寄存器定義、讀寫地址等有所不同;
  4. nandflash的擦除次數由顯示(10萬次),因此在使用過程中,存在壞塊

 

 

 

 

Linux nandflash驅動模塊抽象

而針對nandflash驅動模塊而言,基本上也就是按照上面的特點進行抽象,其驅動模型大概可分爲如下幾部分:

  1. 針對每一個nandflash controller,抽象結構體變量struct nand_chip;所有的接口以及變量均由該結構體去實現關聯
  2. 基於nandflash controller與nandflash的通信命令是統一的,抽象出統一的讀、寫、擦除等接口,作爲mtd_info的_write、_read、badblock等接口;
  3. 基於nandflash存在bit翻轉且每一個nandcontroller實現的糾錯算法不同,因此每一個nandflash controler需要實現自己的糾錯接口、校驗接口等;
  4. 針對每一個nandflash controller而言,需要提供訪問該nandflash controller的接口(包括向nandflash發送命令的接口、讀寫數據接口(通過nandflash controller,間接實現訪問nandflash))。

 

       在驅動模塊中,主要抽象了nand_chip結構體,以及對mtd層而抽象出來的統一的處理接口。下面是nand_chip結構體、對應的抽象接口以及mtd_info之間的關聯關係圖。下面我們來具體說明它們的關聯,並與nandflash驅動模塊進行關聯說明。

  1. mtd_info->priv指向nand_chip,實現mtd與nand flash驅動模塊的關聯;
  2. nandflash驅動模型對上抽象出統一的接口,用於抽象針對nandflash的操作(與vfs接口抽象、mtd模塊向上抽象統一讀寫接口類似),並賦值給mtd_info中對應的函數指針(即mtd_info的_erase、_write、_read等),爲nand_write、nand_read、nand_read_oob等等,此處的讀寫數據接口,可讀取任意長度的數據。
  3. 因nandflash存在糾錯、校驗等因此nandflash驅動模塊又抽象針對ecc的結構體struct nand_ecc_ctrl,而該結構體中定義了讀寫一頁數據的接口(針對nandflash而言,讀寫的單位爲頁,而擦除的單位爲塊大小),而不同的nandflash控制器,其支持的校驗及糾錯方式有所不同,因此這部分接口需要各nandflash控制器驅動實現。
  4. Nand_chip本身也提供了操作nandflash的接口,包括read_byte、read_buf、write_buf、block_bad等接口,這部分接口相對nand_ecc_ctrl的接口而言更加底層,實現一個字節或者多個字節的讀寫,同時也提供nand_chip芯片選擇等接口以及命令控制相關的接口等。而這部分接口也是和nand_controller所息息相關的,因此也有相應的nand_controller驅動實現(當然若nand_controller沒有特殊的操作,則可以使用nandflash模塊已定義的通用接口)

通過以上幾步即完成了mtd、nand_chip的關聯,同時也就完成了mtd_write、mtd_read接口通過nand_write、mtd_read接口,然後再到nand_ecc_ctrl->read_page/write_page接口,最終調用nand_chip->read_buf/write_buf,實現與nandflash的讀寫通信。

 

 

Nandflash驅動模塊相關的數據結構

        針對nandflash驅動模塊,剛纔我們已經大致說明了幾個數據結構nand_chip、nand_ecc_ctrl,下面我們詳細說明下nandflash驅動模塊相關的數據結構。針對linux內核各子模塊而言,理解了其數據結構抽象,基本上也就對模塊實現理解了60%左右,因此針對linux內核各模塊的學習,強烈建議好好理解其相應的數據結構及它們之間的關聯。nandflash驅動模塊的結構體包括nand_chip、nand_onfi_params、nand_hw_control、nand_ecclayout、nand_ecc_ctrl、nand_hw_control、nand_bbt_descr等,這些結構體以nand_chip爲主。下面我們逐一說明

nand_chip

該結構體定義了nand_controller的屬性以及接口,主要包括:

  1. 與nand_controller通信的地址空間(包括命令下發、讀寫操作的接口,即IO_ADDR_R/IO_ADDR_W);
  2. 通過nand_controller讀寫flash數據的接口(read_byte、read_word、write_buff、read_buff,芯片選擇接口select_chip、壞塊判斷及壞塊標記接口block_bad、block_markbad,向nandflash發送命令的接口cmd_ctrl、cmdfunc、waitfunc、erase_cmd,壞塊表相關的接口scan_btt等、支持onfi規範的nandflash相關的操作接口及屬性等);
  3. 芯片的個數、芯片的總大小、頁大小、block大小、壞塊標記在oob的位置及個數等
  4. oob中ecc位置及大小相關的結構體變量nand_ecclayout
  5. ecc糾錯相關的接口及屬性的結構體變量nand_ecc_ctrl。

 

 

nand_ecc_ctrl

該結構體變量的定義如下,主要定義了一個nand_controller所支持的ecc計算、校驗及糾錯相關的內容:

  1. 定義了ecc類型(無、軟件ecc、硬件ecc等);
  2. 定義了一個page需要進行ecc計算的次數,每次ecc計算對應的數據大小(如每512字節進行一次ecc計算),每次ecc計算所產生的ecc字節數等等;
  3. 定義了ecc操作相關的接口(若開啓ecc接口hwctl、計算ecc值接口calculate、糾錯接口correct(主要用於讀取數據時,若讀取數據計算的ecc值與存儲在oob中的ecc不匹配,則需要糾錯,如bch8糾錯算法,則每512字節可最多發現9bit錯誤,最大糾正8bit數據等),並提供了讀寫一頁數據的接口,主要供mtd_info->_read/_write調用,即被nand_read、nand_write調用,還包括讀寫oob數據的接口,在之前我們說明oob主要存儲ecc信息,但針對yaffs2文件系統,也存儲文件系統相關的信息,因此針對掛載yaffs2文件系統而言,要在boot和kernel中確認好yaffs2文件系統信息存儲在oob中的起始位置與大小,並保持一致)

 

 

nand_ecclayout

     該結構體主要用於說明ecc值在oob中存儲的位置及大小,在每一個nand_controller的驅動中,會定義不同page size對應的nand_ecclayout,用於指明該page size對應的oob中的ecc的位置信息及大小等。

  1. eccbytes表明了ecc數據的大小,這個針對選擇的不同的糾錯算法有所不同,比如bch4和bch8相比,每512字節所產生的ecc數據大小則是不同的(bch8產生的ecc大概爲13bytes@per512bytes)。
  2. eccpos則用於說明每一個ecc對應的位置;
  3. oobavail則說明該oob除去ecc字節,所剩餘的可用字節;
  4. oobfree則用於說明3中剩餘可用字節的位置。

 

        該結構體變量是一個非常重要的變量,需要保證bootloader和kernel中定義大小及pos是完全相同的,否則則可能導致系統無法在kernel中使用。另外,若使用yaffs2文件系統,則在進行nandflash芯片選型時,需要確認nandflash的oob在存儲完ecc後有足夠的空間存儲yaffs2文件系統相關數據的空間(雖然也可以將yaffs2文件系統相關的信息存儲page中,但那樣會導致系統的讀寫時間變慢)。

nand_hw_control

        該結構體變量主要定義了鎖、等待隊列,主要用於nandflash操作臨界問題的解決,如當一個nandcontroller處於讀操作時,若系統又觸發了針對該nandcontroller的寫操作,則將該寫操作放入等待隊列中,當讀操作完成後喚醒該等待隊列實現寫操作。

struct nand_hw_control {

spinlock_t lock;

struct nand_chip *active;

wait_queue_head_t wq;

};

 

       nand_bbt_descr與nand_onfi_params主要用於壞塊表和onfi規範的nandflash,針對壞塊表,我之前沒有使用過,個人感覺可以不使用壞塊表,即使使用壞塊表,也就使用內存壞塊表即可,也沒有必要在nandflash中預留一些塊用於存儲壞塊表(個人感覺)。而nand_onfi_params主要用於支持onfi規範的nandflash,此處也不再介紹。

 

         以上即爲本篇文章的內容,主要介紹了nand_chip的抽象說明以及接口間的關聯,並說明了nandflash驅動模塊相關的結構體變量。下一篇文章主要說明相應的操作接口,以及nandcontroller驅動的初始化過程等內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章