All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] New APIs for the Clock framework
@ 2021-02-09 13:20 Peter Maydell
  2021-02-09 13:20 ` [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
                   ` (3 more replies)
  0 siblings, 4 replies; 18+ messages in thread
From: Peter Maydell @ 2021-02-09 13:20 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

Hi; this patchset proposes a couple of new APIs for Clock, which I
found I needed/wanted for a work-in-progress patchset.

In this v2, the only change from the RFC series is that as Luc
suggested I have made the clock-callback registration mechanisms
all take a new parameter specifying the mask of events which
the callback should be invoked for. (This is instead of calling
all callbacks on all events and requiring them to look at their
'events' argument to see if they should ignore the call.)

If people prefer I can keep hold of these patches until I have
the board-support series that makes use of them ready to post;
but I think if we're happy with the new APIs we could reasonably
put them in to the tree sooner (especially since patch 1 means
updates to all input Clock users).


The problem the first two patches are trying to solve is that I found
that I wanted the old value of the Clock's period when my device got a
notification about a frequency/period change. The current
ClockCallback API calls you after the period has changed, so the Clock
is already using the new period. I wanted this because my timer device
has a register that's basically a free-running up-counter; the value
of that counter can be calculated with:

  s->ticks_then + clock_ns_to_ticks(s->clk, now - s->ns_then);

where (ns_then, ticks_then) are a tuple of a QEMU_CLOCK_VIRTUAL time
and the tick count at that point. Whenever the clock frequency changes
we calculate a new (ns_then, ticks_then) to use as the baseline for
future counter value reads, but in order to do that we must calculate
ticks_then using the *old* clock period.

My solution to this is to add a ClockEvent argument to the callback
function, which is an enum:

  ClockPreUpdate : callback called before period change
  ClockUpdate : callback called after period change

When a callback function is registered a mask of event values tells
the framework which events the callback should be called for.

The problem the third patch addresses is that we don't have a function
for "tell me how many times this clock would tick in this length of
time". clock_ns_to_ticks() does the inverse of the clock_ticks_to_ns()
that we already have. Two points in particular where comment would be
useful:

 * I chose to make the overflow case (where a clock has a very short
   period and the specified length of time is very long, so the clock
   would tick more than UINT64_MAX times) just let the value wrap
   around, on the basis that usually this is being used to calculate a
   guest register value that's in a 64 bit or 32 bit register, and so
   wrap-around is the right behaviour.  But I'm not 100% set on this
   if somebody has a better idea.

 * The calculation needs to do a 96-bit / 64 bit => 64 bit division,
   for which the best thing we have is divu128(). This is particularly
   painful on 32-bit hosts. I don't suppose there's anything clever we
   can do to make this better ?

Patch 4 just uses clock_ns_to_ticks() in the one place in the
current codebase where we're currently using clock_ticks_to_ns()
and manual calculation.

thanks
-- PMM

Peter Maydell (4):
  clock: Add ClockEvent parameter to callbacks
  clock: Add ClockPreUpdate callback event type
  clock: Add clock_ns_to_ticks() function
  hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks()

 docs/devel/clocks.rst            | 71 ++++++++++++++++++++++++++++----
 include/hw/clock.h               | 63 +++++++++++++++++++++++++++-
 include/hw/qdev-clock.h          | 17 +++++---
 hw/adc/npcm7xx_adc.c             |  2 +-
 hw/arm/armsse.c                  |  9 ++--
 hw/char/cadence_uart.c           |  4 +-
 hw/char/ibex_uart.c              |  4 +-
 hw/char/pl011.c                  |  5 ++-
 hw/core/clock.c                  | 23 +++++++++--
 hw/core/qdev-clock.c             |  8 ++--
 hw/mips/cps.c                    |  2 +-
 hw/misc/bcm2835_cprman.c         | 23 +++++++----
 hw/misc/npcm7xx_clk.c            | 26 ++++++++++--
 hw/misc/npcm7xx_pwm.c            |  2 +-
 hw/misc/zynq_slcr.c              |  5 ++-
 hw/timer/cmsdk-apb-dualtimer.c   |  5 ++-
 hw/timer/cmsdk-apb-timer.c       |  4 +-
 hw/timer/npcm7xx_timer.c         |  6 +--
 hw/watchdog/cmsdk-apb-watchdog.c |  5 ++-
 target/mips/cpu.c                |  2 +-
 20 files changed, 226 insertions(+), 60 deletions(-)

-- 
2.20.1



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks
  2021-02-09 13:20 [PATCH v2 0/4] New APIs for the Clock framework Peter Maydell
@ 2021-02-09 13:20 ` Peter Maydell
  2021-02-10 20:53   ` Hao Wu
                     ` (2 more replies)
  2021-02-09 13:20 ` [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 18+ messages in thread
From: Peter Maydell @ 2021-02-09 13:20 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

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>
---
v1->v2: (suggested by Luc) instead of making callback functions check
whether 'event' is one they are interested in, specify mask of
interesting events at callback registration time.
---
 docs/devel/clocks.rst            | 52 +++++++++++++++++++++++++++-----
 include/hw/clock.h               | 21 +++++++++++--
 include/hw/qdev-clock.h          | 17 ++++++++---
 hw/adc/npcm7xx_adc.c             |  2 +-
 hw/arm/armsse.c                  |  9 +++---
 hw/char/cadence_uart.c           |  4 +--
 hw/char/ibex_uart.c              |  4 +--
 hw/char/pl011.c                  |  5 +--
 hw/core/clock.c                  | 20 +++++++++---
 hw/core/qdev-clock.c             |  8 +++--
 hw/mips/cps.c                    |  2 +-
 hw/misc/bcm2835_cprman.c         | 23 ++++++++------
 hw/misc/npcm7xx_clk.c            | 26 +++++++++++++---
 hw/misc/npcm7xx_pwm.c            |  2 +-
 hw/misc/zynq_slcr.c              |  5 +--
 hw/timer/cmsdk-apb-dualtimer.c   |  5 +--
 hw/timer/cmsdk-apb-timer.c       |  4 +--
 hw/timer/npcm7xx_timer.c         |  2 +-
 hw/watchdog/cmsdk-apb-watchdog.c |  5 +--
 target/mips/cpu.c                |  2 +-
 20 files changed, 160 insertions(+), 58 deletions(-)

diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
index c54bbb82409..cd344e3fe5d 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();
diff --git a/include/hw/clock.h b/include/hw/clock.h
index e5f45e2626d..5c73b4e7ae9 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;
+    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, int events);
 
 /**
  * clock_clear_callback:
diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h
index 64ca4d266f2..348ec363525 100644
--- a/include/hw/qdev-clock.h
+++ b/include/hw/qdev-clock.h
@@ -22,6 +22,8 @@
  * @name: the name of the clock (can't be NULL).
  * @callback: optional callback to be called on update or NULL.
  * @opaque: argument for the callback
+ * @events: the events the callback should be called for
+ *          (logical OR of ClockEvent enum values)
  * @returns: a pointer to the newly added clock
  *
  * Add an input clock to device @dev as a clock named @name.
@@ -29,7 +31,8 @@
  * The callback will be called with @opaque as opaque parameter.
  */
 Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
-                          ClockCallback *callback, void *opaque);
+                          ClockCallback *callback, void *opaque,
+                          int events);
 
 /**
  * qdev_init_clock_out:
@@ -105,6 +108,7 @@ void qdev_finalize_clocklist(DeviceState *dev);
  * @output: indicates whether the clock is input or output
  * @callback: for inputs, optional callback to be called on clock's update
  * with device as opaque
+ * @callback_events: mask of ClockEvent values for when callback is called
  * @offset: optional offset to store the ClockIn or ClockOut pointer in device
  * state structure (0 means unused)
  */
@@ -112,6 +116,7 @@ struct ClockPortInitElem {
     const char *name;
     bool is_output;
     ClockCallback *callback;
+    int callback_events;
     size_t offset;
 };
 
@@ -119,10 +124,11 @@ struct ClockPortInitElem {
     (offsetof(devstate, field) + \
      type_check(Clock *, typeof_field(devstate, field)))
 
-#define QDEV_CLOCK(out_not_in, devstate, field, cb) { \
+#define QDEV_CLOCK(out_not_in, devstate, field, cb, cbevents) {  \
     .name = (stringify(field)), \
     .is_output = out_not_in, \
     .callback = cb, \
+    .callback_events = cbevents, \
     .offset = clock_offset_value(devstate, field), \
 }
 
@@ -133,14 +139,15 @@ struct ClockPortInitElem {
  * @field: a field in @_devstate (must be Clock*)
  * @callback: (for input only) callback (or NULL) to be called with the device
  * state as argument
+ * @cbevents: (for input only) ClockEvent mask for when callback is called
  *
  * The name of the clock will be derived from @field
  */
-#define QDEV_CLOCK_IN(devstate, field, callback) \
-    QDEV_CLOCK(false, devstate, field, callback)
+#define QDEV_CLOCK_IN(devstate, field, callback, cbevents)       \
+    QDEV_CLOCK(false, devstate, field, callback, cbevents)
 
 #define QDEV_CLOCK_OUT(devstate, field) \
-    QDEV_CLOCK(true, devstate, field, NULL)
+    QDEV_CLOCK(true, devstate, field, NULL, 0)
 
 #define QDEV_CLOCK_END { .name = NULL }
 
diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
index 870a6d50c27..573f4876dc6 100644
--- a/hw/adc/npcm7xx_adc.c
+++ b/hw/adc/npcm7xx_adc.c
@@ -238,7 +238,7 @@ static void npcm7xx_adc_init(Object *obj)
     memory_region_init_io(&s->iomem, obj, &npcm7xx_adc_ops, s,
                           TYPE_NPCM7XX_ADC, 4 * KiB);
     sysbus_init_mmio(sbd, &s->iomem);
-    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
+    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, ClockUpdate);
 
     for (i = 0; i < NPCM7XX_ADC_NUM_INPUTS; ++i) {
         object_property_add_uint32_ptr(obj, "adci[*]",
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index 26e1a8c95b6..fa155b72022 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -230,9 +230,10 @@ static void armsse_forward_sec_resp_cfg(ARMSSE *s)
     qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in);
 }
 
-static void armsse_mainclk_update(void *opaque)
+static void armsse_mainclk_update(void *opaque, ClockEvent event)
 {
     ARMSSE *s = ARM_SSE(opaque);
+
     /*
      * Set system_clock_scale from our Clock input; this is what
      * controls the tick rate of the CPU SysTick timer.
@@ -251,8 +252,8 @@ static void armsse_init(Object *obj)
     assert(info->num_cpus <= SSE_MAX_CPUS);
 
     s->mainclk = qdev_init_clock_in(DEVICE(s), "MAINCLK",
-                                    armsse_mainclk_update, s);
-    s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL);
+                                    armsse_mainclk_update, s, ClockUpdate);
+    s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL, 0);
 
     memory_region_init(&s->container, obj, "armsse-container", UINT64_MAX);
 
@@ -1120,7 +1121,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
 
     /* Set initial system_clock_scale from MAINCLK */
-    armsse_mainclk_update(s);
+    armsse_mainclk_update(s, ClockUpdate);
 }
 
 static void armsse_idau_check(IDAUInterface *ii, uint32_t address,
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index c603e14012a..ceb677bc5a8 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -519,7 +519,7 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
                              uart_event, NULL, s, NULL, true);
 }
 
-static void cadence_uart_refclk_update(void *opaque)
+static void cadence_uart_refclk_update(void *opaque, ClockEvent event)
 {
     CadenceUARTState *s = opaque;
 
@@ -537,7 +537,7 @@ static void cadence_uart_init(Object *obj)
     sysbus_init_irq(sbd, &s->irq);
 
     s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk",
-            cadence_uart_refclk_update, s);
+                                   cadence_uart_refclk_update, s, ClockUpdate);
     /* initialize the frequency in case the clock remains unconnected */
     clock_set_hz(s->refclk, UART_DEFAULT_REF_CLK);
 
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
index 89f1182c9bf..edcaa30aded 100644
--- a/hw/char/ibex_uart.c
+++ b/hw/char/ibex_uart.c
@@ -396,7 +396,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
     }
 }
 
