匆匆忙忙又一年, 由于最近项目不忙, 对之前的工作做些总结, 本文主要描述与硬件通信相关. 与硬件通信不得不提IO端口与IO内存, 对于两者的定义与区别我在网上找了段描述, 感觉还可以, 如下: 这两者如何区分就涉及到硬件知识,X86体系中,具有两个地址空间:IO空间和内存空间,而RISC指令系统的CPU(如ARM、PowerPC等)通常只实现一个物理地址空间,即内存空间。 io端口: 当寄存器或内存位于IO空间时,称为IO端口。一般寄存器也俗称I/O端口,或者说I/O ports,这个I/O端口可以被映射在Memory Space,也可以被映射在I/O Space。 Io内存:当寄存器或内存位于内存空间时,称为IO内存。 本文着重说明IO内存的操作: 首先需要说明的驱动访问I/O寄存器的主要目的是: 处理寄存器操作边际效应. 既:驱动程序必需确保不使用高速缓存(cache), 并且在访问的寄存器时不发生读写指令的重新排序. 关于cache引起的问题只需要将该段地址空间设置为NO CACHE类型即可. ioremap函数在映射的过程中就设置了对应空间的nocacke属性. 对于编译器优化或者硬件重新排序引起的问题, 需要使用内存屏障. 如下是一个内存屏障的例子, 便于理解其工作原理. #define set_mb(var, value) do { var = value; mb(); } while (0) #define mb() __asm__ __volatile__ ("" : : : "memory") 1)set_mb(),mb(),barrier()函数追踪到底,就是__asm__ __volatile__("":::"memory"),而这行代码就是内存屏障。 2)__asm__用于指示编译器在此插入汇编语句 3)__volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。 4)memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将 作废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内 存。 5)"":::表示这是个空指令。barrier()不用在此插入一条串行化汇编指令。在后文将讨论什么叫串行化指令。 6)__asm__,__volatile__,memory在前面已经解释 借此说明对于DMA操作内存管理做个说明: 一般DMA内存会使用dma_alloc_coherent申请, 该函数在内存映射时就增加no cache属性, 该属性存在页表中. wilson 2012-02-02 |
|
来自: clover_xian > 《我的图书馆》