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

Linux DMA详解 (2)

Linux DMA详解 (2)

对于0-3通道来说地址对寄存器的映射如下:

  

A23 ... A16 A15 ... A8  A7 ... A0    (物理地址)
     |  ...  |   |  ... |   |  ... |
     |  ...  |   |  ... |   |  ... |
     |  ...  |   |  ... |   |  ... |
    P7  ...  P0  A7 ... A0  A7 ... A0   
  |    Page    | Addr MSB | Addr LSB |   (DMA
地址寄存器)

  

对于5-7通道来说地址对寄存器的映射如下:

  

A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0    (物理地址)

  

    |  ...  |   \   \   ... \  \  \  ... \  \
    |  ...  |    \   \   ... \  \  \  ... \  (
没用)
    |  ...  |     \   \   ... \  \  \  ... \
   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0  

  

|      Page      |  Addr MSB   |  Addr LSB  |   (DMA 地址寄存器)

  

通道 5-7 传输以字为单位, 地址和计数都必须是以字对齐的。

  

include/asm-i386/dma.h中有i386平台的8237 DMA控制器的各处寄存器的地址及寄存器的定义,这里只对控制寄存器加以说明:

  

DMA Channel Control/Status Register (DCSRX)

  

31
表明是否开始

  

30位选定DescriptorNon-Descriptor模式

  

29
判断有无中断

  

8
请求处理
Request Pending

  

3 Channel是否运行

  

2
当前数据交换是否完成

  

1位是否由Descriptor产生中断

  

0
是否由总线错误引起中断

  

DMA通道使用的地址

  

DMA通道用dma_chan结构数组表示,这个结构在kernel/dma.c中,列出如下:

  

struct dma_chan {
        int  lock;
        const char *device_id;
};

static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {
        [4] = { 1, "cascade" },
};

  

如果dma_chan_busy[n].lock != 0表示忙,DMA0保留为DRAM更新用,DMA4用作级联。DMA 缓冲区的主要问题是,当它大于一页时,它必须占据物理内存中的连续页。

  

由于DMA需要连续的内存,因而在引导时分配内存或者为缓冲区保留物理 RAM 的顶部。在引导时给内核传递一个"mem="参数可以保留 RAM 的顶部。例如,如果系统有 32MB 内存,参数"mem=31M"阻止内核使用最顶部的一兆字节。稍后,模块可以使用下面的代码来访问这些保留的内存:

  

dmabuf = ioremap( 0x1F00000 /* 31M */, 0x100000 /* 1M */);

  

分配 DMA 空间的方法,代码调用 kmallocGFP_ATOMIC
直到失败为止,然后它等待内核释放若干页面,接下来再一次进行分配。最终会发现由连续页面组成的DMA 缓冲区的出现。

  

一个使用 DMA 的设备驱动程序通常会与连接到接口总线上的硬件通讯,这些硬件使用物理地址,而程序代码使用虚拟地址。基于 DMA 的硬件使用总线地址而不是物理地址,有时,接口总线是通过将 I/O 地址映射到不同物理地址的桥接电路连接的。甚至某些系统有一个页面映射方案,能够使任意页面在外围总线上表现为连续的。

  当驱动程序需要向一个 I/O 设备(例如扩展板或者DMA控制器)发送地址信息时,必须使用 virt_to_bus 转换,在接受到来自连接到总线上硬件的地址信息时,必须使用 bus_to_virt 了。
继承事业,薪火相传
返回列表