PCI/PCIE相关知识

PCI/e配置空间
PCI/PCIe的配置空间Configuration Space是一个与Memory空间和IO空间并列的独立的空间。PCI Configuration Space有256 Bytes,对于PCIe Configuration Space,扩展为4096 Bytes,PCIe是在PCI基础上发展的协议,并且在此基础之上进行了扩展,其扩展形式是通过一种称为Capability的寄存器块来完成的。

              

访问方式
IO方式

CPU提供了两组I/O寄存器用于访问配置空间:

1. 配置空间控制寄存器 CF8h-CFBh
2. 配置空间数据寄存器 CFCh-CFFh
传统方式,写IO端口CFCh和CF8h。只能访问PCI/PCIe设备的开始256个字节(PCI设备的配置空间本来就只有256个字节......):

// for PCI
address = BIT31 | ((Bus & 0xFF) << 16) | ((Dev & 0x1F) << 11) | ((Fun & 0x7) << 8) | (Reg & 0xfffffffc);//BIT31=0x80000000
 
// write cfg register
IoWrite8(0xcf8, address);
// read data register
data8  = IoRead8(0xcfc);
data16 = IoRead16(0xcfc);
data32 = IoRead32(0xcfc);
 Bit31代表enable bit。一定要置起来,否则不起作用。

MMIO方式
对于MMIO的访问,跟访问内存的方式一样,它从称为PCIEXBAR的基地址开始,有很大的一段空间,这个PCIEXBAR的值根据不同的平台可能不同,大致可能值有0xB0000000、0xC0000000等(飞腾用的就是0xB0000000)。

#define pcie_addr(m, b, d, f, o)        (m + ((b & 0xff) << 20) + ((d & 0x1f) << 15) + ((f & 0x7) << 12) + (o & 0xfffffffc)
#define mmio_read8(addr)            (*(volatile uint8 *)addr)
#define mmio_write8(addr, data8)    *(volatile uint8 *)addr = data8
#define mmio_read16(addr)           (*(volatile uint16 *)addr)
#define mmio_write16(addr, data16)  *(volatile uint16 *)addr = data16
#define mmio_read32(addr)           (*(volatile uint32 *)addr)
#define mmio_write32(addr, data32)  *(volatile uint32 *)addr = data32
配置寄存器组内保留了对PCI设备的基本特性进行详尽说明的可读信息,CPU读取这些信息后,就可以为PCI设备设定符合需要的配置内容,从而实现自动配置。这些可读信息包括:

Vendor ID :设备供应商编号,由PCI SIG国际组织分配。

Device ID :特定设备编号,由设备供应商分配。

Revision ID :设备的特定版本号,由设备供应商分配。

Class Code :设备的功能类别编号。

Header Type :指示Header 中从地址10H到3FH区域的内容格式,同时指示该设备是否为多功能设备。

扫描PCI设备的时候,我们可以直接通过Vendor ID与Device ID是否为0xffff来判断设备是否存在,如果是,则设备不存在,不过也有一种情况,国产并不完备,在硬件设计的时候,很有可能这个不存在的值并不是0xffff,也有可能是0才不存在:

//
  // Create PCI address map in terms of Bus, Device and Func
  //
  Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
 
  //
  // Read the Vendor ID register
  //
  Status = PciRootBridgeIo->Pci.Read (
                                  PciRootBridgeIo,
                                  EfiPciWidthUint32,
                                  Address,
                                  1,
                                  Pci
                                  );
 
  if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff && (Pci->Hdr).VendorId != 0) {
    //
    // Read the entire config header for the device
    //
    Status = PciRootBridgeIo->Pci.Read (
                                    PciRootBridgeIo,
                                    EfiPciWidthUint32,
                                    Address,
                                    sizeof (PCI_TYPE00) / sizeof (UINT32),
                                    Pci
                                    );
 
    return EFI_SUCCESS;
  }
 
 
这部分代码在PciEnumeratorSupport.c文件中有定义。
————————————————
版权声明:本文为CSDN博主「潇洒Anthony」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011397314/article/details/122452131

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值