驱动移植过程中DMA内存相关接口替换
1. 相关概念介绍及移植简介
1.1 物理地址与总线地址
1)物理地址是与CPU相关的。在CPU的地址信号线上产生的就是物理地址,在程序指令中的的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址线上。
2)总线地址,顾名思义,是与总线相关的,外设使用的就是总线地址。
在x86平台下,外设的I/O地址是独立的,即有专门的指令访问外设I/O,I/O地址就是所谓的“总线地址”。而“物理地址”就是RAM地址。
在ARM平台下,I/O和RAM统一编址,即“总线地址”就是“物理地址”。
Linux系统无论是在内核还是用户空间,都是直接使用“虚拟地址”访问内存或I/O空间,因此要访问外设I/O,必须将I/O地址转换成“虚拟地址”才能够进行访问。
MMU启动前程序中的地址为“物理地址”,和硬件手册中规定的地址一致。MMU启动后程序中的地址为“虚拟地址”,“虚拟地址”和“物理地址”之间的关系参照MMU地址映射表。
1.2 移植介绍
在移植Linux驱动的过程中,会遇到很多非POSIX接口,这些接口是跟Linux系统相关的,而在SylixOS中并未提供兼容接口,因此在替换过程中,需要结合SylixOS本身提供的一些机制实现一套兼容接口,在替换过程中为了保持与linux接口的兼容性,将不改变函数的原型,而只是将内部实现替换成SylixOS接口实现。
本篇将介绍在移植Linux驱动过程中有关DMA内存操作的相关接口的替换方案,注意,本文档提供的替换方案仅适用于“物理地址”和“总线地址”相同的硬件平台。
2. DMA内存相关接口介绍及替换
在移植过程中主要遇到的和DMA内存相关操作的接口如表 2-1所示。
表 2-1 Linux DMA内存相关操作接口
2.1 一致性内存相关接口介绍及替换
2.1.1 分配一致性内存
1)Linux接口介绍
Linux内核提供相应接口用于分配一个DMA一致性的内存区域。
void*dma_alloc_coherent(structdevice*dev,size_tsize,dma_addr_t*handle,gfp_tgfp)
函数dma_alloc_coherent原型分析:
此函数成功时返回分配的缓冲区地址,失败时返回NULL;
参数dev为设备结构,SylixOS没有提供该结构,因此在实际替换中,对该参数进行了修改;
参数size为分配的DMA内存大小;
参数handle为分配的DMA内存的地址;
参数gfp为分配内存标志。
2)SylixOS接口替换
在SylixOS内核中提供分配DMA内存的接口,且DMA内存是一致性内存,因此为保持兼容,dma_alloc_coherent接口在SylixOS中的实现如程序清单 2-1所示。
程序清单 2-1 dma_alloc_coherent接口实现
void*dma_alloc_coherent(void*dev,size_tsize,dma_addr_t*handle,gfp_tgfp){*handle=(dma_addr_t)API_VmmDmaAllocAlign(size,size);if(0==*handle){*handle=~0;returnNULL;}return(void*)(*handle);}
主要调用了API_VmmDmaAllocAlign分配DMA物理内存并将DMA地址返回。与Linux中的不同点在于该替换接口返回的是DMA内存地址,而Linux返回的是handle所对应的虚拟地址,提供给用户使用。
2.1.2 释放一致性内存
1)Linux接口介绍
Linux内核提供相应接口用于释放DMA一致性的内存区域。
voiddma_free_coherent(structdevice*dev,size_tsize,void*cpu_addr,dma_addr_thandle)
函数dma_free_coherent原型分析:
参数dev为设备结构,SylixOS没有提供该结构,因此在实际替换中,对该参数进行了修改;
参数size为分配的DMA内存大小;
参数cpu_addr为待释放的缓冲区地址;
参数handle为DMA地址的值。
2)SylixOS接口替换
在SylixOS中提供释放DMA内存的接口,因此为了兼容,释放DMA内存实现如程序清单 2-2所示。
程序清单 2-2 dma_free_coherent接口实现
voiddma_free_coherent(void*dev,size_tsize,void*cpu_addr,dma_addr_thandle){API_VmmDmaFree((void*)handle);}
由于在SylixOS中DMA内存的物理地址和虚拟地址是一一对应的,因此cpu_addr和handle在数值上是相同的。
2.2 DMA内存池相关接口介绍及替换
2.2.1 创建DMA内存池
1)Linux接口介绍
Linux内核提供相应接口用于创建DMA内存池。
structdma_pool*dma_pool_create(constchar*name,structdevice*dev,size_tsize,size_talign,size_tboundary)
函数dma_pool_create原型分析:
此函数成功时返回DMA池的结构指针,由于SylixOS没有提供该结构,因此在替换过程中接口返回值做了修改。失败时返回NULL;
参数name为DMA池的名字;
参数dev为设备结构,SylixOS没有提供该结构,因此在实际替换中,对该参数进行了修改;
参数size为从该DMA池中分配的缓冲区的大小;
参数align为从该池分配时所遵循的对齐原则;
参数boundary表示从该DMA池返回的内存不能越过2的boundary次方的边界。
2)SylixOS接口替换
SylixOS提供定长内存管理机制,因此创建DMA内存池接口实现如程序清单 2-3所示。
程序清单 2-3 dma_pool_create接口实现
void*dma_pool_create(LW_OBJECT_HANDLE*ulId,void*dev,size_tsize,size_talign,size_tboundary){PVOIDpucDMAPool=NULL;pucDMAPool=API_VmmDmaAllocAlign(size,align);if(pucDMAPool==NULL){returnNULL;}*ulId=Lw_Partition_Create("my_partition",pucDMAPool,size*2,4096/64,LW_OPTION_OBJECT_GLOBAL,LW_NULL);returnpucDMAPool;}
主要实现过程是通过调用API_VmmDmaAllocAlign分配一片DMA内存,调用Lw_Partition_Create对该DMA内存进行管理。此接口成功返回DMA内存池的地址,失败返回NULL。
2.2.2 从DMA内存池获取内存块
1)Linux接口介绍
Linux内核提供相应接口用于从DMA内存池中获取内存块。
void*dma_pool_alloc(structdma_pool*pool,gfp_tmem_flags,dma_addr_t*handle)
函数dma_pool_alloc原型分析:
此函数成功时返回从DMA池中获取的内存块的地址,失败时返回NULL;
参数pool为创建DMA池时返回的结构体指针,由于SylixOS没有提供该结构,因此在替换过程中接口返回值做了修改;
参数mem_flags为分配内存标志;
参数handle为获取的内存块的DMA地址。
2)SylixOS接口替换
SylixOS提供从创建的定长内存中获取内存块,因此从DMA内存池中获取内存块的实现如程序清单 2-4所示。
程序清单 2-4 dma_pool_alloc接口实现
void*dma_pool_alloc(LW_OBJECT_HANDLEulId,gfp_tmem_flags,dma_addr_t*handle){void*alloc;alloc=Lw_Partition_Allocate(ulId);/**由于内存是直接从dma内存中分配,因此,物理地址和虚拟地址一样,*不需要调用API_VmmVirtualToPhysical((addr_t)alloc,handle);进行转换。*/*handle=(dma_addr_t)alloc;returnalloc;}
主要调用定长内存分配接口从定长内存中获取内存块,其中ulId是创建内存池成功时产生的句柄,通过该句柄可以从指定的内存池中获取内存块。
2.2.3 释放内存块到内存池中
1)Linux接口介绍
Linux内核提供相应接口用于释放内存块到DMA内存池中。
voiddma_pool_free(structdma_pool*pool,void*vaddr,dma_addr_tdma)
函数dma_pool_free原型分析:
参数pool为创建DMA池时返回的结构体指针,由于SylixOS没有提供该结构,因此在替换过程中接口返回值做了修改;
参数vaddr为从DMA池中获取的内存块的地址;
参数dma为DMA池中获取的内存块的地址对应的DMA地址。
2)SylixOS接口替换
通过调用定长内存释放函数可实现将分配的内存返还到定长内存中,具体实现如程序清单 2-5所示。
程序清单 2-5 dma_pool_free接口实现
voiddma_pool_free(LW_OBJECT_HANDLEulId,void*vaddr,dma_addr_tdma){Lw_Partition_Free(ulId,vaddr);}
2.2.4 销毁DMA内存池
1)Linux接口介绍
Linux内核提供相应接口用于销毁DMA内存池。
voiddma_pool_destroy(structdma_pool*pool)
函数dma_pool_free原型分析:
参数pool为创建DMA池时返回的结构体指针,由于SylixOS没有提供该结构,因此在替换过程中接口返回值做了修改;
2)SylixOS接口替换
通过调用删除定长内存函数即可销毁DMA内存池,具体实现如程序清单 2-6所示。
程序清单 2-6 dma_pool_destroy接口实现
voiddma_pool_destroy(LW_OBJECT_HANDLE*pulId){Lw_Partition_Delete(pulId);}
3. 总结
在移植过程中,经常会遇到平台相关的接口,虽然SylixOS没有直接提供相应的接口进行替换,但是如果理解该接口的实现目的,那么就可以通过SylixOS本身的机制实现相同的功能。当然需要对SylixOS本身提供的机制与方法有所了解,才能够轻松地进行接口替换。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。