-static void ibex_uart_clk_update(void *opaque)
+static void ibex_uart_clk_update(void *opaque, ClockEvent event)
 {
     IbexUartState *s = opaque;
 
@@ -466,7 +466,7 @@ static void ibex_uart_init(Object *obj)
     IbexUartState *s = IBEX_UART(obj);
 
     s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock",
-                                  ibex_uart_clk_update, s);
+                                  ibex_uart_clk_update, s, ClockUpdate);
     clock_set_hz(s->f_clk, IBEX_UART_CLOCK);
 
     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index ea4a4e52356..c5621a195ff 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -309,7 +309,7 @@ static void pl011_event(void *opaque, QEMUChrEvent event)
         pl011_put_fifo(opaque, 0x400);
 }
 
-static void pl011_clock_update(void *opaque)
+static void pl011_clock_update(void *opaque, ClockEvent event)
 {
     PL011State *s = PL011(opaque);
 
@@ -378,7 +378,8 @@ static void pl011_init(Object *obj)
         sysbus_init_irq(sbd, &s->irq[i]);
     }
 
-    s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s);
+    s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
+                                ClockUpdate);
 
     s->read_trigger = 1;
     s->ifl = 0x12;
diff --git a/hw/core/clock.c b/hw/core/clock.c
index 76b5f468b6e..71dc1f4de65 100644
--- a/hw/core/clock.c
+++ b/hw/core/clock.c
@@ -39,15 +39,16 @@ Clock *clock_new(Object *parent, const char *name)
     return clk;
 }
 
-void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
+void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque, int events)
 {
     clk->callback = cb;
     clk->callback_opaque = opaque;
+    clk->callback_events = events;
 }
 
 void clock_clear_callback(Clock *clk)
 {
-    clock_set_callback(clk, NULL, NULL);
+    clock_set_callback(clk, NULL, NULL, 0);
 }
 
 bool clock_set(Clock *clk, uint64_t period)
@@ -62,6 +63,17 @@ bool clock_set(Clock *clk, uint64_t period)
     return true;
 }
 
+static void clock_call_callback(Clock *clk, ClockEvent event)
+{
+    /*
+     * Call the Clock's callback for this event, if it has one and
+     * is interested in this event.
+     */
+    if (clk->callback && (clk->callback_events & event)) {
+        clk->callback(clk->callback_opaque, event);
+    }
+}
+
 static void clock_propagate_period(Clock *clk, bool call_callbacks)
 {
     Clock *child;
@@ -72,8 +84,8 @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
             trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
                                CLOCK_PERIOD_TO_HZ(clk->period),
                                call_callbacks);
-            if (call_callbacks && child->callback) {
-                child->callback(child->callback_opaque);
+            if (call_callbacks) {
+                clock_call_callback(child, ClockUpdate);
             }
             clock_propagate_period(child, call_callbacks);
         }
diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c
index eb05f2a13ca..9c55ddc23ee 100644
--- a/hw/core/qdev-clock.c
+++ b/hw/core/qdev-clock.c
@@ -111,7 +111,8 @@ Clock *qdev_init_clock_out(DeviceState *dev, const char *name)
 }
 
 Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
-                            ClockCallback *callback, void *opaque)
+                          ClockCallback *callback, void *opaque,
+                          int events)
 {
     NamedClockList *ncl;
 
@@ -120,7 +121,7 @@ Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
     ncl = qdev_init_clocklist(dev, name, false, NULL);
 
     if (callback) {
-        clock_set_callback(ncl->clock, callback, opaque);
+        clock_set_callback(ncl->clock, callback, opaque, events);
     }
     return ncl->clock;
 }
@@ -137,7 +138,8 @@ void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks)
         if (elem->is_output) {
             *clkp = qdev_init_clock_out(dev, elem->name);
         } else {
-            *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev);
+            *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev,
+                                       elem->callback_events);
         }
     }
 }
diff --git a/hw/mips/cps.c b/hw/mips/cps.c
index 7a0d289efaf..2b436700ce6 100644
--- a/hw/mips/cps.c
+++ b/hw/mips/cps.c
@@ -39,7 +39,7 @@ static void mips_cps_init(Object *obj)
     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     MIPSCPSState *s = MIPS_CPS(obj);
 
-    s->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, NULL);
+    s->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, NULL, 0);
     /*
      * Cover entire address space as there do not seem to be any
      * constraints for the base address of CPC and GIC.
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
index 7e415a017c9..75e6c574d46 100644
--- a/hw/misc/bcm2835_cprman.c
+++ b/hw/misc/bcm2835_cprman.c
@@ -107,7 +107,7 @@ static void pll_update(CprmanPllState *pll)
     clock_update_hz(pll->out, freq);
 }
 
-static void pll_xosc_update(void *opaque)
+static void pll_xosc_update(void *opaque, ClockEvent event)
 {
     pll_update(CPRMAN_PLL(opaque));
 }
@@ -116,7 +116,8 @@ static void pll_init(Object *obj)
 {
     CprmanPllState *s = CPRMAN_PLL(obj);
 
-    s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update, s);
+    s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update,
+                                    s, ClockUpdate);
     s->out = qdev_init_clock_out(DEVICE(s), "out");
 }
 
@@ -209,7 +210,7 @@ static void pll_update_all_channels(BCM2835CprmanState *s,
     }
 }
 
-static void pll_channel_pll_in_update(void *opaque)
+static void pll_channel_pll_in_update(void *opaque, ClockEvent event)
 {
     pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
 }
@@ -219,7 +220,8 @@ static void pll_channel_init(Object *obj)
     CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj);
 
     s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in",
-                                   pll_channel_pll_in_update, s);
+                                   pll_channel_pll_in_update, s,
+                                   ClockUpdate);
     s->out = qdev_init_clock_out(DEVICE(s), "out");
 }
 
@@ -303,7 +305,7 @@ static void clock_mux_update(CprmanClockMuxState *mux)
     clock_update_hz(mux->out, freq);
 }
 
-static void clock_mux_src_update(void *opaque)
+static void clock_mux_src_update(void *opaque, ClockEvent event)
 {
     CprmanClockMuxState **backref = opaque;
     CprmanClockMuxState *s = *backref;
@@ -335,7 +337,8 @@ static void clock_mux_init(Object *obj)
         s->backref[i] = s;
         s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
                                         clock_mux_src_update,
-                                        &s->backref[i]);
+                                        &s->backref[i],
+                                        ClockUpdate);
         g_free(name);
     }
 
@@ -380,7 +383,7 @@ static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s)
     clock_update(s->out, clock_get(src));
 }
 
-static void dsi0hsck_mux_in_update(void *opaque)
+static void dsi0hsck_mux_in_update(void *opaque, ClockEvent event)
 {
     dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
 }
@@ -390,8 +393,10 @@ static void dsi0hsck_mux_init(Object *obj)
     CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
     DeviceState *dev = DEVICE(obj);
 
-    s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, s);
-    s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, s);
+    s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update,
+                                    s, ClockUpdate);
+    s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update,
+                                    s, ClockUpdate);
     s->out = qdev_init_clock_out(DEVICE(s), "out");
 }
 
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
index 0bcae9ce957..a1ee67dc9a1 100644
--- a/hw/misc/npcm7xx_clk.c
+++ b/hw/misc/npcm7xx_clk.c
@@ -586,15 +586,26 @@ static const DividerInitInfo divider_init_info_list[] = {
     },
 };
 
+static void npcm7xx_clk_update_pll_cb(void *opaque, ClockEvent event)
+{
+    npcm7xx_clk_update_pll(opaque);
+}
+
 static void npcm7xx_clk_pll_init(Object *obj)
 {
     NPCM7xxClockPLLState *pll = NPCM7XX_CLOCK_PLL(obj);
 
     pll->clock_in = qdev_init_clock_in(DEVICE(pll), "clock-in",
-            npcm7xx_clk_update_pll, pll);
+                                       npcm7xx_clk_update_pll_cb, pll,
+                                       ClockUpdate);
     pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
 }
 
+static void npcm7xx_clk_update_sel_cb(void *opaque, ClockEvent event)
+{
+    npcm7xx_clk_update_sel(opaque);
+}
+
 static void npcm7xx_clk_sel_init(Object *obj)
 {
     int i;
@@ -603,16 +614,23 @@ static void npcm7xx_clk_sel_init(Object *obj)
     for (i = 0; i < NPCM7XX_CLK_SEL_MAX_INPUT; ++i) {
         sel->clock_in[i] = qdev_init_clock_in(DEVICE(sel),
                 g_strdup_printf("clock-in[%d]", i),
-                npcm7xx_clk_update_sel, sel);
+                npcm7xx_clk_update_sel_cb, sel, ClockUpdate);
     }
     sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
 }
+
+static void npcm7xx_clk_update_divider_cb(void *opaque, ClockEvent event)
+{
+    npcm7xx_clk_update_divider(opaque);
+}
+
 static void npcm7xx_clk_divider_init(Object *obj)
 {
     NPCM7xxClockDividerState *div = NPCM7XX_CLOCK_DIVIDER(obj);
 
     div->clock_in = qdev_init_clock_in(DEVICE(div), "clock-in",
-            npcm7xx_clk_update_divider, div);
+                                       npcm7xx_clk_update_divider_cb,
+                                       div, ClockUpdate);
     div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
 }
 
@@ -875,7 +893,7 @@ static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
 {
     int i;
 
-    s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL);
+    s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL, 0);
 
     /* First pass: init all converter modules */
     QEMU_BUILD_BUG_ON(ARRAY_SIZE(pll_init_info_list) != NPCM7XX_CLOCK_NR_PLLS);
diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
index dabcb6c0f95..ce192bb2741 100644
--- a/hw/misc/npcm7xx_pwm.c
+++ b/hw/misc/npcm7xx_pwm.c
@@ -493,7 +493,7 @@ static void npcm7xx_pwm_init(Object *obj)
     memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s,
                           TYPE_NPCM7XX_PWM, 4 * KiB);
     sysbus_init_mmio(sbd, &s->iomem);
-    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
+    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, 0);
 
     for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
         object_property_add_uint32_ptr(obj, "freq[*]",
diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
index 66504a9d3ab..c66d7db177d 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -307,9 +307,10 @@ static void zynq_slcr_propagate_clocks(ZynqSLCRState *s)
     clock_propagate(s->uart1_ref_clk);
 }
 
-static void zynq_slcr_ps_clk_callback(void *opaque)
+static void zynq_slcr_ps_clk_callback(void *opaque, ClockEvent event)
 {
     ZynqSLCRState *s = (ZynqSLCRState *) opaque;
+
     zynq_slcr_compute_clocks(s);
     zynq_slcr_propagate_clocks(s);
 }
@@ -576,7 +577,7 @@ static const MemoryRegionOps slcr_ops = {
 };
 
 static const ClockPortInitArray zynq_slcr_clocks = {
-    QDEV_CLOCK_IN(ZynqSLCRState, ps_clk, zynq_slcr_ps_clk_callback),
+    QDEV_CLOCK_IN(ZynqSLCRState, ps_clk, zynq_slcr_ps_clk_callback, ClockUpdate),
     QDEV_CLOCK_OUT(ZynqSLCRState, uart0_ref_clk),
     QDEV_CLOCK_OUT(ZynqSLCRState, uart1_ref_clk),
     QDEV_CLOCK_END
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
index ef49f5852d3..d4a509c798e 100644
--- a/hw/timer/cmsdk-apb-dualtimer.c
+++ b/hw/timer/cmsdk-apb-dualtimer.c
@@ -449,7 +449,7 @@ static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
     s->timeritop = 0;
 }
 
-static void cmsdk_apb_dualtimer_clk_update(void *opaque)
+static void cmsdk_apb_dualtimer_clk_update(void *opaque, ClockEvent event)
 {
     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
     int i;
@@ -478,7 +478,8 @@ static void cmsdk_apb_dualtimer_init(Object *obj)
         sysbus_init_irq(sbd, &s->timermod[i].timerint);
     }
     s->timclk = qdev_init_clock_in(DEVICE(s), "TIMCLK",
-                                   cmsdk_apb_dualtimer_clk_update, s);
+                                   cmsdk_apb_dualtimer_clk_update, s,
+                                   ClockUpdate);
 }
 
 static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
