針對device是否有packed能力做一些篩選條件,若沒有的話會直接goto mmc_blk_clear_packed離開此函式。
分析一、
max_blk_count =
min(card->host->max_blk_count,
card->host->max_req_size
>> 9);
if (unlikely(max_blk_count > 0xffff))
max_blk_count = 0xffff;
也就是不管如何host端最多最多一次送的blk_count就是65535個blocks.
分析二、
max_phys_segs = queue_max_segments(q);
req_sectors
+= blk_rq_sectors(cur);
phys_segments
+= cur->nr_phys_segments;
if
(rq_data_dir(cur) == WRITE) {
req_sectors++;
phys_segments++;
}
藉由queue_max_segments得到request_queue的max_segmants值。
藉由blk_rq_sectors得到目前request要傳送sector(512bytes)數目。
/* Number of scatter-gather
DMA addr+len pairs after
* physical address coalescing is performed.
*/
unsigned short nr_phys_segments;
藉由nr_phys_segments的註解說明,我們知道紀錄的是scatter-gather DMA addr+len pairs在做完physical
address coalescing的數量。
至於physical
address coalescing是怎麼樣的行為目前先不探討。
接著如果當前的request是一個寫入要求,req_sectors以及phys_segments各加一。WHY? (直覺想到的是要傳packed
command的header,但是若為packed read也是需要header,目前暫留此懸疑。)
再來進入此函數的重頭戲,
while (reqs < max_packed_rw - 1) {
spin_lock_irq(q->queue_lock);
next
= blk_fetch_request(q);
spin_unlock_irq(q->queue_lock);
if
(!next)
break;
先利用spin_lock機制鎖住此request的request_queue。確保在做blk_fecth_request時的同步問題。
/**
*
blk_fetch_request - fetch a request from a request queue
* @q: request
queue to fetch a request from
*
* Description:
* Return the request at the top of @q. The request is started on
* return and LLD can start
processing it immediately.
*
* Return:
* Pointer to the request at the top of @q if
available. Null
* otherwise.
*
* Context:
* queue_lock must be held.
*/
struct request *blk_fetch_request(struct
request_queue *q)
{
struct
request *rq;
rq =
blk_peek_request(q);
if (rq)
blk_start_request(rq);
return
rq;
}
EXPORT_SYMBOL(blk_fetch_request);
分析三、
註解說明其實已經很清楚說明此函數(blk_fetch_request)的任務,這邊我還不了解的是LLD是甚麼? Wiki: LLD(Lower level design, a stage in project
management of SW development or other computer-related projects, following the
High-level design) 在此LLD是指將此request交給dirver去處理。
分析三-甲、
/**
*
blk_peek_request - peek at the top of a request queue
* @q: request
queue to peek at
*
* Description:
* Return the request at the top of @q. The returned request
* should be started using
blk_start_request() before LLD
starts
* processing it.
*
* Return:
* Pointer to the request at the top of @q if
available. Null
* otherwise.
*
* Context:
* queue_lock must be held.
*/
struct request *blk_peek_request(struct request_queue
*q)
再度藉由清楚明瞭的註解知道此函數的目的。(良好的註解習慣是優秀程式設計師必備)
另外會再寫一篇詳細分析blk_peek_request跟io-scheduler相關的探討。
分析三-乙、
/**
*
blk_start_request - start request processing on the driver
* @req:
request to dequeue
*
* Description:
* Dequeue @req and start timeout timer on
it. This
hands off the
*
request to the driver.
*
* Block internal functions which don't want
to start timer should
* call blk_dequeue_request().
*
* Context:
* queue_lock must be held.
*/
void blk_start_request(struct request *req)
{
blk_dequeue_request(req);
/*
* We are now handing the request to the
hardware, initialize
* resid_len
to full count and add the timeout handler.
*/
req->resid_len
= blk_rq_bytes(req);
if
(unlikely(blk_bidi_rq(req)))
req->next_rq->resid_len
= blk_rq_bytes(req->next_rq);
blk_add_timer(req);
}
EXPORT_SYMBOL(blk_start_request);
在註解中提到若是不想要啟動timeout
timer,應該直接呼叫blk_dequeue_request。呼叫blk_dequeue_request後,取得目前request要傳送/接收的data長度,並且藉由blk_bidi_rq知道此request後是否接著還有request,接著取得下個request要傳送/接收的data長度,我想這邊是為了提升request收送的效率。
/**
*
blk_add_timer - Start timeout timer for a
single request
* @req: request that is about to start running.
*
* Notes:
* Each request has its own timer, and as it
is added to the queue, we
* set up the timer. When the request
completes, we cancel the timer.
*/
void blk_add_timer(struct request *req)
這邊就不再多做說明blk_add_timer了。
接著有幾個條件會讓程序走向blk_reqeue_request:
1. 下個request是REQ_DISCARD 或是 REQ_FLUSH
2. 下個request的IO方向不同
3. 下個request是reliable
write但是device不支援
4. 加上下個request要求的data block
count後,大於host最大的block count
5. 加上下個request的nr_phys_segments後,大於host
max_phys_segs
再來,我們看看blk_reqeue_request在做甚麼事。
/**
*
blk_requeue_request - put a request back
on queue
* @q: request queue where request should
be inserted
* @rq: request to be inserted
*
* Description:
* Drivers often keep queueing requests until
the hardware cannot accept
* more, when that condition happens we need
to put the request back
* on the queue. Must be called with queue lock held.
*/
void blk_requeue_request(struct request_queue *q,
struct request *rq)
因此當hardware還能負荷request或是沒有觸動到上面提到的幾個條件,就會持續呼叫list_add_tail將entry加到packed_list中。
/**
*
list_add_tail - add a new entry
* @new: new
entry to be added
* @head: list
head to add it before
*
* Insert a new entry
before the specified head.
* This is
useful for implementing queues.
*/
static inline void list_add_tail(struct list_head
*new, struct list_head *head)
{
__list_add(new,
head->prev, head);
}
離開重頭戲while迴圈後,得知reqs需要執行之數量,呼叫list_add並設定相關packed_num,
packed_retries參數後結束整個函式。
/**
* list_add -
add a new entry
* @new: new
entry to be added
* @head: list
head to add it after
*
* Insert a new entry after the specified head.
* This is good
for implementing stacks.
*/
static inline void list_add(struct list_head *new,
struct list_head *head)
{
__list_add(new,
head, head->next);
}
來看一下,__list_add吧。
static inline void __list_add(struct list_head *new,
struct list_head *prev, struct list_head *next)
{
next->prev = new; //1
new->next = next; //2
new->prev = prev; //3
prev->next = new; //4
}
WHY? (直覺想到的是要傳packed command的header,但是若為packed read也是需要header,目前暫留此懸疑。)
回覆刪除emmc spec中对于packed read的定义说:不需要额外加上一个block,第一次发cmd23 count block = one
第二次发cmd23 count block = all block counts of the individual reads