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

Hi; this patchset proposes a couple of new APIs for Clock, which I
found I needed/wanted for a work-in-progress patchset that includes a
model of a new timer device, the "System Timer" documented in the Arm
SSE-123 Example Subsystem Technical Reference Manual:
  https://developer.arm.com/documentation/101370/0000/system-time-components/system-timer?lang=en

It's going to be a little while before I post the patchseries with the
new timer device implementation, because I need to complete a model of
the SSE-300 SoC and an MPS board model that uses it; so I wanted to
put these out as an RFC to see if people agree on the APIs I'm
suggesting.

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

All callback functions are called for all events, and they look at the
'event' argument to see whether they need to do anything.  This means
that the patch has to update every ClockCallback in the codebase to
take the new argument and do nothing if it is not ClockUpdate, but
luckily there aren't many of them; this seemed better than trying to
manage multiple separate callback pointers.

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.

Side note: there is currently no MAINTAINERS entry for the
clock framework. Any volunteers? It would cover

F: include/hw/clock.h
F: include/hw/qdev-clock.h
F: hw/core/clock.c
F: hw/core/qdev-clock.c
F: docs/devel/clocks.rst

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            | 54 ++++++++++++++++++++++++++++++--
 include/hw/clock.h               | 52 +++++++++++++++++++++++++++++-
 hw/arm/armsse.c                  |  8 +++--
 hw/char/cadence_uart.c           |  5 ++-
 hw/char/ibex_uart.c              |  5 ++-
 hw/char/pl011.c                  |  5 ++-
 hw/core/clock.c                  |  5 ++-
 hw/misc/bcm2835_cprman.c         | 20 +++++++++---
 hw/misc/npcm7xx_clk.c            | 31 ++++++++++++++++--
 hw/misc/zynq_slcr.c              |  6 +++-
 hw/timer/cmsdk-apb-dualtimer.c   |  5 ++-
 hw/timer/cmsdk-apb-timer.c       |  5 ++-
 hw/timer/npcm7xx_timer.c         |  4 +--
 hw/watchdog/cmsdk-apb-watchdog.c |  5 ++-
 14 files changed, 188 insertions(+), 22 deletions(-)

-- 
2.20.1



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

* [RFC 1/4] clock: Add ClockEvent parameter to callbacks
  2021-02-01 12:30 [RFC 0/4] New APIs for the Clock framework Peter Maydell
