关于sdcard读写速率慢的问题排查

1.前言

前段时间测试同事在用androbench测试sdcard速率时,发现我们的机器总是比对比机器(三星S7)在读写速率方面慢很多,我们的机器读取速率基本在21MB/S左右,而对比机器一般在40MB/S左右。本文就介绍如上问题分析解决的整个过程。

2. 启动时的卡模式识别

通过启动时的打印可以看到我们的机器在识别卡的速率模式时,主要有两种情况:
卡识别情况一
编辑
通过三星S7对比样机的bugreport可以看到,同样一张卡(sandisk class10 32G UHI卡),三星 s7识别为ultra high speed DDR50
在这里插入图片描述
通过打印我们样机的dmesg, 发现我们的机器识别为high speed
通过如上的打印,很容易就定位到问题:由于卡识别的模式不同,自然速率也就不同,DDR50模式的工作速率为50MB/S,而high speed模式的工作速率为25MB/s。于是跟原厂最终的沟通结果是由于卡自身的原因导致报给MMC控制器的模式有问题,通过打印的结果也确实是上报给卡的最高速率为high speed(见下文),问题就此搁浅。
卡识别情况二
换另一张卡(TOSHIBA class10 32G UHI卡),我们的机器和对比机在启动时均能检测到卡的速率模式为DDR50,但是在实际速率测试时基本读速率为21MB/S, 偶尔也能测到39MB/S。
本文就以第二张卡的情况为例进行分析。
这里先对获取卡的速率模式,作一下简单说明,获取SD卡速率模式主要是依靠CMD6来完成,CMD6有两种功能一个是获取,另外一个是设置,同时还可以指定功能组,此处主要是利用CMD6的读取功能,功能组为1,也即是获取卡的速率模式。
对于上述卡识别情况一,通过在驱动中mmc_read_switch中加入打印,可以看到status[13] 返回的值为0x3,它就是CMD6 group1 查询模式时返回的SD卡支持的速率模式。
对应下表,0x3表示bit0和bit1置位,也就是支持Default和High-speed模式,不支持DDR50模式
在这里插入图片描述
注:对于UHI的卡,如果当前信号电压为3.3v, 则读取到的速率模式最高只能为HIGH SPEED/SDR25, 如果为1.8V, 才可以获取到所有支持的速率模式

3. 分析过程

对于第二张卡在初始识别时,与对比机器检测到为同一张卡,但是在测试时读取速率大多为21MB/S, 概率性的出现39MB/S, 而对比机器都是40MB/S左右,可以发现我们的问题就在于为何会概率性的读取速率为21MB/S,而让机器读取速率能稳定达到39MB/S以上是我们的目标。
读取速率问题跟整个IO栈都有关系,一开始不知道问题在哪里,就只能先通过工具,来缩小问题的范围。

3.1 fio测试

fio -direct=1 -iodepth=128 -rw=read -ioengine=libaio -bs=4k -numjobs=1 -runtime=30 -filename=/dev/block/mmcblk0p1 -name=test
首先通过fio测试来确认一下存储带宽的利用率,通过测试发现存储带宽利用率为98.5%,基本上接近满载,因此可以确认存储器件已经全负荷运转,不存在传输带宽利用不够的问题,同时通过fio进行裸分区测试可以进一步减少性能损耗,更接近器件的真实速率。

3.2 blktrace测试

通过blktrace加fio测试,来缩小问题的范围。
通过重现此问题,发现此卡有概率性读速率达到39MB/s的情况,抓取了此种情况的blktrace。同时抓取了读速率为21MB/S的blktrace进行比较(见下图),发现采用同样的fio测试命令,39M时的Q2C和D2C时间均小于21M时的Q2C和D2C,这说明21M时的耗时是发生在驱动及器件层,通过3.1 又知道传输带宽利用率较高,因此基本就确认不是由于文件系统层或block层导致的传输问题,而是由于驱动层及器件层导致的传输慢的问题。
在这里插入图片描述
读速率为21m时的D2C,横坐标为时间轴,纵坐标为D2C时间
在这里插入图片描述
读速率为21m时的Q2C,横坐标为时间轴,纵坐标为Q2C时间
在这里插入图片描述
读速率为39m时的D2C,横坐标为时间轴,纵坐标为D2C时间
在这里插入图片描述
读速率为39m时的Q2C,横坐标为时间轴,纵坐标为Q2C时间
注:如上对于blktrace的数据比较,也要考虑到request的大小,如果request大小不同,当然完成时间也不一样,这个可以通过下面的mmc trace event来进一步确认request的大小

3.3. mmc trace event

