clock: Add ClockEvent parameter to callbacks

The Clock framework allows users to specify a callback which is
called after the clock's period has been updated.  Some users need to
also have a callback which is called before the clock period is
updated.

As the first step in adding support for notifying Clock users on
pre-update events, add an argument to the ClockCallback to specify
what event is being notified, and add an argument to the various
functions for registering a callback to specify which events are
of interest to that callback.

Note that the documentation update renders correct the previously
incorrect claim in 'Adding a new clock' that callbacks "will be
explained in a following section".

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: Luc Michel <luc@lmichel.fr>
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20210219144617.4782-2-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2021-02-19 14:45:34 +00:00
parent 0436c55edf
commit 5ee0abed51
20 changed files with 161 additions and 58 deletions

View file

@ -80,11 +80,12 @@ Adding clocks to a device must be done during the init method of the Device
instance.
To add an input clock to a device, the function ``qdev_init_clock_in()``
must be used. It takes the name, a callback and an opaque parameter
for the callback (this will be explained in a following section).
must be used. It takes the name, a callback, an opaque parameter
for the callback and a mask of events when the callback should be
called (this will be explained in a following section).
Output is simpler; only the name is required. Typically::
qdev_init_clock_in(DEVICE(dev), "clk_in", clk_in_callback, dev);
qdev_init_clock_in(DEVICE(dev), "clk_in", clk_in_callback, dev, ClockUpdate);
qdev_init_clock_out(DEVICE(dev), "clk_out");
Both functions return the created Clock pointer, which should be saved in the
@ -113,7 +114,7 @@ output.
* callback for the input clock (see "Callback on input clock
* change" section below for more information).
*/
static void clk_in_callback(void *opaque);
static void clk_in_callback(void *opaque, ClockEvent event);
/*
* static array describing clocks:
@ -124,7 +125,7 @@ output.
* the clk_out field of a MyDeviceState structure.
*/
static const ClockPortInitArray mydev_clocks = {
QDEV_CLOCK_IN(MyDeviceState, clk_in, clk_in_callback),
QDEV_CLOCK_IN(MyDeviceState, clk_in, clk_in_callback, ClockUpdate),
QDEV_CLOCK_OUT(MyDeviceState, clk_out),
QDEV_CLOCK_END
};
@ -153,6 +154,40 @@ nothing else to do. This value will be propagated to other clocks when
connecting the clocks together and devices will fetch the right value during
the first reset.
Clock callbacks
---------------
You can give a clock a callback function in several ways:
* by passing it as an argument to ``qdev_init_clock_in()``
* as an argument to the ``QDEV_CLOCK_IN()`` macro initializing an
array to be passed to ``qdev_init_clocks()``
* by directly calling the ``clock_set_callback()`` function
The callback function must be of this type:
.. code-block:: c
typedef void ClockCallback(void *opaque, ClockEvent event);
The ``opaque`` argument is the pointer passed to ``qdev_init_clock_in()``
or ``clock_set_callback()``; for ``qdev_init_clocks()`` it is the
``dev`` device pointer.
The ``event`` argument specifies why the callback has been called.
When you register the callback you specify a mask of ClockEvent values
that you are interested in. The callback will only be called for those
events.
The events currently supported are:
* ``ClockUpdate`` : called after the input clock's period has changed
Note that a clock only has one callback: it is not possible to register
different functions for different events. You must register a single
callback which listens for all of the events you are interested in,
and use the ``event`` argument to identify which event has happened.
Retrieving clocks from a device
-------------------------------
@ -231,7 +266,7 @@ object during device instance init. For example:
.. code-block:: c
clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback,
dev);
dev, ClockUpdate);
/* set initial value to 10ns / 100MHz */
clock_set_ns(clk, 10);
@ -267,11 +302,12 @@ next lowest integer. This implies some inaccuracy due to the rounding,
so be cautious about using it in calculations.
It is also possible to register a callback on clock frequency changes.
Here is an example:
Here is an example, which assumes that ``clock_callback`` has been
specified as the callback for the ``ClockUpdate`` event:
.. code-block:: c
void clock_callback(void *opaque) {
void clock_callback(void *opaque, ClockEvent event) {
MyDeviceState *s = (MyDeviceState *) opaque;
/*
* 'opaque' is the argument passed to qdev_init_clock_in();