UPGRADE YOUR BROWSER

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!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor srhodgetts
Visitor
143 Views
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?

 

Hello,

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,

Stephanie

 

 

0 Kudos
1 Reply
Visitor srhodgetts
Visitor
62 Views
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);
BUG_ON(engine->magic != MAGIC_ENGINE);

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

xdev = engine->xdev;
BUG_ON(!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