runtime_accessor

版本信息

项目内容
组件版本1.130.9
首发版本openUBMC 26.09
文档作者openUBMC 社区
最后更新2026-09-15
许可证Mulan PSL v2

1. 组件概述

1.1 组件简介

runtime_accessor 是 openUBMC 的 Lua 器件访问库,将外围器件(如 PCA9555、EEPROM、Lm75)和总线(如 I2C、Hisport、LocalBus)的读写操作封装为可按 CSR class_name 选择的驱动模块,供 hwproxy 在进程内调用。

组件在 mds/service.json 中声明为 library。它不启动独立服务进程、不提供 mds/model.json 资源协作接口,也不提供 IPMI 命令。Lua 代码安装到 /opt/bmc/apps/hwproxy/lualib,由 hwproxy 通过 require('driver.driver')require('stream.stream')require('mux.mux')require('protocol.protocol') 加载。底层用户态驱动来自 libsoc_adapter

1.2 解决什么问题

BMC 需要通过多种总线访问温度传感器、GPIO 扩展器、EEPROM、SMC、CPLD、SPI Flash 等外围器件。若各业务组件各自封装总线读写、Mux 切通道和协议组包,会出现重复实现、器件差异难以复用、无法随 hwproxy 组件化交付等问题。

runtime_accessor 把器件驱动、总线 Stream、Mux 切通道和协议包装拆成四类 Lua 模块,hwproxy 按 CSR 对象的 class_name 实例化对应实现,从而:

  • 将器件/总线访问从业务组件中剥离,支持独立仓交付。
  • read / write / bit_read / bit_write 以及 Mux 的 open_channel / close_channel 给出统一调用面。
  • 通过 Protocol 的 wrap / unwrap 支持 SMC 转发、MCTP over SMC 等组包,而不改动上层 Chip 调度。

1.3 核心功能

  • 器件驱动(driver):按芯片类型封装寄存器读写、分页、自检和复位等能力。
  • 总线 Stream(stream):封装 I2C、Hisport、GPIO、LocalBus、JTAG、CAN、ADC 等总线的 init / read / write,内部通过 stream.open_drive 加载 libsoc_adapter.*
  • Mux:封装 PCA9545、PCA9544、JtagSwitch、McuSwitch 的通道打开/关闭。
  • Protocol:封装 SMC 读写转发与 CRC 校验;无协议时使用 None 透传。
  • 字节序辅助drvlib_common 提供 htons / ntohs / htonl / ntohl

1.4 关键术语表

术语解释
driver器件驱动类,封装芯片级 read / write,基类位于 driver.base
stream总线访问类,封装一次总线事务的 read / write,基类位于 stream.base
mux多路复用器封装,提供 open_channel / close_channel
protocol协议包装器,在下发总线前 wrap、在回读后 unwrap
class_nameCSR/对象模型中的类型名,hwproxy 用它在 driver / stream / mux / protocol 导出表中选实现。
input读写请求表,常见字段包括 addroffsetoffsetWidthlenmasktypebuffer
libsoc_adapter用户态 SoC 驱动适配库,Stream 通过 require('libsoc_adapter.i2c') 等打开。
hwproxy硬件代理组件,加载本库并按资源树调度 Chip / Bus 访问。
SMCServer Management Channel,本库同时提供 driver.Smcprotocol.Smc
CSRComponent Self-Description Record,描述芯片地址、总线、Mux 等访问参数。

1.5 外部交互边界图

构建测试依赖见 mds/service.jsonlibmc4luapersistence(均仅出现在 dependencies.test)。运行时代码随 hwproxy 部署;组件自身没有常驻进程、监听端口或 D-Bus 服务名。

2. API 使用说明与示例

以下接口均为 Lua 本地接口,不是资源协作接口,不能通过 busctl / mdbctl 调用。仓库无 mds/model.json、无 mds/ipmi.json

2.1 模块加载与调用约定

功能说明

hwproxy 在构造 Chip / Bus 时按对象 class_name 选择实现;未知类型回退到对应导出表中的 None

lua
local driver = require('driver.driver')
local mux = require('mux.mux')
local protocol = require('protocol.protocol')
local stream = require('stream.stream')

