免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1335 | 回复: 1

ldd3 read note Capter 9 [复制链接]

论坛徽章:
0
发表于 2009-07-15 08:53 |显示全部楼层

   
   
   
2009.7.2
Chapter 9  Communicating with Hardware
I/O Ports and I/O Memory
ISA设备才影射到io呢, PCI一般影射到内存. x86个变态?
访问io空间需要防止编译器和cpu的优化带来的不确定因素.  硬件cache可以通过page禁止. 编译器优化就得.. barrier了
*#include
void barrier(void) 禁止编译器优化
*#include
void rmb(void); //保证之前的读操作,在之后的读操作之前完成
void read_barrier_depends(void); //rmb的弱化版, rmb保证所有read的order, 这个只保证不reorder依赖read
void wmb(void);//类rmb
void mb(void);  //保证rmb和wmb
不懂read_barrier_depends就别乱用.
   


http://lse.sourceforge.net/locking/wmbdd.html
原因: 一些cpu(alpha)不支持cache同步invalidation.
       

注意search中的rmb.   
某些cpu的cache语意导致看起来p->key的读取可能早于在p=head.next!!!!, 这种cpu顺着链表的读取是有问题的,如:d = p->next->data;

比如alpha之流有上面形式的cache. 而wmb只保证invalide小时是p->key先更新,而head.next=p是后更新的.

