4

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

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

  1. 现在在 LINUX 内核中,我使用 dma_alloc_coherent 分配 VARIABLE 大小的 BUFFER
  2. 然后我将此缓冲区的物理地址传递给用户空间作为用户空间的 OFFSET 参数,用于从用户空间调用 mmap。
  3. 然后从用户空间向内核复制和读取数据

此逻辑工作正常,直到缓冲区大小为 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
4

1 回答 1

0

使用 get_free_pages 分配多个页面,或使用 vmalloc 但您需要在每个页面基础上调用 remap_pfn_range,因为 vmalloc 的物理内存可能在物理上不是连续的。

于 2014-03-17T04:49:42.530 回答