-- hwproxy/src/lualib/chip.lua
obj.protocol = (protocol[object.class_name] or protocol.None).new()
obj.driver = (driver[object.class_name] or driver.None).new(obj, object)
obj.mux = (mux[object.class_name] or mux.None).new(obj)

-- hwproxy/src/lualib/hwproxy_objects/work_bus.lua
self.stream = (stream[object.class_name] or stream.None).new(object, object.name)

安装后 Lua 搜索路径需包含 /opt/bmc/apps/hwproxy/lualib(由 hwproxy 进程配置,本库不单独设置 package.path)。

参数说明

四个聚合模块及其导出键如下。键名必须与 CSR class_name 一致(大小写敏感)。

模块文件导出键
driver.driversrc/lualib/driver/driver.luaEepromLm75Pca9555Pca9545Pca9544SmcVrdAds78CpldRegisterCpldChipCanbusChipJtagSwitchRtcCpldChipInaNoneSPIFlash
stream.streamsrc/lualib/stream/stream.luaI2cHisportGpioLocalBusJtagJtagOverLocalBusJtagOverGpioCanAdcI3cOverLocalBusI2cOverHisportSPIOverHisportJtagOverHisportI2cOverLocalBusInnerBusNone
mux.muxsrc/lualib/mux/mux.luaPca9545Pca9544NoneJtagSwitchMcuSwitch
protocol.protocolsrc/lualib/protocol/protocol.luaSmcNone

driver.Rtc 实际加载 driver.rtc_chipstream 目录另有 hisport2.lua,但 加入 stream.stream 导出表;按 class_name = Hisport2 构造时 hwproxy 会落到 stream.None

返回值与异常

require 失败时由 Lua 抛出 module not founddriver.None:read / writeerror('request error, Invalid chip type')stream.Noneread / write 为空实现。

应用场景

hwproxy 根据资源树加载 Chip 和 Bus 后,业务通过 Chip 的访问队列间接调用本库,而不是在其他组件中直接 require 器件驱动。

限制条件

  • 本库不是独立 Skynet 服务;dist/config.cfg 中的 runtime_accessor/service/main 启动项在当前仓库无对应 src/service 实现。
  • gen/runtime_accessor/service.lua 为 bingo 脚手架生成的 DemoService,不是对外 API。
  • 未知 class_name 不会自动报错,而是静默回退到 None

调试示例

lua
local driver = require('driver.driver')
local lm75 = driver.Lm75.new(chip_obj, {
    Address = 0x90,
    AddrWidth = 1,
    OffsetWidth = 1,
    HighTempLimitation = 0xffff,
    LowTempLimitation = 0xffff,
})
lm75:add_bus(host_bus)
local data = lm75:read({
    addr = 0x90,
    addrWidth = 1,
    offsetWidth = 1,
    offset = 0,
    len = 2,
    mask = 0xffff,
})

单元测试入口为 test/unit/test.lua,覆盖 SMC 转发、RTC、INA 等用例。

2.2 通用访问入参 input

功能说明

Driver 与 Stream 的 read / write 共用一张 Lua 表作为请求上下文。基类 driver.base 会写入 rw_type(写 0、读 1),再调用 own_chip:wrap(input),然后把请求交给 host_bus:read / write

参数说明

字段类型说明
addrinteger器件地址(I2C 等总线使用)。
addrWidthinteger地址宽度,构造 Driver 时来自对象属性 AddrWidth
offsetinteger寄存器或存储偏移;0xFFFFFFFF 表示扩展芯片读模式(drvlib_common.HAS_EXTEND_CHIP_READ_MODE)。
offsetWidthinteger偏移宽度,单位字节;I2C/Hisport 要求 0~4
leninteger本次读写长度。I2C write 超过 1100 会报 request error, input len too long
maskinteger位访问掩码;type == 0 时 Stream 可能按掩码裁剪返回值。
typeinteger访问类型。hwproxy 中 0 为 bit、1 为 block;SPI Flash 另用 2 擦除、3 raw_write、4 raw_write_read。
bufferstring写数据;部分接口(如 PCA9555)写时不可为 nil
namestring芯片名,用于日志。
protocol_flaginteger协议标志。I2C SMBUS 为 0x02;MCTP over SMC 为 0x03
drv_write_delayinteger写延迟,默认 0
append_writetableSMC 转发读前需要先下发的写请求。
smc_targetanyProtocol SMC 用来区分 I2C 转发与 SMC 转发。
is_traceboolean为真时触发 set_tracechip 注册的回调。

