| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  Copyright (C) 1994  Linus Torvalds | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Cyrix stuff, June 1998 by: | 
					
						
							|  |  |  |  *	- Rafael R. Reilova (moved everything from head.S), | 
					
						
							|  |  |  |  *        <rreilova@ececs.uc.edu> | 
					
						
							|  |  |  |  *	- Channing Corn (tests & fixes), | 
					
						
							|  |  |  |  *	- Andrew D. Balsa (code cleanup). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/utsname.h>
 | 
					
						
							| 
									
										
										
										
											2007-07-31 00:39:20 -07:00
										 |  |  | #include <asm/bugs.h>
 | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | #include <asm/processor.h>
 | 
					
						
							| 
									
										
										
										
											2008-01-30 13:30:39 +01:00
										 |  |  | #include <asm/processor-flags.h>
 | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | #include <asm/i387.h>
 | 
					
						
							|  |  |  | #include <asm/msr.h>
 | 
					
						
							|  |  |  | #include <asm/paravirt.h>
 | 
					
						
							|  |  |  | #include <asm/alternative.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static double __initdata x = 4195835.0; | 
					
						
							|  |  |  | static double __initdata y = 3145727.0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * This used to check for exceptions.. | 
					
						
							|  |  |  |  * However, it turns out that to support that, | 
					
						
							|  |  |  |  * the XMM trap handlers basically had to | 
					
						
							|  |  |  |  * be buggy. So let's have a correct XMM trap | 
					
						
							|  |  |  |  * handler, and forget about printing out | 
					
						
							|  |  |  |  * some status at boot. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * We should really only care about bugs here | 
					
						
							|  |  |  |  * anyway. Not features. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void __init check_fpu(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-31 23:43:44 +02:00
										 |  |  | 	s32 fdiv_bug; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:19:32 -07:00
										 |  |  | 	kernel_fpu_begin(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-17 22:48:13 +02:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * trap_init() enabled FXSR and company _before_ testing for FP | 
					
						
							|  |  |  | 	 * problems here. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2013-03-20 15:07:25 +01:00
										 |  |  | 	 * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug
 | 
					
						
							| 
									
										
										
										
											2008-05-17 22:48:13 +02:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | 	__asm__("fninit\n\t" | 
					
						
							|  |  |  | 		"fldl %1\n\t" | 
					
						
							|  |  |  | 		"fdivl %2\n\t" | 
					
						
							|  |  |  | 		"fmull %2\n\t" | 
					
						
							|  |  |  | 		"fldl %1\n\t" | 
					
						
							|  |  |  | 		"fsubp %%st,%%st(1)\n\t" | 
					
						
							|  |  |  | 		"fistpl %0\n\t" | 
					
						
							|  |  |  | 		"fwait\n\t" | 
					
						
							|  |  |  | 		"fninit" | 
					
						
							| 
									
										
										
										
											2008-07-31 23:43:44 +02:00
										 |  |  | 		: "=m" (*&fdiv_bug) | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | 		: "m" (*&x), "m" (*&y)); | 
					
						
							| 
									
										
										
										
											2008-07-31 23:43:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:19:32 -07:00
										 |  |  | 	kernel_fpu_end(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-20 15:07:25 +01:00
										 |  |  | 	if (fdiv_bug) { | 
					
						
							|  |  |  | 		set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV); | 
					
						
							| 
									
										
										
										
											2012-05-21 19:50:07 -07:00
										 |  |  | 		pr_warn("Hmm, FPU with FDIV bug\n"); | 
					
						
							| 
									
										
										
										
											2013-03-20 15:07:25 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void __init check_bugs(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	identify_boot_cpu(); | 
					
						
							|  |  |  | #ifndef CONFIG_SMP
 | 
					
						
							| 
									
										
										
										
											2012-05-21 19:50:07 -07:00
										 |  |  | 	pr_info("CPU: "); | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | 	print_cpu_info(&boot_cpu_data); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-04-08 17:57:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Check whether we are able to run this kernel safely on SMP. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * - i386 is no longer supported. | 
					
						
							|  |  |  | 	 * - In order to run on anything without a TSC, we need to be | 
					
						
							|  |  |  | 	 *   compiled for a i486. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (boot_cpu_data.x86 < 4) | 
					
						
							|  |  |  | 		panic("Kernel requires i486+ for 'invlpg' and other features"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-17 22:48:13 +02:00
										 |  |  | 	init_utsname()->machine[1] = | 
					
						
							|  |  |  | 		'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86); | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | 	alternative_instructions(); | 
					
						
							| 
									
										
										
										
											2012-08-24 14:13:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * kernel_fpu_begin/end() in check_fpu() relies on the patched | 
					
						
							|  |  |  | 	 * alternative instructions. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2013-04-29 16:04:20 +02:00
										 |  |  | 	if (cpu_has_fpu) | 
					
						
							|  |  |  | 		check_fpu(); | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:12 +02:00
										 |  |  | } |