电源适配指南
更新时间:2025/07/10
在Gitcode上查看源码

电源管理组件,负责电源基础信息的获取如电压、电流、温度、功率等,提供电源工作模式、睡眠模式的设置与电源固件升级的功能,同时提供异常事件、告警、黑匣子日志等多种方式用于监测电源状态与故障定位。

电源识别加载流程

  1. 自发现识别加载CSR
  2. 自发现上树ObejctGroup对象
  3. 组件框架发送InterfaceAdd信号给各个组件
  4. 各个组件向自发现请求MDS对象
  5. 组件框架创建资源树对象
  6. 组件框架将自发现解析出来的属性赋值给对象
  7. 组件框架从持久化恢复数据到对象上
  8. 组件框架把对象注册上树
  9. 调用各个组件的addobject回调
  10. 执行组件设备树的差异性适配
  11. 执行orm初始化回调,对象初始化完成


电源适配流程

这里以适配一款pmbus电源为例,首先进行电源CSR的适配。

1. 电源CSR适配

首先确认电源模块是插在哪个板子上的,若电源插在扩展版上,则在相应的扩展版的CSR中去进行适配。

配置电源在位信息Scanner(通常位于扩展版上)

这里以配置电源1为例,配置的CSR为14100513_00000001010123456789.sr

json
"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),这里的在位信息使用上一步配置的电源在位状态。

json
"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

json
"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来配置。

json
"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. 电源设备树适配

电源设备树主要涉及的对象有OnePowerPsuSlotMonitorProtocol,各对象定义和作用如下:

OnePower

设备树加载通用模型,与通用逻辑不一致的需要自行在对应的CSR目录下补充adapter,通用OnePowerinit阶段关联上一级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_infopower_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.luainclude/device_tree/adapters/power_mgmt/protocol/init.lua)文件中定义加载的协议文件,封装monitor(可不配置)。

支持如下两种写法:

text
physical_interface = {OnePower对外显示Protocol字段, require xxx文件, monitor的文件路径}`

厂商 = { [型号] = {OnePower对外显示Protocol字段, require xxx文件, monitor的文件路径} }

NOTE

第二种写法需要先加载默认协议,由adapter读完厂商型号后,再根据厂商、型号重新加载协议文件。

这里以之前配置的OnePower对象举例,PhysicalInterface配置的是pmbus_test,则需要在init.lua文件中对应配置所使用的protocolmonitor,这里电源协议和monitor都新加了一个文件(如和已有的相同,可以直接复用)。


设备树adapter适配

设备树adapter适配主要针对PsuSlotOnePower对象,组件仓有一份PsuSlotOnePower的设备树加载通用模型,但如果有差异化的诉求,与通用逻辑不一致,则需要通过在对应的CSR目录下补充adapter

这里以PsuSlot举例,如果想差异性实现代码,则需要新建一个文件夹,文件夹命名和配置的CSR同名,在下面新增对应的PsuSlot文件,框架在加载时,会优先使用和CSR命名匹配的文件夹下对象,其次使用通用的文件。


调试

完成以上配置之后,通过命令busctl --user tree bmc.kepler.power_mgmt,可以在资源树上查看到配置的电源对象OnePower,并且可以查看每个电源对象下属性显示是否正常,若显示信息异常,可先通过手动发送命令读取电源信息,若能够读取则设备树代码适配存在问题,否则就是CSR适配存在问题。

手动查询电源信息方式如下,这里以pmbus读取电源1的输入功率为例:

shell
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. 返回电源升级结果


主要函数逻辑

power_upgrade

is_support_upgrade(psu_obj)

校验电源是否支持升级(电源状态、模式、数量校验)


PsuSlot

power_upgrade(upgrade_path, upgrade_process)

升级前后处理(电源监控任务的停止、拉起和电源状态的刷新)及protocol升级处理的调用


Protocol

upgrade(upgrade_path, upgrade_process)

电源升级处理


常见踩坑点及注意事项

  • 设备树中使用的的类变量需要在ctor中定义出来,否则出现代码中获取为nil的问题