diff mbox

[v1,4/7] target-arm: Implement pmccntr_sync function

Message ID ffad73da5eb3c43aeb7e72922a0dd3eadeb063d5.1403572003.git.alistair.francis@xilinx.com
State New
Headers show

Commit Message

Alistair Francis June 24, 2014, 1:12 a.m. UTC
This is used to synchronise the PMCCNTR counter and swap its
state between enabled and disabled if required. It must always
be called twice, both before and after any logic that could
change the state of the PMCCNTR counter.

Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
---
Remembering that the c15_ccnt register stores the last time
the counter was reset if enabled. If disabled it stores the
counter value (when it was disabled).

The three use cases are as below:
--
Starts enabled/disabled and is staying enabled/disabled
--
The two calls to pmccntr_sync cancel each other out.
Each call implements this logic:
env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt

Which expands to:
env->cp15.c15_ccnt = temp_ticks -
                     (temp_ticks - env->cp15.c15_ccnt)
env->cp15.c15_ccnt = env->cp15.c15_ccnt

--
Starts enabled, gets disabled
--
The logic is run during the first call while during
the second call it is not. That means that c15_ccnt
changes from storing the last time the counter was
reset, to storing the absolute value of the counter.

--
Starts disabled, gets enabled
--
During the fist call no changes are made, while during
the second call the register is changed. This changes it
from storing the absolute value to storing the last time
the counter was reset.

 target-arm/cpu.h    |   11 +++++++++++
 target-arm/helper.c |   19 +++++++++++++++++++
 2 files changed, 30 insertions(+), 0 deletions(-)

Comments

Christopher Covington June 24, 2014, 3:35 p.m. UTC | #1
On 06/23/2014 09:12 PM, Alistair Francis wrote:
> This is used to synchronise the PMCCNTR counter and swap its
> state between enabled and disabled if required. It must always
> be called twice, both before and after any logic that could
> change the state of the PMCCNTR counter.

> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 31aa09c..0984eda 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -1051,6 +1051,17 @@ static inline bool cp_access_ok(int current_pl,
>  }
>  
>  /**
> + * pmccntr_sync
> + * @cpu: ARMCPU
> + *
> + * Syncronises the counter in the PMCCNTR. This must always be called twice,
> + * once before any action that might effect the timer and again afterwards.
> + * The fucntion is used to swap the state of the register if required.

Nit: function
Alistair Francis June 24, 2014, 10:34 p.m. UTC | #2
On Wed, Jun 25, 2014 at 1:35 AM, Christopher Covington
<cov@codeaurora.org> wrote:
> On 06/23/2014 09:12 PM, Alistair Francis wrote:
>> This is used to synchronise the PMCCNTR counter and swap its
>> state between enabled and disabled if required. It must always
>> be called twice, both before and after any logic that could
>> change the state of the PMCCNTR counter.
>
>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>> index 31aa09c..0984eda 100644
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -1051,6 +1051,17 @@ static inline bool cp_access_ok(int current_pl,
>>  }
>>
>>  /**
>> + * pmccntr_sync
>> + * @cpu: ARMCPU
>> + *
>> + * Syncronises the counter in the PMCCNTR. This must always be called twice,
>> + * once before any action that might effect the timer and again afterwards.
>> + * The fucntion is used to swap the state of the register if required.
>
> Nit: function

Good catch, will fix

>
> --
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> hosted by the Linux Foundation.
>
diff mbox

Patch

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 31aa09c..0984eda 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1051,6 +1051,17 @@  static inline bool cp_access_ok(int current_pl,
 }
 
 /**
+ * pmccntr_sync
+ * @cpu: ARMCPU
+ *
+ * Syncronises the counter in the PMCCNTR. This must always be called twice,
+ * once before any action that might effect the timer and again afterwards.
+ * The fucntion is used to swap the state of the register if required.
+ * This only happens when not in user mode (!CONFIG_USER_ONLY)
+ */
+void pmccntr_sync(CPUARMState *env);
+
+/**
  * write_list_to_cpustate
  * @cpu: ARMCPU
  *
diff --git a/target-arm/helper.c b/target-arm/helper.c
index ce986ee..15169c4 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -546,6 +546,25 @@  static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri)
     return CP_ACCESS_OK;
 }
 
+void pmccntr_sync(CPUARMState *env)
+{
+#ifndef CONFIG_USER_ONLY
+    uint64_t temp_ticks;
+
+    temp_ticks = muldiv64(qemu_clock_get_us(QEMU_CLOCK_VIRTUAL),
+                          get_ticks_per_sec(), 1000000);
+
+    if (env->cp15.c9_pmcr & PMCRD) {
+        /* Increment once every 64 processor clock cycles */
+        temp_ticks /= 64;
+    }
+
+    if (CCNT_ENABLED(env)) {
+        env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt;
+    }
+#endif
+}
+
 #ifndef CONFIG_USER_ONLY
 static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                        uint64_t value)