果cache0,1分别存放偶数/奇数地址的地址. 而key在bank0, head在bank1.
虽然key的invalide先到reading cpu的cache, 但是如果bank0的队列忙,
将会导致bank1的head先得到更新而key是垃圾. 而且alpha的cpu 依赖的read
也没有等待操作(没有把早点到达的invalid消息处理完), 导致不一致的结果出现.
解决方法1: 吧wmb 换成wmbdd
解决方法2: rmb换成read_barrie_depends (只有alpha是rmb其他体系是空)
另外参考RUC:
http://lse.sourceforge.net/locking/rclock.html
msdn的参考:
http://blogs.msdn.com/itgoestoeleven/archive/2008/03/11/the-joys-of-compiler-and-processor-reordering-why-you-need-the-read-side-barrier.aspx
void smp_rmb(void);
void smp_read_barrier_depends(void);
void smp_wmb(void);
void smp_mb(void);
These versions of the barrier macros insert hardware barriers only when the kernel
is compiled for SMP systems; otherwise, they all expand to a simple barrier
call. (cpu-cpu之间保序,用smp_在UP的时候会速度更好, 如果CPU->外设, 永远不要用smp_xxx)
典型的驱动使用wmb:
writel(dev->registers.addr, io_destination_address);
writel(dev->registers.size, io_size);
writel(dev->registers.operation, DEV_READ);
wmb( );
writel(dev->registers.control, DEV_GO)
(在x86上写出cpu外的指令不会reorder, 但是read会)
atomic操作和spinlock带有barrier功能.
内核实现的复制附带barrier(这是默认值, 有的体系结构有专用的优化)
#define set_mb(var, value) do {var = value; mb( );} while 0
#define set_wmb(var, value) do {var = value; wmb( );} while 0
#define set_rmb(var, value) do {var = value; rmb( );} while 0
Using I/O Ports
声明占有i/o region:
#include
struct resource *request_region(unsigned long first, unsigned long n, const char *name); /*失败返回NULL*
/
/proc/ioports.
void release_region(unsigned long start, unsigned long n);
int check_region(unsigned long first, unsigned long n); //已经不再使用,不能保证接下来的分配成功
Manipulating I/O ports
)
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port); //不同体系结构的数据类型会不同
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
unsigned inl(unsigned port);
void outl(unsigned longword, unsigned port);//这4个s390不能用, s390只支持byte io
unsigned : 代表体系相关. 但是赋值的时候会自动转换,也没有警告.
I/O Port Access from User Space
*
*编译的时有用 -O, 确保inline被展开
*调用ioperm(单个端口) 或者iopl,(全部), x86特定
*必须有root权限, 准确的是CAP_SYS_RAWIO
可以通过/dev/port来访问, 不过也只有pc用
String Operations //no endian考虑
同样不适用于s390.(问题不大, 390几乎不和别的体系共享设备, 因为总线不同)
void insb(unsigned port, void *addr, unsigned long count);
void outsb(unsigned port, void *addr, unsigned long count);
void insw(unsigned port, void *addr, unsigned long count);
void outsw(unsigned port, void *addr, unsigned long count);
void insl(unsigned port, void *addr, unsigned long count);
void outsl(unsigned port, void *addr, unsigned long count);
Pausing I/O
i386比较明显, 比如超频的cpu和ISA板子.  _p , 要不要_p估计都是试验得出的?
Platform Dependencies
io操作不可避免的,是特定体系结构相关的.
IA-32 (x86)
x86_64 :supports all the functions described in this chapter. Port numbers are of type unsigned short.
IA-64 (Itanium)  :All functions; ports,unsigned long (memory-mapped).String func  implemented in C.
Alpha :All the functions supported(diffrent per cpu),  ports memory-mapped. String  Ports are unsigned long.
ARM : Ports are memory-mapped,all supported; string in C. Ports are of type unsigned int.
Cris :does not support the I/O port abstraction; the various port operations are defined to do nothing at all.
M68k M68k-nommu : memory-mapped. String functions are supported, unsigned char *.
MIPS MIPS64 :supports all , string ( with tight assembly loops), memory-mapped; unsigned long.
PA-RISC :All func supported; ports is int on PCI-based systems and unsigned short on EISA ,string: unsigned long port numbers.
PowerPC PowerPC64 : All func supported; unsigned char * on 32-bit systems, unsigned long on 64-bit

S390
: Similar to the M68k, only byte I/O  no string operations.  Ports are char pointers  memory-mapped.
Super-H : Ports are unsigned int (memory-mapped), and all the functions are supported.
SPARC  SPARC64 : memory-mapped. Versions of the port functions are defined to work with unsigned long ports.
除了x86没有体系是io单独地址空间的. 另外,特别是早期的alpha,不能一次移动单个或两个字节, inb, inw实现为在不同的地址上进行两次32bit read操作.
An I/O Port Example
digital I/O port: 读写直接对应于引脚电平.
GPIO: 通用数字i/o端口. 一般可以被两个io地址控制:一个地方可以选择哪个pin是out,哪个是in, 另外一个地方可以read/write逻辑电平.
更见单的数字io可能定死了, 哪些是in, 哪些是out,: 比如 parallel port.
An Overview of the Parallel Port
*3个 8bit的端口构成,就是24个not so GPIO
*第一个并口在0x378这个位置, 第二个在0x278
*第一个端口是双向数据端口, 直接链接到pin 2-9
*第二个端口是只读的状态端口,如果链接打印机,则能报告缺纸,忙等状态
*第三个端口是只写的控制端口, 比如使能中断等.
*信号: standard transistor-transistor logic (TTL) levels: 0 and 5 volts,the logic threshold at about 1.2 volts
* 至少能满足the standard TTL LS current ratings (起始许多都能做得更好啦)
*并口电路没有和内部电路隔离, 方便加接逻辑门,但是容易损害主板. 往电路加接optoisolators或者,买个plugin的并口吧.

*共12个输出bit(data 8+ control 4),, 5个输入bit (5个状态bit)
*bit 4 (0x10) of port 2是irq控制bit, 没有pin对应
*一些pin是做了逻辑翻转的.
driver short (Simple Hardware Operations and Raw Tests)
为每个端口创建一个设备节点.查看/proc/ioports 有无driver使用相应端口.  可以为每个端口接一个LED,每个LED有1k的电阻.  (ldd3 用pin9 和10做演示, 如果完全按照ldd3的玩法, 不要接led到些pin上).
/dev/short0 => 0x378
/dev/short1 => short0+1
....
/dev/short0p  => 用outb_p
/dev/short0s   => 用 outb_s
while (count--) {
  outb(*(ptr++), port);
  wmb( );  /*防止被优化掉,保障顺序*/
}
//点亮led
echo -n "any string" > /dev/short0  //只有最后一个字符能保持在led带上,所以用-n,不要加回车,否则最后灯的状态不变
//读取
dd if=/dev/short0 bs=1 count=1 | od -t x1
Using I/O Memory
还是内存影射的io操作为主流. 和设备内存一起通称 i/o memory. (寄存器和内存软件看起来一样). 这里主要讨论ISA和PCI的设备内存.
设备内存默认一般还没有建立起页表,所以需要先ioremap一下. 最好用io访问宏来访问io内存, 以便于优化和良好的可移植性.
*
*struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
/proc/iomem
void release_mem_region(unsigned long start, unsigned long len);
int check_mem_region(unsigned long start, unsigned long len); //别用,知道就成
*#include
void *ioremap(unsigned long phys_addr, unsigned long size);
void *ioremap_nocache(unsigned long phys_addr, unsigned long size);
void iounmap(void * addr);
Accessing I/O Memory
* , 为了移植, 不要用pointer访问, 尽量
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);
//在同一个地址上的rep
void ioread8_rep(void *addr, void *buf, unsigned long count);
void ioread16_rep(void *addr, void *buf, unsigned long count);
void ioread32_rep(void *addr, void *buf, unsigned long count);
void iowrite8_rep(void *addr, const void *buf, unsigned long count);
void iowrite16_rep(void *addr, const void *buf, unsigned long count);
void iowrite32_rep(void *addr, const void *buf, unsigned long count);
void memset_io(void *addr, u8 value, unsigned int count);
void memcpy_fromio(void *dest, void *source, unsigned int count);
void memcpy_toio(void *dest, void *source, unsigned int count);
//一些老的,不鼓励使用的宏
unsigned readb(address);
unsigned readw(address);
unsigned readl(address);
void writeb(unsigned value, address);
void writew(unsigned value, address);
void writel(unsigned value, address);
Ports as I/O Memory
一些硬件, 有的版本用i/o 端口, 一些用io memory. linux2.6 实现了一种port as io memory的手段.
void *ioport_map(unsigned long port, unsigned int count);
void ioport_unmap(void *addr);
request_region仍然是需要的.
ISA Memory Below 1 MB
640 KB (0xA0000) 到1 MB(0x100000).  
driver silly, (Simple Tool for Unloading and Printing ISA Data)
访问348k内存, 类似/dev/mem.
#define ISA_BASE 0xA0000
#define ISA_MAX 0x100000 /* for general memory access */
/* this line appears in silly_init */
io_base = ioremap(ISA_BASE, ISA_MAX - ISA_BASE);
/dev/sillyb  --> iowrite8 ioread8
isa_readb and Friends
不要用, 是为过渡使用的. 带有这个前缀的可以跳过ioremap的过程.
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/79526/showart_1996384.html

论坛徽章:
0
发表于 2014-05-23 08:07 |显示全部楼层
翻译了这么多,你运行过这些程序吗?能产生中断吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP