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 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- include/hw/clock.h | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'include/hw/clock.h') diff --git a/include/hw/clock.h b/include/hw/clock.h index e5f45e2626..282a37f7c5 100644 --- a/include/hw/clock.h +++ b/include/hw/clock.h @@ -22,7 +22,17 @@ #define TYPE_CLOCK "clock" OBJECT_DECLARE_SIMPLE_TYPE(Clock, CLOCK) -typedef void ClockCallback(void *opaque); +/* + * Argument to ClockCallback functions indicating why the callback + * has been called. A mask of these values logically ORed together + * is used to specify which events are interesting when the callback + * is registered, so these values must all be different bit values. + */ +typedef enum ClockEvent { + ClockUpdate = 1, /* Clock period has just updated */ +} ClockEvent; + +typedef void ClockCallback(void *opaque, ClockEvent event); /* * clock store a value representing the clock's period in 2^-32ns unit. @@ -50,6 +60,7 @@ typedef void ClockCallback(void *opaque); * @canonical_path: clock path string cache (used for trace purpose) * @callback: called when clock changes * @callback_opaque: argument for @callback + * @callback_events: mask of events when callback should be called * @source: source (or parent in clock tree) of the clock * @children: list of clocks connected to this one (it is their source) * @sibling: structure used to form a clock list @@ -67,6 +78,7 @@ struct Clock { char *canonical_path; ClockCallback *callback; void *callback_opaque; + unsigned int callback_events; /* Clocks are organized in a clock tree */ Clock *source; @@ -114,10 +126,15 @@ Clock *clock_new(Object *parent, const char *name); * @clk: the clock to register the callback into * @cb: the callback function * @opaque: the argument to the callback + * @events: the events the callback should be called for + * (logical OR of ClockEvent enum values) * * Register a callback called on every clock update. + * Note that a clock has only one callback: you cannot register + * different callback functions for different events. */ -void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque); +void clock_set_callback(Clock *clk, ClockCallback *cb, + void *opaque, unsigned int events); /** * clock_clear_callback: -- cgit 1.4.1 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 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 'include/hw/clock.h') 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 1.4.1 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 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 'include/hw/clock.h') 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 1.4.1