PCIE Configuration Space

空闲看看PCIE 5.0 spec, 照本宣科简单记录一下。

先上框架图,部件互连是点对点链接(point-to-point link),由Root Complex(RC), Endpoints(I/O devices), Switch, PCI Express to PCI/PCI-X Bridge组成。PCI Express Link由两个差分信号对组成,发送对和接受对(a Transmit pair and a Receive pair).

 

PCI Express配置模型支持两种Configuration Space访问机制:

1.  PCI-compatible Configuration Access Mechanism(CAM)

2.  PCI Express Enhanced Configuration Access Mechanism(ECAM)

为了保持与PCI软件配置机制的兼容性,所有PCIE设备都具有PCI兼容的Configuration Space. 与PCI允许的256字节相比,PCIE将每个Function的Configuration Space扩展到了4096字节。如图所示,PCIE Configuration Space分为PCI-compatible region和PCI Express Extended Configuration Space. PCI-compatible region 由Configuration Space的前256(0 ~ FFh)个字节组成,PCI Express Extended Configuration Space由剩余空间(100 ~ FFFh)组成。前者可以通过CAM和ECAM两种方式访问,而后者只能通过ECAM访问。

ECAM机制使用 a flat memory-mapped address space来访问设备配置空间的寄存器。memory address space与PCI Express Configuration Space address的映射规则如下图所示。

 edk2 codebase里边定义了将Bus、Device、Function、Register转换成映射的memory address的宏。

/**
  Macro that converts PCI Bus, PCI Device, PCI Function and PCI Register to an
  ECAM (Enhanced Configuration Access Mechanism) address. The unused upper bits
  of Bus, Device, Function and Register are stripped prior to the generation of
  the address.

  @param  Bus       PCI Bus number. Range 0..255.
  @param  Device    PCI Device number. Range 0..31.
  @param  Function  PCI Function number. Range 0..7.
  @param  Register  PCI Register number. Range 0..4095.

  @return The encode ECAM address.

**/
#define PCI_ECAM_ADDRESS(Bus,Device,Function,Offset) \
  (((Offset) & 0xfff) | (((Function) & 0x07) << 12) | (((Device) & 0x1f) << 15) | (((Bus) & 0xff) << 20))

映射到Configuration Space的memory address范围的大小和基址由host bridge和firmware确定。

下面部分讲PCI-Compatible Configuration Registers,首先是Type 0/1 Common Configuration Space,如图

Vendor ID Register (Offset 00h)

Vendor ID是HwInit的,用于识别设备制造商,ID一般由PCI_SIG统一分配,确保唯一性。当值为FFFFh时表示设备不存在,在edk2里边扫描PCI总线时就是以此为根据来判断Device是否存在,部分代码如下(ScanForRootBridges)

    //
    // Scan all the PCI devices on the primary bus of the PCI root bridge
    //
    for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) {

      for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {

        //
        // Compute the PCI configuration address of the PCI device to probe
        //
        Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0);

        //
        // Read the Vendor ID from the PCI Configuration Header
        //
        if (PciRead16 (Address) == MAX_UINT16) {
          if (Function == 0) {
            //
            // If the PCI Configuration Read fails, or a PCI device does not
            // exist, then skip this entire PCI device
            //
            break;
          } else {
            //
            // If PCI function != 0, VendorId == 0xFFFF, we continue to search
            // PCI function.
            //
            continue;
          }
        }

     ...

 

Device ID Register (Offset 02h)

Device ID由Vendor自己分配,也是HwInit.通常Device ID与Vendor ID/Revision ID被用作判断加载哪支驱动的依据。

 

Command Register (Offset 04h)

Command Register属于控制寄存器,一些I/O或Memory Space的访问需要先在这里enable对应的bit才能使用。

 

Status Register (Offset 06h)

状态寄存器,如图

 

Revision ID Register (Offset 08h)

前面Device ID有说,用于判断驱动加载。

 

Class Code Register (Offset 09h)

简单说Class Code主要用于区分Function的通用功能,从高位至低位依次是Base Class Code、Sub-Class Code和Programming Interface, 各占一个字节。

比如,RAID controller对应的Class Code为 01h/04h/00h.

 

Cache Line Size Register (Offset 0Ch)和Latency Timer Register (Offset 0Dh)不适用于PCI Express.

 

Header Type Register (Offset 0Eh)

Header这里特指Configuration Space的0h ~ 3Fh部分,Type指Type 0 或 Type 1. 具体实现方式如下图。

//
// the definition of Header Type
//
#define HEADER_TYPE_DEVICE            0x00
#define HEADER_TYPE_PCI_TO_PCI_BRIDGE 0x01
#define HEADER_TYPE_CARDBUS_BRIDGE    0x02
#define HEADER_TYPE_MULTI_FUNCTION    0x80

 

BIST Register (Offset 0Fh)

Built In Self Test, 用于BIST的控制和状态检查,00h表示不支持BIST. 当调用BIST时不影响PCI Express link的正常操作。

 

Capabilities Pointer (Offset 34h)

简单说就是指向一个capability list. 因为所有PCI Express Functions都需要实现PCI Power Management Capability和PCI Express Capability structure,而这些structures必定包含在capability list中,该寄存器指向list中的第一个元素,list以00h结束。

(PCIE spec这里讲得比较简略,建议看PCI 3.0 spec)

 

Interrupt Line Register (Offset 3Ch)

The Interrupt Line register communicates interrupt line routing information.

 

Interrupt Pin Register (Offset 3Dh)

用于标识legacy interrupt message(s), 有效值为01h/02h/03h/04h, 对应INTA/INTB/INTC/INTD. 00h表示不支持。单Function设备必须是INTA.

 

下面是Type 0 Configuration Space Header

Base Address Registers (Offset 10h - 24h)

在将计算机引导至操作系统之前,系统软件必须构建一致的地址映射(address map). 这意味着必须确定系统中有多少内存,以及系统中的Functions需要多少地址空间。 确定此信息后,系统软件可以将Functions映射到合理的位置,然后继续系统引导。 为了以与设备无关的方式进行此映射,将此映射的基址寄存器(Base Address Registers )放置在配置空间的预定义标头部分中。

所有基址寄存器(Base Address Registers )中的bit 0是只读的,用于确定该寄存器是映射到Memory还是I / O Space. 映射到Memory Space的基址寄存器必须在bit 0中返回0b, 如图。Memory Type位00h表示32位地址,10h表示64位地址。64位地址则占用两个连续的32位基址寄存器(Base Address Registers ).

映射到I / O Space的基址寄存器必须在bit 0中返回1b, 如图。I/O地址通常是32位,高16位设0.

上电时软件可以通过将全1的值写入寄存器然后读回该值来确定功能所需的地址空间。Functions将在所有无关地址位中返回0, 有效地指定所需的地址空间。未实现的基址寄存器被硬接线为零。edk2里边就是根据这个来确定Bar是否存在,代码如下。

/**
  Check whether the bar is existed or not.

  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
  @param Offset            The offset.
  @param BarLengthValue    The bar length value returned.
  @param OriginalBarValue  The original bar value returned.

  @retval EFI_NOT_FOUND    The bar doesn't exist.
  @retval EFI_SUCCESS      The bar exist.

**/
EFI_STATUS
BarExisted (
  IN  PCI_IO_DEVICE *PciIoDevice,
  IN  UINTN         Offset,
  OUT UINT32        *BarLengthValue,
  OUT UINT32        *OriginalBarValue
  )
{
  EFI_PCI_IO_PROTOCOL *PciIo;
  UINT32              OriginalValue;
  UINT32              Value;
  EFI_TPL             OldTpl;

  PciIo = &PciIoDevice->PciIo;

  //
  // Preserve the original value
  //
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);

  //
  // Raise TPL to high level to disable timer interrupt while the BAR is probed
  //
  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);

  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);

  //
  // Write back the original value
  //
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);

  //
  // Restore TPL to its original level
  //
  gBS->RestoreTPL (OldTpl);

  if (BarLengthValue != NULL) {
    *BarLengthValue = Value;
  }

  if (OriginalBarValue != NULL) {
    *OriginalBarValue = OriginalValue;
  }

  if (Value == 0) {
    return EFI_NOT_FOUND;
  } else {
    return EFI_SUCCESS;
  }
}

 

Cardbus CIS Pointer Register (Offset 28h)不适用于PCI Express.

 

Subsystem Vendor ID Register/Subsystem ID Register (Offset 2Ch/2Eh)

Subsystem Vendor ID Register/Subsystem ID用于唯一标识PCI Express组件所在的适配器或子系统。 它们为供应商提供了一种机制,使它们的产品彼此区分开,即使这些组件上可能具有相同的PCI Express组件(因此也具有相同的Vendor ID和Device ID).Subsystem Vendor ID同样也由PCI-SIG分配。

 

Expansion ROM Base Address Register (Offset 30h)

某些Functions,尤其是打算用于add-in cards的那些,需要本地EPROMs作为Expansion ROM. 定义该寄存器以处理此Expansion ROM的基地址和大小信息。Functions请求的地址空间的大小不得大于16 MB. edk2中获取Expansion ROM信息的代码如下。

/**
  Get Pci device's oprom information.

  @param PciIoDevice    Input Pci device instance.
                        Output Pci device instance with updated OptionRom size.

  @retval EFI_NOT_FOUND Pci device has not Option Rom.
  @retval EFI_SUCCESS   Pci device has Option Rom.

**/
EFI_STATUS
GetOpRomInfo (
  IN OUT PCI_IO_DEVICE    *PciIoDevice
  )
{
  UINT8                           RomBarIndex;
  UINT32                          AllOnes;
  UINT64                          Address;
  EFI_STATUS                      Status;
  UINT8                           Bus;
  UINT8                           Device;
  UINT8                           Function;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;

  Bus             = PciIoDevice->BusNumber;
  Device          = PciIoDevice->DeviceNumber;
  Function        = PciIoDevice->FunctionNumber;

  PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;

  //
  // Offset is 0x30 if is not ppb
  //

  //
  // 0x30
  //
  RomBarIndex = PCI_EXPANSION_ROM_BASE;

  if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
    //
    // If is ppb, 0x38
    //
    RomBarIndex = PCI_BRIDGE_ROMBAR;
  }
  //
  // The bit0 is 0 to prevent the enabling of the Rom address decoder
  //
  AllOnes = 0xfffffffe;
  Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);

  Status = PciRootBridgeIo->Pci.Write (
                                  PciRootBridgeIo,
                                  EfiPciWidthUint32,
                                  Address,
                                  1,
                                  &AllOnes
                                  );
  if (EFI_ERROR (Status)) {
    return EFI_NOT_FOUND;
  }

  //
  // Read back
  //
  Status = PciRootBridgeIo->Pci.Read(
                                  PciRootBridgeIo,
                                  EfiPciWidthUint32,
                                  Address,
                                  1,
                                  &AllOnes
                                  );
  if (EFI_ERROR (Status)) {
    return EFI_NOT_FOUND;
  }

  //
  // Bits [1, 10] are reserved
  //
  AllOnes &= 0xFFFFF800;
  if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
    return EFI_NOT_FOUND;
  }

  PciIoDevice->RomSize = (~AllOnes) + 1;
  return EFI_SUCCESS;
}

 

Min_Gnt Register/Max_Lat Register (Offset 3Eh/3Fh)

不适用于PCI Express.

 

下边是Type 1 Configuration Space Header

Type 1 Base Address Registers (Offset 10h-14h)

与Type 0相同。

 

Primary Bus Number Register (Offset 18h)

The Primary Bus Number register is used to record the Bus Number of the logical PCI bus segment to which the primary interface of the bridge is connected. 通常来说就是指记录与Bridge连接的上游的Bus Number.

 

Secondary Bus Number Register (Offset 19h)