index ee51ce3369c..68aa1a76360 100644
--- a/hw/timer/cmsdk-apb-timer.c
+++ b/hw/timer/cmsdk-apb-timer.c
@@ -204,7 +204,7 @@ static void cmsdk_apb_timer_reset(DeviceState *dev)
     ptimer_transaction_commit(s->timer);
 }
 
-static void cmsdk_apb_timer_clk_update(void *opaque)
+static void cmsdk_apb_timer_clk_update(void *opaque, ClockEvent event)
 {
     CMSDKAPBTimer *s = CMSDK_APB_TIMER(opaque);
 
@@ -223,7 +223,7 @@ static void cmsdk_apb_timer_init(Object *obj)
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->timerint);
     s->pclk = qdev_init_clock_in(DEVICE(s), "pclk",
-                                 cmsdk_apb_timer_clk_update, s);
+                                 cmsdk_apb_timer_clk_update, s, ClockUpdate);
 }
 
 static void cmsdk_apb_timer_realize(DeviceState *dev, Error **errp)
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
index 36e2c07db26..4efdf135b82 100644
--- a/hw/timer/npcm7xx_timer.c
+++ b/hw/timer/npcm7xx_timer.c
@@ -627,7 +627,7 @@ static void npcm7xx_timer_init(Object *obj)
     sysbus_init_mmio(sbd, &s->iomem);
     qdev_init_gpio_out_named(dev, &w->reset_signal,
             NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
-    s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL);
+    s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL, 0);
 }
 
 static const VMStateDescription vmstate_npcm7xx_base_timer = {
diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
index 302f1711738..5a2cd46eb76 100644
--- a/hw/watchdog/cmsdk-apb-watchdog.c
+++ b/hw/watchdog/cmsdk-apb-watchdog.c
@@ -310,7 +310,7 @@ static void cmsdk_apb_watchdog_reset(DeviceState *dev)
     ptimer_transaction_commit(s->timer);
 }
 
-static void cmsdk_apb_watchdog_clk_update(void *opaque)
+static void cmsdk_apb_watchdog_clk_update(void *opaque, ClockEvent event)
 {
     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
 
@@ -329,7 +329,8 @@ static void cmsdk_apb_watchdog_init(Object *obj)
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->wdogint);
     s->wdogclk = qdev_init_clock_in(DEVICE(s), "WDOGCLK",
-                                    cmsdk_apb_watchdog_clk_update, s);
+                                    cmsdk_apb_watchdog_clk_update, s,
+                                    ClockUpdate);
 
     s->is_luminary = false;
     s->id = cmsdk_apb_watchdog_id;
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index ad163ead625..2f3d9d2ce2c 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -636,7 +636,7 @@ static void mips_cpu_initfn(Object *obj)
     MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj);
 
     cpu_set_cpustate_pointers(cpu);
