jeremytrimble / ezdma Goto Github PK
View Code? Open in Web Editor NEWSimple, zero-copy DMA to/from userspace.
Simple, zero-copy DMA to/from userspace.
Hi.
I'm writing a DMA driver for my hardware. I don't know about parameter was set on FPGA. Your code works well in user-space. I tried you your code in my driver, but it cannot run get_user_pages_fast
with my buffer. I also followed dmatest.c in xilinx's kernel, it work but when I transmit with higher speed, it showed error: xilinx-dma 40410000.dma: Channel ef31b890 has errors 11 cdr 0 cdr msb 0 tdr 0 tdr msb 0
.
Can you help me solve this error? Thank you.
Here is my code:
static int dma_read(struct dma_priv *priv, uint8_t __kernel *buffer,
size_t count, uint32_t timeout)
{
struct dma_device *device = priv->chan->device;
struct dma_async_tx_descriptor *rxd = NULL;
dma_addr_t dma_src;
struct scatterlist rx_sg[1];
struct completion rx_cmp;
int i, ret=0;
if (down_interruptible(&priv->sem)) {
return -ERESTARTSYS;
}
dma_src = dma_map_page(device->dev, virt_to_page(buffer),
offset_in_page(buffer), count, DMA_DEV_TO_MEM);
if (dma_mapping_error(device->dev, dma_src)) {
error("Mapping error\n");
ret = -1;
goto read_map_err;
}
sg_init_table(rx_sg, 1);
sg_dma_address(&rx_sg[0]) = dma_src;
sg_dma_len(&rx_sg[0]) = count;
rxd = dmaengine_prep_slave_single(priv->chan, dma_src, count,
DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
if (!rxd) {
error(" prep err\n");
dma_unmap_single(device->dev, dma_src, count, DMA_MEM_TO_DEV);
ret = -1;
goto read_out;
}
init_completion(&priv->completion);
rxd->callback = dma_tx_callback;
rxd->callback_param = priv;
priv->cookie = dmaengine_submit(rxd);
if (dma_submit_error(priv->cookie)) {
warn("submit error\n");
}
dma_async_issue_pending(priv->chan);
wait_for_completion(&priv->completion);
if (dma_async_is_tx_complete(priv->chan, priv->cookie, NULL, NULL)
!= DMA_COMPLETE) {
error("DMA error\n");
ret = -1;
goto read_out;
}
ret = priv->bytes_xfered;
read_map_err:
dma_unmap_single(device->dev, dma_src, count, DMA_MEM_TO_DEV);
read_out:
up(&priv->sem);
return ret;
}
Hello,
Taking a look in ezsdk code I see it use SG dma method.
Does it mean that it does not support dma_alloc_coherent (contiguous) memory allocation ?
Thank you,
Ran
Hi Jeremy,
I am using ezdma with Xilinx AXI DMA. When I try to initiate a 1 MB read transfer, ezdma throws this error:
ezdma: loop_rx: dmaengine_prep_slave_sg() failed
I traced the error back to xilinx_dma_alloc_tx_segment() which is called by xilinx_dma_prep_slave_sg(). This function returns NULL (free_seg_list is empty?). I also tried to find the maximum possible size. It turns out to be 1 MB minus 8192 bytes.
Any idea on this? Is it a Xilinx driver issue or ezdma one?
Does it happen to have a relation with the maximum number of descriptors "XILINX_DMA_NUM_DESCS" defined in the Xilinx driver?
Best,
Farzad
Hello all,
Im using petalinux-2018.3 to build image for zedboard.
When I use intrarmfs for rootfs im able to see my ezdma userspace nodes namely loopback_rx and tx.
However if I use SD card rootfs i.e. /dev/mmcblk0p2 then I dont see my ezdma usespace nodes.
Im attempting to use debian rootfs on the zed.
Has anyone been able to use their ezdma nodes on other rootfs other than intrarmFS??
What configuration were done to kernel with petalinux????
Thanks all
Hi Jeremy.
I'm hoping to use ezdma in a project for work, but I'm not getting very far. It's likely that the problem stems from my lack of experience with the Linux DMA engine, and the usual difficulty of finding relevant documentation. I'm using the PL330 DMAC on a Zynq 70xx. The example you provide uses the AXI DMA IP, which has a very different device-tree node.
I have to manually load (modprobe or insmod) the driver, which is a bit of a red flag. And when I do, ezdma_probe() is never called, and of course the /dev/* nodes are never created.
Have you tried ezdma with the Pl330, or do you know of anyone who has?
Here's some debug output that shows what little is happening in the driver on "modprobe ezdma."
Mar 30 01:56:48 snoodle-01 kernel: [ 5216.552188] ezdma: ezdma_driver_init()
Mar 30 01:56:48 snoodle-01 kernel: [ 5216.552214] ezdma: allocated chrdev region: Major: 246, Minor: 0-8
Mar 30 01:56:48 snoodle-01 kernel: [ 5216.552506] ezdma: platform_driver_register(ezdma) returned 0
Thanks,
-Nick
Hi jeremy, in using your ezdma driver to work with DMA transactions. If make a read() and write() with 1KB, the drivers works very well. This is your loopback example. But in my application, in need to write() a 40kB and read() only 1 kB. Using your driver with this constraints, the make the Scatter Gatter table, starts the DMA transactions but the system halts waiting the DMA interrupt.
This is the output Linux console. I`m using the hardware loopback
ezdma: loop_tx: sg_alloc_table() returned 0
ezdma: loop_tx: get_user_pages_fast() returned 11, expected 11
ezdma: loop_tx: sgl[0]: page: dfbe1360, len: 4000, offset: 96
ezdma: loop_tx: sgl[1]: page: dfba0fc0, len: 4096, offset: 0
ezdma: loop_tx: sgl[2]: page: dfba05c0, len: 4096, offset: 0
ezdma: loop_tx: sgl[3]: page: dfbb2f40, len: 4096, offset: 0
ezdma: loop_tx: sgl[4]: page: dfbd8420, len: 4096, offset: 0
ezdma: loop_tx: sgl[5]: page: dfbb6780, len: 4096, offset: 0
ezdma: loop_tx: sgl[6]: page: dfbb3880, len: 4096, offset: 0
ezdma: loop_tx: sgl[7]: page: dfbb03a0, len: 4096, offset: 0
ezdma: loop_tx: sgl[8]: page: dfbb46e0, len: 4096, offset: 0
ezdma: loop_tx: sgl[9]: page: dfbafb60, len: 4096, offset: 0
ezdma: loop_tx: sgl[10]: page: dfbedec0, len: 96, offset: 0
ezdma: loop_tx: dma_map_sg() returned 11, expected 11
ezdma: loop_tx: issued pending for TX
The same app with only 10kB (only write() ) the driver works very good.
ezdma: loop_tx: sg_alloc_table() returned 0
ezdma: loop_tx: get_user_pages_fast() returned 3, expected 3
ezdma: loop_tx: sgl[0]: page: dfbb7920, len: 4000, offset: 96
ezdma: loop_tx: sgl[1]: page: dfbbd900, len: 4096, offset: 0
ezdma: loop_tx: sgl[2]: page: dfb9b5c0, len: 2144, offset: 0
ezdma: loop_tx: dma_map_sg() returned 3, expected 3
ezdma: loop_tx: issued pending for TX
ezdma: loop_tx: callback fired for TX
But if execute 3 times the app the systems halts waiting DMA interrupt.
I need some help to work with bigger sizes of DMA transactions,
Thank you
Any tips/advice on how to go about getting this driver to work for the xilinx zynq ultrscale+ devices?
Hi Jeremy,
I don't have an issue but three questions about your code which I am looking at for educational purposes.
1.
I want to report the physical addresses of the pages so I entered the following right after the dmap_map_sg() function
printk("Physical Address: 0x%08lX", sg_dma_address(table.sgl));
The value reported makes sense but this seems to only get the address of the first page. Any idea how I can print out the physical address for each of the pages in the scatterlist?
2.I am having a hard time understanding the following piece of code
//sg_set_page( sgl, p_info->inflight.pinned_pages[i], len, offset );
sg_set_page( sg, p_info->inflight.pinned_pages[i], len, offset );
left_to_map -= len;
my main confusion comes from the fact that sg is not used again in the function, can you explain how this works?
Hi Jeremy,
First of all, congratulations, your driver works very well!. However, I have an annoying problem if I have to stop an uncompleted DMA operation (either write or read).
I have a sample project in Vivado 2016.2 and a Zedboard hardware (AXI-DMA connected to a loopback AXI-Stream FIFO), with a AD Kernel 4.4 running on Linaro Debian distribution.
The loopback ezdma_speed_test is working:
sudo ./ezdma_speed_test
sent 100000 4096-byte packets in 17.003143051 sec: 22.974 MB/s
But, if I launch a read operation and the FIFO is empty, then, the device read function is waiting the DMA transaction to finish, as expected. In that situation, if I cancel the read operation, by hitting for instance, CTRL+C, then, ezdma driver tries to cancel the DMA operation of the xilinx-dma driver (by calling xilinx_dma_terminate_all() ), but it says that "cannot stop channel" and triggers a Kernel panic. Take a look to this Kernel crash (and system hangs!):
sudo ./ezdma_read
Receiving 100000 4096-byte packets
^C <<< CTRL+C is hit here to stop the process >>>
BUG: scheduling while atomic: ezdma_receive/2588/0x00000002
Modules linked in: ezdma(O)
CPU: 1 PID: 2588 Comm: ezdma_receive Tainted: G O 4.4.0-g6515388-dirty #7
Hardware name: Xilinx Zynq Platform
[] (unwind_backtrace) from [] (show_stack+0x10/0x14)
[] (show_stack) from [] (dump_stack+0x80/0xcc)
[] (dump_stack) from [] (__schedule_bug+0x44/0x60)
[] (__schedule_bug) from [] (__schedule+0x88/0x4c4)
[] (__schedule) from [] (schedule+0xb0/0xcc)
[] (schedule) from [] (schedule_hrtimeout_range_clock+0xc4/0x100)
[] (schedule_hrtimeout_range_clock) from [] (usleep_range+0x44/0x4c)
[] (usleep_range) from [] (xilinx_dma_terminate_all+0x98/0x154)
[] (xilinx_dma_terminate_all) from [] (ezdma_read+0x148/0x188 [ezdma])
[] (ezdma_read [ezdma]) from [] (__vfs_read+0x20/0xcc)
[] (__vfs_read) from [] (vfs_read+0x84/0xec)
[] (vfs_read) from [] (SyS_read+0x40/0x80)
[] (SyS_read) from [] (ret_fast_syscall+0x0/0x3c)
xilinx-dma 40400000.dma: Cannot stop channel df7614d0: 10008
Kernel panic - not syncing: Aiee, killing interrupt handler!
This is normal? is there a way to cancel a pending DMA operation gracefully?
Thank you for your time!
Javier.
At risk of abusing the issues system, I'm curious to know what the current status is of this driver.
I too would very much like to have such a device driver for pushing data from user-space over DMA. Have you made any more attempts to get it added to the mainline kernel tree?
Cheers,
Henry
I've been using 32 KB dma transactions to reliably transfer streaming data. I can read 1 or 100,000 dma dma blocks reliable. However, when increasing the read size by a factor of 2 (to 65KB), I get a kernel error:
[ 3052.666641] xilinx-vdma 40450000.axidma: Channel de8e5810 has errors 200, cdr 780 tdr 1f502900
[ 3053.667960] xilinx-vdma 40450000.axidma: Cannot start channel de8e5810: 10209
It appears that the error is sourced somewhere in the xilinx dma driver. When this happens, the dma also hangs, never returning (data continues streaming, though now it is just dropped in the fpga fabric buffering). I have two 128 KB FIFOs going into the DMA so it isn't that I'm overrunning those. Do you have any ideas of what can be done to increase the dma size?
Hi jeremy,
I use petalinux v2016.3 to contain the source code of ezdma.c in my created module. Once the linux on board booted, I typed "insmod /lib/modules/'uname -r'/extra/ezdma.ko" or "modprobe ezdma", but the terminal outputs:
"ezdma: allocated chrdev region: Major: 244 , Minor: 0-8
probing ezdma
ezdma: couldn't find dma channel: loop_tx, deferring...
ezdma: loop_tx (TX) available
ezdma: couldn't find dma channel: loop_rx, deferring...
ezdma: loop_rx (RX) available"
I debug the source and found some errors occured in the code segment:
/* Get the named DMA channel */
p_info->chan = dma_request_slave_channel(
&pdev->dev, p_dma_name);
if ( !p_info->chan )
{
printk( KERN_WARNING KBUILD_MODNAME
": couldn't find dma channel: %s, deferring...\n",
p_info->name);
outer_rv = -EPROBE_DEFER;
}
the function "dma_request_slave_channel( &pdev->dev, p_dma_name)" returned an unexpected value assigned to "p_info->chan". I can not find either "loop_tx" or "loop_rx" in dir "/dev/". I wondered what's the problem, and what steps might I forgot to exec? Thank you!
Hi Jeremy,
I'm trying to DMA very large buffers (512M byte if I can) into memory. I seem to run into a memory problem for sg_alloc_table if I try to create a DMA buffer > 1Mbyte. I believe I just have too many entries in the sg table.
My AXI DMA core is configured with 23bit addressing for the scatter/gather engine which should allow for individual DMA blocks of up to 8MByte each, so it should be possible to describe the 512 MByte buffer with just 64 chained entries. Looking at the ezdma driver it seems like you are allocating blocks of 4096 bytes for each of the scatterlist entries. Is there a way to allocate 8Mbyte blocks for each of the scatterlist entries so I can reduce the number of them?
Thanks Mike.
I'm not sure if this is the right place to ask this, but I wasn't able to find your email anywhere.
Anyway, we'd like to use this driver to stream data from the PL on the Zedboard into the linux userspace. We are initially trying to get your loopback example running on the Zedboard, however we're having trouble getting the devicetree working. Currently we get the following error:
ezdma: allocated chrdev region: Major: 245, Minor: 0-8
probing ezdma
ezdma: couldn't find dma channel: loop_tx, deferring...
ezdma: loop_tx (TX) available
ezdma: couldn't find dma channel: loop_rx, deferring...
ezdma: loop_rx (RX) available
platform ezdma0: Driver ezdma requests probe deferral
Our dma device in the device tree looks like:
/ {
amba_pl: amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
axi_dma_1: axidma@40400000 {
#dma-cells = <1>;
compatible = "xlnx,axi-dma";
interrupt-parent = <&intc>;
interrupts = <0 29 4 0 30 4>;
reg = <0x40400000 0x10000>;
xlnx,include-sg ;
loop_tx: dma-channel@40400000 {
compatible = "xlnx,axi-dma-mm2s-channel";
interrupts = <0 29 4>;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x1>;
};
loop_rx: dma-channel@40400030 {
compatible = "xlnx,axi-dma-s2mm-channel";
interrupts = <0 30 4>;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x1>;
};
};
};
ezdma0 {
compatible = "ezdma";
dmas = <&axi_dma_1 0 &axi_dma_1 1>;
dma-names = "loop_tx", "loop_rx"; // used when obtaining reference to above DMA core using dma_request_slave_channel()
ezdma,dirs = <2 1>; // direction of DMA channel: 1 = RX (dev->cpu), 2 = TX (cpu->dev)
};
};
I was hoping you may be able to help figure out why the driver can't find the device as we defined in our devicetree. If this is the wrong forum for this issue please let me know how I should contact you. Thanks!!
Hi Jeremy was your module added to baseline kernel?
Whats the difference between EZDMA and Xilinx's dma_proxy??
Is one better than the other?
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842418/Linux+DMA+From+User+Space
Thanks
I'm running your driver on an xilinx embedded linux (built w/ petalinux 2017.3) and a Zynq Ultrascale device, and when I run the speed test /loopback test, dma_map_sg returns 0 and errors out. My HW is an AXI-DMA looped back through an AXI-4 Stream Data Fifo.
The AXI DMA hw (vivado gui) properties are:
Width of Buffer Length Register: 14 bits
Address Width: 32 bits
Max burst size: 128
Stream Data width: 32
Allow unalligned transfers is unchecked.
Enable Scatter Gather Engine is checked.
I tried changing the packet size to a smaller value such that there is only a single entry in the SG table, but I get the same error. I am currently trying see about comparing addresses between the userspace test program and the driver/module.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.