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