openbmc开发22:添加sensor信息到ipmi

前面说过如何添加sensor传感器信息(I2C、ADC、FAN),这些信息添加后是可以展示到web页面,而不能通过ipmitool工具展示出来,那么怎么才能把这些传感器信息添加到ipmi中呢?别着急,下面将一一道来。

1 ipmi配置文件转换成cpp

在软件包下有一个scripts文件夹,这里边是python脚本、模板、示例yaml文件以及使用说明,本内容介绍sensor的yaml文件。在configure阶段,通过autoconf工具,解析configure.ac以及Makefile.am生成Makefile文件,在编译阶段执行sensor_gen.py的python脚本,利用writesensor.mako.cpp模板,并根据sensor.yaml文件生成sensor-gen.cpp文件。
script

2 配置ipmi配置文件

指定自己sensor的yaml文件,有两种方法:
方法一:
通过安装覆盖的方式。参考meta-ibm/meta-romulus。
1 、在your-layer下创建recipes-phosphor/configuration文件夹,创建xxx-yaml-config文件夹和xxx-yaml-config.bb文件,xxx-yaml-config文件夹中存放yaml文件,xxx-yaml-config.bb文件中SRC_URI指定该yaml文件。xxx-yaml-config.bb文件内容如下:

SUMMARY = "YAML configuration for xxx"
PR = "r1"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"

inherit allarch

SRC_URI = " file://xxx-ipmi-sensors.yaml "

S = "${WORKDIR}"

do_install() {
    install -m 0644 -D xxx-ipmi-sensors.yaml \
        ${D}${datadir}/${BPN}/ipmi-sensors.yaml
}
FILES_${PN}-dev = "  ${datadir}/${BPN}/ipmi-sensors.yaml "

内容
2、在your-layer/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend文件中添加如下内容:

DEPENDS_append = " xxx-yaml-config"

EXTRA_OECONF = " SENSOR_YAML_GEN=${STAGING_DIR_HOST}${datadir}/xxx-yaml-config/ipmi-sensors.yaml "

ipmi-host
configuration

方法二:
在your-layer/conf/machine/machine.conf中指定配置文件。可参考meta-quanta/meta-q71l
1、machine.conf添加内容如下

PREFERRED_PROVIDER_virtual/phosphor-ipmi-sensor-inventory = "xxx-ipmi-sensor-map-native"

2、在your-layer/recipes-phosphor/ipmi/下创建xxx-ipmi-sensor-map-native文件夹和xxx-ipmi-sensor-map-native.bb文件,xxx-ipmi-sensor-map-native文件夹下放yaml文件,xxx-ipmi-sensor-map-native.bb文件内容如下

SUMMARY = "IPMI to DBus Sensor mapping."
PR = "r1"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"

inherit native
inherit phosphor-ipmi-host

PROVIDES += "virtual/phosphor-ipmi-sensor-inventory"

SRC_URI += "file://xxx.yaml"

S = "${WORKDIR}"

do_install() {
	DEST=${D}${sensor_datadir}
        install -d ${DEST}
	install xxx.yaml ${DEST}/sensor.yaml
}

bb
ipmi

方法一要注意“SENSOR_YAML_GEN”变量的值,一定要是自己配置文件中ymal文件安装的路径,至于文件名可以自己定义,只要“SENSOR_YAML_GEN”指定实际名称即可。
方法二安装的位置和文件名都是固定( D {D} D{sensor_datadir}/sensor.yaml),包括文件名都是固定的,这是因为在phospho-ipmi-host.bb文件中给“SENSOR_YAML_GEN”指定了该位置,我们把文件安装到固定的位置即可(在phospho-ipmi-hostd/configure.ac中有判断,如果路径下文件不存在使用script下的yaml文件)。
这两种方法选取一种即可,如果想灵活配置可以两种方法组合:按照方法二进行分类文件夹,按照方法一时,一定要在phosphor-ipmi-host_%.bbappend中指定“SENSOR_YAML_GEN”的路径,具体可以自行尝试。
如果同soc有多个不同的平台,最好两种方法不要混用,不然会报错,报错只需要执行“bitbake phosphor-ipmi-host -c cleansstate”命令从新编译即可。
ob下还提供了mrw的方法:通过脚本将mxl文件转换成yaml文件,针对的是比较老的版本,有兴趣可以自行尝试。