-    cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu);
+    cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0);
     env->cpu_model = mcc->cpu_def;
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type
  2021-02-09 13:20 [PATCH v2 0/4] New APIs for the Clock framework Peter Maydell
  2021-02-09 13:20 ` [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
@ 2021-02-09 13:20 ` Peter Maydell
  2021-02-10 20:55   ` Hao Wu
                     ` (2 more replies)
  2021-02-09 13:20 ` [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
  2021-02-09 13:20 ` [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
  3 siblings, 3 replies; 18+ messages in thread
From: Peter Maydell @ 2021-02-09 13:20 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

Add a new callback event type ClockPreUpdate, which is called on
period changes before the period is updated.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 docs/devel/clocks.rst | 9 ++++++++-
 include/hw/clock.h    | 1 +
 hw/core/clock.c       | 3 +++
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
index cd344e3fe5d..f0391e76b4f 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/include/hw/clock.h b/include/hw/clock.h
index 5c73b4e7ae9..d7a6673c29e 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);
diff --git a/hw/core/clock.c b/hw/core/clock.c
index 71dc1f4de65..2c86091d8a3 100644
--- a/hw/core/clock.c
+++ b/hw/core/clock.c
@@ -80,6 +80,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),
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function
  2021-02-09 13:20 [PATCH v2 0/4] New APIs for the Clock framework Peter Maydell
  2021-02-09 13:20 ` [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
  2021-02-09 13:20 ` [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
@ 2021-02-09 13:20 ` Peter Maydell
  2021-02-10 21:00   ` Hao Wu
                     ` (2 more replies)
  2021-02-09 13:20 ` [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
  3 siblings, 3 replies; 18+ messages in thread
From: Peter Maydell @ 2021-02-09 13:20 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

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 <peter.maydell@linaro.org>
---
I have made the overflow behaviour here be "wrap", with justification
as per the comment; but I'm not 100% set on this.
---
 docs/devel/clocks.rst | 12 ++++++++++++
 include/hw/clock.h    | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
index f0391e76b4f..956bd147ea0 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 d7a6673c29e..79c3b7ebe40 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
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks()
  2021-02-09 13:20 [PATCH v2 0/4] New APIs for the Clock framework Peter Maydell
                   ` (2 preceding siblings ...)
  2021-02-09 13:20 ` [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
@ 2021-02-09 13:20 ` Peter Maydell
  2021-02-10 21:01   ` Hao Wu
                     ` (2 more replies)
  3 siblings, 3 replies; 18+ messages in thread
From: Peter Maydell @ 2021-02-09 13:20 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

Use the new clock_ns_to_ticks() function in npcm7xx_timer where
appropriate.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/timer/npcm7xx_timer.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
index 4efdf135b82..32f5e021f85 100644
--- a/hw/timer/npcm7xx_timer.c
+++ b/hw/timer/npcm7xx_timer.c
@@ -138,8 +138,8 @@ static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
 /* Convert a time interval in nanoseconds to a timer cycle count. */
 static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
 {
-    return ns / clock_ticks_to_ns(t->ctrl->clock,
-                                  npcm7xx_tcsr_prescaler(t->tcsr));
+    return clock_ns_to_ticks(t->ctrl->clock, ns) /
+        npcm7xx_tcsr_prescaler(t->tcsr);
 }
 
 static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks
  2021-02-09 13:20 ` [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
@ 2021-02-10 20:53   ` Hao Wu
  2021-02-10 22:19     ` Peter Maydell
  2021-02-11 10:14   ` Luc Michel
  2021-02-11 15:29   ` Philippe Mathieu-Daudé
  2 siblings, 1 reply; 18+ messages in thread
From: Hao Wu @ 2021-02-10 20:53 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

[-- Attachment #1: Type: text/plain, Size: 31556 bytes --]

On Tue, Feb 9, 2021 at 5:24 AM Peter Maydell <peter.maydell@linaro.org>
wrote:

> 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>
> ---
> v1->v2: (suggested by Luc) instead of making callback functions check
> whether 'event' is one they are interested in, specify mask of
> interesting events at callback registration time.
> ---
>  docs/devel/clocks.rst            | 52 +++++++++++++++++++++++++++-----
>  include/hw/clock.h               | 21 +++++++++++--
>  include/hw/qdev-clock.h          | 17 ++++++++---
>  hw/adc/npcm7xx_adc.c             |  2 +-
>  hw/arm/armsse.c                  |  9 +++---
>  hw/char/cadence_uart.c           |  4 +--
>  hw/char/ibex_uart.c              |  4 +--
>  hw/char/pl011.c                  |  5 +--
>  hw/core/clock.c                  | 20 +++++++++---
>  hw/core/qdev-clock.c             |  8 +++--
>  hw/mips/cps.c                    |  2 +-
>  hw/misc/bcm2835_cprman.c         | 23 ++++++++------
>  hw/misc/npcm7xx_clk.c            | 26 +++++++++++++---
>  hw/misc/npcm7xx_pwm.c            |  2 +-
>  hw/misc/zynq_slcr.c              |  5 +--
>  hw/timer/cmsdk-apb-dualtimer.c   |  5 +--
>  hw/timer/cmsdk-apb-timer.c       |  4 +--
>  hw/timer/npcm7xx_timer.c         |  2 +-
>  hw/watchdog/cmsdk-apb-watchdog.c |  5 +--
>  target/mips/cpu.c                |  2 +-
>  20 files changed, 160 insertions(+), 58 deletions(-)
>
> diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
> index c54bbb82409..cd344e3fe5d 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();
> diff --git a/include/hw/clock.h b/include/hw/clock.h
> index e5f45e2626d..5c73b4e7ae9 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;
> +    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, int events);
>
>  /**
>   * clock_clear_callback:
> diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h
> index 64ca4d266f2..348ec363525 100644
> --- a/include/hw/qdev-clock.h
> +++ b/include/hw/qdev-clock.h
> @@ -22,6 +22,8 @@
>   * @name: the name of the clock (can't be NULL).
>   * @callback: optional callback to be called on update or NULL.
>   * @opaque: argument for the callback
> + * @events: the events the callback should be called for
> + *          (logical OR of ClockEvent enum values)
>   * @returns: a pointer to the newly added clock
>   *
>   * Add an input clock to device @dev as a clock named @name.
> @@ -29,7 +31,8 @@
>   * The callback will be called with @opaque as opaque parameter.
>   */
>  Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
> -                          ClockCallback *callback, void *opaque);
> +                          ClockCallback *callback, void *opaque,
> +                          int events);
>
>  /**
>   * qdev_init_clock_out:
> @@ -105,6 +108,7 @@ void qdev_finalize_clocklist(DeviceState *dev);
>   * @output: indicates whether the clock is input or output
>   * @callback: for inputs, optional callback to be called on clock's update
>   * with device as opaque
> + * @callback_events: mask of ClockEvent values for when callback is called
>   * @offset: optional offset to store the ClockIn or ClockOut pointer in
> device
>   * state structure (0 means unused)
>   */
> @@ -112,6 +116,7 @@ struct ClockPortInitElem {
>      const char *name;
>      bool is_output;
>      ClockCallback *callback;
> +    int callback_events;
>      size_t offset;
>  };
>
> @@ -119,10 +124,11 @@ struct ClockPortInitElem {
>      (offsetof(devstate, field) + \
>       type_check(Clock *, typeof_field(devstate, field)))
>
> -#define QDEV_CLOCK(out_not_in, devstate, field, cb) { \
> +#define QDEV_CLOCK(out_not_in, devstate, field, cb, cbevents) {  \
>      .name = (stringify(field)), \
>      .is_output = out_not_in, \
>      .callback = cb, \
> +    .callback_events = cbevents, \
>      .offset = clock_offset_value(devstate, field), \
>  }
>
> @@ -133,14 +139,15 @@ struct ClockPortInitElem {
>   * @field: a field in @_devstate (must be Clock*)
>   * @callback: (for input only) callback (or NULL) to be called with the
> device
>   * state as argument
> + * @cbevents: (for input only) ClockEvent mask for when callback is called
>   *
>   * The name of the clock will be derived from @field
>   */
> -#define QDEV_CLOCK_IN(devstate, field, callback) \
> -    QDEV_CLOCK(false, devstate, field, callback)
> +#define QDEV_CLOCK_IN(devstate, field, callback, cbevents)       \
> +    QDEV_CLOCK(false, devstate, field, callback, cbevents)
>
>  #define QDEV_CLOCK_OUT(devstate, field) \
> -    QDEV_CLOCK(true, devstate, field, NULL)
> +    QDEV_CLOCK(true, devstate, field, NULL, 0)
>
>  #define QDEV_CLOCK_END { .name = NULL }
>
> diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
> index 870a6d50c27..573f4876dc6 100644
> --- a/hw/adc/npcm7xx_adc.c
> +++ b/hw/adc/npcm7xx_adc.c
> @@ -238,7 +238,7 @@ static void npcm7xx_adc_init(Object *obj)
>      memory_region_init_io(&s->iomem, obj, &npcm7xx_adc_ops, s,
>                            TYPE_NPCM7XX_ADC, 4 * KiB);
>      sysbus_init_mmio(sbd, &s->iomem);
> -    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
> +    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL,
> ClockUpdate);
>
Since there's no callback here should it be
 s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, 0);
?

>
>      for (i = 0; i < NPCM7XX_ADC_NUM_INPUTS; ++i) {
>          object_property_add_uint32_ptr(obj, "adci[*]",
> diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
> index 26e1a8c95b6..fa155b72022 100644
> --- a/hw/arm/armsse.c
> +++ b/hw/arm/armsse.c
> @@ -230,9 +230,10 @@ static void armsse_forward_sec_resp_cfg(ARMSSE *s)
>      qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in);
>  }
>
> -static void armsse_mainclk_update(void *opaque)
> +static void armsse_mainclk_update(void *opaque, ClockEvent event)
>  {
>      ARMSSE *s = ARM_SSE(opaque);
> +
>      /*
>       * Set system_clock_scale from our Clock input; this is what
>       * controls the tick rate of the CPU SysTick timer.
> @@ -251,8 +252,8 @@ static void armsse_init(Object *obj)
>      assert(info->num_cpus <= SSE_MAX_CPUS);
>
>      s->mainclk = qdev_init_clock_in(DEVICE(s), "MAINCLK",
> -                                    armsse_mainclk_update, s);
> -    s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL);
> +                                    armsse_mainclk_update, s,
> ClockUpdate);
> +    s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL, 0);
>
>      memory_region_init(&s->container, obj, "armsse-container",
> UINT64_MAX);
>
> @@ -1120,7 +1121,7 @@ static void armsse_realize(DeviceState *dev, Error
> **errp)
>      sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
>
>      /* Set initial system_clock_scale from MAINCLK */
> -    armsse_mainclk_update(s);
> +    armsse_mainclk_update(s, ClockUpdate);
>  }
>
>  static void armsse_idau_check(IDAUInterface *ii, uint32_t address,
> diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
> index c603e14012a..ceb677bc5a8 100644
> --- a/hw/char/cadence_uart.c
> +++ b/hw/char/cadence_uart.c
> @@ -519,7 +519,7 @@ static void cadence_uart_realize(DeviceState *dev,
> Error **errp)
>                               uart_event, NULL, s, NULL, true);
>  }
>
> -static void cadence_uart_refclk_update(void *opaque)
> +static void cadence_uart_refclk_update(void *opaque, ClockEvent event)
>  {
>      CadenceUARTState *s = opaque;
>
> @@ -537,7 +537,7 @@ static void cadence_uart_init(Object *obj)
>      sysbus_init_irq(sbd, &s->irq);
>
>      s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk",
> -            cadence_uart_refclk_update, s);
> +                                   cadence_uart_refclk_update, s,
> ClockUpdate);
>      /* initialize the frequency in case the clock remains unconnected */
>      clock_set_hz(s->refclk, UART_DEFAULT_REF_CLK);
>
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> index 89f1182c9bf..edcaa30aded 100644
> --- a/hw/char/ibex_uart.c
> +++ b/hw/char/ibex_uart.c
> @@ -396,7 +396,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
>      }
>  }
>
> -static void ibex_uart_clk_update(void *opaque)
> +static void ibex_uart_clk_update(void *opaque, ClockEvent event)
>  {
>      IbexUartState *s = opaque;
>
> @@ -466,7 +466,7 @@ static void ibex_uart_init(Object *obj)
>      IbexUartState *s = IBEX_UART(obj);
>
>      s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock",
> -                                  ibex_uart_clk_update, s);
> +                                  ibex_uart_clk_update, s, ClockUpdate);
>      clock_set_hz(s->f_clk, IBEX_UART_CLOCK);
>
>      sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
> diff --git a/hw/char/pl011.c b/hw/char/pl011.c
> index ea4a4e52356..c5621a195ff 100644
> --- a/hw/char/pl011.c
> +++ b/hw/char/pl011.c
> @@ -309,7 +309,7 @@ static void pl011_event(void *opaque, QEMUChrEvent
> event)
>          pl011_put_fifo(opaque, 0x400);
>  }
>
> -static void pl011_clock_update(void *opaque)
> +static void pl011_clock_update(void *opaque, ClockEvent event)
>  {
>      PL011State *s = PL011(opaque);
>
> @@ -378,7 +378,8 @@ static void pl011_init(Object *obj)
>          sysbus_init_irq(sbd, &s->irq[i]);
>      }
>
> -    s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update,
> s);
> +    s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
> +                                ClockUpdate);
>
>      s->read_trigger = 1;
>      s->ifl = 0x12;
> diff --git a/hw/core/clock.c b/hw/core/clock.c
> index 76b5f468b6e..71dc1f4de65 100644
> --- a/hw/core/clock.c
> +++ b/hw/core/clock.c
> @@ -39,15 +39,16 @@ Clock *clock_new(Object *parent, const char *name)
>      return clk;
>  }
>
> -void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
> +void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque, int
> events)
>  {
>      clk->callback = cb;
>      clk->callback_opaque = opaque;
> +    clk->callback_events = events;
>  }
>
>  void clock_clear_callback(Clock *clk)
>  {
> -    clock_set_callback(clk, NULL, NULL);
> +    clock_set_callback(clk, NULL, NULL, 0);
>  }
>
>  bool clock_set(Clock *clk, uint64_t period)
> @@ -62,6 +63,17 @@ bool clock_set(Clock *clk, uint64_t period)
>      return true;
>  }
>
> +static void clock_call_callback(Clock *clk, ClockEvent event)
> +{
> +    /*
> +     * Call the Clock's callback for this event, if it has one and
> +     * is interested in this event.
> +     */
> +    if (clk->callback && (clk->callback_events & event)) {
> +        clk->callback(clk->callback_opaque, event);
> +    }
> +}
> +
>  static void clock_propagate_period(Clock *clk, bool call_callbacks)
>  {
>      Clock *child;
> @@ -72,8 +84,8 @@ static void clock_propagate_period(Clock *clk, bool
> call_callbacks)
>              trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
>                                 CLOCK_PERIOD_TO_HZ(clk->period),
>                                 call_callbacks);
> -            if (call_callbacks && child->callback) {
> -                child->callback(child->callback_opaque);
> +            if (call_callbacks) {
> +                clock_call_callback(child, ClockUpdate);
>              }
>              clock_propagate_period(child, call_callbacks);
>          }
> diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c
> index eb05f2a13ca..9c55ddc23ee 100644
> --- a/hw/core/qdev-clock.c
> +++ b/hw/core/qdev-clock.c
> @@ -111,7 +111,8 @@ Clock *qdev_init_clock_out(DeviceState *dev, const
> char *name)
>  }
>
>  Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
> -                            ClockCallback *callback, void *opaque)
> +                          ClockCallback *callback, void *opaque,
> +                          int events)
>  {
>      NamedClockList *ncl;
>
> @@ -120,7 +121,7 @@ Clock *qdev_init_clock_in(DeviceState *dev, const char
> *name,
>      ncl = qdev_init_clocklist(dev, name, false, NULL);
>
>      if (callback) {
> -        clock_set_callback(ncl->clock, callback, opaque);
> +        clock_set_callback(ncl->clock, callback, opaque, events);
>      }
>      return ncl->clock;
>  }
> @@ -137,7 +138,8 @@ void qdev_init_clocks(DeviceState *dev, const
> ClockPortInitArray clocks)
>          if (elem->is_output) {
>              *clkp = qdev_init_clock_out(dev, elem->name);
>          } else {
> -            *clkp = qdev_init_clock_in(dev, elem->name, elem->callback,
> dev);
> +            *clkp = qdev_init_clock_in(dev, elem->name, elem->callback,
> dev,
> +                                       elem->callback_events);
>          }
>      }
>  }
> diff --git a/hw/mips/cps.c b/hw/mips/cps.c
> index 7a0d289efaf..2b436700ce6 100644
> --- a/hw/mips/cps.c
> +++ b/hw/mips/cps.c
> @@ -39,7 +39,7 @@ static void mips_cps_init(Object *obj)
>      SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
>      MIPSCPSState *s = MIPS_CPS(obj);
>
> -    s->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, NULL);
> +    s->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, NULL, 0);
>      /*
>       * Cover entire address space as there do not seem to be any
>       * constraints for the base address of CPC and GIC.
> diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
> index 7e415a017c9..75e6c574d46 100644
> --- a/hw/misc/bcm2835_cprman.c
> +++ b/hw/misc/bcm2835_cprman.c
> @@ -107,7 +107,7 @@ static void pll_update(CprmanPllState *pll)
>      clock_update_hz(pll->out, freq);
>  }
>
> -static void pll_xosc_update(void *opaque)
> +static void pll_xosc_update(void *opaque, ClockEvent event)
>  {
>      pll_update(CPRMAN_PLL(opaque));
>  }
> @@ -116,7 +116,8 @@ static void pll_init(Object *obj)
>  {
>      CprmanPllState *s = CPRMAN_PLL(obj);
>
> -    s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in",
> pll_xosc_update, s);
> +    s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update,
> +                                    s, ClockUpdate);
>      s->out = qdev_init_clock_out(DEVICE(s), "out");
>  }
>
> @@ -209,7 +210,7 @@ static void pll_update_all_channels(BCM2835CprmanState
> *s,
>      }
>  }
>
> -static void pll_channel_pll_in_update(void *opaque)
> +static void pll_channel_pll_in_update(void *opaque, ClockEvent event)
>  {
>      pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
>  }
> @@ -219,7 +220,8 @@ static void pll_channel_init(Object *obj)
>      CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj);
>
>      s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in",
> -                                   pll_channel_pll_in_update, s);
> +                                   pll_channel_pll_in_update, s,
> +                                   ClockUpdate);
>      s->out = qdev_init_clock_out(DEVICE(s), "out");
>  }
>
> @@ -303,7 +305,7 @@ static void clock_mux_update(CprmanClockMuxState *mux)
>      clock_update_hz(mux->out, freq);
>  }
>
> -static void clock_mux_src_update(void *opaque)
> +static void clock_mux_src_update(void *opaque, ClockEvent event)
>  {
>      CprmanClockMuxState **backref = opaque;
>      CprmanClockMuxState *s = *backref;
> @@ -335,7 +337,8 @@ static void clock_mux_init(Object *obj)
>          s->backref[i] = s;
>          s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
>                                          clock_mux_src_update,
> -                                        &s->backref[i]);
> +                                        &s->backref[i],
> +                                        ClockUpdate);
>          g_free(name);
>      }
>
> @@ -380,7 +383,7 @@ static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState
> *s)
>      clock_update(s->out, clock_get(src));
>  }
>
> -static void dsi0hsck_mux_in_update(void *opaque)
> +static void dsi0hsck_mux_in_update(void *opaque, ClockEvent event)
>  {
>      dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
>  }
> @@ -390,8 +393,10 @@ static void dsi0hsck_mux_init(Object *obj)
>      CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
>      DeviceState *dev = DEVICE(obj);
>
> -    s->plla_in = qdev_init_clock_in(dev, "plla-in",
> dsi0hsck_mux_in_update, s);
> -    s->plld_in = qdev_init_clock_in(dev, "plld-in",
> dsi0hsck_mux_in_update, s);
> +    s->plla_in = qdev_init_clock_in(dev, "plla-in",
> dsi0hsck_mux_in_update,
> +                                    s, ClockUpdate);
> +    s->plld_in = qdev_init_clock_in(dev, "plld-in",
> dsi0hsck_mux_in_update,
> +                                    s, ClockUpdate);
>      s->out = qdev_init_clock_out(DEVICE(s), "out");
>  }
>
> diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
> index 0bcae9ce957..a1ee67dc9a1 100644
> --- a/hw/misc/npcm7xx_clk.c
> +++ b/hw/misc/npcm7xx_clk.c
> @@ -586,15 +586,26 @@ static const DividerInitInfo
> divider_init_info_list[] = {
>      },
>  };
>
> +static void npcm7xx_clk_update_pll_cb(void *opaque, ClockEvent event)
> +{
> +    npcm7xx_clk_update_pll(opaque);
> +}
> +
>  static void npcm7xx_clk_pll_init(Object *obj)
>  {
>      NPCM7xxClockPLLState *pll = NPCM7XX_CLOCK_PLL(obj);
>
>      pll->clock_in = qdev_init_clock_in(DEVICE(pll), "clock-in",
> -            npcm7xx_clk_update_pll, pll);
> +                                       npcm7xx_clk_update_pll_cb, pll,
> +                                       ClockUpdate);
>      pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
>  }
>
> +static void npcm7xx_clk_update_sel_cb(void *opaque, ClockEvent event)
> +{
> +    npcm7xx_clk_update_sel(opaque);
> +}
> +
>  static void npcm7xx_clk_sel_init(Object *obj)
>  {
>      int i;
> @@ -603,16 +614,23 @@ static void npcm7xx_clk_sel_init(Object *obj)
>      for (i = 0; i < NPCM7XX_CLK_SEL_MAX_INPUT; ++i) {
>          sel->clock_in[i] = qdev_init_clock_in(DEVICE(sel),
>                  g_strdup_printf("clock-in[%d]", i),
> -                npcm7xx_clk_update_sel, sel);
> +                npcm7xx_clk_update_sel_cb, sel, ClockUpdate);
>      }
>      sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
>  }
> +
> +static void npcm7xx_clk_update_divider_cb(void *opaque, ClockEvent event)
> +{
> +    npcm7xx_clk_update_divider(opaque);
> +}
> +
>  static void npcm7xx_clk_divider_init(Object *obj)
>  {
>      NPCM7xxClockDividerState *div = NPCM7XX_CLOCK_DIVIDER(obj);
>
>      div->clock_in = qdev_init_clock_in(DEVICE(div), "clock-in",
> -            npcm7xx_clk_update_divider, div);
> +                                       npcm7xx_clk_update_divider_cb,
> +                                       div, ClockUpdate);
>      div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
>  }
>
> @@ -875,7 +893,7 @@ static void
> npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
>  {
>      int i;
>
> -    s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL);
> +    s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL, 0);
>
>      /* First pass: init all converter modules */
>      QEMU_BUILD_BUG_ON(ARRAY_SIZE(pll_init_info_list) !=
> NPCM7XX_CLOCK_NR_PLLS);
> diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
> index dabcb6c0f95..ce192bb2741 100644
> --- a/hw/misc/npcm7xx_pwm.c
> +++ b/hw/misc/npcm7xx_pwm.c
> @@ -493,7 +493,7 @@ static void npcm7xx_pwm_init(Object *obj)
>      memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s,
>                            TYPE_NPCM7XX_PWM, 4 * KiB);
>      sysbus_init_mmio(sbd, &s->iomem);
> -    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
> +    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, 0);
>
>      for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
>          object_property_add_uint32_ptr(obj, "freq[*]",
> diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
> index 66504a9d3ab..c66d7db177d 100644
> --- a/hw/misc/zynq_slcr.c
> +++ b/hw/misc/zynq_slcr.c
> @@ -307,9 +307,10 @@ static void zynq_slcr_propagate_clocks(ZynqSLCRState
> *s)
>      clock_propagate(s->uart1_ref_clk);
>  }
>
> -static void zynq_slcr_ps_clk_callback(void *opaque)
> +static void zynq_slcr_ps_clk_callback(void *opaque, ClockEvent event)
>  {
>      ZynqSLCRState *s = (ZynqSLCRState *) opaque;
> +
>      zynq_slcr_compute_clocks(s);
>      zynq_slcr_propagate_clocks(s);
>  }
> @@ -576,7 +577,7 @@ static const MemoryRegionOps slcr_ops = {
>  };
>
>  static const ClockPortInitArray zynq_slcr_clocks = {
> -    QDEV_CLOCK_IN(ZynqSLCRState, ps_clk, zynq_slcr_ps_clk_callback),
> +    QDEV_CLOCK_IN(ZynqSLCRState, ps_clk, zynq_slcr_ps_clk_callback,
> ClockUpdate),
>      QDEV_CLOCK_OUT(ZynqSLCRState, uart0_ref_clk),
>      QDEV_CLOCK_OUT(ZynqSLCRState, uart1_ref_clk),
>      QDEV_CLOCK_END
> diff --git a/hw/timer/cmsdk-apb-dualtimer.c
> b/hw/timer/cmsdk-apb-dualtimer.c
> index ef49f5852d3..d4a509c798e 100644
> --- a/hw/timer/cmsdk-apb-dualtimer.c
> +++ b/hw/timer/cmsdk-apb-dualtimer.c
> @@ -449,7 +449,7 @@ static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
>      s->timeritop = 0;
>  }
>
> -static void cmsdk_apb_dualtimer_clk_update(void *opaque)
> +static void cmsdk_apb_dualtimer_clk_update(void *opaque, ClockEvent event)
>  {
>      CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
>      int i;
> @@ -478,7 +478,8 @@ static void cmsdk_apb_dualtimer_init(Object *obj)
>          sysbus_init_irq(sbd, &s->timermod[i].timerint);
>      }
>      s->timclk = qdev_init_clock_in(DEVICE(s), "TIMCLK",
> -                                   cmsdk_apb_dualtimer_clk_update, s);
> +                                   cmsdk_apb_dualtimer_clk_update, s,
> +                                   ClockUpdate);
>  }
>
>  static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
> diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
> index ee51ce3369c..68aa1a76360 100644
> --- a/hw/timer/cmsdk-apb-timer.c
> +++ b/hw/timer/cmsdk-apb-timer.c
> @@ -204,7 +204,7 @@ static void cmsdk_apb_timer_reset(DeviceState *dev)
>      ptimer_transaction_commit(s->timer);
>  }
>
> -static void cmsdk_apb_timer_clk_update(void *opaque)
> +static void cmsdk_apb_timer_clk_update(void *opaque, ClockEvent event)
>  {
>      CMSDKAPBTimer *s = CMSDK_APB_TIMER(opaque);
>
> @@ -223,7 +223,7 @@ static void cmsdk_apb_timer_init(Object *obj)
>      sysbus_init_mmio(sbd, &s->iomem);
>      sysbus_init_irq(sbd, &s->timerint);
>      s->pclk = qdev_init_clock_in(DEVICE(s), "pclk",
> -                                 cmsdk_apb_timer_clk_update, s);
> +                                 cmsdk_apb_timer_clk_update, s,
> ClockUpdate);
>  }
>
>  static void cmsdk_apb_timer_realize(DeviceState *dev, Error **errp)
> diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
> index 36e2c07db26..4efdf135b82 100644
> --- a/hw/timer/npcm7xx_timer.c
> +++ b/hw/timer/npcm7xx_timer.c
> @@ -627,7 +627,7 @@ static void npcm7xx_timer_init(Object *obj)
>      sysbus_init_mmio(sbd, &s->iomem);
>      qdev_init_gpio_out_named(dev, &w->reset_signal,
>              NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
> -    s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL);
> +    s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL, 0);
>  }
>
>  static const VMStateDescription vmstate_npcm7xx_base_timer = {
> diff --git a/hw/watchdog/cmsdk-apb-watchdog.c
> b/hw/watchdog/cmsdk-apb-watchdog.c
> index 302f1711738..5a2cd46eb76 100644
> --- a/hw/watchdog/cmsdk-apb-watchdog.c
> +++ b/hw/watchdog/cmsdk-apb-watchdog.c
> @@ -310,7 +310,7 @@ static void cmsdk_apb_watchdog_reset(DeviceState *dev)
>      ptimer_transaction_commit(s->timer);
>  }
>
> -static void cmsdk_apb_watchdog_clk_update(void *opaque)
> +static void cmsdk_apb_watchdog_clk_update(void *opaque, ClockEvent event)
>  {
>      CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
>
> @@ -329,7 +329,8 @@ static void cmsdk_apb_watchdog_init(Object *obj)
>      sysbus_init_mmio(sbd, &s->iomem);
>      sysbus_init_irq(sbd, &s->wdogint);
>      s->wdogclk = qdev_init_clock_in(DEVICE(s), "WDOGCLK",
> -                                    cmsdk_apb_watchdog_clk_update, s);
> +                                    cmsdk_apb_watchdog_clk_update, s,
> +                                    ClockUpdate);
>
>      s->is_luminary = false;
>      s->id = cmsdk_apb_watchdog_id;
> diff --git a/target/mips/cpu.c b/target/mips/cpu.c
> index ad163ead625..2f3d9d2ce2c 100644
> --- a/target/mips/cpu.c
> +++ b/target/mips/cpu.c
> @@ -636,7 +636,7 @@ static void mips_cpu_initfn(Object *obj)
>      MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj);
>
>      cpu_set_cpustate_pointers(cpu);
> -    cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu);
> +    cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0);
>      env->cpu_model = mcc->cpu_def;
>  }
>
> --
> 2.20.1
>
>
>