Driver 构造时从对象属性读取的公共字段(driver.base:ctor):

对象属性Driver 字段默认值
Addressaddress
AddrWidthaddr_width
OffsetWidthoffset_width
WriteTmoutwrite_tmout0
ReadTmoutread_tmout0
HealthStatushealth_statusnil
ChipResetref_accessorfalse

返回值与异常

read 成功返回二进制字符串。write 无返回值。失败时通过 Lua error 抛出字符串,或抛出表 { err = <string>, cc = <number> }(SMC Completion Code)。

应用场景

所有器件/总线读写、SMC 组包、Mux 切通道后的访问都填充这张表。

限制条件

调用方必须先 driver:add_bus(bus),否则 read / write 访问 self.host_bus 会失败。wrap / unwrap 由 Chip 对象提供,单元测试需自行实现链式 wrap(见 test/unit/test_smc.lua)。

调试示例

lua
local input = {
    addr = 0x40,
    addrWidth = 1,
    offsetWidth = 1,
    offset = 0x1f,
    len = 10,
    mask = 0xffffffff,
    type = 1,
}
local ok, ret = pcall(chip.read, chip, input)
if not ok then
    -- SMC 失败时 ret.err / ret.cc 可用
end

2.3 Driver 器件驱动接口

功能说明

基类 driver.base 提供统一读写路径:设置 rw_typeown_chip:wraphost_bus:read/writeown_chip:unwrap。具体器件类覆盖 read / write / bit_read / bit_write / chip_test 等。

参数说明

基类方法
方法入参出参说明
ctor(chip, object)Chip 对象、CSR 属性表保存地址、位宽、超时等。
add_bus(bus)read / write 的 Bus绑定前级总线。
read(input)inputstring读;若存在 append_write 则先写再循环读。
write(input)input写。
bit_read(input)inputstring默认转发 read
bit_write(input)input默认转发 write
chip_test(test_para)可选 {offset, len}boolean连续读两次并比较;未设置 chip_type 时记 error 并返回 false
set_tracechip(func)回调input.is_trace 时调用。
reset_chip()基类空实现;Pca9545 / Pca9544 可按 ref_accessor 复位。

offset == 0x34SMC_READ_BUFFER_FORWARD_MCTP)且存在 append_write 时,基类走 read_forward_mctp:按 SMC Completion Code 0 成功、2 未就绪、6 需继续读进行重试,最多 5 次未就绪则结束。

导出器件与差异行为
导出键源文件相对基类的主要差异
Lm75driver/lm75.lua首次访问按 HighTempLimitation / LowTempLimitation 配置阈值寄存器;read/bit_read 要求 len 为 1 或 2;自检写 0x55 0x00 到寄存器 2
Eepromdriver/eeprom.luaRwBlockSize(默认 32,最大 1024)分页读写;写间隔 WriteInterval(默认 50 ms,最大 500 ms)。
Pca9555driver/pca9555.luabit_write 先改配置寄存器再改输出寄存器;len 必须为 1,offset 只能为 0 或 1,mask 不能为 0。
Pca9545 / Pca9544driver/pca9545.luadriver/pca9544.luaread/write 要求 len == 1;提供 reset_chip
Smcdriver/smc.lua按 opcode 0x20/0x21/0x22 组包并做 CRC8;读侧轮询 Length/CC;DrvWriteDelay 可配。
Chipdriver/chip.lua通用芯片;init_cfg / chip_init 按寄存器表初始化;BusTypeDrvWriteDelay 可配。
Inadriver/ina.luaChipModel(Ina220/Ina226/Ina238)写配置与校准寄存器;未配置寄存器时 error('request error, calibration_reg or config_reg is nil')
SPIFlashdriver/spi_flash.luaread/write 外提供 eraseraw_writeraw_write_readinitChipSelectBytesPerPageCommandSet 可配。擦除模式由 input.buffer 取值 0~3 对应 Sector / 32K / 64K / ChipErase。
Vrddriver/vrd.lua按 page/寄存器操作 VRD;提供 initdelayoperate_vrd
Rtcdriver/rtc_chip.luaRTC 寄存器读写。
Cpld / CpldRegister / CpldChip对应 luaCPLD 访问;Cpld 另有 get_cpld_idcheck_bypass_channelset_numset_bypass_mode
CanbusChipdriver/canbus_chip.luaCAN 芯片读写;另有 multi_readresetset_speedset_id_mask
JtagSwitchdriver/jtag_switch.luaJTAG 切换芯片的读写。
Ads78driver/ads78.luaADC 芯片 bit_read / read / write
Nonedriver/none.luaread/writeInvalid chip type

