MMAP失败超过4k

时间:2013-01-28 13:37:23

标签: linux mmap

这是我的第一篇文章,如果有任何错误,请告诉我。

我的目标是从KERNEL到用户空间获得大约150MB的数据传输。 [这是因为我在OMAP l138上为DMA设备构建驱动程序,以便在DMA DEVICE和FPGA之间传输和接收数据]

  1. 现在在LINUX KERNEL中我使用dma_alloc_coherent
  2. 分配VARIABLE大小的BUFFER
  3. 然后我将这个缓冲区的PHYSICAL地址传递给用户空间作为用户 OFFSET参数用于来自用户空间的mmap调用。
  4. 然后从数据中复制并读回用户空间到内核
  5. 此逻辑工作正常,直到缓冲区大小为4096.高于4k mmap失败并返回“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 个答案:

答案 0 :(得分:0)

使用get_free_pages分配多个页面,或者使用vmalloc但是你需要在每个页面都调用remap_pfn_range,因为vmalloc-ed物理内存可能不是物理连续的。