1.说明
参考文档:
- https://github.com/openbmc/entity-manager/blob/master/docs/entity_manager_dbus_api.md
- https://github.com/openbmc/entity-manager/blob/master/docs/my_first_sensors.md
1.1 简单介绍
注意: 本节是快速浏览整个sensor
框架,了解大致openbmc sensor
的运行机制。难免会有相关描述不当,谨慎阅读。
本节主要简述怎么让sensor
在openbmc
上运行起来。 sensor
包含物理硬件数据的读取与sensor
相关的配置信息,例如阈值,sensor
名字(ipmitool sensor list
出来的名字)。
在openbmc
上讲究的均为功能分离,模块化的管理。因此,简单说涉及到几个文件:
- 内核
hwmon
: 底层实际和物理硬件通信,获取实际的数据。 - https://github.com/openbmc/dbus-sensors,实际应用层获取
sensor数据
,暴露到dbus
上 - https://github.com/openbmc/entity-manager,
sensor
的配置信息,暴露到dbus
上。
1.2 文件关系与文档
- 内核
hwmon
: 底层实际和物理硬件通信,获取实际的数据。 - https://github.com/openbmc/dbus-sensors,实际应用层获取
sensor数据
,暴露到dbus
上 - https://github.com/openbmc/entity-manager,
sensor
的配置信息,暴露到dbus
上。
hwmon
介绍上描述的均为让温度、电压、风扇、电源等设备管理的更加的方便。
摘抄一下文件:linux-aspeed/drivers/hwmon/hwmon.c
中的描述:
hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
This file defines the sysfs class "hwmon", for use by sensors drivers.
所以,简单说,hwmon
定义了sysfs
接口,硬件监控的数据获取均从sysfs
接口拿到。
参考阅读文档:
linux/Documentation/hwmon/hwmon-kernel-api.rst
linux/include/linux/hwmon-sysfs.h
分析hwmon
会发现openbmc
将物理sensor
的数据获取下放到kernel driver
层。这还是对于驱动的稳定性抱很大的信心哪。
2.分析hwmon
2.1 目录内容
查看目录,可以看到如下图所示内容:
2.2 驱动分析
驱动代码位置在:kernel/linux/drivers/hwmon/hwmon.c
,先分析一下该文件,然后延申,了解整个驱动框架做了什么事情。
2.2.1 文件kernel/linux/drivers/hwmon/hwmon.c
分析
1.入口函数
入口函数为:hwmon_init()
,调用内容如下:
static int __init hwmon_init(void)
---> hwmon_pci_quirks();
---> #if defined CONFIG_X86 && defined CONFIG_PCI //不定义这2项,函数代码是不执行的
---> class_register(&hwmon_class);
看一下hwmon_class
的定义:
static struct class hwmon_class = {
.name = "hwmon",
.owner = THIS_MODULE,
.dev_groups = hwmon_dev_attr_groups,
.dev_release = hwmon_dev_release,
};
总体而言,初始化之后,在openbmc
下显示的效果为在目录/sys/class
下创建了hwmon
目录。
2.结构体.dev_groups = hwmon_dev_attr_groups
定义如下:
static const struct attribute_group *hwmon_dev_attr_groups[] = {
&hwmon_dev_attr_group,
NULL
};
其中:
static const struct attribute_group hwmon_dev_attr_group = {
.attrs = hwmon_dev_attrs,
.is_visible = hwmon_dev_name_is_visible,
};
另外:
static struct attribute *hwmon_dev_attrs[] = {
&dev_attr_name.attr,
NULL
};
看到全局定义一个结构体:
static DEVICE_ATTR_RO(name);
找到文件:linux/include/linux/device.h
,定义如下:
#define DEVICE_ATTR_RO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
找到文件:linux/include/linux/sysfs.h
,定义如下:
#define __ATTR_RO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0444 }, \
.show = _name##_show, \
}
因此,文件中定义了内容:
struct device_attribute dev_attr_name =
{
.attr = { .name = __stringify(_name), .mode = 0444 },
.show = name_show,
}
在看一个函数name_show(struct device *dev, struct device_attribute *attr, char *buf)
的定义:
static ssize_t
name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", to_hwmon_device(dev)->name);
}
所以,整个框架基本成型,hwmon
利用sysfs
接口对外提供数据接口能力。
那它当前支持哪些硬件的监控? 可以看文件linux/include/linux/hwmon.h
中的如下代码:
enum hwmon_sensor_types {
hwmon_chip,
hwmon_temp,
hwmon_in,
hwmon_curr,
hwmon_power,
hwmon_energy,
hwmon_humidity,
hwmon_fan,
hwmon_pwm,
hwmon_intrusion,
hwmon_max,
};
即,包含了:hwmon_temp
、hwmon_in
、hwmon_curr
、hwmon_power
、hwmon_energy
、hwmon_humidity
、hwmon_fan
等硬件。
3.硬件设备支持
可以看到,有3种函数调用关系:
- 第一种,描述的是过时的调用关系,使用函数
hwmon_device_register()
:
struct device *hwmon_device_register(struct device *dev)
---> dev_warn(dev,
"hwmon_device_register() is deprecated. Please convert the driver to use hwmon_device_register_with_info().\n");
---> __hwmon_device_register(dev, NULL, NULL, NULL, NULL);
- 第二种, 使用函数
hwmon_device_register_with_info()
:
struct device *
devm_hwmon_device_register_with_info(struct device *dev, const char *name,
void *drvdata,
const struct hwmon_chip_info *chip,
const struct attribute_group **groups)
---> hwdev = hwmon_device_register_with_info(dev, name, drvdata, chip,
groups);
---> if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info))
return ERR_PTR(-EINVAL);
---> __hwmon_device_register(dev, name, drvdata, chip, extra_groups);
- 第三种,使用函数
devm_hwmon_device_register_with_groups()
:
struct device *
devm_hwmon_device_register_with_groups(struct device *dev, const char *name,
void *drvdata,
const struct attribute_group **groups)
---> hwdev = hwmon_device_register_with_groups(dev, name, drvdata, groups);
---> __hwmon_device_register(dev, name, drvdata, NULL, groups);
4.举例
拿一个简单的代码例子:linux/drivers/hwmon/ad7314.c
:
static int ad7314_probe(struct spi_device *spi_dev)
---> hwmon_dev = devm_hwmon_device_register_with_groups(&spi_dev->dev,
spi_dev->modalias,
chip, ad7314_groups);
另外,ad7314_groups
定义如下:
ATTRIBUTE_GROUPS(ad7314);
#define ATTRIBUTE_GROUPS(_name) \
static const struct attribute_group _name##_group = { \
.attrs = _name##_attrs, \
};
static struct attribute *ad7314_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
NULL,
};
#define SENSOR_DEVICE_ATTR_RO(_name, _func, _index) \
SENSOR_DEVICE_ATTR(_name, 0444, _func##_show, NULL, _index)
static SENSOR_DEVICE_ATTR_RO(temp1_input, ad7314_temperature, 0);
#define SENSOR_DEVICE_ATTR(_name, _mode, _show, _store, _index) \
struct sensor_device_attribute sensor_dev_attr_##_name \
= SENSOR_ATTR(_name, _mode, _show, _store, _index)
static ssize_t ad7314_temperature_show(struct device *dev,
struct device_attribute *attr,
char *buf)
参考文件:
linux/include/linux/hwmon-sysfs.h
linux/include/linux/sysfs.h
linux/include/linux/device.h
linux/include/linux/hwmon.h
3.分析dbus-sensors
3.1 dbus-sensors
的目标
dbus-sensors
的实现仓库为: https://github.com/openbmc/dbus-sensors
dbus-sensors is a collection of sensor applications that provide the
xyz.openbmc_project.Sensor collection of interfaces. They read sensor
values from hwmon, d-bus, or direct driver access to provide readings.
Some advance non-sensor features such as fan presence, pwm control,
and automatic cpu detection (x86) are also supported.
因此,其目的即实现了实际的硬件数据的读取,并能将数据暴露给dbus
,供其他应用程序使用。
3.2 目录结构
目录结构如下:
# tree
.
└── dbus-sensors-master
├── include
│ └── linux
│ └── peci-ioctl.h
├── LICENSE
├── meson.build
├── meson.options
├── OWNERS
├── README.md
├── service_files
│ ├── meson.build
│ ├── xyz.openbmc_project.adcsensor.service
│ ├── xyz.openbmc_project.exitairsensor.service
│ ├── xyz.openbmc_project.externalsensor.service
│ ├── xyz.openbmc_project.fansensor.service
│ ├── xyz.openbmc_project.hwmontempsensor.service
│ ├── xyz.openbmc_project.intelcpusensor.service
│ ├── xyz.openbmc_project.intrusionsensor.service
│ ├── xyz.openbmc_project.ipmbsensor.service
│ ├── xyz.openbmc_project.mctpreactor.service
│ ├── xyz.openbmc_project.mcutempsensor.service
│ ├── xyz.openbmc_project.nvmesensor.service
│ └── xyz.openbmc_project.psusensor.service
├── src
│ ├── adc
│ │ ├── ADCSensor.cpp
│ │ ├── ADCSensor.hpp
│ │ ├── ADCSensorMain.cpp
│ │ └── meson.build
│ ├── dbus-sensor_config.h.in
│ ├── DeviceMgmt.cpp
│ ├── DeviceMgmt.hpp
│ ├── exit-air
│ │ ├── ExitAirTempSensor.cpp
│ │ ├── ExitAirTempSensor.hpp
│ │ └── meson.build
│ ├── external
│ │ ├── ExternalSensor.cpp
│ │ ├── ExternalSensor.hpp
│ │ ├── ExternalSensorMain.cpp
│ │ └── meson.build
│ ├── fan
│ │ ├── FanMain.cpp
│ │ ├── meson.build
│ │ ├── PresenceGpio.cpp
│ │ ├── PresenceGpio.hpp
│ │ ├── TachSensor.cpp
│ │ └── TachSensor.hpp
│ ├── FileHandle.cpp
│ ├── FileHandle.hpp
│ ├── hwmon-temp
│ │ ├── HwmonTempMain.cpp
│ │ ├── HwmonTempSensor.cpp
│ │ ├── HwmonTempSensor.hpp
│ │ └── meson.build
│ ├── intel-cpu
│ │ ├── IntelCPUSensor.cpp
│ │ ├── IntelCPUSensor.hpp
│ │ ├── IntelCPUSensorMain.cpp
│ │ └── meson.build
│ ├── intrusion
│ │ ├── ChassisIntrusionSensor.cpp
│ │ ├── ChassisIntrusionSensor.hpp
│ │ ├── IntrusionSensorMain.cpp
│ │ └── meson.build
│ ├── ipmb
│ │ ├── IpmbSDRSensor.cpp
│ │ ├── IpmbSDRSensor.hpp
│ │ ├── IpmbSensor.cpp
│ │ ├── IpmbSensor.hpp
│ │ ├── IpmbSensorMain.cpp
│ │ └── meson.build
│ ├── mctp
│ │ ├── MCTPDeviceRepository.hpp
│ │ ├── MCTPEndpoint.cpp
│ │ ├── MCTPEndpoint.hpp
│ │ ├── MCTPReactor.cpp
│ │ ├── MCTPReactor.hpp
│ │ ├── MCTPReactorMain.cpp
│ │ └── meson.build
│ ├── mcu
│ │ ├── MCUTempSensor.cpp
│ │ ├── MCUTempSensor.hpp
│ │ └── meson.build
│ ├── meson.build
│ ├── nvme
│ │ ├── meson.build
│ │ ├── NVMeBasicContext.cpp
│ │ ├── NVMeBasicContext.hpp
│ │ ├── NVMeContext.hpp
│ │ ├── NVMeSensor.cpp
│ │ ├── NVMeSensor.hpp
│ │ └── NVMeSensorMain.cpp
│ ├── psu
│ │ ├── meson.build
│ │ ├── PSUEvent.cpp
│ │ ├── PSUEvent.hpp
│ │ ├── PSUSensor.cpp
│ │ ├── PSUSensor.hpp
│ │ └── PSUSensorMain.cpp
│ ├── PwmSensor.cpp
│ ├── PwmSensor.hpp
│ ├── sensor.hpp
│ ├── SensorPaths.cpp
│ ├── SensorPaths.hpp
│ ├── tests
│ │ ├── meson.build
│ │ ├── test_IpmbSensor.cpp
│ │ ├── test_MCTPEndpoint.cpp
│ │ ├── test_MCTPReactor.cpp
│ │ └── test_Utils.cpp
│ ├── Thresholds.cpp
│ ├── Thresholds.hpp
│ ├── Utils.cpp
│ ├── Utils.hpp
│ └── VariantVisitors.hpp
└── subprojects
├── boost.wrap
├── googletest.wrap
├── libgpiod.wrap
├── libpeci.wrap
├── liburing.wrap
├── nlohmann_json.wrap
├── packagefiles
│ └── boost
│ └── meson.build
├── phosphor-logging.wrap
└── sdbusplus.wrap
21 directories, 107 files
从目录service_files
中,可以看到openbmc
将每一种类型的sensor
做成了一个服务。
4.分析entity-manager
4.1 目录结构
目录结构如下:
# tree
.
└── entity-manager-master
├── blacklist.json
├── CONFIG_FORMAT.md
├── configurations
│ ├── 1ux16_riser.json
│ ├── 2ux8_riser.json
│ ├── 3ypower_vast2112_psu.json
│ ├── 8x25_hsbp.json
│ ├── a2ul16riser.json
│ ├── a2ux8x4riser.json
│ ├── acbell_rica_psu.json
│ ├── acbel_r1ca2122a_psu.json
│ ├── ahw1um2riser.json
│ ├── aspower_u1a-d10550_psu.json
│ ├── aspower_u1a-d10800_psu.json
│ ├── aspower_u1a-d11200_psu.json
│ ├── aspower_u1a-d11600_psu.json
│ ├── aspower_u1d-d10800_psu.json
│ ├── asrock_c3_medium_x86.json
│ ├── asrock_e3c246d4i.json
│ ├── asrock_e3c256d4i.json
│ ├── asrock_m3_small_x86.json
│ ├── asrock_n3_xlarge_x86.json
│ ├── asrock_romed8hm3.json
│ ├── asrock_spc621d8hm3.json
│ ├── axx1p100hssi_aic.json
│ ├── axx2prthdhd.json
│ ├── bellavista.json
│ ├── blueridge_1s4u_chassis.json
│ ├── blueridge_2u_chassis.json
│ ├── blueridge_4u_chassis.json
│ ├── blyth.json
│ ├── bnp_baseboard.json
│ ├── bonnell.json
│ ├── brcm_100g_1p_ocp_mezz.json
│ ├── brcm_200g_1p_ocp_mezz.json
│ ├── compuware_cdr_9011_3m1_psu.json
│ ├── cx7_ocp.json
│ ├── delta_awf2dc3200w_psu.json
│ ├── delta_dps-1600ab_psu.json
│ ├── delta_dps-2000ab_psu.json
│ ├── delta_dps-750xb_psu.json
│ ├── everest.json
│ ├── f1u12x25_hsbp.json
│ ├── f1u4x25_hsbp.json
│ ├── f2u12x35_hsbp.json
│ ├── f2u8x25_hsbp.json
│ ├── flextronics_s-1100adu00-201_psu.json
│ ├── fp5280g3_chassis.json
│ ├── fp5280g3_fanboard.json
│ ├── fuji.json
│ ├── genesis3_baseboard.json
│ ├── genesis3_chassis.json
│ ├── genesis3_psu.json
│ ├── gospower_g1136-1300wna_psu.json
│ ├── ibm_tacoma_rack_controller.json
│ ├── ingraham.json
│ ├── intel_front_panel.json
│ ├── kudo_bmc.json
│ ├── kudo_motherboard.json
│ ├── meta
│ │ ├── bletchley_baseboard.json
│ │ ├── bletchley_chassis.json
│ │ ├── bletchley_frontpanel.json
│ │ ├── bmc_storage_module.json
│ │ ├── catalina_fio.json
│ │ ├── catalina_hdd.json
│ │ ├── catalina_hdd_nvme.json
│ │ ├── catalina_osfp.json
│ │ ├── catalina_pdb.json
│ │ ├── catalina_scm.json
│ │ ├── fbtp.json
│ │ ├── fbyv2.json
│ │ ├── fbyv35.json
│ │ ├── fbyv35_nic_mellanox.json
│ │ ├── greatlakes.json
│ │ ├── greatlakes_nic_mellanox.json
│ │ ├── harma_bsm.json
│ │ ├── harma_fanboard.json
│ │ ├── harma_mb.json
│ │ ├── harma_mb_vr_infineon.json
│ │ ├── harma_scm.json
│ │ ├── minerva_cmm_bsm.json
│ │ ├── minerva_cmm_hsc_infineon.json
│ │ ├── minerva_cmm.json
│ │ ├── minerva_cmm_scm.json
│ │ ├── minerva_fanboard.json
│ │ ├── minerva_pdb_hsc_xdp.json
│ │ ├── minerva_pdb.json
│ │ ├── minerva_pttv.json
│ │ ├── minerva_sitv.json
│ │ ├── terminus_2x100g_nic_tsff.json
│ │ ├── twinlake.json
│ │ ├── ventura_fanboard.json
│ │ ├── ventura_ioboard.json
│ │ ├── ventura_ledboard.json
│ │ ├── ventura_rmc.json
│ │ ├── ventura_scm.json
│ │ ├── yosemite4_chassis.json
│ │ ├── yosemite4_cpu.json
│ │ ├── yosemite4_fanboard_fsc_max_adc_ti_led_nxp_efuse_max.json
│ │ ├── yosemite4_fanboard_fsc_max_adc_ti_led_nxp_efuse_mps.json
│ │ ├── yosemite4_fanboard_fsc_nct_adc_max_led_ons_efuse_max.json
│ │ ├── yosemite4_fanboard_fsc_nct_adc_max_led_ons_efuse_mps.json
│ │ ├── yosemite4_floatingfalls.json
│ │ ├── yosemite4.json
│ │ ├── yosemite4_medusaboard_adc_rns_12vhsc_adi_48vhsc_inf.json
│ │ ├── yosemite4_medusaboard_adc_rns_12vhsc_mps_48vhsc_adi.json
│ │ ├── yosemite4_medusaboard_adc_rns_12vhsc_mps_48vhsc_inf.json
│ │ ├── yosemite4_medusaboard_adc_rns_hsc_adi.json
│ │ ├── yosemite4_medusaboard_adc_rns_isl_12vhsc_adi_48vhsc_inf.json
│ │ ├── yosemite4_medusaboard_adc_rns_isl_12vhsc_mps_48vhsc_adi.json
│ │ ├── yosemite4_medusaboard_adc_rns_isl_12vhsc_mps_48vhsc_inf.json
│ │ ├── yosemite4_medusaboard_adc_rns_isl_hsc_adi.json
│ │ ├── yosemite4_medusaboard_adc_ti_12vhsc_adi_48vhsc_inf.json
│ │ ├── yosemite4_medusaboard_adc_ti_12vhsc_mps_48vhsc_adi.json
│ │ ├── yosemite4_medusaboard_adc_ti_12vhsc_mps_48vhsc_inf.json
│ │ ├── yosemite4_medusaboard_adc_ti_hsc_adi.json
│ │ ├── yosemite4n.json
│ │ ├── yosemite4_sentineldome_chassis.json
│ │ ├── yosemite4_sentineldome_t1.json
│ │ ├── yosemite4_sentineldome_t1_retimer.json
│ │ ├── yosemite4_sentineldome_t2.json
│ │ ├── yosemite4_sentineldome_t2_retimer.json
│ │ ├── yosemite4_spiderboard_adc_max_pwr_ti.json
│ │ ├── yosemite4_spiderboard_adc_ti_pwr_ti.json
│ │ └── yosemite4_wailuafalls.json
│ ├── micron_7450.json
│ ├── mori_bmc.json
│ ├── mori_motherboard.json
│ ├── mtjade.json
│ ├── mtjefferson_bmc.json
│ ├── mtjefferson_bp.json
│ ├── mtjefferson_mb.json
│ ├── mtmitchell_bmc.json
│ ├── mtmitchell_bp.json
│ ├── mtmitchell_mb.json
│ ├── mtmitchell_riser.json
│ ├── mudflap.json
│ ├── nf5280m7_baseboard.json
│ ├── nisqually.json
│ ├── nuvoton_npcm8xx_evb.json
│ ├── nvidia_gb200_io_board.json
│ ├── nvidia_gb200.json
│ ├── nvidia_hmc.json
│ ├── nvme_intel_p_series.json
│ ├── nvme_p4500_p5500.json
│ ├── pcie_ssd_retimer.json
│ ├── pennybacker.json
│ ├── pssf132202a.json
│ ├── pssf162205a.json
│ ├── pssf212201a.json
│ ├── pssf222201a.json
│ ├── r1000_chassis.json
│ ├── r2000_chassis.json
│ ├── rainier_1s4u_chassis.json
│ ├── rainier_2u_chassis.json
│ ├── rainier_4u_chassis.json
│ ├── sas_module.json
│ ├── sbp1_baseboard.json
│ ├── sbp1_chassis.json
│ ├── sbp1_hbm.json
│ ├── sbp1_nvme.json
│ ├── sbp1_psu.json
│ ├── sbp1_rssd.json
│ ├── solum_pssf162202_psu.json
│ ├── storm_king.json
│ ├── stp_baseboard.json
│ ├── stp_p4000_chassis.json
│ ├── supermicro-pws-920p-sq_psu.json
│ ├── system1_baseboard.json
│ ├── system1_chassis.json
│ ├── tola.json
│ ├── tyan_s7106_baseboard.json
│ ├── tyan_s8036_baseboard.json
│ ├── vegman_n110_baseboard.json
│ ├── vegman_rx20_baseboard.json
│ ├── vegman_sx20_baseboard.json
│ ├── VENDORS.md
│ └── wft_baseboard.json
├── docs
│ ├── associations.md
│ ├── blacklist_configuration.md
│ ├── entity_manager_dbus_api.md
│ └── my_first_sensors.md
├── Doxyfile
├── format-code
├── LICENCE
├── meson.build
├── meson_options.txt
├── OWNERS
├── README.md
├── schemas
│ ├── global.json
│ ├── ibm.json
│ ├── intel.json
│ ├── legacy.json
│ ├── mctp.json
│ ├── openbmc-dbus.json
│ ├── pid.json
│ ├── pid_zone.json
│ ├── README.md
│ ├── satellite_controller.json
│ ├── stepwise.json
│ └── virtual_sensor.json
├── scripts
│ ├── autojson.py
│ ├── run-ci.sh
│ └── validate_configs.py
├── service_files
│ ├── dbus
│ │ └── xyz.openbmc_project.EntityManager.service
│ ├── devicetree-vpd-parser.service
│ ├── meson.build
│ ├── xyz.openbmc_project.EntityManager.service
│ └── xyz.openbmc_project.FruDevice.service
├── src
│ ├── devices.hpp
│ ├── devicetree_vpd_parser.cpp
│ ├── entity_manager.cpp
│ ├── entity_manager.hpp
│ ├── expression.cpp
│ ├── expression.hpp
│ ├── fru_device.cpp
│ ├── fru_reader.cpp
│ ├── fru_reader.hpp
│ ├── fru_utils.cpp
│ ├── fru_utils.hpp
│ ├── machine_context.cpp
│ ├── machine_context.hpp
│ ├── meson.build
│ ├── overlay.cpp
│ ├── overlay.hpp
│ ├── perform_probe.cpp
│ ├── perform_scan.cpp
│ ├── topology.cpp
│ ├── topology.hpp
│ ├── utils.cpp
│ ├── utils.hpp
│ └── variant_visitors.hpp
├── subprojects
│ ├── boost.wrap
│ ├── gtest.wrap
│ ├── nlohmann_json.wrap
│ ├── phosphor-dbus-interfaces.wrap
│ ├── phosphor-logging.wrap
│ ├── sdbusplus.wrap
│ └── valijson.wrap
└── test
├── expected-schema-errors.txt
├── test_entity-manager.cpp
├── test_fru-utils.cpp
└── test_topology.cpp
11 directories, 242 files
其基本功能包含:
- 1.
A detection daemon
- 2.
An entity manager configuration file
- 3.
A reactor
在BMC
系统下,对应目录: