KSENSOR(9E) Driver Entry Points KSENSOR(9E)

NAME


ksensor - kernel sensor framework

SYNOPSIS


#include <sys/sensors.h>

INTERFACE LEVEL


Volatile - This interface is still evolving in illumos. API and ABI
stability is not guaranteed.

DESCRIPTION


The ksensor, kernel sensor, framework provides a means for drivers to
provide various kinds of sensor information to userland such as
temperature, voltage, current, and control sensors. Sensors are exposed in
/dev/sensors and the framework takes care of managing minor nodes and ioctl
interfaces. The driver does not need to expose a character device
interface nor are its minor nodes used.

Sensor Types, Kinds, Units and Naming
Sensors are broken into different types. The types describe the shape of
the value that can be read from the sensor itself. Currently, scalar
sensors are the only supported sensor type. A scalar sensor has several
properties:

unit: uint32_t
The unit of the sensor, discussed below, indicates how to interpret
the value itself.

granularity: int32_t
The granularity indicates the number of increments per unit in the
measurement. A value such as 10 indicates that the value is in
10ths of the unit. If this was a temperature sensor, one would
need to divide by 10 to get the value into degrees. On the other
hand a negative granularity indicates one would need to multiply
the value to get the actual units. For example, a value of -2
would indicate that you'd need to multiply the value by two to get
the actual number of degrees.

precision: uint32_t
The precision represents the accuracy of the sensor itself and is
measured in units of the granularity. For example, a temperature
sensor that has a granularity of 1, meaning the value read from the
sensor is in degrees, and is accurate to +/-5 degrees would set the
precision to 5. Conversely, a temperature sensor that measured in
0.5 degree increments has a granularity of 2. If the sensor was
accurate to +/-1 degree, then it'd have a precision of 2. If the
precision is unknown, it should be left at zero.

value: int64_t
The value is the actual reading from the sensor and it is
interpreted according to the granularity. This is a signed value
as the value may be negative or positive depending on the unit.

In addition to the type, sensors also have a notion of a kind, which
indicates what kind of physical property the sensor measures. The kernel
defines the kinds currently:

SENSOR_KIND_TEMPERATURE
This measures temperature, potentially in degrees Celsius,
Fahrenheit, or Kelvin. This is one of the more common kinds
of sensors in the system, as many ASICs embed temperature
sensors for health and monitoring.

SENSOR_KIND_VOLTAGE
Voltage sensors measure the amount of voltage at a particular
point in a circuit. This is one part of determining how much
power a device is consuming. While some ASICs and ICs
operate at a fixed voltage range, many support operating at
diverse ranges and can dynamically vary their voltage.

SENSOR_KIND_CURRENT
Current sensors measure the total numbers of amps that are
passing through a measurement point on a circuit (which may
be indirect). This is often a proxy for measuring how much
power something is using as many computer related electronics
operate at a fixed voltage.

SENSOR_KIND_SYNTHETIC
A synthetic sensor is different from the others in that it
does not actually measure an actual physical phenomenon.
Synthetic sensors are generally a unitless measure on some
fixed scale. That measure is often derived from some actual
physical measurement, which is why synthetic sensors have the
ability to indicate that their measurement is derived from
another kind of sensor. To make this more concrete, let's
look at an example.

The smntemp(4D) driver exposes the AMD Tctl sensor, which is
a control temperature value. This is not a measurement in
degrees C, but rather is a value from 0 to 100 where 100
indicates that a thermal shutdown is imminent. This value is
synthesized and transformed from several different
temperature samples and goes through its own algorithm, but
critically the resulting synthetic Tctl sensor does not
represent a temperature, but is used to power cooling control
loops.

SENSOR_KIND_UNKNOWN
This value is used by the framework to indicate a kind was
not reported. Drivers should not use this value.

From here, a given measurement that occurs also has a unit that is
associated with it. The following sensors are supported:

SENSOR_UNIT_CELSIUS
Indicates that the sensor measure degrees in Celsius (C).

SENSOR_UNIT_FAHRENHEIT
Indicates that the sensor measure degrees in Fahrenheit (F).

SENSOR_UNIT_KELVIN
Indicates that the sensor measure degrees in Kelvin (K).

SENSOR_UNIT_VOLTS
Indicates that the sensor measures voltage in Volts (V).

SENSOR_UNIT_AMPS
Indicates that the sensor measures current in Amperes (A).

SENSOR_UNIT_NONE
This unit indicates that there is no unit because there is
associated physical property. This should be used by
SENSOR_KIND_SYNTHETIC sensors.

SENSOR_UNIT_UNKNOWN
This value is used by the framework to indicate a unit was
not reported. Drivers should not use this value.

Sensor Names and Classes


When a sensor is created with ksensor_create(9F) it must specify both a
name and a class, which influence how the sensor shows up under
/dev/sensors. The class is a `:' delineated string (the same conceptually
as a minor node's type, see ddi_create_minor_node(9F)) that describes the
type of sensor. They begin with "ddi_sensor" and then are followed by the
sensor's kind and then, after another colon, something that describes what
type of hardware it corresponds to. The framework takes care of defining
the class for PCI devices that create sensors with
ksensor_create_scalar_pcidev(9F) and provides the following classes
otherwise:

DDI_NT_SENSOR_TEMP_CPU
Indicates that this is a temperature sensor that relates to the
CPU, whether the socket as a whole, a core, or some other unit.

DDI_NT_SENSOR_TEMP_PCH
Indicates that this is a temperature sensor that relates to an
external chipset to the CPU that is otherwise part of the platform.

In general, drivers shouldn't create arbitrary classes that aren't defined
by the framework as then they won't be tied into system services, like
topology provided by the fault management architecture.

Where the class effectively indicates the directory structure under
/dev/sensors, the name of the sensor corresponds to the name of the device
that will be created. The semantics of the name determine a bit on the
interface used. While the PCI sensor creation routines are tied into
things such that the name is usually something descriptive, for other
sensors that use ksensor_create(9F), usually the name is part of a contract
with something in userland that will consume it like FMA.

Sensor Creation, Destruction, and Lifetimes
Sensors are tied to an instance of a driver (i.e. a particular dev_info_t)
and are identified through an opaque id_t identifier that is unique in the
system.

To create a ksensor, a driver must call either ksensor_create(9F) or
ksensor_create_scalar_pcidev(9F) in its attach(9E) entry point. A ksensor
cannot be created outside of a driver's attach(9E) entry point. Once
created, the sensor will persist until the driver removes the sensors with
ksensor_remove(9F) which can only be called during detach(9E) or
attach(9E).

As part of creating a ksensor, a driver must supply an operations vector
described in ksensor_ops(9E). This provides both metadata and data about
the sensor itself. The framework provides the following guarantees and
constraints around when the operation vectors will be called:

+o No ksensor operations registered will ever be called during attach(9E)
and detach(9E).

+o Like with other character devices, if the driver detaches for any
reason (e.g. modunload thread) the character device will be maintained
in /devices and its corresponding symlink in /dev/sensors. If the
device is accessed again, the driver will automatically be reattached
by the system like any other character device. This alleviates the
sensor driver from having to worry about whether or not it is okay to
detach.

+o A single ksensor should assume that its operation vectors will be
called in parallel. That is, not only can both kso_kind(9E) and
kso_scalar(9E) be called from different threads at the same time, but
multiple threads may call a single operation entry point as well. Put
differently, the framework does not intend to serialize access to a
single ksensor.

+o If a driver provides multiple ksensors, it should assume that they can
all be called in parallel. Put differently, different ksensors can be
accessed at the same time.

Kernel versus Userland Processing


The ksensor framework is intended for cases where there are registers or
schemes that can only be accessed by the kernel itself. A good case of
this is where sensors are available through PCI configuration space or a
memory-mapped BAR. Other devices like optical transceivers have an array
of sensors, but are only accessible through an additional I/O interface
like mac_capab_transceiver(9E). In cases where there are a lot of
semantics and parsing required, or the kernel cannot wholly own the device,
it can make more sense to instead leverage a different interface and allow
another part of the system like FMA to amalgamate the different sensors
using additional components in userland.

The right call will vary based on the device and interface. The main point
here is that while the ksensor framework exists, it doesn't have to be the
only way that sensors are provided for consumption. But it is here to be
used where it makes sense!

SEE ALSO


ksensor(4D), attach(9E), detach(9E), ksensor_ops(9E),
ddi_create_minor_node(9F), ksensor_create(9F),
ksensor_create_scalar_pcidev(9F), ksensor_kind(9F)

illumos May 10, 2024 illumos