我正在使用TI AM3358 SoC,运行一个运行Linux3.12的ARM Cortex-A8处理器。我在设备树中启用了GPMC节点的一个子设备,它探测我的驱动程序,在那里,我用设备树节点提供的资源调用ioremap_nocache()
,以获得一个未缓存的区域。
我之所以不请求缓存,是因为它不是连接到GPMC总线的实际内存设备,它当然会从处理器缓存中受益,而是一个FPGA设备。因此,访问需要始终通过实际的电线。
当我这么做时:
u16 __iomem *addr = ioremap_nocache(...);
iowrite16(1, &addr[0]);
iowrite16(1, &addr[1]);
iowrite16(1, &addr[2]);
iowrite16(1, &addr[3]);
ioread16(&addr[0]);
ioread16(&addr[1]);
ioread16(&addr[2]);
ioread16(&addr[3]);
我看到这8次访问是用逻辑分析器在电线上完成的。然而,当我这样做时:
u16 v;
addr[0] = 1;
addr[1] = 1;
addr[2] = 1;
addr[3] = 1;
v = addr[0];
v = addr[1];
v = addr[2];
v = addr[3];
我看到了四个写访问,但没有看到后续的读访问。
我是不是遗漏了什么?ioread16()
和直接内存访问之间有什么区别,因为它知道整个GPMC范围应该和内存一样是可寻址的?
这种行为是否是可以避免的编译器优化的结果?我还没有看生成的指令,但在那之前,可能有人有足够的经验,有一些有趣的答复。
发布于 2015-03-24 14:00:08
ioread*()
和iowrite*()
在ARM上执行数据内存屏障,然后执行volatile
访问,例如:
#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); })
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
__raw_read*()
和__raw_write*()
( *
为b
、w
或l
)可用于直接读/写。它们执行这些操作所需的精确的单一指令,将地址指针转换为volatile
指针。
__raw_writew()
示例(存储寄存器,半字):
#define __raw_writew __raw_writew
static inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
asm volatile("strh %1, %0"
: "+Q" (*(volatile u16 __force *)addr)
: "r" (val));
}
但是,请注意,这两个函数没有插入任何障碍,因此您应该在任何您希望对内存访问进行排序的地方调用rmb()
(读内存屏障)和wmb()
(写内存屏障)。
https://stackoverflow.com/questions/29083876
复制