요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
==============================
PXA/MMP - DMA Slave controller
==============================
Constraints
===========
a) Transfers hot queuing
A driver submitting a transfer and issuing it should be granted the transfer
is queued even on a running DMA channel.
This implies that the queuing doesn't wait for the previous transfer end,
and that the descriptor chaining is not only done in the irq/tasklet code
triggered by the end of the transfer.
A transfer which is submitted and issued on a phy doesn't wait for a phy to
stop and restart, but is submitted on a "running channel". The other
drivers, especially mmp_pdma waited for the phy to stop before relaunching
a new transfer.
b) All transfers having asked for confirmation should be signaled
Any issued transfer with DMA_PREP_INTERRUPT should trigger a callback call.
This implies that even if an irq/tasklet is triggered by end of tx1, but
at the time of irq/dma tx2 is already finished, tx1->complete() and
tx2->complete() should be called.
c) Channel running state
A driver should be able to query if a channel is running or not. For the
multimedia case, such as video capture, if a transfer is submitted and then
a check of the DMA channel reports a "stopped channel", the transfer should
not be issued until the next "start of frame interrupt", hence the need to
know if a channel is in running or stopped state.
d) Bandwidth guarantee
The PXA architecture has 4 levels of DMAs priorities : high, normal, low.
The high priorities get twice as much bandwidth as the normal, which get twice
as much as the low priorities.
A driver should be able to request a priority, especially the real-time
ones such as pxa_camera with (big) throughputs.
Design
======
a) Virtual channels
Same concept as in sa11x0 driver, ie. a driver was assigned a "virtual
channel" linked to the requestor line, and the physical DMA channel is
assigned on the fly when the transfer is issued.
b) Transfer anatomy for a scatter-gather transfer
::
+------------+-----+---------------+----------------+-----------------+
| desc-sg[0] | ... | desc-sg[last] | status updater | finisher/linker |
+------------+-----+---------------+----------------+-----------------+
This structure is pointed by dma->sg_cpu.
The descriptors are used as follows :
- desc-sg[i]: i-th descriptor, transferring the i-th sg
element to the video buffer scatter gather
- status updater
Transfers a single u32 to a well known dma coherent memory to leave
a trace that this transfer is done. The "well known" is unique per
physical channel, meaning that a read of this value will tell which
is the last finished transfer at that point in time.
- finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN
- linker: has ddadr= desc-sg[0] of next transfer, dcmd=0
c) Transfers hot-chaining
Suppose the running chain is:
::
Buffer 1 Buffer 2
+---------+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+---+
| |
+----+
After a call to dmaengine_submit(b3), the chain will look like:
::
Buffer 1 Buffer 2 Buffer 3
+---------+----+---+ +----+----+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+
| | | |
+----+ +----+
new_link
If while new_link was created the DMA channel stopped, it is _not_
restarted. Hot-chaining doesn't break the assumption that
dma_async_issue_pending() is to be used to ensure the transfer is actually started.
One exception to this rule :
- if Buffer1 and Buffer2 had all their addresses 8 bytes aligned
- and if Buffer3 has at least one address not 4 bytes aligned
- then hot-chaining cannot happen, as the channel must be stopped, the
"align bit" must be set, and the channel restarted As a consequence,
such a transfer tx_submit() will be queued on the submitted queue, and
this specific case if the DMA is already running in aligned mode.
d) Transfers completion updater
Each time a transfer is completed on a channel, an interrupt might be
generated or not, up to the client's request. But in each case, the last
descriptor of a transfer, the "status updater", will write the latest
transfer being completed into the physical channel's completion mark.
This will speed up residue calculation, for large transfers such as video
buffers which hold around 6k descriptors or more. This also allows without
any lock to find out what is the latest completed transfer in a running
DMA chain.
e) Transfers completion, irq and tasklet
When a transfer flagged as "DMA_PREP_INTERRUPT" is finished, the dma irq
is raised. Upon this interrupt, a tasklet is scheduled for the physical
channel.
The tasklet is responsible for :
- reading the physical channel last updater mark
- calling all the transfer callbacks of finished transfers, based on
that mark, and each transfer flags.
If a transfer is completed while this handling is done, a dma irq will
be raised, and the tasklet will be scheduled once again, having a new
updater mark.
f) Residue
Residue granularity will be descriptor based. The issued but not completed
transfers will be scanned for all of their descriptors against the
currently running descriptor.
g) Most complicated case of driver's tx queues
The most tricky situation is when :
- there are not "acked" transfers (tx0)
- a driver submitted an aligned tx1, not chained
- a driver submitted an aligned tx2 => tx2 is cold chained to tx1
- a driver issued tx1+tx2 => channel is running in aligned mode
- a driver submitted an aligned tx3 => tx3 is hot-chained
- a driver submitted an unaligned tx4 => tx4 is put in submitted queue,
not chained
- a driver issued tx4 => tx4 is put in issued queue, not chained
- a driver submitted an aligned tx5 => tx5 is put in submitted queue, not
chained
- a driver submitted an aligned tx6 => tx6 is put in submitted queue,
cold chained to tx5
This translates into (after tx4 is issued) :
- issued queue
::
+-----+ +-----+ +-----+ +-----+
| tx1 | | tx2 | | tx3 | | tx4 |
+---|-+ ^---|-+ ^-----+ +-----+
| | | |
+---+ +---+
- submitted queue
+-----+ +-----+
| tx5 | | tx6 |
+---|-+ ^-----+
| |
+---+
- completed queue : empty
- allocated queue : tx0
It should be noted that after tx3 is completed, the channel is stopped, and
restarted in "unaligned mode" to handle tx4.
Author: Robert Jarzmik <robert.jarzmik@free.fr>
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
PXA/MMP DMA slave controller 제약
1-38PXA/MMP DMA slave controller driver가 충족해야 할 제약은 다음과 같습니다.
- Transfer hot queuing: driver가 transfer를 submit하고 issue하면 DMA channel이 이미 실행 중이어도 queue에 들어가야 합니다. queueing은 이전 transfer 종료를 기다리지 않으며 descriptor chaining을 transfer 종료 irq/tasklet에서만 수행해서도 안 됩니다. physical channel이 멈췄다가 재시작할 때까지 기다리지 않고 running channel에 submit해야 합니다. 기존 `mmp_pdma` 같은 driver는 physical channel 정지를 기다린 뒤 새 transfer를 시작했습니다.
- Confirmation을 요청한 모든 transfer signal: `DMA_PREP_INTERRUPT`로 issue한 모든 transfer가 callback을 trigger해야 합니다. tx1 종료가 irq/tasklet을 일으켰지만 irq 또는 DMA 처리 시점에 tx2도 이미 끝났다면 `tx1->complete()`와 `tx2->complete()`를 모두 호출해야 합니다.
- Channel running state: driver가 channel의 running/stopped 상태를 조회할 수 있어야 합니다. video capture 같은 multimedia에서 transfer를 submit한 뒤 channel이 stopped로 보고되면 다음 start-of-frame interrupt 전까지 issue하면 안 되므로 상태를 알아야 합니다.
- Bandwidth guarantee: 원문은 PXA architecture에 DMA priority가 4단계라고 설명하면서 high, normal, low를 나열합니다. high는 normal의 두 배, normal은 low의 두 배 bandwidth를 얻습니다. `pxa_camera`처럼 throughput이 큰 real-time driver는 priority를 요청할 수 있어야 합니다.
running channel queueing, callback, state query와 priority 요구를 정리했습니다.
설계: virtual channel
39-45`sa11x0` driver와 같은 개념을 사용합니다. driver에는 requestor line과 연결된 virtual channel을 할당하고, transfer를 issue할 때 physical DMA channel을 동적으로 배정합니다.
Scatter-gather transfer anatomy
46-69`dma->sg_cpu`가 가리키는 transfer 구조는 다음 순서로 구성됩니다.
원문 ASCII의 descriptor, status updater와 종료·연결 slot을 같은 순서로 재구성했습니다.
- `desc-sg[i]`: i번째 scatter-gather element를 video buffer scatter-gather로 전송하는 i번째 descriptor입니다.
- status updater: well-known DMA coherent memory에 `u32` 하나를 기록해 transfer 완료 흔적을 남깁니다. 이 위치는 physical channel마다 고유하므로 값을 읽으면 그 시점에 마지막으로 끝난 transfer를 알 수 있습니다.
- finisher: `ddadr=DADDR_STOP`, `dcmd=ENDIRQEN`을 사용합니다.
- linker: `ddadr`가 다음 transfer의 `desc-sg[0]`을 가리키고 `dcmd=0`입니다.
Transfer hot-chaining
70-97실행 중인 chain이 Buffer 1에서 Buffer 2로 연결된 상태를 구조화하면 다음과 같습니다.
Buffer 1 linker가 Buffer 2의 첫 descriptor를 가리키고 Buffer 2는 finisher로 끝납니다.
`dmaengine_submit(b3)` 호출 뒤에는 Buffer 2의 finisher가 linker로 바뀌어 Buffer 3으로 이어집니다.
새 link가 Buffer 2에서 Buffer 3으로 이어지고 마지막 Buffer 3에 finisher가 남습니다.
`new_link`를 만드는 동안 DMA channel이 멈췄다면 자동으로 재시작하지 않습니다. hot-chaining은 transfer가 실제로 시작되도록 `dma_async_issue_pending()`을 호출해야 한다는 전제를 바꾸지 않습니다.
Hot-chaining alignment 예외
98-108다음 조건에서는 hot-chaining을 수행할 수 없습니다.
- Buffer 1과 Buffer 2의 모든 address가 8-byte aligned입니다.
- Buffer 3에는 4-byte aligned가 아닌 address가 하나 이상 있습니다.
- channel을 멈추고 `align bit`를 설정한 뒤 다시 시작해야 합니다.
따라서 이 transfer의 `tx_submit()`은 submitted queue에 들어갑니다. DMA가 이미 aligned mode로 실행 중인 이 특수 상황에서는 running chain에 바로 연결되지 않습니다.
기존 chain과 새 buffer alignment에 따른 hot-chain 가능 여부를 구분했습니다.
Transfer completion updater
109-119channel에서 transfer가 완료될 때 client 요청에 따라 interrupt가 발생할 수도 있고 발생하지 않을 수도 있습니다. 어느 경우든 transfer의 마지막 descriptor인 status updater가 physical channel completion mark에 마지막 완료 transfer를 기록합니다.
video buffer처럼 descriptor가 약 6,000개 이상인 큰 transfer에서 residue 계산을 빠르게 하며, lock 없이 running DMA chain의 최신 완료 transfer를 찾을 수 있게 합니다.
Completion, IRQ와 tasklet
120-135`DMA_PREP_INTERRUPT` flag가 설정된 transfer가 끝나면 DMA IRQ가 발생하고 physical channel의 tasklet이 schedule됩니다.
- tasklet은 physical channel의 마지막 updater mark를 읽습니다.
- 그 mark와 각 transfer flag를 기준으로 완료된 모든 transfer callback을 호출합니다.
처리 중 다른 transfer가 완료되면 DMA IRQ가 다시 발생하고 새 updater mark를 가진 tasklet이 다시 schedule됩니다.
status updater에서 IRQ, tasklet, callback으로 이어지는 순서를 정리했습니다.
Residue
136-140residue granularity는 descriptor 기반입니다. issue됐지만 완료되지 않은 transfer의 모든 descriptor를 현재 running descriptor와 대조해 scan합니다.
복합 tx queue 사례와 author
141-190가장 까다로운 상황은 다음 순서로 만들어집니다.
- acknowledge되지 않은 transfer `tx0`가 있습니다.
- driver가 aligned `tx1`을 submit했지만 아직 chain되지 않았습니다.
- aligned `tx2`를 submit해 `tx1`에 cold-chain합니다.
- `tx1+tx2`를 issue해 channel이 aligned mode로 실행됩니다.
- aligned `tx3`를 submit해 hot-chain합니다.
- unaligned `tx4`는 chain되지 않고 submitted queue에 들어갑니다.
- `tx4`를 issue하면 chain되지 않은 채 issued queue에 들어갑니다.
- aligned `tx5`는 chain되지 않고 submitted queue에 들어갑니다.
- aligned `tx6`는 submitted queue에서 `tx5`에 cold-chain됩니다.
`tx4` issue 뒤 queue 상태는 다음과 같습니다.
원문 ASCII의 issued, submitted, completed, allocated queue와 chain 관계를 재구성했습니다.
`tx3`가 완료되면 channel을 멈추고 `tx4`를 처리하기 위해 unaligned mode로 재시작해야 합니다.
Author: Robert Jarzmik <robert.jarzmik@free.fr>
요약과 해설
pxa_dma.rst:1-190PXA/MMP DMA driver는 running physical channel에 새 transfer를 hot-chain하고 `DMA_PREP_INTERRUPT`를 요청한 모든 완료 callback을 빠짐없이 호출해야 합니다. scatter-gather chain은 data descriptor 뒤 status updater와 finisher/linker를 두며 completion mark로 residue와 callback 대상을 빠르게 찾습니다. alignment mode가 달라지는 transfer는 running chain에 붙이지 않고 queue한 뒤 channel을 정지·재시작하며, virtual channel과 issued/submitted/allocated queue 상태를 일관되게 유지해야 합니다.