From 5ee0abed51231949ef91d7f8e1115be69ed91e93 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Feb 2021 14:45:34 +0000 Subject: 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 Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Tested-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210219144617.4782-2-peter.maydell@linaro.org --- docs/devel/clocks.rst | 52 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) (limited to 'docs') diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst index c54bbb8240..cd344e3fe5 100644 --- a/docs/devel/clocks.rst +++ b/docs/devel/clocks.rst @@ -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(); -- cgit v1.2.3-55-g7522 From e4341623a3b87e7eca87d42b7b88da967cd21c49 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Feb 2021 14:45:35 +0000 Subject: clock: Add ClockPreUpdate callback event type Add a new callback event type ClockPreUpdate, which is called on period changes before the period is updated. Signed-off-by: Peter Maydell Reviewed-by: Luc Michel Reviewed-by: Hao Wu Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 20210219144617.4782-3-peter.maydell@linaro.org --- docs/devel/clocks.rst | 9 ++++++++- hw/core/clock.c | 3 +++ include/hw/clock.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst index cd344e3fe5..f0391e76b4 100644 --- a/docs/devel/clocks.rst +++ b/docs/devel/clocks.rst @@ -181,7 +181,14 @@ events. The events currently supported are: - * ``ClockUpdate`` : called after the input clock's period has changed + * ``ClockPreUpdate`` : called when the input clock's period is about to + update. This is useful if the device needs to do some action for + which it needs to know the old value of the clock period. During + this callback, Clock API functions like ``clock_get()`` or + ``clock_ticks_to_ns()`` will use the old period. + * ``ClockUpdate`` : called after the input clock's period has changed. + During this callback, Clock API functions like ``clock_ticks_to_ns()`` + will use the new period. Note that a clock only has one callback: it is not possible to register different functions for different events. You must register a single diff --git a/hw/core/clock.c b/hw/core/clock.c index 4479eff145..fc5a99683f 100644 --- a/hw/core/clock.c +++ b/hw/core/clock.c @@ -81,6 +81,9 @@ static void clock_propagate_period(Clock *clk, bool call_callbacks) QLIST_FOREACH(child, &clk->children, sibling) { if (child->period != clk->period) { + if (call_callbacks) { + clock_call_callback(child, ClockPreUpdate); + } child->period = clk->period; trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period), diff --git a/include/hw/clock.h b/include/hw/clock.h index 282a37f7c5..2ba44e1442 100644 --- a/include/hw/clock.h +++ b/include/hw/clock.h @@ -30,6 +30,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(Clock, CLOCK) */ typedef enum ClockEvent { ClockUpdate = 1, /* Clock period has just updated */ + ClockPreUpdate = 2, /* Clock period is about to update */ } ClockEvent; typedef void ClockCallback(void *opaque, ClockEvent event); -- cgit v1.2.3-55-g7522 From cd3a53b727d2f86e9db795cee69cc142332ca079 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Feb 2021 14:45:36 +0000 Subject: clock: Add clock_ns_to_ticks() function Add a clock_ns_to_ticks() function which does the opposite of clock_ticks_to_ns(): given a duration in nanoseconds, it returns the number of clock ticks that would happen in that time. This is useful for devices that have a free running counter register whose value can be calculated when it is read. Signed-off-by: Peter Maydell Reviewed-by: Luc Michel Reviewed-by: Hao Wu Tested-by: Philippe Mathieu-Daudé Message-id: 20210219144617.4782-4-peter.maydell@linaro.org --- docs/devel/clocks.rst | 12 ++++++++++++ include/hw/clock.h | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) (limited to 'docs') diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst index f0391e76b4..956bd147ea 100644 --- a/docs/devel/clocks.rst +++ b/docs/devel/clocks.rst @@ -360,6 +360,18 @@ rather than simply passing it to a QEMUTimer function like ``timer_mod_ns()`` then you should be careful to avoid overflow in those calculations, of course.) +Obtaining tick counts +--------------------- + +For calculations where you need to know the number of ticks in +a given duration, use ``clock_ns_to_ticks()``. This function handles +possible non-whole-number-of-nanoseconds periods and avoids +potential rounding errors. It will return '0' if the clock is stopped +(i.e. it has period zero). If the inputs imply a tick count that +overflows a 64-bit value (a very long duration for a clock with a +very short period) the output value is truncated, so effectively +the 64-bit output wraps around. + Changing a clock period ----------------------- diff --git a/include/hw/clock.h b/include/hw/clock.h index 2ba44e1442..a7187eab95 100644 --- a/include/hw/clock.h +++ b/include/hw/clock.h @@ -286,6 +286,47 @@ static inline uint64_t clock_ticks_to_ns(const Clock *clk, uint64_t ticks) return ns_low >> 32 | ns_high << 32; } +/** + * clock_ns_to_ticks: + * @clk: the clock to query + * @ns: duration in nanoseconds + * + * Returns the number of ticks this clock would make in the given + * number of nanoseconds. Because a clock can have a period which + * is not a whole number of nanoseconds, it is important to use this + * function rather than attempting to obtain a "period in nanoseconds" + * value and then dividing the duration by that value. + * + * If the clock is stopped (ie it has period zero), returns 0. + * + * For some inputs the result could overflow a 64-bit value (because + * the clock's period is short and the duration is long). In these + * cases we truncate the result to a 64-bit value. This is on the + * assumption that generally the result is going to be used to report + * a 32-bit or 64-bit guest register value, so wrapping either cannot + * happen or is the desired behaviour. + */ +static inline uint64_t clock_ns_to_ticks(const Clock *clk, uint64_t ns) +{ + /* + * ticks = duration_in_ns / period_in_ns + * = ns / (period / 2^32) + * = (ns * 2^32) / period + * The hi, lo inputs to divu128() are (ns << 32) as a 128 bit value. + */ + uint64_t lo = ns << 32; + uint64_t hi = ns >> 32; + if (clk->period == 0) { + return 0; + } + /* + * Ignore divu128() return value as we've caught div-by-zero and don't + * need different behaviour for overflow. + */ + divu128(&lo, &hi, clk->period); + return lo; +} + /** * clock_is_enabled: * @clk: a clock -- cgit v1.2.3-55-g7522 From dd750743ecd01352ad7697cabd58cb26abf11efd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Feb 2021 14:46:16 +0000 Subject: docs/system/arm/mps2.rst: Document the new mps3-an547 board Add brief documentation of the new mps3-an547 board. Signed-off-by: Peter Maydell Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210219144617.4782-44-peter.maydell@linaro.org --- docs/system/arm/mps2.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/system/arm/mps2.rst b/docs/system/arm/mps2.rst index 601ccea15c..f83b151787 100644 --- a/docs/system/arm/mps2.rst +++ b/docs/system/arm/mps2.rst @@ -1,5 +1,5 @@ -Arm MPS2 and MPS3 boards (``mps2-an385``, ``mps2-an386``, ``mps2-an500``, ``mps2-an505``, ``mps2-an511``, ``mps2-an521``, ``mps3-an524``) -========================================================================================================================================= +Arm MPS2 and MPS3 boards (``mps2-an385``, ``mps2-an386``, ``mps2-an500``, ``mps2-an505``, ``mps2-an511``, ``mps2-an521``, ``mps3-an524``, ``mps3-an547``) +========================================================================================================================================================= These board models all use Arm M-profile CPUs. @@ -27,6 +27,8 @@ QEMU models the following FPGA images: Dual Cortex-M33 as documented in Arm Application Note AN521 ``mps3-an524`` Dual Cortex-M33 on an MPS3, as documented in Arm Application Note AN524 +``mps3-an547`` + Cortex-M55 on an MPS3, as documented in Arm Application Note AN547 Differences between QEMU and real hardware: -- cgit v1.2.3-55-g7522