进一步通过抓取驱动层关于mmc的trace event,并对每个请求的执行时间进行统计,绘制散点图。通过mmc trace event抓取的信息分析,发现读取速率21MB/S时的每个request读数据完成时间均大于39M的。
在这里插入图片描述
读速率为 21MB/S时的request处理时间,横坐标为时间轴,纵坐标为request处理时间
在这里插入图片描述
读速率为 39MB/S时的request处理时间,横坐标为时间轴,纵坐标为request处理时间
我们知道MMC在读取操作时首先发送读取命令,然后执行数据读取,当数据读取命令完成和数据读取完成都会触发中断,并分别记录一条trace event,通过计算这两条trace event的时间差,可以作为一个request的器件读取时间,提取每个request的读取时间来作散点图,可进一步确认两种读取速率的差异。
因此通过上面的分析进一步确认了数据传输速率慢的原因就是器件的传输速率慢,这其中有可能的原因是:clock频率低,dev frequence调频,gating/ungating,通过对这些可能原因做调整基本没有改善。

3.4. 查看/sys/kernel/debug/mmc0/ios节点

在fio测试时,通过ios节点来查看卡的工作模式,发现卡在39MB/S读取速率时是工作在1.8V的工作模式,而卡在21MB/S读取速率时是工作在3.3v的工作模式。根据SD卡的规范,高速必须工作在1.8V,低速工作在3.3v,因此要想跑DDR50模式,必须首先将卡切换到1.8V,因此这里就要分析为何有时卡能切换到1.8v, 有时却不能。
在这里插入图片描述
读速率为 39MB/S时的ios信息
在这里插入图片描述

读速率为 21MB/S时的ios信息

3.5. 电压切换

通过进一步定位可以发现在如下代码中切换电压时,由于检测sdcard处于busy状态(实际是检测data0是否为低电平,低电平为busy状态),导致切换电压失败
在这里插入图片描述

我们根据spec中关于电压切换的描述如下:
在这里插入图片描述
实际测量电压切换波形如下,其中C1(黄色)为CLK,C2(红色)为CMD, C4(绿色)为DATA0
在这里插入图片描述
可以看出与spec中有如下差异:
切换命令后电压任然为3.3V,也即是在clk从stop重新变为start时,高电平仍然为3.3v,这显然是与spec不符合的,spec中约定clk从stop重新变为start时,高电平将为1.8V。
正常情况下,在切换电压成功后,信号电压之后的工作都将切换到1.8V, 然而通过示波器看却没有,为何?我们要找到电压切换的代码去看下。

3.6 电压切换流程

通过调用栈可以看到如下的电压切换流程:

[    7.538086] [<6>][78, kworker/6:1] sdhci_start_signal_voltage_switch+0x68/0x2d8
[    7.538087] [<6>][78, kworker/6:1] mmc_host_set_uhs_voltage+0x134/0x270
[    7.538088] [<6>][78, kworker/6:1] mmc_set_uhs_voltage+0xf8/0x1e8
[    7.538091] [<6>][78, kworker/6:1] mmc_sd_get_cid+0x128/0x230
[    7.554775] [<6>][78, kworker/6:1] mmc_sd_init_card+0x58/0x4c0
[    7.554777] [<6>][78, kworker/6:1] mmc_attach_sd+0x108/0x1c0
[    7.554779] [<6>][78, kworker/6:1] mmc_rescan+0x244/0x328
[    7.574050] [<6>][78, kworker/6:1] process_one_work+0x204/0x458
[    7.574051] [<6>][78, kworker/6:1] worker_thread+0x304/0x480
[    7.574052] [<6>][78, kworker/6:1] kthread+0x118/0x128
[    7.574053] [<6>][78, kworker/6:1] ret_from_fork+0x10/0x18

sdhci_start_signal_voltage_switch函数中在设置1.8v时会通过sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2)来触发power irq,由sdhci_msm_pwr_irq>sdhci_msm_set_vdd_io_vol函数完成电压切换, 这里我们惊奇的发现无论设置为多少的电压,示波器量到的都是3.3V左右,而打印的电压值都是1.8V,这个让我们怀疑是电压配置有问题,去查下dts

3.7 dts电源检查

通过反编译最后的fdt文件,发现vdd io的电压范围值1.8~1.8, 也就是只能设置为1.8v,这路电压应该是1.8V~3.3V才对。对照原理图发现是将卡插拔检测的电压源配置为VDD IO的电压源导致的问题。通过修改DTS中关于此部分的设置,读写速率正常

4. 总结

本文主要总结了sdcard速率问题的分析思路,主要的思路就是通过逐步缩小问题范围,最终定位到问题点。分析过程中运用了一些工具,这些工具对定位问题起到很重要的作用,但是除了工具,分析代码的流程以及对SD规范的了解也是必不可少的。当然有些检查点是一开始就要去检查的,比如一开始就要检查dts配置是否正确,但是由于卡本来是可以工作的,所以阴差阳错的没有考虑到这个问题。另本问题在测试速率为21m和39M的情况下,是否可以想象为2倍的关系,进而直接证实猜测。
本次调试得到李大和各位的耐心指导,在此表示感谢!

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值