1.. _modules:
2
3Modules
4=======
5
6Modules add additional functionality to the core :class:`Target` interface.
7Usually, it is support for specific subsystems on the target. Modules are
8instantiated as attributes of the :class:`Target` instance.
9
10hotplug
11-------
12
13Kernel ``hotplug`` subsystem allows offlining ("removing") cores from the
14system, and onlining them back in. The ``devlib`` module exposes a simple
15interface to this subsystem
16
17.. code:: python
18
19   from devlib import LocalLinuxTarget
20   target = LocalLinuxTarget()
21
22   # offline cpus 2 and 3, "removing" them from the system
23   target.hotplug.offline(2, 3)
24
25   # bring CPU 2 back in
26   target.hotplug.online(2)
27
28   # Make sure all cpus are online
29   target.hotplug.online_all()
30
31cpufreq
32-------
33
34``cpufreq`` is the kernel subsystem for managing DVFS (Dynamic Voltage and
35Frequency Scaling). It allows controlling frequency ranges and switching
36policies (governors). The ``devlib`` module exposes the following interface
37
38.. note:: On ARM big.LITTLE systems, all cores on a cluster (usually all cores
39          of the same type) are in the same frequency domain, so setting
40          ``cpufreq`` state on one core on a cluster will affect all cores on
41          that cluster. Because of this, some devices only expose cpufreq sysfs
42          interface (which is what is used by the ``devlib`` module) on the
43          first cpu in a cluster. So to keep your scripts portable, always use
44          the fist (online) CPU in a cluster to set ``cpufreq`` state.
45
46.. method:: target.cpufreq.list_governors(cpu)
47
48   List cpufreq governors available for the specified cpu. Returns a list of
49   strings.
50
51   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
52               ``1`` or ``"cpu1"``).
53
54.. method:: target.cpufreq.list_governor_tunables(cpu)
55
56   List the tunables for the specified cpu's current governor.
57
58   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
59       ``1`` or ``"cpu1"``).
60
61
62.. method:: target.cpufreq.get_governor(cpu)
63
64   Returns the name of the currently set governor for the specified cpu.
65
66   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
67               ``1`` or ``"cpu1"``).
68
69.. method:: target.cpufreq.set_governor(cpu, governor, \*\*kwargs)
70
71   Sets the governor for the specified cpu.
72
73   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
74        ``1`` or ``"cpu1"``).
75   :param governor: The name of the governor. This must be one of the governors
76                supported by the CPU (as returned by ``list_governors()``.
77
78   Keyword arguments may be used to specify governor tunable values.
79
80
81.. method:: target.cpufreq.get_governor_tunables(cpu)
82
83   Return a dict with the values of the specified CPU's current governor.
84
85   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
86       ``1`` or ``"cpu1"``).
87
88.. method:: target.cpufreq.set_governor_tunables(cpu, \*\*kwargs)
89
90   Set the tunables for the current governor on the specified CPU.
91
92   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
93       ``1`` or ``"cpu1"``).
94
95   Keyword arguments should be used to specify tunable values.
96
97.. method:: target.cpufreq.list_frequencies(cpu)
98
99   List DVFS frequencies supported by the specified CPU. Returns a list of ints.
100
101   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
102       ``1`` or ``"cpu1"``).
103
104.. method:: target.cpufreq.get_min_frequency(cpu)
105            target.cpufreq.get_max_frequency(cpu)
106            target.cpufreq.set_min_frequency(cpu, frequency[, exact=True])
107            target.cpufreq.set_max_frequency(cpu, frequency[, exact=True])
108
109   Get and set min and max frequencies on the specified CPU. "set" functions are
110   available with all governors other than ``userspace``.
111
112   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
113       ``1`` or ``"cpu1"``).
114   :param frequency: Frequency to set.
115
116.. method:: target.cpufreq.get_frequency(cpu)
117            target.cpufreq.set_frequency(cpu, frequency[, exact=True])
118
119   Get and set current frequency on the specified CPU. ``set_frequency`` is only
120   available if the current governor is ``userspace``.
121
122   :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
123       ``1`` or ``"cpu1"``).
124   :param frequency: Frequency to set.
125
126cpuidle
127-------
128
129``cpuidle`` is the kernel subsystem for managing CPU low power (idle) states.
130
131.. method:: target.cpuidle.get_driver()
132
133   Return the name current cpuidle driver.
134
135.. method:: target.cpuidle.get_governor()
136
137   Return the name current cpuidle governor (policy).
138
139.. method:: target.cpuidle.get_states([cpu=0])
140
141   Return idle states (optionally, for the specified CPU). Returns a list of
142   :class:`CpuidleState` instances.
143
144.. method:: target.cpuidle.get_state(state[, cpu=0])
145
146   Return :class:`CpuidleState` instance (optionally, for the specified CPU)
147   representing the specified idle state. ``state`` can be either an integer
148   index of the state or a string with the states ``name`` or ``desc``.
149
150.. method:: target.cpuidle.enable(state[, cpu=0])
151            target.cpuidle.disable(state[, cpu=0])
152            target.cpuidle.enable_all([cpu=0])
153            target.cpuidle.disable_all([cpu=0])
154
155    Enable or disable the specified or all states (optionally on the specified
156    CPU.
157
158You can also call ``enable()`` or ``disable()`` on :class:`CpuidleState` objects
159returned by get_state(s).
160
161cgroups
162-------
163
164TODO
165
166hwmon
167-----
168
169TODO
170
171API
172---
173
174Generic Module API Description
175~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
176
177Modules implement discrete, optional pieces of functionality ("optional" in the
178sense that the functionality may or may not be present on the target device, or
179that it may or may not be necessary for a particular application).
180
181Every module (ultimately) derives from :class:`Module` class.  A module must
182define the following class attributes:
183
184:name: A unique name for the module. This cannot clash with any of the existing
185       names and must be a valid Python identifier, but is otherwise free-form.
186:kind: This identifies the type of functionality a module implements, which in
187       turn determines the interface implemented by the module (all modules of
188       the same kind must expose a consistent interface). This must be a valid
189       Python identifier, but is otherwise free-form, though, where possible,
190       one should try to stick to an already-defined kind/interface, lest we end
191       up with a bunch of modules implementing similar functionality but
192       exposing slightly different interfaces.
193
194       .. note:: It is possible to omit ``kind`` when defining a module, in
195                 which case the module's ``name`` will be treated as its
196                 ``kind`` as well.
197
198:stage: This defines when the module will be installed into a :class:`Target`.
199        Currently, the following values are allowed:
200
201        :connected: The module is installed after a connection to the target has
202                    been established. This is the default.
203        :early: The module will be installed when a :class:`Target` is first
204                created. This should be used for modules that do not rely on a
205                live connection to the target.
206
207Additionally, a module must implement a static (or class) method :func:`probe`:
208
209.. method:: Module.probe(target)
210
211    This method takes a :class:`Target` instance and returns ``True`` if this
212    module is supported by that target, or ``False`` otherwise.
213
214    .. note:: If the module ``stage`` is ``"early"``, this method cannot assume
215              that a connection has been established (i.e. it can only access
216              attributes of the Target that do not rely on a connection).
217
218Installation and invocation
219***************************
220
221The default installation method will create an instance of a module (the
222:class:`Target` instance being the sole argument) and assign it to the target
223instance attribute named after the module's ``kind`` (or ``name`` if ``kind`` is
224``None``).
225
226It is possible to change the installation procedure for a module by overriding
227the default :func:`install` method. The method must have the following
228signature:
229
230.. method:: Module.install(cls, target, **kwargs)
231
232    Install the module into the target instance.
233
234
235Implementation and Usage Patterns
236*********************************
237
238There are two common ways to implement the above API, corresponding to the two
239common uses for modules:
240
241- If a module provides an interface to a particular set of functionality (e.g.
242  an OS subsystem), that  module would typically derive directly form
243  :class:`Module` and  would leave ``kind`` unassigned, so that it is accessed
244  by it name. Its instance's methods and attributes provide the interface for
245  interacting with its functionality. For examples of this type of module, see
246  the subsystem modules listed above (e.g. ``cpufreq``).
247- If a module provides a platform- or infrastructure-specific implementation of
248  a common function, the module would derive from one of :class:`Module`
249  subclasses that define the interface for that function. In that case the
250  module would be accessible via the common ``kind`` defined its super. The
251  module would typically implement :func:`__call__` and be invoked directly. For
252  examples of this type of module, see common function interface definitions
253  below.
254
255
256Common Function Interfaces
257~~~~~~~~~~~~~~~~~~~~~~~~~~
258
259This section documents :class:`Module` classes defining interface for common
260functions. Classes derived from them provide concrete implementations for
261specific platforms.
262
263
264HardResetModule
265***************
266
267.. attribute:: HardResetModule.kind
268
269    "hard_reset"
270
271.. method:: HardResetModule.__call__()
272
273    Must be implemented by derived classes.
274
275    Implements hard reset for a target devices. The equivalent of physically
276    power cycling the device.  This may be used by client code in situations
277    where the target becomes unresponsive and/or a regular reboot is not
278    possible.
279
280
281BootModule
282**********
283
284.. attribute:: BootModule.kind
285
286    "hard_reset"
287
288.. method:: BootModule.__call__()
289
290    Must be implemented by derived classes.
291
292    Implements a boot procedure. This takes the device from (hard or soft)
293    reset to a booted state where the device is ready to accept connections. For
294    a lot of commercial devices the process is entirely automatic, however some
295    devices (e.g. development boards), my require additional steps, such as
296    interactions with the bootloader, in order to boot into the OS.
297
298.. method:: Bootmodule.update(\*\*kwargs)
299
300    Update the boot settings. Some boot sequences allow specifying settings
301    that will be utilized during boot (e.g. linux kernel boot command line). The
302    default implementation will set each setting in ``kwargs`` as an attribute of
303    the boot module (or update the existing attribute).
304
305
306FlashModule
307***********
308
309.. attribute:: FlashModule.kind
310
311    "flash"
312
313.. method:: __call__(image_bundle=None, images=None, boot_config=None)
314
315    Must be implemented by derived classes.
316
317    Flash the target platform with the specified images.
318
319    :param image_bundle: A compressed bundle of image files with any associated
320                         metadata. The format of the bundle is specific to a
321                         particular implementation.
322    :param images: A dict mapping image names/identifiers to the path on the
323                   host file system of the corresponding image file. If both
324                   this and ``image_bundle`` are specified, individual images
325                   will override those in the bundle.
326    :param boot_config: Some platforms require specifying boot arguments at the
327                        time of flashing the images, rather than during each
328                        reboot. For other platforms, this will be ignored.
329
330
331Module Registration
332~~~~~~~~~~~~~~~~~~~
333
334Modules are specified on :class:`Target` or :class:`Platform` creation by name.
335In order to find the class associated with the name, the module needs to be
336registered with ``devlib``. This is accomplished by passing the module class
337into :func:`register_module` method once it is defined.
338
339.. note:: If you're wiring a module to be included as part of ``devlib`` code
340          base, you can place the file with the module class under
341          ``devlib/modules/`` in the source and it will be automatically
342          enumerated. There is no need to explicitly register it in that case.
343
344The code snippet below illustrates an implementation of a hard reset function
345for an "Acme" device.
346
347.. code:: python
348
349    import os
350    from devlib import HardResetModule, register_module
351
352
353    class AcmeHardReset(HardResetModule):
354
355        name = 'acme_hard_reset'
356
357        def __call__(self):
358            # Assuming Acme board comes with a "reset-acme-board" utility
359            os.system('reset-acme-board {}'.format(self.target.name))
360
361    register_module(AcmeHardReset)
362
363