歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

linux內核mmc讀寫分析

MMC 讀寫分析

EMMC讀寫操作的調用棧

mmc_queue_thread ->

mmc_blk_issue_rq ->

mmc_blk_issue_rw_rq ->

mmc_start_req ->

__mmc_start_data_req ->

mmc_start_request ->

omap_hsmmc_request

首先mmc_queue_thread獲取相應的mmc_request然然後調用mq->issue_fn處理reuqest,issue_fn有可能被阻塞在mmc_wait_for_data_req_done,如果此時有新的請求到達,那麼有可能會喚醒阻塞的進程(條件是cur==null, prev!=null)。

然後調用mmc_blk_issue_rq來選擇對應的分區,根據req->cmd_flags的命令做不同的事情。REQ_SANITIZE、REQ_DISCARD、REQ_FLUSH分別為2.1 mmc_blk_issue_secdiscard_rq

和mmc_blk_issue_discard_rq

2.2 mmc_blk_issue_flush

2.3 mmc_blk_issue_rw_rq,這個是我們要分析的讀寫數據流程

進入mmc_blk_issue_rw_rq函數如果參數req為空(無新request),或者mmc

queue的previous request也為空(無未完成的request),那麼mmc_blk_issue_rw_rq直接返回。

mmc_blk_prep_packed_list嘗試把當前request和隊列中的其他request合並,以增強性能。是否可以合並,要依賴於:

1.

控制器支持packed功能

2. device的MAX_PACKED_WRITES

大於0

3.

只對寫request進行packed

正常情況下執行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

3. ....

真正的執行讀寫請求是在執行函數mmc_start_req裡:1、 首先它會執行到mmc_wait_for_data_req_done函數,等待上一次的命令的完成,如果上一次未完成就會將當前進程加入等待隊列休眠,等待被喚醒。當上一次完成後會立即返回,並將上一次命令執行的狀態返回給mmc_blk_issue_rw_rq。

2、if (host->areq) {

err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);

host->areq不為空,說明有正在處理的reuqest,函數mmc_wait_for_data_req_done用來等待這個host->areq,有兩個條件會喚醒該MMC上下文:

is_done_rcv和is_new_req

if (!err && areq)

start_err = __mmc_start_data_req(host, areq->mrq);

進入__mmc_start_data_req(host, areq->mrq);首先會將函數指針mmc_wait_data_done賦給mrq->done

if (host->card && host->card->ext_csd.cmdq_mode_en)

mrq->done = mmc_wait_cmdq_done;

else

mrq->done = mmc_wait_data_done;

mmc_wait_data_done會設置context_info->is_done_rcv=true,這正好是喚醒mmc_wait_for_data_req_done的條件之一,然後調wake_up_interruptible(&context_info->wait);喚醒之。

然後會調用mmc_start_request(host, mrq);

mmc_start_reuqest實際調用host->ops->request方法,進入了平台特定的request函數

進入特定的平台之後,會進入相應的中斷對硬件進行讀寫的命令的執行,當命令執行完畢後,會進行函數回調調到剛才的mmc_wait_data_done喚醒等待的進程進行下一次命令的執行。

Copyright © Linux教程網 All Rights Reserved