[PATCH] clocksource: imx-tpm: Wait for CnV write to take effect
Daniel Lezcano
daniel.lezcano at linaro.org
Wed Oct 11 00:48:23 PDT 2023
On 09/10/2023 10:42, Jacky Bai wrote:
> The value write into the TPM CnV can only be updated into the HW
> when CNT increase. Additional writes to the CnV write buffer are
> ignored until the register has been updated. So we need to check
> if the CnV has been updated before continue. Wait for 1 CNT cycle
> in worst case.
Is that a fix for an erratic observed behavior on the platform ?
> Additionally, current return check is not correct, if a max_delta
> need be set, it will return '-ETIME' wrongly due to the 'int' type
> cast, so refine the check logic to fix it.
Please put that in a separate patch and double check the fix (now -
prev) which seems to be always nearly one CNT
Fixes tag missing
> Signed-off-by: Jacky Bai <ping.bai at nxp.com>
> ---
> drivers/clocksource/timer-imx-tpm.c | 16 ++++++++++++----
> 1 file changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c
> index bd64a8a8427f..92c025b70eb6 100644
> --- a/drivers/clocksource/timer-imx-tpm.c
> +++ b/drivers/clocksource/timer-imx-tpm.c
> @@ -83,20 +83,28 @@ static u64 notrace tpm_read_sched_clock(void)
> static int tpm_set_next_event(unsigned long delta,
> struct clock_event_device *evt)
> {
> - unsigned long next, now;
> + unsigned long next, prev, now;
>
> - next = tpm_read_counter();
> - next += delta;
> + prev = tpm_read_counter();
> + next = prev + delta;
> writel(next, timer_base + TPM_C0V);
> now = tpm_read_counter();
>
> + /*
> + * Need to wait CNT increase at least 1 cycle to make sure
> + * the C0V has been updated into HW.
> + */
> + if ((next & 0xffffffff) != readl(timer_base + TPM_C0V))
Why do you use a mask for 'next' ?
> + while (now == tpm_read_counter())
> + ;
IIUC, we can rely on one of these condition:
Check against timer_base + TPM_C0V or tpm_read_counter()
We can use the following routine:
while (readl(timer_base + TPM_C0V) != next);
because as soon as 1 CNT cycle happened, TPM_C0V is updated.
Other version could be:
while (now == tpm_read_counter());
Or simply:
usleep_range(min, max);
Right?
> /*
> * NOTE: We observed in a very small probability, the bus fabric
> * contention between GPU and A7 may results a few cycles delay
> * of writing CNT registers which may cause the min_delta event got
> * missed, so we need add a ETIME check here in case it happened.
> */
> - return (int)(next - now) <= 0 ? -ETIME : 0;
> + return (now - prev) >= delta ? -ETIME : 0;
> }
>
> static int tpm_set_state_oneshot(struct clock_event_device *evt)
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
More information about the linux-arm-kernel
mailing list