Pci中segment的实现-LoongArch

Pci中segment的实现

龙芯新一代处理器3C5000L, 从4W(64核)板卡开始,将支持双桥7A.


本章节就双桥7A,在UEFI添加segment的支持.

简介

PCI设备编号: Segment: Bus: DeviceNum: FunctionNum .

PCI Scaning

自PC在1981年被IBM发明以来,主板上都有扩展槽用于扩充计算机功能。现在最常见的扩展槽是PCIe插槽,实际上在你看不见的计算机主板芯片内部,各种硬件控制模块大部分也是以PCIe设备的形式挂载到了一颗或者几颗PCI/PCIe设备树上。固件和操作系统正是通过枚举设备树们才能发现绝大多数即插即用(PNP)设备的。

如何枚举?: PCI设备的扫描是基于深度优先搜索算法(DFS:Depth First Search),也就是说,下级分支最多的PCI桥将最先完成其子设备的扫描。下面我们以图片来具体说明,如何一步步完成PCI 设备扫描的?
在这里插入图片描述

  1. PciHost (主桥)扫描Bus0(与HOST主桥直接相连的PCI总线)上的设备: 首先先忽略Bus0上的D1,D2等不会挂接PCI桥的设备,主桥发现Bridge1后, 将Bridge1下面Bus定为Bus1,系统将初始化Bridge1的配置空间,并将该桥的PrimaryBus核SecondaryBus分别设置成0,1(即上下游总线),由于还无法确定Bridge1下挂载设备的具体情况,系统先暂时将SubordinateBus设为0xFF.
  2. 系统开始扫描Bus1, 发现Bridge2, 系统将Bridge2下面的PciBus定为Bus2, 并将PrimaryBus和SecondaryBus设置成1和2, SubordinateBus设置为0xFF.
  3. 系统开始扫描Bus2, 发现Bridge4, 系统将Bridge4下面的PciBus定为Bus3,并将PrimaryBus和SecondaryBus设置成2和3.
  4. 系统继续扫描Bus3, 发现总线上没有Bridge了,意味着该PCI总线上已经没有任何挂载下游总线了,因此Bridge4的SubordinateBus的值已经可以确定为3.
  5. 完成Bus3的扫描后,系统返回到了Bus2继续扫描, 发现Bus2下面已经没有其他Bridge了,此时Bridge2的SubordinateBus的值也已经可以确定为3.
  6. 完成Bus2的扫描后,系统返回到Bus1继续扫描, 会发现Bridge3,系统将Bridge3下面的PciBus定为Bus4, 并将Bridge4的PrimaryBus和SecondaryBus寄存器分别设置成1和4(即上游总线Bus1,下游总线Bus4).
  7. 继续扫描Bus4,发现下面没有任何Bridge了,意味着该PCI总线下已经没有挂载下游总线了, 因此Bridge3的SubordinateBus的值已经可以确定为4了.
  8. 完成Bus4的扫描后, 系统返回到Bus1继续扫描, 发现Bus1下面已经没有Bridge了, 此时Bridge1的SubordinateBus的值已经可以确定为4.
  9. 继续返回Bus0进行扫描, (如果Bus0上还有其它的Bridge,将重复上述的步骤进行扫描),至此本例中的PCI设备扫描已经完成.

标准PCI & X86 & LoongArch定义的PCI访问方式

1) UEFI标准PCI配置空间访问

UEFI下 PCI_SEGMENT_LIB_ADDRESS_STRUCTURE 该结构很好的定义了这个标准, 其中32-47bit定义了segment字段.

   19 typedef struct {                                                                                                                                                                                       
   20   UINT64  Register : 12;                                                                                                                                                                               
   21   UINT64  Function : 3;                                                                                                                                                                                
   22   UINT64  Device : 5;                                                                                                                                                                                  
   23   UINT64  Bus : 8;                                                                                                                                                                                     
   24   UINT64  Reserved1 : 4;                                                                                                                                                                               
   25   UINT64  Segment : 16;                                                                                                                                                                                
   26   UINT64  Reserved2 : 16;                                                                                                                                                                              
   27 } PCI_SEGMENT_LIB_ADDRESS_STRUCTURE; 

2) X86-PCI访问

在X86体系中, 我们可以通过两个寄存器来访问PCI的配置空间: CONFIG_ADDRESS & CONFIG_DATA: 即 0xCF8 & 0xCFC
UEFI下标准 X86 CF8: 在这里插入图片描述

