驅動移植過程當中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內存相關操做接口linux

系統接口 接口功能
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一致性的內存區域。code

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接口實現it

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自己提供的機制與方法有所瞭解,纔可以輕鬆地進行接口替換。

相關文章
相關標籤/搜索