IO-Mapping
Linux/io-mapping文件中提供的io映射抽象接口,可以将设备上的小空间有效地映射到处理器。io映射最初用来在32位处理器上支持大的显存,在这种情况下,由于显存太大,不能直接使用ioremap_wc将整个显存静态映射到处理器,因为这样会消耗过大的内核地址空间。
在驱动程序初始化时,可以使用下面的函数创建一个映射对象(mapping object):
struct io_mapping *io_mapping_create_wc(unsigned long base, unsigned long size)
参数base是被映射区域的总线地址,‘size’表示映射区域的大小。两个参数都以字节为单位。
这个以_wc结尾的函数提供的映射仅能与io_mapping_map_atomic_wc 或 io_mapping_map_wc一起使用。
在映射对象中,某个页面或者完全被原子的映射,或者不被原子的映射,这依赖于调度环境的需要。当然,原子映射更加有效:
void *io_mapping_map_atomic_wc(struct io_mapping *mapping,
unsigned long offset)
参数‘offset’是映射区域中的偏移。对创建函数指定的区域以外的地址的访问将产生不确定的结果。如果偏移量没有页对齐,也会产生不确定的结果。返回值将指向CPU地址空间中的某个页面。
这个函数以_wc结尾,将返回一个具有写捆绑映射的页面,而且只能用于通过函数io_mapping_create创建的映射。
注意,持有页面映射的任务不能睡眠。
void io_mapping_unmap_atomic(void *vaddr)
‘vaddr’必须是最后一次调用io_mapping_map_atomic_wc返回的值。该函数将取消对指定页面的映射,之后,将允许任务睡眠。
如果任务需要在持有锁的时候睡眠,可以使用非原子映射,但是它们的速度较慢。
void *io_mapping_map_wc(struct io_mapping *mapping,
unsigned long offset)
该函数与io_mapping_map_atomic_wc类似,但是它运行任务在持有映射页面(page mapped)期间睡眠。
void io_mapping_unmap(void *vaddr)
该函数类似于io_mapping_unmap_atomic,用于被io_mapping_map_wc函数映射的页面。
在驱动程序退出的时候,io_mapping对象必须被释放:
void io_mapping_free(struct io_mapping *mapping)
当前实现:
这些函数的初步实现使用了现存的映射机制,并且仅提供了一个抽象层而没有任何新增功能。
在64位的处理器上,io_mapping_create_wc在整个空间上调用ioremap_wc,为资源创建一个永久的内核可见映射。map_atomic与映射函数在ioremap_wc返回的虚拟地址区域的基地址上加上需要的偏移量。
在定义了高端内存的32位处理器上,io_mapping_map_atomic_wc使用kmap_atomic_pfn以原子的方式映射指定的页面;kmap_atomic_pfn并非专用于设备页面,但它为映射提供了一个很好的途径。
在没有定义高端内存的32位处理器上,io_mapping_map_atomic_wc与io_mapping_map_wc都使用了ioremap_wc,该函数的效率很低,在进行映射时,需要使用IPI知会所有的处理器,显著降低了系统的性能。