溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

驅動移植過程中DMA內存相關接口替換

發(fā)布時間:2020-07-11 21:41:25 來源:網絡 閱讀:983 作者:爐yu 欄目:編程語言

1. 相關概念介紹及移植簡介 
1.1 物理地址與總線地址 
        1)物理地址是與CPU相關的。在CPU的地址信號線上產生的就是物理地址,在程序指令中的的虛擬地址經過段映射和頁面映射后,就生成了物理地址,這個物理地址被放到CPU的地址線上。 
        2)總線地址,顧名思義,是與總線相關的,外設使用的就是總線地址。 
        在x86平臺下,外設的I/O地址是獨立的,即有專門的指令訪問外設I/O,I/O地址就是所謂的“總線地址”。而“物理地址”就是RAM地址。 
        在ARM平臺下,I/O和RAM統(tǒng)一編址,即“總線地址”就是“物理地址”。 
        Linux系統(tǒng)無論是在內核還是用戶空間,都是直接使用“虛擬地址”訪問內存或I/O空間,因此要訪問外設I/O,必須將I/O地址轉換成“虛擬地址”才能夠進行訪問。 
        MMU啟動前程序中的地址為“物理地址”,和硬件手冊中規(guī)定的地址一致。MMU啟動后程序中的地址為“虛擬地址”,“虛擬地址”和“物理地址”之間的關系參照MMU地址映射表。 
1.2 移植介紹 
        在移植Linux驅動的過程中,會遇到很多非POSIX接口,這些接口是跟Linux系統(tǒng)相關的,而在SylixOS中并未提供兼容接口,因此在替換過程中,需要結合SylixOS本身提供的一些機制實現(xiàn)一套兼容接口,在替換過程中為了保持與linux接口的兼容性,將不改變函數(shù)的原型,而只是將內部實現(xiàn)替換成SylixOS接口實現(xiàn)。 
        本篇將介紹在移植Linux驅動過程中有關DMA內存操作的相關接口的替換方案,注意,本文檔提供的替換方案僅適用于“物理地址”和“總線地址”相同的硬件平臺。 
2. DMA內存相關接口介紹及替換 
        在移植過程中主要遇到的和DMA內存相關操作的接口如表 2-1所示。 
        表 2-1 Linux DMA內存相關操作接口

系統(tǒng)接口接口功能
dma_alloc_coherent分配一片DMA一致性的內存區(qū)域
dma_free_coherent釋放一片DMA一致性內存
dma_pool_create創(chuàng)建一片DMA內存池
dma_pool_alloc從DMA內存池中分配一塊DMA內存
dma_pool_free釋放DMA內存到DMA內存池中
dma_pool_destroy銷毀DMA內存池

