Documentation/driver-api/mmc/mmc-async-req.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

MMC Asynchronous Request

DMA 준비와 MMC 전송을 병렬화하는 비동기 요청 API의 전문 번역입니다.

Source pathDocumentation/driver-api/mmc/mmc-async-req.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

mmc-async-req.rst:1-98

비동기 MMC request는 DMA map/unmap을 활성 전송과 겹치고 첫 요청을 두 chunk로 준비해 controller 유휴 시간을 줄입니다.

문서 구성
원문 줄내용
1-22필요성
23-41Block driver와 성능
42-62Core와 host API
63-98첫 요청 최적화

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 ========================
2 MMC Asynchronous Request
3 ========================
4
5 Rationale
6 =========
7
8 How significant is the cache maintenance overhead?
9
10 It depends. Fast eMMC and multiple cache levels with speculative cache
11 pre-fetch makes the cache overhead relatively significant. If the DMA
12 preparations for the next request are done in parallel with the current
13 transfer, the DMA preparation overhead would not affect the MMC performance.
14
15 The intention of non-blocking (asynchronous) MMC requests is to minimize the
16 time between when an MMC request ends and another MMC request begins.
17
18 Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
19 dma_unmap_sg are processing. Using non-blocking MMC requests makes it
20 possible to prepare the caches for next job in parallel with an active
21 MMC request.
22
23 MMC block driver
24 ================
25
26 The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
27
28 The increase in throughput is proportional to the time it takes to
29 prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
30 a request and how fast the memory is. The faster the MMC/SD is the
31 more significant the prepare request time becomes. Roughly the expected
32 performance gain is 5% for large writes and 10% on large reads on a L2 cache
33 platform. In power save mode, when clocks run on a lower frequency, the DMA
34 preparation may cost even more. As long as these slower preparations are run
35 in parallel with the transfer performance won't be affected.
36
37 Details on measurements from IOZone and mmc_test
38 ================================================
39
40 https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
41
42 MMC core API extension
43 ======================
44
45 There is one new public function mmc_start_req().
46
47 It starts a new MMC command request for a host. The function isn't
48 truly non-blocking. If there is an ongoing async request it waits
49 for completion of that request and starts the new one and returns. It
50 doesn't wait for the new request to complete. If there is no ongoing
51 request it starts the new request and returns immediately.
52
53 MMC host extensions
54 ===================
55
56 There are two optional members in the mmc_host_ops -- pre_req() and
57 post_req() -- that the host driver may implement in order to move work
58 to before and after the actual mmc_host_ops.request() function is called.
59
60 In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
61 descriptor, and post_req() runs the dma_unmap_sg().
62
63 Optimize for the first request
64 ==============================
65
66 The first request in a series of requests can't be prepared in parallel
67 with the previous transfer, since there is no previous request.
68
69 The argument is_first_req in pre_req() indicates that there is no previous
70 request. The host driver may optimize for this scenario to minimize
71 the performance loss. A way to optimize for this is to split the current
72 request in two chunks, prepare the first chunk and start the request,
73 and finally prepare the second chunk and start the transfer.
74
75 Pseudocode to handle is_first_req scenario with minimal prepare overhead::
76
77 if (is_first_req && req->size > threshold)
78 /* start MMC transfer for the complete transfer size */
79 mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
80
81 /*
82 * Begin to prepare DMA while cmd is being processed by MMC.
83 * The first chunk of the request should take the same time
84 * to prepare as the "MMC process command time".
85 * If prepare time exceeds MMC cmd time
86 * the transfer is delayed, guesstimate max 4k as first chunk size.
87 */
88 prepare_1st_chunk_for_dma(req);
89 /* flush pending desc to the DMAC (dmaengine.h) */
90 dma_issue_pending(req->dma_desc);
91
92 prepare_2nd_chunk_for_dma(req);
93 /*
94 * The second issue_pending should be called before MMC runs out
95 * of the first chunk. If the MMC runs out of the first data chunk
96 * before this call, the transfer is delayed.
97 */
98 dma_issue_pending(req->dma_desc);
99

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

