Skip to content

Commit

Permalink
Merge branch 'powernv-cpuidle' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/benh/powerpc

Pull powerpc non-virtualized cpuidle from Ben Herrenschmidt:
 "This is the branch I mentioned in my other pull request which contains
  our improved cpuidle support for the "powernv" platform
  (non-virtualized).

  It adds support for the "fast sleep" feature of the processor which
  provides higher power savings than our usual "nap" mode but at the
  cost of losing the timers while asleep, and thus exploits the new
  timer broadcast framework to work around that limitation.

  It's based on a tip timer tree that you seem to have already merged"

* 'powernv-cpuidle' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  cpuidle/powernv: Parse device tree to setup idle states
  cpuidle/powernv: Add "Fast-Sleep" CPU idle state
  powerpc/powernv: Add OPAL call to resync timebase on wakeup
  powerpc/powernv: Add context management for Fast Sleep
  powerpc: Split timer_interrupt() into timer handling and interrupt handling routines
  powerpc: Implement tick broadcast IPI as a fixed IPI message
  powerpc: Free up the slot of PPC_MSG_CALL_FUNC_SINGLE IPI message
  • Loading branch information
Linus Torvalds committed Apr 2, 2014
2 parents 235c7b9 + 0888839 commit e6d9bfc
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 77 deletions.
2 changes: 2 additions & 0 deletions arch/powerpc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ config PPC
select GENERIC_CMOS_UPDATE
select GENERIC_TIME_VSYSCALL_OLD
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select HAVE_MOD_ARCH_SPECIFIC
Expand Down
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/opal.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_FLASH_VALIDATE 76
#define OPAL_FLASH_MANAGE 77
#define OPAL_FLASH_UPDATE 78
#define OPAL_RESYNC_TIMEBASE 79
#define OPAL_DUMP_INIT 81
#define OPAL_DUMP_INFO 82
#define OPAL_DUMP_READ 83
Expand Down Expand Up @@ -923,6 +924,7 @@ extern int opal_machine_check(struct pt_regs *regs);
extern bool opal_mce_check_early_recovery(struct pt_regs *regs);

extern void opal_shutdown(void);
extern int opal_resync_timebase(void);

extern void opal_lpc_init(void);

Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};

extern int powersave_nap; /* set if nap mode can be used in idle loop */
extern void power7_nap(void);
extern void power7_sleep(void);
extern void flush_instruction_cache(void);
extern void hard_reset_now(void);
extern void poweroff_now(void);
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ extern int cpu_to_core_id(int cpu);
* in /proc/interrupts will be wrong!!! --Troy */
#define PPC_MSG_CALL_FUNCTION 0
#define PPC_MSG_RESCHEDULE 1
#define PPC_MSG_CALL_FUNC_SINGLE 2
#define PPC_MSG_TICK_BROADCAST 2
#define PPC_MSG_DEBUGGER_BREAK 3

/* for irq controllers that have dedicated ipis per message (4) */
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/include/asm/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extern struct clock_event_device decrementer_clockevent;
struct rtc_time;
extern void to_tm(int tim, struct rtc_time * tm);
extern void GregorianDay(struct rtc_time *tm);
extern void tick_broadcast_ipi_handler(void);

extern void generic_calibrate_decr(void);

Expand Down
10 changes: 8 additions & 2 deletions arch/powerpc/kernel/exceptions-64s.S
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,10 @@ BEGIN_FTR_SECTION
cmpwi cr1,r13,2
/* Total loss of HV state is fatal, we could try to use the
* PIR to locate a PACA, then use an emergency stack etc...
* but for now, let's just stay stuck here
* OPAL v3 based powernv platforms have new idle states
* which fall in this catagory.
*/
bgt cr1,.
bgt cr1,8f
GET_PACA(r13)

#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
Expand All @@ -141,6 +142,11 @@ BEGIN_FTR_SECTION
beq cr1,2f
b .power7_wakeup_noloss
2: b .power7_wakeup_loss

/* Fast Sleep wakeup on PowerNV */
8: GET_PACA(r13)
b .power7_wakeup_tb_loss

9:
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
#endif /* CONFIG_PPC_P7_NAP */
Expand Down
90 changes: 71 additions & 19 deletions arch/powerpc/kernel/idle_power7.S
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,31 @@
#include <asm/ppc-opcode.h>
#include <asm/hw_irq.h>
#include <asm/kvm_book3s_asm.h>
#include <asm/opal.h>

#undef DEBUG

.text
/* Idle state entry routines */

_GLOBAL(power7_idle)
/* Now check if user or arch enabled NAP mode */
LOAD_REG_ADDRBASE(r3,powersave_nap)
lwz r4,ADDROFF(powersave_nap)(r3)
cmpwi 0,r4,0
beqlr
/* fall through */
#define IDLE_STATE_ENTER_SEQ(IDLE_INST) \
/* Magic NAP/SLEEP/WINKLE mode enter sequence */ \
std r0,0(r1); \
ptesync; \
ld r0,0(r1); \
1: cmp cr0,r0,r0; \
bne 1b; \
IDLE_INST; \
b .

_GLOBAL(power7_nap)
.text

/*
* Pass requested state in r3:
* 0 - nap
* 1 - sleep
*/
_GLOBAL(power7_powersave_common)
/* Use r3 to pass state nap/sleep/winkle */
/* NAP is a state loss, we create a regs frame on the
* stack, fill it up with the state we care about and
* stick a pointer to it in PACAR1. We really only
Expand Down Expand Up @@ -79,8 +90,8 @@ _GLOBAL(power7_nap)
/* Continue saving state */
SAVE_GPR(2, r1)
SAVE_NVGPRS(r1)
mfcr r3
std r3,_CCR(r1)
mfcr r4
std r4,_CCR(r1)
std r9,_MSR(r1)
std r1,PACAR1(r13)

Expand All @@ -90,15 +101,56 @@ _GLOBAL(power7_enter_nap_mode)
li r4,KVM_HWTHREAD_IN_NAP
stb r4,HSTATE_HWTHREAD_STATE(r13)
#endif
cmpwi cr0,r3,1
beq 2f
IDLE_STATE_ENTER_SEQ(PPC_NAP)
/* No return */
2: IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
/* No return */

/* Magic NAP mode enter sequence */
std r0,0(r1)
ptesync
ld r0,0(r1)
1: cmp cr0,r0,r0
bne 1b
PPC_NAP
b .
_GLOBAL(power7_idle)
/* Now check if user or arch enabled NAP mode */
LOAD_REG_ADDRBASE(r3,powersave_nap)
lwz r4,ADDROFF(powersave_nap)(r3)
cmpwi 0,r4,0
beqlr
/* fall through */

_GLOBAL(power7_nap)
li r3,0
b power7_powersave_common
/* No return */

_GLOBAL(power7_sleep)
li r3,1
b power7_powersave_common
/* No return */

_GLOBAL(power7_wakeup_tb_loss)
ld r2,PACATOC(r13);
ld r1,PACAR1(r13)

/* Time base re-sync */
li r0,OPAL_RESYNC_TIMEBASE
LOAD_REG_ADDR(r11,opal);
ld r12,8(r11);
ld r2,0(r11);
mtctr r12
bctrl

/* TODO: Check r3 for failure */

REST_NVGPRS(r1)
REST_GPR(2, r1)
ld r3,_CCR(r1)
ld r4,_MSR(r1)
ld r5,_NIP(r1)
addi r1,r1,INT_FRAME_SIZE
mtcr r3
mfspr r3,SPRN_SRR1 /* Return SRR1 */
mtspr SPRN_SRR1,r4
mtspr SPRN_SRR0,r5
rfid

_GLOBAL(power7_wakeup_loss)
ld r1,PACAR1(r13)
Expand Down
25 changes: 18 additions & 7 deletions arch/powerpc/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <asm/ptrace.h>
#include <linux/atomic.h>
#include <asm/irq.h>
#include <asm/hw_irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
Expand Down Expand Up @@ -145,9 +146,9 @@ static irqreturn_t reschedule_action(int irq, void *data)
return IRQ_HANDLED;
}

static irqreturn_t call_function_single_action(int irq, void *data)
static irqreturn_t tick_broadcast_ipi_action(int irq, void *data)
{
generic_smp_call_function_single_interrupt();
tick_broadcast_ipi_handler();
return IRQ_HANDLED;
}

Expand All @@ -168,14 +169,14 @@ static irqreturn_t debug_ipi_action(int irq, void *data)
static irq_handler_t smp_ipi_action[] = {
[PPC_MSG_CALL_FUNCTION] = call_function_action,
[PPC_MSG_RESCHEDULE] = reschedule_action,
[PPC_MSG_CALL_FUNC_SINGLE] = call_function_single_action,
[PPC_MSG_TICK_BROADCAST] = tick_broadcast_ipi_action,
[PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action,
};

const char *smp_ipi_name[] = {
[PPC_MSG_CALL_FUNCTION] = "ipi call function",
[PPC_MSG_RESCHEDULE] = "ipi reschedule",
[PPC_MSG_CALL_FUNC_SINGLE] = "ipi call function single",
[PPC_MSG_TICK_BROADCAST] = "ipi tick-broadcast",
[PPC_MSG_DEBUGGER_BREAK] = "ipi debugger",
};

Expand Down Expand Up @@ -251,8 +252,8 @@ irqreturn_t smp_ipi_demux(void)
generic_smp_call_function_interrupt();
if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE))
scheduler_ipi();
if (all & IPI_MESSAGE(PPC_MSG_CALL_FUNC_SINGLE))
generic_smp_call_function_single_interrupt();
if (all & IPI_MESSAGE(PPC_MSG_TICK_BROADCAST))
tick_broadcast_ipi_handler();
if (all & IPI_MESSAGE(PPC_MSG_DEBUGGER_BREAK))
debug_ipi_action(0, NULL);
} while (info->messages);
Expand Down Expand Up @@ -280,7 +281,7 @@ EXPORT_SYMBOL_GPL(smp_send_reschedule);

void arch_send_call_function_single_ipi(int cpu)
{
do_message_pass(cpu, PPC_MSG_CALL_FUNC_SINGLE);
do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}

void arch_send_call_function_ipi_mask(const struct cpumask *mask)
Expand All @@ -291,6 +292,16 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}

#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
void tick_broadcast(const struct cpumask *mask)
{
unsigned int cpu;

for_each_cpu(cpu, mask)
do_message_pass(cpu, PPC_MSG_TICK_BROADCAST);
}
#endif

#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
void smp_send_debugger_break(void)
{
Expand Down
Loading

0 comments on commit e6d9bfc

Please sign in to comment.