NAME
sysmon_envsys —
kernel part of the
envsys 2 framework
SYNOPSIS
#include <dev/sysmon/sysmonvar.h>
struct sysmon_envsys *
sysmon_envsys_create(
void);
void
sysmon_envsys_destroy(
struct
sysmon_envsys *);
int
sysmon_envsys_register(
struct
sysmon_envsys *);
void
sysmon_envsys_unregister(
struct
sysmon_envsys *);
int
sysmon_envsys_sensor_attach(
struct
sysmon_envsys *,
envsys_data_t *);
int
sysmon_envsys_sensor_detach(
struct
sysmon_envsys *,
envsys_data_t *);
void
sysmon_envsys_sensor_event(
struct
sysmon_envsys *,
envsys_data_t *,
int);
void
sysmon_envsys_foreach_sensor(
sysmon_envsys_callback_t,
void *,
bool);
int
sysmon_envsys_update_limits(
struct
sysmon_envsys *,
envsys_data_t *);
DESCRIPTION
sysmon_envsys is the kernel part of the
envsys(4) framework. With this
framework you are able to register and unregister a
sysmon_envsys device, attach or detach sensors into a
device, and enable or disable automatic monitoring for some sensors without
any user interactivity, among other things.
HOW TO USE THE FRAMEWORK
To register a new driver to the
sysmon_envsys framework, a
sysmon_envsys object must be allocated and initialized; the
sysmon_envsys_create() function is used for this. This
returns a zero'ed pointer to a
sysmon_envsys structure.
Once the object has been initialized, actual sensors may be initialized and
attached (see the
SENSOR DETAILS
section for more information). This is accomplished by the
sysmon_envsys_sensor_attach() function, which will attach
the
envsys_data_t (a sensor) specified as second argument
into the
sysmon_envsys object specified in the first
argument.
Finally, after all sensors have been attached, the device needs to set some
required (and optional) members of the
sysmon_envsys
structure before calling the
sysmon_envsys_register()
function to register the device.
In case of errors during the initialization, the
sysmon_envsys_destroy() function should be used. This
detaches all previously attached sensors and deallocates the
sysmon_envsys object.
Some sensors can be monitored, and when the sensor value changes an event can be
delivered to the
powerd(8)
daemon. Sensor monitoring can be performed by the
sysmon_envsys framework on a polled basis. Alternatively,
the sensor's device driver can call the
sysmon_envsys_sensor_event() function to deliver the event
without waiting for the device to be polled.
The
sysmon_envsys_foreach_sensor() function can be used by
other parts of the kernel to iterate over all registered sensors. This
capability is used by the
i386/apm(4) driver to
summarize the state of all battery sensors.
Drivers can also call the
sysmon_envsys_update_limits()
function when it is necessary to reinitialize a sensor's threshold values.
This is used by the
acpibat(4)
driver when a new battery is inserted.
The
sysmon_envsys structure is defined as follows (only the
public members are shown):
struct sysmon_envsys {
const char *sme_name;
int sme_flags;
int sme_class;
uint64_t sme_events_timeout;
void *sme_cookie;
void (*sme_refresh)(struct sysmon_envsys *, envsys_data_t *);
void (*sme_set_limits)(struct sysmon_envsys *, envsys_data_t *,
sysmon_envsys_lim_t *, uint32_t *);
void (*sme_get_limits)(struct sysmon_envsys *, envsys_data_t *,
sysmon_envsys_lim_t *, uint32_t *);
};
The members have the following meaning:
-
-
- sme_class
- This specifies the class of the sysmon envsys device. See
the DEVICE CLASSES section for more information
(OPTIONAL).
-
-
- sme_name
- The name that will be used in the driver (REQUIRED).
-
-
- sme_flags
- Additional flags for the sysmon_envsys
device. Currently supporting SME_DISABLE_REFRESH. If
enabled, the sme_refresh function callback won't be
used to refresh sensor data and the driver will use its own method
(OPTIONAL).
-
-
- sme_events_timeout
- This is used to specify the default timeout value (in
seconds) that will be used to check for critical events if any monitoring
flag was set (OPTIONAL).
If the driver wants to refresh sensors data via the
sysmon_envsys framework, the following members may be
specified:
-
-
- sme_cookie
- Typically a pointer to the device struct (also called
“softc”). This may be used in the
sme_refresh, sme_get_limits, or
sme_set_limits function callbacks.
-
-
- sme_refresh
- Pointer to a function that will be used to refresh sensor
data in the device. This can be used to set the state and other properties
of the sensor depending on the data returned by the driver.
NOTE: You don't have to refresh all
sensors, only the sensor specified by the
edata->sensor index. If this member
is not specified, the device driver will be totally responsible for all
updates of this sensor; the sysmon_envsys framework will
not be able to update the sensor value.
-
-
- sme_get_limits
- Pointer to a function that will be used to obtain from the
driver the initial limits (or thresholds) used when monitoring a sensor's
value. (See the SENSOR DETAILS
section for more information.) If this member is not specified, the
ENVSYS_FMONLIMITS
flag will be ignored, and limit
monitoring will not occur until appropriate limits are enabled from
userland via
envstat(8).
-
-
- sme_set_limits
- Pointer to a function that alerts the device driver
whenever monitoring limits (or thresholds) are updated by the user.
Setting this function allows the device driver to reprogram hardware
limits (if provided by the device) when the user-specificied limits are
updated, and gives the driver direct control over setting the sensor's
state based on hardware status.
The sme_set_limits callback can be invoked with the
third argument (a pointer to the new limits) set to a
NULL
pointer. Device drivers must recognize this
as a request to restore the sensor limits to their original, boot-time
values.
If the sme_set_limits member is not specified, the
device driver is not informed of changes to the sensor's limit values, and
the sysmon_envsys framework performs all limit checks in
software.
Note that it's not necessary to refresh the sensors data before the driver is
registered, only do it if you need the data in your driver to check for a
specific condition.
The timeout value for the monitoring events on a device may be changed via the
ENVSYS_SETDICTIONARY
ioctl(2) or the
envstat(8) command.
To unregister a driver previously registered with the
sysmon_envsys framework, the
sysmon_envsys_unregister() function must be used. If there
were monitoring events registered for the driver, they all will be destroyed
before the device is unregistered and its sensors are detached. Finally the
sysmon_envsys object will be freed, so there's no need to
call
sysmon_envsys_destroy().
DEVICE CLASSES
The
sme_class member of the
sysmon_envsys structure is an optional flag that
specifies the class of the sysmon envsys device. Currently there are two
classes:
-
-
- SME_CLASS_ACADAPTER
-
This class is for devices that want to act as an AC
adapter. The device writer must ensure that at least there is a sensor
with units of
ENVSYS_INDICATOR
.
This will be used to report its current state (on/off).
-
-
- SME_CLASS_BATTERY
-
This class is for devices that want to act as a Battery.
The device writer must ensure that at least there are two sensors with
units of
ENVSYS_BATTERY_CAPACITY
and
ENVSYS_BATTERY_CHARGE
.
These two sensors are used to ensure that the battery device can send a
low-power event to the
powerd(8) daemon (if
running) when all battery devices are in a critical state. (The critical
state occurs when a battery is not currently charging and its charge state
is low or critical.) When the low-power condition is
met, an event is sent to the
powerd(8) daemon (if
running), which will shutdown the system gracefully by executing the
/etc/powerd/scripts/sensor_battery script.
If powerd(8) is not running,
the system will be powered off via the
cpu_reboot(9) call with
the RB_POWERDOWN
flag.
NOTE: If a
SME_CLASS_ACADAPTER
or
SME_CLASS_BATTERY
class device doesn't have the
sensors required, the
low-power event will never be sent,
and the graceful shutdown won't be possible.
SENSOR DETAILS
Each sensor uses a
envsys_data_t structure, it's defined as
follows (only the public members are shown);
typedef struct envsys_data {
uint32_t units;
uint32_t state;
uint32_t flags;
uint32_t rpms;
int32_t rfact;
int32_t value_cur;
int32_t value_max;
int32_t value_min;
int32_t value_avg;
sysmon_envsys_lim_t limits;
int upropset;
char desc[ENVSYS_DESCLEN];
} envsys_data_t;
The members for the
envsys_data_t structure have the following
meaning:
-
-
- units
- Used to set the units type.
-
-
- state
- Used to set the current state.
-
-
- flags
- Used to set additional flags. Among other uses, if one or
more of the
ENVSYS_FMONxxx
flags are set,
automatic sensor monitoring will be enabled. Periodically, the sensor's
value will be checked and if certain conditions are met, an event will be
sent to the powerd(8)
daemon. NOTE that limits (or thresholds)
can be set at any time to enable monitoring that the
sensor's value remains within those limits.
-
-
- rpms
- Used to set the nominal RPM value for fan
sensors.
-
-
- rfact
- Used to set the rfact value for voltage
sensors.
-
-
- value_cur
- Used to set the current value.
-
-
- value_max
- Used to set the maximum value.
-
-
- value_min
- Used to set the minimum value.
-
-
- value_avg
- Used to set the average value.
-
-
- limits
- Structure used to contain the sensor's alarm
thresholds.
-
-
- upropset
- Used to keep track of which sensor properties are set.
-
-
- desc
- Used to set the description string. NOTE
that the description string must be unique in a device, and
sensors with duplicate or empty description will simply
be ignored.
Users of this framework must take care about the following points:
- The desc member needs to have a
valid description, unique in a device and non empty to be valid.
- The units type must be valid. The
following units are defined:
ENVSYS_STEMP
- For temperature sensors, in microkelvins.
ENVSYS_SFANRPM
- For fan sensors.
ENVSYS_SVOLTS_AC
- For AC Voltage.
ENVSYS_SVOLTS_DC
- For DC Voltage.
ENVSYS_SOHMS
- For Ohms.
ENVSYS_SWATTS
- For Watts.
ENVSYS_SAMPS
- For Ampere.
ENVSYS_SWATTHOUR
- For Watts hour.
ENVSYS_SAMPHOUR
- For Ampere hour.
ENVSYS_INDICATOR
- For sensors that only want a boolean type.
ENVSYS_INTEGER
- For sensors that only want an integer type.
ENVSYS_DRIVE
- For drive sensors.
ENVSYS_BATTERY_CAPACITY
- For Battery device classes. This sensor unit uses the
ENVSYS_BATTERY_CAPACITY_*
values in
value_cur to report its current capacity to
userland. Mandatory if sme_class is set to
SME_CLASS_BATTERY
.
ENVSYS_BATTERY_CHARGE
- For Battery device classes. This sensor is equivalent
to the Indicator type, it's a boolean. Use it to specify in what state
is the Battery state: true if the battery is
currently charging or false otherwise. Mandatory if
sme_class is set to
SME_CLASS_BATTERY
.
- When initializing or refreshing the sensor, the
state member should be set to a known state
(otherwise it will be in unknown state). Possible values:
ENVSYS_SVALID
- Sets the sensor to a valid state.
ENVSYS_SINVALID
- Sets the sensor to an invalid state.
ENVSYS_SCRITICAL
- Sets the sensor to a critical state.
ENVSYS_SCRITUNDER
- Sets the sensor to a critical under state.
ENVSYS_SCRITOVER
- Sets the sensor to a critical over state.
ENVSYS_SWARNUNDER
- Sets the sensor to a warning under state.
ENVSYS_SWARNOVER
- Sets the sensor to a warning over state.
- The flags member accepts one or
more of the following flags:
-
-
ENVSYS_FCHANGERFACT
- Marks the sensor with ability to change the
rfact value on the fly (in voltage sensors). The
rfact member must be used in the correct place
of the code that retrieves and converts the value of the sensor.
-
-
ENVSYS_FPERCENT
- This uses the value_cur and
value_max members to make a percentage. Both
values must be enabled and have data.
-
-
ENVSYS_FVALID_MAX
- Marks the value_max value as
valid.
-
-
ENVSYS_FVALID_MIN
- Marks the value_min value as
valid.
-
-
ENVSYS_FVALID_AVG
- Marks the value_avg value as
valid.
-
-
ENVSYS_FMONCRITICAL
- Enables and registers a new event to monitor a critical
state.
-
-
ENVSYS_FMONLIMITS
- Enables and registers a new event to monitor a sensor's
value crossing limits or thresholds.
-
-
ENVSYS_FMONSTCHANGED
- Enables and registers a new event to monitor battery
capacity or drive state sensors. The flag is not effective if the
units member is not
ENVSYS_DRIVE
or
ENVSYS_BATTERY_CAPACITY
.
-
-
ENVSYS_FMONNOTSUPP
- Disallows setting of limits (or thresholds) via the
ENVSYS_SETDICTIONARY
ioctl(2). This flag only
disables setting the limits from userland. It has no effect on
monitoring flags set by the driver.
-
-
ENVSYS_FHAS_ENTROPY
- Allows this sensor to provide entropy for
rnd(4).
If the driver has to use any of the
value_max, value_min,
or value_avg
members, they should be marked as valid with the appropriate
flag.
- If units is set to
ENVSYS_DRIVE
, the value_cur
member must be set to one of the following predefined states:
ENVSYS_DRIVE_EMPTY
- Drive state is unknown.
ENVSYS_DRIVE_READY
- Drive is ready.
ENVSYS_DRIVE_POWERUP
- Drive is powering up.
ENVSYS_DRIVE_ONLINE
- Drive is online.
ENVSYS_DRIVE_OFFLINE
- Drive is offline.
ENVSYS_DRIVE_IDLE
- Drive is idle.
ENVSYS_DRIVE_ACTIVE
- Drive is active.
ENVSYS_DRIVE_BUILD
- Drive is building.
ENVSYS_DRIVE_REBUILD
- Drive is rebuilding.
ENVSYS_DRIVE_POWERDOWN
- Drive is powering down.
ENVSYS_DRIVE_FAIL
- Drive has failed.
ENVSYS_DRIVE_PFAIL
- Drive has been degraded.
ENVSYS_DRIVE_MIGRATING
- Drive is migrating.
ENVSYS_DRIVE_CHECK
- Drive is checking its state.
- If units is set to
ENVSYS_BATTERY_CAPACITY
, the
value_cur member must be set to one of the following
predefined capacity states:
ENVSYS_BATTERY_CAPACITY_NORMAL
- Battery charge is normal.
ENVSYS_BATTERY_CAPACITY_CRITICAL
- Battery charge is critical.
ENVSYS_BATTERY_CAPACITY_LOW
- Battery charge is low.
ENVSYS_BATTERY_CAPACITY_WARNING
- Battery charge is on or below the warning
capacity.
- The
envsys(4) framework expects
to have the values converted to a unit that can be converted to another
one easily. That means the user should convert the value returned by the
driver to the appropriate unit. For example voltage sensors to
mV, temperature sensors to uK, Watts
to mW, Ampere to mA, etc.
The following types shouldn't need any conversion:
ENVSYS_BATTERY_CAPACITY
,
ENVSYS_BATTERY_CHARGE
,
ENVSYS_INDICATOR
,
ENVSYS_INTEGER
, and
ENVSYS_DRIVE
.
PLEASE NOTE THAT YOU MUST AVOID USING FLOATING POINT
OPERATIONS IN KERNEL WHEN CONVERTING THE DATA RETURNED
BY THE DRIVER TO THE APPROPRIATE UNIT, IT'S NOT
ALLOWED.
HOW TO ENABLE
AUTOMATIC MONITORING IN SENSORS
The following example illustrates how to enable automatic monitoring in a
virtual driver for a
critical state in the first sensor
(
sc_sensor[0]):
int
mydriver_initialize_sensors(struct mysoftc *sc)
{
...
/* sensor is initialized with a valid state */
sc->sc_sensor[0].state = ENVSYS_SVALID;
/*
* the monitor member must be true to enable
* automatic monitoring.
*/
sc->sc_sensor[0].monitor = true;
/* and now we specify the type of the monitoring event */
sc->sc_sensor[0].flags |= ENVSYS_FMONCRITICAL;
...
}
int
mydriver_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
struct mysoftc *sc = sme->sme_cookie;
/* we get current data from the driver */
edata->value_cur = sc->sc_getdata();
/*
* if value is too high, mark the sensor in
* critical state.
*/
if (edata->value_cur > MYDRIVER_SENSOR0_HIWAT) {
edata->state = ENVSYS_SCRITICAL;
/* a critical event will be sent now automatically */
} else {
/*
* if value is within the limits, and we came from
* a critical state make sure to change sensor's state
* to valid.
*/
edata->state = ENVSYS_SVALID;
}
...
}
CODE REFERENCES
The
envsys 2 framework is implemented within the files:
sys/dev/sysmon/sysmon_envsys.c
sys/dev/sysmon/sysmon_envsys_events.c
sys/dev/sysmon/sysmon_envsys_tables.c
sys/dev/sysmon/sysmon_envsys_util.c
SEE ALSO
envsys(4),
envstat(8)
HISTORY
The first
envsys framework first appeared in
NetBSD 1.5. The
envsys 2 framework
first appeared in
NetBSD 5.0.
AUTHORS
The (current)
envsys 2 framework was implemented by
Juan Romero Pardines. Additional input on the design
was provided by many
NetBSD developers around the
world.
The first
envsys framework was implemented by Jason R. Thorpe,
Tim Rightnour, and Bill Squier.