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: 
Contributor
Contributor
659 Views
Registered: ‎11-23-2017

S2MM AXI DMA Simple Mode problem

Hi all,

My userspace application for simple mode AXI DMA , freezes while polling status register, although MM2S works perfectly.

 

here is my code , please help me to figure out :

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>

#define DMA_BASE_ADDRESS 	 0xa0000000
#define MM2S_CONTROL_REGISTER 	 0x00
#define MM2S_STATUS_REGISTER     0x04
#define MM2S_SOURCE_ADDRESS      0x18
#define MM2S_LENGTH 	         0x28
#define S2MM_CONTROL_REGISTER 	 0x30
#define S2MM_STATUS_REGISTER 	 0x34
#define S2MM_DESTINATION_ADDRESS 0x48
#define S2MM_LENGTH 		 0x58
#define DESTINATION_ADDRESS     0X80001400
#define SOURCE_ADDRESS		0x80001C00

static volatile unsigned int* dma_virt_addr=NULL;
static volatile unsigned int* virt_source_buf_address=NULL;
static volatile unsigned int* virt_destination_buf_address=NULL;
unsigned long page_size;

int main () {

int fd = open("/dev/mem", O_RDWR | O_SYNC);

if (fd<0) {
perror("\nError opening device file\n");

}

page_size=sysconf(_SC_PAGE_SIZE);


dma_virt_addr=(unsigned int*)mmap(DMA_BASE_ADDRESS, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_size);

if (dma_virt_addr == NULL) {
printf("\nUnable fetch virt. addr. for AXI DMA\n"); 
}



virt_source_buf_address=(unsigned int*)mmap(SOURCE_ADDRESS, 256*1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_size);


if (virt_source_buf_address == NULL) {
perror("\nUnable fetch virt. addr. for AXI DMA buffer\n");

}


virt_destination_buf_address=(unsigned int*)mmap(DESTINATION_ADDRESS, 256*1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_size);


if (virt_destination_buf_address== NULL) {
perror("\nUnable fetch virt. addr. for AXI DMA buffer\n");
}


//WRITE SOURCE AND DESTINATION ADDRESSES FOR TX(MM2S) AND RX (S2MM)



///////////////////////////////////WRITING DMA -MM2S///////////////////////////////////////////////////////////////////
//userspace_source_buffer_allocation
 unsigned int* src_buff;
 src_buff=(unsigned int*) malloc(1024);

//fill in the userspace_buffer locations with some random data
int i;
for( i=0; i<1024/4; i++){
*src_buff=i+1;

//#DEBUG
printf("userspace buffer data\n%d",*src_buff);
src_buff++;
}

//memset(virt_source_buf_address,25,10);


//copy datafrom userspace buffer tovirtual buffer to be sent
memcpy(virt_source_buf_address,src_buff,1024);
//start data transfer (Write) data to DMA(MM2S)


*(dma_virt_addr+MM2S_CONTROL_REGISTER)=0x801;
*(dma_virt_addr+MM2S_SOURCE_ADDRESS)=SOURCE_ADDRESS;
*(dma_virt_addr+MM2S_LENGTH)=1024;

while ((*(dma_virt_addr+ MM2S_STATUS_REGISTER) & (0x1<<12)) == 0);

printf("\nTransfer complete\n%h\n",*(dma_virt_addr+ MM2S_STATUS_REGISTER));


///////////////////////////////////////READING DMA -S2MM///////////////////////////////////////////////////////////////////
//userspace destination buffer allocation
unsigned int* dest_buff;
dest_buff=(unsigned int*)malloc(1024);
memset(dest_buff,0,1024);

//start data transfer (Read) data from DMA (S2MM)


*(dma_virt_addr+S2MM_CONTROL_REGISTER)=0x801;



*(dma_virt_addr+S2MM_DESTINATION_ADDRESS)=DESTINATION_ADDRESS;
*(dma_virt_addr+S2MM_LENGTH)=1024;
printf("S2MM statuc\n%h\n",*(dma_virt_addr+S2MM_CONTROL_REGISTER));

//while ((*(dma_virt_addr+ S2MM_STATUS_REGISTER) & (0x1<<12)) == 0);

printf("\nReading complete from DMA S2MM\n");


//copy data read from DMA back to user space buffer
memcpy(dest_buff,virt_destination_buf_address, 1024);


//Verify the Test Results
int j;
for (j=0; j<1024/4; j++) {
printf("\data read\n\n%d",*dest_buff);
dest_buff++;
}
return 0;
}









0 Kudos
5 Replies
Xilinx Employee
Xilinx Employee
610 Views
Registered: ‎10-04-2016

Re: S2MM AXI DMA Simple Mode problem

Hi @haroonrl123,

I think the problem is in this line:

*(dma_virt_addr+MM2S_CONTROL_REGISTER)=0x801;

 

Your code does not enable the IOC_IrqEn bit in the MM2S_DMACR register. It is bit 12 and you are enabling bit 11. You need to enable this bit in order for polling on the interrupt in the MM2S_DMASR register to work.

 

Regards,

Deanna

 

 

-------------------------------------------------------------------------
Don’t forget to reply, kudo, and accept as solution.
-------------------------------------------------------------------------
0 Kudos
Contributor
Contributor
604 Views
Registered: ‎11-23-2017

Re: S2MM AXI DMA Simple Mode problem

