Перейти к содержанию
    

AXI-DMA на Zynq-7000 Вопрос по управлению пересылкой данных из userspace

День добрый всем!

Я работаю с коркой AXI DMA от Xilinx. В системе их пара.

  1. Одна корка используется так: данные передаются в FPGA на дециматор по одному каналу в одном потоке, а децимированный сигнал обратно забирается с помощью 2-го канала в другом потоке. Драйвер был взят DMA-proxy от Xilinx. Требуется забирать данные по заполнению буфера при получении сигнала с дециматора. Была попытка использовать такие инструменты linux как select и poll, вида:

#include <poll.h>

                int ret = poll( &freceive, 1, -1);
                if(ret == -1)
                        perror("poll");
                if(ret > 0 && (freceive.revents & POLLIN))
                {
                        printf("ret = %i\n\n", ret);
                        ioctl(rx_proxy_fd, 0, &dummy);
                }

но они срабатывают и в случае, когда данных в буфере нет, во всяком случае при вызове ioctl для пересылки - система впадает в ожидание и сообщает об истечении таймаута. Проблема в том, что хотелось бы вызывать ioctl именно тогда, когда буфер заполнен, чтобы своевременно забирать данные из него, и не стартовать тогда, когда он не заполнен. Есть ли у кого опыт решения подобной задачи?

   2. С использованием второй корки - несколько еще веселее. Был выбран драйвер, который не поддерживает многопоточность. Он здесь:
https://github.com/bperez77/xilinx_axidma

Здесь также используются оба канала DMA: через первый (TX) данные поступают на интерполятор и дальше в DAC, а через второй (RX) канал данные поступают с FPGA. Здесь тоже хотелось бы вызывать пересылку только в момент, когда данные есть в буфере (в частности это касается второго канала - RX), потому-что если их нет - то команда зависнет на время таймаута, что недопустимо в системе. Имеется ли опыт работы с таким у кого-то?

Подскажите пожалуйста.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 hours ago, Kiryanov said:

Подскажите пожалуйста.

если этот тот драйвер что вы используете то в нём не реализована poll

https://github.com/Xilinx-Wiki-Projects/software-prototypes/blob/4efebc90dde0e6b8004358faa77583f72628f076/linux-user-space-dma/Software/Kernel/dma-proxy.c#L387

дописать надо не больше 10 строк наверно. Во втором драйвере аналогично poll не реализован

https://github.com/bperez77/xilinx_axidma/blob/42ed91e83bc4da1e29149b2be0c6a6b8f4549222/driver/axidma_chrdev.c#L538

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за подсказку. В целом - я вообще не знал даже куда копать. Не скрою: в написании драйверов я пока новичок, разве что на уровне _module_init() _module_exit(). Не могли бы вы мне посоветовать: где хотя бы посмотреть? Используемые структуры - более-менее понятно. А вот названия функций, их объявление, где они прописываются - пока темный лес. Можно ли где-то найти примеры реализации?

Основательно читать Linux Device Drivers сейчас времени нет, нужно срочное решение. Спасибо!

Изменено пользователем Kiryanov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 4/22/2022 at 11:57 AM, Kiryanov said:

я вообще не знал даже куда копать

для начала - в вашем примере с poll этот poll вообще не нужен, в драйвере (если этот тот драйвер который вы используете) блокирующий ioctl для ожидания окончания тразакции,  для одного файлового дескриптора нет разницы как вы будете ожидать поступления данных - через poll или другой блокирующий вызов - текущая задача одинаково переходит в режим ожидания, надо лишь настроить таймаут чтобы не просыпаться раньше времени. Если хочется poll - примеров в ядре предостаточно, вот тут по шагам есть что надо дописать

 

https://stackoverflow.com/questions/30035776/how-to-add-poll-function-to-the-kernel-module-code/30038432#30038432

Изменено пользователем sasamy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 4/23/2022 at 12:54 PM, sasamy said:

И снова день добрый!

