驱动移植过程中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内存相关操作接口

系统接口 接口功能
dma_alloc_coherent 分配一片DMA一致性的内存区域
dma_free_coherent 释放一片DMA一致性内存
dma_pool_create 创建一片DMA内存池
dma_pool_alloc 从DMA内存池中分配一块DMA内存
dma_pool_free 释放DMA内存到DMA内存池中
dma_pool_destroy 销毁DMA内存池

2.1 一致性内存相关接口介绍及替换 
2.1.1 分配一致性内存 
        1)Linux接口介绍 
        Linux内核提供相应接口用于分配一个DMA一致性的内存区域。

void *dma_alloc_coherent(struct device  *dev, 
                          size_t         size, 
                          dma_addr_t    *handle, 
                          gfp_t          gfp)

函数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_t size, dma_addr_t *handle, gfp_t gfp)
{
    *handle = (dma_addr_t )API_VmmDmaAllocAlign(size, size);
    if(0 == *handle) {
        *handle = ~0;
        return NULL;
    }
    return (void *)(*handle);
}

主要调用了API_VmmDmaAllocAlign分配DMA物理内存并将DMA地址返回。与Linux中的不同点在于该替换接口返回的是DMA内存地址,而Linux返回的是handle所对应的虚拟地址,提供给用户使用。 
2.1.2 释放一致性内存 
        1)Linux接口介绍 
        Linux内核提供相应接口用于释放DMA一致性的内存区域。

void dma_free_coherent(struct device    *dev, 
                        size_t           size, 
                        void            *cpu_addr, 
                        dma_addr_t       handle)

函数dma_free_coherent原型分析: 
        参数dev为设备结构,SylixOS没有提供该结构,因此在实际替换中,对该参数进行了修改; 
        参数size为分配的DMA内存大小; 
        参数cpu_addr为待释放的缓冲区地址; 
        参数handle为DMA地址的值。 
        2)SylixOS接口替换 
        在SylixOS中提供释放DMA内存的接口,因此为了兼容,释放DMA内存实现如程序清单 2-2所示。 
                                            程序清单 2-2 dma_free_coherent接口实现

void dma_free_coherent(void *dev, size_t size, void *cpu_addr, dma_addr_t handle)
{
    API_VmmDmaFree ((void *)handle);
}

由于在SylixOS中DMA内存的物理地址和虚拟地址是一一对应的,因此cpu_addr和handle在数值上是相同的。 
2.2 DMA内存池相关接口介绍及替换 
2.2.1 创建DMA内存池 
        1)Linux接口介绍 
        Linux内核提供相应接口用于创建DMA内存池。

struct dma_pool *dma_pool_create(const char     *name, 
                                  struct device *dev,
                                  size_t         size, 
                                  size_t         align, 
                                  size_t         boundary)

函数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_t size, size_t align, size_t boundary)
{
    PVOID pucDMAPool = NULL;
    pucDMAPool = API_VmmDmaAllocAlign(size, align);
    if (pucDMAPool == NULL) {
        return NULL;
    }    
    *ulId = Lw_Partition_Create("my_partition",
                                 pucDMAPool,
                                 size *2,
                                 4096/64,
                                 LW_OPTION_OBJECT_GLOBAL,
                                 LW_NULL);
    return pucDMAPool;
}

主要实现过程是通过调用API_VmmDmaAllocAlign分配一片DMA内存,调用Lw_Partition_Create对该DMA内存进行管理。此接口成功返回DMA内存池的地址,失败返回NULL。 
2.2.2 从DMA内存池获取内存块 
        1)Linux接口介绍 
        Linux内核提供相应接口用于从DMA内存池中获取内存块。

void *dma_pool_alloc(struct dma_pool    *pool, 
                      gfp_t                  mem_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_HANDLE  ulId, gfp_t mem_flags,
             dma_addr_t *handle)
{
    void *alloc;
    alloc = Lw_Partition_Allocate(ulId);

    /*
     * 由于内存是直接从dma内存中分配,因此,物理地址和虚拟地址一样,
     * 不需要调用API_VmmVirtualToPhysical((addr_t)alloc, handle);进行转换。
     */
    *handle = (dma_addr_t)alloc;

    return alloc;
}

主要调用定长内存分配接口从定长内存中获取内存块,其中ulId是创建内存池成功时产生的句柄,通过该句柄可以从指定的内存池中获取内存块。 
2.2.3 释放内存块到内存池中 
        1)Linux接口介绍 
        Linux内核提供相应接口用于释放内存块到DMA内存池中。

void dma_pool_free(struct dma_pool *pool, 
                    void           *vaddr, 
                    dma_addr_t      dma)

函数dma_pool_free原型分析: 
        参数pool为创建DMA池时返回的结构体指针,由于SylixOS没有提供该结构,因此在替换过程中接口返回值做了修改; 
        参数vaddr为从DMA池中获取的内存块的地址; 
        参数dma为DMA池中获取的内存块的地址对应的DMA地址。 
        2)SylixOS接口替换 
        通过调用定长内存释放函数可实现将分配的内存返还到定长内存中,具体实现如程序清单 2-5所示。 
                                            程序清单 2-5 dma_pool_free接口实现

void dma_pool_free(LW_OBJECT_HANDLE  ulId, void *vaddr, dma_addr_t dma)
{
    Lw_Partition_Free(ulId, vaddr);
}

2.2.4 销毁DMA内存池 
        1)Linux接口介绍 
        Linux内核提供相应接口用于销毁DMA内存池。

void dma_pool_destroy(struct dma_pool *pool)

