如何使用 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 范围不支持此功能。