cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
200 Views
Registered: ‎04-27-2020

How to quickly move DMA data to a file

mmap physical address to user space, then  write to file buffer,  the write speed is too slowly, any solotion to solved?

setup:

https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842418/Linux+DMA+From+User+Space

run:

root@sem:~# insmod dma-proxy.ko 
[ 2325.438075] dma_proxy module initialized
[ 2325.443625] Allocating uncached memory at virtual address 0xffffff800cea2000, physical address 0x000000006fd00000
[ 2325.455688] Allocating uncached memory at virtual address 0xffffff800d1ad000, physical address 0x0000000070100000

test memcpy from dma to user space:

/* DMA Proxy Test Application
 *
 * This application is intended to be used with the DMA Proxy device driver. It provides
 * an example application showing how to use the device driver to do user space DMA
 * operations.
 *
 * The driver allocates coherent memory which is non-cached in a s/w coherent system.
 * Transmit and receive buffers in that memory are mapped to user space such that the
 * application can send and receive data using DMA channels (transmit and receive).
 *
 * It has been tested with an AXI DMA system with transmit looped back to receive.
 * Since the AXI DMA transmit is a stream without any buffering it is throttled until
 * the receive channel is running.
 *
 * More complete documentation is contained in the device driver (dma-proxy.c).
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include "dma-proxy.h"
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>

static struct dma_proxy_channel_interface *tx_proxy_interface_p;
static int tx_proxy_fd;
static int test_size;


char data1[3*1024*1024];

typedef struct
{
	unsigned int memAddr;
	unsigned int memSize;
	unsigned int mapMemAddr;
	unsigned int mapMemSize;
	unsigned int memOffset;

	int memDevFd;
	unsigned int *pMemVirtAddr;
} MMapCtrl;
#define MMAP_MEM_PAGEALIGN (4*1024 - 1)
int Phy2Vir_MMap(MMapCtrl *gMMapCtrl, uint32_t physAddr, uint32_t memsize, uint32_t *pMemVirtAddr)
{
	//open device
    gMMapCtrl->memDevFd = open("/dev/mem",O_RDWR|O_SYNC);
    if (gMMapCtrl->memDevFd < 0)
    {
        printf("Eroor: /dev/mem open failed!\n");
        return -1;
    }
    // map
    gMMapCtrl->memOffset = physAddr & MMAP_MEM_PAGEALIGN;
    gMMapCtrl->mapMemAddr = physAddr - gMMapCtrl->memOffset;
    gMMapCtrl->mapMemSize= memsize + gMMapCtrl->memOffset;
    gMMapCtrl->pMemVirtAddr = ( unsigned int *)mmap(
    		    (void *)gMMapCtrl->mapMemAddr,
				gMMapCtrl->mapMemSize,
				PROT_READ|PROT_WRITE,MAP_SHARED|MAP_FILE|MAP_LOCKED,
				gMMapCtrl->memDevFd,
				gMMapCtrl->mapMemAddr
				);
    if (gMMapCtrl->pMemVirtAddr == NULL)
    {
    	printf("Error: map failed!\n");
    	return -1;
    }
    close(gMMapCtrl->memDevFd);
    *pMemVirtAddr = (uint32_t)((uint32_t) gMMapCtrl->pMemVirtAddr + gMMapCtrl->memOffset);
    return 0;
}
int main(int argc, char *argv[])
{

	int ret = 0;
	int counter;
	int counter_max = 4096 * 5;

	printf("DMA proxy test\n");
#define C_AXI_DataReg_BASEADDR    0x6fd00000
#define C_AXI_DataReg_LENTH       128*1024
	unsigned int DataReg_VIRTADDR;
	MMapCtrl DataReg;

	/* Get the size of the test to run, making sure it's not bigger than the statically configured memory size)
	 */
	test_size =  128*1024;
	if (test_size > TEST_SIZE)
		test_size = TEST_SIZE;


	ret = Phy2Vir_MMap(&DataReg,C_AXI_DataReg_BASEADDR,C_AXI_DataReg_LENTH,&DataReg_VIRTADDR);
	if (ret != 0)
	{
		printf("File:%s Line:%d Func:Phy2Vir_MMap() Error!\n",
				__FILE__, __LINE__);
		exit(-1);
	}

	for(int i = 0; i < test_size; i++)
	{
		data1[i] = i;
	}

	struct timeval t;
	gettimeofday(&t, NULL);
	double start  = t.tv_sec + 1E-6 * t.tv_usec;
	for (counter = 0; counter < counter_max; counter++) {
		memcpy(DataReg_VIRTADDR,data1,test_size);

	}

	/* Unmap the proxy channel interface memory and close the device files before leaving
	 */
	gettimeofday(&t, NULL);
	double end  = t.tv_sec + 1E-6 * t.tv_usec;
	printf("send 512M data in %.6f secs \n", end - start);


	gettimeofday(&t, NULL);
	start  = t.tv_sec + 1E-6 * t.tv_usec;
	for (counter = 0; counter < counter_max; counter++) {
		memcpy(data1,DataReg_VIRTADDR,test_size);

	}
	gettimeofday(&t, NULL);
	end  = t.tv_sec + 1E-6 * t.tv_usec;
	printf("recieve 512M data in %.6f secs \n", end - start);



	for(int i = 0; i < test_size; i++)
	{
		if(data1[i] != (i & 0xff))
		{
			printf("error%d\n",i);
		}
	}
	printf("DMA proxy test complete\n");

	return 0;
}

print:

DMA proxy test
send 512M data in 0.534793 secs 
recieve 512M data in 16.565873 secs 
DMA proxy test complete

 

 

0 Kudos
1 Reply
Highlighted
Visitor
Visitor
114 Views
Registered: ‎01-08-2019

hello ~

but you don't use AXI DMA IP HW transfer , the iotcl() is trigger the AXI DMA IP to transfer .

your example is only memory copy, no use the AXI DMA IP operation.

thank your share !

0 Kudos