3 yaml文件

yaml文件在configure时会调用python生成cpp文件,将文件内容转换成IdInfoMap的map类型的常量,具体请参看源码下include/ipmid/types.hpp文件。
sensor.yaml文件示例:(更多请参看scripts/sensor-example.yaml文件)

0x01:
  entityID: 0x01
  sensorType: 0x01
  path: /xyz/openbmc_project/sensors/temperature/temp1
  sensorReadingType: 0x01
  multiplierM: 1
  offsetB: 0
  bExp: 0
  unit: xyz.openbmc_project.Sensor.Value.Unit.DegreesC
  scale: -3
  rExp: 0
  mutability: Mutability::Read
  serviceInterface: org.freedesktop.DBus.Properties
  readingType: readingData
  interfaces:
    xyz.openbmc_project.Sensor.Value:
      Value:
        Offsets:
          0x0:
            type: int64_t

entityID #指定传感器entityID,具体见ipmi协议2.0中的43.14小结节
entityInstance #示例标号,相同entityID的sensor,要有不同的entityInstance编号进行区分,每个类型从0开始,具体见ipmi协议2.0中的39.1小结节
sensorType #传感器类型,具体见ipmi协议2.0中42.2小节
path #传感器Dbus对象
sensorReadingType #传感器读类型具体见ipmi协议2.0中42.1小节
sensorNamePattern #可以给定字符串(最大长度为16),或者使用如下方式从path或者属性中获取

nameLeaf:从path中解析(最后一个“/”后面的为传感器名)得到,一般用这个。
nameParentLeaf:从path中解析,后两个为传感器名,例如“path:/xyz/openbmc_project/sensors/temperature/temp1”,怎传感器名为“temperature_temp1”
nameProperty:传感器名即interfaces的属性
interfaces:
xyz.openbmc_project.Control.Boot.RebootAttempts:
AttemptsLeft:
Offsets:
0xFF:
type: uint32_t
则传感器名为“AttemptsLeft”

multiplierM #ipmi协议中的算子,一般multiplierM*255 要稍大于可能的最大值,以保证精度
offsetB #偏移量
bExp #offsetB的指数,一般给0
unit #传感器单位,配置文件做了转换为字符串,具体见ipmi协议2.0中42.17小节
scale #缩放因子,是10的指数,一般温度电压等都是-3,即读取值是实际值的1000倍
rExp #和scale一样的指数,一般给0

1、scale是用于ipmid程序将从传感器中得到的值转化成实际值,一般hwmonz子系统中,传感器驱动创建的文件中存放的都是将实际值放大1000倍的值,因此sclae=-3 。如果自己写的驱动或者创建的文件中存放的值是实际值,则scale=0。

如hwmon子系统创建的文件 /sys/class/hwmon/hwmon1/temp1_input中的值是52000,则scal=-3。
如自己创建的文件/var/hwmon/hwmon0/temp1_input中值是52,则scale=0。

2、ipmi协议中一般阈值型传感器是有计算公式的(参见ipmi协议2.0的36.3小节),在ipmid程序中需要通过计算得到公式的中x值,并返回给发起者(netfn=04,cmd=0x21)。
3、配置文件中配置这些值会转化到ipmi协议数据中(multiplierM一个字节,offsetB一个字节,bExp(低4bits)和rExp(高4bits)一个字节,具体参见ipmi协议第43小节),命令发起者得到数据后,利用公式计算得到实际值,计算值的范围是[ offsetB * 10 ^bExp, multiplierM255 + offsetB * 10 ^bExp] * 10 ^rExp。在不考虑rExp和offsetB的情况下(rExp=bExp=0),计算值y的最大范围是[0,65025](此时 multiplierM=255)。
4、一般除了温度外,offsetB=0,rExp=-3,即计算值y的最大范围是[0, 65.25],为了保证精度,我们可以调小multiplierM值,尽量使最大值稍大于阈值中设置的最大值。快速计算:multiplierM=(最大阈值 - offsetB
10 ^bExp) /255向上取整数。

例如例如12V的电压传感器,假设阈值中设置最大上限值是14V,则可以设置 multiplierM = 14000/255 ≈55(向上取整),即配置文件中内容如下:
multiplierM=55
offsetB=0
bExp=0
scale=-3
rExp=-3

