Linux内核开发之内存与I/O访问(五)

来源:互联网 发布:微信为什么要封淘宝客 编辑:程序博客网 时间:2024/06/05 15:42

“小王,告诉你一个好消息,最难理解的部分不知不觉中已经讲完了,今天的课程就简单多了,而且最重要的是咱们的Linux设备驱动核心理论课也差不多了…”

“最难的部分?已经讲完了?我咋没感觉呢..你讲的真是太好了,太通俗易懂了,太..”小王调皮的说。

“切,就你嘴甜,我还不知道你啊,小脑筋..”我白了小王一样。

   那么今天呢?今天就讲讲IO内存静态映射。在将Linux移植到目标电路板中,通常会建立外设IO内存物理地址到虚拟地址的静态映射,这个映射通过在电路板对应的

map_desc结构体数组中添加新的成员来完成,map_desc结构体的定义如下:

struct map_desc{   unsigned long virtual;  //虚拟地址   unsigned long pfn;  //__phys_to_pfn(phy_addr)   unsigned long length;   //大小   unsigned int type;  //类型 }

   将Linux操作系统移植到特定平台上,MACHINE_START到MACHINE_EDN宏之间的定义针对特定电路板而设计,其中的map_io()成员函数完成IO内存的静态映射,最后通过调用cpu—>map_io()建立map_desc数组中物理内存和虚拟内存的静态映射关系。

   在一个已经移植好的OS的内核中,驱动工程师完全可以对非常规内存区域的IO内存(外设控制器寄存器,MCU内部集成的外设控制寄存器等)依照电路板的资源使用情况添加到map_desc数组中。下边给出SMDK2440内存情况定义的map_desc:

SMDK2440内存资源情况定义的map_desc

 

“小王,今天要讲的另外一个主题是DMA”我补充道:

  DMA是一种无须CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制。使用DMA可以是系统CPU从实际的IO数据传输过程中摆脱出来,从而大大提

供系统的吞吐率。DMA方式的数据传输由DMA控制器(DMAC)控制,在传输期间,CPU可以并发地执行其他任务,当DMA结束后,DMAC通过中断通知CPU数据传输已经结束,然后由CPU执行相应的中断服务程序进行后续处理。

  说到DMA,就会想到Cache,两者本身似乎是好不相关的事物。的确,假设DMA针对内存的目的地址和Cache缓存的对象没有重叠区域,DMA和Cache之间就相安无事,但是,如果有重叠呢,经过DMA操作,Cache缓存对应的内存的数据已经被修改,而CPU本身并不知道,它仍然认为Cache中的数据仍然还是内存中的数据,以后访问Cache映射的内存时,它仍然使用陈旧的Cache数据,这就会发生Cache与内存之间数据“不一致性”的错误。一旦出现这样的情况,没有处理好,驱动就将无

法正常运行。那么怎样解决呢?最简单的方法是直接禁止DMA目标地址范围内内存的Cache功能,当然这是牺牲性能的,但却高可靠。不是吗,所以这两者之间究竟怎么平衡,还真不好解决。

  其实啊,Cache不一致的情况在其他地方也是可能发生的,比如,对于带MMU功能的ARM处理器,在开启MMU之前,需要设置Cache无效,TLB也是如此。

  说了,那么多DMA理论的东西,剩下的来点Linux下DMA编程的东西,当然,这里也是点一下,具体怎么操作,我可要卖个关子到下节了。

  在内存中用于与外设交互数据的一块区域被称作DMA缓冲区,在设备不支持scatter/gatherCSG,分散/聚集操作的情况下,DMA缓冲区必须是物理上联系的。

  对于ISA设备而言,其DMA操作只能在16MB以下的内存进行,因此,在使用kmalloc()和__get_free_pages()及其类似函数申请DMA缓冲区时应使用GFP_DMA标

志,这样能保证获得的内存是具备DMA能力的。

   内核中定义了__get_free_pages()针对DMA的“快捷方式”__get_dma_pages(),它在申请标志中添加了GFP_DMA,如下所示:

  #define __get_dma__pages(gfp_mask, order)  __get_free_pages((gfp_mask) | GFP_DMA, (order))
  "我不想使用order为参数的申请DMA内存,感觉就是怪怪的,那咋办?"小王抱怨道.
  那?这样吧,你就用另外一个函数dma_mem_alloc()源代码如下:
static unsigned long dma_mem_alloc(int size){   int order = get_order(size);    //大小->指数   return __get_dma_pages(GFP_KERNEL, order);}
 
"小王,感觉怎样,要不咱们下节继续?看你挺多不懂的地方?"我看到小王那充满疑惑的眼神。
"好,行,我正有这种打算呢"小王又露出了让人陶醉的笑容。

原创粉丝点击