如何使用memcpy_toio/fromio?

如何使用memcpy_toio/fromio?,c,linux-kernel,memcpy,C,Linux Kernel,Memcpy,我正在用C编写一个内核模块,以便与PCIe卡进行通信,我已经使用pci_iomap分配了一些io内存,并使用ioread/write32在那里进行写/读操作 这是可行的,但性能相当差,我读到我可以通过memcpy_toio/fromio使用块传输,而不是一次只执行32b 为了写,我使用了iowrite32(buffer[I],privdata->registers+I) 要读取,我需要buffer[I]=ioread32(&privdata->registers[I]) 我尝试将这些中的for循

我正在用C编写一个内核模块,以便与PCIe卡进行通信,我已经使用pci_iomap分配了一些io内存,并使用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指令替换读取循环时,它会崩溃

我想这可能是因为读操作试图访问mem位置,而它仍在被写入。有没有办法在iowrite32或memcpy_toio之后刷新写入队列


我做错了什么

您使用哪种缓冲区类型

从执行情况看,

你可以看到简单的memcpy调用

请看下面的示例和实现:

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;
 }
如您所见,不适合使用PCIe设备

memcpy\u from/toio()
仅当I/O内存的行为类似于内存时才可使用,即,如果可以推测性地读取值,并多次写入或无序写入值


标记为不可预取的I/O范围不支持此操作。

感谢您对崩溃的详细信息保密。这是因为它们是。在我执行“insmod module_name”命令后,它停止响应任何东西,包括magic SysRq,我所能做的就是按下shutdown按钮。如果有帮助的话,我保留了一个/var/log/messages的尾部-f,它会打印所有的KERN_信息消息,直到memcpy_toio指令发出。这似乎也不是内核恐慌,但我不知道在重新启动后在哪里可以找到更多细节。哪种体系结构?寄存器是否实现了内存语义?不确定您所说的体系结构(内存体系结构?)是什么意思,或者内存语义是否与这个特定问题相关。这只是一些通过覆盖条0分配的内存映射io,我应该能够像执行32位读/写操作一样执行块传输。我只是不知道如何(使用哪些功能,使用哪些功能以获得更好的性能,如何使用它们)。系统架构(在
arch
目录下的任何内容)。该条是否设置了预取位?我发现这些函数可以在许多源代码中使用,但没有关于如何准确使用它们的详细信息。例如,表示它们可以作为ioread/write32的替代品,在io内存块上进行操作。还有其他方法吗?请编写部分代码,在其中尝试更改寄存器。根据我最初的问题,我使用了一个带有iowrites的for循环:for(I=0;I<512;I++){iowrite32((u32+++c,&privdata->registers[I]),如果我将其替换为:memcpy_toio(privdata->registers,buffer,2048);它没有任何作用。如果我还通过memcpy_fromio添加read,它会崩溃。请用变量定义编写代码,我不知道,您使用哪种类型。像这样写:u32缓冲区[512];void*\uu iomem私有数据;然后继续。另请参见,。虽然我对深入研究代码表示欢迎,但memcpy_fromio和memcpy_toio确实适合与PCIe设备一起工作。您知道如何使用iowrite32/ioread32提高单个32位读写的性能吗?应该有一些函数在内存块上运行。pci-e链路带宽高达2.5Gb,当前性能远低于100Mb/s。你不能。如果设备想要更快,它应该实现DMA。我们有一个E5-2600处理器,其中编程的I/O比以ntb_性能为基准的IOAT DMA快得多(约5GB/s,而不是约3GB/s)。这是作为一个内核模块实现的,在这个模块中,找出实际发生的事情是。。。卷入的
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;
 }