Secondary Bus Number Register 记录与Bridge连接的下游的Bus Number.

 

Subordinate Bus Number Register (Offset 1Ah)

Subordinate Bus Number记录Bridge下方编号最大的Bus Number.

 

Secondary Latency Timer (Offset 1Bh)不适用于PCI Express.

 

I/O Base/I/O Limit Registers(Offset 1Ch/1Dh)

I/O Base/I/O Limit Registers是可选的,它们定义一个地址范围,Bridge使用该地址范围来确定何时将I / O事务从一个接口转发到另一个接口。

如果Bridge实现了I / O地址范围,则I/O Base/I/O Limit Registers的高4位都是可写的,并且对应于地址位Address [15:12]. 出于地址解码的目的,Bridge假定I / O base address(未在I/O Base Register中实现)的低12位地址位Address [11:0]为零。 类似地,Bridge假定I / O limit address(未在I/O Limit Register中实现)的低12地址位Address [11:0]为FFFh. 因此,定义的I / O地址范围的底部将与4 KB边界对齐,而定义的I / O地址范围的顶部将比4 KB边界小1.

I/O Base/I/O Limit Registers的低4位是只读的,如图所示。当Bits 3:0为1h时,32位地址值的高16位放在I/O Base Upper 16 Bits/I/O Limit Upper 16 Bits Registers (Offset 30h/32h).

 

Secondary Status Register (Offset 1Eh)

 

Memory Base Register/Memory Limit Register(Offset 20h/22h)

Memory Base Register/Memory Limit Register定义了内存映射的地址范围,bridge使用该地址范围来确定何时将内存事务从一个接口转发到另一个接口。

Memory Base Register/Memory Limit Register的高12位都是读/写的,它们对应于32位地址的高12地址位Address [31:20]. 出于地址解码的目的,bridge假定memory base address(未在Memory Base Register中实现)的低20地址位Address [19:0]为零。 类似地,bridge假定memory limit address(未在Memory Limit Register中实现)的低20地址位Address [19:0]为F FFFFh. 因此,定义的内存地址范围的底部将与1 MB边界对齐,而定义的内存地址范围的顶部将比1 MB边界小1.

Memory Base Register/Memory Limit Register的低4位只读,返回为0.

 

Prefetchable Memory Base/Prefetchable Memory Limit Registers (Offset 24h/26h)

Prefetchable Memory Base/Prefetchable Memory Limit Registers必须指示支持64位地址。 它们定义了一个可预取的内存地址范围,bridge使用该范围来确定何时将内存事务从一个接口转发到另一个接口。

如果bridge实现了可预取的内存地址范围,则将对寄存器的高12位进行读/写操作,并与32位地址的高12位地址Address [31:20]相对应。 出于地址解码的目的,bridge假定prefetchable memory base address(未在Prefetchable Memory Base Register中实现)的低20地址位Address [19:0]为零。 类似地,bridge假定prefetchable memory limit address(未在Prefetchable Memory Limit Registers中实现)的低20地址位Address [19:0]为F FFFFh. 因此,定义的可预取内存地址范围的底部将与1 MB边界对齐,并且定义的内存地址范围的顶部将比1 MB边界小1.

低4位是只读的,00h表示仅支持32位地址,01h表示支持64位地址,并且高32位地址保存在Prefetchable Base Upper 32 Bits/Prefetchable Limit Upper 32 Bits Registers.

 

Prefetchable Base Upper 32 Bits/Prefetchable Limit Upper 32 Bits Registers (Offset 28h/2Ch)

Prefetchable Memory Base/Prefetchable Memory Limit Registers的扩充。

 

I/O Base Upper 16 Bits/I/O Limit Upper 16 Bits Registers (Offset 30h/32h)

I/O Base/I/O Limit Registers的扩充。

 

Expansion ROM Base Address Register (Offset 38h)

与Type 0相同。

 

Bridge Control Register (Offset 3Eh)

Command Register的扩展。需要注意的是Command Register主要作用于primary interface, 而Bridge Control Register主要针对secondary interface.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值