韓大衛@吉林師範大學
2015.1.27.
轉載請表明出處
*********************************************
uboot 和linux 下flash 的寫入速度不一樣, 主要原因是兩者使用的延遲最小延時時間不一樣. linux比較大. 原因如下:
flash 晶片手冊中有兩個重要的時間參數:
第一個是一般的塊寫入逾時時間, 記為time-ty, 第二個是最大的塊寫入逾時時間, 記為time-max.
假設有兩個CFI nor flash 晶片, A 的time-ty 為10, B 的time-ty 為8 ; A, B 的time-max 都為2.
下面會看到, 在uboot 下, A, B 的flash 寫入速度差異很小. 但在linux 下, A和B的flash 寫入時間有很大的差異. 假設時鐘均穩定.
uboot中的算法:
1,先得出逾時時間 info->buffer_write_tout :
info->buffer_write_tout = (((1 << time-ty) * (1 << time-max)) + 999) / 1000;
A的flash : time-ty = 10, time-max = 2, 計算得 5 ms
B 的flash : time-ty = 8, time-max = 2, 計算得 2 ms
2, 再使用 info->buffer_write_tout :
while (1) {
...
if (ready) //這個标志表示寫指令已經完成,
break;
if (get_timer() > info->buffer_write_tout) {
return ERR_TIMOUT;
}
udelay(1); //每次使用1 us 的延時, 直到出現 ready 退出循環. 一般地, 寫指令的執行時間不會等到buffer_write_tout這麼長時間就會成功, 是以很塊快跳出循環
}
uboot寫flash 時使用的延時都是在 us 級别的. 是以使用者幾乎感覺不到flash "Typical timeout for maximum size buffer program " 時間參數不同所造成的影響.
linux 下的延時時間:
1, 先得出chip->buffer_write_time
chips[i].buffer_write_time = 1<<time-ty;
A : buffer_write_time = 1024 us
B : buffer_write_time = 256 us
2, linux 使用 buffer_write_time 作為最小延時函數的變量 :
static inline void cfi_udelay(int us){
if (us >= 1000) { //A的buffer_write_time 為1024, 使用msleep 延時, 時間機關為 ms
msleep((us+999)/1000);
} else {
udelay(us); // B 的buffer_write_time 為256, 使用udelay 延時, 時間機關為 us
cond_resched();
}
}
可以看到, 由于A和B 的flash 的 "Typical timeout for maximum size buffer program " 參數不一樣. 會導緻了底層使用的延時函數差異很大.
這就是在linux 下flash 的寫入時間會有很大的差異的原因.
備注:
一個 flash 晶片執行個體資訊:
vendor ID is 2 (AMD 系列)
manufacturer id is 0x89
device id is 0x7e
device id2 is 0x2201
cfi version is 0x3133
晶片大小: 33554687 B, 32MB
扇區個數 256 個
扇區大小/一次可以緩存擦寫大小: 131072 B, 128KB
緩存寫等待時間: 1024 us
緩存寫最大時間: 4096 us
以上可以參考uboot/linux/openwrt的源代碼:
uboot:
drivers/mtd/cfi_flash.c (cfi 規範的flash驅動)
common/cmd_flash.c (uboot 的upgrade 指令的實作)
linux:
drivers/mtd/chips/cfi_probe.c (CFI 規範通用驅動入口)
drivers/mtd/chips/cfi_cmdset_0002.c (AMD 規範flash驅動)
arch/mips/cavium-octeon/flash_setup.c (octeon平台flash驅動)
drivers/mtd/cmdlinepart.c (解析分區)
drivers/mtd/mtdpart.c (系統mtd操作調用中心)
openwrt:
package/mtd/src/mtd.c (mtd 工具的源代碼)