cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Contributor
Contributor
576 Views
Registered: ‎01-29-2019

physical address access in linux via DMA

Hi all. i have an app that executed correctly on my custom board (read data from my custom IP and write to DDR via DMA). 

i compiled it in petalinux v18.3. and execute correctly.

I need to migrate v19.1 but when i execute my app, Segmentation fault appeare.

my code is:

/**
 * Proof of concept offloaded memcopy using AXI Direct Memory Access v7.1
 */

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

#include <time.h>

#define MM2S_CONTROL_REGISTER 0x00
#define MM2S_STATUS_REGISTER 0x04
#define MM2S_START_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 RECEIVE_RATE_REGISTER 0x1 
#define SEND_RATE_REGISTER 0x0 

#define total_packet 10
#define size_packet 1024

	clock_t start, end;
	double cpu_time_used;

unsigned int dma_set(unsigned int* dma_virtual_address, int offset, unsigned int value) {
    dma_virtual_address[offset>>2] = value;
}

unsigned int tester_set(unsigned int* dma_virtual_address, int offset, unsigned int value) {
    dma_virtual_address[offset] = value;
}

unsigned int dma_get(unsigned int* dma_virtual_address, int offset) {
    return dma_virtual_address[offset>>2];
}

void dma_s2mm_status(unsigned int* dma_virtual_address) {
    unsigned int status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
    printf("Stream to memory-mapped status (0x%08x@0x%02x):", status, S2MM_STATUS_REGISTER);
    if (status & 0x00000001) printf(" halted"); else printf(" running");
    if (status & 0x00000002) printf(" idle");
    if (status & 0x00000008) printf(" SGIncld");
    if (status & 0x00000010) printf(" DMAIntErr");
    if (status & 0x00000020) printf(" DMASlvErr");
    if (status & 0x00000040) printf(" DMADecErr");
    if (status & 0x00000100) printf(" SGIntErr");
    if (status & 0x00000200) printf(" SGSlvErr");
    if (status & 0x00000400) printf(" SGDecErr");
    if (status & 0x00001000) printf(" IOC_Irq");
    if (status & 0x00002000) printf(" Dly_Irq");
    if (status & 0x00004000) printf(" Err_Irq");
    printf("\n");
}

void dma_mm2s_status(unsigned int* dma_virtual_address) {
    unsigned int status = dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
    printf("Memory-mapped to stream status (0x%08x@0x%02x):", status, MM2S_STATUS_REGISTER);
    if (status & 0x00000001) printf(" halted"); else printf(" running");
    if (status & 0x00000002) printf(" idle");
    if (status & 0x00000008) printf(" SGIncld");
    if (status & 0x00000010) printf(" DMAIntErr");
    if (status & 0x00000020) printf(" DMASlvErr");
    if (status & 0x00000040) printf(" DMADecErr");
    if (status & 0x00000100) printf(" SGIntErr");
    if (status & 0x00000200) printf(" SGSlvErr");
    if (status & 0x00000400) printf(" SGDecErr");
    if (status & 0x00001000) printf(" IOC_Irq");
    if (status & 0x00002000) printf(" Dly_Irq");
    if (status & 0x00004000) printf(" Err_Irq");
    printf("\n");
}

void memdump(void* virtual_address, int byte_count) {
    unsigned long *p = virtual_address;
    int offset;
    for (offset = 0; offset < byte_count/8; offset++) {
        printf("%10d", p[offset]);
	printf(" ");
    }
    printf("\n");
}



int dma_s2mm_sync(unsigned int* dma_virtual_address, unsigned int* virtual_destination_address) {
	unsigned int s2mm_status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
	while(!(s2mm_status & 1<<12) || !(s2mm_status & 1<<1)){
		s2mm_status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
		if((s2mm_status & 1<<13)||(s2mm_status & 1<<14))
		{
			dma_s2mm_status(dma_virtual_address);
			break;
		}
	}
	dma_set(dma_virtual_address, S2MM_STATUS_REGISTER, 1<<12);
}

int main() {
	int dh = open("/dev/mem", O_RDWR | O_SYNC); // Open /dev/mem which represents the whole physical memory
	unsigned int* virtual_address = (unsigned int*)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x80010000); // Memory map AXI Lite register block
	unsigned int* virtual_address_tester = (unsigned int*)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x80000000); // Memory map AXI Lite register block
	unsigned int* virtual_destination_address = (unsigned int*)mmap(NULL, total_packet * size_packet, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x0f000000); // Memory map destination address

	memset(virtual_destination_address, 0, total_packet * size_packet); // Clear destination block

	dma_s2mm_status(virtual_address);

	tester_set(virtual_address_tester, RECEIVE_RATE_REGISTER, 0x00000001);

	unsigned int loop_counter = 0;
	printf("start DMA transfer %d packet\n",total_packet);
	
	start = clock();

	while(loop_counter < total_packet)
	{
		dma_set(virtual_address, S2MM_CONTROL_REGISTER, 0);
		dma_set(virtual_address, S2MM_DESTINATION_ADDRESS, 0x0f000000 + loop_counter * size_packet/4); // Write destination address
		dma_set(virtual_address, S2MM_CONTROL_REGISTER, 0xf001);
		dma_set(virtual_address, S2MM_LENGTH, size_packet); //512
		dma_s2mm_sync(virtual_address, virtual_destination_address); // If this locks up make sure all memory ranges are assigned under Address Editor!

		loop_counter++;
	}

	end = clock();
	cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
	printf("execute time is = %f\n",cpu_time_used);

	int i=0;
	unsigned long* p = (void*)virtual_destination_address;
	unsigned long check_data = p[0];
	unsigned int error_count = 0;

	for(i=0; i<(total_packet * size_packet)/8/4; i++)
	{
		if (check_data != p[i])	error_count++;
		check_data = check_data + 4;
	}
	printf("error = %d\n",error_count);
}

error appear in highlighted line. mmap function returend -1 value! in 2019.1.

this code is similar to xilinx axi dma example. I cant understand why in 2018.3, my app execute correctly but 2019.1 has segmentation fault.

how can i get rid of this error in v2019.1?!

thank you.

 

0 Kudos
Reply
3 Replies
Visitor
Visitor
558 Views
Registered: ‎10-17-2016

when you migrate to vivado 2019.1, maybe you change address space? 

I Think, DMA doesn't impact for mmap function, because mmap using in linux kernel.

try to change address of segment in mmap function (change

0x0f000000

to other address and check this). maybe, it works

check dh variable, if i not mistaken, it should return non-1 result.

current problem in linux, not axidma, because your application failed in startup, when you open file descriptors for work with physical address from linux application, and axi dma not involved in current process.

 

 

0 Kudos
Reply
Contributor
Contributor
518 Views
Registered: ‎01-29-2019

hi , thanks for reply.

address spaces are the same.

i changed address 0x0f000000 but segmentation fault didnt resolved.

dh variable return 3 in both version, but highlighted line return -1 in v2019.1.

I think linux kernel need some configuration or somthing like that.

anyone can help me?

0 Kudos
Reply
Visitor
Visitor
225 Views
Registered: ‎12-11-2018

@johnblackxilinx2 

Hello,

I am trying to configure and send data from DDR with the DMA, but haven't found a good example yet. 

Is this application resolved and working for you in Petalinux 2019?

 

Thank you

regards

0 Kudos
Reply