[-- Attachment #2: Type: text/html, Size: 37157 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type
  2021-02-09 13:20 ` [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
@ 2021-02-10 20:55   ` Hao Wu
  2021-02-10 22:55   ` Philippe Mathieu-Daudé
  2021-02-11 10:11   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Hao Wu @ 2021-02-10 20:55 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

[-- Attachment #1: Type: text/plain, Size: 2543 bytes --]

On Tue, Feb 9, 2021 at 5:21 AM Peter Maydell <peter.maydell@linaro.org>
wrote:

> Add a new callback event type ClockPreUpdate, which is called on
> period changes before the period is updated.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>
Reviewed-by: Hao Wu <wuhaotsh@google.com>

> ---
>  docs/devel/clocks.rst | 9 ++++++++-
>  include/hw/clock.h    | 1 +
>  hw/core/clock.c       | 3 +++
>  3 files changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
> index cd344e3fe5d..f0391e76b4f 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/include/hw/clock.h b/include/hw/clock.h
> index 5c73b4e7ae9..d7a6673c29e 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);
> diff --git a/hw/core/clock.c b/hw/core/clock.c
> index 71dc1f4de65..2c86091d8a3 100644
> --- a/hw/core/clock.c
> +++ b/hw/core/clock.c
> @@ -80,6 +80,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),
> --
> 2.20.1
>
>
>

[-- Attachment #2: Type: text/html, Size: 3424 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function
  2021-02-09 13:20 ` [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
@ 2021-02-10 21:00   ` Hao Wu
  2021-02-10 23:44   ` Philippe Mathieu-Daudé
  2021-02-11 10:13   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Hao Wu @ 2021-02-10 21:00 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

[-- Attachment #1: Type: text/plain, Size: 3708 bytes --]

On Tue, Feb 9, 2021 at 5:27 AM Peter Maydell <peter.maydell@linaro.org>
wrote:

> 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 <peter.maydell@linaro.org>
>
Reviewed-by: Hao Wu <wuhaotsh@google.com>

> ---
> I have made the overflow behaviour here be "wrap", with justification
> as per the comment; but I'm not 100% set on this.
> ---
>  docs/devel/clocks.rst | 12 ++++++++++++
>  include/hw/clock.h    | 41 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)
>
> diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
> index f0391e76b4f..956bd147ea0 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 d7a6673c29e..79c3b7ebe40 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
> --
> 2.20.1
>
>
>

[-- Attachment #2: Type: text/html, Size: 4718 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks()
  2021-02-09 13:20 ` [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
@ 2021-02-10 21:01   ` Hao Wu
  2021-02-10 23:44   ` Philippe Mathieu-Daudé
  2021-02-11 10:13   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Hao Wu @ 2021-02-10 21:01 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Tyrone Ting, Luc Michel,
	Philippe Mathieu-Daudé,
	Havard Skinnemoen

[-- Attachment #1: Type: text/plain, Size: 1127 bytes --]

On Tue, Feb 9, 2021 at 5:21 AM Peter Maydell <peter.maydell@linaro.org>
wrote:

> Use the new clock_ns_to_ticks() function in npcm7xx_timer where
> appropriate.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>
Reviewed-by: Hao Wu <wuhaotsh@google.com>

Thanks!

> ---
>  hw/timer/npcm7xx_timer.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
> index 4efdf135b82..32f5e021f85 100644
> --- a/hw/timer/npcm7xx_timer.c
> +++ b/hw/timer/npcm7xx_timer.c
> @@ -138,8 +138,8 @@ static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer
> *t, uint32_t count)
>  /* Convert a time interval in nanoseconds to a timer cycle count. */
>  static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
>  {
> -    return ns / clock_ticks_to_ns(t->ctrl->clock,
> -                                  npcm7xx_tcsr_prescaler(t->tcsr));
> +    return clock_ns_to_ticks(t->ctrl->clock, ns) /
> +        npcm7xx_tcsr_prescaler(t->tcsr);
>  }
>
>  static uint32_t npcm7xx_watchdog_timer_prescaler(const
> NPCM7xxWatchdogTimer *t)
> --
> 2.20.1
>
>
>

[-- Attachment #2: Type: text/html, Size: 1851 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks
  2021-02-10 20:53   ` Hao Wu
@ 2021-02-10 22:19     ` Peter Maydell
  0 siblings, 0 replies; 18+ messages in thread
From: Peter Maydell @ 2021-02-10 22:19 UTC (permalink / raw)
  To: Hao Wu
  Cc: Luc Michel, Havard Skinnemoen, QEMU Developers, Tyrone Ting,
	qemu-arm, Philippe Mathieu-Daudé

On Wed, 10 Feb 2021 at 20:53, Hao Wu <wuhaotsh@google.com> wrote:
>
>
>
> On Tue, Feb 9, 2021 at 5:24 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>> diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
>> index 870a6d50c27..573f4876dc6 100644
>> --- a/hw/adc/npcm7xx_adc.c
>> +++ b/hw/adc/npcm7xx_adc.c
>> @@ -238,7 +238,7 @@ static void npcm7xx_adc_init(Object *obj)
>>      memory_region_init_io(&s->iomem, obj, &npcm7xx_adc_ops, s,
>>                            TYPE_NPCM7XX_ADC, 4 * KiB);
>>      sysbus_init_mmio(sbd, &s->iomem);
>> -    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
>> +    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, ClockUpdate);
>
> Since there's no callback here should it be
>  s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, 0);
> ?

Yes; thanks for the catch. (The function ignores the events argument
if there's no callback function specified, but 0 makes more sense.)

-- PMM


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type
  2021-02-09 13:20 ` [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
  2021-02-10 20:55   ` Hao Wu
@ 2021-02-10 22:55   ` Philippe Mathieu-Daudé
  2021-02-11 10:11   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-10 22:55 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Tyrone Ting, Luc Michel, Havard Skinnemoen

On 2/9/21 2:20 PM, Peter Maydell wrote:
> Add a new callback event type ClockPreUpdate, which is called on
> period changes before the period is updated.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  docs/devel/clocks.rst | 9 ++++++++-
>  include/hw/clock.h    | 1 +
>  hw/core/clock.c       | 3 +++
>  3 files changed, 12 insertions(+), 1 deletion(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function
  2021-02-09 13:20 ` [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
  2021-02-10 21:00   ` Hao Wu
@ 2021-02-10 23:44   ` Philippe Mathieu-Daudé
  2021-02-11 10:13   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-10 23:44 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Luc Michel, Havard Skinnemoen, Tyrone Ting

On 2/9/21 2:20 PM, Peter Maydell wrote:
> 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 <peter.maydell@linaro.org>
> ---
> I have made the overflow behaviour here be "wrap", with justification
> as per the comment; but I'm not 100% set on this.
> ---
>  docs/devel/clocks.rst | 12 ++++++++++++
>  include/hw/clock.h    | 41 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)

Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks()
  2021-02-09 13:20 ` [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
  2021-02-10 21:01   ` Hao Wu
@ 2021-02-10 23:44   ` Philippe Mathieu-Daudé
  2021-02-11 10:13   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-10 23:44 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Tyrone Ting, Luc Michel, Havard Skinnemoen

On 2/9/21 2:20 PM, Peter Maydell wrote:
> Use the new clock_ns_to_ticks() function in npcm7xx_timer where
> appropriate.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/timer/npcm7xx_timer.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type
  2021-02-09 13:20 ` [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
  2021-02-10 20:55   ` Hao Wu
  2021-02-10 22:55   ` Philippe Mathieu-Daudé
@ 2021-02-11 10:11   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Luc Michel @ 2021-02-11 10:11 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Havard Skinnemoen, qemu-devel, Tyrone Ting, qemu-arm,
	Edgar E. Iglesias, Philippe Mathieu-Daudé

On 13:20 Tue 09 Feb     , Peter Maydell wrote:
> Add a new callback event type ClockPreUpdate, which is called on
> period changes before the period is updated.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Luc Michel <luc@lmichel.fr>

> ---
>  docs/devel/clocks.rst | 9 ++++++++-
>  include/hw/clock.h    | 1 +
>  hw/core/clock.c       | 3 +++
>  3 files changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
> index cd344e3fe5d..f0391e76b4f 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/include/hw/clock.h b/include/hw/clock.h
> index 5c73b4e7ae9..d7a6673c29e 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);
> diff --git a/hw/core/clock.c b/hw/core/clock.c
> index 71dc1f4de65..2c86091d8a3 100644
> --- a/hw/core/clock.c
> +++ b/hw/core/clock.c
> @@ -80,6 +80,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),
> -- 
> 2.20.1
> 

-- 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function
  2021-02-09 13:20 ` [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
  2021-02-10 21:00   ` Hao Wu
  2021-02-10 23:44   ` Philippe Mathieu-Daudé
@ 2021-02-11 10:13   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Luc Michel @ 2021-02-11 10:13 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Havard Skinnemoen, qemu-devel, Tyrone Ting, qemu-arm,
	Edgar E. Iglesias, Philippe Mathieu-Daudé

On 13:20 Tue 09 Feb     , Peter Maydell wrote:
> 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 <peter.maydell@linaro.org>

Reviewed-by: Luc Michel <luc@lmichel.fr>

> ---
> I have made the overflow behaviour here be "wrap", with justification
> as per the comment; but I'm not 100% set on this.
> ---
>  docs/devel/clocks.rst | 12 ++++++++++++
>  include/hw/clock.h    | 41 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)
> 
> diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
> index f0391e76b4f..956bd147ea0 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 d7a6673c29e..79c3b7ebe40 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
> -- 
> 2.20.1
> 

-- 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks()
  2021-02-09 13:20 ` [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
  2021-02-10 21:01   ` Hao Wu
  2021-02-10 23:44   ` Philippe Mathieu-Daudé
@ 2021-02-11 10:13   ` Luc Michel
  2 siblings, 0 replies; 18+ messages in thread
From: Luc Michel @ 2021-02-11 10:13 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Havard Skinnemoen, qemu-devel, Tyrone Ting, qemu-arm,
	Edgar E. Iglesias, Philippe Mathieu-Daudé

On 13:20 Tue 09 Feb     , Peter Maydell wrote:
> Use the new clock_ns_to_ticks() function in npcm7xx_timer where
> appropriate.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Luc Michel <luc@lmichel.fr>

> ---
>  hw/timer/npcm7xx_timer.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
> index 4efdf135b82..32f5e021f85 100644
> --- a/hw/timer/npcm7xx_timer.c
> +++ b/hw/timer/npcm7xx_timer.c
> @@ -138,8 +138,8 @@ static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
>  /* Convert a time interval in nanoseconds to a timer cycle count. */
>  static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
>  {
> -    return ns / clock_ticks_to_ns(t->ctrl->clock,
> -                                  npcm7xx_tcsr_prescaler(t->tcsr));
> +    return clock_ns_to_ticks(t->ctrl->clock, ns) /
> +        npcm7xx_tcsr_prescaler(t->tcsr);
>  }
>  
>  static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
> -- 
> 2.20.1
> 

-- 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks
  2021-02-09 13:20 ` [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
  2021-02-10 20:53   ` Hao Wu
@ 2021-02-11 10:14   ` Luc Michel
  2021-02-11 15:29   ` Philippe Mathieu-Daudé
  2 siblings, 0 replies; 18+ messages in thread
From: Luc Michel @ 2021-02-11 10:14 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Havard Skinnemoen, qemu-devel, Tyrone Ting, qemu-arm,
	Edgar E. Iglesias, Philippe Mathieu-Daudé

On 13:20 Tue 09 Feb     , Peter Maydell wrote:
> 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>

With Hao's comment addressed:

Reviewed-by: Luc Michel <luc@lmichel.fr>

> ---
> v1->v2: (suggested by Luc) instead of making callback functions check
> whether 'event' is one they are interested in, specify mask of
> interesting events at callback registration time.
> ---
>  docs/devel/clocks.rst            | 52 +++++++++++++++++++++++++++-----
>  include/hw/clock.h               | 21 +++++++++++--
>  include/hw/qdev-clock.h          | 17 ++++++++---
>  hw/adc/npcm7xx_adc.c             |  2 +-
>  hw/arm/armsse.c                  |  9 +++---
>  hw/char/cadence_uart.c           |  4 +--
>  hw/char/ibex_uart.c              |  4 +--
>  hw/char/pl011.c                  |  5 +--
>  hw/core/clock.c                  | 20 +++++++++---
>  hw/core/qdev-clock.c             |  8 +++--
>  hw/mips/cps.c                    |  2 +-
>  hw/misc/bcm2835_cprman.c         | 23 ++++++++------
>  hw/misc/npcm7xx_clk.c            | 26 +++++++++++++---
>  hw/misc/npcm7xx_pwm.c            |  2 +-
>  hw/misc/zynq_slcr.c              |  5 +--
>  hw/timer/cmsdk-apb-dualtimer.c   |  5 +--
>  hw/timer/cmsdk-apb-timer.c       |  4 +--
>  hw/timer/npcm7xx_timer.c         |  2 +-
>  hw/watchdog/cmsdk-apb-watchdog.c |  5 +--
>  target/mips/cpu.c                |  2 +-
>  20 files changed, 160 insertions(+), 58 deletions(-)
> 
> diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
> index c54bbb82409..cd344e3fe5d 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();
> diff --git a/include/hw/clock.h b/include/hw/clock.h
> index e5f45e2626d..5c73b4e7ae9 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;
> +    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, int events);
>  
>  /**
>   * clock_clear_callback:
> diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h
> index 64ca4d266f2..348ec363525 100644
> --- a/include/hw/qdev-clock.h
> +++ b/include/hw/qdev-clock.h
> @@ -22,6 +22,8 @@
>   * @name: the name of the clock (can't be NULL).
>   * @callback: optional callback to be called on update or NULL.
>   * @opaque: argument for the callback
> + * @events: the events the callback should be called for
> + *          (logical OR of ClockEvent enum values)
>   * @returns: a pointer to the newly added clock
>   *
>   * Add an input clock to device @dev as a clock named @name.
> @@ -29,7 +31,8 @@
>   * The callback will be called with @opaque as opaque parameter.
>   */
>  Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
> -                          ClockCallback *callback, void *opaque);
> +                          ClockCallback *callback, void *opaque,
> +                          int events);
>  
>  /**
>   * qdev_init_clock_out:
> @@ -105,6 +108,7 @@ void qdev_finalize_clocklist(DeviceState *dev);
>   * @output: indicates whether the clock is input or output
>   * @callback: for inputs, optional callback to be called on clock's update
>   * with device as opaque
> + * @callback_events: mask of ClockEvent values for when callback is called
>   * @offset: optional offset to store the ClockIn or ClockOut pointer in device
>   * state structure (0 means unused)
>   */
> @@ -112,6 +116,7 @@ struct ClockPortInitElem {
>      const char *name;
>      bool is_output;
>      ClockCallback *callback;
> +    int callback_events;
>      size_t offset;
>  };
>  
> @@ -119,10 +124,11 @@ struct ClockPortInitElem {
>      (offsetof(devstate, field) + \
>       type_check(Clock *, typeof_field(devstate, field)))
>  
> -#define QDEV_CLOCK(out_not_in, devstate, field, cb) { \
> +#define QDEV_CLOCK(out_not_in, devstate, field, cb, cbevents) {  \
>      .name = (stringify(field)), \
>      .is_output = out_not_in, \
>      .callback = cb, \
> +    .callback_events = cbevents, \
>      .offset = clock_offset_value(devstate, field), \
>  }
>  
> @@ -133,14 +139,15 @@ struct ClockPortInitElem {
>   * @field: a field in @_devstate (must be Clock*)
>   * @callback: (for input only) callback (or NULL) to be called with the device
>   * state as argument
> + * @cbevents: (for input only) ClockEvent mask for when callback is called
>   *
>   * The name of the clock will be derived from @field
>   */
> -#define QDEV_CLOCK_IN(devstate, field, callback) \
> -    QDEV_CLOCK(false, devstate, field, callback)
> +#define QDEV_CLOCK_IN(devstate, field, callback, cbevents)       \
> +    QDEV_CLOCK(false, devstate, field, callback, cbevents)
>  
>  #define QDEV_CLOCK_OUT(devstate, field) \
> -    QDEV_CLOCK(true, devstate, field, NULL)
> +    QDEV_CLOCK(true, devstate, field, NULL, 0)
>  
>  #define QDEV_CLOCK_END { .name = NULL }
>  
> diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
> index 870a6d50c27..573f4876dc6 100644
> --- a/hw/adc/npcm7xx_adc.c
> +++ b/hw/adc/npcm7xx_adc.c
> @@ -238,7 +238,7 @@ static void npcm7xx_adc_init(Object *obj)
>      memory_region_init_io(&s->iomem, obj, &npcm7xx_adc_ops, s,
>                            TYPE_NPCM7XX_ADC, 4 * KiB);
>      sysbus_init_mmio(sbd, &s->iomem);
> -    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
> +    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, ClockUpdate);
>  
>      for (i = 0; i < NPCM7XX_ADC_NUM_INPUTS; ++i) {
>          object_property_add_uint32_ptr(obj, "adci[*]",
> diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
> index 26e1a8c95b6..fa155b72022 100644
> --- a/hw/arm/armsse.c
> +++ b/hw/arm/armsse.c
> @@ -230,9 +230,10 @@ static void armsse_forward_sec_resp_cfg(ARMSSE *s)
>      qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in);
>  }
>  
> -static void armsse_mainclk_update(void *opaque)
> +static void armsse_mainclk_update(void *opaque, ClockEvent event)
>  {
>      ARMSSE *s = ARM_SSE(opaque);
> +
>      /*
>       * Set system_clock_scale from our Clock input; this is what
>       * controls the tick rate of the CPU SysTick timer.
> @@ -251,8 +252,8 @@ static void armsse_init(Object *obj)
>      assert(info->num_cpus <= SSE_MAX_CPUS);
>  
>      s->mainclk = qdev_init_clock_in(DEVICE(s), "MAINCLK",
> -                                    armsse_mainclk_update, s);
> -    s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL);
> +                                    armsse_mainclk_update, s, ClockUpdate);
> +    s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL, 0);
>  
>      memory_region_init(&s->container, obj, "armsse-container", UINT64_MAX);
>  
> @@ -1120,7 +1121,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
>      sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
>  
>      /* Set initial system_clock_scale from MAINCLK */
> -    armsse_mainclk_update(s);
> +    armsse_mainclk_update(s, ClockUpdate);
>  }
>  
>  static void armsse_idau_check(IDAUInterface *ii, uint32_t address,
> diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
> index c603e14012a..ceb677bc5a8 100644
> --- a/hw/char/cadence_uart.c
> +++ b/hw/char/cadence_uart.c
> @@ -519,7 +519,7 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
>                               uart_event, NULL, s, NULL, true);
>  }
>  
> -static void cadence_uart_refclk_update(void *opaque)
> +static void cadence_uart_refclk_update(void *opaque, ClockEvent event)
>  {
>      CadenceUARTState *s = opaque;
>  
> @@ -537,7 +537,7 @@ static void cadence_uart_init(Object *obj)
>      sysbus_init_irq(sbd, &s->irq);
>  
>      s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk",
> -            cadence_uart_refclk_update, s);
> +                                   cadence_uart_refclk_update, s, ClockUpdate);
>      /* initialize the frequency in case the clock remains unconnected */
>      clock_set_hz(s->refclk, UART_DEFAULT_REF_CLK);
>  
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> index 89f1182c9bf..edcaa30aded 100644
> --- a/hw/char/ibex_uart.c
> +++ b/hw/char/ibex_uart.c
> @@ -396,7 +396,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
>      }
>  }
>  
> -static void ibex_uart_clk_update(void *opaque)
> +static void ibex_uart_clk_update(void *opaque, ClockEvent event)
>  {
>      IbexUartState *s = opaque;
>  
> @@ -466,7 +466,7 @@ static void ibex_uart_init(Object *obj)
>      IbexUartState *s = IBEX_UART(obj);
>  
>      s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock",
> -                                  ibex_uart_clk_update, s);
> +                                  ibex_uart_clk_update, s, ClockUpdate);
>      clock_set_hz(s->f_clk, IBEX_UART_CLOCK);
>  
>      sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
> diff --git a/hw/char/pl011.c b/hw/char/pl011.c
> index ea4a4e52356..c5621a195ff 100644
> --- a/hw/char/pl011.c
> +++ b/hw/char/pl011.c
> @@ -309,7 +309,7 @@ static void pl011_event(void *opaque, QEMUChrEvent event)
>          pl011_put_fifo(opaque, 0x400);
>  }
>  
> -static void pl011_clock_update(void *opaque)
> +static void pl011_clock_update(void *opaque, ClockEvent event)
>  {
>      PL011State *s = PL011(opaque);
>  
> @@ -378,7 +378,8 @@ static void pl011_init(Object *obj)
>          sysbus_init_irq(sbd, &s->irq[i]);
>      }
>  
> -    s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s);
> +    s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
> +                                ClockUpdate);
>  
>      s->read_trigger = 1;
>      s->ifl = 0x12;
> diff --git a/hw/core/clock.c b/hw/core/clock.c
> index 76b5f468b6e..71dc1f4de65 100644
> --- a/hw/core/clock.c
> +++ b/hw/core/clock.c
> @@ -39,15 +39,16 @@ Clock *clock_new(Object *parent, const char *name)
>      return clk;
>  }
>  
> -void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
> +void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque, int events)
>  {
>      clk->callback = cb;
>      clk->callback_opaque = opaque;
> +    clk->callback_events = events;
>  }
>  
>  void clock_clear_callback(Clock *clk)
>  {
> -    clock_set_callback(clk, NULL, NULL);
> +    clock_set_callback(clk, NULL, NULL, 0);
>  }
>  
>  bool clock_set(Clock *clk, uint64_t period)
> @@ -62,6 +63,17 @@ bool clock_set(Clock *clk, uint64_t period)
>      return true;
>  }
>  
> +static void clock_call_callback(Clock *clk, ClockEvent event)
> +{
> +    /*
> +     * Call the Clock's callback for this event, if it has one and
> +     * is interested in this event.
> +     */
> +    if (clk->callback && (clk->callback_events & event)) {
> +        clk->callback(clk->callback_opaque, event);
> +    }
> +}
> +
>  static void clock_propagate_period(Clock *clk, bool call_callbacks)
>  {
>      Clock *child;
> @@ -72,8 +84,8 @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
>              trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
>                                 CLOCK_PERIOD_TO_HZ(clk->period),
>                                 call_callbacks);
> -            if (call_callbacks && child->callback) {
> -                child->callback(child->callback_opaque);
> +            if (call_callbacks) {
> +                clock_call_callback(child, ClockUpdate);
>              }
>              clock_propagate_period(child, call_callbacks);
>          }
> diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c
> index eb05f2a13ca..9c55ddc23ee 100644
> --- a/hw/core/qdev-clock.c
> +++ b/hw/core/qdev-clock.c
> @@ -111,7 +111,8 @@ Clock *qdev_init_clock_out(DeviceState *dev, const char *name)
>  }
>  
>  Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
> -                            ClockCallback *callback, void *opaque)
> +                          ClockCallback *callback, void *opaque,
> +                          int events)
>  {
>      NamedClockList *ncl;
>  
> @@ -120,7 +121,7 @@ Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
>      ncl = qdev_init_clocklist(dev, name, false, NULL);
>  
>      if (callback) {
> -        clock_set_callback(ncl->clock, callback, opaque);
> +        clock_set_callback(ncl->clock, callback, opaque, events);
>      }
>      return ncl->clock;
>  }
> @@ -137,7 +138,8 @@ void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks)
>          if (elem->is_output) {
>              *clkp = qdev_init_clock_out(dev, elem->name);
>          } else {
> -            *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev);
> +            *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev,
> +                                       elem->callback_events);
>          }
>      }
>  }
> diff --git a/hw/mips/cps.c b/hw/mips/cps.c
> index 7a0d289efaf..2b436700ce6 100644
> --- a/hw/mips/cps.c
> +++ b/hw/mips/cps.c
> @@ -39,7 +39,7 @@ static void mips_cps_init(Object *obj)
>      SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
>      MIPSCPSState *s = MIPS_CPS(obj);
>  
> -    s->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, NULL);
> +    s->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, NULL, 0);
>      /*
>       * Cover entire address space as there do not seem to be any
>       * constraints for the base address of CPC and GIC.
> diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
> index 7e415a017c9..75e6c574d46 100644
> --- a/hw/misc/bcm2835_cprman.c
> +++ b/hw/misc/bcm2835_cprman.c
> @@ -107,7 +107,7 @@ static void pll_update(CprmanPllState *pll)
>      clock_update_hz(pll->out, freq);
>  }
>  
> -static void pll_xosc_update(void *opaque)
> +static void pll_xosc_update(void *opaque, ClockEvent event)
>  {
>      pll_update(CPRMAN_PLL(opaque));
>  }
> @@ -116,7 +116,8 @@ static void pll_init(Object *obj)
>  {
>      CprmanPllState *s = CPRMAN_PLL(obj);
>  
> -    s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update, s);
> +    s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update,
> +                                    s, ClockUpdate);
>      s->out = qdev_init_clock_out(DEVICE(s), "out");
>  }
>  
> @@ -209,7 +210,7 @@ static void pll_update_all_channels(BCM2835CprmanState *s,
>      }
>  }
>  
> -static void pll_channel_pll_in_update(void *opaque)
> +static void pll_channel_pll_in_update(void *opaque, ClockEvent event)
>  {
>      pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
>  }
> @@ -219,7 +220,8 @@ static void pll_channel_init(Object *obj)
>      CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj);
>  
>      s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in",
> -                                   pll_channel_pll_in_update, s);
> +                                   pll_channel_pll_in_update, s,
> +                                   ClockUpdate);
>      s->out = qdev_init_clock_out(DEVICE(s), "out");
>  }
>  
> @@ -303,7 +305,7 @@ static void clock_mux_update(CprmanClockMuxState *mux)
>      clock_update_hz(mux->out, freq);
>  }
>  
> -static void clock_mux_src_update(void *opaque)
> +static void clock_mux_src_update(void *opaque, ClockEvent event)
>  {
>      CprmanClockMuxState **backref = opaque;
>      CprmanClockMuxState *s = *backref;
> @@ -335,7 +337,8 @@ static void clock_mux_init(Object *obj)
>          s->backref[i] = s;
>          s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
>                                          clock_mux_src_update,
> -                                        &s->backref[i]);
> +                                        &s->backref[i],
> +                                        ClockUpdate);
>          g_free(name);
>      }
>  
> @@ -380,7 +383,7 @@ static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s)
>      clock_update(s->out, clock_get(src));
>  }
>  
> -static void dsi0hsck_mux_in_update(void *opaque)
> +static void dsi0hsck_mux_in_update(void *opaque, ClockEvent event)
>  {
>      dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
>  }
> @@ -390,8 +393,10 @@ static void dsi0hsck_mux_init(Object *obj)
>      CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
>      DeviceState *dev = DEVICE(obj);
>  
> -    s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, s);
> -    s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, s);
> +    s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update,
> +                                    s, ClockUpdate);
> +    s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update,
> +                                    s, ClockUpdate);
>      s->out = qdev_init_clock_out(DEVICE(s), "out");
>  }
>  
> diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
> index 0bcae9ce957..a1ee67dc9a1 100644
> --- a/hw/misc/npcm7xx_clk.c
> +++ b/hw/misc/npcm7xx_clk.c
> @@ -586,15 +586,26 @@ static const DividerInitInfo divider_init_info_list[] = {
>      },
>  };
>  
> +static void npcm7xx_clk_update_pll_cb(void *opaque, ClockEvent event)
> +{
> +    npcm7xx_clk_update_pll(opaque);
> +}
> +
>  static void npcm7xx_clk_pll_init(Object *obj)
>  {
>      NPCM7xxClockPLLState *pll = NPCM7XX_CLOCK_PLL(obj);
>  
>      pll->clock_in = qdev_init_clock_in(DEVICE(pll), "clock-in",
> -            npcm7xx_clk_update_pll, pll);
> +                                       npcm7xx_clk_update_pll_cb, pll,
> +                                       ClockUpdate);
>      pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
>  }
>  
> +static void npcm7xx_clk_update_sel_cb(void *opaque, ClockEvent event)
> +{
> +    npcm7xx_clk_update_sel(opaque);
> +}
> +
>  static void npcm7xx_clk_sel_init(Object *obj)
>  {
>      int i;
> @@ -603,16 +614,23 @@ static void npcm7xx_clk_sel_init(Object *obj)
>      for (i = 0; i < NPCM7XX_CLK_SEL_MAX_INPUT; ++i) {
>          sel->clock_in[i] = qdev_init_clock_in(DEVICE(sel),
>                  g_strdup_printf("clock-in[%d]", i),
> -                npcm7xx_clk_update_sel, sel);
> +                npcm7xx_clk_update_sel_cb, sel, ClockUpdate);
>      }
>      sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
>  }
> +
> +static void npcm7xx_clk_update_divider_cb(void *opaque, ClockEvent event)
> +{
> +    npcm7xx_clk_update_divider(opaque);
> +}
> +
>  static void npcm7xx_clk_divider_init(Object *obj)
>  {
>      NPCM7xxClockDividerState *div = NPCM7XX_CLOCK_DIVIDER(obj);
>  
>      div->clock_in = qdev_init_clock_in(DEVICE(div), "clock-in",
> -            npcm7xx_clk_update_divider, div);
> +                                       npcm7xx_clk_update_divider_cb,
> +                                       div, ClockUpdate);
>      div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
>  }
>  
> @@ -875,7 +893,7 @@ static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
>  {
>      int i;
>  
> -    s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL);
> +    s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL, 0);
>  
>      /* First pass: init all converter modules */
>      QEMU_BUILD_BUG_ON(ARRAY_SIZE(pll_init_info_list) != NPCM7XX_CLOCK_NR_PLLS);
> diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
> index dabcb6c0f95..ce192bb2741 100644
> --- a/hw/misc/npcm7xx_pwm.c
> +++ b/hw/misc/npcm7xx_pwm.c
> @@ -493,7 +493,7 @@ static void npcm7xx_pwm_init(Object *obj)
>      memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s,
>                            TYPE_NPCM7XX_PWM, 4 * KiB);
>      sysbus_init_mmio(sbd, &s->iomem);
> -    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
> +    s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, 0);
>  
>      for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
>          object_property_add_uint32_ptr(obj, "freq[*]",
> diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
> index 66504a9d3ab..c66d7db177d 100644
> --- a/hw/misc/zynq_slcr.c
> +++ b/hw/misc/zynq_slcr.c
> @@ -307,9 +307,10 @@ static void zynq_slcr_propagate_clocks(ZynqSLCRState *s)
>      clock_propagate(s->uart1_ref_clk);
>  }
>  
> -static void zynq_slcr_ps_clk_callback(void *opaque)
> +static void zynq_slcr_ps_clk_callback(void *opaque, ClockEvent event)
>  {
>      ZynqSLCRState *s = (ZynqSLCRState *) opaque;
> +
>      zynq_slcr_compute_clocks(s);
>      zynq_slcr_propagate_clocks(s);
>  }
> @@ -576,7 +577,7 @@ static const MemoryRegionOps slcr_ops = {
>  };
>  
>  static const ClockPortInitArray zynq_slcr_clocks = {
> -    QDEV_CLOCK_IN(ZynqSLCRState, ps_clk, zynq_slcr_ps_clk_callback),
> +    QDEV_CLOCK_IN(ZynqSLCRState, ps_clk, zynq_slcr_ps_clk_callback, ClockUpdate),
>      QDEV_CLOCK_OUT(ZynqSLCRState, uart0_ref_clk),
>      QDEV_CLOCK_OUT(ZynqSLCRState, uart1_ref_clk),
>      QDEV_CLOCK_END
> diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
> index ef49f5852d3..d4a509c798e 100644
> --- a/hw/timer/cmsdk-apb-dualtimer.c
> +++ b/hw/timer/cmsdk-apb-dualtimer.c
> @@ -449,7 +449,7 @@ static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
>      s->timeritop = 0;
>  }
>  
> -static void cmsdk_apb_dualtimer_clk_update(void *opaque)
> +static void cmsdk_apb_dualtimer_clk_update(void *opaque, ClockEvent event)
>  {
>      CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
>      int i;
> @@ -478,7 +478,8 @@ static void cmsdk_apb_dualtimer_init(Object *obj)
>          sysbus_init_irq(sbd, &s->timermod[i].timerint);
>      }
>      s->timclk = qdev_init_clock_in(DEVICE(s), "TIMCLK",
> -                                   cmsdk_apb_dualtimer_clk_update, s);
> +                                   cmsdk_apb_dualtimer_clk_update, s,
> +                                   ClockUpdate);
>  }
>  
>  static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
> diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
> index ee51ce3369c..68aa1a76360 100644
> --- a/hw/timer/cmsdk-apb-timer.c
> +++ b/hw/timer/cmsdk-apb-timer.c
> @@ -204,7 +204,7 @@ static void cmsdk_apb_timer_reset(DeviceState *dev)
>      ptimer_transaction_commit(s->timer);
>  }
>  
> -static void cmsdk_apb_timer_clk_update(void *opaque)
> +static void cmsdk_apb_timer_clk_update(void *opaque, ClockEvent event)
>  {
>      CMSDKAPBTimer *s = CMSDK_APB_TIMER(opaque);
>  
> @@ -223,7 +223,7 @@ static void cmsdk_apb_timer_init(Object *obj)
>      sysbus_init_mmio(sbd, &s->iomem);
>      sysbus_init_irq(sbd, &s->timerint);
>      s->pclk = qdev_init_clock_in(DEVICE(s), "pclk",
> -                                 cmsdk_apb_timer_clk_update, s);
> +                                 cmsdk_apb_timer_clk_update, s, ClockUpdate);
>  }
>  
>  static void cmsdk_apb_timer_realize(DeviceState *dev, Error **errp)
> diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
> index 36e2c07db26..4efdf135b82 100644
> --- a/hw/timer/npcm7xx_timer.c
> +++ b/hw/timer/npcm7xx_timer.c
> @@ -627,7 +627,7 @@ static void npcm7xx_timer_init(Object *obj)
>      sysbus_init_mmio(sbd, &s->iomem);
>      qdev_init_gpio_out_named(dev, &w->reset_signal,
>              NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
> -    s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL);
> +    s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL, 0);
>  }
>  
>  static const VMStateDescription vmstate_npcm7xx_base_timer = {
> diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
> index 302f1711738..5a2cd46eb76 100644
> --- a/hw/watchdog/cmsdk-apb-watchdog.c
> +++ b/hw/watchdog/cmsdk-apb-watchdog.c
> @@ -310,7 +310,7 @@ static void cmsdk_apb_watchdog_reset(DeviceState *dev)
>      ptimer_transaction_commit(s->timer);
>  }
>  
> -static void cmsdk_apb_watchdog_clk_update(void *opaque)
> +static void cmsdk_apb_watchdog_clk_update(void *opaque, ClockEvent event)
>  {
>      CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
>  
> @@ -329,7 +329,8 @@ static void cmsdk_apb_watchdog_init(Object *obj)
>      sysbus_init_mmio(sbd, &s->iomem);
>      sysbus_init_irq(sbd, &s->wdogint);
>      s->wdogclk = qdev_init_clock_in(DEVICE(s), "WDOGCLK",
> -                                    cmsdk_apb_watchdog_clk_update, s);
> +                                    cmsdk_apb_watchdog_clk_update, s,
> +                                    ClockUpdate);
>  
>      s->is_luminary = false;
>      s->id = cmsdk_apb_watchdog_id;
> diff --git a/target/mips/cpu.c b/target/mips/cpu.c
> index ad163ead625..2f3d9d2ce2c 100644
> --- a/target/mips/cpu.c
> +++ b/target/mips/cpu.c
> @@ -636,7 +636,7 @@ static void mips_cpu_initfn(Object *obj)
>      MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj);
>  
>      cpu_set_cpustate_pointers(cpu);
> -    cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu);
> +    cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0);
>      env->cpu_model = mcc->cpu_def;
>  }
>  
> -- 
> 2.20.1
> 

