2005-04-17 02:20:36 +04:00
# include <linux/module.h>
2006-12-07 07:40:06 +03:00
# include <linux/reboot.h>
2008-01-30 15:32:51 +03:00
# include <linux/init.h>
# include <linux/pm.h>
# include <linux/efi.h>
# include <acpi/reboot.h>
# include <asm/io.h>
2005-04-17 02:20:36 +04:00
# include <asm/apic.h>
2005-09-04 02:56:38 +04:00
# include <asm/desc.h>
2008-01-30 15:32:51 +03:00
# include <asm/hpet.h>
2008-03-18 02:37:13 +03:00
# include <asm/pgtable.h>
2008-04-28 03:15:59 +04:00
# include <asm/proto.h>
2007-05-02 21:27:06 +04:00
# include <asm/reboot_fixups.h>
2007-05-02 21:27:11 +04:00
# include <asm/reboot.h>
2005-04-17 02:20:36 +04:00
2008-01-30 15:32:51 +03:00
# ifdef CONFIG_X86_32
# include <linux / dmi.h>
# include <linux / ctype.h>
# include <linux / mc146818rtc.h>
# else
# include <asm / iommu.h>
# endif
2005-04-17 02:20:36 +04:00
/*
* Power off function , if any
*/
void ( * pm_power_off ) ( void ) ;
2005-06-23 11:08:33 +04:00
EXPORT_SYMBOL ( pm_power_off ) ;
2005-04-17 02:20:36 +04:00
2008-05-12 17:43:38 +04:00
static const struct desc_ptr no_idt = { } ;
2005-04-17 02:20:36 +04:00
static int reboot_mode ;
2008-08-25 14:11:27 +04:00
/*
* Keyboard reset and triple fault may result in INIT , not RESET , which
* doesn ' t work when we ' re in vmx root mode . Try ACPI first .
*/
enum reboot_type reboot_type = BOOT_ACPI ;
2008-01-30 15:32:51 +03:00
int reboot_force ;
2005-04-17 02:20:36 +04:00
2008-01-30 15:32:51 +03:00
# if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
2005-04-17 02:20:36 +04:00
static int reboot_cpu = - 1 ;
# endif
2008-01-30 15:32:51 +03:00
/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]
warm Don ' t set the cold reboot flag
cold Set the cold reboot flag
bios Reboot by jumping through the BIOS ( only for X86_32 )
smp Reboot by executing reset on BSP or other CPU ( only for X86_32 )
triple Force a triple fault ( init )
kbd Use the keyboard controller . cold reset ( default )
acpi Use the RESET_REG in the FADT
efi Use efi reset_system runtime service
force Avoid anything that could hang .
*/
2005-04-17 02:20:36 +04:00
static int __init reboot_setup ( char * str )
{
2008-01-30 15:32:51 +03:00
for ( ; ; ) {
2005-04-17 02:20:36 +04:00
switch ( * str ) {
2008-01-30 15:32:51 +03:00
case ' w ' :
2005-04-17 02:20:36 +04:00
reboot_mode = 0x1234 ;
break ;
2008-01-30 15:32:51 +03:00
case ' c ' :
reboot_mode = 0 ;
2005-04-17 02:20:36 +04:00
break ;
2008-01-30 15:32:51 +03:00
# ifdef CONFIG_X86_32
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SMP
2008-01-30 15:32:51 +03:00
case ' s ' :
2005-09-13 12:25:48 +04:00
if ( isdigit ( * ( str + 1 ) ) ) {
2005-04-17 02:20:36 +04:00
reboot_cpu = ( int ) ( * ( str + 1 ) - ' 0 ' ) ;
2005-09-13 12:25:48 +04:00
if ( isdigit ( * ( str + 2 ) ) )
2005-04-17 02:20:36 +04:00
reboot_cpu = reboot_cpu * 10 + ( int ) ( * ( str + 2 ) - ' 0 ' ) ;
}
2008-01-30 15:32:51 +03:00
/* we will leave sorting out the final value
when we are ready to reboot , since we might not
have set up boot_cpu_id or smp_num_cpu */
2005-04-17 02:20:36 +04:00
break ;
2008-01-30 15:32:51 +03:00
# endif /* CONFIG_SMP */
case ' b ' :
2005-04-17 02:20:36 +04:00
# endif
2008-01-30 15:32:51 +03:00
case ' a ' :
case ' k ' :
case ' t ' :
case ' e ' :
reboot_type = * str ;
break ;
case ' f ' :
reboot_force = 1 ;
break ;
2005-04-17 02:20:36 +04:00
}
2008-01-30 15:32:51 +03:00
str = strchr ( str , ' , ' ) ;
if ( str )
2005-04-17 02:20:36 +04:00
str + + ;
else
break ;
}
return 1 ;
}
__setup ( " reboot= " , reboot_setup ) ;
2008-01-30 15:32:51 +03:00
# ifdef CONFIG_X86_32
2005-04-17 02:20:36 +04:00
/*
* Reboot options and system auto - detection code provided by
* Dell Inc . so their systems " just work " . : - )
*/
/*
2008-01-30 15:32:51 +03:00
* Some machines require the " reboot=b " commandline option ,
* this quirk makes that automatic .
2005-04-17 02:20:36 +04:00
*/
2007-10-03 23:15:40 +04:00
static int __init set_bios_reboot ( const struct dmi_system_id * d )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:32:51 +03:00
if ( reboot_type ! = BOOT_BIOS ) {
reboot_type = BOOT_BIOS ;
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " %s series board detected. Selecting BIOS-method for reboots. \n " , d - > ident ) ;
}
return 0 ;
}
static struct dmi_system_id __initdata reboot_dmi_table [ ] = {
2007-06-01 11:46:40 +04:00
{ /* Handle problems with rebooting on Dell E520's */
. callback = set_bios_reboot ,
. ident = " Dell E520 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Dell DM061 " ) ,
} ,
} ,
2005-04-17 02:20:36 +04:00
{ /* Handle problems with rebooting on Dell 1300's */
2005-06-26 01:57:55 +04:00
. callback = set_bios_reboot ,
2005-04-17 02:20:36 +04:00
. ident = " Dell PowerEdge 1300 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Computer Corporation " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " PowerEdge 1300/ " ) ,
} ,
} ,
{ /* Handle problems with rebooting on Dell 300's */
. callback = set_bios_reboot ,
. ident = " Dell PowerEdge 300 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Computer Corporation " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " PowerEdge 300/ " ) ,
} ,
} ,
2007-07-21 19:11:11 +04:00
{ /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
. callback = set_bios_reboot ,
. ident = " Dell OptiPlex 745 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " OptiPlex 745 " ) ,
} ,
} ,
2008-03-05 02:05:41 +03:00
{ /* Handle problems with rebooting on Dell Optiplex 745's DFF*/
. callback = set_bios_reboot ,
. ident = " Dell OptiPlex 745 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " OptiPlex 745 " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 0MM599 " ) ,
} ,
} ,
2008-03-12 18:27:56 +03:00
{ /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
. callback = set_bios_reboot ,
. ident = " Dell OptiPlex 745 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " OptiPlex 745 " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 0KW626 " ) ,
} ,
} ,
2005-04-17 02:20:36 +04:00
{ /* Handle problems with rebooting on Dell 2400's */
. callback = set_bios_reboot ,
. ident = " Dell PowerEdge 2400 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Computer Corporation " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " PowerEdge 2400 " ) ,
} ,
} ,
2008-07-17 15:50:15 +04:00
{ /* Handle problems with rebooting on Dell T5400's */
. callback = set_bios_reboot ,
. ident = " Dell Precision T5400 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Precision WorkStation T5400 " ) ,
} ,
} ,
2006-01-06 11:12:20 +03:00
{ /* Handle problems with rebooting on HP laptops */
2005-11-30 06:34:35 +03:00
. callback = set_bios_reboot ,
2006-01-06 11:12:20 +03:00
. ident = " HP Compaq Laptop " ,
2005-11-30 06:34:35 +03:00
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Hewlett-Packard " ) ,
2006-01-06 11:12:20 +03:00
DMI_MATCH ( DMI_PRODUCT_NAME , " HP Compaq " ) ,
2005-11-30 06:34:35 +03:00
} ,
} ,
2005-04-17 02:20:36 +04:00
{ }
} ;
static int __init reboot_init ( void )
{
dmi_check_system ( reboot_dmi_table ) ;
return 0 ;
}
core_initcall ( reboot_init ) ;
/* The following code and data reboots the machine by switching to real
mode and jumping to the BIOS reset entry point , as if the CPU has
really been reset . The previous version asked the keyboard
controller to pulse the CPU reset line , which is more thorough , but
doesn ' t work with at least one type of 486 motherboard . It is easy
to stop this code working ; hence the copious comments . */
2008-05-12 17:43:38 +04:00
static const unsigned long long
2005-04-17 02:20:36 +04:00
real_mode_gdt_entries [ 3 ] =
{
0x0000000000000000ULL , /* Null descriptor */
2008-05-12 17:43:38 +04:00
0x00009b000000ffffULL , /* 16-bit real-mode 64k code at 0x00000000 */
0x000093000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */
2005-04-17 02:20:36 +04:00
} ;
2008-05-12 17:43:38 +04:00
static const struct desc_ptr
2006-09-26 10:32:22 +04:00
real_mode_gdt = { sizeof ( real_mode_gdt_entries ) - 1 , ( long ) real_mode_gdt_entries } ,
2008-01-30 15:32:51 +03:00
real_mode_idt = { 0x3ff , 0 } ;
2005-04-17 02:20:36 +04:00
/* This is 16-bit protected mode code to disable paging and the cache,
switch to real mode and jump to the BIOS reset code .
The instruction that switches to real mode by writing to CR0 must be
followed immediately by a far jump instruction , which set CS to a
valid value for real mode , and flushes the prefetch queue to avoid
running instructions that have already been decoded in protected
mode .
Clears all the flags except ET , especially PG ( paging ) , PE
( protected - mode enable ) and TS ( task switch for coprocessor state
save ) . Flushes the TLB after paging has been disabled . Sets CD and
NW , to disable the cache on a 486 , and invalidates the cache . This
is more like the state of a 486 after reset . I don ' t know if
something else should be done for other chips .
More could be done here to set up the registers as if a CPU reset had
occurred ; hopefully real BIOSs don ' t assume much . */
2008-05-12 17:43:38 +04:00
static const unsigned char real_mode_switch [ ] =
2005-04-17 02:20:36 +04:00
{
0x66 , 0x0f , 0x20 , 0xc0 , /* movl %cr0,%eax */
0x66 , 0x83 , 0xe0 , 0x11 , /* andl $0x00000011,%eax */
0x66 , 0x0d , 0x00 , 0x00 , 0x00 , 0x60 , /* orl $0x60000000,%eax */
0x66 , 0x0f , 0x22 , 0xc0 , /* movl %eax,%cr0 */
0x66 , 0x0f , 0x22 , 0xd8 , /* movl %eax,%cr3 */
0x66 , 0x0f , 0x20 , 0xc3 , /* movl %cr0,%ebx */
0x66 , 0x81 , 0xe3 , 0x00 , 0x00 , 0x00 , 0x60 , /* andl $0x60000000,%ebx */
0x74 , 0x02 , /* jz f */
0x0f , 0x09 , /* wbinvd */
0x24 , 0x10 , /* f: andb $0x10,al */
0x66 , 0x0f , 0x22 , 0xc0 /* movl %eax,%cr0 */
} ;
2008-05-12 17:43:38 +04:00
static const unsigned char jump_to_bios [ ] =
2005-04-17 02:20:36 +04:00
{
0xea , 0x00 , 0x00 , 0xff , 0xff /* ljmp $0xffff,$0x0000 */
} ;
/*
* Switch to real mode and then execute the code
* specified by the code and length parameters .
* We assume that length will aways be less that 100 !
*/
2008-05-12 17:43:38 +04:00
void machine_real_restart ( const unsigned char * code , int length )
2005-04-17 02:20:36 +04:00
{
local_irq_disable ( ) ;
/* Write zero to CMOS register number 0x0f, which the BIOS POST
routine will recognize as telling it to do a proper reboot . ( Well
that ' s what this book in front of me says - - it may only apply to
the Phoenix BIOS though , it ' s not clear ) . At the same time ,
disable NMIs by setting the top bit in the CMOS address register ,
as we ' re about to do peculiar things to the CPU . I ' m not sure if
` outb_p ' is needed instead of just ` outb ' . Use it to be on the
safe side . ( Yes , CMOS_WRITE does outb_p ' s . - Paul G . )
*/
2007-05-02 21:27:18 +04:00
spin_lock ( & rtc_lock ) ;
2005-04-17 02:20:36 +04:00
CMOS_WRITE ( 0x00 , 0x8f ) ;
2007-05-02 21:27:18 +04:00
spin_unlock ( & rtc_lock ) ;
2005-04-17 02:20:36 +04:00
/* Remap the kernel at virtual address zero, as well as offset zero
from the kernel segment . This assumes the kernel segment starts at
virtual address PAGE_OFFSET . */
2008-03-18 02:37:13 +03:00
memcpy ( swapper_pg_dir , swapper_pg_dir + KERNEL_PGD_BOUNDARY ,
2008-01-30 15:32:51 +03:00
sizeof ( swapper_pg_dir [ 0 ] ) * KERNEL_PGD_PTRS ) ;
2005-04-17 02:20:36 +04:00
/*
* Use ` swapper_pg_dir ' as our page directory .
*/
load_cr3 ( swapper_pg_dir ) ;
/* Write 0x1234 to absolute memory location 0x472. The BIOS reads
this on booting to tell it to " Bypass memory test (also warm
boot ) " . This seems like a fairly standard thing that gets set by
REBOOT . COM programs , and the previous reset routine did this
too . */
* ( ( unsigned short * ) 0x472 ) = reboot_mode ;
/* For the switch to real mode, copy some code to low memory. It has
to be in the first 64 k because it is running in 16 - bit mode , and it
has to have the same physical and virtual address , because it turns
off paging . Copy it near the end of the first page , out of the way
of BIOS variables . */
2008-01-30 15:32:51 +03:00
memcpy ( ( void * ) ( 0x1000 - sizeof ( real_mode_switch ) - 100 ) ,
2005-04-17 02:20:36 +04:00
real_mode_switch , sizeof ( real_mode_switch ) ) ;
2008-01-30 15:32:51 +03:00
memcpy ( ( void * ) ( 0x1000 - 100 ) , code , length ) ;
2005-04-17 02:20:36 +04:00
/* Set up the IDT for real mode. */
2005-09-04 02:56:38 +04:00
load_idt ( & real_mode_idt ) ;
2005-04-17 02:20:36 +04:00
/* Set up a GDT from which we can load segment descriptors for real
mode . The GDT is not used in real mode ; it is just needed here to
prepare the descriptors . */
2005-09-04 02:56:38 +04:00
load_gdt ( & real_mode_gdt ) ;
2005-04-17 02:20:36 +04:00
/* Load the data segment registers, and thus the descriptors ready for
real mode . The base address of each segment is 0x100 , 16 times the
selector value being loaded here . This is so that the segment
registers don ' t have to be reloaded after switching to real mode :
the values are consistent for real mode operation already . */
__asm__ __volatile__ ( " movl $0x0010,%%eax \n "
" \t movl %%eax,%%ds \n "
" \t movl %%eax,%%es \n "
" \t movl %%eax,%%fs \n "
" \t movl %%eax,%%gs \n "
" \t movl %%eax,%%ss " : : : " eax " ) ;
/* Jump to the 16-bit code that we copied earlier. It disables paging
and the cache , switches to real mode , and jumps to the BIOS reset
entry point . */
__asm__ __volatile__ ( " ljmp $0x0008,%0 "
:
2008-01-30 15:32:51 +03:00
: " i " ( ( void * ) ( 0x1000 - sizeof ( real_mode_switch ) - 100 ) ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-23 11:08:33 +04:00
# ifdef CONFIG_APM_MODULE
EXPORT_SYMBOL ( machine_real_restart ) ;
# endif
2005-04-17 02:20:36 +04:00
2008-01-30 15:32:51 +03:00
# endif /* CONFIG_X86_32 */
static inline void kb_wait ( void )
{
int i ;
2008-01-30 15:33:25 +03:00
for ( i = 0 ; i < 0x10000 ; i + + ) {
if ( ( inb ( 0x64 ) & 0x02 ) = = 0 )
2008-01-30 15:32:51 +03:00
break ;
2008-01-30 15:33:25 +03:00
udelay ( 2 ) ;
}
2008-01-30 15:32:51 +03:00
}
2008-03-06 20:29:43 +03:00
void __attribute__ ( ( weak ) ) mach_reboot_fixups ( void )
{
}
2008-02-13 02:37:48 +03:00
static void native_machine_emergency_restart ( void )
2005-04-17 02:20:36 +04:00
{
2008-01-30 15:32:51 +03:00
int i ;
/* Tell the BIOS if we want cold or warm reboot */
* ( ( unsigned short * ) __va ( 0x472 ) ) = reboot_mode ;
for ( ; ; ) {
/* Could also try the reset bit in the Hammer NB */
switch ( reboot_type ) {
case BOOT_KBD :
2008-03-06 20:29:43 +03:00
mach_reboot_fixups ( ) ; /* for board specific fixups */
2008-01-30 15:32:51 +03:00
for ( i = 0 ; i < 10 ; i + + ) {
kb_wait ( ) ;
udelay ( 50 ) ;
outb ( 0xfe , 0x64 ) ; /* pulse reset low */
udelay ( 50 ) ;
}
case BOOT_TRIPLE :
2008-05-12 17:43:38 +04:00
load_idt ( & no_idt ) ;
2008-01-30 15:32:51 +03:00
__asm__ __volatile__ ( " int3 " ) ;
reboot_type = BOOT_KBD ;
break ;
# ifdef CONFIG_X86_32
case BOOT_BIOS :
machine_real_restart ( jump_to_bios , sizeof ( jump_to_bios ) ) ;
reboot_type = BOOT_KBD ;
break ;
# endif
case BOOT_ACPI :
acpi_reboot ( ) ;
reboot_type = BOOT_KBD ;
break ;
case BOOT_EFI :
if ( efi_enabled )
efi . reset_system ( reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD ,
EFI_SUCCESS , 0 , NULL ) ;
reboot_type = BOOT_KBD ;
break ;
}
}
}
2008-03-17 22:08:39 +03:00
void native_machine_shutdown ( void )
2008-01-30 15:32:51 +03:00
{
/* Stop the cpus and apics */
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SMP
2005-06-26 01:57:55 +04:00
/* The boot cpu is always logical cpu 0 */
2008-07-16 01:14:30 +04:00
int reboot_cpu_id = 0 ;
2005-06-26 01:57:55 +04:00
2008-01-30 15:32:51 +03:00
# ifdef CONFIG_X86_32
2005-06-26 01:57:55 +04:00
/* See if there has been given a command line override */
2005-07-26 22:07:01 +04:00
if ( ( reboot_cpu ! = - 1 ) & & ( reboot_cpu < NR_CPUS ) & &
2008-07-25 05:21:31 +04:00
cpu_online ( reboot_cpu ) )
2005-06-26 01:57:55 +04:00
reboot_cpu_id = reboot_cpu ;
2008-01-30 15:32:51 +03:00
# endif
2005-04-17 02:20:36 +04:00
2008-01-30 15:32:51 +03:00
/* Make certain the cpu I'm about to reboot on is online */
2008-07-25 05:21:31 +04:00
if ( ! cpu_online ( reboot_cpu_id ) )
2005-06-26 01:57:55 +04:00
reboot_cpu_id = smp_processor_id ( ) ;
/* Make certain I only run on the appropriate processor */
2008-07-25 05:21:31 +04:00
set_cpus_allowed_ptr ( current , & cpumask_of_cpu ( reboot_cpu_id ) ) ;
2005-06-26 01:57:55 +04:00
2008-01-30 15:32:51 +03:00
/* O.K Now that I'm on the appropriate processor,
* stop all of the others .
2005-04-17 02:20:36 +04:00
*/
smp_send_stop ( ) ;
2008-01-30 15:32:51 +03:00
# endif
2005-04-17 02:20:36 +04:00
lapic_shutdown ( ) ;
# ifdef CONFIG_X86_IO_APIC
disable_IO_APIC ( ) ;
# endif
2008-01-30 15:32:51 +03:00
2007-12-03 19:17:10 +03:00
# ifdef CONFIG_HPET_TIMER
hpet_disable ( ) ;
# endif
2005-06-26 01:57:55 +04:00
2008-01-30 15:32:51 +03:00
# ifdef CONFIG_X86_64
pci_iommu_shutdown ( ) ;
# endif
2007-05-02 21:27:06 +04:00
}
2008-02-13 02:37:48 +03:00
static void native_machine_restart ( char * __unused )
2005-06-26 01:57:55 +04:00
{
2008-01-30 15:32:51 +03:00
printk ( " machine restart \n " ) ;
2005-04-17 02:20:36 +04:00
2008-01-30 15:32:51 +03:00
if ( ! reboot_force )
machine_shutdown ( ) ;
2005-07-26 21:41:26 +04:00
machine_emergency_restart ( ) ;
}
2008-02-13 02:37:48 +03:00
static void native_machine_halt ( void )
2005-04-17 02:20:36 +04:00
{
}
2008-02-13 02:37:48 +03:00
static void native_machine_power_off ( void )
2005-04-17 02:20:36 +04:00
{
2006-01-12 00:43:12 +03:00
if ( pm_power_off ) {
2008-01-30 15:32:51 +03:00
if ( ! reboot_force )
machine_shutdown ( ) ;
2005-04-17 02:20:36 +04:00
pm_power_off ( ) ;
2006-01-12 00:43:12 +03:00
}
2005-04-17 02:20:36 +04:00
}
2007-05-02 21:27:11 +04:00
struct machine_ops machine_ops = {
2008-02-13 02:37:48 +03:00
. power_off = native_machine_power_off ,
. shutdown = native_machine_shutdown ,
. emergency_restart = native_machine_emergency_restart ,
. restart = native_machine_restart ,
2008-03-17 22:08:38 +03:00
. halt = native_machine_halt ,
# ifdef CONFIG_KEXEC
. crash_shutdown = native_machine_crash_shutdown ,
# endif
2007-05-02 21:27:11 +04:00
} ;
2008-02-13 02:37:48 +03:00
void machine_power_off ( void )
{
machine_ops . power_off ( ) ;
}
void machine_shutdown ( void )
{
machine_ops . shutdown ( ) ;
}
void machine_emergency_restart ( void )
{
machine_ops . emergency_restart ( ) ;
}
void machine_restart ( char * cmd )
{
machine_ops . restart ( cmd ) ;
}
void machine_halt ( void )
{
machine_ops . halt ( ) ;
}
2008-03-17 22:08:38 +03:00
# ifdef CONFIG_KEXEC
void machine_crash_shutdown ( struct pt_regs * regs )
{
machine_ops . crash_shutdown ( regs ) ;
}
# endif