电源管理组件,负责电源基础信息的获取如电压、电流、温度、功率等,提供电源工作模式、睡眠模式的设置与电源固件升级的功能,同时提供异常事件、告警、黑匣子日志等多种方式用于监测电源状态与故障定位。
电源识别加载流程
- 自发现识别加载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的问题