拓扑建立
拓扑建立的主要目的是生成SlotId到PortId的关系,再将其填写到对应的PcieAddrInfo中。其中PortId对应的是Serdes中配置的Device表中的值,SlotId则根据PSR和IEU/EXU/SEU中相应下行接口共同决定,拓扑建立匹配如下图。
之所以需要拓扑建立,是因为IEU/EXU/SEU等组件有多种连接到BCU上的插法,而PCIe设备槽位的PortId和SlotId是和插法有关的,BMC需要根据实际的插法计算每个槽位的PortId和SlotId。
拓扑建立的结果会被bios组件用以生成丝印,在较新版本的BMC中,丝印文件为一键收集中/dump_info/AppDump/bios/1/silkconfig.json,在旧版本中需要在BMC的文件系统中找,路径为/data/opt/bmc/conf/bios/silkconfig/json。
打开丝印文件后,关注以下内容:
"PCIeSilk": [{
"RootPortDeviceId": 4,
"SocketId": 0,
"Segment": 0,
"SlotId": 1,
"Slik": "",
"DeviceType": "OCP"
}, {
"RootPortDeviceId": 20,
"SocketId": 1,
"Segment": 0,
"SlotId": 47,
"Slik": "",
"DeviceType": "NVME"
}, {
"RootPortDeviceId": 8,
"SocketId": 0,
"Segment": 0,
"SlotId": 2,
"Slik": "",
"DeviceType": "PCIe"
}]以上展示了三种设备的丝印,分别是OCP卡,NVME硬盘和PCIe卡,这三种设备的加载依赖带内host的上报。这三种类型的槽位是分开计算的,一般来说,
丝印文件是根据PcieAddrInfo资源树对象生成的,对应关系如下:
| PcieAddrInfo中属性 | 丝印文件中的属性 | 说明 |
|---|---|---|
| PortID | RootPortDeviceId | 注意二者名称不同 |
| Segment | Segment | |
| SlotID | SlotId | 注意大小写 |
| SocketID | SocketId | 注意大小写 |
| ComponentType | DeviceType | 二者不是直接对应,ComponentType为整数,DeviceType为字符串,其中83对应"OCP",2对应"NVME",8对应"PCIe",此处只列出常见值,完整定义见BCU配置指南。 |
1. 硬件提供表格示意
| CHIP | DIE | Macro | Lane | Core编号 | CHIP0 | CHIP1 | ||
| PortId | RootBDF | PortId | RootBDF | |||||
| XXX CHIP | NA | M0 | X4 | Core0 | Port0 | 01:00.0 | Port20 | 40:00.0 |
| Port1 | 01:01.0 | Port21 | 40:01.0 | |||||
| M1 | X4 | Port2 | 01:02.0 | Port22 | 40:02.0 | |||
| Port3 | 01:01.0 | Port23 | 40:03.0 | |||||
2. 拓扑建立组件介绍
拓扑建立主要涉及四种组件,IEU、EXU、SEU和BCU,其中前三种都提供PcieAddrInfo对象,BCU提供Serdes对象。
IEU是Riser卡,负责将BCU上的UBC、UBCDD资源转换为PCIe槽位。
EXU是扩展版,负责将BCU上的UBC、UBCDD资源转换为BMC卡、FlexIO的接口。
SEU是硬盘背板,负责将BCU上的UBC、UBCDD资源或RAID卡出的miniSAS资源转换为NVME或SATA槽位。
BCU是基础板,负责提供UBC、UBCDD资源。
下文以IEU为例。
3. 关键定义
- UnitConfiguration:线缆白名单,配置在PSR里。承接BCU(CPU板)和IEU(Riser卡)之间的连接关系。
- Serdes:CPU资源,配置在BCU的sr中。包含丝印文件的关键属性
RootPortDeviceId,即PcieAddrInfo对象的PortID属性。 - BusinessConnector:
- BCU下行连接器,配置在BCU的soft部分的CSR里,老版本配置在UbcConfig.sr文件里。包含Serdes和UBC端口PortName的关系。
- IEU上行连接器,配置在IEU。包含线缆端口号PortID。
- IEU下行连接器,配置在IEU。包含自发现的连接器、对应的PcieAddrInfo、对应的上行连接器名字。
- PcieAddrInfo:PCIe槽位,配置在IEU。包含IEU信息以及IEU的槽位等信息。拓扑建立完成后会更新槽位号SlotID、Segment、SocketID、rootBDF(Bus、Device、Function)。
在同一个组件的连接器中,靠近CPU的为上行连接器,靠近PCIe设备的为下行连接器。
以下按顺序sr文件中的各个关键对象,其中BusinessConnector有三种。
- UnitConfiguration 类,配置在PSR中
"UnitConfiguration_IEU1": {
"SlotType": "IEU", // 对应PcieAddrInfo 类里 ContainerUnitType 属性
"SlotNumber": 1, // 对应PcieAddrInfo 类里 ContainerSlot 属性
"SlotSilkText": "IEUSlot1",
"Configurations": [
{
"UID": "00000001040302044499", // 对应PcieAddrInfo 类里 ContainerUID 属性
"Index": 1, // 对应线缆应该和哪个CPU链接,CPLD会上报是哪个CPU的连线,如果配置为0或不配置的话不检测
"BCUIndex": 1, // 对应线缆应该和哪个BCU链接,CPLD通过哪个BCU获取就对应哪个BCU(部分机型在CPLD里会上报一个BCUIndex),如果配置为0或不配置则不检测
"SrcPortName": [
"A1a", // 索引和 TargetPortID 里的索引一致。后续解析成转成 zone、src_port_id。对应BCU下行连接器里的 Ports 的 name 属性
"A2a"
],
"TargetPortID": [
49, // 对应 IEU下行连接器里的 first_res_port_id,即IEU上行连接器里的Ports元素的ID
33
],
"Slot": [
2, // 对应 PcieAddrInfo 里的 SlotID
3
],
"Device": [
8, // 对应 PcieAddrInfo 里的 PortID,一般不配置,部分场景需要在PSR中配死,不去BCU中寻找
12
]
},
...
],
"Port1LinkInfo": ""
},- SerDes 类,配置在BCU中,连接BCU下行连接器
"SerDes_1_8": {
"Name": "SerDes_1_8",
"ID": 8,
"SocketID": 1, // 对应哪一个CPU,从0开始
"LinkWidth": 8,
"WorkMode": 1, // 工作状态, 1 = PCIe, 4 = SAS, 3 = SATA
"ModeConfigs": [
{
"Mode": 1, // 匹配对应的工作模式 WorkMode 属性,根据上级的WorkMode匹配ModeConfigs的具体项目
"Device": [
8, // device 值,后续对应 PcieAddrInfo 里的 PortID
8,
9,
9,
10,
10,
11,
11
],
"ControllerIndex": [
1, // 对应Core编号
1,
1,
1,
1,
1,
1,
1
]
}
]
// 以上是CSR配置,以下是bmc代码里设置的属性
start_lane // 匹配到的BCU下行连接器累计的当前 LinkWidth (多个serdes对应一个BCU下行连接器)
}- 1.BCU 下行连接器,对应BCU上的UBC/UBCDD端口:
"BusinessConnector_CPU2UBCDD2": {
"Direction": "Downstream",
"Slot": 8,
"LinkWidth": "X16",
"MaxLinkRate": "PCIe 4.0",
"ConnectorType": "UBCDD",
"SilkText": "CPU2 UBCDD2",
"UpstreamResources": [
{
"Name": "SerDes_1_8", // 用来匹配SerDes的 Name。数组顺序对应SerDes的真实顺序。
"ID": 8,
"Offset": 0,
"Width": 8
},
...
],
"ActualResourceOrder": [
"SerDes_1_10", // 对应res_serdeses的真实顺序,如果配了这个字段,就按照这个顺序重排res_serdeses
"SerDes_1_7",
"SerDes_1_8"
],
"Ports": [
{
"Name": "B4a", // 这里是端口名,主要用来匹配,B是所属的Zone
"ID": 13, // 这里的ID是源端的ID,注意和TargetPortID区分
"Offset": 0, // 也是对应的IEU下行连接器开始的lane
"Width": 8
},
...
],
"Port1LinkInfo": "",
"Port2LinkInfo": ""
// 以上是CSR配置,以下是bmc代码里设置的属性
res_serdeses // 匹配到的所有的 SerDes
},- 2.IEU上行连接器:
"BusinessConnector_3": {
"Name": "Up_1",
"Direction": "Upstream",
"Slot": 1,
"LinkWidth": "X8",
"MaxLinkRate": "PCIe4.0",
"ConnectorType": "UBC",
"Ports": [
{
"Name": "Port1",
"ID": 49,
"Offset": 0, // 这个Offset主要用来索引Port,和BCU中PortID的索引无关
"Width": 8
}
]
},- 3.IEU下行连接器(pcie卡的连接器):
"BusinessConnector_1": {
"Name": "Down_1",
"Direction": "Downstream",
"Slot": 1, // 找 PcieAddrInfo 对象的 SlotID 用到,作为数组下标去PSR的Slot数组里查找。
"LinkWidth": "X16",
"MaxLinkRate": "PCIe 4.0",
"ConnectorType": "PCIe CEM",
"UpstreamResources": [
{
"Name": "Up_1", // 用来匹配上行连接器的 Name
"ID": 255,
"Offset": 0, // 用来匹配上行连接器端口的 Offset
"Width": 16
}
],
"RefMgmtConnector": "#/Connector_PCIE_1", // 关联框架自发现的连接器
"RefPCIeAddrInfo": "#/PcieAddrInfo_1" // 关联对应的PcieAddrInfo对象
// 以上是CSR配置,以下是bmc代码里设置的属性
res_connectors: // 匹配到的所有的上行连接器
res_port_ids: // 匹配到的上行连接器的端口的ID(可能有多个)
port_offsets: // 匹配到的上行连接器的端口的Offset(可能有多个,和res_port_ids中的对象一一对应)
link_width: // 解析 LinkWidth 的数字
ref_pcie_addr_info: // 根据RefPCIeAddrInfo匹配的pcie_addr_info对象
src_connector: // 匹配到的BCU下行连接器。
ref_mgmt_connector // 根据load_info信息,主要是type和SlotID,找到并重新获取资源树对象。
ref_mgmt_connector_tianchi // 根据load_info信息,主要是type和SlotID,找到并重新获取资源树对象。
},- PcieAddrInfo 类:
"PcieAddrInfo_1": {
"Location": "RiserCard${Slot}",
"ComponentType": 8,
"ContainerSlot": "${Slot}", // 对应psr里 UnitConfiguration 对象 SlotNumber 属性
"ContainerUID": "00000001040302044498", // 对应psr里 UnitConfiguration 对象 Configurations 属性里元素的 UID 属性。
"ContainerUnitType": "IEU", // 对应psr里 UnitConfiguration 对象 SlotType 属性
"GroupPosition": "PcieAddrInfo_1_${GroupPosition}" // 主键不能重复,GroupPosition 保证了不同CSR之间不重复。
// 以上是CSR配置,以下是bmc代码里设置的属性
SlotID: // 来自 UnitConfiguration 里的 Configurations 的 Slot 数组里的元素,IEU下行连接器Slot的值作为索引。
PortID: // 来自 SerDes 或 UnitConfiguration 类的 device值
SocketID: // 来自最高位的 serdes 类的 SocketID 属性
ControllerIndex: // 来自最高位的 serdes 类的 ControllerIndex 值
Bus // 根据 SocketID 和 PortID 在 override_root_bdf 或 BDFConfig 里找到。
Device // 根据 SocketID 和 PortID 在 override_root_bdf 或 BDFConfig 里找到。
Function // 根据 SocketID 和 PortID 在 override_root_bdf 或 BDFConfig 里找到。
DevBus // 从持久化数据读取 或者监听bios上报的devBDF
DevDevice // 从持久化数据读取 或者监听bios上报的devBDF
DevFunction // 从持久化数据读取 或者监听bios上报的devBDF
},4. 匹配示意:
因为代码里的流程是从PCIe槽位开始,向上匹配找到Serdes对象,所以下图以PcieAddrInfo对象开始,详细介绍如何关联各个CSR里的对象。
- IEU下行连接器的
UpstreamResources数组里的第一个元素的Name和Offset,找到IEU上行连接器的Ports的元素。比如上面的接线方式最终找到ID=49和33。 - 拓扑建立选择对应的PSR中的
UnitConfiguration时,会先根据SlotType和SlotNumber,如某个IEU,对应的PcieAddrInfo的ContainerSlot = 1,对应PSR中UnitConfiguration.SlotType = "IEU",UnitConfiguration.SlotNumber = 1。 - 当
UnitConfiguration.Configurations只有一项时,默认选择这一项;否则,拓扑建立会根据实际线缆信息匹配UnitConfiguration.Configurations中的项目,会匹配UID、BCUIndex、Index,BCUIndex不配置或为0或(线缆信息不包含BCUIndex且TopoNode不能明确BCUIndex)时忽略BCUIndex的匹配。Index不配置或为0或线缆信息不包含Index时忽略Index的匹配,之后进行TargetPortID的匹配,根据线缆读出的对端线缆ID去匹配,如线缆读取33、49,就会匹配TargetPortID = [33, 49]的项(顺序无关);如果一条都匹配不上,匹配配置了default: true的项;最后如果没有配置default: true,匹配第一项。 TargetPortID和SrcPortName的数组元素是一一对应的。例如下图UnitConfiguration_IEU1中TargetPortID的33、34、49分别对应A2a、A2c、A3a。- UnitConfiguration的
SrcPortName,找到BCU下行连接器里的Ports数组里的元素。BCU下行连接器的Ports和UpstreamResources是一一对应的,进而找到对应的Serdes。注意如果有ActualResourceOrder字段,就是Ports和ActualResourceOrder是一一对应的。 - PortID的值是对应的Serdes对象的
Device数组里的最小值。比如下图的A3a,向上找Serdes中的Device是4,因此下行的PcieAddrInfo的PortID也是4,即PcieAddrInfo_1.PortID=4槽位。 - 注意如果PcieAddrInfo_2槽位的宽度是X8,那么A2a对应的PortID就是10。因为A2a对应的Serdes是
ActualResourceOrder里的SerDes_0_4_A,宽度是X8。
5. 计算rootBDF
rootBDF和PortId的关系由带内给出,通过上面提到的硬件提供表格给出了示意,对于1630处理器的机型,对应表直接写在代码中,其他机型配置在BDFConfig里。
BDFConfig配置示意:
"BDFConfig_cpu0": {
"Type": "RootBDF",
"SocketId": 0,
"BDFConfigs": [
{
"PortId": 4,
"Bus": 1,
"ControllerIndex": 0,
"Device": 4
},
{
"PortId": 5,
"Bus": 1,
"ControllerIndex": 0,
"Device": 5
}
]
}6. 常见配置
BCU的CSR一般已经固定,IEU/EXU/SEU的CSR虽然看起来配置很多,但是大体有以下三种类型,主要是上下行连接器的区别,列出如下:
6.1 1个UBC/UBCDD对应1个槽位
IEU上行端口对应1个x16的Port,下行端口为x16。
IEU上行端口:
"BusinessConnector_1": {
"Name": "Up_1",
"Direction": "Upstream",
"Slot": 1,
"LinkWidth": "X16",
"MaxLinkRate": "PCIe5.0",
"ConnectorType": "UBCDD",
"Ports": [
{
"Name": "Port1",
"ID": 17,
"Offset": 0,
"Width": 16
}
]
},IEU下行端口:
"BusinessConnector_2": {
"Name": "Down_1",
"Direction": "Downstream",
"Slot": 1,
"LinkWidth": "X16",
"MaxLinkRate": "PCIe 5.0",
"ConnectorType": "PCIe CEM",
"UpstreamResources": [
{
"Name": "Up_1",
"ID": 255,
"Offset": 0,
"Width": 16
}
],
"RefMgmtConnector": "#/Connector_PCIE_1",
"RefPCIeAddrInfo": "#/PcieAddrInfo_1"
},6.2 1个UBCDD分为多个UBC口,对应多个槽位
IEU上行端口有2个x8的Port,下行端口为2个x8。
IEU上行端口 :
"BusinessConnector_1": {
"Name": "Up_1",
"Direction": "Upstream",
"Slot": 1,
"LinkWidth": "X16",
"MaxLinkRate": "PCIe5.0",
"ConnectorType": "UBCDD",
"Ports": [
{
"Name": "Port1",
"ID": 17,
"Offset": 0,
"Width": 8
},
{
"Name": "Port2",
"ID": 33,
"Offset": 8,
"Width": 8
}
]
},IEU下行端口:
"BusinessConnector_2": {
"Name": "Down_1",
"Direction": "Downstream",
"Slot": 1,
"LinkWidth": "X8",
"MaxLinkRate": "PCIe 5.0",
"ConnectorType": "PCIe CEM",
"UpstreamResources": [
{
"Name": "Up_1",
"ID": 255,
"Offset": 0,
"Width": 8
}
],
"RefMgmtConnector": "#/Connector_PCIE_1",
"RefPCIeAddrInfo": "#/PcieAddrInfo_1"
},
"BusinessConnector_3": {
"Name": "Down_2",
"Direction": "Downstream",
"Slot": 2,
"LinkWidth": "X8",
"MaxLinkRate": "PCIe 5.0",
"ConnectorType": "PCIe CEM",
"UpstreamResources": [
{
"Name": "Up_1",
"ID": 255,
"Offset": 8,
"Width": 8
}
],
"RefMgmtConnector": "#/Connector_PCIE_2",
"RefPCIeAddrInfo": "#/PcieAddrInfo_2"
},6.3 多个UBC口合成1个槽位
两个x8的Port的对应两个IEU上行端口,对应一个下行x16端口。
IEU上行端口 :
"BusinessConnector_1": {
"Name": "Up_1",
"Direction": "Upstream",
"Slot": 3,
"LinkWidth": "X8",
"MaxLinkRate": "PCIe 5.0",
"ConnectorType": "UBC",
"Ports": [
{
"Name": "Port1",
"ID": 33,
"Offset": 0,
"Width": 8
}
],
"Port2LinkInfo": "UBC3"
},
"BusinessConnector_2": {
"Name": "Up_2",
"Direction": "Upstream",
"Slot": 4,
"LinkWidth": "X8",
"MaxLinkRate": "PCIe 5.0",
"ConnectorType": "UBC",
"Ports": [
{
"Name": "Port2",
"ID": 34,
"Offset": 0,
"Width": 8
}
],
"Port2LinkInfo": "UBC4"
},IEU下行端口:
"BusinessConnector_3": {
"Name": "Down_1",
"Direction": "Downstream",
"Slot": 2,
"LinkWidth": "X16",
"MaxLinkRate": "PCIe 5.0",
"ConnectorType": "PCIe CEM",
"UpstreamResources": [
{
"Name": "Up_1",
"ID": 255,
"Offset": 0,
"Width": 8
},
{
"Name": "Up_2",
"ID": 255,
"Offset": 0,
"Width": 8
}
],
"RefMgmtConnector": "#/Connector_PCIE_SLOT2",
"RefMgmtConnectorTianChi": "#/Connector_PCIE_SLOT2TianChi",
"RefPCIeAddrInfo": "#/PcieAddrInfo_2"
},7. Q&A
Q: 拓扑建立和线缆检测有什么异同?
A:拓扑建立的目的是确定一种插法,因此当只配置了一种插法时,不关心实际线缆信息的结果,有多种时才会去匹配当前插法,若没有匹配上也会用默认插法(没有默认时用第一种插法)去进行。而线缆检测如果没有完全匹配就会告警(有部分特殊情况)。
Q: 我已经确定了端口的BDF、PortID和SlotID,是否可以直接配死?
A: 可以,如果不需要使用BDF上报的方式进行卡加载,只需要写死PcieAddrInfo各个属性,然后保证卡的Connector的DeviceType和SlotID和PcieAddrInfo对应(需要手动设置Presence=1,或直接把PCIeDevice写在SR中),卡就能加载并正常关联上PcieAddrInfo。如果希望使用上报BDF的方式进行卡加载,需要配置下行连接器、PcieAddrInfo和Connector,PcieAddrInfo中的PortID会被置为对应Configurations下对应项目的Device[下行连接器Slot],SlotID为对应项目的Slot[下行连接器Slot]。
Q: IEU有三个下行连接器,但是实际接法只允许两个槽位,我又不想改CSR,应该如何配置
A: 将PSR中对应配置的Slot配置为255,如"Slot": [255, 2, 3]
Q: 我遇到了概率性卡不加载,发现一种类型设备的BDF上报到另外一种设备的指令中了(如PCIe卡的BDF作为OCP上报)
A: 检查是否发生了PortID冲突(对应丝印中的RootPortDeviceId),RootPortDeviceId和SocketId组成的索引应该在丝印的PCIeSilk项目中唯一。
Q: 我遇到了同槽位的卡只加载上一张
A: 检查是否SlotID冲突,注意SlotId和DeviceType组成的索引在丝印文件的PCIeSilk项目中才是唯一的,单SlotId不唯一。
Q: Riser卡的槽位是怎么确定的?
A: 对于低速线和高速线分开的情况,槽位就是低速线配置的槽位。对于低速线和高速线合一的情况,当低速线在位时,会去PSR中匹配Connector中的源端线缆名称(如Connector_A1a为A1a),找到有A1a的UnitConfiguration,用该UnitConfiguration的SlotNumber作为组件的SlotNumber(注意这种情况下,若两个UnitConfiguration都有A1a,可能会导致SlotNumber不确定)。
Q: 拓扑建立会使用那种配置进行?
A:如果当前UnitConfiguration只有一种配置,选择这种;如果有多种配置,会读取一次线缆信息之后使用完全匹配上的;如果没有完全匹配上的,选择default = true的;如果没有配置default,选择第一个。