答案内容由AI生成,仅供参考:
关于通过自定义EEPROM格式进行厂商板卡加载的配置机制分析
根据当前系统架构和已知信息,针对通过自定义Eeprom格式进行厂商板卡加载的问题,现就现有机制、技术限制及可行方案进行全面梳理与回答。
问题背景概述
某厂商采用自定义的EEPROM数据格式,在特定域中存储板卡编码(Board ID),以用于识别和加载对应的SR(System Resource)文件。具体格式如下:
Eeprom Header 结构(关键偏移)
| 域内偏移 | 段含义 |
|---|---|
| 0 | 规范码(Signature) |
| 12 | 规范版本(Spec Version) |
| 13 | Elabel Offset |
| 15 | System Offset |
| 17 | PDR Offset |
| 19 | CDR Offset |
CDR 域结构(Component Description Record)
| 域内偏移 | 段含义 |
|---|---|
| 0 | CDR版本 |
| 1 | Vendor(厂商标识) |
| 17 | Component ID(组件ID) |
| 33 | 子域数量 |
| 34 | 子域类型 |
| 35 | 子域偏移 |
实际案例中:
CDR_Offset = 0x104(从Header中读取)- 实际Component ID起始偏移:
(0x104 * 8) + 17 = 0x831- 从
0x831开始读取8字节数据,作为Board ID字符串
当前现状与挑战
现状1:Accessor/Scanner 不支持动态Offset
"Accessor_BoardUID1": {
"Chip": "#Eeprom_SEU",
"Offset": "<= Accessor_CDR_Offset.Value |> expr(($1 * 8) + 17)",
"Size": 2,
"Type": 0
}
问题:
尽管可通过表达式语法(expr(($1 * 8) + 17))实现动态偏移计算,但 Accessor 和 Scanner 的 Offset 在对象创建时即固化,不会实时刷新或重新计算。
来自社区官方答复:
“offset当前不支持变更,不会实时读取资源树的值,并且Accessor的值需要访问才会触发硬件读取,同步Accessor的操作实际是没有意义的”
结论:动态偏移配置在初始化后失效,无法用于运行时更新。
现状2:无法直接将多字节整数转为字符串
- Accessor读取结果为无符号整数(uint),即使块读8字节(
Size=8),返回值仍以数值形式存在。 - 虽然CSR语法支持
string.format等表达式处理,但当尝试将Accessor.Value通过<=/A1.Value; <=/A2.Value; ... |> string.format(...)等方式拼接为字符串时,资源树不支持多值绑定与序列化表达式拼接。
官方说明:
“当前csr的语法配置使用string类型去同步其他类型时会进行强转,理论上U8类型会强转为字符串类型再赋值”
但实际中,这种“理论上的强转”仅适用于单个U8字段绑定到字符串属性,不支持8个独立Accessor逐个读取后拼接成字符串。
结论:无法通过标准Accessor + 表达式机制构建出8字节字符串ID。
现状3:多级Accessor + 手动拼接存在时序风险
现有方案尝试通过配置多个单字节Accessor(如Accessor_KunLun_BoardUID1~8),然后在Connector.Id中使用链式引用:
"Id": "<=Accessor_KunLun_BoardUID1.Value<=Accessor_KunLun_BoardUID2.Value..."
问题:
- 读取非原子操作:每个Accessor需单独触发硬件读取(Status=4未读取 → Status=0已读取)
- 加载时序依赖:
Presence检测先于Id计算完成,导致框架可能因Id为空而跳过加载 - 无自动重试机制:Connector不会等待所有Accessor数据就绪后再加载下级SR
结果:概率性加载失败,存在稳定性风险。
可行解决方案分析
方案一:使用 Chip.BlockIo 接口 + 自定义驱动或脚本(推荐)
目前最可靠的方式是绕过Accessor/Scanner机制,使用底层接口直接读取EEPROM。
使用 busctl 手动调用BlockIo读取(适用于调试与引导阶段)
busctl --user call bmc.kepler.hwproxy \
/bmc/kepler/Chip/Eeprom/Eeprom_SEU \
bmc.kepler.Chip.BlockIo Read a{ss}uu 0 0x831 8
0x831:计算后的Component ID起始偏移8:读取8字节- 返回原始字节数组,可由上层服务解析为字符串
在自发现或加载服务中集成此逻辑(生产级方案)
由硬件自发现服务(hwdiscovery)在探测到设备在位后,主动调用BlockIo.Read读取指定偏移的8字节数据,并解析为字符串,用于后续SR文件名匹配。
支持文档:《硬件代理总线读写接口使用方法》
支持I2C器件的Block读写操作
优点:
- 不依赖Accessor机制,避免表达式和类型转换问题
- 可实现原子性读取
- 可精确控制加载流程时序
缺点:
- 需修改或扩展自发现逻辑代码
- 不完全通过纯CSR配置实现(需程序干预)
方案二:扩展 Connector.Id 加载机制(建议未来优化方向)
当前Connector.Id仅支持静态字符串或简单表达式绑定,建议未来支持如下能力:
| 功能建议 | 描述 |
|---|---|
| 支持BlockIo表达式 | 允许在Id字段中嵌入`<= BlockIo(“/Eeprom_SEU”, 0x831, 8) |
| 支持多阶段加载 | Presence检测 → 等待Id获取完成 → 再加载SR,提供重试与超时机制 |
| 引入“PreLoad” Hook | 在加载SR前,允许运行一段预加载脚本完成ID提取 |
方案三:固化偏移 + 工具预处理(临时规避方案)
若CDR_Offset在所有板卡中固定(如恒为0x104),可预计算所有可能的ID偏移,并为每种板卡单独定义SR文件。
例如:
- 所有KunLun板卡均使用
CDR_Offset=0x104→ID offset=0x831 - 在CSR中直接写死:
"Accessor_BoardUID": { "Chip": "#Eeprom_SEU", "Offset": 2103, // 0x831 = 2103 "Size": 8, "Type": 1 // 块读 } - 并配合工具,在烧录EEPROM前确保ID位于指定位置
适用场景:板卡型号较少、格式统一的项目
是否有计划扩展 Connector.Type 或加载机制?
根据目前文档与设计趋势分析:
当前已有加载模式分类(基于IdentifyMode):
| IdentifyMode | 说明 |
|---|---|
| 1 | BoardId可读:从Eeprom读取,支持ID识别 |
| 2 | BoardId不可读:使用Bom+AuxId加载内置SR |
| 3 | 天池标准组件:通过Eeprom header自动识别 |
来源:《CSR配置字典之Connector类》
未来可扩展性展望:
- 系统已支持“非标电子标签”
StorageType=Power、Others - 支持动态表达式语法(如
expr、string.*) - 支持refInterface实现自定义接口加载
建议:可向社区提议扩展一种新的IdentifyMode=4,表示自定义格式组件,其ID读取规则由外部脚本或配置定义。
总结与建议
| 项目 | 当前状态 | 建议 |
|---|---|---|
| 动态Offset支持 | 避免依赖表达式计算Offset | |
| 多字节转字符串 | 禁用拼接字符串方案 | |
| 多级Accessor加载 | 仅可用于调试,不可用于生产 | |
| 可靠ID读取方式 | 使用bmc.kepler.Chip.BlockIo接口 |
|
| 加载稳定性保障 | 建议在自发现层增强逻辑 | |
| 长期可维护性 | 推动社区支持IdentifyMode=4或ID预加载钩子 |
最佳实践建议(当前可行路径)
-
在系统加载初期,通过
BlockIo主动读取EEPROM- 读取Header中
CDR Offset(偏移0x13) - 计算Component ID偏移:
(CDR_Offset × 8) + 17 - 读取8字节数据 → 转换为ASCII字符串
- 读取Header中
-
将获取的ID作为SR文件名的一部分进行加载
- 如:
14140130_KUNLUN_Server.sr
- 如:
-
在BOM或Connector中声明该设备为“自定义格式组件”
- 使用
Type="CustomPCIe"或预留字段标记
- 使用
-
推动openUBMC社区支持更灵活的ID加载机制
- 提出RFC:支持
IdentifyMode=4 - 增加
PreLoadScript或IdProvider机制
- 提出RFC:支持
结论:
目前CSR配置没有完全无风险的纯声明式机制来完成该需求。
推荐方案是结合BlockIo底层接口与自发现服务扩展,实现稳定、可靠的自定义板卡加载机制,同时向社区反馈增加对复杂ID提取场景的支持。
相关链接: