一、power_mgmt介绍
电源管理组件,负责电源基础信息的获取如电压、电流、温度、功率等,提供电源工作模式、睡眠模式的设置与电源固件升级的功能,同时提供异常事件、告警、黑匣子日志等多种方式用于监测电源状态与故障定位
代码目录结构
include:
device_tree: --设备树相关实现
adapters:
14060876_0000000xxxxxxxxxxxxx --14060876_0000000xxxxxxxxxxxxx单板对应adapter实现
14100513_0000000xxxxxxxxxxxxx --14060876_0000000xxxxxxxxxxxxx单板对应adapter实现
14191046_0000000xxxxxxxxxxxxx --14060876_0000000xxxxxxxxxxxxx单板对应adapter实现
power_mgmt:
protocol:
monitor:
canbus.lua --canbus电源monitor
pmbus.lua --pmbus电源monitor
upgrade:
canbus_upgrade.lua --canbus电源升级处理
pmbus_upgrade.lua --pmbus电源升级处理
init.lua --Protocol适配与加载
canbus.lua --canbus协议
pmbus.lua --pmbus协议
utils.lua --工具函数实现
OnePower.lua --OnePower通用实现
PsuSlot.lua --PsuSlot通用实现
hwproxy: --电源插件相关实现
plugins:
power_mgmt:
init.lua --电源插件代码
manufacture:
manufacture_app.lua --装备测试项代码
src:
lualib:
device: --电源对象处理层
psu.lua --单个电源处理层
psu_slot.lua --单个电源槽位对象处理层
power_configuration.lua --电源配置对象处理层
external_interface:
handler.lua --存放外部调用接口和全局变量接口
macros: --存放常量
fw_def.lua --固件升级相关常量
log_def.lua --电源日志相关常量
power_mgmt_enums.lua --枚举定义
psu_def.lua --电源相关常量
add_event.lua --调用接口生成软件告警
export_import_engine.lua --配置导入导出
gpio_drived.lua --中断信号抓取
log_service.lua --日志收集、aclost事件记录
metric_collect.lua --数据采集
parser_cfg.lua --升级包解析文件
power_ipmi.lua --电源ipmi实现
power_mgmt_app.lua --app入口
power_mgmt_bus.lua --全局bus存放(当前无调用)
power_mgmt_utils.lua --电源工具函数实现
power_upgrade.lua --电源升级处理
psu_service.lua --所有电源对象处理层
signal.lua --电源升级信号处理
system_power.lua --电源fru信息定制化配置
task_service.lua --通用任务处理
二、电源识别加载流程
- 1、自发现识别加载CSR
- 2、自发现上树ObejctGroup对象
- 3、sd-bus发送InterfaceAdd信号给各个组件
- 4、各个组件向自发现请求CSR对象(解析出来的CSR文本)
- 5、libmc4lua创建资源树对象
- 6、libmc4lua将自发现解析出来的属性赋值给对象
- 7、libmc4lua从持久化恢复数据到对象上
- 8、libmc4lua把对象注册上树
- 9、调用各个组件的addobject回调
- 10、执行组件设备树的差异性适配
- 11、执行orm初始化回调,对象初始化完成
三、电源适配流程
这里以适配一款pmbus电源为例,首先进行电源CSR的适配
步骤1—— 电源CSR适配
首先确认电源模块是插在哪个板子上的,若电源插在扩展版上,则在相应的扩展版的CSR中去进行适配
1、配置电源在位信息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
}
2、配置电源连接器(通常位于扩展版上)
这一步用于配置电源加载使用的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的类型
}
3、配置电源槽位和电源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
}
4、配置电源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需要实现):
1、fetch_power_supply_info
注册对应的协议(如pmbus,canbus),并刷新Fru数据
2、power_monitor_start
拉起属性轮询任务
3、psm_monitor_stop
停止电源轮询任务
Monitor
不同协议的电源在属性查询、轮询周期等实现上有所不同,所以需要对fetch_power_supply_info和power_monitor_start的实现函数提取,不同的任务调度提取出来作为monitor
Monitor主要函数逻辑(适配新adapter需要实现):
1、fetch_power_supply_info
获取并刷新Fru数据
2、power_monitor_start()
启动电源信息监控
3、stop_monitor_tasks()
停止电源信息监控
Protocol
电源协议,根据不同的电源类型实现,对外屏蔽命令字和逻辑功能实现,接口功能和名称保持一致。
主要包含:
- 1、电源功率信息、状态信息、Fru信息的查询
- 2、电源黑匣子数据获取
- 3、电源模式设置(主备、深度休眠)
- 4、电源风扇转速设置
- 5、电源升级处理
1、电源协议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的文件路径} } 该写法需要先加载默认协议,由adapter读完厂商型号后,再根据厂商、型号重新加载协议文件
这里以之前配置的OnePower对象举例,PhysicalInterface配置的是pmbus_test,则需要在init.lua文件中对应配置所使用的protocol和monitor,这里电源协议和monitor都新加了一个文件(如和已有的相同,可以直接复用)

2、设备树adpter适配
设备树adpter适配主要针对PsuSlot和OnePower对象,组件仓有一份PsuSlot和OnePower的设备树加载通用模型,但如果有差异化的诉求,与通用逻辑不一致,则需要通过在对应的csr目录下补充adapter
这里以PsuSlot举例,如果想差异性实现代码,则需要新建一个文件夹,文件夹命名和配置的CSR同名,在下面新增对应的PsuSlot文件,框架在加载时,会优先使用和CSR命名匹配的文件夹下对象,其次使用通用的文件
步骤3——调试
完成以上配置之后,通过命令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个字节
四、电源固件升级
- 1、获取协议和升级包匹配的电源
- 2、检验电源数是否为0
- 3、电源模式切换,防止整机掉电
- 4、电源升级顺序排序,按照电源健康度进行排序
- 5、按照排序顺序遍历每个电源电源
- 6、校验环境是否支持升级
- 7、停止电源数据监控
- 8、升级单个电源
- 9、恢复数据监控并刷新电源固件信息
- 10、返回电源升级结果
主要函数逻辑:
1、power_upgrade
校验电源是否支持升级(电源状态、模式、数量校验)
is_support_upgrade(psu_obj)
2、PsuSlot
升级前后处理(电源监控任务的停止、拉起和电源状态的刷新)及protocol升级处理的调用
power_upgrade(upgrade_path, upgrade_process)
3、Protocol
电源升级处理
upgrade(upgrade_path, upgrade_process)
五、常见踩坑点及注意事项
1、设备树中使用的的类变量需要在ctor中定义出来,否则出现代码中获取为nil的问题