비동기 요청의 필요성

1-22

빠른 eMMC, 여러 cache level, speculative prefetch가 결합되면 cache maintenance 비용은 상대적으로 커질 수 있습니다. 다음 요청의 DMA 준비를 현재 전송과 병렬로 수행하면 이 비용이 MMC 성능을 막지 않습니다.

Non-blocking MMC request의 목적은 한 요청이 끝난 뒤 다음 요청이 시작될 때까지의 빈 시간을 최소화하는 것입니다.

`mmc_wait_for_req()`를 사용하면 `dma_map_sg()`와 `dma_unmap_sg()` 처리 중 controller가 유휴 상태가 됩니다. 비동기 요청은 활성 MMC 전송과 병렬로 다음 작업의 cache를 준비하게 합니다.

동기 요청과 비동기 요청
동기전송 완료`dma_unmap_sg()``dma_map_sg()`다음 전송
비동기현재 전송다음 요청 DMA 준비즉시 다음 전송

DMA 준비를 전송 구간과 겹쳐 controller 유휴 시간을 줄입니다.

========================
MMC Asynchronous Request
========================

Rationale
=========

How significant is the cache maintenance overhead?

It depends. Fast eMMC and multiple cache levels with speculative cache
pre-fetch makes the cache overhead relatively significant. If the DMA
preparations for the next request are done in parallel with the current
transfer, the DMA preparation overhead would not affect the MMC performance.

The intention of non-blocking (asynchronous) MMC requests is to minimize the
time between when an MMC request ends and another MMC request begins.

Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
dma_unmap_sg are processing. Using non-blocking MMC requests makes it
possible to prepare the caches for next job in parallel with an active
MMC request.

MMC block driver와 성능

23-41

MMC block driver의 `mmc_blk_issue_rw_rq()`는 non-blocking 방식으로 만들어졌습니다.

처리량 증가는 요청 준비 시간, 주로 `dma_map_sg()`와 `dma_unmap_sg()`, 그리고 memory 속도에 비례합니다. MMC/SD가 빠를수록 준비 시간의 비중이 커집니다.

L2 cache platform에서 예상되는 대략적인 성능 향상은 대용량 write 5%, 대용량 read 10%입니다. 절전 모드처럼 clock이 느릴 때 DMA 준비 비용은 더 커질 수 있지만, 전송과 병렬로 수행하면 성능에는 영향을 주지 않습니다.

IOZone과 `mmc_test` 측정 상세는 문서에 적힌 Linaro StoragePerfMMC async request 자료에서 확인할 수 있습니다.

비동기 요청 성능 효과
조건효과
대용량 write약 5% 향상 예상
대용량 read약 10% 향상 예상
저주파 절전 모드DMA 준비 비용 증가, 병렬화로 은닉 가능

MMC block driver
================

The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.

The increase in throughput is proportional to the time it takes to
prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
a request and how fast the memory is. The faster the MMC/SD is the
more significant the prepare request time becomes. Roughly the expected
performance gain is 5% for large writes and 10% on large reads on a L2 cache
platform. In power save mode, when clocks run on a lower frequency, the DMA
preparation may cost even more. As long as these slower preparations are run
in parallel with the transfer performance won't be affected.

Details on measurements from IOZone and mmc_test
================================================

https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req

MMC core와 host 확장

42-62

새 public function은 `mmc_start_req()`입니다. Host에 새 MMC command request를 시작합니다.

이 함수는 완전히 non-blocking은 아닙니다. 진행 중인 async request가 있으면 그 완료를 기다린 뒤 새 요청을 시작하고 반환하지만, 새 요청 자체의 완료는 기다리지 않습니다. 진행 중인 요청이 없으면 새 요청을 시작하고 즉시 반환합니다.

