Linux DMA API: указание поведения приращения адреса?

Я пишу драйвер для Altera Soc Development Kit и должен поддерживать два режима передачи данных в / из FPGA:

  1. Передачи FIFO: при записи (или чтении) из FIFO FPGA адрес назначения (или источника) не должен увеличиваться контроллером DMA.
  2. передачи не в формате 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.

Другие вопросы по тегам