Hi Jeremy, On Thu, May 21, 2015 at 09:34:03PM -0400, Jeremy Trimble wrote: > Hello all, > > I've written a kernel module that allows data to be sent to or received from > any DMA device that supports the dmaengine API, using simple read()/write() > calls from userspace. > > Motivation: > > While doing some work for my master's thesis recently using the Xilinx Zynq > SoC, I needed a way to stream test data into and out of an FPGA soft-core I was > developing. I was using the Xilinx AXI DMA soft-core (and its > dmaengine-compatible driver that I believe is related to Kedareswara rao > Appana's patch submitted recently). > > Although dmaengine provides a versatile in-kernel API, to my knowledge there's > no direct userspace interface for the case where one wants to simply > send/receive data through a slave dma channel -- writing a separate > userspace-facing module would be required. (Or some hack using /dev/kmem.) Good. I'd have some usage for that as well, mostly to support the async_tx transfers types though, and offload them from the CPU. > Usage: > > The ezdma ("easy DMA") module implements a read()/write() interface for > receiving/sending data through any slave DMA channel. > > It is configured using the device tree: > > 1. Include a node like below into the device tree: > > ezdma0 { > compatible = "ezdma"; > dmas = <&loopback_dma 0 &loopback_dma 1>; > dma-names = "loop_tx", "loop_rx"; > ezdma,dirs = <2 1>; // direction of DMA channel: > // 1 = RX (dev->cpu), 2 = TX (cpu->dev) > }; > > 2. After inserting the ezdma module, two devices, as named in your dma-names > above, will become available: > > /dev/loop_tx > /dev/loop_rx Even though I understand that this is the most convenient setup right now, I would expect to have this a bit more dynamic, and be able to request/release channels straight from the user-space (to have several memset happening at the same time for example). That would probably require a different interface though, or at least to implement some ioctls. > 3. Sending data is as easy as: > > int tx_fd = open("/dev/loop_tx", O_WRONLY); > int rx_fd = open("/dev/loop_rx", O_RDONLY); > > write(tx_fd, tx_buf, xfer_size); // send a DMA transaction > read (rx_fd, rx_buf, xfer_size); > > Currently, each read()/write() call causes a single transfer to occur in the > underlying slave DMA channel, but support could be added for readv()/writev() > as well. How do you set the address it should be sent to? the width? burst? Is it currently hardcoded (which is totally fine for your use case, but wouldn't really work for other use). This is definitely a good start though. Thanks! Maxime -- Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com
Attachment:
signature.asc
Description: Digital signature