`mmc_host_ops`에는 host driver가 구현할 수 있는 optional member `pre_req()`와 `post_req()`가 있습니다. 실제 `mmc_host_ops.request()` 호출 전후로 작업을 이동하기 위한 hook입니다.

DMA 사용 시 `pre_req()`는 `dma_map_sg()`와 DMA descriptor 준비를 수행하고, `post_req()`는 `dma_unmap_sg()`를 수행할 수 있습니다.

`mmc_start_req()` pipeline
`pre_req()``dma_map_sg()`와 descriptor 준비
`mmc_host_ops.request()`MMC 전송
`post_req()``dma_unmap_sg()`

이전 요청 완료와 새 요청 시작 사이에 host 준비 및 정리 hook을 배치합니다.

MMC core API extension
======================

There is one new public function mmc_start_req().

It starts a new MMC command request for a host. The function isn't
truly non-blocking. If there is an ongoing async request it waits
for completion of that request and starts the new one and returns. It
doesn't wait for the new request to complete. If there is no ongoing
request it starts the new request and returns immediately.

MMC host extensions
===================

There are two optional members in the mmc_host_ops -- pre_req() and
post_req() -- that the host driver may implement in order to move work
to before and after the actual mmc_host_ops.request() function is called.

In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
descriptor, and post_req() runs the dma_unmap_sg().

첫 요청 최적화

63-98

연속 요청의 첫 요청은 앞선 전송이 없으므로 준비 작업을 이전 전송과 병렬화할 수 없습니다. `pre_req()`의 `is_first_req` 인자가 이 상황을 알립니다.

Host driver는 성능 손실을 줄이기 위해 요청을 두 chunk로 나눌 수 있습니다. 첫 chunk를 준비하고 전체 크기의 MMC command를 시작한 뒤, command 처리 중 두 번째 chunk를 준비합니다.

첫 chunk 준비 시간은 MMC command 처리 시간과 비슷해야 합니다. 준비가 더 오래 걸리면 전송이 지연되므로 첫 chunk는 최대 4 KiB 정도로 추정합니다.

첫 descriptor의 `dma_issue_pending()` 후 두 번째 chunk를 준비하고 다시 issue합니다. 두 번째 호출은 MMC가 첫 data chunk를 모두 소비하기 전에 이루어져야 합니다.

`is_first_req` 최적화
전체 크기 command 시작첫 chunk 준비첫 `dma_issue_pending()`
첫 chunk 전송두 번째 chunk 준비두 번째 `dma_issue_pending()`

첫 요청의 DMA 준비를 command 처리와 겹치고 두 chunk를 끊김 없이 공급합니다.

Optimize for the first request
==============================

The first request in a series of requests can't be prepared in parallel
with the previous transfer, since there is no previous request.

The argument is_first_req in pre_req() indicates that there is no previous
request. The host driver may optimize for this scenario to minimize
the performance loss. A way to optimize for this is to split the current
request in two chunks, prepare the first chunk and start the request,
and finally prepare the second chunk and start the transfer.

Pseudocode to handle is_first_req scenario with minimal prepare overhead::

  if (is_first_req && req->size > threshold)
     /* start MMC transfer for the complete transfer size */
     mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);

     /*
      * Begin to prepare DMA while cmd is being processed by MMC.
      * The first chunk of the request should take the same time
      * to prepare as the "MMC process command time".
      * If prepare time exceeds MMC cmd time
      * the transfer is delayed, guesstimate max 4k as first chunk size.
      */
      prepare_1st_chunk_for_dma(req);
      /* flush pending desc to the DMAC (dmaengine.h) */
      dma_issue_pending(req->dma_desc);

      prepare_2nd_chunk_for_dma(req);
      /*
       * The second issue_pending should be called before MMC runs out
       * of the first chunk. If the MMC runs out of the first data chunk
       * before this call, the transfer is delayed.
       */
      dma_issue_pending(req->dma_desc);