4
votes

This is my first post so please let me know if there is any mistake from .

My aim is to get approx 150MBytes of data transfer from KERNEL to user space. [This is because i am building an driver for DMA device on OMAP l138 to transfer and receive data between DMA DEVICE and FPGA]

  1. Now in LINUX KERNEL i am allocating BUFFER of VARIABLE size using dma_alloc_coherent
  2. Then the PHYSICAL address of this buffer i am passing to user space to be user as OFFSET parameter to be used for mmap call from user space .
  3. Then from data is copied and read back to and from from user space to kernel

This logic work fine till size of buffer is 4096. Above 4k the mmap fails and return "MAP_FAILED"

static int driver_mmap(struct file *f, struct vm_area_struct *vma)
{

    u32bit ret;
    u32bit size = (vma->vm_end)-(vma->vm_start);

    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

    if (size > (NUM_PAGE*PAGE_SIZE)){
        return(-1);  
    }

    if ((ret = remap_pfn_range(vma,vma->vm_start,
                    (virt_to_phys((void *)krnl_area) >> PAGE_SHIFT),
                    size,vma->vm_page_prot)) < 0)
    {
        return ret;  
    }
    printk("\nDVR:The MMAP returned %x to USER SAPCE \n",ret);
    return 0;  

}


//MMAP STEP 1
dmasrc_ptr = dma_alloc_coherent( NULL ,GLOBAL_BUFFER_SIZE , &dmasrc ,0);
if( !dmasrc_ptr ) {
    printk(KERN_INFO "DMA_ALLOC_FAILED for the source buffer ...\n");
    return -ENOMEM;
}else{
    printk( "\n--->The address of SRC is %x..\n",dmasrc_ptr);       
}

temp_source=dmasrc_ptr;



//MMAP STEP 2
// Round the allocated KERNEL MEMORY to the page bondary   
krnl_area=(int *)((((unsigned long)dmasrc_ptr) + PAGE_SIZE - 1)&PAGE_MASK); 
printk(KERN_CRIT "DVR:The KERNEL VIRTUAL ADDRS is %x..\n",krnl_area);

//MMAP STEP 3
// Marking the PAGES as RESERVED 
for (i = 0; i < (NUM_PAGE * PAGE_SIZE); i+= PAGE_SIZE) {  
    SetPageReserved(virt_to_page(((unsigned long)krnl_area) + i)); 


//Application code part

while(1){

    fflush(stdin);
    fflush(stdout);

    printf("\n\n\n----------------------------------------------------\n");
    printf("USR:Please enter your requirement ");
    printf("\n----------------------------------------------------\n");
    printf("\t1----->GET_UPP_OFFSET\n");
    printf("\t2----->UPP_MMAP_CALL\n");
    printf("\t3----->IOCTL_UPP_WRITE\n");
    printf("\t4----->IOCTL_UPP_READ\n");

    printf("\n");
    scanf("%d",&option);
    printf("\nThe OPTION is %d..\n",option);
    printf("\n");

    switch(option){

    case 1 :
    {
        offset=0;
        ret = ioctl(dev_FD ,IOCTL_UPP_START, &info);
        if (ret < 0) {
            printf("dma buffer info ioctl failed\n");
        }       
        offset = info.var;      
        printf("THE ADDRESS WE GOT IS %X..\n",offset);

    }
    break;

    case 2 :
    {
        printf("THE OFFSET is %X..\n",offset);
        mmap_Ptr= mmap(0,BUFFER_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, dev_FD, 0);     
        if (mmap_Ptr == MAP_FAILED){
            printf("USR[UPP] :MMAP FAiled \n\n");
            close(dev_FD);
            exit(-1);   
        }
        printf("THE MMAP address is %X..\n",mmap_Ptr);

    }
    break;

    case 3:
    {
        struct upp_struct user_local_struct;

        printf("\n***************************************************\n");
        for (i = 0; i <(1024);i++) {  
            *(mmap_Ptr+i)=test_var;
            printf("WR:%X ",*(mmap_Ptr+i));
            //test_var++; 
        } 
        ioctl(dev_FD , IOCTL_UPP_WRITE ,&user_local_struct);    

        printf("\n***************************************************\n\n\n");
        for(i=0;i<20402;i++){
            //NOP
        }

        //test_var=0x00;
    }
    break;

    case 4:
    {
        struct upp_struct user_local_struct;
        ioctl(dev_FD , IOCTL_UPP_READ,&user_local_struct);

        for(i=0;i<20402;i++){
            //NOP
        }
        printf("\n***************************************************\n");
        for (i = 0; i <(1024);i++) {  
            printf("RD:%X",*(mmap_Ptr+i));  
        }
        printf("\n***************************************************\n\n\n");  
    }
    break;

    default:
    { 
        printf("USR:You have entered an wrong option \n");
        printf("\nUSR:CLosing the FILE ENTERIES ...\n");
        munmap(mmap_Ptr,BUFFER_SIZE);
        free(source_ptr);
        free(dest_ptr);
        close(dev_FD);
        exit(0);
    }
    break;

} //END OF SWITCH LOOP  

} //END OF WHILE LOOP
1
Are you familiar with the practice of checking errno?Heath Hunnicutt
is NUM_PAGE 1 by any chance? are you reaching driver_mmap?Hasturkun
Hasturkun: Yes it was .Actually initially i have build the MMAP logic for KMALLOC which was based on PAGESIZE logic. Then i modified the logic for dma_alloc_coherent , which involved mentioning SIZE .But this line meant for KMALLOC led to error as for any buffer size above 4k it used to return (-1).Ashish
if i remember well, for large chunk of memory, you need to use vmallocc4f4t0r

1 Answers

0
votes

use get_free_pages to allocate multiple pages, or use vmalloc but you need call remap_pfn_range at every page basis as vmalloc-ed physical memory could be not physically continuous.