3) LoongArch-PCI访问

龙芯PCI配置访问: 在这里插入图片描述

为何增添Segment?

  • 我们在扫描PCI的时候,或者说访问PCI设备的时候,我们只需知道这个PCIE设备的Bus & Device & Function & Offset 即可访问到对应的配置空间, 所以我们可以将双桥看成一个桥来分配资源(我们也这样做过,Segment=0), 但是访问也相应的受限了(两颗Chipset需一致).
    所以我们针对双桥的产品来说, 往往使用Segment来区别访问每一个桥的信息与分配资源更加独立,更加的规范, 并有效的防止桥片间差异化的影响, 比如我们假想可以使用下一代产品7A2000 + 7A1000的搭配方式.
    如需了解更多优点 & UEFI对Segment的支持 & Linux对Segment的支持详解对应Code.

Code Adding

InitializePciHostBridgeDxe

  • 初始化PCI主桥资源, 即7A1000的PCIE资源.
  1. InitializePciHostBridge -> PciHostBridgeGetRootBridges (这是个NULL函数需要我们自己实现, 是与平台强相关来初始化RootBridge信息的). 即我们需要初始化两个HostBridge的如下资源信息(桥0 Segment=0; 桥1 Segment=1 ):
 46 typedef struct {                                                                                                                                                                                        
 47   UINT32                   Segment;               ///< Segment number.                                                                                                                                  
 48   UINT64                   Supports;              ///< Supported attributes.                                                                                                                            
 49                                                   ///< Refer to EFI_PCI_ATTRIBUTE_xxx used by GetAttributes()                                                                                           
 50                                                   ///< and SetAttributes() in EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.                                                                                          
 51   UINT64                   Attributes;            ///< Initial attributes.                                                                                                                              
 52                                                   ///< Refer to EFI_PCI_ATTRIBUTE_xxx used by GetAttributes()                                                                                           
 53                                                   ///< and SetAttributes() in EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.                                                                                          
 54   BOOLEAN                  DmaAbove4G;            ///< DMA above 4GB memory.                                                                                                                            
 55                                                   ///< Set to TRUE when root bridge supports DMA above 4GB memory.                                                                                      
 56   BOOLEAN                  NoExtendedConfigSpace; ///< When FALSE, the root bridge supports                                                                                                             
 57                                                   ///< Extended (4096-byte) Configuration Space.                                                                                                        
 58                                                   ///< When TRUE, the root bridge supports                                                                                                              
 59                                                   ///< 256-byte Configuration Space only.                                                                                                               
 60   BOOLEAN                  ResourceAssigned;      ///< Resource assignment status of the root bridge.                                                                                                   
 61                                                   ///< Set to TRUE if Bus/IO/MMIO resources for root bridge have been assigned.                                                                         
 62   UINT64                   AllocationAttributes;  ///< Allocation attributes.                                                                                                                           
 63                                                   ///< Refer to EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM and                                                                                                
 64                                                   ///< EFI_PCI_HOST_BRIDGE_MEM64_DECODE used by GetAllocAttributes()                                                                                    
 65                                                   ///< in EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.                                                                                             
 66   PCI_ROOT_BRIDGE_APERTURE Bus;                   ///< Bus aperture which can be used by the root bridge.                                                                                               
 67   PCI_ROOT_BRIDGE_APERTURE Io;                    ///< IO aperture which can be used by the root bridge.                                                                                                
 68   PCI_ROOT_BRIDGE_APERTURE Mem;                   ///< MMIO aperture below 4GB which can be used by the root bridge.                                                                                    
 69   PCI_ROOT_BRIDGE_APERTURE MemAbove4G;            ///< MMIO aperture above 4GB which can be used by the root bridge.                                                                                    
 70   PCI_ROOT_BRIDGE_APERTURE PMem;                  ///< Prefetchable MMIO aperture below 4GB which can be used by the root bridge.                                                                       
 71   PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;           ///< Prefetchable MMIO aperture above 4GB which can be used by the root bridge.                                                                       
 72   EFI_DEVICE_PATH_PROTOCOL *DevicePath;           ///< Device path.                                                                                                                                     
 73 } PCI_ROOT_BRIDGE;  
  1. InitializePciHostBridge -> CreateRootBridge 创建 PCI_ROOT_BRIDGE_INSTANCE 实例, 即初始化Instance : PCI_ROOT_BRIDGE 是 PCI_ROOT_BRIDGE_INSTANCE的子集(父类).
 60 #define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('_', 'p', 'r', 'b')                                                                                                                                     
 61                                                                                                                                                                                                         
 62 typedef struct {                                                                                                                                                                                        
 63   UINT32                            Signature;                                                                                                                                                          
 64   LIST_ENTRY                        Link;                                                                                                                                                               
 65   EFI_HANDLE                        Handle;                                                                                                                                                             
 66   UINT64                            AllocationAttributes;                                                                                                                                               
 67   UINT64                            Attributes;                                                                                                                                                         
 68   UINT64                            Supports;                                                                                                                                                           
 69   PCI_RES_NODE                      ResAllocNode[TypeMax];                                                                                                                                              
 70   PCI_ROOT_BRIDGE_APERTURE          Bus;                                                                                                                                                                
 71   PCI_ROOT_BRIDGE_APERTURE          Io;                                                                                                                                                                 
 72   PCI_ROOT_BRIDGE_APERTURE          Mem;                                                                                                                                                                
 73   PCI_ROOT_BRIDGE_APERTURE          PMem;                                                                                                                                                               
 74   PCI_ROOT_BRIDGE_APERTURE          MemAbove4G;                                                                                                                                                         
 75   PCI_ROOT_BRIDGE_APERTURE          PMemAbove4G;                                                                                                                                                        
 76   BOOLEAN                           DmaAbove4G;                                                                                                                                                         
 77   BOOLEAN                           NoExtendedConfigSpace;                                                                                                                                              
 78   VOID                              *ConfigBuffer;                                                                                                                                                      
 79   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;                                                                                                                                                        
 80   CHAR16                            *DevicePathStr;                                                                                                                                                     
 81   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   RootBridgeIo;     //  PCI_ROOT_BRIDGE                                                                                                                                        
 82                                                                                                                                                                                                         
 83   BOOLEAN                           ResourceSubmitted;                                                                                                                                                  
 84   LIST_ENTRY                        Maps;                                                                                                                                                               
 85 } PCI_ROOT_BRIDGE_INSTANCE;      

