Linux kernel 如何通过内存映射从Linux内核空间访问PCI内存(内核3.14)
我正在寻找一种无需使用DMA和IO映射即可访问PCI设备(显式BAR2和BAR3)内存空间的方法。我读过很多文档,但我从来没有看过流程图或一步一步的操作方法。所以我所有的尝试都没有成功 以下是Linux kernel 如何通过内存映射从Linux内核空间访问PCI内存(内核3.14),linux-kernel,kernel,kernel-module,pci,Linux Kernel,Kernel,Kernel Module,Pci,我正在寻找一种无需使用DMA和IO映射即可访问PCI设备(显式BAR2和BAR3)内存空间的方法。我读过很多文档,但我从来没有看过流程图或一步一步的操作方法。所以我所有的尝试都没有成功 以下是pci_probe我实际尝试的步骤: data=kzalloc(sizeof(*data),GFP_内核) pci设置数据(pdev,数据) pci_启用_设备(pdev) 现在的问题是,使用writeb或readb访问BAR2+offset的正确地址是什么?或者是否有另一个从该空间读取/写入的函数 PS
pci_probe
我实际尝试的步骤:
data=kzalloc(sizeof(*data),GFP_内核)代码>
pci设置数据(pdev,数据)代码>
pci_启用_设备(pdev)代码>
writeb
或readb
访问BAR2+offset
的正确地址是什么?或者是否有另一个从该空间读取/写入的函数
PS:关于iomap的一个类似问题也被发布了。经过大量研究,我找到了一种方法,可以读写PCI
BAR2
。似乎ioremap
、pci\u ioremap\u bar
或memremap()
(内核4.3+)允许CPU缓存在pci设备和内核空间内存之间传输的数据。这会导致数据损坏。但我不知道它最终是从哪里来的
解决此问题的方法使用来自io.h
的ioremap\u nocache
。下面的代码显示了PCI probe函数
static int
_pci_probe ( struct pci_dev *pdev,
const struct pci_device_id *ent )
{
int ret = 0;
int i;
unsigned long *pbas2addr;
u8 buf8;
u8 *mem8;
buf8 = 0xF0;
// put mem8 to the heap and initialize them with zeros
mem8 = kcalloc((0x020000),sizeof(u8), GFP_KERNEL);
// enabling the device
ret = pci_enable_device(pdev);
if( ret )
{
printk(KERN_ERR "Failed to enable PCI device.\n");
goto no_enable;
}
// take ownership of pci related regions
pci_request_regions(pdev, "expdev");
// checking if PCI-device reachable by checking that BAR0 is defined and
// memory mapped
if( !(pci_resource_flags(pdev,0) & IORESOURCE_MEM) )
{
printk(KERN_ERR "Incorrect BAR configuration.\n");
ret = -ENODEV;
goto bad_bar;
}
// remap BAR2 avoiding the use of CPU cache
pbas2addr = ioremap_nocache(pci_resource_start(pdev,2),
pci_resource_len(pdev,2));
printk(KERN_INFO "BAR2 Addr: %p\n",pbas2addr);
printk(KERN_INFO "BAR2 len: %x\n",(int)pci_resource_len(pdev,2));
// write something to BAR2
buf8 = 0xF0;
for ( i = 0x000000; i<0x020000; i++ )
{
*((u8*)pbas2addr+i) = buf8; // it's important to cast the pointer
}
// read back
buf8 = 0;
for ( i = 0x000000; i<0x020000; i++ )
{
mem8[i] = *((u8*)pbas2addr+i);
}
return 0;
bad_bar:
pci_disable_device(pdev);
no_enable:
return ret;
}
static int
_pci_探测器(结构pci_开发*pdev,
const struct pci_device_id*ent)
{
int-ret=0;
int i;
无符号长*pbas2addr;
u8 buf8;
u8*mem8;
buf8=0xF0;
//将mem8放到堆中,并用零初始化它们
mem8=kcaloc((0x020000),sizeof(u8),GFP_内核);
//启用设备
ret=pci_启用_设备(pdev);
如果(ret)
{
printk(KERN_ERR“无法启用PCI设备。\n”);
转到no_enable;
}
//拥有pci相关区域的所有权
pci请求区域(pdev,expdev);
//通过检查BAR0是否已定义且
//内存映射
if(!(pci_资源_标志(pdev,0)和IORESOURCE_MEM))
{
printk(KERN_ERR“不正确的条配置。\n”);
ret=-ENODEV;
去巴德酒吧;
}
//重新映射BAR2,避免使用CPU缓存
pbas2addr=ioremap\u nocache(pci\u资源\u启动(pdev,2),
pci_资源_len(pdev,2));
printk(KERN_INFO“BAR2地址:%p\n”,pbas2addr);
printk(KERN_INFO“BAR2 len:%x\n”,(int)pci_资源(pdev,2));
//写点东西给BAR2
buf8=0xF0;
对于(i=0x000000;i一种可移植的方法是使用pci_iomap()函数。它自动确定条形图的类型,并与MMIO和PIO一起工作。您应该使用ioread*()/iowrite*()而不是writeb()/readb()不映射就无法访问任何内容。您试图解决的实际问题是什么?目标是访问PCI设备上的内存空间以实现快速数据交换。我知道我需要映射地址。但我了解到有两种不同类型的映射。IO映射到IO空间和内存映射到内存空间。我知道通过io映射来访问mem空间的方法,但现在我正在寻找通过内存映射来实现这一点的更快方法。就我所知,在x86(-64)上,您只能通过I/O映射来映射I/O条,通过内存映射来映射内存条。其他架构不一定有区别,它们的实现可能会使用内存映射来实现I/O范围(例如PPC)。好的。那么如何通过内存映射来映射内存条呢?pcim\u iomap\u regions()
是您的帮助者。如果您询问通过PCI总线连接的内存,那么您可能需要将PCI\u资源*()
与memremap()
结合使用。我建议您也看看