[POWERPC] PS3: Save power in busy loops on halt
authorGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Thu, 27 Mar 2008 00:38:31 +0000 (11:38 +1100)
committerPaul Mackerras <paulus@samba.org>
Tue, 1 Apr 2008 09:43:07 +0000 (20:43 +1100)
PS3 save power on halt:
  - Replace infinite busy loops by smarter loops calling
    lv1_pause() to save power.
  - Add ps3_halt() and ps3_sys_manager_halt().
  - Add __noreturn annotations.

Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/ps3/setup.c
drivers/ps3/ps3-sys-manager.c
drivers/ps3/sys-manager-core.c
include/asm-powerpc/ps3.h

index 5c2cbb0..c144669 100644 (file)
@@ -95,6 +95,14 @@ static void ps3_power_off(void)
        ps3_sys_manager_power_off(); /* never returns */
 }
 
+static void ps3_halt(void)
+{
+       DBG("%s:%d\n", __func__, __LINE__);
+
+       smp_send_stop();
+       ps3_sys_manager_halt(); /* never returns */
+}
+
 static void ps3_panic(char *str)
 {
        DBG("%s:%d %s\n", __func__, __LINE__, str);
@@ -105,7 +113,8 @@ static void ps3_panic(char *str)
        printk("   Please press POWER button.\n");
        printk("\n");
 
-       while(1);
+       while(1)
+               lv1_pause(1);
 }
 
 #if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) || \
@@ -266,6 +275,7 @@ define_machine(ps3) {
        .progress                       = ps3_progress,
        .restart                        = ps3_restart,
        .power_off                      = ps3_power_off,
+       .halt                           = ps3_halt,
 #if defined(CONFIG_KEXEC)
        .kexec_cpu_down                 = ps3_kexec_cpu_down,
        .machine_kexec                  = default_machine_kexec,
index d4f6f96..1260b01 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/reboot.h>
 
 #include <asm/firmware.h>
+#include <asm/lv1call.h>
 #include <asm/ps3.h>
 
 #include "vuart.h"
@@ -581,6 +582,23 @@ fail_id:
        return -EIO;
 }
 
+static void ps3_sys_manager_fin(struct ps3_system_bus_device *dev)
+{
+       ps3_sys_manager_send_request_shutdown(dev);
+
+       pr_emerg("System Halted, OK to turn off power\n");
+
+       while (ps3_sys_manager_handle_msg(dev)) {
+               /* pause until next DEC interrupt */
+               lv1_pause(0);
+       }
+
+       while (1) {
+               /* pause, ignoring DEC interrupt */
+               lv1_pause(1);
+       }
+}
+
 /**
  * ps3_sys_manager_final_power_off - The final platform machine_power_off routine.
  *
@@ -602,12 +620,8 @@ static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev)
 
        ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN,
                PS3_SM_WAKE_DEFAULT);
-       ps3_sys_manager_send_request_shutdown(dev);
-
-       pr_emerg("System Halted, OK to turn off power\n");
 
-       while (1)
-               ps3_sys_manager_handle_msg(dev);
+       ps3_sys_manager_fin(dev);
 }
 
 /**
@@ -639,12 +653,8 @@ static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev)
        ps3_sys_manager_send_attr(dev, 0);
        ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_REBOOT,
                PS3_SM_WAKE_DEFAULT);
-       ps3_sys_manager_send_request_shutdown(dev);
-
-       pr_emerg("System Halted, OK to turn off power\n");
 
-       while (1)
-               ps3_sys_manager_handle_msg(dev);
+       ps3_sys_manager_fin(dev);
 }
 
 /**
index 31648f7..4742258 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <linux/kernel.h>
+#include <asm/lv1call.h>
 #include <asm/ps3.h>
 
 /**
@@ -50,10 +51,7 @@ void ps3_sys_manager_power_off(void)
        if (ps3_sys_manager_ops.power_off)
                ps3_sys_manager_ops.power_off(ps3_sys_manager_ops.dev);
 
-       printk(KERN_EMERG "System Halted, OK to turn off power\n");
-       local_irq_disable();
-       while (1)
-               (void)0;
+       ps3_sys_manager_halt();
 }
 
 void ps3_sys_manager_restart(void)
@@ -61,8 +59,14 @@ void ps3_sys_manager_restart(void)
        if (ps3_sys_manager_ops.restart)
                ps3_sys_manager_ops.restart(ps3_sys_manager_ops.dev);
 
-       printk(KERN_EMERG "System Halted, OK to turn off power\n");
+       ps3_sys_manager_halt();
+}
+
+void ps3_sys_manager_halt(void)
+{
+       pr_emerg("System Halted, OK to turn off power\n");
        local_irq_disable();
        while (1)
-               (void)0;
+               lv1_pause(1);
 }
+
index 2b69367..d01c701 100644 (file)
@@ -434,8 +434,9 @@ struct ps3_sys_manager_ops {
 };
 
 void ps3_sys_manager_register_ops(const struct ps3_sys_manager_ops *ops);
-void ps3_sys_manager_power_off(void);
-void ps3_sys_manager_restart(void);
+void __noreturn ps3_sys_manager_power_off(void);
+void __noreturn ps3_sys_manager_restart(void);
+void __noreturn ps3_sys_manager_halt(void);
 
 struct ps3_prealloc {
     const char *name;