Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

Correct use of ALTERA DMA Core with linux

Hi,

I'm playing with a design in order to test the highest throughput from

the FPGA to the SDRAM.

Here you can have my design explained:

http://www.alteraforum.com/forum/showthread.php?t=45290

Basically:

1. I've set the F2S SDRAM Bridge data to 64 bits WIDTH and write only, avalon-mm

2. I've added a SPAN EXTENDER, then i set the DATA PATH WIDTH to 64

bits and the ADDRESS WIDTH of the master to 32 bits (4 giga) and a

default subwindow of 512kb

3. I've added an ALTERA DMA Controller and the WIDTH of the DMA LENGTH

REGISTER is set to 32 bits

4. I've connected the DMA write master to the windowed slave on the

SPAN EXTENDER

5. I've connected the expanded master to F2H_DATA

The question is how to properly configure the DMA in Linux. I've

already read Documentation/DMA-API.txt and

Documentation/DMA-API-HOWTO.txt, but it is not clear how to use those

set of functions.

I've made a Concept test device driver that allocate a buffer with this command:

vbuffer = dma_alloc_coherent(acq.dev, BUFFER_SIZE, &pbuffer,

GFP_ATOMIC | GFP_DMA);

Then I write the paddr to the DMA (actualy to the

address_span_extender and the DMA ip), and send the GO command to the

dma.

When the interrupt from the DMA arrive, I clear the DMA IRQ and do a

dma_sync_single_for_cpu(acq.dev, pbuffer, BUFFER_SIZE, DMA_FROM_DEVICE);

After that, i release the read fop;

Is this the correct use of the DMA api for this case??? It seems to

work (MAGIC_STRING is being transferred). But I'm afraid I'm missing

something.

Bellow there is a piece of code used for this test:

static irqreturn_t dma_isr (int irq, void *dev_id)

{

acq.dma_ready = 1;

writel(CLEAR_DMA_IRQ, acq.dma + DMA_STATUS);

dma_sync_single_for_cpu(acq.dev, pbuffer, BUFFER_SIZE, DMA_FROM_DEVICE);

wake_up_interruptible(&dma_irq_wait);

return IRQ_HANDLED;

}

static ssize_t acq_read(struct file *filp, char __user *buff, size_t count,

loff_t *offp)

{

int num_reads;

u64 jiffies_before, jiffies_after;

char str[100];

int len;

writel(pbuffer, acq.span_extender + ADDR_SPAN_EXT_BASE);

jiffies_before = jiffies;

for (num_reads = 0; num_reads < 100000; num_reads++) {

acq.dma_ready = 0;

writel(0, acq.dma + DMA_DEST_ADDR);

writel(0, acq.dma + DMA_SOURCE_ADDR);

writel(BUFFER_SIZE, acq.dma + DMA_LENGTH);

writel(DMA_GO_CMD, acq.dma + DMA_CONTROL);

if (wait_event_interruptible(dma_irq_wait, acq.dma_ready)) {

return -ERESTARTSYS;

}

}

jiffies_after = jiffies;

len = sprintf(str, "jiffies / HZ = %lld / %d

VBUFFER_MAGIG_STRING:%s\n", jiffies_after - jiffies_before,

HZ,vbuffer);

return simple_read_from_buffer(buff, count, offp, str, len);

}

Thank you, regards.
No RepliesBe the first to reply