-- 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks
  2021-02-09 13:20 ` [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
  2021-02-10 20:53   ` Hao Wu
  2021-02-11 10:14   ` Luc Michel
@ 2021-02-11 15:29   ` Philippe Mathieu-Daudé
  2 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-11 15:29 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: Tyrone Ting, Luc Michel, Havard Skinnemoen

Hi Peter,

On 2/9/21 2:20 PM, Peter Maydell wrote:
> 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>
> ---
> v1->v2: (suggested by Luc) instead of making callback functions check
> whether 'event' is one they are interested in, specify mask of
> interesting events at callback registration time.
> ---
>  docs/devel/clocks.rst            | 52 +++++++++++++++++++++++++++-----
>  include/hw/clock.h               | 21 +++++++++++--
>  include/hw/qdev-clock.h          | 17 ++++++++---
>  hw/adc/npcm7xx_adc.c             |  2 +-
>  hw/arm/armsse.c                  |  9 +++---
>  hw/char/cadence_uart.c           |  4 +--
>  hw/char/ibex_uart.c              |  4 +--
>  hw/char/pl011.c                  |  5 +--
>  hw/core/clock.c                  | 20 +++++++++---
>  hw/core/qdev-clock.c             |  8 +++--
>  hw/mips/cps.c                    |  2 +-
>  hw/misc/bcm2835_cprman.c         | 23 ++++++++------
>  hw/misc/npcm7xx_clk.c            | 26 +++++++++++++---
>  hw/misc/npcm7xx_pwm.c            |  2 +-
>  hw/misc/zynq_slcr.c              |  5 +--
>  hw/timer/cmsdk-apb-dualtimer.c   |  5 +--
>  hw/timer/cmsdk-apb-timer.c       |  4 +--
>  hw/timer/npcm7xx_timer.c         |  2 +-
>  hw/watchdog/cmsdk-apb-watchdog.c |  5 +--
>  target/mips/cpu.c                |  2 +-
>  20 files changed, 160 insertions(+), 58 deletions(-)

