emmc kernel driver流程

来源:互联网 发布:网络变压器厂商 编辑:程序博客网 时间:2024/06/03 23:40
首先执行的第一个函数:mmc_blk_register(__init触发)
1.完成了mmc block设备的注册,可以在proc/devices下看到这个Block设备
2.将mmc_driver 和mmc_bus_type进行绑定,这样将mmc_bus_probe和mmc_blk_probe联系起来了
第二个函数:sprd_sdhc_probe(__init触发)
1.mmc_allock_host函数:初始化host(mmc_host )结构体的部分内容,将mmc_host的class属性赋值给host,并建立INIT_DELAYED_WORK(mmc_rescan)
2.建立mmc_host *mmc 和 sprd_sdhc_host * host 之间的关系,并读取dt获取参数初始化sprd_sdhc_host *host
3.通过sprd_set_mmc_struct 完成对mmc_host *mmc结构体的初始化
4.调用add_mmc_host 注册一种说到的class(sys/class/mmc_host),并启动delayed work,调用mmc_rescan去初始化emmc
第三个函数:mmc_rescan
1.mmc_try_rescan_freq 尝试使用不同的频率去初始化设备.里面会初始化emmc  sdcard  wifi芯片
第四个函数:mmc_attach_mmc
1.按照初始化流程初始化emmc card,并在mmc_init_card里面完成mmc_card *card的初始化同时完成了mmc_host *host和mmc_card * card之间的拥有关系
2.调用mm_add_card将mmc设备添加到总线上,首先在sys/class/mmc_host/mmc0/下添加了mmc0:0001的设备,并将次设备添加到mmc_bus_type下面
第五个函数:mmc_bus_probe
1.在第四个函数的2中,由于在mmc bus下添加了mmc0:001的设备,因此此时满足了probe的条件,出发了mmc_bus_probe的函数
2.调用在此函数中调用与其关联的mmc_driver 的probe函数,mmc_blk_probe
第五个函数:mmc_blk_probe
1.初始化emmc对应的blk设备
2.并为此块设备创建磁盘信息,并初始化磁盘分区
创建blk_req_queue的请求函数及请求
md->queue.issue_fn = mmc_blk_issue_rq;
md->queue.data = md;


调用流程:
在上面的mmc_block_probe中会根据emmc的硬件分区创建对应的mmcqd queue线程,比如说emmc有boot0 boot1  rpmb user分区,那么在上面的probe函数中会去创建四个mmc_queue_thread(mmcqd0、mmcqdboot0、mmcqdboot1、mmcqdrpmb),每个进程对应处理相应分区的读写请求(这几个进程可以ps手机进程看到),当IO调度层发出任务请求时,会去调用相应的queue对应的issue_fn即:md->queue.issue_fn = mmc_blk_issue_rq,调用流程如下:

mmc_queue_thread ->   负责从IO调度的队列中取request

    mmc_blk_issue_rq -> 

        mmc_blk_issue_rw_rq ->

            mmc_start_req ->

                __mmc_start_data_req ->

                    mmc_start_request ->

                        sprd_sdhc_request

mmc_queue_thread:从io调度层获取req(mmc_queue_thread),如果获得的req不为空或者上次的req不为空,则queue的状态值为runing,并且调用queue.issue_fn = mmc_blk_issue_rq开始处理req

mmc_blk_issue_rq:判断当前的req是否为第一个req,如果是的话需要claim  host激活时钟,否则不需要直接执行下面的mmc_blk_part_switch函数完成对emmc硬件分区的切换,md中包含要操作的分区,判断当前分区是否和即将操作的分区相同,如果相同直接return否则发送cmd6进行切换,接下来会根据req中的cmd_flags(REQ_DISCATD、REQ_FLUSH、others),根据不同的请求类型调用不同的函数:mmc_blk_issue_secdiscard_rq、mmc_blk_issue_flush、mmc_blk_issue_rw_rq

首先看mmc_blk_issue_rw_rq函数

如果参数req为空(无新request),或者mmc queueprevious request也为空(无未完成的request,那么mmc_blk_issue_rw_rq直接返回。

mmc_blk_prep_packed_list尝试把当前request和队列中的其他request合并,以增强性能。是否可以合并,要依赖于:

1. 控制器支持packed功能 host->caps

2. device的MAX_PACKED_WRITES 大于0

3. 只对写request进行packed

4.如果当前的写为增强写,但是设备不支持的情况下不packed

接下来会判断当前的req的block是否满足4k的sector,满足则继续执行,否则直接abort本次的请求

然后判断packed的数量是否超过了packed_nr,超过了会执行mmc_blk_packed_hdr_wr_prep,否则继续

正常情况下执行mmc_blk_rw_rq_prep函数,从request构造mmc_request,并下发给host请求,是mmc_request,而不是block层通用的request。如果支持packed功能,那么就用pack_list来构造mmc_request

areq表示async req,实际上,只要参数req存在,就表明这是一个新request,必然是异步传输的。

mmc_start_req 启动一个非阻塞的request,这个函数会等待前一个request完成,然后把启动当前requeset,并立刻返回

如果mmc_start_req返回的areq不为空,说明完成了上一次的request,

如果使用了bounce buffer,那么需要把传输结果从bounce buffer复制会sg buffer。所谓bounce buffer是因为某些DMA控制器只能处理连续物理内存,此时需要通过bounce buffer来达到物理内存连续性。

检查mmc_start_req返回的状态:

1. 如果是MMC_BLK_SUCCESS或者MMC_BLK_PARTIAL,需要调用blk_end_request通知block设备层,完成了本次读写request。

2. 如果是MMC_BLK_CMD_ERR,那么调用mmc_blk_reset复位host。调用mmc_blk_cmd_err尝试blk_end_request,如果发现reuqest未完成,说明本次操作失败,反之成功start_new_req


1 0