如何使用 memcpy_toio/fromio?
How do I use memcpy_toio/fromio?
我正在使用 C 编写一个内核模块来与 PCIe 卡通信,我已经使用 pci_iomap 分配了一些 io 内存,并且我 write/read 在那里使用 ioread/write32。
这可行,但性能很差,我读到我可以通过 memcpy_toio/fromio 使用块传输,而不是一次只执行 32b。
写,我用的是iowrite32(buffer[i], privdata->registers + i);
读书,我buffer[i] = ioread32(&privdata->registers[i]);
我尝试将其中的 for 循环替换为:
memcpy_toio(privdata->registers, buffer, 2048);
memcpy_fromio(buffer, privdata->registers, 2048);
如果我只用 memcpy_toio 替换写循环并使用 ioread32 进行读取,程序不会崩溃,但指令似乎没有做任何事情(寄存器没有改变) ;
此外,当我用 memcpy_fromio 指令替换读取循环时,它崩溃了。
我在想这可能是因为读取尝试访问仍在写入的内存位置。有没有办法在 iowrite32 或 memcpy_toio 之后刷新写入队列?
我在这里做错了什么?
您使用哪种缓冲区类型?
查看memcpy_fromio() , memcpy_toio()
的实现
static inline void
memcpy_fromio(void *dst, volatile void __iomem *src, int count)
{
memcpy(dst, (void __force *) src, count);
}
static inline void
memcpy_toio(volatile void __iomem *dst, const void *src, int count)
{
memcpy((void __force *) dst, src, count);
}
你可以看到简单的 memcpy 调用。
并查看 iowrite32() and ioread32() 实现:
static inline void iowrite32(u32 val, void __iomem *p)
{
if (__is_PCI_addr(p))
val = _swapl(val);
__builtin_write32(p, val);
if (__is_PCI_MEM(p))
__flush_PCI_writes();
}
static inline unsigned int ioread32(void __iomem *p)
{
uint32_t ret = __builtin_read32(p);
if (__is_PCI_addr(p))
ret = _swapl(ret);
return ret;
}
如您所见,memcpy_fromio() , memcpy_toio() 不适合与 PCIe 设备一起使用。
memcpy_from/toio()
仅当 I/O 内存表现得像内存时才能使用,即,如果值可以推测读取,并且可以多次写入或乱序写入。
标记为不可预取的 I/O 范围不支持此功能。
我正在使用 C 编写一个内核模块来与 PCIe 卡通信,我已经使用 pci_iomap 分配了一些 io 内存,并且我 write/read 在那里使用 ioread/write32。
这可行,但性能很差,我读到我可以通过 memcpy_toio/fromio 使用块传输,而不是一次只执行 32b。
写,我用的是iowrite32(buffer[i], privdata->registers + i);
读书,我buffer[i] = ioread32(&privdata->registers[i]);
我尝试将其中的 for 循环替换为:
memcpy_toio(privdata->registers, buffer, 2048);
memcpy_fromio(buffer, privdata->registers, 2048);
如果我只用 memcpy_toio 替换写循环并使用 ioread32 进行读取,程序不会崩溃,但指令似乎没有做任何事情(寄存器没有改变) ;
此外,当我用 memcpy_fromio 指令替换读取循环时,它崩溃了。
我在想这可能是因为读取尝试访问仍在写入的内存位置。有没有办法在 iowrite32 或 memcpy_toio 之后刷新写入队列?
我在这里做错了什么?
您使用哪种缓冲区类型?
查看memcpy_fromio() , memcpy_toio()
的实现 static inline void
memcpy_fromio(void *dst, volatile void __iomem *src, int count)
{
memcpy(dst, (void __force *) src, count);
}
static inline void
memcpy_toio(volatile void __iomem *dst, const void *src, int count)
{
memcpy((void __force *) dst, src, count);
}
你可以看到简单的 memcpy 调用。
并查看 iowrite32() and ioread32() 实现:
static inline void iowrite32(u32 val, void __iomem *p)
{
if (__is_PCI_addr(p))
val = _swapl(val);
__builtin_write32(p, val);
if (__is_PCI_MEM(p))
__flush_PCI_writes();
}
static inline unsigned int ioread32(void __iomem *p)
{
uint32_t ret = __builtin_read32(p);
if (__is_PCI_addr(p))
ret = _swapl(ret);
return ret;
}
如您所见,memcpy_fromio() , memcpy_toio() 不适合与 PCIe 设备一起使用。
memcpy_from/toio()
仅当 I/O 内存表现得像内存时才能使用,即,如果值可以推测读取,并且可以多次写入或乱序写入。
标记为不可预取的 I/O 范围不支持此功能。