qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] target-arm: Make the counter tick relative to cntfrq
@ 2019-08-09  3:13 Andrew Jeffery
  2019-08-09  4:05 ` no-reply
  0 siblings, 1 reply; 3+ messages in thread
From: Andrew Jeffery @ 2019-08-09  3:13 UTC (permalink / raw)
  To: qemu-arm; +Cc: Andrew Jeffery, peter.maydell, clg, qemu-devel, joel

The use of GTIMER_SCALE assumes the clock feeding the generic timer is
62.5MHz for all platforms. This is untrue in general, for example the
ASPEED AST2600 feeds the counter with either an 800 or 1200MHz clock,
and CNTFRQ is configured appropriately by u-boot.

To cope with these values we need to take care of the quantization
caused by the clock scaling in terms of nanoseconds per clock by
calculating an effective frequency such that NANOSECONDS_PER_SECOND is
an integer multiple of the effective frequency. Failing to account for
the quantisation leads to sticky behaviour in the VM as the guest timer
subsystems account for the difference between delay time and the counter
value.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
The timer rate assumptions seemed unusual, so I'm not sure if this patch is way
off-base or not. However it does make the AST2600 u-boot and kernel behave
correctly.

 target/arm/helper.c | 51 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 47 insertions(+), 4 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index b74c23a9bc08..35d14c183630 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2277,6 +2277,34 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
 
 #ifndef CONFIG_USER_ONLY
 
+static void gt_recalc_timer(ARMCPU *cpu, int timeridx);
+static void gt_cntfrq_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                            uint64_t value)
+{
+    uint64_t scale;
+    ARMCPU *cpu;
+    int i;
+
+    raw_write(env, ri, value);
+
+    /* Fix up the timer scaling */
+    cpu = env_archcpu(env);
+    scale = MAX(1, NANOSECONDS_PER_SECOND / value);
+    for (i = 0; i < NUM_GTIMERS; i++) {
+        if (!cpu->gt_timer[i]) {
+            continue;
+        }
+
+        cpu->gt_timer[i]->scale = scale;
+        gt_recalc_timer(cpu, i);
+    }
+}
+
+static void gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque)
+{
+    gt_cntfrq_write(env, opaque, opaque->resetvalue);
+}
+
 static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri,
                                        bool isread)
 {
@@ -2405,9 +2433,21 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
     }
 }
 
+static uint64_t gt_calc_tick(CPUARMState *env, uint64_t ns)
+{
+    /*
+     * Deal with quantized clock scaling by calculating the effective frequency
+     * in terms of the timer scale.
+     */
+    uint32_t scale = MAX(1, NANOSECONDS_PER_SECOND / env->cp15.c14_cntfrq);
+    uint64_t effective = NANOSECONDS_PER_SECOND / scale;
+
+    return muldiv64(ns, effective, NANOSECONDS_PER_SECOND);
+}
+
 static uint64_t gt_get_countervalue(CPUARMState *env)
 {
-    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE;
+    return gt_calc_tick(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 }
 
 static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
@@ -2443,8 +2483,8 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
          * set the timer for as far in the future as possible. When the
          * timer expires we will reset the timer for any remaining period.
          */
-        if (nexttick > INT64_MAX / GTIMER_SCALE) {
-            nexttick = INT64_MAX / GTIMER_SCALE;
+        if (nexttick > INT64_MAX / cpu->gt_timer[timeridx]->scale) {
+            nexttick = INT64_MAX / cpu->gt_timer[timeridx]->scale;
         }
         timer_mod(cpu->gt_timer[timeridx], nexttick);
         trace_arm_gt_recalc(timeridx, irqstate, nexttick);
@@ -2686,13 +2726,16 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
     { .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0,
       .type = ARM_CP_ALIAS,
       .access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
+      .writefn = gt_cntfrq_write,
       .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_cntfrq),
     },
     { .name = "CNTFRQ_EL0", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0,
       .access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
+      .writefn = gt_cntfrq_write,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
       .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE,
+      .resetfn = gt_cntfrq_reset,
     },
     /* overall control: mostly access permissions */
     { .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH,
@@ -2875,7 +2918,7 @@ static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
      * can't call gt_get_countervalue(env), instead we directly
      * call the lower level functions.
      */
-    return cpu_get_clock() / GTIMER_SCALE;
+    return gt_calc_tick(env, cpu_get_clock());
 }
 
 static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
-- 
2.20.1



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

* Re: [Qemu-devel] [PATCH] target-arm: Make the counter tick relative to cntfrq
  2019-08-09  3:13 [Qemu-devel] [PATCH] target-arm: Make the counter tick relative to cntfrq Andrew Jeffery
@ 2019-08-09  4:05 ` no-reply
  2019-08-09  4:57   ` Andrew Jeffery
  0 siblings, 1 reply; 3+ messages in thread
From: no-reply @ 2019-08-09  4:05 UTC (permalink / raw)
  To: andrew; +Cc: peter.maydell, andrew, qemu-devel, qemu-arm, joel, clg

Patchew URL: https://patchew.org/QEMU/20190809031321.14760-1-andrew@aj.id.au/



Hi,

This series failed build test on s390x host. Please find the details below.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
set -e

echo
echo "=== ENV ==="
env

echo
echo "=== PACKAGES ==="
rpm -qa

echo
echo "=== UNAME ==="
uname -a

CC=$HOME/bin/cc
INSTALL=$PWD/install
BUILD=$PWD/build
mkdir -p $BUILD $INSTALL
SRC=$PWD
cd $BUILD
$SRC/configure --cc=$CC --prefix=$INSTALL
make -j4
# XXX: we need reliable clean up
# make check -j4 V=1
make install
=== TEST SCRIPT END ===

  CC      aarch64_be-linux-user/target/arm/arm-semi.o
  CC      aarch64_be-linux-user/target/arm/helper.o
/var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c: In function ‘gt_virt_cnt_read’:
/var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c:2921:12: error: implicit declaration of function ‘gt_calc_tick’ [-Werror=implicit-function-declaration]
 2921 |     return gt_calc_tick(env, cpu_get_clock());
      |            ^~~~~~~~~~~~
/var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c:2921:12: error: nested extern declaration of ‘gt_calc_tick’ [-Werror=nested-externs]
cc1: all warnings being treated as errors
make[1]: *** [/var/tmp/patchew-tester-tmp-hkd7ua1n/src/rules.mak:69: target/arm/helper.o] Error 1
make: *** [Makefile:472: aarch64_be-linux-user/all] Error 2


The full log is available at
http://patchew.org/logs/20190809031321.14760-1-andrew@aj.id.au/testing.s390x/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [Qemu-devel]  [PATCH] target-arm: Make the counter tick relative to cntfrq
  2019-08-09  4:05 ` no-reply
@ 2019-08-09  4:57   ` Andrew Jeffery
  0 siblings, 0 replies; 3+ messages in thread
From: Andrew Jeffery @ 2019-08-09  4:57 UTC (permalink / raw)
  To: no-reply, qemu-devel
  Cc: Peter Maydell, qemu-arm, Joel Stanley, Cédric Le Goater



On Fri, 9 Aug 2019, at 13:36, no-reply@patchew.org wrote:
> Patchew URL: https://patchew.org/QEMU/20190809031321.14760-1-andrew@aj.id.au/
> 
> 
> 
> Hi,
> 
> This series failed build test on s390x host. Please find the details below.
> 
> === TEST SCRIPT BEGIN ===
> #!/bin/bash
> # Testing script will be invoked under the git checkout with
> # HEAD pointing to a commit that has the patches applied on top of "base"
> # branch
> set -e
> 
> echo
> echo "=== ENV ==="
> env
> 
> echo
> echo "=== PACKAGES ==="
> rpm -qa
> 
> echo
> echo "=== UNAME ==="
> uname -a
> 
> CC=$HOME/bin/cc
> INSTALL=$PWD/install
> BUILD=$PWD/build
> mkdir -p $BUILD $INSTALL
> SRC=$PWD
> cd $BUILD
> $SRC/configure --cc=$CC --prefix=$INSTALL
> make -j4
> # XXX: we need reliable clean up
> # make check -j4 V=1
> make install
> === TEST SCRIPT END ===
> 
>   CC      aarch64_be-linux-user/target/arm/arm-semi.o
>   CC      aarch64_be-linux-user/target/arm/helper.o
> /var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c: In 
> function ‘gt_virt_cnt_read’:
> /var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c:2921:12: 
> error: implicit declaration of function ‘gt_calc_tick’ 
> [-Werror=implicit-function-declaration]
>  2921 |     return gt_calc_tick(env, cpu_get_clock());
>       |            ^~~~~~~~~~~~
> /var/tmp/patchew-tester-tmp-hkd7ua1n/src/target/arm/helper.c:2921:12: 
> error: nested extern declaration of ‘gt_calc_tick’ 
> [-Werror=nested-externs]
> cc1: all warnings being treated as errors
> make[1]: *** [/var/tmp/patchew-tester-tmp-hkd7ua1n/src/rules.mak:69: 
> target/arm/helper.o] Error 1
> make: *** [Makefile:472: aarch64_be-linux-user/all] Error 2
> 

Ah, I missed that I put the implementation inside the
#ifndef CONFIG_USER_ONLY` block. Maybe we can just not do the scaling
for userspace anyway?

Andrew


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

end of thread, other threads:[~2019-08-09  4:57 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-09  3:13 [Qemu-devel] [PATCH] target-arm: Make the counter tick relative to cntfrq Andrew Jeffery
2019-08-09  4:05 ` no-reply
2019-08-09  4:57   ` Andrew Jeffery

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).