This section discusses the operations manipulating the out-of-band interrupt stage, along with the current execution stage of an arbitrary routine.
Before you can direct the incoming interrupt flow to out-of-band handlers, you need to install the out-of-band interrupt stage. Conversely, you need to remove the out-of-band stage from the interrupt pipeline when you are done with receiving out-of-band events.
A symbolic name describing the high priority interrupt stage which is being installed. This information is merely used in kernel messages, so it should be short but descriptive enough. For instance, the EVL core installs the “EVL” stage.
This call enables the out-of-band stage context in the interrupt pipeline, which in turn allows an autonomous core to install out-of-band handlers for interrupts. It returns zero on success, or a negated error code if something went wrong:
-EBUSY The out-of-band stage is already enabled.
This call disables the out-of-band stage context in the interrupt pipeline. From that point, the interrupt flow is exclusively directed to the in-band stage.
This call does not perform any serialization with ongoing
interrupt handling on remote CPUs whatsoever. The autonomous core must
synchronize with remote CPUs before calling disable_oob_stage()
to
prevent them from running out-of-band handlers while the out-of-band
stage is being dismantled. This is particularly important if these
handlers belong to a dynamically loaded module which might be unloaded
right after disable_oob_stage()
returns. In that case, you certainly
don’t want the .text section containing interrupt handlers to vanish
while they are still running.
Sometimes you may need to escalate the current execution stage from
in-band to out-of-band, only for running a particular routine. This
can be done using run_oob_call()
. For instance, the EVL core is
using this service to escalate calls to its rescheduling procedure to
the out-of-band stage, as described in the discussion about switching
task contexts with Dovetail’s
support for alternate scheduling.
The address of the routine to execute on the out-of-band stage.
The routine argument.
run_oob_call() first switches the current execution stage to out-of-band - if need be - then calls the routine with hard interrupts disabled (i.e. disabled in the CPU). Upon return, the integer value returned by fn() is passed back to the caller.
Because the routine may switch the execution stage back to in-band for the calling context, run_oob_call() restores the original stage only if it did not change in the meantime. In addition, the interrupt log of the current CPU is synchronized before returning to the caller. The following matrix describes the logic for determining which epilogue should be performed before leaving run_oob_call(), depending on the active stage on entry to the latter and on return from fn():
On entry to run_oob_call() | At exit from fn() | Epilogue |
---|---|---|
out-of-band | out-of-band | sync current stage if not stalled |
in-band | out-of-band | switch to in-band + sync both stages |
out-of-band | in-band | sync both stages |
in-band | in-band | sync both stages |
run_oob_call() is a lightweight operation that switches the CPU to the out-of-band interrupt stage for the duration of the call, whatever the underlying context may be. This is different from switching a task context to the out-of-band stage by offloading it to the autonomous core for scheduling. The latter operation would involve a more complex procedure.