pci设备的IO空间和地址空间如何区分

2510阅读 0评论2019-03-24 lelv123
分类:嵌入式

网上的Linux PCI驱动教程基本就没有有用的。扯半天PCI配置空间就完了。但是PCI配置空间是最容易访问的,只是内核启动时扫描PCI设备时比较重要。对于PCI驱动,更常用的是PCI设备的IO空间和内存空间。
以前只知道在PCI设备的配置空间中,BAR0-BAR5能够读取到PCI设备的IO空间或地址空间的基址,但是如何区分这个BAR代表的到底是IO空间还是内存地址空间呢?
在PCI网卡的示例程序(pci-skeleton.c)中:

  1. pio_start = pci_resource_start(pdev, 0);
  2.     pio_end = pci_resource_end(pdev, 0);
  3.     pio_flags = pci_resource_flags(pdev, 0);
  4.     pio_len = pci_resource_len(pdev, 0);

  5.     mmio_start = pci_resource_start(pdev, 1);
  6.     mmio_end = pci_resource_end(pdev, 1);
  7.     mmio_flags = pci_resource_flags(pdev, 1);
  8.     mmio_len = pci_resource_len(pdev, 1);

  9.     /* make sure PCI base addr 0 is PIO */
  10.     if (!(pio_flags & IORESOURCE_IO)) {
  11.     dev_err(&pdev->dev, “region #0 not a PIO resource, aborting\n”);
  12.     rc = -ENODEV;
  13.     goto err_out;
  14.     }

  15.     /* make sure PCI base addr 1 is MMIO */
  16.     if (!(mmio_flags & IORESOURCE_MEM)) {
  17.     dev_err(&pdev->dev, “region #1 not an MMIO resource, aborting\n”);
  18.     rc = -ENODEV;
  19.     goto err_out;
  20.     }

可以看到如果只写驱动程序的话,内核在扫描pci设备的时候早就把设备的BAR的属性识别好了。当然,到底有几个BAR,每个BAR到底是IO空间还是PCI地址空间可以直接问制作PCI设备的硬件工程师。
那么内核是如何获得这个flags呢?我跟了半天源码也没找到。只是知道,PCI总线规范规定直接读BAR,返回的是BAR空间基址。先写全1到BAR再 读,就能读取到BAR空间大小和属性。选最低的一位非0的,比如读到0xFFFFFF00,那个空间的大小就为0x100个Byte ,最后一位为0说明是地址区域,为1则这个BAR是IO空间。

此外,非常重要的一个概念是,BAR读取到的是PCI地址空间中的地址,不等同于CPU认识的内存地址。虽然在x86上如果没有开启IOMMU时,它们的值一般是相同的,但是对于其他构架的CPU如PowerPC就可以是不一样的。
所以正确的使用BAR空间的方法:

pciaddr=pci_resource_start(pdev,1);
if(pciaddr!=NULL)
{
ioremap(pciaddr,xx_SIZE);
}

错误的方法:

pci_read_config_dword(pdev,1,&pciaddr);
ioremap(pciaddr,xx_SIZE);

上一篇:任意位置访问pci设备
下一篇:不用sizeof如何判断系统位数