mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 19:07:52 +00:00
[AVR32] Put cpu in sleep 0 when idle.
This patch puts the CPU in sleep 0 when doing nothing, idle. This will turn of the CPU clock and thus save power. The CPU is waken again when an interrupt occurs. Signed-off-by: Hans-Christian Egtvedt <hcegtvedt@atmel.com> Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
This commit is contained in:
parent
7760989e5e
commit
19b7ce8bad
3 changed files with 42 additions and 7 deletions
|
@ -630,9 +630,12 @@ irq_level\level:
|
||||||
rcall do_IRQ
|
rcall do_IRQ
|
||||||
|
|
||||||
lddsp r4, sp[REG_SR]
|
lddsp r4, sp[REG_SR]
|
||||||
andh r4, (MODE_MASK >> 16), COH
|
bfextu r4, r4, SYSREG_M0_OFFSET, 3
|
||||||
|
cp.w r4, MODE_SUPERVISOR >> SYSREG_M0_OFFSET
|
||||||
|
breq 2f
|
||||||
|
cp.w r4, MODE_USER >> SYSREG_M0_OFFSET
|
||||||
#ifdef CONFIG_PREEMPT
|
#ifdef CONFIG_PREEMPT
|
||||||
brne 2f
|
brne 3f
|
||||||
#else
|
#else
|
||||||
brne 1f
|
brne 1f
|
||||||
#endif
|
#endif
|
||||||
|
@ -649,9 +652,18 @@ irq_level\level:
|
||||||
sub sp, -4 /* ignore r12_orig */
|
sub sp, -4 /* ignore r12_orig */
|
||||||
rete
|
rete
|
||||||
|
|
||||||
|
2: get_thread_info r0
|
||||||
|
ld.w r1, r0[TI_flags]
|
||||||
|
bld r1, TIF_CPU_GOING_TO_SLEEP
|
||||||
#ifdef CONFIG_PREEMPT
|
#ifdef CONFIG_PREEMPT
|
||||||
2:
|
brcc 3f
|
||||||
get_thread_info r0
|
#else
|
||||||
|
brcc 1b
|
||||||
|
#endif
|
||||||
|
sub r1, pc, . - cpu_idle_skip_sleep
|
||||||
|
stdsp sp[REG_PC], r1
|
||||||
|
#ifdef CONFIG_PREEMPT
|
||||||
|
3: get_thread_info r0
|
||||||
ld.w r2, r0[TI_preempt_count]
|
ld.w r2, r0[TI_preempt_count]
|
||||||
cp.w r2, 0
|
cp.w r2, 0
|
||||||
brne 1b
|
brne 1b
|
||||||
|
@ -662,12 +674,32 @@ irq_level\level:
|
||||||
bld r4, SYSREG_GM_OFFSET
|
bld r4, SYSREG_GM_OFFSET
|
||||||
brcs 1b
|
brcs 1b
|
||||||
rcall preempt_schedule_irq
|
rcall preempt_schedule_irq
|
||||||
rjmp 1b
|
|
||||||
#endif
|
#endif
|
||||||
|
rjmp 1b
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.section .irq.text,"ax",@progbits
|
.section .irq.text,"ax",@progbits
|
||||||
|
|
||||||
|
.global cpu_idle_sleep
|
||||||
|
cpu_idle_sleep:
|
||||||
|
mask_interrupts
|
||||||
|
get_thread_info r8
|
||||||
|
ld.w r9, r8[TI_flags]
|
||||||
|
bld r9, TIF_NEED_RESCHED
|
||||||
|
brcs cpu_idle_enable_int_and_exit
|
||||||
|
sbr r9, TIF_CPU_GOING_TO_SLEEP
|
||||||
|
st.w r8[TI_flags], r9
|
||||||
|
unmask_interrupts
|
||||||
|
sleep 0
|
||||||
|
cpu_idle_skip_sleep:
|
||||||
|
mask_interrupts
|
||||||
|
ld.w r9, r8[TI_flags]
|
||||||
|
cbr r9, TIF_CPU_GOING_TO_SLEEP
|
||||||
|
st.w r8[TI_flags], r9
|
||||||
|
cpu_idle_enable_int_and_exit:
|
||||||
|
unmask_interrupts
|
||||||
|
retal r12
|
||||||
|
|
||||||
.global irq_level0
|
.global irq_level0
|
||||||
.global irq_level1
|
.global irq_level1
|
||||||
.global irq_level2
|
.global irq_level2
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
void (*pm_power_off)(void) = NULL;
|
void (*pm_power_off)(void) = NULL;
|
||||||
EXPORT_SYMBOL(pm_power_off);
|
EXPORT_SYMBOL(pm_power_off);
|
||||||
|
|
||||||
|
extern void cpu_idle_sleep(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file handles the architecture-dependent parts of process handling..
|
* This file handles the architecture-dependent parts of process handling..
|
||||||
*/
|
*/
|
||||||
|
@ -27,9 +29,8 @@ void cpu_idle(void)
|
||||||
{
|
{
|
||||||
/* endless idle loop with no priority at all */
|
/* endless idle loop with no priority at all */
|
||||||
while (1) {
|
while (1) {
|
||||||
/* TODO: Enter sleep mode */
|
|
||||||
while (!need_resched())
|
while (!need_resched())
|
||||||
cpu_relax();
|
cpu_idle_sleep();
|
||||||
preempt_enable_no_resched();
|
preempt_enable_no_resched();
|
||||||
schedule();
|
schedule();
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
|
|
|
@ -83,6 +83,7 @@ static inline struct thread_info *current_thread_info(void)
|
||||||
#define TIF_SINGLE_STEP 6 /* single step after next break */
|
#define TIF_SINGLE_STEP 6 /* single step after next break */
|
||||||
#define TIF_MEMDIE 7
|
#define TIF_MEMDIE 7
|
||||||
#define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal */
|
#define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal */
|
||||||
|
#define TIF_CPU_GOING_TO_SLEEP 9 /* CPU is entering sleep 0 mode */
|
||||||
#define TIF_USERSPACE 31 /* true if FS sets userspace */
|
#define TIF_USERSPACE 31 /* true if FS sets userspace */
|
||||||
|
|
||||||
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
|
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
|
||||||
|
@ -94,6 +95,7 @@ static inline struct thread_info *current_thread_info(void)
|
||||||
#define _TIF_SINGLE_STEP (1 << TIF_SINGLE_STEP)
|
#define _TIF_SINGLE_STEP (1 << TIF_SINGLE_STEP)
|
||||||
#define _TIF_MEMDIE (1 << TIF_MEMDIE)
|
#define _TIF_MEMDIE (1 << TIF_MEMDIE)
|
||||||
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
|
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
|
||||||
|
#define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP)
|
||||||
|
|
||||||
/* XXX: These two masks must never span more than 16 bits! */
|
/* XXX: These two masks must never span more than 16 bits! */
|
||||||
/* work to do on interrupt/exception return */
|
/* work to do on interrupt/exception return */
|
||||||
|
|
Loading…
Reference in a new issue