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