/root/src/xen/xen/arch/x86/shutdown.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * arch/x86/shutdown.c |
3 | | * |
4 | | * x86-specific shutdown handling. |
5 | | */ |
6 | | |
7 | | #include <xen/init.h> |
8 | | #include <xen/lib.h> |
9 | | #include <xen/sched.h> |
10 | | #include <xen/smp.h> |
11 | | #include <xen/delay.h> |
12 | | #include <xen/dmi.h> |
13 | | #include <xen/irq.h> |
14 | | #include <xen/watchdog.h> |
15 | | #include <xen/console.h> |
16 | | #include <xen/shutdown.h> |
17 | | #include <xen/acpi.h> |
18 | | #include <xen/efi.h> |
19 | | #include <asm/msr.h> |
20 | | #include <asm/regs.h> |
21 | | #include <asm/mc146818rtc.h> |
22 | | #include <asm/system.h> |
23 | | #include <asm/io.h> |
24 | | #include <asm/processor.h> |
25 | | #include <asm/mpspec.h> |
26 | | #include <asm/tboot.h> |
27 | | #include <asm/apic.h> |
28 | | |
29 | | enum reboot_type { |
30 | | BOOT_INVALID, |
31 | | BOOT_TRIPLE = 't', |
32 | | BOOT_KBD = 'k', |
33 | | BOOT_ACPI = 'a', |
34 | | BOOT_CF9 = 'p', |
35 | | BOOT_CF9_PWR = 'P', |
36 | | BOOT_EFI = 'e', |
37 | | }; |
38 | | |
39 | | static int reboot_mode; |
40 | | |
41 | | /* |
42 | | * reboot=t[riple] | k[bd] | a[cpi] | p[ci] | n[o] | [e]fi [, [w]arm | [c]old] |
43 | | * warm Don't set the cold reboot flag |
44 | | * cold Set the cold reboot flag |
45 | | * no Suppress automatic reboot after panics or crashes |
46 | | * triple Force a triple fault (init) |
47 | | * kbd Use the keyboard controller. cold reset (default) |
48 | | * acpi Use the RESET_REG in the FADT |
49 | | * pci Use the so-called "PCI reset register", CF9 |
50 | | * Power Like 'pci' but for a full power-cyle reset |
51 | | * efi Use the EFI reboot (if running under EFI) |
52 | | */ |
53 | | static enum reboot_type reboot_type = BOOT_INVALID; |
54 | | |
55 | | static int __init set_reboot_type(const char *str) |
56 | 0 | { |
57 | 0 | int rc = 0; |
58 | 0 |
|
59 | 0 | for ( ; ; ) |
60 | 0 | { |
61 | 0 | switch ( *str ) |
62 | 0 | { |
63 | 0 | case 'n': /* no reboot */ |
64 | 0 | opt_noreboot = 1; |
65 | 0 | break; |
66 | 0 | case 'w': /* "warm" reboot (no memory testing etc) */ |
67 | 0 | reboot_mode = 0x1234; |
68 | 0 | break; |
69 | 0 | case 'c': /* "cold" reboot (with memory testing etc) */ |
70 | 0 | reboot_mode = 0x0; |
71 | 0 | break; |
72 | 0 | case 'a': |
73 | 0 | case 'e': |
74 | 0 | case 'k': |
75 | 0 | case 'P': |
76 | 0 | case 'p': |
77 | 0 | case 't': |
78 | 0 | reboot_type = *str; |
79 | 0 | break; |
80 | 0 | default: |
81 | 0 | rc = -EINVAL; |
82 | 0 | break; |
83 | 0 | } |
84 | 0 | if ( (str = strchr(str, ',')) == NULL ) |
85 | 0 | break; |
86 | 0 | str++; |
87 | 0 | } |
88 | 0 |
|
89 | 0 | if ( reboot_type == BOOT_EFI && !efi_enabled(EFI_RS) ) |
90 | 0 | { |
91 | 0 | printk("EFI reboot selected, but no EFI runtime services available.\n" |
92 | 0 | "Falling back to default reboot type.\n"); |
93 | 0 | reboot_type = BOOT_INVALID; |
94 | 0 | } |
95 | 0 |
|
96 | 0 | return rc; |
97 | 0 | } |
98 | | custom_param("reboot", set_reboot_type); |
99 | | |
100 | | static inline void kb_wait(void) |
101 | 0 | { |
102 | 0 | int i; |
103 | 0 |
|
104 | 0 | for ( i = 0; i < 0x10000; i++ ) |
105 | 0 | if ( (inb_p(0x64) & 0x02) == 0 ) |
106 | 0 | break; |
107 | 0 | } |
108 | | |
109 | | static void noreturn __machine_halt(void *unused) |
110 | 0 | { |
111 | 0 | local_irq_disable(); |
112 | 0 | for ( ; ; ) |
113 | 0 | halt(); |
114 | 0 | } |
115 | | |
116 | | void machine_halt(void) |
117 | 0 | { |
118 | 0 | watchdog_disable(); |
119 | 0 | console_start_sync(); |
120 | 0 |
|
121 | 0 | if ( system_state >= SYS_STATE_smp_boot ) |
122 | 0 | { |
123 | 0 | local_irq_enable(); |
124 | 0 | smp_call_function(__machine_halt, NULL, 0); |
125 | 0 | } |
126 | 0 |
|
127 | 0 | __machine_halt(NULL); |
128 | 0 | } |
129 | | |
130 | | static void default_reboot_type(void) |
131 | 1 | { |
132 | 1 | if ( reboot_type == BOOT_INVALID ) |
133 | 1 | reboot_type = efi_enabled(EFI_RS) ? BOOT_EFI |
134 | 1 | : acpi_disabled ? BOOT_KBD |
135 | 1 | : BOOT_ACPI; |
136 | 1 | } |
137 | | |
138 | | static int __init override_reboot(struct dmi_system_id *d) |
139 | 0 | { |
140 | 0 | enum reboot_type type = (long)d->driver_data; |
141 | 0 |
|
142 | 0 | if ( type == BOOT_ACPI && acpi_disabled ) |
143 | 0 | type = BOOT_KBD; |
144 | 0 |
|
145 | 0 | if ( reboot_type != type ) |
146 | 0 | { |
147 | 0 | static const char *__initdata msg[] = |
148 | 0 | { |
149 | 0 | [BOOT_KBD] = "keyboard controller", |
150 | 0 | [BOOT_ACPI] = "ACPI", |
151 | 0 | [BOOT_CF9] = "PCI", |
152 | 0 | }; |
153 | 0 |
|
154 | 0 | reboot_type = type; |
155 | 0 | ASSERT(type >= 0 && type < ARRAY_SIZE(msg) && msg[type]); |
156 | 0 | printk("%s series board detected. Selecting %s reboot method.\n", |
157 | 0 | d->ident, msg[type]); |
158 | 0 | } |
159 | 0 | return 0; |
160 | 0 | } |
161 | | |
162 | | static struct dmi_system_id __initdata reboot_dmi_table[] = { |
163 | | { /* Handle problems with rebooting on Dell E520's */ |
164 | | .callback = override_reboot, |
165 | | .driver_data = (void *)(long)BOOT_KBD, |
166 | | .ident = "Dell E520", |
167 | | .matches = { |
168 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
169 | | DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), |
170 | | }, |
171 | | }, |
172 | | { /* Handle problems with rebooting on Dell 1300's */ |
173 | | .callback = override_reboot, |
174 | | .driver_data = (void *)(long)BOOT_KBD, |
175 | | .ident = "Dell PowerEdge 1300", |
176 | | .matches = { |
177 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
178 | | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), |
179 | | }, |
180 | | }, |
181 | | { /* Handle problems with rebooting on Dell 300's */ |
182 | | .callback = override_reboot, |
183 | | .driver_data = (void *)(long)BOOT_KBD, |
184 | | .ident = "Dell PowerEdge 300", |
185 | | .matches = { |
186 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
187 | | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), |
188 | | }, |
189 | | }, |
190 | | { /* Handle problems with rebooting on Dell Optiplex 745's SFF */ |
191 | | .callback = override_reboot, |
192 | | .driver_data = (void *)(long)BOOT_KBD, |
193 | | .ident = "Dell OptiPlex 745", |
194 | | .matches = { |
195 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
196 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), |
197 | | }, |
198 | | }, |
199 | | { /* Handle problems with rebooting on Dell Optiplex 745's DFF */ |
200 | | .callback = override_reboot, |
201 | | .driver_data = (void *)(long)BOOT_KBD, |
202 | | .ident = "Dell OptiPlex 745", |
203 | | .matches = { |
204 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
205 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), |
206 | | DMI_MATCH(DMI_BOARD_NAME, "0MM599"), |
207 | | }, |
208 | | }, |
209 | | { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ |
210 | | .callback = override_reboot, |
211 | | .driver_data = (void *)(long)BOOT_KBD, |
212 | | .ident = "Dell OptiPlex 745", |
213 | | .matches = { |
214 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
215 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), |
216 | | DMI_MATCH(DMI_BOARD_NAME, "0KW626"), |
217 | | }, |
218 | | }, |
219 | | { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ |
220 | | .callback = override_reboot, |
221 | | .driver_data = (void *)(long)BOOT_KBD, |
222 | | .ident = "Dell OptiPlex 330", |
223 | | .matches = { |
224 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
225 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), |
226 | | DMI_MATCH(DMI_BOARD_NAME, "0KP561"), |
227 | | }, |
228 | | }, |
229 | | { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ |
230 | | .callback = override_reboot, |
231 | | .driver_data = (void *)(long)BOOT_KBD, |
232 | | .ident = "Dell OptiPlex 360", |
233 | | .matches = { |
234 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
235 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), |
236 | | DMI_MATCH(DMI_BOARD_NAME, "0T656F"), |
237 | | }, |
238 | | }, |
239 | | { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */ |
240 | | .callback = override_reboot, |
241 | | .driver_data = (void *)(long)BOOT_KBD, |
242 | | .ident = "Dell OptiPlex 760", |
243 | | .matches = { |
244 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
245 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"), |
246 | | DMI_MATCH(DMI_BOARD_NAME, "0G919G"), |
247 | | }, |
248 | | }, |
249 | | { /* Handle problems with rebooting on Dell 2400's */ |
250 | | .callback = override_reboot, |
251 | | .driver_data = (void *)(long)BOOT_KBD, |
252 | | .ident = "Dell PowerEdge 2400", |
253 | | .matches = { |
254 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
255 | | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), |
256 | | }, |
257 | | }, |
258 | | { /* Handle problems with rebooting on Dell T5400's */ |
259 | | .callback = override_reboot, |
260 | | .driver_data = (void *)(long)BOOT_KBD, |
261 | | .ident = "Dell Precision T5400", |
262 | | .matches = { |
263 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
264 | | DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), |
265 | | }, |
266 | | }, |
267 | | { /* Handle problems with rebooting on Dell T7400's */ |
268 | | .callback = override_reboot, |
269 | | .driver_data = (void *)(long)BOOT_KBD, |
270 | | .ident = "Dell Precision T7400", |
271 | | .matches = { |
272 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
273 | | DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"), |
274 | | }, |
275 | | }, |
276 | | { /* Handle problems with rebooting on HP laptops */ |
277 | | .callback = override_reboot, |
278 | | .driver_data = (void *)(long)BOOT_KBD, |
279 | | .ident = "HP Compaq Laptop", |
280 | | .matches = { |
281 | | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
282 | | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), |
283 | | }, |
284 | | }, |
285 | | { /* Handle problems with rebooting on Dell XPS710 */ |
286 | | .callback = override_reboot, |
287 | | .driver_data = (void *)(long)BOOT_KBD, |
288 | | .ident = "Dell XPS710", |
289 | | .matches = { |
290 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
291 | | DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), |
292 | | }, |
293 | | }, |
294 | | { /* Handle problems with rebooting on Dell DXP061 */ |
295 | | .callback = override_reboot, |
296 | | .driver_data = (void *)(long)BOOT_KBD, |
297 | | .ident = "Dell DXP061", |
298 | | .matches = { |
299 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
300 | | DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), |
301 | | }, |
302 | | }, |
303 | | { /* Handle problems with rebooting on Sony VGN-Z540N */ |
304 | | .callback = override_reboot, |
305 | | .driver_data = (void *)(long)BOOT_KBD, |
306 | | .ident = "Sony VGN-Z540N", |
307 | | .matches = { |
308 | | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
309 | | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), |
310 | | }, |
311 | | }, |
312 | | { /* Handle problems with rebooting on ASUS P4S800 */ |
313 | | .callback = override_reboot, |
314 | | .driver_data = (void *)(long)BOOT_KBD, |
315 | | .ident = "ASUS P4S800", |
316 | | .matches = { |
317 | | DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), |
318 | | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), |
319 | | }, |
320 | | }, |
321 | | { /* Handle reboot issue on Acer Aspire one */ |
322 | | .callback = override_reboot, |
323 | | .driver_data = (void *)(long)BOOT_KBD, |
324 | | .ident = "Acer Aspire One A110", |
325 | | .matches = { |
326 | | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
327 | | DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), |
328 | | }, |
329 | | }, |
330 | | { /* Handle problems with rebooting on Apple MacBook5 */ |
331 | | .callback = override_reboot, |
332 | | .driver_data = (void *)(long)BOOT_CF9, |
333 | | .ident = "Apple MacBook5", |
334 | | .matches = { |
335 | | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
336 | | DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"), |
337 | | }, |
338 | | }, |
339 | | { /* Handle problems with rebooting on Apple MacBookPro5 */ |
340 | | .callback = override_reboot, |
341 | | .driver_data = (void *)(long)BOOT_CF9, |
342 | | .ident = "Apple MacBookPro5", |
343 | | .matches = { |
344 | | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
345 | | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"), |
346 | | }, |
347 | | }, |
348 | | { /* Handle problems with rebooting on Apple Macmini3,1 */ |
349 | | .callback = override_reboot, |
350 | | .driver_data = (void *)(long)BOOT_CF9, |
351 | | .ident = "Apple Macmini3,1", |
352 | | .matches = { |
353 | | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
354 | | DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"), |
355 | | }, |
356 | | }, |
357 | | { /* Handle problems with rebooting on the iMac9,1. */ |
358 | | .callback = override_reboot, |
359 | | .driver_data = (void *)(long)BOOT_CF9, |
360 | | .ident = "Apple iMac9,1", |
361 | | .matches = { |
362 | | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
363 | | DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), |
364 | | }, |
365 | | }, |
366 | | { /* Handle problems with rebooting on the Latitude E6320. */ |
367 | | .callback = override_reboot, |
368 | | .driver_data = (void *)(long)BOOT_CF9, |
369 | | .ident = "Dell Latitude E6320", |
370 | | .matches = { |
371 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
372 | | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), |
373 | | }, |
374 | | }, |
375 | | { /* Handle problems with rebooting on the Latitude E5420. */ |
376 | | .callback = override_reboot, |
377 | | .driver_data = (void *)(long)BOOT_CF9, |
378 | | .ident = "Dell Latitude E5420", |
379 | | .matches = { |
380 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
381 | | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), |
382 | | }, |
383 | | }, |
384 | | { /* Handle problems with rebooting on the Latitude E6220. */ |
385 | | .callback = override_reboot, |
386 | | .driver_data = (void *)(long)BOOT_CF9, |
387 | | .ident = "Dell Latitude E6220", |
388 | | .matches = { |
389 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
390 | | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6220"), |
391 | | }, |
392 | | }, |
393 | | { /* Handle problems with rebooting on the Latitude E6420. */ |
394 | | .callback = override_reboot, |
395 | | .driver_data = (void *)(long)BOOT_CF9, |
396 | | .ident = "Dell Latitude E6420", |
397 | | .matches = { |
398 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
399 | | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), |
400 | | }, |
401 | | }, |
402 | | { /* Handle problems with rebooting on the OptiPlex 990. */ |
403 | | .callback = override_reboot, |
404 | | .driver_data = (void *)(long)BOOT_CF9, |
405 | | .ident = "Dell OptiPlex 990", |
406 | | .matches = { |
407 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
408 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), |
409 | | }, |
410 | | }, |
411 | | { /* Handle problems with rebooting on the Precision M6600. */ |
412 | | .callback = override_reboot, |
413 | | .driver_data = (void *)(long)BOOT_CF9, |
414 | | .ident = "Dell OptiPlex 990", |
415 | | .matches = { |
416 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
417 | | DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"), |
418 | | }, |
419 | | }, |
420 | | { /* Handle problems with rebooting on the Latitude E6520. */ |
421 | | .callback = override_reboot, |
422 | | .driver_data = (void *)(long)BOOT_CF9, |
423 | | .ident = "Dell Latitude E6520", |
424 | | .matches = { |
425 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
426 | | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6520"), |
427 | | }, |
428 | | }, |
429 | | { /* Handle problems with rebooting on the OptiPlex 790. */ |
430 | | .callback = override_reboot, |
431 | | .driver_data = (void *)(long)BOOT_CF9, |
432 | | .ident = "Dell OptiPlex 790", |
433 | | .matches = { |
434 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
435 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 790"), |
436 | | }, |
437 | | }, |
438 | | { /* Handle problems with rebooting on the OptiPlex 990. */ |
439 | | .callback = override_reboot, |
440 | | .driver_data = (void *)(long)BOOT_CF9, |
441 | | .ident = "Dell OptiPlex 990", |
442 | | .matches = { |
443 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
444 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), |
445 | | }, |
446 | | }, |
447 | | { /* Handle problems with rebooting on the OptiPlex 390. */ |
448 | | .callback = override_reboot, |
449 | | .driver_data = (void *)(long)BOOT_CF9, |
450 | | .ident = "Dell OptiPlex 390", |
451 | | .matches = { |
452 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
453 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 390"), |
454 | | }, |
455 | | }, |
456 | | { /* Handle problems with rebooting on Dell OptiPlex 9020. */ |
457 | | .callback = override_reboot, |
458 | | .driver_data = (void *)(long)BOOT_ACPI, |
459 | | .ident = "Dell OptiPlex 9020", |
460 | | .matches = { |
461 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
462 | | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020"), |
463 | | }, |
464 | | }, |
465 | | { /* Handle problems with rebooting on the Latitude E6320. */ |
466 | | .callback = override_reboot, |
467 | | .driver_data = (void *)(long)BOOT_CF9, |
468 | | .ident = "Dell Latitude E6320", |
469 | | .matches = { |
470 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
471 | | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), |
472 | | }, |
473 | | }, |
474 | | { /* Handle problems with rebooting on the Latitude E6420. */ |
475 | | .callback = override_reboot, |
476 | | .driver_data = (void *)(long)BOOT_CF9, |
477 | | .ident = "Dell Latitude E6420", |
478 | | .matches = { |
479 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
480 | | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), |
481 | | }, |
482 | | }, |
483 | | { /* Handle problems with rebooting on the Latitude E6520. */ |
484 | | .callback = override_reboot, |
485 | | .driver_data = (void *)(long)BOOT_CF9, |
486 | | .ident = "Dell Latitude E6520", |
487 | | .matches = { |
488 | | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
489 | | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6520"), |
490 | | }, |
491 | | }, |
492 | | { } |
493 | | }; |
494 | | |
495 | | static int __init reboot_init(void) |
496 | 1 | { |
497 | 1 | /* |
498 | 1 | * Only do the DMI check if reboot_type hasn't been overridden |
499 | 1 | * on the command line |
500 | 1 | */ |
501 | 1 | if ( reboot_type != BOOT_INVALID ) |
502 | 0 | return 0; |
503 | 1 | |
504 | 1 | default_reboot_type(); |
505 | 1 | dmi_check_system(reboot_dmi_table); |
506 | 1 | return 0; |
507 | 1 | } |
508 | | __initcall(reboot_init); |
509 | | |
510 | | static void noreturn __machine_restart(void *pdelay) |
511 | 0 | { |
512 | 0 | machine_restart(*(unsigned int *)pdelay); |
513 | 0 | } |
514 | | |
515 | | void machine_restart(unsigned int delay_millisecs) |
516 | 0 | { |
517 | 0 | unsigned int i, attempt; |
518 | 0 | enum reboot_type orig_reboot_type; |
519 | 0 | const struct desc_ptr no_idt = { 0 }; |
520 | 0 |
|
521 | 0 | watchdog_disable(); |
522 | 0 | console_start_sync(); |
523 | 0 | spin_debug_disable(); |
524 | 0 |
|
525 | 0 | /* |
526 | 0 | * We may be called from an interrupt context, and various functions we |
527 | 0 | * may need to call (alloc_domheap_pages, map_domain_page, ...) assert that |
528 | 0 | * they are not called from interrupt context. This hack keeps them happy. |
529 | 0 | */ |
530 | 0 | local_irq_count(0) = 0; |
531 | 0 |
|
532 | 0 | if ( system_state >= SYS_STATE_smp_boot ) |
533 | 0 | { |
534 | 0 | local_irq_enable(); |
535 | 0 |
|
536 | 0 | /* Ensure we are the boot CPU. */ |
537 | 0 | if ( get_apic_id() != boot_cpu_physical_apicid ) |
538 | 0 | { |
539 | 0 | /* Send IPI to the boot CPU (logical cpu 0). */ |
540 | 0 | on_selected_cpus(cpumask_of(0), __machine_restart, |
541 | 0 | &delay_millisecs, 0); |
542 | 0 | for ( ; ; ) |
543 | 0 | halt(); |
544 | 0 | } |
545 | 0 |
|
546 | 0 | smp_send_stop(); |
547 | 0 | } |
548 | 0 |
|
549 | 0 | mdelay(delay_millisecs); |
550 | 0 |
|
551 | 0 | if ( tboot_in_measured_env() ) |
552 | 0 | { |
553 | 0 | acpi_dmar_reinstate(); |
554 | 0 | tboot_shutdown(TB_SHUTDOWN_REBOOT); |
555 | 0 | } |
556 | 0 |
|
557 | 0 | /* Just in case reboot_init() didn't run yet. */ |
558 | 0 | default_reboot_type(); |
559 | 0 | orig_reboot_type = reboot_type; |
560 | 0 |
|
561 | 0 | /* Rebooting needs to touch the page at absolute address 0. */ |
562 | 0 | if ( reboot_type != BOOT_EFI ) |
563 | 0 | *((unsigned short *)__va(0x472)) = reboot_mode; |
564 | 0 |
|
565 | 0 | for ( attempt = 0; ; attempt++ ) |
566 | 0 | { |
567 | 0 | switch ( reboot_type ) |
568 | 0 | { |
569 | 0 | case BOOT_INVALID: |
570 | 0 | ASSERT_UNREACHABLE(); |
571 | 0 | /* fall through */ |
572 | 0 | case BOOT_KBD: |
573 | 0 | /* Pulse the keyboard reset line. */ |
574 | 0 | for ( i = 0; i < 100; i++ ) |
575 | 0 | { |
576 | 0 | kb_wait(); |
577 | 0 | udelay(50); |
578 | 0 | outb(0xfe,0x64); /* pulse reset low */ |
579 | 0 | udelay(50); |
580 | 0 | } |
581 | 0 | /* |
582 | 0 | * If this platform supports ACPI reset, we follow a Windows-style |
583 | 0 | * reboot attempt sequence: |
584 | 0 | * ACPI -> KBD -> ACPI -> KBD |
585 | 0 | * After this we revert to our usual sequence: |
586 | 0 | * KBD -> TRIPLE -> KBD -> TRIPLE -> KBD -> ... |
587 | 0 | */ |
588 | 0 | reboot_type = (((attempt == 1) && (orig_reboot_type == BOOT_ACPI)) |
589 | 0 | ? BOOT_ACPI : BOOT_TRIPLE); |
590 | 0 | break; |
591 | 0 | case BOOT_EFI: |
592 | 0 | reboot_type = acpi_disabled ? BOOT_KBD : BOOT_ACPI; |
593 | 0 | efi_reset_system(reboot_mode != 0); |
594 | 0 | *((unsigned short *)__va(0x472)) = reboot_mode; |
595 | 0 | break; |
596 | 0 | case BOOT_TRIPLE: |
597 | 0 | asm volatile ("lidt %0; int3" : : "m" (no_idt)); |
598 | 0 | reboot_type = BOOT_KBD; |
599 | 0 | break; |
600 | 0 | case BOOT_ACPI: |
601 | 0 | acpi_reboot(); |
602 | 0 | reboot_type = BOOT_KBD; |
603 | 0 | break; |
604 | 0 | case BOOT_CF9: |
605 | 0 | case BOOT_CF9_PWR: |
606 | 0 | { |
607 | 0 | u8 cf9 = inb(0xcf9) & ~0x0e; |
608 | 0 |
|
609 | 0 | /* Request warm, hard, or power-cycle reset. */ |
610 | 0 | if ( reboot_type == BOOT_CF9_PWR ) |
611 | 0 | cf9 |= 0x0a; |
612 | 0 | else if ( reboot_mode == 0 ) |
613 | 0 | cf9 |= 0x02; |
614 | 0 | outb(cf9, 0xcf9); |
615 | 0 | udelay(50); |
616 | 0 | outb(cf9 | 0x04, 0xcf9); /* Actually do the reset. */ |
617 | 0 | udelay(50); |
618 | 0 | } |
619 | 0 | reboot_type = BOOT_ACPI; |
620 | 0 | break; |
621 | 0 | } |
622 | 0 | } |
623 | 0 | } |
624 | | |
625 | | /* |
626 | | * Local variables: |
627 | | * mode: C |
628 | | * c-file-style: "BSD" |
629 | | * c-basic-offset: 4 |
630 | | * tab-width: 4 |
631 | | * indent-tabs-mode: nil |
632 | | * End: |
633 | | */ |