用TF卡作为bb的文件系统载体,在使用过程中,偶尔会遇到文件系统只能读取不能写入的错误,该问题轻则导致当前运行的程序出错,重则直接导致操作系统崩溃。通过执行dmesg命令,打印系统错误日志,发现以下错误信息:
mmcblk0: error -110 transferring data, sector 4126233, nr 8, card status 0xc00
error -110为mmc访问超时错误。上网google一下,发现OMAP系统有点挑TF卡,价格便宜、低端一些的卡比较容易出这个错。我用的Kingmax Class 10的卡很容易出这个问题,但换成Kinston Class 10的卡,就基本上没有出过错。当然,TI给出了官方的解决方法,可以通过修改mmc驱动,将延迟参数修改为最大值,来避免该错误。
具体解决办法:
STEP 1:修改Linux内核的mmc驱动
该驱动在Linux内核源码的drivers/mmc/host/omap_hsmmc.c文件中,以下为替换的代码部分:
drivers/mmc/host/omap_hsmmc.c | 30 +++++-------------------------
1 files changed, 5 insertions(+), 25 deletions(-)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index fd0c661..afd7292 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1481,11 +1481,8 @@ static int omap_hsmmc_start_dma_transfer(struct
omap_hsmmc_host *host,
return 0;
}
-static void set_data_timeout(struct omap_hsmmc_host *host,
- unsigned int timeout_ns,
- unsigned int timeout_clks)
+static void set_data_timeout(struct omap_hsmmc_host *host)
{
- unsigned int timeout, cycle_ns;
uint32_t reg, clkd, dto = 0;
reg = OMAP_HSMMC_READ(host->base, SYSCTL);
@@ -1493,25 +1490,8 @@ static void set_data_timeout(struct omap_hsmmc_host
*host,
if (clkd == 0)
clkd = 1;
- cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
- timeout = timeout_ns / cycle_ns;
- timeout += timeout_clks;
- if (timeout) {
- while ((timeout & 0x80000000) == 0) {
- dto += 1;
- timeout <<= 1;
- }
- dto = 31 - dto;
- timeout <<= 1;
- if (timeout && dto)
- dto += 1;
- if (dto >= 13)
- dto -= 13;
- else
- dto = 0;
- if (dto > 14)
- dto = 14;
- }
+ /* Use the maximum timeout value allowed in the standard of 14 or 0xE */
+ dto = 14;
reg &= ~DTO_MASK;
reg |= dto << DTO_SHIFT;
@@ -1534,13 +1514,13 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host,
struct mmc_request *req)
* busy signal.
*/
if (req->cmd->flags & MMC_RSP_BUSY)
- set_data_timeout(host, 100000000U, 0);
+ set_data_timeout(host);
return 0;
}
OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
| (req->data->blocks << 16));
- set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
+ set_data_timeout(host);
if (host->use_dma) {
ret = omap_hsmmc_start_dma_transfer(host, req);
注:-号表示删除该行;+号表示添加该行
STEP 2:重新编译替换uImage
完成修改后,重新编译内核,生成uImage文件,替换掉老的uImage。然后,重启,进行了若干天的压力测试,基本上就没有再出错了。