首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux DMA详解 (6)

Linux DMA详解 (6)

函数pci_map_sg完成分散/集中映射,其返回值是要传送的 DMA 缓冲区数;它可能会小于nents(也就是传入的分散表项的数量),因为可能有的缓冲区地址上是相邻的。一旦传输完成,分散/集中映射通过调用函数pci_unmap_sg 来撤销映射。
函数pci_map_sg分析如下(在include/asm-generic/pci-dma-compat.h中):

  

static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
                                    int nents, int direction)
{
        return dma_map_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents,
(enum dma_data_direction)direction);
}
include/asm-i386/dma-mapping.h
static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction direction)
{
        int i;

        BUG_ON(direction == DMA_NONE);

        for (i = 0; i < nents; i++ ) {
                BUG_ON(!sg.page);
//
将页及页偏移地址转化为物理地址
                sg.dma_address = page_to_phys(sg.page) + sg.offset;
        }
    //
可能有些数据还会保留在处理器的高速缓冲存储器中,因此必须显式刷新
        flush_write_buffers();
        return nents;
}

  

DMA

  

许多驱动程序需要又多又小的一致映射内存区域给DMA描述子或I/O缓存buffer,这使用DMA池比用dma_alloc_coherent分配的一页或多页内存区域好,DMA池用函数dma_pool_create创建,用函数dma_pool_allocDMA池中分配一块一致内存,用函数dmp_pool_free放内存回到DMA池中,使用函数dma_pool_destory释放DMA池的资源。

  

结构dma_poolDMA池描述结构,列出如下:

  

struct dma_pool {        /* the pool */
        struct list_head        page_list;//
页链表
        spinlock_t                lock;
        size_t                        blocks_per_page;//
每页的块数
        size_t                        size;     //DMA
池里的一致内存块的大小
        struct device                *dev; //
将做DMA的设备
        size_t                        allocation; //
分配的没有跨越边界的块数,是size的整数倍
        char                        name [32];//
池的名字
        wait_queue_head_t        waitq;  //
等待队列
        struct list_head        pools;
};

  

函数dma_pool_createDMA创建一个一致内存块池,其参数nameDMA池的名字,用于诊断用,参数dev是将做DMA的设备,参数sizeDMA池里的块的大小,参数align是块的对齐要求,是2的幂,参数allocation返回没有跨越边界的块数(或0)。

  

函数dma_pool_create返回创建的带有要求字符串的DMA池,若创建失败返回null对被给的DMA池,函数dma_pool_alloc被用来分配内存,这些内存都是一致DMA映射,可被设备访问,且没有使用缓存刷新机制,因为对齐原因,分配的块的实际尺寸比请求的大。如果分配非0的内存,从函数dma_pool_alloc返回的对象将不跨越size边界(如不跨越4K字节边界)。这对在个体的DMA传输上有地址限制的设备来说是有利的。

  

函数dma_pool_create分析如下(在drivers/base/dmapool.c中):

  struct dma_pool *dma_pool_create (const char *name, struct device *dev,
        size_t size, size_t align, size_t allocation)
{
        struct dma_pool                *retval;

        if (align == 0)
                align = 1;
        if (size == 0)
                return NULL;
        else if (size < align)
                size = align;
        else if ((size % align) != 0) {//
对齐处理
                size += align + 1;
                size &= ~(align - 1);
        }
//
如果一致内存块比页大,是分配为一致内存块大小,否则,分配为页大小
        if (allocation == 0) {
                if (PAGE_SIZE < size)//
页比一致内存块小
                        allocation = size;
                else
                        allocation = PAGE_SIZE;//
页大小
                // FIXME: round up for less fragmentation
        } else if (allocation < size)
                return NULL;
//
分配dma_pool结构对象空间
        if (!(retval = kmalloc (sizeof *retval, SLAB_KERNEL)))
                return retval;

        strlcpy (retval->name, name, sizeof retval->name);

        retval->dev = dev;
继承事业,薪火相传
返回列表