Thanks for your reply. i changed the values, but still it's not working . Kernel freezes.

 

then i build kernel module and what i figured out that the problem is with writing to DDR memory via virtual address returned by ioremap_nocache() function i used.

 

here is my kernel module i wrote to test :

 

#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>



#define DEVICE_NAME   "dma_kernel"

#define CLASS_NAME    "axi_dma"


MODULE_LICENSE("GPL");              
MODULE_AUTHOR("Harry");      
MODULE_DESCRIPTION("A simple Linux driver for the AXI DMA."); 
MODULE_VERSION("1.0");

//static void __iomem *dma_virt_addr;
static void __iomem *virt_source_buf_address;
//static void __iomem *virt_destination_buf_address;
//static unsigned int* p;
//static volatile unsigned int* dma_virt_addr;

static int    majorNumber;                             
static struct class*  axidmaclass  = NULL;
		
static int     axi_dma_open(struct inode *, struct file *);
static int     axi_dma_release(struct inode *, struct file *);

static int axi_dma_open(struct inode *inodep, struct file *filep){
  
   printk(KERN_INFO "AXI DMA: Device has been opened time(s)\n");
   return 0;
}

static int axi_dma_release(struct inode *inodep, struct file *filep){
   printk(KERN_INFO "AXI DMA: Device successfully closed\n");
   return 0;
}
static struct file_operations axi_dma={

.owner=THIS_MODULE,
.open=axi_dma_open,
.release=axi_dma_release,
};

static int __init axi_dma_init(void){
// Try to dynamically allocate a major number for the device -- more difficult but worth it
   majorNumber = register_chrdev(0, DEVICE_NAME, &axi_dma);
   if (majorNumber<0){
      printk(KERN_ALERT "axidma failed to register a major number\n");
      return majorNumber;
   }
   printk(KERN_INFO "axidma: registered correctly with major number %d\n", majorNumber);


   // Register the device class
   axidmaclass = class_create(THIS_MODULE, CLASS_NAME);
   if (IS_ERR(axidmaclass)){                // Check for error and clean up if there is
      unregister_chrdev(majorNumber, DEVICE_NAME);
      printk(KERN_ALERT "Failed to register device class\n");
      return PTR_ERR(axidmaclass);          // Correct way to return an error on a pointer
   }
   printk(KERN_INFO "axidma: device class registered correctly\n");

//request memory region

if(request_mem_region(0x80001400,256*2048,"axi_dma_mmeory")==NULL){
printk("failed to request memory region\n");
}

   printk(KERN_INFO "AXI DMA Initialized");

	u32  *src_buffer;
	u32  *dest_buffer;
	u32  *p; 
	src_buffer = kmalloc(1024, GFP_KERNEL);
	dest_buffer = kzalloc(1024, GFP_KERNEL);
int i;

if (!src_buffer || !dest_buffer) {
		printk(KERN_ERR "Allocating memory failed\n");
		return -1;
	}

		for (i = 0; i < 1024/4; i++)
		src_buffer[i] = i;


	virt_source_buf_address = ioremap_nocache(0x80001400, 256*1024);
        if (!virt_source_buf_address ) {
                printk("Could not map physical memory to virtual\n");
                return -1;
        }
	printk("virt_source_buf_address: %08X\n", (unsigned int)virt_source_buf_address);
	p = virt_source_buf_address;

		for (i = 0; i < 1024/4; i++){
		__raw_writel(src_buffer[i], p++);
			printk("data \n%d\n",*p);
			*p++;
}

		p = virt_source_buf_address;
	
		for (i = 0; i < 1024/4; i++)
		dest_buffer[i] = __raw_readl(p++);


		for (i = 0; i < 1024/4; i++) {
		if (dest_buffer[i] != src_buffer[i]) { 
			printk("index = %d, src=%02X, dest = %02X\n", i, src_buffer[i], dest_buffer[i]);
		}
	}

return 0;

}


static void __exit axi_dma_exit(void){
	device_destroy(axidmaclass, MKDEV(majorNumber, 0));     // remove the device
   	class_unregister(axidmaclass);                          // unregister the device class
   	class_destroy(axidmaclass);                             // remove the device class
   	unregister_chrdev(majorNumber, DEVICE_NAME);             // unregister the major num
	release_mem_region(0x80001300 ,256*1024*256);
        printk(KERN_INFO "AXI DMA Exit\n");
}
module_init(axi_dma_init);
module_exit(axi_dma_exit);

 

when i insert the module kernel hangs /stucks/freezes with following results:

reult.png

i have been struggling to figure out this problem since two weeks, please help me out , this project is really important to me.

 

 

0 Kudos
Visitor yedechang
Visitor
395 Views
Registered: ‎07-18-2018

Re: S2MM AXI DMA Simple Mode problem

你好,我现在也遇到了这个问题请问您是怎么解决的?非常期待您的答复!!!!!

0 Kudos
Moderator
Moderator
352 Views
Registered: ‎08-01-2007

Re: S2MM AXI DMA Simple Mode problem

@yedechang, please ask the question in Chinese forum http://forum.xilinx.com/cn if you need to use Chinese. Thanks for your co-operation.

0 Kudos
Visitor yedechang
Visitor
338 Views
Registered: ‎07-18-2018

Re: S2MM AXI DMA Simple Mode problem

Hello, I have encountered this problem now. How do you solve it? I look forward to your reply!!!!!

0 Kudos