2005-04-16 15:20:36 -07:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
2006-01-18 17:37:07 +00:00
* Copyright ( C ) 2001 , 06 by Ralf Baechle ( ralf @ linux - mips . org )
2005-04-16 15:20:36 -07:00
* Copyright ( C ) 2001 MIPS Technologies , Inc .
*/
# include <linux/kernel.h>
2011-07-23 16:30:40 -04:00
# include <linux/export.h>
2006-01-18 17:37:07 +00:00
# include <linux/pm.h>
2005-04-16 15:20:36 -07:00
# include <linux/types.h>
# include <linux/reboot.h>
2015-03-25 10:25:44 -07:00
# include <linux/delay.h>
2006-01-18 17:37:07 +00:00
2017-08-23 13:53:16 -07:00
# include <asm/compiler.h>
# include <asm/idle.h>
# include <asm/mipsregs.h>
2005-04-16 15:20:36 -07:00
# include <asm/reboot.h>
/*
* Urgs . . . Too many MIPS machines to handle this in a generic way .
* So handle all using function pointers to machine specific
* functions .
*/
void ( * _machine_restart ) ( char * command ) ;
void ( * _machine_halt ) ( void ) ;
2006-01-18 17:37:07 +00:00
void ( * pm_power_off ) ( void ) ;
2005-04-16 15:20:36 -07:00
2006-12-10 15:09:38 +00:00
EXPORT_SYMBOL ( pm_power_off ) ;
2017-08-23 13:53:16 -07:00
static void machine_hang ( void )
{
/*
* We ' re hanging the system so we don ' t want to be interrupted anymore .
* Any interrupt handlers that ran would at best be useless & at worst
* go awry because the system isn ' t in a functional state .
*/
local_irq_disable ( ) ;
/*
* Mask all interrupts , giving us a better chance of remaining in the
* low power wait state .
*/
clear_c0_status ( ST0_IM ) ;
while ( true ) {
if ( cpu_has_mips_r ) {
/*
* We know that the wait instruction is supported so
* make use of it directly , leaving interrupts
* disabled .
*/
asm volatile (
" .set push \n \t "
" .set " MIPS_ISA_ARCH_LEVEL " \n \t "
" wait \n \t "
" .set pop " ) ;
} else if ( cpu_wait ) {
/*
* Try the cpu_wait ( ) callback . This isn ' t ideal since
* it ' ll re - enable interrupts , but that ought to be
* harmless given that they ' re all masked .
*/
cpu_wait ( ) ;
local_irq_disable ( ) ;
} else {
/*
* We ' re going to burn some power running round the
* loop , but we don ' t really have a choice . This isn ' t
* a path we should expect to run for long during
* typical use anyway .
*/
}
/*
* In most modern MIPS CPUs interrupts will cause the wait
* instruction to graduate even when disabled , and in some
* cases even when masked . In order to prevent a timer
* interrupt from continuously taking us out of the low power
* wait state , we clear any pending timer interrupt here .
*/
if ( cpu_has_counter )
write_c0_compare ( 0 ) ;
}
}
2005-04-16 15:20:36 -07:00
void machine_restart ( char * command )
{
2006-01-17 21:14:01 +00:00
if ( _machine_restart )
_machine_restart ( command ) ;
2015-03-25 10:25:44 -07:00
# ifdef CONFIG_SMP
preempt_disable ( ) ;
smp_send_stop ( ) ;
# endif
do_kernel_restart ( command ) ;
mdelay ( 1000 ) ;
pr_emerg ( " Reboot failed -- System halted \n " ) ;
2017-08-23 13:53:16 -07:00
machine_hang ( ) ;
2005-04-16 15:20:36 -07:00
}
void machine_halt ( void )
{
2006-01-17 21:14:01 +00:00
if ( _machine_halt )
_machine_halt ( ) ;
2015-03-25 10:25:44 -07:00
# ifdef CONFIG_SMP
preempt_disable ( ) ;
smp_send_stop ( ) ;
# endif
2017-08-23 13:53:16 -07:00
machine_hang ( ) ;
2005-04-16 15:20:36 -07:00
}
void machine_power_off ( void )
{
2006-01-18 17:37:07 +00:00
if ( pm_power_off )
pm_power_off ( ) ;
2015-03-25 10:25:44 -07:00
# ifdef CONFIG_SMP
preempt_disable ( ) ;
smp_send_stop ( ) ;
# endif
2017-08-23 13:53:16 -07:00
machine_hang ( ) ;
2005-04-16 15:20:36 -07:00
}