返回值与异常

成功:read 返回原始字节串。失败:error 字符串(前缀多为 request error / response error)或 SMC 表 {err, cc}chip_test 返回 true/false,不抛错。

SMC Completion Code(driver.base / driver.smc / protocol.smc 一致):

cc含义
0成功
1request error, opcode not supported
2未就绪(读侧重试)
3request error, parameter error
4response error, chip internal error
5request error, CRC error
6需继续读(MCTP forward)

应用场景

hwproxy 将 CSR 中的芯片对象映射为 Driver,通过访问器/扫描器发起周期或按需 IO。

限制条件

  • 器件类覆盖了 read 后,仍依赖 host_bus 与 Chip 的 wrap/unwrap
  • Lm75 在阈值均为默认 0xffff 时跳过配置;温度寄存器 bit_read 固定按 2 字节读取后再按请求长度截取。
  • SPIFlash:erase 在器件仍处于写过程中会 error('the spi flash is in writing process, unable to erase')

调试示例

lua
-- 摘自 README 的新增器件方式,实现见 src/lualib/driver/lm75.lua
local class = require('mc.class')
local driver = require('driver.base')
local lm75 = class(driver)

function lm75:read(input)
    if input.len ~= 1 and input.len ~= 2 then
        error(string.format('request error, invalid input length: %d', input.len))
    end
    return driver.read(self, input)
end

2.4 Stream 总线接口

功能说明

Stream 负责打开 libsoc_adapter 驱动并执行总线事务。基类 stream.base 提供 open_drivebus_lock / bus_unlock。hwproxy 的 work_busbus:read / write 直接转给 self.stream

参数说明

基类
方法入参出参说明
ctor(property, bus_name)总线属性表、总线名保存 property.Id(默认 0)和 bus_name
open_drive(drv_file_name, ...)模块名,如 'libsoc_adapter.i2c'驱动对象或 nilpcall(require)pcall(drv_lib.new, ...);失败只记录一次 failed to open drive
bus_lock() / bus_unlock()若底层驱动提供 lock/unlock 则调用。
get_value_with_mask(...)type、value、length、maskvalue基类原样返回;I2C/Hisport/LocalBus 等会覆盖。
已导出 Stream
导出键源文件主要方法初始化要点
I2cstream/i2c.luainitreadwriteSpeed/Mode/SlaveAddr/UseSmbus/SdaHold/MultiIOUseSmbus==1deploy,否则 drv:init。读路径:扩展模式 / SMBUS 0x02 / 普通读。
Hisportstream/hisport.luareadwrite构造时 open_drive('libsoc_adapter.hisport')initBusNumRegNumMaxDataLen 等可配。
Gpiostream/gpio.luainitreadwritegpio_group_readgpio_group_writeDirectionReverseBitBit0GpioNum~Bit7GpioNum
LocalBusstream/localbus.luainitreadwrite校验 id 0~3、地址偏移与位宽配置。
Canstream/can.luainitreadwriteresetset_speedset_id_mask打开 libsoc_adapter CAN 驱动。
Adcstream/adc.luainitreadADC 采样读。
I2cOverHisport / SPIOverHisport / JtagOverHisport对应 luaread/write在 Hisport 上承载 I2C/SPI/JTAG。
I2cOverLocalBus / I3cOverLocalBus / JtagOverLocalBus / JtagOverGpio对应 luainitread/write在 LocalBus 或 GPIO 上承载对应协议。
Jtagstream/jtag.luainitwriteget_cpld_idcheck_bypass_channel具体升级/校验/收集在 jtag_base.lua
InnerBusstream/innerbus.luainitreadwrite进程内总线。
Nonestream/none.luaread/write未知总线类型回退。

jtag_base.lua 另提供 start_upgrade_workupgradeverifycollectset_numset_bypass_mode,由 JTAG 系列 Stream 使用。

返回值与异常

I2C:底层 ret ~= 0 时调用 reinit_i2c_and_throw_error;若 protocol_flag == 0x02ret == 19(ENODEV)会尝试重新 init,然后 error('response error, i2c <read|write|deploy> fail, ...')offsetWidth 非法时 error('request error, offsetWidth is invalid: ...')。Hisport 对 offsetWidth > 4 同样报错。

应用场景

CSR 中的 Bus 对象(如 I2cHisport)由 hwproxy 创建 Stream,Chip Driver 通过 host_bus 访问。

限制条件

  • I2C 在 speed == 2(代码中的 I2C_HIGH_SPEED)且走 SMBus deploy 时直接 error('request error, i2c smbus init failed')
  • I2C 普通读的 offsetWidth 只能是 0~4
  • open_drive 失败返回 nil,后续对 self.drv 的调用会在业务路径上失败。
  • hisport2.lua 未从 stream.stream 导出。

调试示例

lua
local stream = require('stream.stream')
local i2c = stream.I2c.new({
    Id = 1,
    Speed = 0,      -- 100k
    Mode = 0,       -- master
    UseSmbus = 0,
}, 'I2c1')
i2c:init()
local data = i2c:read({
    addr = 0x90,
    offset = 0,
    offsetWidth = 1,
    len = 2,
    mask = 0xffff,
    type = 1,
})

hwproxy 单测 test/unit/test_hwproxy.lua 通过 require('stream.i2c') 直接加载该类。

2.5 Mux 多路复用接口

功能说明

Mux 在访问挂在多路复用器后级的芯片前打开通道,访问结束后关闭。基类 mux.base:ctor(chip) 只保存 own_chip。hwproxy 在 SwitchSupported 未开启(或未提供函数形态的 ComboWriteRead)时,按 class_name 创建 Mux。

参数说明

导出键源文件open_channel(id)close_channel
Pca9545mux/pca9545.lua向 offset 0 写入 1 << id写入 0
Pca9544mux/pca9544.luaid >= 4 时报 invalid PCA9544 channel id;写入 0x04 | id写入 0
JtagSwitchmux/jtag_switch.luaown_chip:write({}, id)own_chip:write({}, 0),无 id 参数
McuSwitchmux/mcu_switch.lua依赖 libmgmt_protocolconfig.ieu_mcu;成功则 SetMcuSwitch('\x01')SetMcuSwitch('\x00')
Nonemux/none.lua空实现空实现

McuSwitch 额外方法:init()switch(data)reboot_action()libmgmt_protocol 加载失败时 init 打 warn 并跳过功能。

返回值与异常

PCA9544 通道号越界抛 request error, invalid PCA9544 channel id。McuSwitch 在依赖缺失或不支持 opcode 0x0201 时直接返回,不抛错。

应用场景

I2C Mux 芯片(PCA954x)后挂 LM75/EEPROM 等器件时,hwproxy 先 open_channel 再访问后级 Chip。

限制条件

Mux 通过 own_chip:write 下发,因此该 Chip 必须已绑定 Driver 与 Bus。McuSwitch 不是纯寄存器 Mux,行为取决于 Riser MCU Capabilities。

调试示例

lua
local mux = require('mux.mux')
local pca9545 = mux.Pca9545.new(own_chip)
pca9545:open_channel(0)   -- 写 0x01 到 offset 0
pca9545:close_channel(0)  -- 写 0x00

2.6 Protocol 协议包装接口

功能说明

Protocol 在 Driver 真正访问总线前改写 inputwrap),并在读回后剥协议头/校验(unwrap)。hwproxy 按芯片 class_name 创建;仅 SmcNone 两种实现。

参数说明

