Linux kernel 如何通过内存映射从Linux内核空间访问PCI内存(内核3.14)

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

我正在寻找一种无需使用DMA和IO映射即可访问PCI设备(显式BAR2和BAR3)内存空间的方法。我读过很多文档,但我从来没有看过流程图或一步一步的操作方法。所以我所有的尝试都没有成功

以下是
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()
    结合使用。我建议您也看看