1# Sensor Support for OpenBMC using phosphor-hwmon 2 3This document describes sensors provided by [phosphor-hwmon][15]. An alternate 4method is to use the suite of applications provided by [dbus-sensors][16]. 5While the configuration details between the two methods differ, the D-Bus 6representation remains mostly the same. 7 8OpenBMC makes it easy to add sensors for your hardware and is compliant with 9the traditional Linux HWMon sensor format. The architecture of OpenBMC 10sensors is to map sensors to [D-Bus][1] 11objects. The D-Bus object will broadcast the `PropertiesChanged` signal when either 12the sensor or threshold value changes. It is the responsibility of other 13applications to determine the effect of the signal on the system. 14 15## D-Bus 16 17``` 18Service xyz.openbmc_project.Hwmon-<hash>.Hwmon1 19Path /xyz/openbmc_project/sensors/<type>/<label> 20Interfaces xyz.openbmc_project.Sensor.[*], others (see below) 21 22Signals: All properties for an interface will broadcast signal changed 23``` 24 25**Path definitions** 26 27* **<type\>** : The [HWMon class][2] name in lower case. 28 - Examples include `temperature, fan_tach, voltage`. 29 30* **<label\>** : User defined name of the sensor. 31 - Examples include `ambient, cpu0, fan5` 32 33**Note**: The label shall comply with "Valid Object Paths" of [D-Bus Spec][3], 34that shall only contain the ASCII characters "[A-Z][a-z][0-9]_". 35 36**Hash definition** 37 38The hash value in the service name is used to give the service a unique 39and stable name. It is a decimal number that is obtained by hashing 40characteristics of the device it is monitoring using std::hash(). 41 42## Redfish 43 44The [BMCWeb Redfish][10] support returns information about sensors. The 45support depends on two types of [ObjectMapper associations][11] to find the 46necessary sensor information on D-Bus. 47 48### Association Type #1: Linking a chassis to all sensors within the chassis 49 50Sensors are grouped by chassis in Redfish. An ObjectMapper association is used 51to link a chassis to all the sensors within the chassis. This includes the 52sensors for all hardware that is considered to be within the chassis. For 53example, a chassis might contain two fan sensors, an ambient temperature 54sensor, and a VRM output voltage sensor. 55 56#### D-Bus object paths 57 58The association links the following D-Bus object paths together: 59* Chassis inventory item object path 60* List of sensor object paths for sensors within the chassis 61 62#### Association names 63* "all_sensors" 64 * Contains the list of all sensors for this chassis 65* "chassis" 66 * Contains the chassis associated with this sensor 67 68#### Example associations 69* /xyz/openbmc_project/inventory/system/chassis/all_sensors 70 * "endpoints" property contains 71 * /xyz/openbmc_project/sensors/fan_tach/fan0_0 72 * /xyz/openbmc_project/sensors/fan_tach/fan0_1 73 * /xyz/openbmc_project/sensors/temperature/ambient 74 * /xyz/openbmc_project/sensors/voltage/p0_vdn_voltage 75* /xyz/openbmc_project/sensors/fan_tach/fan0_0/chassis 76 * "endpoints" property contains 77 * /xyz/openbmc_project/inventory/system/chassis 78 79### Association Type #2: Linking a low-level hardware item to its sensors 80 81A sensor is usually related to a low-level hardware item, such as a fan, power 82supply, VRM, or CPU. The Redfish sensor support can obtain the following 83information from the related hardware item: 84* Presence ([Inventory.Item interface][12]) 85* Functional state ([OperationalStatus interface][13]) 86* Manufacturer, Model, PartNumber, SerialNumber ([Decorator.Asset interface][14]) 87 88For this reason, an ObjectMapper association is used to link a low-level 89hardware item to its sensors. For example, a processor VRM could have 90temperature and output voltage sensors, or a dual-rotor fan could have 91two tach sensors. 92 93#### D-Bus object paths 94 95The association links the following D-Bus object paths together: 96* Low-level hardware inventory item object path 97* List of sensor object paths for sensors related to that hardware item 98 99#### Association names 100* "sensors" 101 * Contains the list of sensors for this low-level hardware item 102* "inventory" 103 * Contains the low-level hardware inventory item for this sensor 104 105#### Example associations 106* /xyz/openbmc_project/inventory/system/chassis/motherboard/fan0/sensors 107 * "endpoints" property contains 108 * /xyz/openbmc_project/sensors/fan_tach/fan0_0 109 * /xyz/openbmc_project/sensors/fan_tach/fan0_1 110* /xyz/openbmc_project/sensors/fan_tach/fan0_0/inventory 111 * "endpoints" property contains 112 * /xyz/openbmc_project/inventory/system/chassis/motherboard/fan0 113 114## Development Details 115 116Sensor properties are standardized based on the type of sensor. A Threshold 117sensor contains specific properties associated with the rise and fall of a 118sensor value. The [Sensor Interfaces][4] 119are described in their respective YAML files. The path location in the source 120tree is identical to the interface being described below the 121[phosphor-dbus-interfaces][5] parent directory. 122 123 example: 124[openbmc/phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Threshold/Warning.yaml][6] 125 126 127 Maps to D-Bus interface 128`xyz.openbmc_project.Sensor.Threshold.Warning` 129 130Each 'name' property in the YAML file maps directly to D-Bus properties. 131 132 example: 133 134 [Warning.interface.yaml][6] 135 136``` 137properties: 138 - name: WarningHigh 139 type: int64 140 - name: WarningLow 141 type: int64 142 - name: WarningAlarmHigh 143 type: boolean 144 - name: WarningAlarmLow 145 type: boolean 146``` 147 148Maps to 149 150``` 151busctl --system introspect xyz.openbmc_project.Hwmon-3301914901.Hwmon1 \ 152 /xyz/openbmc_project/Sensors/temperature/ambient \ 153 xyz.openbmc_project.Sensor.Threshold.Warning | grep property 154 155.WarningAlarmHigh property b false emits-change writable 156.WarningAlarmLow property b false emits-change writable 157.WarningHigh property x 40000 emits-change writable 158.WarningLow property x 10000 emits-change writable 159 160``` 161 162### REST 163 164``` 165"/xyz/openbmc_project/Sensors/temperature/ambient": { 166 "Scale": -3, 167 "Unit": "xyz.openbmc_project.Sensor.Value.Unit.DegreesC", 168 "Value": 30125, 169 "WarningAlarmHigh": 0, 170 "WarningAlarmLow": 0, 171 "WarningHigh": 40000, 172 "WarningLow": 10000 173} 174``` 175 176### Other Interfaces 177 178Aside from the `xyz.openbmc_project.Sensor` interfaces, the sensor D-Bus objects 179may also expose the following interfaces: 180 1811. `xyz.openbmc_project.Control.FanSpeed` 182 - Provides a Target property to set a fan RPM value 1832. `xyz.openbmc_project.Control.FanPwm` 184 - Provides a Target property to set a fan PWM value 1853. `xyz.openbmc_project.State.Decorator.OperationalStatus` 186 - Provides a Functional property that tracks the state of any fault files 187 188### Signals 189 190Any property value change broadcasts a signal on D-Bus. When a value trips 191past a threshold, an additional D-Bus signal is sent. 192 193Example, if the value of WarningLow is 5... 194 195| From | To | propertyChanged Signals | 196|---|---|---| 197| 1 | 5 | "xyz.openbmc_project.Sensor.Value" : value = 5 | 198| 1 | 6 | "xyz.openbmc\_project.Sensor.Value" : value = 6 ,<br>"xyz.openbmc\_project.Sensor.Threshold.Warning" : WarningAlarmLow = 0 | 199| 5 | 6 | "xyz.openbmc\_project.Sensor.Value" : value = 6 | 200| 6 | 1 | "xyz.openbmc\_project.Sensor.Value" : value = 1 ,<br>"xyz.openbmc\_project.Sensor.Threshold.Warning" : WarningAlarmLow = 1 | 201 202 203### System Configuration 204 205On the BMC each sensor's configuration is located in a file. These files 206can be found as a child of the `/etc/default/obmc/hwmon` path. 207 208 209## Creating a Sensor 210 211HWMon sensors are defined in the `recipes-phosphor/sensor/phosphor-hwmon%` 212path within the [machine configuration][7]. 213The children of the `obmc/hwmon` directory should follow the path of either: 214 2151. The children of the `devicetree/base` directory path on the system, 216as defined by the kernel. The code obtains this from the OF_FULLNAME udev 217environment variable. 218 2192. If the device isn't in the device tree, then the device path can be used. 220 221As an example, the Palmetto [configuration][8] 222file for the ambient temperature sensor. 223 224``` 225recipes-phosphor/sensors/phosphor-hwmon/obmc/hwmon/ahb/apb/bus@1e78a000/i2c-bus@c0/tmp423@4c.conf 226``` 227 228which maps to this specific sensor and conf file on the system... 229 230``` 231/sys/firmware/devicetree/base/ahb/apb/bus@1e78a000/i2c-bus@c0/tmp423@4c 232/etc/default/obmc/hwmon/ahb/apb/bus@1e78a000/i2c@c0/tmp423@4c.conf 233``` 234 235This next example shows using the device path as opposed to the devicetree 236path for the OCC device on an OpenPOWER system. 237Note how a '--' replaces a ':' in the directory names for the conf file. 238 239``` 240recipes-phosphor/sensors/phosphor-hwmon%/obmc/hwmon/devices/platform/gpio-fsi/fsi0/slave@00--00/00--00--00--06/sbefifo1-dev0/occ-hwmon.1.conf 241``` 242 243which maps to this specific sensor and conf file on the system... 244 245``` 246/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/00:00:00:06/sbefifo1-dev0/occ-hwmon.1 247/etc/default/obmc/hwmon/devices/platform/gpio-fsi/fsi0/slave@00--00/00--00--00--06/sbefifo1-dev0/occ-hwmon.1.conf 248``` 249 250In order for the sensor to be exposed to D-Bus, the configuration file must 251describe the sensor attributes. Attributes follow a format. 252 253``` 254xxx_yyy#=value 255 256xxx = Attribute 257# = Association number (i.e. 1-n) 258yyy = HWMon sensor type (i.e. temp, pwm) 259``` 260 261| Attribute | Interfaces Added | 262|---|---| 263|LABEL | xyz.openbmc\_project.Sensor.Value | 264| WARNHI, WARNLO | xyz.openbmc\_project.Threshold.Warning | 265| CRITHI, CRITLO | xyz.openbmc\_project.Threshold.Critical | 266 267 268The HWMon sensor type 269 270| [HWMon sensor type][2] | type | 271|---|---| 272| temp | temperature | 273| in | voltage | 274| * | All other names map directly | 275 276 277 278See the [HWMon interface][2] 279definitions for more definitions and keyword details 280 281 282 283In this conf example the tmp423 chip is wired to two temperature sensors. 284The values must be described in 10<sup>-3</sup> degrees Celsius. 285 286 287``` 288LABEL_temp1=ambient 289WARNLO_temp1=10000 290WARNHI_temp1=40000 291 292LABEL_temp2=cpu 293WARNLO_temp2=10000 294WARNHI_temp2=80000 295``` 296 297#### Additional Config File Entries 298The phosphor-hwmon code supports these additional config file entries: 299 300**INTERVAL** 301 302The interval, in microseconds, at which sensors should be read. If 303not specified the interval is 1000000us (1 second). 304``` 305INTERVAL=1000000 306``` 307 308**GAIN**, **OFFSET** 309 310Used to support scaled sensor readings, where 311value = (raw sensor reading) * gain + offset 312``` 313GAIN_in3 = 5.0 #GAIN is a double 314OFFSET_in3 = 6 #OFFSET is an integer 315``` 316 317**MINVALUE**, **MAXVALUE** 318 319If found, will be used to set the MinValue/MaxValue properties 320on the `xyz.openbmc_project.Sensor.Value` interface. 321``` 322MINVALUE_temp1 = 1 323``` 324 325**MODE** 326 327Needed for certain device drivers, specifically the OpenPOWER OCC driver, 328where the instance number (the N in tempN_input) is dynamic and instead 329another file contains the known ID. 330 331For example 332``` 333temp26_input:29000 334temp26_label:171 335``` 336Where the 26 is just what hwmon assigns, but the 171 corresponds 337to something like an IPMI sensor value for a DIMM temperature. 338 339The config file would then have: 340``` 341MODE_temp26 = "label" #Tells the code to look in temp26_label 342LABEL_temp171 = "dimm3_temp" #Says that temp26_input holds dimm3_temp 343``` 344 345**REMOVERCS** 346 347Contains a list of device driver errno values where if these are obtained 348when reading the hardware, the corresponding sensor object will be removed 349from D-Bus until it is successfully read again. 350 351``` 352REMOVERCS = "5,6" #If any sensor on the device returns a 5 or 6, remove it. 353REMOVERCS_temp1 = "42" #If reading temp1_input returns a 42, remove it. 354``` 355 356**TARGET\_MODE** 357 358Allows one to choose the fan target mode, either RPM or PWM, 359if the device driver exposes both methods. 360``` 361TARGET_MODE = "RPM" 362``` 363 364**PWM\_TARGET** 365 366For fans that are PWM controlled, can be used to map the pwmN file to a fan M. 367``` 368PWM_TARGET_fan0 = 1 #Use the pwm1 file to control fan 0 369``` 370 371**ENABLE** 372 373Will write a value to a pwmN\_enable file on startup if present. 374``` 375ENABLE_fan1 = 2 #Write a 2 to pwm1_enable 376``` 377 378### Defining sensors in an IPMI YAML configuration file 379For an example of how sensors entries are defined, consult the [example 380YAML](https://github.com/openbmc/phosphor-host-ipmid/blob/master/scripts/sensor-example.yaml) 381 382#### How to best choose coefficients 383Sensor reading, according to IPMI spec, is calculated as: 384 385```none 386y = L[(Mx + B * 10^(bExp)) * 10^(rExp)] 387``` 388 389- y: the 'final value' as reported by IPMItool 390- x: 8 bits, unsigned, reading data encoded in IPMI response packet 391- M: 10 bits, signed integer multiplier, `multiplierM` in YAML 392- B: 10 bits, signed additive offset, `offsetB` in YAML 393- bExp: 4 bits, signed, `bExp` in YAML 394- rExp: 4 bits, signed, `rExp` in YAML 395 396In addition, phosphor-ipmi-host configuration also supports `scale` property, 397which applies for analog sensors, meaning the value read over DBus should be 398scaled by 10^S. 399 400As you can tell, one should choose the coefficients based on possible sensor 401reading range and desired resolution. Commonly, B=0, we would have 402 403 Supported range: [0, 255 * M * 10^(scale - rExp)] 404 Resolution: M * 10^(scale - rExp) 405 406For a concrete example, let's say a voltage sensor reports between 0 to 5.0V. 407hwmon sysfs scales the value by 1000, so the sensor value read over DBus is 408between 0 and 5000. A possible configuration for this is: 409 410```none 411multiplierM: 20 412offsetB: 0 413bExp: 0 414rExp: -3 415scale: -3 416``` 417 418so for a DBus sensor value of 4986 meaning 4.986V, phosphor-ipmi-host would 419encode it as 420 421 x: 4986 / 20 = 249 422 M: 20 423 rExp: -3 424 425When ipmitool sensor list is called, the tool fetches sensor factors and 426computes value as: 427 428```none 429y = 20 * 249 * 10^-3 = 4.98 (V) 430``` 431 432## Additional Reading 433Mailing List [Comments on Sensor design][9] 434 435 436[1]: https://dbus.freedesktop.org/doc/dbus-tutorial.html 437[2]: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface 438[3]: https://dbus.freedesktop.org/doc/dbus-specification.html#basic-types 439[4]: https://github.com/openbmc/phosphor-dbus-interfaces/tree/master/yaml/xyz/openbmc_project/Sensor 440[5]: https://github.com/openbmc/phosphor-dbus-interfaces 441[6]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Sensor/Threshold/Warning.interface.yaml 442[7]: https://github.com/openbmc/openbmc/tree/master/meta-openbmc-machines 443[8]: https://github.com/openbmc/openbmc/blob/master/meta-ibm/meta-palmetto/recipes-phosphor/sensors/phosphor-hwmon/obmc/hwmon/ahb/apb/bus@1e78a000/i2c-bus@c0/tmp423@4c.conf 444[9]: https://lists.ozlabs.org/pipermail/openbmc/2016-November/005309.html 445[10]: https://github.com/openbmc/bmcweb/blob/master/DEVELOPING.md#redfish 446[11]: https://github.com/openbmc/docs/blob/master/architecture/object-mapper.md#associations 447[12]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Inventory/Item.interface.yaml 448[13]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/State/Decorator/OperationalStatus.interface.yaml 449[14]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Inventory/Decorator/Asset.interface.yaml 450[15]: https://github.com/openbmc/phosphor-hwmon 451[16]: https://github.com/openbmc/dbus-sensors 452