Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 302eca18 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Paul Mackerras
Browse files

[POWERPC] cell: use ppc_md->power_save instead of cbe_idle_loop



This moves the cell idle function to use the default cpu_idle
with a special power_save callback, like all other platforms
except iSeries already do.

It also makes it possible to disable this power_save function
with a new powerpc-specific boot option "powersave=off".

Signed-off-by: default avatarArnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent b3d7dc19
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -39,6 +39,13 @@
#define cpu_should_die()	0
#endif

static int __init powersave_off(char *arg)
{
	ppc_md.power_save = NULL;
	return 0;
}
__setup("powersave=off", powersave_off);

/*
 * The body of the idle task.
 */
+27 −69
Original line number Diff line number Diff line
@@ -38,32 +38,16 @@
#include "pervasive.h"
#include "cbe_regs.h"

static DEFINE_SPINLOCK(cbe_pervasive_lock);

static void __init cbe_enable_pause_zero(void)
static void cbe_power_save(void)
{
	unsigned long thread_switch_control;
	unsigned long temp_register;
	struct cbe_pmd_regs __iomem *pregs;

	spin_lock_irq(&cbe_pervasive_lock);
	pregs = cbe_get_cpu_pmd_regs(smp_processor_id());
	if (pregs == NULL)
		goto out;

	pr_debug("Power Management: CPU %d\n", smp_processor_id());

	 /* Enable Pause(0) control bit */
	temp_register = in_be64(&pregs->pmcr);

	out_be64(&pregs->pmcr,
		 temp_register | CBE_PMD_PAUSE_ZERO_CONTROL);
	unsigned long ctrl, thread_switch_control;
	ctrl = mfspr(SPRN_CTRLF);

	/* Enable DEC and EE interrupt request */
	thread_switch_control  = mfspr(SPRN_TSC_CELL);
	thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;

	switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
	switch (ctrl & CTRL_CT) {
	case CTRL_CT0:
		thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
		break;
@@ -75,59 +59,22 @@ static void __init cbe_enable_pause_zero(void)
			__FUNCTION__);
		break;
	}

	mtspr(SPRN_TSC_CELL, thread_switch_control);

out:
	spin_unlock_irq(&cbe_pervasive_lock);
}

static void cbe_idle(void)
{
	unsigned long ctrl;

	/* Why do we do that on every idle ? Couldn't that be done once for
	 * all or do we lose the state some way ? Also, the pmcr
	 * register setting, that can't be set once at boot ? We really want
	 * to move that away in order to implement a simple powersave
	/*
	 * go into low thread priority, medium priority will be
	 * restored for us after wake-up.
	 */
	cbe_enable_pause_zero();

	while (1) {
		if (!need_resched()) {
			local_irq_disable();
			while (!need_resched()) {
				/* go into low thread priority */
	HMT_low();

	/*
				 * atomically disable thread execution
				 * and runlatch.
				 * External and Decrementer exceptions
				 * are still handled when the thread
				 * is disabled but now enter in
				 * cbe_system_reset_exception()
	 * atomically disable thread execution and runlatch.
	 * External and Decrementer exceptions are still handled when the
	 * thread is disabled but now enter in cbe_system_reset_exception()
	 */
				ctrl = mfspr(SPRN_CTRLF);
	ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
	mtspr(SPRN_CTRLT, ctrl);
}
			/* restore thread prio */
			HMT_medium();
			local_irq_enable();
		}

		/*
		 * turn runlatch on again before scheduling the
		 * process we just woke up
		 */
		ppc64_runlatch_on();

		preempt_enable_no_resched();
		schedule();
		preempt_disable();
	}
}

static int cbe_system_reset_exception(struct pt_regs *regs)
{
@@ -158,9 +105,20 @@ static int cbe_system_reset_exception(struct pt_regs *regs)

void __init cbe_pervasive_init(void)
{
	int cpu;
	if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
		return;

	ppc_md.idle_loop = cbe_idle;
	for_each_possible_cpu(cpu) {
		struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu);
		if (!regs)
			continue;

		 /* Enable Pause(0) control bit */
		out_be64(&regs->pmcr, in_be64(&regs->pmcr) |
					    CBE_PMD_PAUSE_ZERO_CONTROL);
	}

	ppc_md.power_save = cbe_power_save;
	ppc_md.system_reset_exception = cbe_system_reset_exception;
}