CPU通过硬件设备的寄存器读写设备IO。
对X86平台,这些寄存器位于专门的IO空间中,称为IO端口;而对于其他大多是CPU,IO寄存器是映射到普通内存中,没有划出特别的空间,因此称作IO内存。
对IO端口的操作流程
op1=>operation: request_region
op2=>operation: inb(),outb()等
op3=>operation: release_region
op1->op2->op3
对IO内存操作
op1=>operation: request_mem_region
op2=>operation: ioremap()
op3=>operation: inb(),outb()等
op4=>operation:
op5=>operation: release_mem_region
op1->op2->op3->op4->op5
可见IO内存操作比IO端口多一个io映射的动作:
void *ioremap(unsigend long *add, unsigned long size)
对IO端口的操作函数主要是inb/w/l,outb/w/l等。
以及连续读写 insb/w/l、outsb/w/l等。
对于非x86的CPU,一般都是用IO内存方法,读写接口如下:
unsigned int readb/w/l(addr)
writeb/w/l(value, addr)
//LDD中建议使用下面接口,因为会进行类型检查,更加安全
unsigned int ioread8/16/32(addr)
void iowrite8/16/32(value, addr)
void ioread8/16/32/_rep(addr, buf, count) //连续读写
void iowrite8/16/32/_rep(addr, buf, count)
//整块操作, 与对应C库函数意义相似
void memset_io(addr, value, count)
void memcpy_fromio(dest, source, count)
void memcpy_toio(dest, source, count)
关于IO屏障的问题,
为了防止硬件优化带来的读写乱序而是用内存屏障
相关函数有 rmb() wmb() mb()等。
参考内核源码,readb,writeb等函数已经使用了屏障,因此不需要再写一次:
linux-3.18.27\arch\arm\include\asm\io.h
/* IO barriers */
#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
#include <asm/barrier.h>
#define __iormb() rmb()
#define __iowmb() wmb()
#else
#define __iormb() do { } while (0)
#define __iowmb() do { } while (0)
#endif
//-----------------------------------------------------------------------------
#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
上面 CONFIG_ARM_DMA_MEM_BUFFERABLE 这个宏,是在内核编译时配置的,有相关说明:
Historically, the kernel has used strongly ordered mappings to
provide DMA coherent memory. With the advent of ARMv7, mapping
memory with differing types results in unpredictable behaviour,
so on these CPUs, this option is forced on.
大概是说对arm中采用strongly ordered mappings的cpu不需要内存壁障,否则就要增加 内存壁障来保证安全。
网友评论