Прошу прощения, что надолго пропал, просто анализировал решения. Если не использовать поллинг и пользоваться драйвером как он есть - натыкаюсь на одну и ту же проблему: при отсутствии данных в буфере - приемный канал rx_dma - вываливается после таймаута с сообщениями:

axidma: axidma_dma.c: axidma_start_transfer: 305: DMA receive transaction timed out.

xilinx-vdma 40000000.axidma0: Cannot stop channel ee952110: 10008

В системе нет vdma, но при стопе транзакции - вылетает сообщение о xilinx-vdma

Это реакция на функцию

dmaengine_terminate_all(chan->chan);

в самом драйвере (axidma_dma.c).

При вызове axidma_stop_transfer для канала rx (канал 1) это сообщение появляется вновь. После этого пересылка вообще не работает пока драйвер не выгрузить rmmod'ом и снова не перезагрузить insmod'ом. Решения для поллинга я искал для этого, в данном случае мне не понятно вообще как с этим бороться. Посоветуйте пожалуйста.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

22 hours ago, Kiryanov said:

приемный канал rx_dma - вываливается после таймаута

если проблема только в этом и вам надо ожидать завершения транзакции до бесконечности (как в примере с poll), то решить можно заменой ф-ции ожидания без таймаута

https://github.com/bperez77/xilinx_axidma/blob/42ed91e83bc4da1e29149b2be0c6a6b8f4549222/driver/axidma_dma.c#L294
 

    // Wait for the completion timeout or the DMA to complete
    if (dma_tfr->wait) {
        timeout = msecs_to_jiffies(AXIDMA_DMA_TIMEOUT);
//        time_remain = wait_for_completion_timeout(dma_comp, timeout);
        wait_for_completion(dma_comp);
        time_remain = 1;
        status = dma_async_is_tx_complete(chan->chan, dma_cookie, NULL, NULL);

в драйвере dma-proxy.c анаогично

https://github.com/Xilinx-Wiki-Projects/software-prototypes/blob/4efebc90dde0e6b8004358faa77583f72628f076/linux-user-space-dma/Software/Kernel/dma-proxy.c#L239

 

	/* Wait for the transaction to complete, or timeout, or get an error
	 */
//	timeout = wait_for_completion_timeout(&pchannel_p->bdtable[bdindex].cmp, timeout);
	wait_for_completion(&pchannel_p->bdtable[bdindex].cmp);
	timeout = 1;
	status = dma_async_is_tx_complete(pchannel_p->channel_p, pchannel_p->bdtable[bdindex].cookie, NULL, NULL);

 

Изменено пользователем sasamy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 5/14/2022 at 5:18 PM, sasamy said:

если проблема только в этом и вам надо ожидать завершения транзакции до бесконечности (как в примере с poll), то решить можно заменой ф-ции ожидания без таймаута

https://github.com/bperez77/xilinx_axidma/blob/42ed91e83bc4da1e29149b2be0c6a6b8f4549222/driver/axidma_dma.c#L294
 


    // Wait for the completion timeout or the DMA to complete
    if (dma_tfr->wait) {
        timeout = msecs_to_jiffies(AXIDMA_DMA_TIMEOUT);
//        time_remain = wait_for_completion_timeout(dma_comp, timeout);
        wait_for_completion(dma_comp);
        time_remain = 1;
        status = dma_async_is_tx_complete(chan->chan, dma_cookie, NULL, NULL);

в драйвере dma-proxy.c анаогично

https://github.com/Xilinx-Wiki-Projects/software-prototypes/blob/4efebc90dde0e6b8004358faa77583f72628f076/linux-user-space-dma/Software/Kernel/dma-proxy.c#L239

 


	/* Wait for the transaction to complete, or timeout, or get an error
	 */
//	timeout = wait_for_completion_timeout(&pchannel_p->bdtable[bdindex].cmp, timeout);
	wait_for_completion(&pchannel_p->bdtable[bdindex].cmp);
	timeout = 1;
	status = dma_async_is_tx_complete(pchannel_p->channel_p, pchannel_p->bdtable[bdindex].cookie, NULL, NULL);

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

День добрый! Попробовал - так вообще не работает:

# axidma: axidma_dma.c: axidma_start_transfer: 307: DMA transmit transaction timed out.

это сообщение вылетает сразу. Ну и такое поведение, наверное, сразу предусмотрено здесь:

        if (time_remain == 0) {
            axidma_err("%s %s transaction timed out.\n", type, direction);
            rc = -ETIME;
            goto stop_dma;
парой строк ниже.

И еще момент: ожидать до бесконечности, как я понимаю, не подойдет, потому-что у меня не должно быть бесконечных блокировок. В работе изделия предусмотрено: по управляющим сигналам (из другого потока) у меня включается либо канал tx либо канал rx. И если я переключу в другой режим в тот момент, когда на функции axidma_oneway_transfer устройство будет в режиме бесконечного ожидания (например для канала rx), и в это же время начнется подача данных для канала tx - это ситуация не рабочая.

   Нужно не оэжидание до бесконечности, а все же корректный стоп dma-канала, но чтобы при его старте возобновлялась работоспособность. Сейчас стоп происходит некорректно, и все вываливается:

 

# axidma: axidma_dma.c: axidma_start_transfer: 307: DMA receive transaction timed out.                                                          
xilinx-vdma 40000000.axidma0: Cannot stop channel ef100e10: 10008 

 

и корректного возобновления работы не происходит. После этого не работает и tx канал, даже при подаче на него данных и он вываливается по таймауту с теми же сообщениями.

 

Изменено пользователем Kiryanov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сложность в том, что никакого VDMA у меня в принципе нет, и почему он обращается вообще к нему - мне не понятно.

axi_dma_0: axidma0@40000000 {
      #dma-cells = <1>;
      compatible = "xlnx,axi-dma", "xlnx,axi-dma-6.03.a", "xlnx,axi-dma-1.00.a";
      reg = <0x40000000 0x10000>;
      clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>, <&clkc 15>;
      clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";    
      xlnx,include-sg;    
      xlnx,addrwidth = <32>;

      dma-mm2s-channel@40000000 {
        compatible = "xlnx,axi-dma-mm2s-channel";
        dma-channels = <1>;
        xlnx,datawidth = <256>;
        xlnx,device-id = <0>;
        interrupt-parent = <&intc>;
        interrupts = <0 29 4>;
      };
    
      dma-s2mm-channel@40000030 {
        compatible = "xlnx,axi-dma-s2mm-channel";
        dma-channels = <1>;
        xlnx,datawidth = <256>;
        xlnx,device-id = <1>;
        interrupt-parent = <&intc>;
        interrupts = <0 30 4>;
      };
    };

Вот это фрагмент dts-файла обращения к используемой корке DMA с помощью драйвера axidma от bperez77.

Или здесь нужно напрячься и реализовать все же поллинг?

Изменено пользователем Kiryanov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще на один момент набрел, уже с DMA_proxy:

На C программу пишу - не видно эффектов, а на C++                 


                memcpy(tx_proxy_interface_p->buffer, &HF_Receive.receive_buf[0], n);
                int var = ioctl(tx_proxy_fd, 0, &dummy);
                if(var != 0)
                    perror("DMA ioctl:");

сама функция perror не пишет ничего плохого: DMA ioctl:: Success , но идет ожидание тайм аута и выдается сообщение:

xilinx-vdma 40400000.axidma0: Channel ef100c10 has errors 200, cdr 0 tdr ef100c00                                                                
DMA timed out

Опять же откуда-то берется vdma, которого нет. Описание второй DMA-корки в dts:

        axi_dma_1: axidma0@40400000 {
            #dma-cells = <1>;
            compatible = "xlnx,axi-dma", "xlnx,axi-dma-6.03.a", "xlnx,axi-dma-1.00.a";
            reg = <0x40400000 0x10000>;
            clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>, <&clkc 15>;
            clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";    
            xlnx,include-sg;    
            xlnx,addrwidth = <32>;

            dma-mm2s-channel@40400000 {
                compatible = "xlnx,axi-dma-mm2s-channel";
                dma-channels = <1>;
                xlnx,datawidth = <32>;
                xlnx,device-id = <0>;
                interrupt-parent = <&intc>;
                interrupts = <0 31 4>;
            };
    
            dma-s2mm-channel@40400030 {
                compatible = "xlnx,axi-dma-s2mm-channel";
                dma-channels = <1>;
                xlnx,datawidth = <32>;
                xlnx,device-id = <1>;
                interrupt-parent = <&intc>;
                interrupts = <0 32 4>;
            };
        };

Оно почти не отличается от axi_dma_0, только драйвера разные. Как убрать это обращение к vdma в обоих случаях?

Изменено пользователем Kiryanov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 hours ago, Kiryanov said:

это сообщение вылетает сразу. Ну и такое поведение, наверное, сразу предусмотрено здесь:

        if (time_remain == 0) {
            axidma_err("%s %s transaction timed out.\n", type, direction);

похоже вы не заметили что в моём примере не только закоментирована строка но и добавлены две

Quote

//        time_remain = wait_for_completion_timeout(dma_comp, timeout);
        wait_for_completion(dma_comp);
        time_remain = 1;

так что этого сообщения просто не может быть

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый вечер. Простите за задержку. Попробоавал на отладочной плате с dma-proxy: - у меня более старая версия драйвера под 4.9 ядро. Изменил так:

    //timeout = wait_for_completion_timeout(&pchannel_p->cmp, timeout);
    wait_for_completion(pchannel_p->cookie);
    timeout = 1;
    status = dma_async_is_tx_complete(pchannel_p->channel_p, pchannel_p->cookie, NULL, NULL);

Получилось вот такое:

 

# xilinx-vdma 40400000.axidma0: Cannot start channel ef207e10: 24209                                                                                
Alignment trap: not handling instruction e1902f9f at [<c0539e10>]                                                                                   
Unhandled fault: alignment exception (0x001) at 0x00000006                                                                                          
pgd = ee800000                                                                                                                                      
[00000006] *pgd=00000000                                                                                                                            
Internal error: Oops - BUG: 1 [#1] PREEMPT SMP ARM                                                                                                  
Modules linked in: dma_proxy(O) usb_f_rndis u_ether libcomposite xilinx_dma [last unloaded: dma_proxy]                                              
CPU: 1 PID: 847 Comm: ReceiveWorkHF_A Tainted: G           O    4.9.0-xilinx #5                                                                     
Hardware name: Xilinx Zynq Platform                                                                                                                 
task: ef07d180 task.stack: ee9c2000                                                                                                                 
PC is at _raw_spin_lock_irq+0x24/0x5c                                                                                                               
LR is at wait_for_common+0x20/0x134                                                                                                                 
pc : [<c0539e14>]    lr : [<c0537448>]    psr: 60000093                                                                                             
sp : ee9c3eb8  ip : ef148040  fp : bea8ec7c                                                                                                         
r10: 00000000  r9 : ee9c2000  r8 : 00000002                                                                                                         
r7 : 00000006  r6 : ee9976c0  r5 : 00000002  r4 : 7fffffff                                                                                          
r3 : ee9c2000  r2 : 00000001  r1 : 7fffffff  r0 : 00000006                                                                                          
Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment none                                                                                  
Control: 18c5387d  Table: 2e80004a  DAC: 00000051                                                                                                   
Process ReceiveWorkHF_A (pid: 847, stack limit = 0xee9c2210)                                                                                        
Stack: (0xee9c3eb8 to 0xee9c4000)                                                                                                                   
3ea0:                                                       ef207e1c 20000013                                                                       
3ec0: 00000001 00000012 bf04ae00 ef144ab8 ee9976c0 bf04ae00 ef144ab8 ee9976c0                                                                       
3ee0: bea8ec40 ee9976c0 ee9c2000 bf04a13c bf04ae00 00000000 00000001 00000000                                                                       
3f00: bf04ae00 bf04a22c bea8ec40 c01db720 bea8ec40 c01db8f8 00000000 00000000                                                                       
3f20: ee9c2000 40000001 00000002 c011dc24 00000000 00000000 00400000 0000000a                                                                       
3f40: ef242480 00000000 ef242488 eec6acd0 00000002 00000000 bea8eab0 c01cc6c0                                                                       
3f60: 00000000 00000000 0000000a ee9976c0 00000005 00000000 bea8ec40 ee9976c0                                                                       
3f80: ee9c2000 00000000 bea8ec7c c01dc118 7f5fcf2c 00000000 7f5eadcc 00000036                                                                       
3fa0: c0106ec4 c0106d00 7f5fcf2c 00000000 00000005 00000000 bea8ec40 00000000                                                                       
3fc0: 7f5fcf2c 00000000 7f5eadcc 00000036 00000000 00000000 7f5fcf2c bea8ec7c                                                                       
3fe0: 7f5fcf60 bea8eb80 7f5eb6c8 b6d54b34 60000010 00000005 bdee57cc 8cd051cd                                                                       
[<c0539e14>] (_raw_spin_lock_irq) from [<c0537448>] (wait_for_common+0x20/0x134)                                                                    
[<c0537448>] (wait_for_common) from [<bf04a13c>] (wait_for_transfer+0x20/0x80 [dma_proxy])                                                          
[<bf04a13c>] (wait_for_transfer [dma_proxy]) from [<bf04a22c>] (ioctl+0x20/0x28 [dma_proxy])                                                        
[<bf04a22c>] (ioctl [dma_proxy]) from [<c01db720>] (vfs_ioctl+0x20/0x38)                                                                            
[<c01db720>] (vfs_ioctl) from [<c01db8f8>] (do_vfs_ioctl+0x9c/0x884)                                                                                
[<c01db8f8>] (do_vfs_ioctl) from [<c01dc118>] (SyS_ioctl+0x38/0x54)                                                                                 
[<c01dc118>] (SyS_ioctl) from [<c0106d00>] (ret_fast_syscall+0x0/0x3c)                                                                              
Code: e2822001 e5832004 f590f000 e1902f9f (e2823801)                                                                                                
---[ end trace ffe0c43a49eeadec ]---                                                                                                                
note: ReceiveWorkHF_A[847] exited with preempt_count 1

 

Где ReceiveWorkHF - это рабочая программа из UserSpace.

 

Последний драйвер от [ilinx : https://github.com/Xilinx-Wiki-Projects/software-prototypes/tree/master/linux-user-space-dma/Software - в ядро insmod'ится, но не работает. Не приходит ни одного прерывания

 

dma-proxy.c dma-proxy.h

Вместо https://github.com/bperez77/xilinx_axidma применил https://github.com/corna/xilinx_axidma  в котором есть возможность мониорить остаток свободного места в буфере для rx-канала с помощью функции axidma_get_residue - это заработало. А вот dma-proxy пока не желает.

Изменено пользователем Kiryanov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Рассмотрите использование механизмов уведомлений, таких как wait_event_interruptible, чтобы блокировать поток, ожидающий появления данных в буфере. Когда данные появляются, поток разблокируется и может продолжить выполнение. Используйте механизм очереди работ для планирования асинхронной работы, когда появляются данные в буфере. Такой подход может позволить вам избежать блокировок и таймаутов. Если это необходимо, рассмотрите возможность внесения изменений в исходный код драйвера, чтобы поддерживать асинхронные операции или другие механизмы оповещения о наличии данных.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Использование механизмов уведомлений, таких как wait_event_interruptible, в комбинации с механизмом очереди работ может быть полезным для решения проблемы блокирования потока, ожидающего появления данных в буфере. Если потребуется надо купить прокси, чтобы можно было зайти на сайт. Давайте рассмотрим пример такого подхода на языке ядра Linux (C).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...