Linux DMA API: указание поведения приращения адреса?
Я пишу драйвер для Altera Soc Development Kit и должен поддерживать два режима передачи данных в / из FPGA:
- Передачи FIFO: при записи (или чтении) из FIFO FPGA адрес назначения (или источника) не должен увеличиваться контроллером DMA.
- передачи не в формате FIFO: это обычные (подобные RAM) передачи, когда адреса источника и получателя требуют приращения для каждого передаваемого слова.
Конкретным контроллером DMA, который я использую, является контроллер DMA CoreLink DMA-330, а его драйвер для Linux - pl330.c (drivers/dma/pl330.c). Этот контроллер DMA обеспечивает механизм переключения между "пакетной передачей с фиксированным адресом" и "пакетной передачей приращения" (это синонимы моих "передач FIFO" и "передач не-FIFO"). Драйвер pl330 определяет, какое поведение он хочет, устанавливая соответствующие биты в регистре CCRn.
#define CC_SRCINC (1 << 0)
#define CC_DSTINC (1 << 14)
Мой вопрос: мне совсем не ясно, как клиенты pl330 (мой драйвер, например) должны указывать поведение приращения адреса.
API клиента механизма DMA ничего не говорит о том, как это указать, в то время как API поставщика механизма DMA просто заявляет:
Адреса, указывающие на RAM, обычно увеличиваются (или уменьшаются) после каждой передачи. В случае кольцевого буфера они могут зацикливаться (DMA_CYCLIC). Адреса, указывающие на регистр устройства (например, FIFO), обычно являются фиксированными.
не давая никаких подробностей о том, как типы адресов передаются поставщикам (в моем случае это драйвер pl300).
В методе pl330_prep_slave_sg это делает:
if (direction == DMA_MEM_TO_DEV) {
desc->rqcfg.src_inc = 1;
desc->rqcfg.dst_inc = 0;
desc->req.rqtype = MEMTODEV;
fill_px(&desc->px,
addr, sg_dma_address(sg), sg_dma_len(sg));
} else {
desc->rqcfg.src_inc = 0;
desc->rqcfg.dst_inc = 1;
desc->req.rqtype = DEVTOMEM;
fill_px(&desc->px,
sg_dma_address(sg), addr, sg_dma_len(sg));
}
где позже, драйвер desc->rqcfg.src_inc и desc->rqcfg.dst_inc используются для определения поведения приращения адреса.
Это подразумевает следующее:
- Указание направления = DMA_MEM_TO_DEV означает, что клиент желает извлечь данные из FIFO в RAM. И, по-видимому, DMA_DEV_TO_MEM означает, что клиент желает перенести данные из ОЗУ в FIFO.
- Операции прямого доступа к памяти с разбором (по крайней мере для pl300) ограничены случаями, когда конечной точкой источника или назначения является FIFO. Что если я захочу выполнить операцию сбора из системного ОЗУ в память FPGA (не FIFO)?
Я что-то недопонимаю и / или упускаю из виду? Механизм DMA уже предоставляет (недокументированный) механизм для определения поведения приращения адреса?
2 ответа
Посмотри на это
pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
pd->device_prep_slave_sg = pl330_prep_slave_sg;
Это означает, что у вас разные подходы, которые вы прочитали в документации. Подозреваемые передачи могут быть сделаны, я подозреваю, через device_prep_dma_memcpy()
,
Мне кажется (после просмотра различных драйверов в ядре) единственными стилями передачи DMA, которые позволяют (косвенно) управлять поведением автоинкремента, являются те, которые имеют enum dma_transfer_direction
в соответствующем device_prep_...
функция.
И этот параметр объявлен только для device_prep_slave_sg
а также device_prep_dma_cyclic
, в соответствии с include/linux/dmaengine.h
Другим вариантом должно быть использование и struct dma_interleaved_template
который позволяет вам указать поведение приращения напрямую. Но поддержка этого метода ограничена (например, только драйвер i.MX DMA поддерживает его в ядре 3.8. И даже эта поддержка кажется ограниченной)
Поэтому я думаю, что мы застряли с device_prep_slave_sg
дело со всеми sg
связанные сложности на некоторое время.
Это то, что я делаю в данный момент (хотя это для доступа к некоторым устройствам, подключенным к EBI, на Atmel SAM9 SOC)
Еще одна вещь, которую следует учитывать, это ширина шины устройства. memcopy
-вариант может выполнять различные передачи ширины шины, в зависимости от адреса источника и целевого адреса и размеров. И это может не соответствовать размеру элемента FIFO.