diff mbox

[3/9] arm: add call to CPU idle quirks handler

Message ID 1435094387-20146-4-git-send-email-pawelo@king.net.pl
State New
Headers show

Commit Message

Paul Osmialowski June 23, 2015, 9:19 p.m. UTC
Some SoCs need additional actions to be performed after arch idle,
e.g. Kinetis requires invalidation of the I/D bus cache.

Such handler could be held in provided <mach/idle.h> header file.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig          | 7 +++++++
 arch/arm/kernel/process.c | 7 +++++++
 2 files changed, 14 insertions(+)

Comments

Arnd Bergmann June 23, 2015, 9:59 p.m. UTC | #1
On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
> Some SoCs need additional actions to be performed after arch idle,
> e.g. Kinetis requires invalidation of the I/D bus cache.
> 
> Such handler could be held in provided <mach/idle.h> header file.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  arch/arm/Kconfig          | 7 +++++++
>  arch/arm/kernel/process.c | 7 +++++++
>  2 files changed, 14 insertions(+)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 8e3a833..8ef8f8f 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
>  config NEED_SG_DMA_LENGTH
>  	bool
>  
> +config NEED_MACH_IDLE_H
> +	bool
> +
> +config ARM_CPU_IDLE_QUIRKS
> +	bool
> +	select NEED_MACH_IDLE_H
> +

We're not adding header files like this, please come up
with another solution. How about a cpuidle driver, or
possibly just overriding arm_pm_idle()?


	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nicolas Pitre June 25, 2015, 4:42 p.m. UTC | #2
On Tue, 23 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
> > Some SoCs need additional actions to be performed after arch idle,
> > e.g. Kinetis requires invalidation of the I/D bus cache.
> > 
> > Such handler could be held in provided <mach/idle.h> header file.
> > 
> > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> > ---
> >  arch/arm/Kconfig          | 7 +++++++
> >  arch/arm/kernel/process.c | 7 +++++++
> >  2 files changed, 14 insertions(+)
> > 
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 8e3a833..8ef8f8f 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
> >  config NEED_SG_DMA_LENGTH
> >  	bool
> >  
> > +config NEED_MACH_IDLE_H
> > +	bool
> > +
> > +config ARM_CPU_IDLE_QUIRKS
> > +	bool
> > +	select NEED_MACH_IDLE_H
> > +
> 
> We're not adding header files like this, please come up
> with another solution. How about a cpuidle driver, or
> possibly just overriding arm_pm_idle()?

If the WFI instruction always requires I and D flushing, then it might 
be a better idea to provide a replacement for the corresponding 
cpu_*_do_idle function.  Plenty of examples exist for other cpu_* 
functions.


Nicolas
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paul Osmialowski June 26, 2015, 5:30 a.m. UTC | #3
Hi Nicolas,

Thanks for your proposal, however, I have some trouble with it.

That would look lovely:

#include <linux/linkage.h>
#include <asm/assembler.h>

/*
  *      cpu_kinetis_do_idle()
  *
  *      Idle the processor (wait for interrupt).
  *
  *      IRQs are already disabled.
  */
