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&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;example:
124[openbmc/phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Threshold/Warning.yaml][6]
125
126
127&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;example:
133
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[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