5、 一般温度传感器multiplierM=1,offsetB=-127,scale =-3, bExp =0,rExp=0,计算的y值范围是[-127,128]基本满足正常使用情况。

一般温度下限可能到不了-127,我们可以调整offsetB为-100,这样取值范围是[-100, 155]。
如果想提高精度,可以給rExp=-2, bExp=2,multiplierM=100,offsetB=-100,这样取值范围是[-100,155],并且可以显示两位小数。

6、ipmi计算得到的值和ipmid程序获取到的值是有细微的差距,例如bmcweb页面上显示的阈值是配置文件设置的值(一般在/etc/default/obmc/hwmon下),但是ipmitool显示是略小于设置的阈值。这是因为在计算得到 multiplierM和x都是8bits的整数,为了包含最大的阈值,进行了稍微的放大(向上取整),这样ipmid在计算时以及ipmitool计算时会存在除法除不尽时候的舍去误差,因此为了尽量缩小误差,尽量取最小满足条件的 multiplierM值( multiplierM越大,误差也越大(当然一些值和rExp也有关系))。

hasScale #是否缩放,取值“true”或者“false”
mutability # Mutability::Read和 Mutability::Write,用于设置是否可读写
serviceInterface #传感器DBus服务接口,不同的

org.freedesktop.DBus.Properties #属性类,set设置属性,get获取属性
xyz.openbmc_project.Inventory.Manager #管理类,get获取,notify通知

readingType #获取dbus接口值或者属性等的方法,这里是指定的是调用的函数名

readingType和 serviceInterface接口有关,get(netfn cmd 0x4 0x2D)方法有四种,set(netfn cmd 0x4 0x30)方法有6种,对于接口时xyz.openbmc_project.Inventory.Manager的只有assertion一种,对于yaml文件一定不要写错了,这几种对应的是函数。
readingAssertion #传感器有效状态作为值类型
readingData #读取值常用的温度电压传感器
assertion #bool有效型
eventdata # 紧set方法有
eventdata1 # 紧set方法才有
eventdata2 #属性值是字符串
更多请参看源码下的sensordatahandler.hpp和sensordatahandler.cpp文件

interfaces #获取传感器信息Dbus的接口

xyz.openbmc_project.Sensor.Value #获取传感器值接口
xyz.openbmc_project.State.Boot.Progress #启动进度
xyz.openbmc_project.State.OperatingSystem.Status #系统启动方式
xyz.openbmc_project.Inventory.Manager #资产类,比如内存条、CPU核等
。。。。更多见DBus接口(cmd:busctrl tree)

Value #Dbus对应接口的的属性,常见的温度电压等传感器都是value

Present #在位
Functional #
Prereqs #

Offsets#指定数据偏移字节,不同传感器类型偏移不一样,具体见ipmi协议2.0中42.2小节
type #vlaue的类型,一般传感器值是int64_t或者double,离散量是bool或者string
skipOn #指定跳过跟新类型,一般离散量不在位不能更新。

xyz.openbmc_project.Inventory.Item:
Present:
Offsets:
0x07:
assert: true
deassert: false
skipOn: deassert
type: bool

entityID表:
entityID
sensorType表:
sensorType
sensorReadingType表:
sensorReadingType
传感器值转换公式:(L:一般没有,k1:bExp,k2:rExp)
Formula

注:
1、这里/xyz/openbmc_project/sensors/temperature/tempx中的tempx要和recipes-phosphor/sensors中传感器配置文件中LABEL_tempx的值保持一致,因为hwmon创建的dbus对象是根据sensor配置文件来的。
2、这里只说明了标准的阈值型的传感器,其他类型的可以参考openbmc下其他机型以及phosphor-ipmi-host源码中scripts下的sensor-example.yaml文件。
3、如果想研究yaml文件如何转换成sensor-gen.cpp文件,请看phosphor-ipmi-host源码中scripts下sensor_gen.py、writesensor.mako.cpp以及Makefile.am和Configure.ac文件。

4 编译及结果

没有给定sensor.yaml文件时,使用的是默认的,结果如下
ipmi默认sensor信息
修改后
ipmitool-sensor
这里一个值都没有是因为,romulus-bmc的虚拟机没有模拟外部的温度芯片,如果在实际机型上运行,则会展示传感器值以及阈值等信息。