Modules

Modules add additional functionality to the core Target interface. Usually, it is support for specific subsystems on the target. Modules are instantiated as attributes of the Target instance.

hotplug

Kernel hotplug subsystem allows offlining (“removing”) cores from the system, and onlining them back in. The devlib module exposes a simple interface to this subsystem

from devlib import LocalLinuxTarget
target = LocalLinuxTarget()

# offline cpus 2 and 3, "removing" them from the system
target.hotplug.offline(2, 3)

# bring CPU 2 back in
target.hotplug.online(2)

# Make sure all cpus are online
target.hotplug.online_all()

cpufreq

cpufreq is the kernel subsystem for managing DVFS (Dynamic Voltage and Frequency Scaling). It allows controlling frequency ranges and switching policies (governors). The devlib module exposes the following interface

Note

On ARM big.LITTLE systems, all cores on a cluster (usually all cores of the same type) are in the same frequency domain, so setting cpufreq state on one core on a cluster will affect all cores on that cluster. Because of this, some devices only expose cpufreq sysfs interface (which is what is used by the devlib module) on the first cpu in a cluster. So to keep your scripts portable, always use the fist (online) CPU in a cluster to set cpufreq state.

target.cpufreq.list_governors(cpu)

List cpufreq governors available for the specified cpu. Returns a list of strings.

Parameters:cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").
target.cpufreq.list_governor_tunables(cpu)

List the tunables for the specified cpu’s current governor.

Parameters:cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").
target.cpufreq.get_governor(cpu)

Returns the name of the currently set governor for the specified cpu.

Parameters:cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").
target.cpufreq.set_governor(cpu, governor, **kwargs)

Sets the governor for the specified cpu.