函数dma_pool_free原型分析: 
        参数pool为创建DMA池时返回的结构体指针,由于SylixOS没有提供该结构,因此在替换过程中接口返回值做了修改; 
        2)SylixOS接口替换 
        通过调用删除定长内存函数即可销毁DMA内存池,具体实现如程序清单 2-6所示。 
                                            程序清单 2-6 dma_pool_destroy接口实现

void dma_pool_destroy(LW_OBJECT_HANDLE   *pulId)
{
    Lw_Partition_Delete (pulId);
}

3. 总结 
        在移植过程中,经常会遇到平台相关的接口,虽然SylixOS没有直接提供相应的接口进行替换,但是如果理解该接口的实现目的,那么就可以通过SylixOS本身的机制实现相同的功能。当然需要对SylixOS本身提供的机制与方法有所了解,才能够轻松地进行接口替换。

时间: 2024-08-09 14:40:22

驱动移植过程中DMA内存相关接口替换的相关文章

Linux内核,文件系统移植过程中出现的一些问题与解决办法

1.bootm地址和load address一样 此种情况下,bootm不会对uImage header后的zImage进行memory move的动作,而会直接go到entry point开始执行.因此此时的entry point必须设置为load address + 0x40.如果kernel boot过程没有到uncompressing the kernel,就可能是这里设置不对. boom address == load address == entry point - 0x40 2.

Lucene索引过程中的内存管理与数据存储

Lucene的索引过程分两个阶段,第一阶段把文档索引到内存中:第二阶段,即内存满了,就把内存中的数据刷新到硬盘上.          倒排索引信息在内存存储方式 Lucene有各种Field,比如StringField,TextField,IntField,FloatField,DoubleField-,Lucene在处理的过程中把各种Field都处理成相应的byte[],以最本质的方式来看待各种Field的内容,统一了数据的存储形式. 在写入内存阶段,第一步就是需要理清各个类之间的关系. 在索

[linux内存]系统启动过程中的内存管理

内核启动过程的内存管理1,memblock机制 kernel/arm/mm/memblock.c arm_memblock_init()函数 系统刚启动的时候不是所有的内存都是可以作为分配使用的,比如有些内存是默认给rootfs或者kernel使用的,memblock机制 作用就是决定哪些内存是可以分配的,哪些是默认已经被使用的. 涉及的三个主要API是memblock_init() memblock_reserve()  memblock_add()函数 2,bootmem机制 http://

C++类的继承过程中的内存泄漏问题

在笔试题中,经常会考到“内存泄露”的问题,其中一个就是: 当用基类的指针指向new出来的派生类对象,然后再delete改指针时,会造成内存泄露. 原因大家都很清楚,用基类的指针指向了派生类的对象,派生类对象的结构并未发生变化,当我们delete该基类指针时,只有指向基类的数据成员的内存被释放,而派生类新增的成员占用的内存则仍然存在,这就造成了内存泄露. 解决办法:将基类的析构函数声明为虚函数,即虚析构函数(virtual). [程序实例1] 1 #include <iostream> 2 us

Android系统移植过程中系统起不来

============问题描述============ 我们板子的android 源码版本是4.2,现在我想把android源码升级到4.4, 用板子原来的kernel和android 4.4制作了一个升级包, 升级成功后, 板子不能正常启动, 启动时报下面的错误: [    [email protected]] CEC node init [    7[    [email protected]] Changing baud from 0 to 115200 [    [email prot

STM32 USB转串口驱动移植到SylixOS中遇到的问题总结

1. 简介         由于客户项目需求,需要在STM32的硬件平台上实现USB转串口的功能,由于ST公司基于STM32硬件平台实现了相应的USB库以方便开发者进行开发,因此,在SylixOS下实现USB转串口功能时对该USB库进行了移植.由于该USB库的实现是基于STM32的裸机代码实现,因此在移植的过程中,不需要做过多的修改.         下面章节主要介绍在移植STM32的USB转串口驱动到SylixOS下遇到的问题以及对应的解决方法.对于其中的有些解决方法在移植STM32其他外设驱

DM9000驱动移植在mini2440(linux2.6.29)和FS4412(linux3.14.78)上的实现(deep dive)篇一

关于dm9000的驱动移植分为两篇,第一篇在mini2440上实现,基于linux2.6.29,也成功在在6410上移植了一遍,和2440非常类似,第二篇在fs4412(Cortex A9)上实现,基于linux3.14.78,用设备树匹配,移植过程中调试和整体理解很重要,一路上幸有良师益友指点,下面详细介绍: 1.物理时序分析相关 DM9000芯片是DAVICOM公司生产的一款以太网处理芯片,提供一个通用的处理器接口.一个10/100M自适应的PHY芯片和4K双字的SRAM.内部框架如下,涉及

AM335x(TQ335x)学习笔记——WM8960声卡驱动移植

经过一段时间的调试,终于调好了TQ335x的声卡驱动.TQ335x采用的Codec是WM8960,本文来总结下WM8960驱动在AM335x平台上的移植方法.Linux声卡驱动架构有OSS和ALSA两种架构,目前最常用的架构是ALSA,本文也使用ALSA架构对WM8960驱动进行移植. ASoC是对ALSA驱动架构的进一步封装.ASoC将ALSA驱动中的各模块抽象为三部分:Platform.Codec和Machine.Platform主要是平台硬件驱动,包括SoC的IIS模块.DMA等,在本文中

启动期间的内存管理之初始化过程概述----Linux内存管理(九)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检测到可用内存和寄存器. 而我们今天要讲的boot阶段就是系统初始化阶段使用的内存分配器. 1 前景回顾 1.1