导出键方法说明
Nonewrap(data, _, _) 空实现;unwrap(data, _) 原样返回 data无协议包装。
Smcwrap(input, self_chip, r_chip)unwrap(data, input, self_chip)protocol_flagrw_type 选择 I2C/SMC 转发或 MCTP over SMC 转发。

SMC wrap 行为摘要:

protocol_flagrw_type行为
0x030smc_write_forward_mctp:opcode 0x33,payload 超 250 报错
0x031smc_read_forward_mctp:读缓冲 opcode 0x34
其他0smc_write_forward:opcode 0x30,I2C 或 SMC 目标
其他1smc_read_forward:读缓冲 opcode 0x31,I2C 读会填充 append_write

unwrap 校验 Length、Completion Code 和 CRC8;MCTP 路径截取 data:sub(4, #data - 1)

返回值与异常

payload 超过 MAX_SMC_WRITE_LENGTH(250)时 error('request error, smc wrap exceed maximum payload length')。CC 非成功且非未就绪时抛 {err, cc}。MCTP CRC 不匹配抛 request error, get crc: ...。普通 CRC 不匹配当前仅 log:debug,不抛错。

应用场景

后级芯片挂在 SMC 后面时,前级 protocol.Smc 把 I2C/MCTP 访问转换成 SMC Forward 命令。单元测试 test/unit/test_smc.luatest_mctp_over_smc.lua 覆盖该路径。

限制条件

wrap 会就地修改 inputaddr/offset/buffer/len。多级 SMC 需要 Chip 上的 l_chip 链表由调用方(hwproxy 或测试夹具)维护。

调试示例

lua
local smc_protocol = require('protocol.smc')
local proto = smc_protocol.new()
-- 由 Chip.wrap 沿 l_chip 链路调用:
-- tmp_chip.protocol:wrap(input, tmp_chip, r_chip)

2.7 drvlib_common 辅助函数

功能说明

src/lualib/drvlib_common.lua 提供网络字节序转换,以及扩展读模式常量。

参数说明

符号说明
HAS_EXTEND_CHIP_READ_MODE0xFFFFFFFF,与 Stream/Protocol 中的扩展芯片读偏移相同。
htons(value) / ntohs(value)16 位主机序与网络序互转,返回 2 字节串或整数。
htonl(value) / ntohl(value)32 位主机序与网络序互转。

返回值与异常

转换函数按位运算实现,无额外错误码。

应用场景

Hisport 扩展读、SMC 组包等需要固定字节序的场合。

限制条件

ntohs/ntohl 假定入参已是二进制字符串;长度不足时 string.byte 行为未在本库额外防护。

调试示例

lua
local drvlib_common = require('drvlib_common')
assert(drvlib_common.HAS_EXTEND_CHIP_READ_MODE == 0xFFFFFFFF)

3. 组件扩展案例

3.1 拓展能力概述

本库没有插件加载机制。扩展方式是在对应目录新增 Lua 类,并登记到聚合导出表,使 hwproxy 能按新的 CSR class_name 实例化。

3.2 扩展点说明

扩展点文件说明
器件驱动src/lualib/driver/<name>.luadriver.lua继承 driver.base,实现 read/write 等,并在 driver.lua 增加导出键。
总线 Streamsrc/lualib/stream/<name>.luastream.lua继承 stream.base,实现 init/read/write,通过 open_drive 绑定 libsoc_adapter。
Muxsrc/lualib/mux/<name>.luamux.lua实现 open_channel / close_channel
Protocolsrc/lualib/protocol/<name>.luaprotocol.lua实现 wrap / unwrap
MCU 切换配置src/lualib/config/ieu_mcu.luaMcuSwitch 使用的 SMBus opcode 与 Capabilities 解析。

同步修改 hwproxy 的 object_defs.lua(芯片/总线类型声明)不在本仓库范围内,但新 class_name 必须能被 hwproxy 识别,否则对象不会走到本库。

3.3 二次开发指导

以新增器件驱动为例(与仓库 README 及 driver/lm75.lua 一致):

lua
-- 1. 在 src/lualib/driver 新增 lua 文件
local class = require('mc.class')
local driver = require('driver.base')
local my_chip = class(driver)

function my_chip:ctor(chip, object)
    self.chip_type = 'MyChip'
end

function my_chip:read(input)
    return driver.read(self, input)
end

function my_chip:write(input)
    driver.write(self, input)
end

return my_chip
lua
-- 2. 在 src/lualib/driver/driver.lua 登记
local driver = {
    -- ...
    MyChip = require('driver.my_chip'),
}

验证步骤:

  1. 按仓库既有流程构建并安装到 hwproxy 的 lualib
  2. 在单元测试中 require('driver.driver'),构造假 host_bus 后调用 read/write
  3. 需要总线时再为 Stream 增加用例;SMC 转发可参考 test/unit/test_smc.lua

注意事项:导出键必须与 CSR class_name 完全一致;read/write 最终应回到 driver.base,以便走协议包装和前级总线。

4. 日志说明

4.1 一键日志收集

runtime_accessor 是库,不创建独立日志文件,仓库未注册 on_dump 回调。一键收集是否包含本库日志,取决于宿主 hwproxy 的 dump 配置。dist/config.cfg 写有 logger = "/data/var/log/bmc/runtime_accessor.log",但当前仓库无独立 src/service 进程消费该配置。

实际日志走宿主进程的 mc.logging,常见路径为 hwproxy 日志(如 /data/var/log/bmc 下的 app 日志)。

4.2 关键日志信息

级别典型日志含义
errorfailed to open drive: %s, err: %sstream.open_drive 打开 libsoc_adapter 失败。
errorSelfTest failed: This type of ChipTest is not supported temporarily该 Driver 未设置 chip_type,无法自检。
error%s selfTest failed: The first reading operation failed基类自检第一次读失败。
errorlm75-selfTest failed: The writing operation failedLM75 自检写失败。
errorresponse error, i2c %s fail, ret: %s, input:%sI2C 读写失败(抛错前)。
errorlocalbus invalid id:%s, expect 0~3LocalBus Id 非法。
noticeConfig %s high limitation register ... successfullyLM75 高温阈值配置并回读成功。
noticelocalbus set id:%s config successLocalBus 位宽/偏移配置成功。
warnrequire libmgmt failed, the environment does not support the MCU Switch.无法加载 libmgmt_protocol,McuSwitch 不可用。
debugChip %s fails to write data through the SMBUS protocolSMBus 写失败,随后会尝试重初始化。

5. 问题定界指南

5.1 典型问题定界

问题描述是否为本组件问题判断依据关键证据收集方法
require('driver.driver') 找不到模块可能是安装路径或 hwproxy package.path 未包含本库 lualib检查 /opt/bmc/apps/hwproxy/lualib/driver/driver.lua 是否存在。
request error, Invalid chip typeclass_name 未在 driver.driver 导出表中,落到 driver.None核对 CSR class_namedriver.lua 导出键。
总线读写无效果或空返回可能是class_name 未在 stream.stream 中,落到 stream.None(空 read/write)。核对 Bus 类型是否在 2.1 导出表中;注意 Hisport2 未导出。
response error, i2c read/write fail可能是libsoc_adapter 返回非 0,或 SMBus 切换失败。记录 retinput 的 JSON、总线 Id、是否 protocol_flag=0x02
SMC cc=4 / chip internal error可能是后级芯片或 SMC 应答失败。参考 test_smc.luaret.err / ret.cc;抓 I2C 与 SMC opcode。
PCA9544 invalid channel id通道号 >= 4检查 Mux id 与硬件通道数。
McuSwitch 无切通道动作可能是libmgmt_protocol 未加载,或 Capabilities 不含 0x0201检索 require libmgmt failed / get %s smbus Capabilities failed
打开驱动失败可能是libsoc_adapter.<bus> 不存在或 new 失败。检索 failed to open drive

5.2 错误码速查表

错误来源含义排查建议
request error, Invalid chip typedriver.None未知器件类型。补齐导出或修正 class_name
request error, invalid input lengthLm75/Pca954x/Pca9555 等len 不符合器件约束。按器件文档核对 len
request error, invalid input mask: 0Pca9555位写 mask 为 0。传入非 0 mask。
request error, input len too longI2c写长度大于 1100。拆分写入。
request error, offsetWidth is invalidI2c/Hisport偏移宽度大于 4。修正 CSR OffsetWidth
request error, i2c smbus init failedI2c高速档不允许该 SMBus deploy。检查 Speed
request error, smc wrap exceed maximum payload lengthprotocol.SmcForward payload > 250。减小一次转发长度。
response error, reinit i2c failI2c失败后重新 init 仍失败。检查控制器与 libsoc_adapter.i2c
SMC cc 1/3/4/5Driver/Protocol SMCopcode/参数/内部/CRC 错误。对照 2.3 节 CC 表。
I2C ret == 19I2cENODEV,会尝试重初始化。确认总线与从设备在位。

5.3 最小化复现与证据收集

  1. 记录 CSR class_name、总线类型、器件地址、offset/len/mask/typeprotocol_flag
  2. 在 hwproxy 日志中检索 failed to open drivei2c ... failselfTest failed、SMC completion code
  3. 用假 host_bustest/unit 下复现 Driver/Protocol(无需真实硬件)。
  4. 确认 /opt/bmc/apps/hwproxy/lualib/{driver,stream,mux,protocol} 已按 dist/permissions.ini 部署。

5.4 调试方法

  • 运行 test/unit/test.lua(含 test_smctest_mctp_over_smctest_rtctest_ina)。
  • 在 hwproxy 侧打开 debug 日志,观察 SMBus 切换与 SMC CRC debug。
  • 对 Mux 问题先确认 open_channel 写入值(PCA9545 为 1<<id,PCA9544 为 0x04|id)。

6. 常见问题解答

Q1:require('driver.driver') 失败怎么办?

  • 问题描述:Lua 报 module not found。
  • 一句话答案:本库安装在 hwproxy 的 lualib 下,必须在 hwproxy 进程的 Lua 路径中加载。
  • 根因说明:未随 hwproxy 部署,或在其他进程中直接 require 且未设置搜索路径。
  • 解决方案:确认 /opt/bmc/apps/hwproxy/lualib/driver/driver.lua 存在,并在 hwproxy 环境中调用。
  • 规避方案:不要把本库当作独立服务启动;不要只拷贝单个 lua 文件。
  • 适用版本:1.130.9。

Q2:读写落到空实现或 Invalid chip type

  • 问题描述:访问无数据,或抛 request error, Invalid chip type
  • 一句话答案:class_name 与四个导出表的键不一致,分别回退到 stream.Nonedriver.None
  • 根因说明:hwproxy 使用 table[class_name] or None,不会因未知类型立即失败。
  • 解决方案:对照 2.1 节导出键修正 CSR;新增类型必须同时改导出表。
  • 规避方案:变更 CSR 类型名时同步改 driver.lua / stream.lua / mux.lua / protocol.lua
  • 适用版本:1.130.9。

Q3:如何确认问题在器件驱动还是总线上?

  • 问题描述:Chip 读失败,不确定是 Driver、Protocol 还是 Stream。
  • 一句话答案:先看错误字符串前缀和是否含 SMC cc;再看是否已 open_drive 成功。
  • 根因说明:Driver 负责组包与器件语义,Stream 负责 libsoc_adapter 返回码,Protocol 只在 SMC 链路上改写 input
  • 解决方案:Invalid chip type/长度/mask 错误偏 Driver;i2c fail/failed to open drive 偏 Stream;smc wrap/completion code 偏 Protocol/SMC。
  • 规避方案:用 test_smc.lua 风格的假 host_bus 隔离 Driver/Protocol。
  • 适用版本:1.130.9。

Q4:本组件能否用 busctl 调试?

  • 问题描述:希望像其他业务组件一样 introspect D-Bus 接口。
  • 一句话答案:不能。本组件是 library,没有资源协作接口。
  • 根因说明:仓库仅有 mds/service.json,无 mds/model.json,也无 IPMI 命令定义。
  • 解决方案:在 hwproxy 侧查看 Chip 对象与访问日志,或跑本仓库单元测试。
  • 规避方案:不要为 runtime_accessor 查找 bmc.kepler.runtime_accessor 服务名。
  • 适用版本:1.130.9。