@ 2021-02-01 12:30 ` Peter Maydell
  2021-02-02 21:26   ` Luc Michel
  2021-02-01 12:30 ` [RFC 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Peter Maydell @ 2021-02-01 12:30 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Philippe Mathieu-Daudé,
	Luc Michel, Havard Skinnemoen, Tyrone Ting

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 make the existing callback
implementations check this argument and only act if the event is
ClockUpdate.

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>
---
I thought about trying to add support for pre-update callbacks
in a way that didn't require changes to every current callback
user, but there aren't *that* many of them and I think this API
is nicer than having multiple separate callback pointers and
extra functions for "also set the pre-update callback" and so on.
---
 docs/devel/clocks.rst            | 35 ++++++++++++++++++++++++++++++--
 include/hw/clock.h               | 10 ++++++++-
 hw/arm/armsse.c                  |  8 ++++++--
 hw/char/cadence_uart.c           |  5 ++++-
 hw/char/ibex_uart.c              |  5 ++++-
 hw/char/pl011.c                  |  5 ++++-
 hw/core/clock.c                  |  2 +-
 hw/misc/bcm2835_cprman.c         | 20 ++++++++++++++----
 hw/misc/npcm7xx_clk.c            | 31 +++++++++++++++++++++++++---
 hw/misc/zynq_slcr.c              |  6 +++++-
 hw/timer/cmsdk-apb-dualtimer.c   |  5 ++++-
 hw/timer/cmsdk-apb-timer.c       |  5 ++++-
 hw/watchdog/cmsdk-apb-watchdog.c |  5 ++++-
 13 files changed, 122 insertions(+), 20 deletions(-)

diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
index c54bbb82409..8d3b456561f 100644
--- a/docs/devel/clocks.rst
+++ b/docs/devel/clocks.rst
@@ -113,7 +113,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:
@@ -153,6 +153,34 @@ 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.
+Callback functions should check this and only do something for
+specific events they need to handle, so that if in future different
+events are added the callback code doesn't need to be updated.
+The events currently supported are:
+
+ * ``ClockUpdate`` : called after the input clock's period has changed
+
 Retrieving clocks from a device
 -------------------------------
 
@@ -271,12 +299,15 @@ Here is an example:
 
 .. 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();
          * usually this will be the device state pointer.
          */
+        if (event != ClockUpdate) {
+            return;
+        }
 
         /* do something with the new period */
         fprintf(stdout, "device new period is %" PRIu64 "* 2^-32 ns\n",
diff --git a/include/hw/clock.h b/include/hw/clock.h
index e5f45e2626d..323f8d49fed 100644
--- a/include/hw/clock.h
+++ b/include/hw/clock.h
@@ -22,7 +22,15 @@
 #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.
+ */
+typedef enum ClockEvent {
+    ClockUpdate, /* 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.
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index 26e1a8c95b6..cf0bd962ea2 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -230,9 +230,13 @@ 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);
+
+    if (event != ClockUpdate) {
+        return;
+    }
     /*
      * Set system_clock_scale from our Clock input; this is what
      * controls the tick rate of the CPU SysTick timer.
@@ -1120,7 +1124,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..2900688fc24 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -519,10 +519,13 @@ 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;
 
+    if (event != ClockUpdate) {
+        return;
+    }
     /* recompute uart's speed on clock change */
     uart_parameters_setup(s);
 }
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
index 89f1182c9bf..c90d4d69baf 100644
--- a/hw/char/ibex_uart.c
+++ b/hw/char/ibex_uart.c
@@ -396,10 +396,13 @@ 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;
 
+    if (event != ClockUpdate) {
+        return;
+    }
     /* recompute uart's speed on clock change */
     uint64_t baud = ibex_uart_get_baud(s);
 
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index ea4a4e52356..d3040c0fab3 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -309,10 +309,13 @@ 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);
 
+    if (event != ClockUpdate) {
+        return;
+    }
     pl011_trace_baudrate_change(s);
 }
 
diff --git a/hw/core/clock.c b/hw/core/clock.c
index 76b5f468b6e..772d03a2eb5 100644
--- a/hw/core/clock.c
+++ b/hw/core/clock.c
@@ -73,7 +73,7 @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
                                CLOCK_PERIOD_TO_HZ(clk->period),
                                call_callbacks);
             if (call_callbacks && child->callback) {
-                child->callback(child->callback_opaque);
+                child->callback(child->callback_opaque, ClockUpdate);
             }
             clock_propagate_period(child, call_callbacks);
         }
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
index 7e415a017c9..5df4bcdb22d 100644
--- a/hw/misc/bcm2835_cprman.c
+++ b/hw/misc/bcm2835_cprman.c
@@ -107,8 +107,11 @@ 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)
 {
+    if (event != ClockUpdate) {
+        return;
+    }
     pll_update(CPRMAN_PLL(opaque));
 }
 
@@ -209,8 +212,11 @@ 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)
 {
+    if (event != ClockUpdate) {
+        return;
+    }
     pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
 }
 
@@ -303,12 +309,15 @@ 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;
     CprmanClockMuxSource src = backref - s->backref;
 
+    if (event != ClockUpdate) {
+        return;
+    }
     if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) {
         return;
     }
@@ -380,8 +389,11 @@ 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)
 {
+    if (event != ClockUpdate) {
+        return;
+    }
     dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
 }
 
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
index 0bcae9ce957..935184d5482 100644
--- a/hw/misc/npcm7xx_clk.c
+++ b/hw/misc/npcm7xx_clk.c
@@ -586,15 +586,31 @@ static const DividerInitInfo divider_init_info_list[] = {
     },
 };
 
+static void npcm7xx_clk_update_pll_cb(void *opaque, ClockEvent event)
+{
+    if (event != ClockUpdate) {
+        return;
+    }
+    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);
     pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
 }
 
+static void npcm7xx_clk_update_sel_cb(void *opaque, ClockEvent event)
+{
+    if (event != ClockUpdate) {
+        return;
+    }
+    npcm7xx_clk_update_sel(opaque);
+}
+
 static void npcm7xx_clk_sel_init(Object *obj)
 {
     int i;
@@ -603,16 +619,25 @@ 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);
     }
     sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
 }
+
+static void npcm7xx_clk_update_divider_cb(void *opaque, ClockEvent event)
+{
+    if (event != ClockUpdate) {
+        return;
+    }
+    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);
     div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
 }
 
diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
index 66504a9d3ab..555d93ba50c 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -307,9 +307,13 @@ 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;
+
+    if (event != ClockUpdate) {
+        return;
+    }
     zynq_slcr_compute_clocks(s);
     zynq_slcr_propagate_clocks(s);
 }
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
index ef49f5852d3..ebbc036dc89 100644
--- a/hw/timer/cmsdk-apb-dualtimer.c
+++ b/hw/timer/cmsdk-apb-dualtimer.c
@@ -449,11 +449,14 @@ 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;
 
+    if (event != ClockUpdate) {
+        return;
+    }
     for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
         CMSDKAPBDualTimerModule *m = &s->timermod[i];
         ptimer_transaction_begin(m->timer);
diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
index ee51ce3369c..06264f36d4e 100644
--- a/hw/timer/cmsdk-apb-timer.c
+++ b/hw/timer/cmsdk-apb-timer.c
@@ -204,10 +204,13 @@ 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);
 
+    if (event != ClockUpdate) {
+        return;
+    }
     ptimer_transaction_begin(s->timer);
     ptimer_set_period_from_clock(s->timer, s->pclk, 1);
     ptimer_transaction_commit(s->timer);
diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
index 302f1711738..7564e8b3326 100644
--- a/hw/watchdog/cmsdk-apb-watchdog.c
+++ b/hw/watchdog/cmsdk-apb-watchdog.c
@@ -310,10 +310,13 @@ 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);
 
+    if (event != ClockUpdate) {
+        return;
+    }
     ptimer_transaction_begin(s->timer);
     ptimer_set_period_from_clock(s->timer, s->wdogclk, 1);
     ptimer_transaction_commit(s->timer);
-- 
2.20.1



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

* [RFC 2/4] clock: Add ClockPreUpdate callback event type
  2021-02-01 12:30 [RFC 0/4] New APIs for the Clock framework Peter Maydell
  2021-02-01 12:30 ` [RFC 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
@ 2021-02-01 12:30 ` Peter Maydell
  2021-02-01 12:30 ` [RFC 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2021-02-01 12:30 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Philippe Mathieu-Daudé,
	Luc Michel, Havard Skinnemoen, Tyrone Ting

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 8d3b456561f..dea63742fb0 100644
--- a/docs/devel/clocks.rst
+++ b/docs/devel/clocks.rst
@@ -179,7 +179,14 @@ specific events they need to handle, so that if in future different
 events are added the callback code doesn't need to be updated.
 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.
 
 Retrieving clocks from a device
 -------------------------------
diff --git a/include/hw/clock.h b/include/hw/clock.h
index 323f8d49fed..7d0eb286faa 100644
--- a/include/hw/clock.h
+++ b/include/hw/clock.h
@@ -27,6 +27,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(Clock, CLOCK)
  * has been called.
  */
 typedef enum ClockEvent {
+    ClockPreUpdate, /* Clock period is about to update */
     ClockUpdate, /* Clock period has just updated */
 } ClockEvent;
 
diff --git a/hw/core/clock.c b/hw/core/clock.c
index 772d03a2eb5..963fe83a363 100644
--- a/hw/core/clock.c
+++ b/hw/core/clock.c
@@ -68,6 +68,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 && child->callback) {
+                child->callback(child->callback_opaque, 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] 8+ messages in thread

* [RFC 3/4] clock: Add clock_ns_to_ticks() function
  2021-02-01 12:30 [RFC 0/4] New APIs for the Clock framework Peter Maydell
  2021-02-01 12:30 ` [RFC 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
  2021-02-01 12:30 ` [RFC 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
@ 2021-02-01 12:30 ` Peter Maydell
  2021-02-03 20:51   ` Luc Michel
  2021-02-01 12:30 ` [RFC 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
  2021-02-03 21:14 ` [RFC 0/4] New APIs for the Clock framework Luc Michel
  4 siblings, 1 reply; 8+ messages in thread
From: Peter Maydell @ 2021-02-01 12:30 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Edgar E. Iglesias, Philippe Mathieu-Daudé,
	Luc Michel, Havard Skinnemoen, Tyrone Ting

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 dea63742fb0..84fb45bbe5f 100644
--- a/docs/devel/clocks.rst
+++ b/docs/devel/clocks.rst
@@ -355,6 +355,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 7d0eb286faa..e3545eda439 100644
--- a/include/hw/clock.h
+++ b/include/hw/clock.h
@@ -277,6 +277,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] 8+ messages in thread

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

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 36e2c07db26..fc48d494151 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] 8+ messages in thread

* Re: [RFC 1/4] clock: Add ClockEvent parameter to callbacks
  2021-02-01 12:30 ` [RFC 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
@ 2021-02-02 21:26   ` Luc Michel
  0 siblings, 0 replies; 8+ messages in thread
From: Luc Michel @ 2021-02-02 21:26 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Philippe Mathieu-Daudé,
	qemu-devel, Tyrone Ting, qemu-arm, Edgar E. Iglesias,
	Havard Skinnemoen

Hi Peter,

On 12:30 Mon 01 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 make the existing callback
> implementations check this argument and only act if the event is
> ClockUpdate.
> 
> 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>
> ---
> I thought about trying to add support for pre-update callbacks
> in a way that didn't require changes to every current callback
> user, but there aren't *that* many of them and I think this API
> is nicer than having multiple separate callback pointers and
> extra functions for "also set the pre-update callback" and so on.

Have you considered using a mask to record the events the clock
user is interested in? This mask would be passed at clock init time.
This would add a parameter to qdev_init_clock_in (we could even add a
new function to set this mask) but would avoid the need of those "if" in
the callbacks.

This way if we ever end up adding yet another event, it won't require
any changes to the users.

What do you think?

-- 
Luc

> ---
>  docs/devel/clocks.rst            | 35 ++++++++++++++++++++++++++++++--
>  include/hw/clock.h               | 10 ++++++++-
>  hw/arm/armsse.c                  |  8 ++++++--
>  hw/char/cadence_uart.c           |  5 ++++-
>  hw/char/ibex_uart.c              |  5 ++++-
>  hw/char/pl011.c                  |  5 ++++-
>  hw/core/clock.c                  |  2 +-
>  hw/misc/bcm2835_cprman.c         | 20 ++++++++++++++----
>  hw/misc/npcm7xx_clk.c            | 31 +++++++++++++++++++++++++---
>  hw/misc/zynq_slcr.c              |  6 +++++-
>  hw/timer/cmsdk-apb-dualtimer.c   |  5 ++++-
>  hw/timer/cmsdk-apb-timer.c       |  5 ++++-
>  hw/watchdog/cmsdk-apb-watchdog.c |  5 ++++-
>  13 files changed, 122 insertions(+), 20 deletions(-)
> 
> diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
> index c54bbb82409..8d3b456561f 100644
> --- a/docs/devel/clocks.rst
> +++ b/docs/devel/clocks.rst
> @@ -113,7 +113,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:
> @@ -153,6 +153,34 @@ 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.
> +Callback functions should check this and only do something for
> +specific events they need to handle, so that if in future different
> +events are added the callback code doesn't need to be updated.
> +The events currently supported are:
> +
> + * ``ClockUpdate`` : called after the input clock's period has changed
> +
>  Retrieving clocks from a device
>  -------------------------------
>  
> @@ -271,12 +299,15 @@ Here is an example:
>  
>  .. 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();
>           * usually this will be the device state pointer.
>           */
> +        if (event != ClockUpdate) {
> +            return;
> +        }
>  
>          /* do something with the new period */
>          fprintf(stdout, "device new period is %" PRIu64 "* 2^-32 ns\n",
> diff --git a/include/hw/clock.h b/include/hw/clock.h
> index e5f45e2626d..323f8d49fed 100644
> --- a/include/hw/clock.h
> +++ b/include/hw/clock.h
> @@ -22,7 +22,15 @@
>  #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.
> + */
> +typedef enum ClockEvent {
> +    ClockUpdate, /* 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.
> diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
> index 26e1a8c95b6..cf0bd962ea2 100644
> --- a/hw/arm/armsse.c
> +++ b/hw/arm/armsse.c
> @@ -230,9 +230,13 @@ 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);
> +
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      /*
>       * Set system_clock_scale from our Clock input; this is what
>       * controls the tick rate of the CPU SysTick timer.
> @@ -1120,7 +1124,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..2900688fc24 100644
> --- a/hw/char/cadence_uart.c
> +++ b/hw/char/cadence_uart.c
> @@ -519,10 +519,13 @@ 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;
>  
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      /* recompute uart's speed on clock change */
>      uart_parameters_setup(s);
>  }
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> index 89f1182c9bf..c90d4d69baf 100644
> --- a/hw/char/ibex_uart.c
> +++ b/hw/char/ibex_uart.c
> @@ -396,10 +396,13 @@ 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;
>  
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      /* recompute uart's speed on clock change */
>      uint64_t baud = ibex_uart_get_baud(s);
>  
> diff --git a/hw/char/pl011.c b/hw/char/pl011.c
> index ea4a4e52356..d3040c0fab3 100644
> --- a/hw/char/pl011.c
> +++ b/hw/char/pl011.c
> @@ -309,10 +309,13 @@ 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);
>  
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      pl011_trace_baudrate_change(s);
>  }
>  
> diff --git a/hw/core/clock.c b/hw/core/clock.c
> index 76b5f468b6e..772d03a2eb5 100644
> --- a/hw/core/clock.c
> +++ b/hw/core/clock.c
> @@ -73,7 +73,7 @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
>                                 CLOCK_PERIOD_TO_HZ(clk->period),
>                                 call_callbacks);
>              if (call_callbacks && child->callback) {
> -                child->callback(child->callback_opaque);
> +                child->callback(child->callback_opaque, ClockUpdate);
>              }
>              clock_propagate_period(child, call_callbacks);
>          }
> diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
> index 7e415a017c9..5df4bcdb22d 100644
> --- a/hw/misc/bcm2835_cprman.c
> +++ b/hw/misc/bcm2835_cprman.c
> @@ -107,8 +107,11 @@ 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)
>  {
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      pll_update(CPRMAN_PLL(opaque));
>  }
>  
> @@ -209,8 +212,11 @@ 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)
>  {
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
>  }
>  
> @@ -303,12 +309,15 @@ 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;
>      CprmanClockMuxSource src = backref - s->backref;
>  
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) {
>          return;
>      }
> @@ -380,8 +389,11 @@ 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)
>  {
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
>  }
>  
> diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
> index 0bcae9ce957..935184d5482 100644
> --- a/hw/misc/npcm7xx_clk.c
> +++ b/hw/misc/npcm7xx_clk.c
> @@ -586,15 +586,31 @@ static const DividerInitInfo divider_init_info_list[] = {
>      },
>  };
>  
> +static void npcm7xx_clk_update_pll_cb(void *opaque, ClockEvent event)
> +{
> +    if (event != ClockUpdate) {
> +        return;
> +    }
> +    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);
>      pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
>  }
>  
> +static void npcm7xx_clk_update_sel_cb(void *opaque, ClockEvent event)
> +{
> +    if (event != ClockUpdate) {
> +        return;
> +    }
> +    npcm7xx_clk_update_sel(opaque);
> +}
> +
>  static void npcm7xx_clk_sel_init(Object *obj)
>  {
>      int i;
> @@ -603,16 +619,25 @@ 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);
>      }
>      sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
>  }
> +
> +static void npcm7xx_clk_update_divider_cb(void *opaque, ClockEvent event)
> +{
> +    if (event != ClockUpdate) {
> +        return;
> +    }
> +    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);
>      div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
>  }
>  
> diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
> index 66504a9d3ab..555d93ba50c 100644
> --- a/hw/misc/zynq_slcr.c
> +++ b/hw/misc/zynq_slcr.c
> @@ -307,9 +307,13 @@ 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;
> +
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      zynq_slcr_compute_clocks(s);
>      zynq_slcr_propagate_clocks(s);
>  }
> diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
> index ef49f5852d3..ebbc036dc89 100644
> --- a/hw/timer/cmsdk-apb-dualtimer.c
> +++ b/hw/timer/cmsdk-apb-dualtimer.c
> @@ -449,11 +449,14 @@ 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;
>  
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
>          CMSDKAPBDualTimerModule *m = &s->timermod[i];
>          ptimer_transaction_begin(m->timer);
> diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
> index ee51ce3369c..06264f36d4e 100644
> --- a/hw/timer/cmsdk-apb-timer.c
> +++ b/hw/timer/cmsdk-apb-timer.c
> @@ -204,10 +204,13 @@ 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);
>  
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      ptimer_transaction_begin(s->timer);
>      ptimer_set_period_from_clock(s->timer, s->pclk, 1);
>      ptimer_transaction_commit(s->timer);
> diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
> index 302f1711738..7564e8b3326 100644
> --- a/hw/watchdog/cmsdk-apb-watchdog.c
> +++ b/hw/watchdog/cmsdk-apb-watchdog.c
> @@ -310,10 +310,13 @@ 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);
>  
> +    if (event != ClockUpdate) {
> +        return;
> +    }
>      ptimer_transaction_begin(s->timer);
>      ptimer_set_period_from_clock(s->timer, s->wdogclk, 1);
>      ptimer_transaction_commit(s->timer);
> -- 
> 2.20.1
> 

-- 


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

* Re: [RFC 3/4] clock: Add clock_ns_to_ticks() function
  2021-02-01 12:30 ` [RFC 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
@ 2021-02-03 20:51   ` Luc Michel
  0 siblings, 0 replies; 8+ messages in thread
From: Luc Michel @ 2021-02-03 20:51 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Philippe Mathieu-Daudé,
	qemu-devel, Tyrone Ting, qemu-arm, Edgar E. Iglesias,
	Havard Skinnemoen

On 12:30 Mon 01 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>
> ---
> I have made the overflow behaviour here be "wrap", with justification
> as per the comment; but I'm not 100% set on this.
I thought about this, but I can't see a scenario where the upper 64 bits
would be needed. So I guess wrapping is fine.

> ---
>  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 dea63742fb0..84fb45bbe5f 100644
> --- a/docs/devel/clocks.rst
> +++ b/docs/devel/clocks.rst
> @@ -355,6 +355,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 7d0eb286faa..e3545eda439 100644
> --- a/include/hw/clock.h
> +++ b/include/hw/clock.h
> @@ -277,6 +277,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] 8+ messages in thread

* Re: [RFC 0/4] New APIs for the Clock framework
  2021-02-01 12:30 [RFC 0/4] New APIs for the Clock framework Peter Maydell
                   ` (3 preceding siblings ...)
  2021-02-01 12:30 ` [RFC 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
@ 2021-02-03 21:14 ` Luc Michel
  4 siblings, 0 replies; 8+ messages in thread
From: Luc Michel @ 2021-02-03 21:14 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Philippe Mathieu-Daudé,
	qemu-devel, Tyrone Ting, qemu-arm, Edgar E. Iglesias,
	Havard Skinnemoen

On 12:30 Mon 01 Feb     , Peter Maydell wrote:
[snip]
> 
> Side note: there is currently no MAINTAINERS entry for the
> clock framework. Any volunteers? It would cover
> 
> F: include/hw/clock.h
> F: include/hw/qdev-clock.h
> F: hw/core/clock.c
> F: hw/core/qdev-clock.c
> F: docs/devel/clocks.rst

I'd love to get involved as a maintainer so I volunteer. And I think
this part is reasonably small to get started. Do you have some
guidelines? I found https://wiki.qemu.org/Contribute/SubmitAPullRequest
on the QEMU wiki.

Thanks.

-- 
Luc

> 
> 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            | 54 ++++++++++++++++++++++++++++++--
>  include/hw/clock.h               | 52 +++++++++++++++++++++++++++++-
>  hw/arm/armsse.c                  |  8 +++--
>  hw/char/cadence_uart.c           |  5 ++-
>  hw/char/ibex_uart.c              |  5 ++-
>  hw/char/pl011.c                  |  5 ++-
>  hw/core/clock.c                  |  5 ++-
>  hw/misc/bcm2835_cprman.c         | 20 +++++++++---
>  hw/misc/npcm7xx_clk.c            | 31 ++++++++++++++++--
>  hw/misc/zynq_slcr.c              |  6 +++-
>  hw/timer/cmsdk-apb-dualtimer.c   |  5 ++-
>  hw/timer/cmsdk-apb-timer.c       |  5 ++-
>  hw/timer/npcm7xx_timer.c         |  4 +--
>  hw/watchdog/cmsdk-apb-watchdog.c |  5 ++-
>  14 files changed, 188 insertions(+), 22 deletions(-)
> 
> -- 
> 2.20.1
> 

-- 


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

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

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-01 12:30 [RFC 0/4] New APIs for the Clock framework Peter Maydell
2021-02-01 12:30 ` [RFC 1/4] clock: Add ClockEvent parameter to callbacks Peter Maydell
2021-02-02 21:26   ` Luc Michel
2021-02-01 12:30 ` [RFC 2/4] clock: Add ClockPreUpdate callback event type Peter Maydell
2021-02-01 12:30 ` [RFC 3/4] clock: Add clock_ns_to_ticks() function Peter Maydell
2021-02-03 20:51   ` Luc Michel
2021-02-01 12:30 ` [RFC 4/4] hw/timer/npcm7xx_timer: Use new clock_ns_to_ticks() Peter Maydell
2021-02-03 21:14 ` [RFC 0/4] New APIs for the Clock framework 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.