PCI bar 解析
创始人
2024-03-16 03:58:32
0

只要是接入系统的 pci 设备就需要和系统软件进行交互,设备和系统之间的交流主要包含以下两部分:

1,系统要能访问到设备的寄存器

用于控制设备行为,包括DMA,数据收发等;设备通过寄存器报告自身的状态,如是否工作正常,有没有什么错误;

2,设备和系统之间互相传输数据

系统定位设备寄存器的位置以及数据收发的位置。换句话说,设备内部的这些资源应该是可寻址的,能够被系统访问到进而完成一些读写操作。一种思路是设备出厂的时候,就固化自己片上存储空间对应在系统中的地址空间,比如对应到0xFE000000h ~ 0xFE000FFF(4KB),这段地址被该设备独占,对这段地址进行ioremap映射后进行访问就可以和该设备交互。可想而知这种方式可扩展性差,毕竟设备有很多,照这样分配地址,那估计系统有多少地址宽度都不够造的。

另外每个设备对于其所需要的地址空间类型(无论是IO映射还是MMIO映射)和大小有多种多样的需求,但是又不能自己配置,所以必须以一定方式提供信息(包括请求的地址空间类型和大小)给系统,从而让BIOS或操作系统内核来为其分配。这就引出了BAR,BAR指的是设备配置空间中的4个字节,针对一个设备来说,其有6个BAR地址(实际中所有的BAR并不会都使用,不使用的BAR必须由厂商硬编码为0),设备的每个BAR对应设备上的一段存储空间(或者寄存器空间),系统通过将系统地址写入BAR就建立了存储空间的卡上地址和系统地址空间的映射。

在硬件加电初始化时,BIOS固件统一检查了所有的PCI设备, 并统一为他们分配了一个和其他互不冲突的地址,让他们的驱动程序可以向这些地址映射他们的寄存器,这些地址被BIOS写进了各个设备的配置空间的BAR寄存器中,因为这个活动是一个PCI的标准的活动,所以自然写到各个设备的配置空间里而不是他们风格各异的控制寄存器空间里。当然只有BIOS可以访问配置空间。当操作系统 初始化时,他为每个PCI设备分配了pci_dev结构,并且把BIOS获得的并写到了配置空间中的地址读出来写到了pci_dev中的resource 字段中。这样以后我们在读这些地址就不需要在访问配置空间了,直接跟pci_dev要就可以了,我们这里的四个函数就是直接从pci_dev读出了相关数 据,代码在include/linux/pci.h中。定义如下:

        #define pci_resource_start(dev,bar) ((dev)->resource[(bar)].start)

        #define pci_resource_end(dev,bar) ((dev)->resource[(bar)].end)

在内核中pci_setup_device()函数完成了对单个pci 设备的设备和检测,并将获取的信息存取设备结构体中,用于后期具体设备的使用,在pci_setup_device->pci_read_bases-> __pci_read_base中会decode bar读取bios 中配好的系统地址,并写到创建的 resource中去,这里的地址都是物理的(即写到bar中的地址值),必须要在pci设备驱动的probe函数中调用ioremap 或者 pci_iomap 来将这些地址map成虚拟地址才可以使用,访问这个虚拟地址就可以直接操作pcie 设备上的寄存器(片上物理地址)了:

        base_addr = pci_resource_start(pci_dev, bar_idx); 

        size = pci_resource_len(pci_dev, bar_idx); 

        virt_addr = pci_iomap(vpri_dev->pci_dev, bar_idx, 0); 

pci_read_bases 作用:

1,pci_read_bases首先会依次遍历howmany PCI/PCIe设备的BAR配置;

2,struct resource *res = &dev->resource[pos]获取对应的PCI/PCIe设备对应的BAR的resource结构体,为后面的获取到资源信息做填充使用;

3,__pci_read_base用于具体的PCI/PCIe设备资源获取和解析;

4,如果rom是有效的,则会进一步去解析PCI_ROM_RESOURCE的扩展配置空间的资源信息( #6: expansion ROM resource );

__pci_read_base 的作用:

1,读取PCI/PCIe设备的BAR寄存器,解析PCI/PCIe设备的属性以及资源需求信息;

2,读取BAR寄存器的过程

 ·读BAR,保留原值;

 ·写0xFFFFFFFF到BAR;

 ·再读出来,解析出所需要的地址空间大小,记录在pci_dev->resource[ ]里;

       pci_dev->resource[ ].start = 0;

       pci_dev->resource[ ].end = size - 1;

 ·将原值写会BAR寄存器中;

 ·根据上一步读取出的l和sz去计算设备当前BAR所需要资源的基址和大小,通过pcibios_bus_to_resource配置到对应设备BAR的resource里面(设置resource.start);

涉及的代码如下:

    /* 读取BAR寄存器的过程 */

    pci_read_config_dword(dev, pos, &l); /* BARl(起始地址) */

    pci_write_config_dword(dev, pos, mask); /* BAR1 */

    pci_read_config_dword(dev, pos, &sz); /* BARsz(长度) */

    pci_write_config_dword(dev, pos, l); /* BAR l(恢复) */

相关内容

热门资讯

保存时出现了1个错误,导致这篇... 当保存文章时出现错误时,可以通过以下步骤解决问题:查看错误信息:查看错误提示信息可以帮助我们了解具体...
汇川伺服电机位置控制模式参数配... 1. 基本控制参数设置 1)设置位置控制模式   2)绝对值位置线性模...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
表格中数据未显示 当表格中的数据未显示时,可能是由于以下几个原因导致的:HTML代码问题:检查表格的HTML代码是否正...
本地主机上的图像未显示 问题描述:在本地主机上显示图像时,图像未能正常显示。解决方法:以下是一些可能的解决方法,具体取决于问...
表格列调整大小出现问题 问题描述:表格列调整大小出现问题,无法正常调整列宽。解决方法:检查表格的布局方式是否正确。确保表格使...
不一致的条件格式 要解决不一致的条件格式问题,可以按照以下步骤进行:确定条件格式的规则:首先,需要明确条件格式的规则是...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...