内存映射IO空间的读写函数readl_relaxed和readl差别

kernel IO 访问
通过 I/O 访问外设是深度架构和设备特定的。对于想要在多种体系结构和总线实现之间移植的驱动程序,内核提供了一系列访问器函数,这些函数提供了不同程度的排序保证:

定义
arch/arm64/include/asm/io.h,可以看出

readX()相对于readX_relaxed()多了一个__iormb()指令,__iormb()封装了dsb指令
writeX()相对于writeX_relaxed()多了一个__iowmb()指令,__iowmb()封装了dmb指令
/*

  • Relaxed I/O memory access primitives. These follow the Device memory
  • ordering rules but do not guarantee any ordering relative to Normal memory
  • accesses.
    */
    #define readb_relaxed© ({ u8 __r = __raw_readb©; __r; })
    #define readw_relaxed© ({ u16 __r = le16_to_cpu((__force __le16)__raw_readw©); __r; })
    #define readl_relaxed© ({ u32 __r = le32_to_cpu((__force __le32)__raw_readl©); __r; })
    #define readq_relaxed© ({ u64 __r = le64_to_cpu((__force __le64)__raw_readq©); __r; })

#define writeb_relaxed(v,c) ((void)__raw_writeb((v),©))
#define writew_relaxed(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),©))
#define writel_relaxed(v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),©))
#define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),©))

/*

  • I/O memory access primitives. Reads are ordered relative to any
  • following Normal memory access. Writes are ordered relative to any prior
  • Normal memory access.
    */
    #define readb© ({ u8 __v = readb_relaxed©; __iormb(__v); __v; })
    #define readw© ({ u16 __v = readw_relaxed©; __iormb(__v); __v; })
    #define readl© ({ u32 __v = readl_relaxed©; __iormb(__v); __v; })
    #define readq© ({ u64 __v = readq_relaxed©; __iormb(__v); __v; })

#define writeb(v,c) ({ __iowmb(); writeb_relaxed((v),©); })
#define writew(v,c) ({ __iowmb(); writew_relaxed((v),©); })
#define writel(v,c) ({ __iowmb(); writel_relaxed((v),©); })
#define writeq(v,c) ({ __iowmb(); writeq_relaxed((v),©); })

如何使用
内核定义了这么多的read和write函数,到底怎么用呢?
从内存映射的 I/O 空间读取数据。
readb 从 I/O 读取 8 位数据 ( 1 字节 );
readw 从 I/O 读取 16 位数据 ( 2 字节 );
readl 从 I/O 读取 32 位数据 ( 4 字节 )。

readX()/writeX()比readX_relaxed()/writeX_relaxed()多了dsb/dmb内存屏障指令,所以内核是想让开发者灵活使用来提高CPU的执行效率,在没必要使用readX()/writeX()的时候,使用readX_relaxed()/writeX_relaxed()函数来减少不必要的内存屏障,下面针对不同的内存类型来分析一下:

1、Normal Memory操作
Normal Memory支持乱序访问和cache。使用readX()/writeX()相当于禁止了这些加速功能。readX_relaxed()/writeX_relaxed()没有关闭加速功能。
单core,只访问Normal Memory的场景。使用_relaxed()函数即可,单个core不需要内存屏障来同步
多core,一个core读某个内存、另一个core写相同内存的场景,要使用readX()/writeX(),确保所有的操作均完成

2、Device memory操作
Device Memory不支持乱序访问和不支持cache。使用readX()/writex()和 readX_relaxed()/writeX_relaxed()效果都是一样的,都不会有乱序访问和cache功能,readX()/writeX()反而多几条内存屏障指令。
典型场景是CPU操作外设寄存器,不需要执行dsb/dmb指令,使用_relaxed()可以减少指令执行

3、Normal Memory & Device Memory混合操作
典型场景是CPU向Normal Memory读写数据使用readX_relaxed()/writeX_relaxed()函数,然后启动DMA搬移使用writeX()。
读写Normal Memory可以利用乱序访问和cache特性加快执行速度。但是在DMA搬移之前一定要保证cache中的数据写到Normal Memory中,因此要使用writeX()来保证之前的操作执行成功。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值