Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12652 Discussions

Correct use of Altera DMA core with linux

Altera_Forum
Honored Contributor II
1,158 Views

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. 

 

BTW I'm using Linux 3.9 and quartus 13.1 

0 Kudos
0 Replies
Reply