We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

Showing results for 
Search instead for 
Did you mean: 
Visitor srhodgetts
Registered: ‎07-31-2018

Xilinx PCI Express DMA Drivers and Software Guide 65444 nonblocking functionality

I posted this in Embedded Systems/Embedded Linux but I haven't had any replies. https://forums.xilinx.com/t5/Embedded-Linux/Xilinx-PCI-Express-DMA-Drivers-and-Software-Guide-65444/td-p/922220

I think this might be a better location, can anyone help me?



The Xilinx PCI Express DMA Drivers provided here https://www.xilinx.com/support/answers/65444.html work pretty well but there appears to be some missing functionality for nonblocking reads.  I'm using Xilinx_Answer_65444_Linux_Files_rel20180420.zip with Linux Centos 7 and have enable_credit_mp=1.  I have PCIe streaming setup from the FPGA, this works when there is data, but falls apart when reading and 0 bytes are returned.

In the driver there is no implementation of file_operations .poll  in cdev_sgdma.c which would be used by sys/select or sys/poll.  So the file descriptor is always set in currentReadFdSet  for the following select() call in software.  A timeout was expected here when no data was available as currentReadFdSet only contains one fd for the /dev/xdma0.

 select ((nsfd + 1) , &currentReadFdSet, NULL, NULL, &timeoutPeriod)

Secondly nowhere in the code are the file->f_flags evaluated.  There should be checks for O_NONBLOCK in the read functionality and the driver should return -EAGAIN when there is no data on a nonblocking read.

Is the driver setup for nonblocking operations?  because it appears not to be the case.

I ran an experiment using this website (files are attached) http://www.sharetechnote.com/html/Linux_DeviceDriver_Programing.html

If I comment out the testdriver_poll from file_operations like this, then select always returns true and it tries to read the data when none is available.

static struct file_operations testdriver_fops =
.owner = THIS_MODULE,
.open = testdriver_open,
.release = testdriver_close,
.read = testdriver_read,
.write = testdriver_write,
// .poll = testdriver_poll

If it is in place I only read data when it is available, the check for NONBLOCK in the read code when bytes=0 is not seen.  So this seems confirms my hypothesis with the Xilinx driver.

Thanking you in advance,




0 Kudos
1 Reply
Visitor srhodgetts
Registered: ‎07-31-2018

Re: Xilinx PCI Express DMA Drivers and Software Guide 65444 nonblocking functionality

I did try to implement a function in cdev_sgdma.c for the driver but this corrupts the Linux kernel, so it's very hard to debug.  I think I have a chicken and an egg situation with the following code.  I want to check the engine for certain conditions to see if the read will block but the engine transfer is only setup when a 'read' is called so I believe I'm accessing null pointers and hence the code doesn't work.

There is char_events_poll function in the xdma/cdev_events.c file which is very similar to the code below.  I have MSI interrupts enabled which don't seem to trigger the cdev_events_poll or do I need to disable the cyclic buffer for this to work?

unsigned int char_sgdma_poll(struct file* file, poll_table *wait)

struct xdma_engine *engine;
struct xdma_cdev *xcdev = (struct xdma_cdev *)file->private_data;
unsigned long flags;
unsigned int mask = 0;
int rv;
struct xdma_transfer *transfer;
struct xdma_dev *xdev;

pr_info("char_sgdma_poll: begin\n");
rv = xcdev_check(__func__, xcdev, 0);
if (rv < 0)
return rv;

engine = xcdev->engine;
BUG_ON(engine->magic != MAGIC_ENGINE);

if (engine->streaming && engine->dir == DMA_FROM_DEVICE) {

xdev = engine->xdev;

transfer = &engine->cyclic_req->xfer;
poll_wait(file, &transfer->wq, wait);

spin_lock_irqsave(&engine->lock, flags);

if (engine->rx_head!=engine->rx_tail ||engine->rx_overrun) {
  mask = POLLIN | POLLRDNORM; /* readable */

spin_unlock_irqrestore(&engine->lock, flags);

dbg_tfr("char_sgdma_poll: end\n");

return mask;


0 Kudos