Драйвер AXI DMA Linux на ZynqMPLinux

Ответить
Anonymous
 Драйвер AXI DMA Linux на ZynqMP

Сообщение Anonymous »

У меня есть плата ZynqMP с 4 ГБ ОЗУ PS и 2 ГБ ОЗУ PL. Мне нужно записать потоковые данные в PL RAM, используя канал AXI DMA s2mm, и передать их через 1G Ethernet. Я сделал это в проекте с голым железом, но теперь мне нужно сделать это при работающем Linux (я создал образ с помощью Yocto). Я написал специальный драйвер для AXI DMA, который использует функции механизма DMA Linux по умолчанию, поскольку Xilinx написала свой драйвер, который интегрируется в Linux. Поскольку оба моих порта M_AXI_SG и M_AXI_S2MM подключены к PL RAM (0x4_0000_0000 - 0x4_7FFF_FFFF), и буфер данных, и кольцевой буфер bd ДОЛЖНЫ находиться в PL RAM. Поэтому я зарезервировал эту память в дереве устройств следующим образом:

Код: Выделить всё

reserved-memory {
#address-cells = ;
#size-cells = ;
ranges;

pl_dma_pool: dma_pool@400000000 {
compatible = "shared-dma-pool";
no-map;
reg = ;
};
};

reserved-mem@400000000 {
compatible = "xlnx,reserved-memory";
memory-region = ;
};
Вот и другие важные узлы:

Код: Выделить всё

axi_dma_0: dma@80000000 {
interrupts = ;
compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
xlnx,s2mm-data-width = ;
xlnx,mm2s-burst-size = ;
xlnx,m-axi-mm2s-data-width = ;
xlnx,num-s2mm-channels = ;
xlnx,dlytmr-resolution = ;
interrupt-parent = ;
xlnx,sg-length-width = ;
xlnx,prmry-is-aclk-async = ;
xlnx,include-s2mm-sf = ;
#dma-cells = ;
xlnx,ip-name = "axi_dma";
xlnx,single-interface = ;
xlnx,sg-include-stscntrl-strm = ;
xlnx,include-s2mm-dre = ;
reg = ;
xlnx,addr-width = ;
xlnx,include-s2mm = ;
clocks = ,
,
;
xlnx,s-axis-s2mm-tdata-width = ;
xlnx,micro-dma = ;
xlnx,increase-throughput = ;
xlnx,mm2s-data-width = ;
xlnx,addrwidth = ;
xlnx,include-sg;
xlnx,sg-use-stsapp-length = ;
xlnx,m-axis-mm2s-tdata-width = ;
xlnx,edk-iptype = "PERIPHERAL";
xlnx,s2mm-burst-size = ;
xlnx,m-axi-s2mm-data-width = ;
xlnx,num-mm2s-channels = ;
xlnx,enable-multi-channel = ;
status = "okay";
xlnx,include-mm2s-sf = ;
clock-names = "m_axi_s2mm_aclk", "m_axi_sg_aclk", "s_axi_lite_aclk";
interrupt-names = "s2mm_introut";
xlnx,include-mm2s = ;
xlnx,include-mm2s-dre = ;
phandle = ;
memory-region = ;

dma_channel_80000030:  dma-channel@80000030 {
interrupts = ;
xlnx,datawidth = ;
xlnx,device-id = ;
compatible = "xlnx,axi-dma-s2mm-channel";
dma-channels = ;
phandle = ;
memory-region = ;
};
};

axidma_driver {
compatible = "xlnx,axidma_driver";
reg = ;
dmas = ;
dma-names = "axidma_rx";
dma-coherent;
memory-region = ;
};
В функциях зонда() драйвера я успешно запрашиваю канал s2mm с помощью dma_request_chan() и выделяю буфер почти 2 ГБ с помощью dmam_alloc_coherent().
В своих функциях setup_transfer(), которые вызываются в ioctl(), я использую axidmatest.c в качестве примера и выполняю этот код:

Код: Выделить всё

spin_lock(&adev->s2mm->lock);
    adev->s2mm->transfer_complete = false;
    spin_unlock(&adev->s2mm->lock);

    sg_init_table(adev->s2mm->sglist, BD_CNT);

    for (int i = 0; i < BD_CNT; i++) {
        sg_set_buf(&adev->s2mm->sglist[i], adev->s2mm->data_virt_addr + i*TRANSFER_SIZE, TRANSFER_SIZE);
        sg_dma_address(&adev->s2mm->sglist[i]) = data_phys_addr + i * TRANSFER_SIZE;
        sg_dma_len(&adev->s2mm->sglist[i]) = TRANSFER_SIZE;
    }

    adev->s2mm->desc = adev->s2mm->dma_dev->device_prep_slave_sg(adev->s2mm->dma_channel, adev->s2mm->sglist, BD_CNT, DMA_DEV_TO_MEM, flags, NULL);
    if (!adev->s2mm->desc) {
        pr_err("Failed to prepare SG list\n");
        return -ENOMEM;
    }

    adev->s2mm->desc->callback = axidma_callback;
    adev->s2mm->desc->callback_param = adev;

    adev->s2mm->cookie = adev->s2mm->desc->tx_submit(adev->s2mm->desc);

    dma_async_issue_pending(adev->s2mm->dma_channel);