ENTRY(cpu_kinetis_do_idle)
         wfi
         movw    r3, #:lower16:0xe0082000
         movt    r3, #:upper16:0xe0082000
         ldr     r0, [r3, #0]
         orr     r2, r0, #0x85000000
         str     r2, [r3, #0]
         ret     lr
ENDPROC(cpu_kinetis_do_idle)

But... what about the rest of this hypothetical proc_kinetis.S file?

It would be a lot of code duplication with proc-v7m.S I think.

I could define CPU_KINETIS as such:

config CPU_KINETIS
 	bool
 	select CPU_V7M

But there's no such thing like customize_processor_functions that would be 
called after proc-v7m.S define_processor_functions specified things like 
idle routine.

Finally, while I was searching for suitable arm_pm_idle-based solution, I 
found idle.c in mach-gemini that encouraged me to write my own idle.c for 
Kinetis:

/*
  * arch/arm/mach-kinetis/idle.c
  */

#include <linux/init.h>
#include <linux/io.h>
#include <asm/system_misc.h>
#include <asm/proc-fns.h>

static void kinetis_idle(void)
{
         asm volatile ("wfi");

         /*
          * This is a dirty hack that invalidates the I/D bus cache
          * on Kinetis K70. This must be done after idle.
          */
         writel(readl(IOMEM(0xe0082000)) | 0x85000000, IOMEM(0xe0082000));
}

static int __init kinetis_idle_init(void)
{
         arm_pm_idle = kinetis_idle;
         return 0;
}

arch_initcall(kinetis_idle_init);

Et voila:

(gdb) c
Continuing.
^C
Program received signal SIGTRAP, Trace/breakpoint trap.
kinetis_idle () at ../arch/arm/mach-kinetis/idle.c:18
18		writel(readl(IOMEM(0xe0082000)) | 0x85000000, 
IOMEM(0xe0082000));
(gdb) bt
#0  kinetis_idle () at ../arch/arm/mach-kinetis/idle.c:18
#1  0x0800a91e in arch_cpu_idle () at ../arch/arm/kernel/process.c:70
#2  0x08025402 in cpuidle_idle_call (state=<value optimized out>)
     at ../kernel/sched/idle.c:157
#3  cpu_idle_loop (state=<value optimized out>) at 
../kernel/sched/idle.c:253
#4  cpu_startup_entry (state=<value optimized out>) at 
../kernel/sched/idle.c:301
#5  0x081bf816 in start_kernel () at ../init/main.c:683
#6  0x08008024 in stext () at ../arch/arm/kernel/head-nommu.S:85
(gdb)

On Thu, 25 Jun 2015, Nicolas Pitre wrote:

> On Tue, 23 Jun 2015, Arnd Bergmann wrote:
>
>> On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
>>> Some SoCs need additional actions to be performed after arch idle,
>>> e.g. Kinetis requires invalidation of the I/D bus cache.
>>>
>>> Such handler could be held in provided <mach/idle.h> header file.
>>>
>>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>>> ---
>>>  arch/arm/Kconfig          | 7 +++++++
>>>  arch/arm/kernel/process.c | 7 +++++++
>>>  2 files changed, 14 insertions(+)
>>>
>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>>> index 8e3a833..8ef8f8f 100644
>>> --- a/arch/arm/Kconfig
>>> +++ b/arch/arm/Kconfig
>>> @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
>>>  config NEED_SG_DMA_LENGTH
>>>  	bool
>>>
>>> +config NEED_MACH_IDLE_H
>>> +	bool
>>> +
>>> +config ARM_CPU_IDLE_QUIRKS
>>> +	bool
>>> +	select NEED_MACH_IDLE_H
>>> +
>>
>> We're not adding header files like this, please come up
>> with another solution. How about a cpuidle driver, or
>> possibly just overriding arm_pm_idle()?
>
> If the WFI instruction always requires I and D flushing, then it might
> be a better idea to provide a replacement for the corresponding
> cpu_*_do_idle function.  Plenty of examples exist for other cpu_*
> functions.
>
>
> Nicolas
>
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Arnd Bergmann June 26, 2015, 7:40 a.m. UTC | #4
On Friday 26 June 2015 07:30:49 Paul Osmialowski wrote:
> ENDPROC(cpu_kinetis_do_idle)
> 
> But... what about the rest of this hypothetical proc_kinetis.S file?
> 
> It would be a lot of code duplication with proc-v7m.S I think.
> 

I doubt that the Kinetis has a custom version of the CPU core. Are you
sure that not all Cortex-M4 need this?

As long as the idle implementation depends only on the CPU core type,
it's easy to just define multiple .proc.info.init entries in the
same file, like we do in proc-v7.S.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8e3a833..8ef8f8f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -98,6 +98,13 @@  config ARM_HAS_SG_CHAIN
 config NEED_SG_DMA_LENGTH
 	bool
 
+config NEED_MACH_IDLE_H
+	bool
+
+config ARM_CPU_IDLE_QUIRKS
+	bool
+	select NEED_MACH_IDLE_H
+
 config ARM_DMA_USE_IOMMU
 	bool
 	select ARM_HAS_SG_CHAIN
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index f192a2a..0033460 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -37,6 +37,10 @@ 
 #include <asm/tls.h>
 #include <asm/vdso.h>
 
+#ifdef CONFIG_NEED_MACH_IDLE_H
+#include <mach/idle.h>
+#endif
+
 #ifdef CONFIG_CC_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
@@ -70,6 +74,9 @@  void arch_cpu_idle(void)
 		arm_pm_idle();
 	else
 		cpu_do_idle();
+#ifdef CONFIG_ARM_CPU_IDLE_QUIRKS
+	handle_cpu_idle_quirks();
+#endif
 	local_irq_enable();
 }