> diff --git a/include/hw/clock.h b/include/hw/clock.h
> index e5f45e2626d..5c73b4e7ae9 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 */

Just wondering loudly (QEMU doesn't have enum naming conventions),
maybe rename  ClockUpdate -> ClockUpdateEvent to clarify.

> +} 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;
> +    int callback_events;

Isn't "unsigned" recommended for bit mask?

Otherwise (minor Hao Wu's NULL remark):
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2021-02-11 15:32 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-09 13:20 [PATCH v2 0/4] New APIs for the Clock framework Peter Maydell
2021-02-09 13:20 ` [PATCH v2 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
2021-02-10 20:53   ` Hao Wu
2021-02-10 22:19     ` Peter Maydell
2021-02-11 10:14   ` Luc Michel
2021-02-11 15:29   ` Philippe Mathieu-Daudé
2021-02-09 13:20 ` [PATCH v2 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
2021-02-10 20:55   ` Hao Wu
2021-02-10 22:55   ` Philippe Mathieu-Daudé
2021-02-11 10:11   ` Luc Michel
2021-02-09 13:20 ` [PATCH v2 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
2021-02-10 21:00   ` Hao Wu
2021-02-10 23:44   ` Philippe Mathieu-Daudé
2021-02-11 10:13   ` Luc Michel
2021-02-09 13:20 ` [PATCH v2 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
2021-02-10 21:01   ` Hao Wu
2021-02-10 23:44   ` Philippe Mathieu-Daudé
2021-02-11 10:13   ` Luc Michel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.