2.1 一致性內存相關接口介紹及替換 
2.1.1 分配一致性內存 
        1)Linux接口介紹 
        Linux內核提供相應接口用于分配一個DMA一致性的內存區(qū)域。

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

        函數(shù)dma_alloc_coherent原型分析: 
        此函數(shù)成功時返回分配的緩沖區(qū)地址,失敗時返回NULL; 
        參數(shù)dev為設備結構,SylixOS沒有提供該結構,因此在實際替換中,對該參數(shù)進行了修改; 
        參數(shù)size為分配的DMA內存大??; 
        參數(shù)handle為分配的DMA內存的地址; 
        參數(shù)gfp為分配內存標志。 
        2)SylixOS接口替換 
        在SylixOS內核中提供分配DMA內存的接口,且DMA內存是一致性內存,因此為保持兼容,dma_alloc_coherent接口在SylixOS中的實現(xiàn)如程序清單 2-1所示。 
                                            程序清單 2-1 dma_alloc_coherent接口實現(xiàn)

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一致性的內存區(qū)域。

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

        函數(shù)dma_free_coherent原型分析: 
        參數(shù)dev為設備結構,SylixOS沒有提供該結構,因此在實際替換中,對該參數(shù)進行了修改; 
        參數(shù)size為分配的DMA內存大??; 
        參數(shù)cpu_addr為待釋放的緩沖區(qū)地址; 
        參數(shù)handle為DMA地址的值。 
        2)SylixOS接口替換 
        在SylixOS中提供釋放DMA內存的接口,因此為了兼容,釋放DMA內存實現(xiàn)如程序清單 2-2所示。 
                                            程序清單 2-2 dma_free_coherent接口實現(xiàn)

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在數(shù)值上是相同的。 
2.2 DMA內存池相關接口介紹及替換 
2.2.1 創(chuàng)建DMA內存池 
        1)Linux接口介紹 
        Linux內核提供相應接口用于創(chuàng)建DMA內存池。

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

        函數(shù)dma_pool_create原型分析: 
        此函數(shù)成功時返回DMA池的結構指針,由于SylixOS沒有提供該結構,因此在替換過程中接口返回值做了修改。失敗時返回NULL; 
        參數(shù)name為DMA池的名字; 
        參數(shù)dev為設備結構,SylixOS沒有提供該結構,因此在實際替換中,對該參數(shù)進行了修改; 
        參數(shù)size為從該DMA池中分配的緩沖區(qū)的大?。?nbsp;
        參數(shù)align為從該池分配時所遵循的對齊原則; 
        參數(shù)boundary表示從該DMA池返回的內存不能越過2的boundary次方的邊界。 
        2)SylixOS接口替換 
        SylixOS提供定長內存管理機制,因此創(chuàng)建DMA內存池接口實現(xiàn)如程序清單 2-3所示。 
                                            程序清單 2-3 dma_pool_create接口實現(xiàn)

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;
}

        主要實現(xiàn)過程是通過調用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)

        函數(shù)dma_pool_alloc原型分析: 
        此函數(shù)成功時返回從DMA池中獲取的內存塊的地址,失敗時返回NULL; 
        參數(shù)pool為創(chuàng)建DMA池時返回的結構體指針,由于SylixOS沒有提供該結構,因此在替換過程中接口返回值做了修改; 
        參數(shù)mem_flags為分配內存標志; 
        參數(shù)handle為獲取的內存塊的DMA地址。 
        2)SylixOS接口替換 
        SylixOS提供從創(chuàng)建的定長內存中獲取內存塊,因此從DMA內存池中獲取內存塊的實現(xiàn)如程序清單 2-4所示。 
                                            程序清單 2-4 dma_pool_alloc接口實現(xiàn)

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是創(chuàng)建內存池成功時產生的句柄,通過該句柄可以從指定的內存池中獲取內存塊。 
2.2.3 釋放內存塊到內存池中 
        1)Linux接口介紹 
        Linux內核提供相應接口用于釋放內存塊到DMA內存池中。

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

        函數(shù)dma_pool_free原型分析: 
        參數(shù)pool為創(chuàng)建DMA池時返回的結構體指針,由于SylixOS沒有提供該結構,因此在替換過程中接口返回值做了修改; 
        參數(shù)vaddr為從DMA池中獲取的內存塊的地址; 
        參數(shù)dma為DMA池中獲取的內存塊的地址對應的DMA地址。 
        2)SylixOS接口替換 
        通過調用定長內存釋放函數(shù)可實現(xiàn)將分配的內存返還到定長內存中,具體實現(xiàn)如程序清單 2-5所示。 
                                            程序清單 2-5 dma_pool_free接口實現(xiàn)

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)

        函數(shù)dma_pool_free原型分析: 
        參數(shù)pool為創(chuàng)建DMA池時返回的結構體指針,由于SylixOS沒有提供該結構,因此在替換過程中接口返回值做了修改; 
        2)SylixOS接口替換 
        通過調用刪除定長內存函數(shù)即可銷毀DMA內存池,具體實現(xiàn)如程序清單 2-6所示。 
                                            程序清單 2-6 dma_pool_destroy接口實現(xiàn)

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

3. 總結 
        在移植過程中,經常會遇到平臺相關的接口,雖然SylixOS沒有直接提供相應的接口進行替換,但是如果理解該接口的實現(xiàn)目的,那么就可以通過SylixOS本身的機制實現(xiàn)相同的功能。當然需要對SylixOS本身提供的機制與方法有所了解,才能夠輕松地進行接口替換。


向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI