[PATCH v2 1/2] powerpc/timer - large decrementer support

oliver oohall at gmail.com
Mon May 9 19:01:26 AEST 2016


On Mon, May 9, 2016 at 4:28 PM, Balbir Singh <bsingharora at gmail.com> wrote:
>
>
> On 04/05/16 17:37, Oliver O'Halloran wrote:
>> POWER ISA v3 adds large decrementer (LD) mode of operation which increases
>> the size of the decrementer register from 32 bits to an implementation
>> defined with of up to 64 bits.
>>
>> This patch adds support for the LD on processors with the CPU_FTR_ARCH_300
>> cpu feature flag set. Even for CPUs with this feature LD mode is only
>> enabled when the property ibm,dec-bits devicetree property is supplied
>> for the boot CPU. The decrementer value is a signed quantity (with
>> negative values indicating a pending exception) and this property is
>> required to find the maximum positive decrementer value. If this property
>> is not supplied then the traditional decrementer width of 32 bits is
>> assumed and LD mode is disabled.
>>
>> This patch was based on initial work by Jack Miller.
>>
>> Signed-off-by: Oliver O'Halloran <oohall at gmail.com>
>> Cc: Jack Miller <jack at codezen.org>
>> Cc: Balbir Singh <bsingharora at gmail.com>
>> ---
>>  arch/powerpc/include/asm/reg.h  |  1 +
>>  arch/powerpc/include/asm/time.h |  6 +--
>>  arch/powerpc/kernel/time.c      | 89 +++++++++++++++++++++++++++++++++++++----
>>  3 files changed, 86 insertions(+), 10 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
>> index f5f4c66bbbc9..ff581ed1ab9d 100644
>> --- a/arch/powerpc/include/asm/reg.h
>> +++ b/arch/powerpc/include/asm/reg.h
>> @@ -332,6 +332,7 @@
>>  #define   LPCR_AIL_0 0x00000000      /* MMU off exception offset 0x0 */
>>  #define   LPCR_AIL_3 0x01800000      /* MMU on exception offset 0xc00...4xxx */
>>  #define   LPCR_ONL   0x00040000      /* online - PURR/SPURR count */
>> +#define   LPCR_LD    0x00020000      /* large decremeter */
>>  #define   LPCR_PECE  0x0001f000      /* powersave exit cause enable */
>>  #define     LPCR_PECEDP      0x00010000      /* directed priv dbells cause exit */
>>  #define     LPCR_PECEDH      0x00008000      /* directed hyp dbells cause exit */
>> diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
>> index 1092fdd7e737..09211640a0e0 100644
>> --- a/arch/powerpc/include/asm/time.h
>> +++ b/arch/powerpc/include/asm/time.h
>> @@ -146,7 +146,7 @@ static inline void set_tb(unsigned int upper, unsigned int lower)
>>   * in auto-reload mode.  The problem is PIT stops counting when it
>>   * hits zero.  If it would wrap, we could use it just like a decrementer.
>>   */
>> -static inline unsigned int get_dec(void)
>> +static inline u64 get_dec(void)
>>  {
>>  #if defined(CONFIG_40x)
>>       return (mfspr(SPRN_PIT));
>> @@ -160,10 +160,10 @@ static inline unsigned int get_dec(void)
>>   * in when the decrementer generates its interrupt: on the 1 to 0
>>   * transition for Book E/4xx, but on the 0 to -1 transition for others.
>>   */
>> -static inline void set_dec(int val)
>> +static inline void set_dec(u64 val)
>>  {
>>  #if defined(CONFIG_40x)
>> -     mtspr(SPRN_PIT, val);
>> +     mtspr(SPRN_PIT, (u32) val);
>>  #else
>>  #ifndef CONFIG_BOOKE
>>       --val;
>> diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
>> index 81b0900a39ee..fab34abfb4cd 100644
>> --- a/arch/powerpc/kernel/time.c
>> +++ b/arch/powerpc/kernel/time.c
>> @@ -95,7 +95,8 @@ static struct clocksource clocksource_timebase = {
>>       .read         = timebase_read,
>>  };
>>
>> -#define DECREMENTER_MAX      0x7fffffff
>> +#define DECREMENTER_DEFAULT_MAX 0x7FFFFFFF
>> +u64 decrementer_max = DECREMENTER_DEFAULT_MAX;
>
> Should this be signed, given that the decrementer is signed?

Maybe, but there's no particular reason to prefer signed since we (almost)
never look at the decrementer value directly. I used u64 since the value to
be loaded into the decrementer is calculated using a u64 and the explicit
cast to int when calling set_dec() in __timer_interrupt() was the only place I
could find where an int was expected.

>> +static inline bool large_dec_supp(void)
>> +{
>> +     return cpu_has_feature(CPU_FTR_ARCH_300);
>> +}
>> +
>
> Can we rename this to is_large_dec()?

Honestly, I don't like either. How about have_large_dec() ?

>> +/* enables the large decrementer for the current CPU */
>> +static void enable_large_decrementer(void)
>> +{
>> +     /* do we have a large decrementer? */
>> +     if (!large_dec_supp())
>> +             return;
>> +
>> +     /* do we need a large decrementer? */
>> +     if (decrementer_max <= DECREMENTER_DEFAULT_MAX)
>> +             return;
>> +
>> +     mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_LD);
>> +
>> +     if (!large_dec_on()) {
>> +             decrementer_max = DECREMENTER_DEFAULT_MAX;
>> +
>> +             pr_warn("time_init: Failed to enable LD mode on CPU %d\n",
>
> I think stating "Failed to enable Large Decrementer" might be easier to understand in the logs

You're right, I was just trying to keep it under 80 cols :)

>
>> +                     smp_processor_id());
>> +     }
>> +}
>> +
>> +static void __init set_decrementer_max(void)
>> +{
>> +     struct device_node *cpu;
>> +     const __be32 *fp;
>> +     u64 bits = 32;
>> +
>> +     /* dt node exists? */
>> +     cpu = of_find_node_by_type(NULL, "cpu");
>> +     if (cpu)
>> +             fp = of_get_property(cpu, "ibm,dec-bits", NULL);
>> +
>> +     if (cpu && fp) {
>> +             bits = of_read_number(fp, 1);
>> +
>> +             /* clamp to sane values */
>> +             if (bits > 64)
>> +                     bits = 64;
>> +             if (bits < 32)
>> +                     bits = 32;
>> +
>
> Shouldn't we warn about a firmware bug if we wrap the bits for > 64 or < 32?

Good idea.


More information about the Linuxppc-dev mailing list