После этого программа зависает в ожидании прерывания завершения. После распечатки фактических регистров AXI DMA s2mm (после dma_async_issue_pending() ) я обнаружил, что s2mm_curdesc указывает на текущий дескриптор буфера, который нужно обработать, и s2mm_taildesc определенно не указывают на PL RAM. Я думаю (?), что выделение кольца BD происходит внутри драйвера Xilinx, так что я могу сделать в этом случае, чтобы убедиться, что мое кольцо BD распределяется внутри PL RAM? Кроме того, вот дампы регистров: первый находится в начале функции зонда(), второй — в конце, а третий — в конце функции setup_transfer():

Код: Выделить всё

[ 4.688662] axidma: loading out-of-tree module taints kernel.
[ 4.695278] AXI DMA driver initialization started!
[ 4.700074] Successfully allocated AXI DMA device!
[ 4.704865] axidma_driver 80000000.axidma_driver: Reg base address: 0x0x0000000080000000, size: 0x10000
[ 4.714274] axidma_driver 80000000.axidma_driver: Reg virtual address: 0xffff800081b50000
[ 4.722456] axidma_driver 80000000.axidma_driver: Register 48 stores: 0x00017002
[ 4.729851] axidma_driver 80000000.axidma_driver: Register 52 stores: 0x00010009
[ 4.737246] axidma_driver 80000000.axidma_driver: Register 56 stores: 0x00000000
[ 4.744642] axidma_driver 80000000.axidma_driver: Register 60 stores: 0x00000000
[ 4.752037] axidma_driver 80000000.axidma_driver: Register 64 stores: 0x00000000
[ 4.759432] axidma_driver 80000000.axidma_driver: Register 68 stores: 0x00000000
[ 4.766828] Successfully allocated S2MM channel!
[ 4.772648] Successfully requested S2MM DMA channel!
[ 4.777626] Successfuly acquired DMA device!
[ 4.782029] axidma_driver 80000000.axidma_driver: assigned reserved memory node dma_pool@400000000
[ 5.730493] Successfully allocated data buffer!
[ 5.735022] Successfully allocated SG list!
[ 5.739394] Successfully registered miscellaneous device!
[ 5.744822] axidma_driver 80000000.axidma_driver: Register 48 stores: 0x00017002
[ 5.752227] axidma_driver 80000000.axidma_driver: Register 52 stores: 0x00010009
[ 5.759631] axidma_driver 80000000.axidma_driver: Register 56 stores: 0x00000000
[ 5.767035] axidma_driver 80000000.axidma_driver: Register 60 stores: 0x00000000
[ 5.774438] axidma_driver 80000000.axidma_driver: Register 64 stores: 0x00000000
[ 5.781841] axidma_driver 80000000.axidma_driver: Register 68 stores: 0x00000000

root@rfsoc-axrf47-sdt-wave:~# axidma-transfer
axidma-transfer started!
axidma device opened successfully!
[ 28.739513] Entered axidma_mmap()
[ 28.758756] axidma_driver 80000000.axidma_driver: Register 48 stores: 0x00017002
[ 28.766193] axidma_driver 80000000.axidma_driver: Register 52 stores: 0x00014509
[ 28.773603] axidma_driver 80000000.axidma_driver: Register 56 stores: 0x019A4000
[ 28.781009] axidma_driver 80000000.axidma_driver: Register 60 stores: 0x00000000
[ 28.788416] axidma_driver 80000000.axidma_driver: Register 64 stores: 0x019A407C
[ 28.795815] axidma_driver 80000000.axidma_driver: Register 68 stores: 0x00000000
[ 28.803210] AXI DMA transfer has been set up!
mmap() executed successfully!'nTransfer started successfully!
[ 28.807642] Entered axidma_poll()
[ 28.816371] Went past poll_wait()
Любая помощь приветствуется! (Кстати, я впервые программирую драйверы для Linux)

Подробнее здесь: https://stackoverflow.com/questions/798 ... -on-zynqmp
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Linux»