电源管理组件,负责电源基础信息的获取如电压、电流、温度、功率等,提供电源工作模式、睡眠模式的设置与电源固件升级的功能,同时提供异常事件、告警、黑匣子日志等多种方式用于监测电源状态与故障定位。
电源识别加载流程
- 自发现识别加载CSR
- 自发现上树
ObejctGroup
对象 - 组件框架发送
InterfaceAdd
信号给各个组件 - 各个组件向自发现请求MDS对象
- 组件框架创建资源树对象
- 组件框架将自发现解析出来的属性赋值给对象
- 组件框架从持久化恢复数据到对象上
- 组件框架把对象注册上树
- 调用各个组件的
addobject
回调 - 执行组件设备树的差异性适配
- 执行
orm
初始化回调,对象初始化完成
电源适配流程
这里以适配一款pmbus
电源为例,首先进行电源CSR的适配。
1. 电源CSR适配
首先确认电源模块是插在哪个板子上的,若电源插在扩展版上,则在相应的扩展版的CSR中去进行适配。
配置电源在位信息Scanner(通常位于扩展版上)
这里以配置电源1为例,配置的CSR为14100513_00000001010123456789.sr
"Scanner_PS1Pres": {
"Chip": "#/Smc_ExpBoardSMC", // 关联的chip
"Offset": 603981056, // 偏移
"Size": 2, // 读取数据长度
"Mask": 1, // 位读时有效,从硬件读取数据后与掩码按位与操作
"Type": 0, // 读类型,0:位读,1:块读
"Value": 255, // 读值
"Period": 2000 // 扫描周期,单位ms
}
配置电源连接器(通常位于扩展版上)
这一步用于配置电源加载使用的CSR,这里配置的是电源1加载使用的是CSR(14191046_PSU_0.sr
),这里的在位信息使用上一步配置的电源在位状态。
"Connector_PowerSupply_1": {
"Bom": "14191046", // 下级组件Bomid
"Slot": 1, // 当前连接器槽位,用于确认下级组件的槽位信息(必填)
"Position": 9, // 当前连接器位置,用于计算下级组件的位置(必填)
"Presence": "<=/Scanner_PS1Pres.Value", // 下级组件在位信息(必填)
"Id": "PSU", // 下级组件的组件id
"AuxId": "0", // 下级组件的组件Auxid
"Buses": [ // 连接器的总线信息,用于传递至下级组件(必填)
"I2c_2"
],
"SystemId": 1, // 连接器下级的SystemId,用于传递至下级组件
"SilkText": "psu1", // 连接器的丝印信息
"IdentifyMode": 2, // Connector的标志模式(必填)
"Type": "Psu" // Connector的类型
}
配置电源槽位和电源chip(通常位于扩展版上)
这一步配置槽位信息及电源chip,配置的CSR为14100513_00000001010123456789.sr
"PsuSlot_1": {
"SlotNumber": 1, // 槽位号
"Presence": "<=/Scanner_PS1Pres.Value", // 引用电源的在位寄存器
"SlotI2cAddr": 184, // 电源槽位i2c地址
"PsuChip": "#/Eeprom_PsuChip1" // 关联电源i2c器件
},
"Eeprom_PsuChip1": {
"Address": 184, // 地址信息
"AddrWidth": 1, // 位宽
"OffsetWidth": 1, // 偏移宽度
"ReadTmout": 30, // 读取超时时间,单位ms
"WriteTmout": 30, // 写入超时时间,单位ms
"RwBlockSize": 1024 // 分页读写的数据大小,单位Byte
}
配置电源CSR
这一步进行电源对象的配置,电源对象需要根据电源在位信息变化来加载及卸载,需要在14191046_PSU_0.sr
来配置。
"FruData_Ps": {
"FruId": 1, // FruId,1-63会自动分配fruid,默认可以配1
"StorageType": "Power" // 非标电子标签不做限制
},
"Fru_Ps": {
"PowerState": 1, // Fru的热插拔状态
"Health": 0, // 健康状态
"EepStatus": 1, // EEPROM状态
"Type": 3, // FRU类型,参考iBMC IPMI接口说明附录
"FruDataId": "#/FruData_Ps" // 关联frudata对象名
},
"OnePower_0": {
"SlotNumber": "${Slot}", // 槽位号(必填)
"Presence": 1, // 在位信息(必填)
"Protocol": "pmbus", // 电源协议
"PhysicalInterface": "pmbus_test", // 物理接口(必填)
"DeviceLocator": "PSU${Slot}", // 物理位置(必填)
"Position": "EXU", // 容器信息(必填)
"EnvTemperatureCelsius": 0, // 单个电源环境温度
"SerialNumber": "", // 序列号
"OutputState": 1, // 电源电压输出状态
"DeepSleepEnabled": 0, // 电源深度休眠使能(告警使用)
"OutputPowerWatts": 0, // 输出功耗
"InputVoltageFault": 32768, // 电压输入状态
"OutputVoltageFault": 0, // 电压输出状态
"OutputCurrentFault": 0, // 电流输出状态
"FanFault": 0, // 风扇状态
"Fan1Fault": 0, // 风扇1故障
"Fan2Fault": 0, // 风扇2故障
"Failure": 0, // 电源故障
"OverTemperature": 0, // 风扇1故障
"LossOfInput": 255, // 过温故障
"RefFrudata": "#/FruData_Ps", // 关联的Frudata对象
"PartNumber": "" // 部件编码
}
2. 电源设备树适配
电源设备树主要涉及的对象有OnePower
、PsuSlot
、Monitor
、Protocol
,各对象定义和作用如下:
OnePower
设备树加载通用模型,与通用逻辑不一致的需要自行在对应的CSR目录下补充adapter
,通用OnePower
在init
阶段关联上一级position
的同槽位PsuSlot
对象,并刷新Fru
信息。
PsuSlot
PsuSlot
所在不同的单板,需要独立配置一份adapter
。框架在获取到PsuSlot
对象后,会根据所属的CSR,拉起不同的adapter
。
PsuSlot
主要函数逻辑(适配新adapter
需要实现):
fetch_power_supply_info
注册对应的协议(如pmbus,canbus),并刷新Fru数据power_monitor_start
拉起属性轮询任务psm_monitor_stop
停止电源轮询任务
Monitor
不同协议的电源在属性查询、轮询周期等实现上有所不同,所以需要对fetch_power_supply_info
和power_monitor_start
的实现函数提取,不同的任务调度提取出来作为monitor
。
Monitor
主要函数逻辑(适配新adapter
需要实现):
fetch_power_supply_info
获取并刷新Fru数据power_monitor_start
启动电源信息监控stop_monitor_tasks
停止电源信息监控
Protocol
电源协议,根据不同的电源类型实现,对外屏蔽命令字和逻辑功能实现,接口功能和名称保持一致。
主要包含:
- 电源功率信息、状态信息、Fru信息的查询;
- 电源黑匣子数据获取;
- 电源模式设置(主备、深度休眠);
- 电源风扇转速设置;
- 电源升级处理。
3. 电源协议Protocol
适配与加载
首先,根据上层传入的physical_interface
(即OnePower
对象上配置的PhysicalInterface
属性),在设备树的init.lua
(include/device_tree/adapters/power_mgmt/protocol/init.lua
)文件中定义加载的协议文件,封装monitor
(可不配置)。
支持如下两种写法:
physical_interface = {OnePower对外显示Protocol字段, require xxx文件, monitor的文件路径}`
厂商 = { [型号] = {OnePower对外显示Protocol字段, require xxx文件, monitor的文件路径} }
NOTE
第二种写法需要先加载默认协议,由adapter
读完厂商型号后,再根据厂商、型号重新加载协议文件。
这里以之前配置的OnePower
对象举例,PhysicalInterface
配置的是pmbus_test
,则需要在init.lua
文件中对应配置所使用的protocol
和monitor
,这里电源协议和monitor
都新加了一个文件(如和已有的相同,可以直接复用)。
设备树adapter
适配
设备树adapter
适配主要针对PsuSlot
和OnePower
对象,组件仓有一份PsuSlot
和OnePower
的设备树加载通用模型,但如果有差异化的诉求,与通用逻辑不一致,则需要通过在对应的CSR目录下补充adapter
这里以PsuSlot
举例,如果想差异性实现代码,则需要新建一个文件夹,文件夹命名和配置的CSR同名,在下面新增对应的PsuSlot
文件,框架在加载时,会优先使用和CSR命名匹配的文件夹下对象,其次使用通用的文件。
调试
完成以上配置之后,通过命令busctl --user tree bmc.kepler.power_mgmt
,可以在资源树上查看到配置的电源对象OnePower
,并且可以查看每个电源对象下属性显示是否正常,若显示信息异常,可先通过手动发送命令读取电源信息,若能够读取则设备树代码适配存在问题,否则就是CSR适配存在问题。
手动查询电源信息方式如下,这里以pmbus
读取电源1的输入功率为例:
busctl --user call bmc.kepler.hwproxy /bmc/kepler/Chip/Eeprom/Eeprom_PsuChip1_0101 bmc.kepler.Chip.BlockIo Read a{ss}uu 0 151 3
解释:
/bmc/kepler/Chip/Eeprom/Eeprom_PsuChip1_0101
:对应Chip的资源树路径(根据环境上路径进行调整)bmc.kepler.Chip.BlockIo
:资源树块读写接口Read
:方法名a{ss}uu
:请求参数签名,其中a{ss}
为上下文可以直接填0,第一个u
代表偏移,151
对应pmbus
获取输入功率命令字,第二个u
代表读取字节数,输入功率2字节+crc码,共3个字节
电源固件升级
- 获取协议和升级包匹配的电源
- 检验电源数是否为0
- 电源模式切换,防止整机掉电
- 电源升级顺序排序,按照电源健康度进行排序
- 按照排序顺序遍历每个电源电源
- 校验环境是否支持升级
- 停止电源数据监控
- 升级单个电源
- 恢复数据监控并刷新电源固件信息
- 返回电源升级结果
主要函数逻辑
power_upgrade
is_support_upgrade(psu_obj)
校验电源是否支持升级(电源状态、模式、数量校验)
PsuSlot
power_upgrade(upgrade_path, upgrade_process)
升级前后处理(电源监控任务的停止、拉起和电源状态的刷新)及protocol升级处理的调用
Protocol
upgrade(upgrade_path, upgrade_process)
电源升级处理
常见踩坑点及注意事项
- 设备树中使用的的类变量需要在
ctor
中定义出来,否则出现代码中获取为nil
的问题