gEfiPciRootBridgeIoProtocolGuid : 即&RootBridge->RootBridgeIo (注册一系列回调函数, 用于对This->Segment指向各自桥的PciBus:Device:Function:Reg访问(包含配置空间及MEM等空间访问方式)). 即底层的配置为上一层产生配置和产生配置服务.(具体针对Segment的访问修改看步骤4)

  1. ResourceAssigned(资源分配Flag) 控制 HostBridge->ResAlloc的注册:
    在初始化HostBridge时, 若已经分配Host资源将不再注册PciBus扫描时所需的gEfiPciHostBridgeResourceAllocationProtocolGuid.
    结尾必须注册的Protocol: gEfiDevicePathProtocolGuid & gEfiPciRootBridgeIoProtocolGuid.
  1. 注册配置空间与MEM&IO空间区分Segment的访问: RootBridge->RootBridgeIo.Pci.Read(RootBridgeIoPciRead)->RootBridgeIoPciAccess
 964 EFI_STATUS                                                                                                                                                                                                                                                        
 965 EFIAPI                                                                                                                                                                                                                                                            
 966 RootBridgeIoPciAccess (                                                                                                                                                                                                                                           
 967   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This,                                                                                                                                                                                                             
 968   IN     BOOLEAN                               Read,                                                                                                                                                                                                              
 969   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,                                                                                                                                                                                                             
 970   IN     UINT64                                Address,                                                                                                                                                                                                           
 971   IN     UINTN                                 Count,                                                                                                                                                                                                             
 972   IN OUT VOID                                  *Buffer                                                                                                                                                                                                            
 973   )                                                                                                                                                                                                                                                               
 974 {                                                                                                                                                                                                                                                                 
 975   EFI_STATUS                                   Status;                                                                                                                                                                                                            
 976   PCI_ROOT_BRIDGE_INSTANCE                     *RootBridge;                                                                                                                                                                                                       
 977   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS  PciAddress;                                                                                                                                                                                                        
 978   UINT8                                        *Uint8Buffer;                                                                                                                                                                                                      
 979   UINT8                                        InStride;                                                                                                                                                                                                          
 980   UINT8                                        OutStride;                                                                                                                                                                                                         
 981   UINTN                                        Size;                                                                                                                                                                                                              
 982                                                                                                                                                                                                                                                                   
 983   Status = RootBridgeIoCheckParameter (This, PciOperation, Width, Address, Count, Buffer);                                                                                                                                                                        
 984   if (EFI_ERROR (Status)) {                                                                                                                                                                                                                                       
 985     return Status;                                                                                                                                                                                                                                                
 986   }                                                                                                                                                                                                                                                               
 987                                                                                                                                                                                                                                                                   
 988   //                                                                                                                                                                                                                                                              
 989   // Read Pci configuration space                                                                                                                                                                                                                                 
 990   //                                                                                                                                                                                                                                                              
 991   RootBridge = ROOT_BRIDGE_FROM_THIS (This);                                                                                                                                                                                                                      
 992   CopyMem (&PciAddress, &Address, sizeof (PciAddress));                                                                                                                                                                                                           
 993                                                                                                                                                                                                                                                                   
 994   if (PciAddress.ExtendedRegister == 0) {                                                                                                                                                                                                                         
 995     PciAddress.ExtendedRegister = PciAddress.Register;                                                                                                                                                                                                            
 996   }                                                                                                                                                                                                                                                               
 997                                                                                                                                                                                                                                                                   
 998   Address = PCI_SEGMENT_LIB_ADDRESS (                                                                                                                                                                                                                             
 999               RootBridge->RootBridgeIo.SegmentNumber,                                                                                                                                                                                                             
1000               PciAddress.Bus,                                                                                                                                                                                                                                     
1001               PciAddress.Device,                                                                                                                                                                                                                                  
1002               PciAddress.Function,                                                                                                                                                                                                                                
1003               PciAddress.ExtendedRegister                                                                                                                                                                                                                         
1004               );                                                                                                                                                                                                                                                  
1005                                                                                                                                                                                                                                                                   
1006   //                                                                                                                                                                                                                                                              
1007   // Select loop based on the width of the transfer                                                                                                                                                                                                               
1008   //                                                                                                                                                                                                                                                              
1009   InStride  = mInStride[Width];                                                                                                                                                                                                                                   
1010   OutStride = mOutStride[Width];                                                                                                                                                                                                                                  
1011   Size      = (UINTN) (1 << (Width & 0x03));                                                                                                                                                                                                                      
1012   for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {                                                                                                                                                                 
1013     if (Read) {                                                                                                                                                                                                                                                   
1014       PciSegmentReadBuffer (Address, Size, Uint8Buffer);                                                                                                                                                                                                          
1015     } else {                                                                                                                                                                                                                                                      
1016       PciSegmentWriteBuffer (Address, Size, Uint8Buffer);                                                                                                                                                                                                         
1017     }                                                                                                                                                                                                                                                             
1018   }                                                                                                                                                                                                                                                               
1019                                                                                                                                                                                                                                                                   
1020   return EFI_SUCCESS;                                                                                                                                                                                                                                             
1021 }                    

梳理代码最终调用PciSegmentReadBuffer(这个Address是标准PCI访问地址) -> PciRead(需要我们自己实现来解析包含Segment的标准PCI地址来转换成我们架构的地址空间进行访问) 先借助Cf8参考修改LoongArch转换如下:

 124 UINT8                                                                                                                                                                                                                                                              
 125 EFIAPI                                                                                                                                                                                                                                                             
 126 PciCf8Read8 (                                                                                                                                                                                                                                                      
 127   IN      UINTN                     Address                                                                                                                                                                                                                        
 128   )                                                                                                                                                                                                                                                                
 129 {                                                                                                                                                                                                                                                                  
 130   UINTN  Tmp;                                                                                                                                                                                                                                                      
 131   UINT32 Val;                                                                                                                                                                                                                                                      
 132   UINT32 Result;                                                                                                                                                                                                                                                   
 133   UINT32 ValRaw;                                                                                                                                                                                                                                                   
 134   UINT64 HtConfType0Addr;                                                                                                                                                                                                                                          
 135   UINT64 HtConfType1Addr;                                                                                                                                                                                                                                          
 136   UINT64 BusNum;                                                                                                                                                                                                                                                   
 137                                                                                                                                                                                                                                                                    
 138   HtConfType0Addr = HT_CONF_TYPE0_ADDR;                                                                                                                                                                                                                            
 139   HtConfType1Addr = HT_CONF_TYPE1_ADDR;                                                                                                                                                                                                                            
 140   if (((Address >> 32) & 0xffff) == 1) {     // Address >> 32 is Segment , LoongArch's chipset1 on Node5                                                                                                                                                                                                        
 141     HtConfType0Addr |= (NODE5 << NODE_OFFSET);                                                                                                                                                                                                                     
 142     HtConfType1Addr |= (NODE5 << NODE_OFFSET);                                                                                                                                                                                                                     
 143   }                                                                                                                                                                                                                                                                
 144   Address &= 0xffffffff;                                                                                                                                                                                                                                           
 145                                                                                                                                                                                                                                                                    
 146                                                                                                                                                                                                                                                                    
 147   Tmp     = Address & 0xff;                                                                                                                                                                                                                                        
 148   Address &= ~0xff;                                                                                                                                                                                                                                                
 149   Address >>= 4;                                                                                                                                                                                                                                                   
 150   Address |= Tmp;                                                                                                                                                                                                                                                  
 151   Result  = 0;                                                                                                                                                                                                                                                     
 152       ...                

同理MemRead&IoRead等回调函数都是可以通过 RootBridge->RootBridgeIo.SegmentNumber 来区分访问的Chipset 以此来访问不同桥的地址空间, 简贴代码如下:

  661 EFI_STATUS                                                                                                                                                                                                                                                        
  662 EFIAPI                                                                                                                                                                                                                                                            
  663 RootBridgeIoMemRead (                                                                                                                                                                                                                                             
  664   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,                                                                                                                                                                                                            
  665   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,                                                                                                                                                                                                            
  666   IN     UINT64                                 Address,                                                                                                                                                                                                          
  667   IN     UINTN                                  Count,                                                                                                                                                                                                            
  668   OUT    VOID                                   *Buffer                                                                                                                                                                                                           
  669   )                                                                                                                                                                                                                                                               
  670 {                                                                                                                                                                                                                                                                 
  671   EFI_STATUS                             Status;                                                                                                                                                                                                                  
  672   UINT64                                 Addr;                                                                                                                                                                                                                    
  673   PCI_ROOT_BRIDGE_INSTANCE               *RootBridge;                                                                                                                                                                                                             
  674                                                                                                                                                                                                                                                                   
  675   Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,                                                                                                                                                                                        
  676                                        Count, Buffer);                                                                                                                                                                                                            
  677   RootBridge = ROOT_BRIDGE_FROM_THIS (This);                                                                                                                                                                                                                      
  678                                                                                                                                                                                                                                                                   
  679  if (EFI_ERROR (Status)) {                                                                                                                                                                                                                                        
  680     return Status;                                                                                                                                                                                                                                                
  681   }                                                                                                                                                                                                                                                               
  682                                                                                                                                                                                                                                                                   
  683   Addr = (Address & ADDR_MASK_32BIT) | PCI_UNCACHE_ADDR_BASE;                                                                                                                                                                                                     
  684   if (RootBridge->RootBridgeIo.SegmentNumber == 1) {     //Chipset 1 on Node5                                                                                                                                                                                                       
  685     Addr |= 0x500000000000ULL;                                                                                                                                                                                                                                    
  686   }                                                                                                                                                                                                                                                               
  687                                                                                                                                                                                                                                                                   
  688   return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Addr, Count, Buffer);                                                                                                                                                                       
  689 }                                    

我们借助了Cf8的库进行了修改配置空间的访问梳理, 我们真正的Code将脱离Cf8,写我们自己PciCfgAccess.

  • 关于我们为PciBus注册的Protocol如何被使用,就不详细展开了,它是标准的PCI深度优先扫描, 最底层的访问即是回调的这一章节的地址访问, 而扫描时如何详细分配资源还需大家一同学习了解.

总结

使用Segment来区分双桥ID, 可以更好的维护与清晰代码结构, 创建的两个RootBridge可以彼此分离, 各自维护各自不同类的Instance.Ops, 并且EDK2 Core内代码对Segment有更好的功能延伸, 减少后期成本.

知识小提示

PCI接口带宽:
在这里插入图片描述

关于PCIE-Spec详细手册请点击 PCIE-SPEC手册, 包含配置空间及Capability寄存器.

  • 临近7.1百年: 祝好!
  • 虚心使人进步,骄傲使人落后,我们应当永远记住这个真理~
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来杯清咖_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值