diff mbox

[v20,08/17] clocksource/drivers/arm_arch_timer: Rework counter frequency detection.

Message ID CADyBb7sU6DVMk6px0963r8by--U-3k_XjESd88zZMkj7xbywgA@mail.gmail.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

fu.wei@linaro.org Jan. 25, 2017, 6:46 a.m. UTC
Hi Mark,

On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
> On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
>> From: Fu Wei <fu.wei@linaro.org>
>>
>> The counter frequency detection call(arch_timer_detect_rate) combines two
>> ways to get counter frequency: system coprocessor register and MMIO timer.
>> But in a specific timer init code, we only need one way to try:
>> getting frequency from MMIO timer register will be needed only when we
>> init MMIO timer; getting frequency from system coprocessor register will
>> be needed only when we init arch timer.
>
> When I mentioned this splitting before, I had mean that we'd completely
> separate the two, with separate mmio_rate and sysreg_rate variables.

sorry for misunderstanding.

Are you saying :



But what have I learned From ARMv8 ARM is
AArch64 System register CNTFRQ_EL0 is provided so that software can
discover the frequency of the system counter.
CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can
discover the frequency of the system counter.
The bit assignments of the registers are identical in the System
register interface and in the memory-mapped system level interface.
So I think they both contain the same value : the frequency of the
system counter, just in different view, and can be accessed in
different ways.

So do we really need to separate mmio_rate and sysreg_rate variables?

And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in
Linux kernel (EL1),
Because ARMv8 ARM says:
In a system that implements both Secure and Non-secure states, this
register is only accessible by Secure accesses.
That means we still need to get the frequency of the system counter
from CNTFRQ_EL0 in MMIO timer code.
This have been proved when I tested this driver on foundation model, I
got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)

So I guess the logic of the original code is
 static u32 arch_timer_rate keeps the frequency of the system counter,
 no matter where the value comes from.
Because  they should be the same value. if we have got the frequency
of the system counter(arch_timer_rate != 0), then we don't need to get
it again, even in anther way.

But  the above is just my thought, and I believe you're the expert of
ARM. So please correct me if I misunderstand something.  :-)

Thanks!
>
> The probing logic relying on this is complicated and fragile, and I
> think these patches are complicating that further (though I appreciate
> that's far from the intent).
>
> I believe we need to split the MMIO and sysreg timer code apart
> entirely. I've had a look at that today, though it's been fairly painful
> so far. It appears some platforms may inadvertently be relying on the
> order and manner in which the rates are probed, which is a major
> headache.
>
> I will try to attack that some more tomorrow.
>
>> This patch separates paths to determine frequency:
>> Separate out the MMIO frequency and the sysreg frequency detection call,
>> and use the appropriate one for the counter.
>>
>> Signed-off-by: Fu Wei <fu.wei@linaro.org>
>> ---
>>  drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++--------------
>>  1 file changed, 25 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
>> index 6484f84..9482481 100644
>> --- a/drivers/clocksource/arm_arch_timer.c
>> +++ b/drivers/clocksource/arm_arch_timer.c
>> @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu)
>>       return 0;
>>  }
>>
>> -static void arch_timer_detect_rate(void __iomem *cntbase)
>> +static void __arch_timer_determine_rate(u32 rate)
>>  {
>> -     /* Who has more than one independent system counter? */
>> -     if (arch_timer_rate)
>> -             return;
>> +     /* Check the timer frequency. */
>> +     if (!arch_timer_rate) {
>> +             if (rate)
>> +                     arch_timer_rate = rate;
>> +             else
>> +                     pr_warn("frequency not available\n");
>> +     } else if (rate && arch_timer_rate != rate) {
>> +             pr_warn("got different frequency, keep original.\n");
>> +     }
>> +}
>
> This function should be killed off entirely. We need to be able to fail
> the probe if we cannot determine the rate, and that means we need error
> handling in the ACPI and DT cases anyway.
>
> Thanks,
> Mark.

Comments

fu.wei@linaro.org Jan. 25, 2017, 7:23 a.m. UTC | #1
Hi Mark,

On 25 January 2017 at 14:46, Fu Wei <fu.wei@linaro.org> wrote:
> Hi Mark,
>
> On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
>> On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
>>> From: Fu Wei <fu.wei@linaro.org>
>>>
>>> The counter frequency detection call(arch_timer_detect_rate) combines two
>>> ways to get counter frequency: system coprocessor register and MMIO timer.
>>> But in a specific timer init code, we only need one way to try:
>>> getting frequency from MMIO timer register will be needed only when we
>>> init MMIO timer; getting frequency from system coprocessor register will
>>> be needed only when we init arch timer.
>>
>> When I mentioned this splitting before, I had mean that we'd completely
>> separate the two, with separate mmio_rate and sysreg_rate variables.
>
> sorry for misunderstanding.
>
> Are you saying :
>
> diff --git a/drivers/clocksource/arm_arch_timer.c
> b/drivers/clocksource/arm_arch_timer.c
> index 663a57a..eec92f6 100644
> --- a/drivers/clocksource/arm_arch_timer.c
> +++ b/drivers/clocksource/arm_arch_timer.c
> @@ -65,7 +65,8 @@ struct arch_timer {
>
>  #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
>
> -static u32 arch_timer_rate;
> +static u32 arch_timer_sysreg_rate ;
> +static u32 arch_timer_mmio_rate;
>  static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
>
>  static struct clock_event_device __percpu *arch_timer_evt;
>
>
> But what have I learned From ARMv8 ARM is
> AArch64 System register CNTFRQ_EL0 is provided so that software can
> discover the frequency of the system counter.
> CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can
> discover the frequency of the system counter.
> The bit assignments of the registers are identical in the System
> register interface and in the memory-mapped system level interface.
> So I think they both contain the same value : the frequency of the
> system counter, just in different view, and can be accessed in
> different ways.
>
> So do we really need to separate mmio_rate and sysreg_rate variables?
>
> And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in
> Linux kernel (EL1),
> Because ARMv8 ARM says:
> In a system that implements both Secure and Non-secure states, this
> register is only accessible by Secure accesses.
> That means we still need to get the frequency of the system counter
> from CNTFRQ_EL0 in MMIO timer code.
> This have been proved when I tested this driver on foundation model, I
> got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
>
> So I guess the logic of the original code is
>  static u32 arch_timer_rate keeps the frequency of the system counter,
>  no matter where the value comes from.
> Because  they should be the same value. if we have got the frequency
> of the system counter(arch_timer_rate != 0), then we don't need to get
> it again, even in anther way.

*IF*  the above is right,
For ARM32, boot with dtb,  the original logic and this patch work well.
For ARM64, boot with dtb,  if MMIO timer is probed first, and there is
not "clock-frequency" in the node. MMIO timer can't get  the
frequency. Because we will get "0" when we access CNTFRQ from Linux
kernel (Non-secure EL1), that means the original logic and this patch
won't work. To fix this issue, we need to get  the frequency  from
sysreg CNTFRQ_EL0.
For ARM64, boot with ACPI, the original logic and this patch work
well, because we always probe arch_timer first.

So *IF* I understand it correctly, May I suggest that we only get  the
frequency from sysreg CNTFRQ_EL0 in this driver?
I think that can simplify the code and avoid the issue when we boot
ARM64 with dtb.

Again,  please correct me if I misunderstand something.  :-)  Great
thanks for your help!

>
> But  the above is just my thought, and I believe you're the expert of
> ARM. So please correct me if I misunderstand something.  :-)
>
> Thanks!
>>
>> The probing logic relying on this is complicated and fragile, and I
>> think these patches are complicating that further (though I appreciate
>> that's far from the intent).
>>
>> I believe we need to split the MMIO and sysreg timer code apart
>> entirely. I've had a look at that today, though it's been fairly painful
>> so far. It appears some platforms may inadvertently be relying on the
>> order and manner in which the rates are probed, which is a major
>> headache.
>>
>> I will try to attack that some more tomorrow.
>>
>>> This patch separates paths to determine frequency:
>>> Separate out the MMIO frequency and the sysreg frequency detection call,
>>> and use the appropriate one for the counter.
>>>
>>> Signed-off-by: Fu Wei <fu.wei@linaro.org>
>>> ---
>>>  drivers/clocksource/arm_arch_timer.c | 40 ++++++++++++++++++++++--------------
>>>  1 file changed, 25 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
>>> index 6484f84..9482481 100644
>>> --- a/drivers/clocksource/arm_arch_timer.c
>>> +++ b/drivers/clocksource/arm_arch_timer.c
>>> @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu)
>>>       return 0;
>>>  }
>>>
>>> -static void arch_timer_detect_rate(void __iomem *cntbase)
>>> +static void __arch_timer_determine_rate(u32 rate)
>>>  {
>>> -     /* Who has more than one independent system counter? */
>>> -     if (arch_timer_rate)
>>> -             return;
>>> +     /* Check the timer frequency. */
>>> +     if (!arch_timer_rate) {
>>> +             if (rate)
>>> +                     arch_timer_rate = rate;
>>> +             else
>>> +                     pr_warn("frequency not available\n");
>>> +     } else if (rate && arch_timer_rate != rate) {
>>> +             pr_warn("got different frequency, keep original.\n");
>>> +     }
>>> +}
>>
>> This function should be killed off entirely. We need to be able to fail
>> the probe if we cannot determine the rate, and that means we need error
>> handling in the ACPI and DT cases anyway.
>>
>> Thanks,
>> Mark.
>
>
>
> --
> Best regards,
>
> Fu Wei
> Software Engineer
> Red Hat
Christopher Covington Jan. 25, 2017, 3:38 p.m. UTC | #2
Hi Fu,

On 01/25/2017 01:46 AM, Fu Wei wrote:
> Hi Mark,
> 
> On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
>> On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
>>> From: Fu Wei <fu.wei@linaro.org>
>>>
>>> The counter frequency detection call(arch_timer_detect_rate) combines two
>>> ways to get counter frequency: system coprocessor register and MMIO timer.
>>> But in a specific timer init code, we only need one way to try:
>>> getting frequency from MMIO timer register will be needed only when we
>>> init MMIO timer; getting frequency from system coprocessor register will
>>> be needed only when we init arch timer.
>>
>> When I mentioned this splitting before, I had mean that we'd completely
>> separate the two, with separate mmio_rate and sysreg_rate variables.
> 
> sorry for misunderstanding.
> 
> Are you saying :
> 
> diff --git a/drivers/clocksource/arm_arch_timer.c
> b/drivers/clocksource/arm_arch_timer.c
> index 663a57a..eec92f6 100644
> --- a/drivers/clocksource/arm_arch_timer.c
> +++ b/drivers/clocksource/arm_arch_timer.c
> @@ -65,7 +65,8 @@ struct arch_timer {
> 
>  #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
> 
> -static u32 arch_timer_rate;
> +static u32 arch_timer_sysreg_rate ;
> +static u32 arch_timer_mmio_rate;
>  static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
> 
>  static struct clock_event_device __percpu *arch_timer_evt;
> 
> 
> But what have I learned From ARMv8 ARM is
> AArch64 System register CNTFRQ_EL0 is provided so that software can
> discover the frequency of the system counter.
> CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can
> discover the frequency of the system counter.
> The bit assignments of the registers are identical in the System
> register interface and in the memory-mapped system level interface.
> So I think they both contain the same value : the frequency of the
> system counter, just in different view, and can be accessed in
> different ways.
> 
> So do we really need to separate mmio_rate and sysreg_rate variables?
> 
> And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in
> Linux kernel (EL1),
> Because ARMv8 ARM says:
> In a system that implements both Secure and Non-secure states, this
> register is only accessible by Secure accesses.
> That means we still need to get the frequency of the system counter
> from CNTFRQ_EL0 in MMIO timer code.
> This have been proved when I tested this driver on foundation model, I
> got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)

That sounds like a firmware problem. Firmware in EL3 is supposed to write
the value into CNTFRQ. If you're not currently using any firmware, I'd
recommend the bootwrapper on models/simulators/emulators.

http://git.kernel.org/cgit/linux/kernel/git/mark/boot-wrapper-aarch64.git/tree/arch/aarch64/boot.S#n48

Cheers,
Cov
Mark Rutland Jan. 25, 2017, 5:25 p.m. UTC | #3
On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
> Hi Mark,

Hi,

> On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
> > On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
> >> From: Fu Wei <fu.wei@linaro.org>
> >>
> >> The counter frequency detection call(arch_timer_detect_rate) combines two
> >> ways to get counter frequency: system coprocessor register and MMIO timer.
> >> But in a specific timer init code, we only need one way to try:
> >> getting frequency from MMIO timer register will be needed only when we
> >> init MMIO timer; getting frequency from system coprocessor register will
> >> be needed only when we init arch timer.
> >
> > When I mentioned this splitting before, I had mean that we'd completely
> > separate the two, with separate mmio_rate and sysreg_rate variables.
> 
> sorry for misunderstanding.
> 
> Are you saying :
> 
> diff --git a/drivers/clocksource/arm_arch_timer.c
> b/drivers/clocksource/arm_arch_timer.c
> index 663a57a..eec92f6 100644
> --- a/drivers/clocksource/arm_arch_timer.c
> +++ b/drivers/clocksource/arm_arch_timer.c
> @@ -65,7 +65,8 @@ struct arch_timer {
> 
>  #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
> 
> -static u32 arch_timer_rate;
> +static u32 arch_timer_sysreg_rate ;
> +static u32 arch_timer_mmio_rate;
>  static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
> 
>  static struct clock_event_device __percpu *arch_timer_evt;
> 
> 
> But what have I learned From ARMv8 ARM is
> AArch64 System register CNTFRQ_EL0 is provided so that software can
> discover the frequency of the system counter.
> CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can
> discover the frequency of the system counter.
> The bit assignments of the registers are identical in the System
> register interface and in the memory-mapped system level interface.

This means that the bits in the registers have the same meaning.

However, they are separate registers, and must be written separately. A
write to one does not propagate to the other, and they are not
guaranteed to contain the same value.

> So I think they both contain the same value : the frequency of the
> system counter, just in different view, and can be accessed in
> different ways.

Certainly, in theory, these *should* contain the same value.

Unfortunately, in practice, on several systems, they do not. It is very
easy to forget to initialise one of these registers correctly, and it's
possible for some software to work (masking the issue), while other
software will fail very quickly. I very much suspect we will see the
same class of issue on ACPI systems.

Consider a system where the sysreg CNTFRQ was correct, but the MMIO
CNTFRQ contains an erroneous non-zero value.

If we get the frequency out of CNTFRQ_EL0 first, and assign this to
arch_timer_rate, we won't bother to look at the MMIO registers (which
could contain erroneous values). If we read an erroneous CNTBaseN.CNTFRQ
value first, and assign this to arch_timer_rate, we won't look at
CNTFRQ_EL0.

This is *very* fragile w.r.t. probe order. I don't like the fragility of
setting a common arch_timer_rate depending on which gets probed first,
as this masks a bug, which will adversely affect us later.

This is already a problem for DT systems, and I do not want this problem
to spread to ACPI systems.

For ACPI, the approach I'd personally like to take is to keep the two
rates separate. Probe the sysreg timer first and subsequently probe the
MMIO timers. If the MMIO CNTFRQ (of all frames) does not match the
sysreg CNTFRQ, we log a warning and give up probing the MMIO timers.

For legacy reasons, DT is going to be more complicated, but I believe we
can apply that approach to ACPI.
 
> So do we really need to separate mmio_rate and sysreg_rate variables?
> 
> And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in
> Linux kernel (EL1),
> Because ARMv8 ARM says:
> In a system that implements both Secure and Non-secure states, this
> register is only accessible by Secure accesses.

CNTCTLBase.CNTFRQ can only be accessed in secure states. That is clear
from Table I1-3 in ARM DDI 0487A.k_iss10775). I agree that we cannot
access this.

For CNT{,EL0}BaseN.CNTFRQ, I am very concerned by the wording in the
current ARMv8 ARM ARM. This does not match my understanding, nor does it
match the description in the ARMv7 ARM. I believe this may be a
documentation error, and I'm chasing that up internally.

Either the currently logic in the driver which attempts to read
CNT{,EL0}BaseN.CNTFRQ is flawed, or the description in the ARM ARM is
erroneous.

> That means we still need to get the frequency of the system counter
> from CNTFRQ_EL0 in MMIO timer code.
> This have been proved when I tested this driver on foundation model, I
> got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)

As mentioned in I3.5.7, the CNTBase{,EL0}N.CNTFRQ values are UNKNOWN out
of reset, and require configuration by FW.

> So I guess the logic of the original code is
>  static u32 arch_timer_rate keeps the frequency of the system counter,
>  no matter where the value comes from.
> Because  they should be the same value. if we have got the frequency
> of the system counter(arch_timer_rate != 0), then we don't need to get
> it again, even in anther way.

Unfortunately, in practice this is not the case. :(

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Rutland Jan. 25, 2017, 5:36 p.m. UTC | #4
On Wed, Jan 25, 2017 at 10:38:01AM -0500, Christopher Covington wrote:
> On 01/25/2017 01:46 AM, Fu Wei wrote:
> > On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
> >> On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
> >>> From: Fu Wei <fu.wei@linaro.org>

> > And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in
> > Linux kernel (EL1),
> > Because ARMv8 ARM says:
> > In a system that implements both Secure and Non-secure states, this
> > register is only accessible by Secure accesses.
> > That means we still need to get the frequency of the system counter
> > from CNTFRQ_EL0 in MMIO timer code.
> > This have been proved when I tested this driver on foundation model, I
> > got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
> 
> That sounds like a firmware problem. Firmware in EL3 is supposed to write
> the value into CNTFRQ.

Definitely. FW *should* program the CNTFRQ_EL0 CPU registers and any
MMIO CNTFRQ registers.

> If you're not currently using any firmware, I'd
> recommend the bootwrapper on models/simulators/emulators.
> 
> http://git.kernel.org/cgit/linux/kernel/git/mark/boot-wrapper-aarch64.git/tree/arch/aarch64/boot.S#n48

Unfortunately, the boot-wrapper only programs the CNTFRQ_EL0 CPU system
registers, and does not program any MMIO CNTFRQ registers.

IIRC the models it was originally written for didn't have any (and we
had no DT binding until far later...). Luckily the model DTs do not
expose any MMIO timer addresses to the kernel currently.

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
fu.wei@linaro.org Jan. 26, 2017, 5:49 a.m. UTC | #5
Hi Mark,

On 26 January 2017 at 01:25, Mark Rutland <mark.rutland@arm.com> wrote:
> On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
>> Hi Mark,
>
> Hi,
>
>> On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
>> > On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
>> >> From: Fu Wei <fu.wei@linaro.org>
>> >>
>> >> The counter frequency detection call(arch_timer_detect_rate) combines two
>> >> ways to get counter frequency: system coprocessor register and MMIO timer.
>> >> But in a specific timer init code, we only need one way to try:
>> >> getting frequency from MMIO timer register will be needed only when we
>> >> init MMIO timer; getting frequency from system coprocessor register will
>> >> be needed only when we init arch timer.
>> >
>> > When I mentioned this splitting before, I had mean that we'd completely
>> > separate the two, with separate mmio_rate and sysreg_rate variables.
>>
>> sorry for misunderstanding.
>>
>> Are you saying :
>>
>> diff --git a/drivers/clocksource/arm_arch_timer.c
>> b/drivers/clocksource/arm_arch_timer.c
>> index 663a57a..eec92f6 100644
>> --- a/drivers/clocksource/arm_arch_timer.c
>> +++ b/drivers/clocksource/arm_arch_timer.c
>> @@ -65,7 +65,8 @@ struct arch_timer {
>>
>>  #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
>>
>> -static u32 arch_timer_rate;
>> +static u32 arch_timer_sysreg_rate ;
>> +static u32 arch_timer_mmio_rate;
>>  static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
>>
>>  static struct clock_event_device __percpu *arch_timer_evt;
>>
>>
>> But what have I learned From ARMv8 ARM is
>> AArch64 System register CNTFRQ_EL0 is provided so that software can
>> discover the frequency of the system counter.
>> CNTFRQ(in CNTCTLBase and CNTBaseN) is provided so that software can
>> discover the frequency of the system counter.
>> The bit assignments of the registers are identical in the System
>> register interface and in the memory-mapped system level interface.
>
> This means that the bits in the registers have the same meaning.
>
> However, they are separate registers, and must be written separately. A
> write to one does not propagate to the other, and they are not
> guaranteed to contain the same value.

Ah, Sorry for misunderstanding this, and thanks for correcting it,
I thought they point to the same register.

>
>> So I think they both contain the same value : the frequency of the
>> system counter, just in different view, and can be accessed in
>> different ways.
>
> Certainly, in theory, these *should* contain the same value.
>
> Unfortunately, in practice, on several systems, they do not. It is very
> easy to forget to initialise one of these registers correctly, and it's
> possible for some software to work (masking the issue), while other
> software will fail very quickly. I very much suspect we will see the
> same class of issue on ACPI systems.

Ah, thanks , that makes sense to me :-)

So can I say:
In normal case, CNTFRQ_EL0, CNTCTLBase.CNTFRQ and CNTBaseN.CNTFRQ
should be set to the same value.
But in some special case, some CNTFRQ maybe set to a different number
for some reason(maybe on purpose).

>
> Consider a system where the sysreg CNTFRQ was correct, but the MMIO
> CNTFRQ contains an erroneous non-zero value.
>
> If we get the frequency out of CNTFRQ_EL0 first, and assign this to
> arch_timer_rate, we won't bother to look at the MMIO registers (which
> could contain erroneous values). If we read an erroneous CNTBaseN.CNTFRQ
> value first, and assign this to arch_timer_rate, we won't look at
> CNTFRQ_EL0.
>
> This is *very* fragile w.r.t. probe order. I don't like the fragility of
> setting a common arch_timer_rate depending on which gets probed first,
> as this masks a bug, which will adversely affect us later.
>
> This is already a problem for DT systems, and I do not want this problem
> to spread to ACPI systems.
>
> For ACPI, the approach I'd personally like to take is to keep the two
> rates separate. Probe the sysreg timer first and subsequently probe the
> MMIO timers. If the MMIO CNTFRQ (of all frames) does not match the
> sysreg CNTFRQ, we log a warning and give up probing the MMIO timers.

OK, I think I got your point, will do this way. Thanks :-)

>
> For legacy reasons, DT is going to be more complicated, but I believe we
> can apply that approach to ACPI.
>
>> So do we really need to separate mmio_rate and sysreg_rate variables?
>>
>> And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in
>> Linux kernel (EL1),
>> Because ARMv8 ARM says:
>> In a system that implements both Secure and Non-secure states, this
>> register is only accessible by Secure accesses.
>
> CNTCTLBase.CNTFRQ can only be accessed in secure states. That is clear
> from Table I1-3 in ARM DDI 0487A.k_iss10775). I agree that we cannot
> access this.

yes , got it.
And we don't do it in the driver, we try to access  CNTBaseN.CNTFRQ
(in a frame) instead.

>
> For CNT{,EL0}BaseN.CNTFRQ, I am very concerned by the wording in the
> current ARMv8 ARM ARM. This does not match my understanding, nor does it
> match the description in the ARMv7 ARM. I believe this may be a
> documentation error, and I'm chasing that up internally.
>
> Either the currently logic in the driver which attempts to read
> CNT{,EL0}BaseN.CNTFRQ is flawed, or the description in the ARM ARM is
> erroneous.

Yes, those description did confuse me. :-(

But according to another document(ARMv8-A Foundation Platform User
Guide  ARM DUI0677K),
Table 3-2 ARMv8-A Foundation Platform memory map (continued)

AP_REFCLK CNTBase0, Generic Timer 64KB   S
AP_REFCLK CNTBase1, Generic Timer 64KB   S/NS

Dose it means the timer frame 0 can be accessed in SECURE status  only,
and the timer frame 1 can be accessed in both status?

And because Linux kernel is running on Non-secure EL1, so should we
skip "SECURE" timer in Linux?

>
>> That means we still need to get the frequency of the system counter
>> from CNTFRQ_EL0 in MMIO timer code.
>> This have been proved when I tested this driver on foundation model, I
>> got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
>
> As mentioned in I3.5.7, the CNTBase{,EL0}N.CNTFRQ values are UNKNOWN out
> of reset, and require configuration by FW.
>
>> So I guess the logic of the original code is
>>  static u32 arch_timer_rate keeps the frequency of the system counter,
>>  no matter where the value comes from.
>> Because  they should be the same value. if we have got the frequency
>> of the system counter(arch_timer_rate != 0), then we don't need to get
>> it again, even in anther way.
>
> Unfortunately, in practice this is not the case. :(
>
> Thanks,
> Mark.
fu.wei@linaro.org Jan. 26, 2017, 5:55 a.m. UTC | #6
Hi Mark, Christopher,

On 26 January 2017 at 01:36, Mark Rutland <mark.rutland@arm.com> wrote:
> On Wed, Jan 25, 2017 at 10:38:01AM -0500, Christopher Covington wrote:
>> On 01/25/2017 01:46 AM, Fu Wei wrote:
>> > On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
>> >> On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
>> >>> From: Fu Wei <fu.wei@linaro.org>
>
>> > And for CNTFRQ(in CNTCTLBase and CNTBaseN) , we can NOT access it in
>> > Linux kernel (EL1),
>> > Because ARMv8 ARM says:
>> > In a system that implements both Secure and Non-secure states, this
>> > register is only accessible by Secure accesses.
>> > That means we still need to get the frequency of the system counter
>> > from CNTFRQ_EL0 in MMIO timer code.
>> > This have been proved when I tested this driver on foundation model, I
>> > got "0" when I access CNTFRQ from Linux kernel (Non-secure EL1)
>>
>> That sounds like a firmware problem. Firmware in EL3 is supposed to write
>> the value into CNTFRQ.
>
> Definitely. FW *should* program the CNTFRQ_EL0 CPU registers and any
> MMIO CNTFRQ registers.

Many thanks for the explanation. This might be the problem. Maybe we
can check the UEFI :-)

>
>> If you're not currently using any firmware, I'd
>> recommend the bootwrapper on models/simulators/emulators.
>>
>> http://git.kernel.org/cgit/linux/kernel/git/mark/boot-wrapper-aarch64.git/tree/arch/aarch64/boot.S#n48
>
> Unfortunately, the boot-wrapper only programs the CNTFRQ_EL0 CPU system
> registers, and does not program any MMIO CNTFRQ registers.
>
> IIRC the models it was originally written for didn't have any (and we
> had no DT binding until far later...). Luckily the model DTs do not
> expose any MMIO timer addresses to the kernel currently.

But according to another document(ARMv8-A Foundation Platform User
Guide  ARM DUI0677K), Table 3-2 ARMv8-A Foundation Platform memory
map,
we may have two frames in the Generic timer block, right?


>
> Thanks,
> Mark.
Mark Rutland Jan. 30, 2017, 5:49 p.m. UTC | #7
On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
> On 26 January 2017 at 01:25, Mark Rutland <mark.rutland@arm.com> wrote:
> > On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
> >> On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
> >> > On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
> >> >> From: Fu Wei <fu.wei@linaro.org>

> > For CNT{,EL0}BaseN.CNTFRQ, I am very concerned by the wording in the
> > current ARMv8 ARM ARM. This does not match my understanding, nor does it
> > match the description in the ARMv7 ARM. I believe this may be a
> > documentation error, and I'm chasing that up internally.
> >
> > Either the currently logic in the driver which attempts to read
> > CNT{,EL0}BaseN.CNTFRQ is flawed, or the description in the ARM ARM is
> > erroneous.
> 
> Yes, those description did confuse me. :-(
> 
> But according to another document(ARMv8-A Foundation Platform User
> Guide  ARM DUI0677K),
> Table 3-2 ARMv8-A Foundation Platform memory map (continued)
> 
> AP_REFCLK CNTBase0, Generic Timer 64KB   S
> AP_REFCLK CNTBase1, Generic Timer 64KB   S/NS
> 
> Dose it means the timer frame 0 can be accessed in SECURE status  only,
> and the timer frame 1 can be accessed in both status?

That does appear to be what it says.

I assume in this case CNTCTLBase.CNTSAR<0> is RES0.

> And because Linux kernel is running on Non-secure EL1, so should we
> skip "SECURE" timer in Linux?

I guess you mean by checking the GTx Common flags, to see if the timer
is secure? Yes, we must skip those.

Looking further at this, the ACPI spec is sorely lacking any statement
as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's
not clear if we can access anything in a frame, even if it is listed as
being a non-secure timer.

I think we need a stronger statement here. Otherwise, we will encounter
problems. Linux currently assumes that CNTCTLBase.CNTACR<N> is
writeable, given a non-secure frame N. This is only the case if
CNTCTLBase.CNTSAR.NS<N> == 1.

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Rutland Jan. 31, 2017, 11:42 a.m. UTC | #8
On Mon, Jan 30, 2017 at 05:49:59PM +0000, Mark Rutland wrote:
> On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:

> > And because Linux kernel is running on Non-secure EL1, so should we
> > skip "SECURE" timer in Linux?
> 
> I guess you mean by checking the GTx Common flags, to see if the timer
> is secure? Yes, we must skip those.
> 
> Looking further at this, the ACPI spec is sorely lacking any statement
> as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's
> not clear if we can access anything in a frame, even if it is listed as
> being a non-secure timer.

Given CNTNSAR.NS<n> enables non-secure access to CNTACR<n>, I guess the
obvious interpretation is that for frames listed as non-secure, this has
been configured to permit non-secure access to the frame and associated
CNTACR<n>.

I will work to that assumption while reviewing, though I still believe
this needs to be clarified in the spec.

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
fu.wei@linaro.org Jan. 31, 2017, 6:43 p.m. UTC | #9
Hi Mark,

On 31 January 2017 at 01:49, Mark Rutland <mark.rutland@arm.com> wrote:
> On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
>> On 26 January 2017 at 01:25, Mark Rutland <mark.rutland@arm.com> wrote:
>> > On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
>> >> On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
>> >> > On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
>> >> >> From: Fu Wei <fu.wei@linaro.org>
>
>> > For CNT{,EL0}BaseN.CNTFRQ, I am very concerned by the wording in the
>> > current ARMv8 ARM ARM. This does not match my understanding, nor does it
>> > match the description in the ARMv7 ARM. I believe this may be a
>> > documentation error, and I'm chasing that up internally.
>> >
>> > Either the currently logic in the driver which attempts to read
>> > CNT{,EL0}BaseN.CNTFRQ is flawed, or the description in the ARM ARM is
>> > erroneous.
>>
>> Yes, those description did confuse me. :-(
>>
>> But according to another document(ARMv8-A Foundation Platform User
>> Guide  ARM DUI0677K),
>> Table 3-2 ARMv8-A Foundation Platform memory map (continued)
>>
>> AP_REFCLK CNTBase0, Generic Timer 64KB   S
>> AP_REFCLK CNTBase1, Generic Timer 64KB   S/NS
>>
>> Dose it means the timer frame 0 can be accessed in SECURE status  only,
>> and the timer frame 1 can be accessed in both status?
>
> That does appear to be what it says.
>
> I assume in this case CNTCTLBase.CNTSAR<0> is RES0.
>
>> And because Linux kernel is running on Non-secure EL1, so should we
>> skip "SECURE" timer in Linux?
>
> I guess you mean by checking the GTx Common flags, to see if the timer
> is secure? Yes, we must skip those.

Yes, exactly.

I think we can check the  GTx Common flags, if the timer is set as
SECURE, this driver should just skip this timer.

Reason:
1, IF the timer is designed to be a secure timer which is only can be
accessed in secure status, the ACPI table should label this as SECURE,
then driver should skip it.
2, IF the timer is accessible from both status, but the firmware want
to use this driver for secure OS,  the ACPI table should also label
this as SECURE(meanwhile firmware should configure CNTSAR too), then
driver should skip it, too.

Actually I have added this into my next patchset v21. If you don't
have other suggestion I can post it tomorrow.

Can I? any thought?

>
> Looking further at this, the ACPI spec is sorely lacking any statement
> as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's
> not clear if we can access anything in a frame, even if it is listed as
> being a non-secure timer.
>
> I think we need a stronger statement here. Otherwise, we will encounter
> problems. Linux currently assumes that CNTCTLBase.CNTACR<N> is
> writeable, given a non-secure frame N. This is only the case if
> CNTCTLBase.CNTSAR.NS<N> == 1.

the original driver has checked these registers, but the problem is:
What if the timer frame is designed to be a secure timer, all the
register in this frame is only can be accessed in secure status, just
like foundation model?
Note: for foundation model, Please check Table 3-1 Access permissions
of 3.1 ARMv8-A Foundation Platform memory map in ARMv8-A Foundation
Platform User Guide

So I think we should check the GTDT first, if it's not a secure timer,
then we can go on checking CNTSAR. :-)

Please correct me, If I miss something. :-)

Great thanks for your info :-)

>
> Thanks,
> Mark.
Mark Rutland Jan. 31, 2017, 6:49 p.m. UTC | #10
On Wed, Feb 01, 2017 at 02:43:02AM +0800, Fu Wei wrote:
> On 31 January 2017 at 01:49, Mark Rutland <mark.rutland@arm.com> wrote:
> > On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
> >> On 26 January 2017 at 01:25, Mark Rutland <mark.rutland@arm.com> wrote:
> >> > On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
> >> >> On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
> >> >> > On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
> >> >> >> From: Fu Wei <fu.wei@linaro.org>
> >
> >> But according to another document(ARMv8-A Foundation Platform User
> >> Guide  ARM DUI0677K),
> >> Table 3-2 ARMv8-A Foundation Platform memory map (continued)
> >>
> >> AP_REFCLK CNTBase0, Generic Timer 64KB   S
> >> AP_REFCLK CNTBase1, Generic Timer 64KB   S/NS
> >>
> >> Dose it means the timer frame 0 can be accessed in SECURE status  only,
> >> and the timer frame 1 can be accessed in both status?
> >
> > That does appear to be what it says.
> >
> > I assume in this case CNTCTLBase.CNTSAR<0> is RES0.
> >
> >> And because Linux kernel is running on Non-secure EL1, so should we
> >> skip "SECURE" timer in Linux?
> >
> > I guess you mean by checking the GTx Common flags, to see if the timer
> > is secure? Yes, we must skip those.
> 
> Yes, exactly.
> 
> I think we can check the  GTx Common flags, if the timer is set as
> SECURE, this driver should just skip this timer.

I completely agree that we must skip these.

> > Looking further at this, the ACPI spec is sorely lacking any statement
> > as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's
> > not clear if we can access anything in a frame, even if it is listed as
> > being a non-secure timer.
> >
> > I think we need a stronger statement here. Otherwise, we will encounter
> > problems. Linux currently assumes that CNTCTLBase.CNTACR<N> is
> > writeable, given a non-secure frame N. This is only the case if
> > CNTCTLBase.CNTSAR.NS<N> == 1.
> 
> the original driver has checked these registers, but the problem is:
> What if the timer frame is designed to be a secure timer, all the
> register in this frame is only can be accessed in secure status, just
> like foundation model?
> Note: for foundation model, Please check Table 3-1 Access permissions
> of 3.1 ARMv8-A Foundation Platform memory map in ARMv8-A Foundation
> Platform User Guide
> 
> So I think we should check the GTDT first, if it's not a secure timer,
> then we can go on checking CNTSAR. :-)

I've clearly confused matters here. I completely agree that we must skip
timers the GTDT descrbies as secure.

My complaint here is that the spec does not explicitly state that
CNTCTLBase.CNTSAR.NS<N> must be set for timers *not* marked as secure
(though I believe that is the intent). That is a spec issue, not a code
issue.

We unfortunately can't check CNTNSAR, as it is secure-only. :(

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
fu.wei@linaro.org Jan. 31, 2017, 7:07 p.m. UTC | #11
Hi Mark,

On 1 February 2017 at 02:49, Mark Rutland <mark.rutland@arm.com> wrote:
> On Wed, Feb 01, 2017 at 02:43:02AM +0800, Fu Wei wrote:
>> On 31 January 2017 at 01:49, Mark Rutland <mark.rutland@arm.com> wrote:
>> > On Thu, Jan 26, 2017 at 01:49:03PM +0800, Fu Wei wrote:
>> >> On 26 January 2017 at 01:25, Mark Rutland <mark.rutland@arm.com> wrote:
>> >> > On Wed, Jan 25, 2017 at 02:46:12PM +0800, Fu Wei wrote:
>> >> >> On 25 January 2017 at 01:24, Mark Rutland <mark.rutland@arm.com> wrote:
>> >> >> > On Wed, Jan 18, 2017 at 09:25:32PM +0800, fu.wei@linaro.org wrote:
>> >> >> >> From: Fu Wei <fu.wei@linaro.org>
>> >
>> >> But according to another document(ARMv8-A Foundation Platform User
>> >> Guide  ARM DUI0677K),
>> >> Table 3-2 ARMv8-A Foundation Platform memory map (continued)
>> >>
>> >> AP_REFCLK CNTBase0, Generic Timer 64KB   S
>> >> AP_REFCLK CNTBase1, Generic Timer 64KB   S/NS
>> >>
>> >> Dose it means the timer frame 0 can be accessed in SECURE status  only,
>> >> and the timer frame 1 can be accessed in both status?
>> >
>> > That does appear to be what it says.
>> >
>> > I assume in this case CNTCTLBase.CNTSAR<0> is RES0.
>> >
>> >> And because Linux kernel is running on Non-secure EL1, so should we
>> >> skip "SECURE" timer in Linux?
>> >
>> > I guess you mean by checking the GTx Common flags, to see if the timer
>> > is secure? Yes, we must skip those.
>>
>> Yes, exactly.
>>
>> I think we can check the  GTx Common flags, if the timer is set as
>> SECURE, this driver should just skip this timer.
>
> I completely agree that we must skip these.
>
>> > Looking further at this, the ACPI spec is sorely lacking any statement
>> > as to the configuration of CNTCTLBase.{CNTSAR,CNTTIDR,CNTACR}, so it's
>> > not clear if we can access anything in a frame, even if it is listed as
>> > being a non-secure timer.
>> >
>> > I think we need a stronger statement here. Otherwise, we will encounter
>> > problems. Linux currently assumes that CNTCTLBase.CNTACR<N> is
>> > writeable, given a non-secure frame N. This is only the case if
>> > CNTCTLBase.CNTSAR.NS<N> == 1.
>>
>> the original driver has checked these registers, but the problem is:
>> What if the timer frame is designed to be a secure timer, all the
>> register in this frame is only can be accessed in secure status, just
>> like foundation model?
>> Note: for foundation model, Please check Table 3-1 Access permissions
>> of 3.1 ARMv8-A Foundation Platform memory map in ARMv8-A Foundation
>> Platform User Guide
>>
>> So I think we should check the GTDT first, if it's not a secure timer,
>> then we can go on checking CNTSAR. :-)
>
> I've clearly confused matters here. I completely agree that we must skip
> timers the GTDT descrbies as secure.

Yes, got it :-)

>
> My complaint here is that the spec does not explicitly state that
> CNTCTLBase.CNTSAR.NS<N> must be set for timers *not* marked as secure
> (though I believe that is the intent). That is a spec issue, not a code
> issue.

agree :-)

>
> We unfortunately can't check CNTNSAR, as it is secure-only. :(

yes, the spec says:
In a system that implements both Secure and Non-secure states, this
register is only accessible by Secure accesses.

So I think the firmware(from vendor) can decide which timer frame
should be marked as secure according to the GTDT, then kernel just get
this info from GTDT instead of checking CNTNSAR.


>
> Thanks,
> Mark.
diff mbox

Patch

diff --git a/drivers/clocksource/arm_arch_timer.c
b/drivers/clocksource/arm_arch_timer.c
index 663a57a..eec92f6 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -65,7 +65,8 @@  struct arch_timer {

 #define to_arch_timer(e) container_of(e, struct arch_timer, evt)

-static u32 arch_timer_rate;
+static u32 arch_timer_sysreg_rate ;
+static u32 arch_timer_mmio_rate;
 static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];

 static struct clock_event_device __percpu *arch_timer_evt;