Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is subject to the terms and conditions of the GNU General Public
0003  * License.  See the file "COPYING" in the main directory of this archive
0004  * for more details.
0005  *
0006  * Copyright (C) 2001, 06 by Ralf Baechle (ralf@linux-mips.org)
0007  * Copyright (C) 2001 MIPS Technologies, Inc.
0008  */
0009 #include <linux/kernel.h>
0010 #include <linux/export.h>
0011 #include <linux/pm.h>
0012 #include <linux/types.h>
0013 #include <linux/reboot.h>
0014 #include <linux/delay.h>
0015 
0016 #include <asm/compiler.h>
0017 #include <asm/idle.h>
0018 #include <asm/mipsregs.h>
0019 #include <asm/reboot.h>
0020 
0021 /*
0022  * Urgs ...  Too many MIPS machines to handle this in a generic way.
0023  * So handle all using function pointers to machine specific
0024  * functions.
0025  */
0026 void (*_machine_restart)(char *command);
0027 void (*_machine_halt)(void);
0028 void (*pm_power_off)(void);
0029 
0030 EXPORT_SYMBOL(pm_power_off);
0031 
0032 static void machine_hang(void)
0033 {
0034     /*
0035      * We're hanging the system so we don't want to be interrupted anymore.
0036      * Any interrupt handlers that ran would at best be useless & at worst
0037      * go awry because the system isn't in a functional state.
0038      */
0039     local_irq_disable();
0040 
0041     /*
0042      * Mask all interrupts, giving us a better chance of remaining in the
0043      * low power wait state.
0044      */
0045     clear_c0_status(ST0_IM);
0046 
0047     while (true) {
0048         if (cpu_has_mips_r) {
0049             /*
0050              * We know that the wait instruction is supported so
0051              * make use of it directly, leaving interrupts
0052              * disabled.
0053              */
0054             asm volatile(
0055                 ".set   push\n\t"
0056                 ".set   " MIPS_ISA_ARCH_LEVEL "\n\t"
0057                 "wait\n\t"
0058                 ".set   pop");
0059         } else if (cpu_wait) {
0060             /*
0061              * Try the cpu_wait() callback. This isn't ideal since
0062              * it'll re-enable interrupts, but that ought to be
0063              * harmless given that they're all masked.
0064              */
0065             cpu_wait();
0066             local_irq_disable();
0067         } else {
0068             /*
0069              * We're going to burn some power running round the
0070              * loop, but we don't really have a choice. This isn't
0071              * a path we should expect to run for long during
0072              * typical use anyway.
0073              */
0074         }
0075 
0076         /*
0077          * In most modern MIPS CPUs interrupts will cause the wait
0078          * instruction to graduate even when disabled, and in some
0079          * cases even when masked. In order to prevent a timer
0080          * interrupt from continuously taking us out of the low power
0081          * wait state, we clear any pending timer interrupt here.
0082          */
0083         if (cpu_has_counter)
0084             write_c0_compare(0);
0085     }
0086 }
0087 
0088 void machine_restart(char *command)
0089 {
0090     if (_machine_restart)
0091         _machine_restart(command);
0092 
0093 #ifdef CONFIG_SMP
0094     preempt_disable();
0095     smp_send_stop();
0096 #endif
0097     do_kernel_restart(command);
0098     mdelay(1000);
0099     pr_emerg("Reboot failed -- System halted\n");
0100     machine_hang();
0101 }
0102 
0103 void machine_halt(void)
0104 {
0105     if (_machine_halt)
0106         _machine_halt();
0107 
0108 #ifdef CONFIG_SMP
0109     preempt_disable();
0110     smp_send_stop();
0111 #endif
0112     machine_hang();
0113 }
0114 
0115 void machine_power_off(void)
0116 {
0117     do_kernel_power_off();
0118 
0119 #ifdef CONFIG_SMP
0120     preempt_disable();
0121     smp_send_stop();
0122 #endif
0123     machine_hang();
0124 }