reboot.c 2.98 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
/* Various gunk just to reboot the machine. */ 
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/string.h>
9
#include <linux/pm.h>
10
#include <linux/kdebug.h>
Alexey Dobriyan's avatar
Alexey Dobriyan committed
11
#include <linux/sched.h>
Linus Torvalds's avatar
Linus Torvalds committed
12
13
14
15
16
17
18
19
20
21
22
23
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/hw_irq.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <asm/apic.h>

/*
 * Power off function, if any
 */
void (*pm_power_off)(void);
24
EXPORT_SYMBOL(pm_power_off);
Linus Torvalds's avatar
Linus Torvalds committed
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

static long no_idt[3];
static enum { 
	BOOT_TRIPLE = 't',
	BOOT_KBD = 'k'
} reboot_type = BOOT_KBD;
static int reboot_mode = 0;
int reboot_force;

/* reboot=t[riple] | k[bd] [, [w]arm | [c]old]
   warm   Don't set the cold reboot flag
   cold   Set the cold reboot flag
   triple Force a triple fault (init)
   kbd    Use the keyboard controller. cold reset (default)
   force  Avoid anything that could hang.
 */ 
static int __init reboot_setup(char *str)
{
	for (;;) {
		switch (*str) {
		case 'w': 
			reboot_mode = 0x1234;
			break;

		case 'c':
			reboot_mode = 0;
			break;

		case 't':
		case 'b':
		case 'k':
			reboot_type = *str;
			break;
		case 'f':
			reboot_force = 1;
			break;
		}
		if((str = strchr(str,',')) != NULL)
			str++;
		else
			break;
	}
	return 1;
}

__setup("reboot=", reboot_setup);

72
static inline void kb_wait(void)
Linus Torvalds's avatar
Linus Torvalds committed
73
{
74
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
75

76
77
78
79
	for (i=0; i<0x10000; i++)
		if ((inb_p(0x64) & 0x02) == 0)
			break;
}
Linus Torvalds's avatar
Linus Torvalds committed
80

81
82
void machine_shutdown(void)
{
83
	unsigned long flags;
84
85
86
	/* Stop the cpus and apics */
#ifdef CONFIG_SMP
	int reboot_cpu_id;
Linus Torvalds's avatar
Linus Torvalds committed
87

88
89
90
91
92
93
	/* The boot cpu is always logical cpu 0 */
	reboot_cpu_id = 0;

	/* Make certain the cpu I'm about to reboot on is online */
	if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
		reboot_cpu_id = smp_processor_id();
Linus Torvalds's avatar
Linus Torvalds committed
94
95
	}

96
97
98
99
100
101
102
	/* Make certain I only run on the appropriate processor */
	set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));

	/* O.K Now that I'm on the appropriate processor,
	 * stop all of the others.
	 */
	smp_send_stop();
Linus Torvalds's avatar
Linus Torvalds committed
103
104
#endif

105
	local_irq_save(flags);
Linus Torvalds's avatar
Linus Torvalds committed
106

107
108
109
110
111
112
#ifndef CONFIG_SMP
	disable_local_APIC();
#endif

	disable_IO_APIC();

113
	local_irq_restore(flags);
Linus Torvalds's avatar
Linus Torvalds committed
114
115
}

116
void machine_emergency_restart(void)
Linus Torvalds's avatar
Linus Torvalds committed
117
118
119
120
121
122
123
124
125
126
{
	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:
127
		for (i=0; i<10; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
			kb_wait();
			udelay(50);
			outb(0xfe,0x64);         /* pulse reset low */
			udelay(50);
		}

		case BOOT_TRIPLE: 
			__asm__ __volatile__("lidt (%0)": :"r" (&no_idt));
			__asm__ __volatile__("int3");

			reboot_type = BOOT_KBD;
			break;
		}      
	}      
}

144
145
146
147
148
149
150
151
152
153
void machine_restart(char * __unused)
{
	printk("machine restart\n");

	if (!reboot_force) {
		machine_shutdown();
	}
	machine_emergency_restart();
}

Linus Torvalds's avatar
Linus Torvalds committed
154
155
156
157
158
159
void machine_halt(void)
{
}

void machine_power_off(void)
{
160
161
162
163
	if (pm_power_off) {
		if (!reboot_force) {
			machine_shutdown();
		}
Linus Torvalds's avatar
Linus Torvalds committed
164
		pm_power_off();
165
	}
Linus Torvalds's avatar
Linus Torvalds committed
166
167
}