Parameters:
  • cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").
  • governor – The name of the governor. This must be one of the governors supported by the CPU (as returned by list_governors().

Keyword arguments may be used to specify governor tunable values.

target.cpufreq.get_governor_tunables(cpu)

Return a dict with the values of the specified CPU’s current governor.

Parameters:cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").
target.cpufreq.set_governor_tunables(cpu, **kwargs)

Set the tunables for the current governor on the specified CPU.

Parameters:cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").

Keyword arguments should be used to specify tunable values.

target.cpufreq.list_frequencies(cpu)

List DVFS frequencies supported by the specified CPU. Returns a list of ints.

Parameters:cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").
target.cpufreq.get_min_frequency(cpu)
target.cpufreq.get_max_frequency(cpu)
target.cpufreq.set_min_frequency(cpu, frequency[, exact=True])
target.cpufreq.set_max_frequency(cpu, frequency[, exact=True])

Get the currently set, or set new min and max frequencies for the specified CPU. “set” functions are available with all governors other than userspace.

Parameters:cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").
target.cpufreq.get_min_available_frequency(cpu)
target.cpufreq.get_max_available_frequency(cpu)
Retrieve the min or max DVFS frequency that is supported (as opposed to currently enforced) for a given CPU. Returns an int or None if could not be determined.
Parameters:frequency – Frequency to set.
target.cpufreq.get_frequency(cpu)
target.cpufreq.set_frequency(cpu, frequency[, exact=True])

Get and set current frequency on the specified CPU. set_frequency is only available if the current governor is userspace.

Parameters:
  • cpu – The cpu; could be a numeric or the corresponding string (e.g. 1 or "cpu1").
  • frequency – Frequency to set.

cpuidle

cpuidle is the kernel subsystem for managing CPU low power (idle) states.

target.cpuidle.get_driver()

Return the name current cpuidle driver.

target.cpuidle.get_governor()

Return the name current cpuidle governor (policy).

target.cpuidle.get_states([cpu=0])

Return idle states (optionally, for the specified CPU). Returns a list of CpuidleState instances.

target.cpuidle.get_state(state[, cpu=0])

Return CpuidleState instance (optionally, for the specified CPU) representing the specified idle state. state can be either an integer index of the state or a string with the states name or desc.

target.cpuidle.enable(state[, cpu=0])
target.cpuidle.disable(state[, cpu=0])
target.cpuidle.enable_all([cpu=0])
target.cpuidle.disable_all([cpu=0])

Enable or disable the specified or all states (optionally on the specified CPU.

You can also call enable() or disable() on CpuidleState objects returned by get_state(s).

cgroups

TODO

hwmon

TODO

API

Generic Module API Description

Modules implement discrete, optional pieces of functionality (“optional” in the sense that the functionality may or may not be present on the target device, or that it may or may not be necessary for a particular application).

Every module (ultimately) derives from devlib.module.Module class. A module must define the following class attributes:

name:

A unique name for the module. This cannot clash with any of the existing names and must be a valid Python identifier, but is otherwise free-form.

kind:

This identifies the type of functionality a module implements, which in turn determines the interface implemented by the module (all modules of the same kind must expose a consistent interface). This must be a valid Python identifier, but is otherwise free-form, though, where possible, one should try to stick to an already-defined kind/interface, lest we end up with a bunch of modules implementing similar functionality but exposing slightly different interfaces.

Note

It is possible to omit kind when defining a module, in which case the module’s name will be treated as its kind as well.

stage:

This defines when the module will be installed into a Target. Currently, the following values are allowed:

connected:The module is installed after a connection to the target has been established. This is the default.
early:The module will be installed when a Target is first created. This should be used for modules that do not rely on a live connection to the target.
setup:The module will be installed after initial setup of the device has been performed. This allows the module to utilize assets deployed during the setup stage for example ‘Busybox’.

Additionally, a module must implement a static (or class) method probe():

Module.probe(target)

This method takes a Target instance and returns True if this module is supported by that target, or False otherwise.

Note

If the module stage is "early", this method cannot assume that a connection has been established (i.e. it can only access attributes of the Target that do not rely on a connection).

Installation and invocation

The default installation method will create an instance of a module (the Target instance being the sole argument) and assign it to the target instance attribute named after the module’s kind (or name if kind is None).

It is possible to change the installation procedure for a module by overriding the default install() method. The method must have the following signature:

Module.install(cls, target, **kwargs)

Install the module into the target instance.

Implementation and Usage Patterns

There are two common ways to implement the above API, corresponding to the two common uses for modules:

  • If a module provides an interface to a particular set of functionality (e.g. an OS subsystem), that module would typically derive directly form Module and would leave kind unassigned, so that it is accessed by it name. Its instance’s methods and attributes provide the interface for interacting with its functionality. For examples of this type of module, see the subsystem modules listed above (e.g. cpufreq).
  • If a module provides a platform- or infrastructure-specific implementation of a common function, the module would derive from one of Module subclasses that define the interface for that function. In that case the module would be accessible via the common kind defined its super. The module would typically implement __call__() and be invoked directly. For examples of this type of module, see common function interface definitions below.

Common Function Interfaces

This section documents Module classes defining interface for common functions. Classes derived from them provide concrete implementations for specific platforms.

HardResetModule

HardResetModule.kind

“hard_reset”

HardResetModule.__call__()

Must be implemented by derived classes.

Implements hard reset for a target devices. The equivalent of physically power cycling the device. This may be used by client code in situations where the target becomes unresponsive and/or a regular reboot is not possible.

BootModule

BootModule.kind

“hard_reset”

BootModule.__call__()

Must be implemented by derived classes.

Implements a boot procedure. This takes the device from (hard or soft) reset to a booted state where the device is ready to accept connections. For a lot of commercial devices the process is entirely automatic, however some devices (e.g. development boards), my require additional steps, such as interactions with the bootloader, in order to boot into the OS.

Bootmodule.update(**kwargs)

Update the boot settings. Some boot sequences allow specifying settings that will be utilized during boot (e.g. linux kernel boot command line). The default implementation will set each setting in kwargs as an attribute of the boot module (or update the existing attribute).

FlashModule

FlashModule.kind

“flash”

devlib.module.hwmon.__call__(image_bundle=None, images=None, boot_config=None, connect=True)

Must be implemented by derived classes.

Flash the target platform with the specified images.

Parameters:
  • image_bundle – A compressed bundle of image files with any associated metadata. The format of the bundle is specific to a particular implementation.
  • images – A dict mapping image names/identifiers to the path on the host file system of the corresponding image file. If both this and image_bundle are specified, individual images will override those in the bundle.
  • boot_config – Some platforms require specifying boot arguments at the time of flashing the images, rather than during each reboot. For other platforms, this will be ignored.
Connect:

Specifiy whether to try and connect to the target after flashing.

Module Registration

Modules are specified on Target or Platform creation by name. In order to find the class associated with the name, the module needs to be registered with devlib. This is accomplished by passing the module class into register_module() method once it is defined.

Note

If you’re wiring a module to be included as part of devlib code base, you can place the file with the module class under devlib/modules/ in the source and it will be automatically enumerated. There is no need to explicitly register it in that case.

The code snippet below illustrates an implementation of a hard reset function for an “Acme” device.

import os
from devlib import HardResetModule, register_module


class AcmeHardReset(HardResetModule):

    name = 'acme_hard_reset'

    def __call__(self):
        # Assuming Acme board comes with a "reset-acme-board" utility
        os.system('reset-acme-board {}'.format(self.target.name))

register_module(AcmeHardReset)