]>
Commit | Line | Data |
---|---|---|
a8ebf6d1 FY |
1 | /* |
2 | * X86 CPU microcode early update for Linux | |
3 | * | |
4 | * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> | |
5 | * H Peter Anvin" <hpa@zytor.com> | |
6 | * | |
7 | * This driver allows to early upgrade microcode on Intel processors | |
8 | * belonging to IA-32 family - PentiumPro, Pentium II, | |
9 | * Pentium III, Xeon, Pentium 4, etc. | |
10 | * | |
11 | * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture | |
12 | * Software Developer's Manual. | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or | |
15 | * modify it under the terms of the GNU General Public License | |
16 | * as published by the Free Software Foundation; either version | |
17 | * 2 of the License, or (at your option) any later version. | |
18 | */ | |
19 | #include <linux/module.h> | |
20 | #include <asm/microcode_intel.h> | |
757885e9 | 21 | #include <asm/microcode_amd.h> |
a8ebf6d1 FY |
22 | #include <asm/processor.h> |
23 | ||
24 | #define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24)) | |
25 | #define CPUID_INTEL1 QCHAR('G', 'e', 'n', 'u') | |
26 | #define CPUID_INTEL2 QCHAR('i', 'n', 'e', 'I') | |
27 | #define CPUID_INTEL3 QCHAR('n', 't', 'e', 'l') | |
28 | #define CPUID_AMD1 QCHAR('A', 'u', 't', 'h') | |
29 | #define CPUID_AMD2 QCHAR('e', 'n', 't', 'i') | |
30 | #define CPUID_AMD3 QCHAR('c', 'A', 'M', 'D') | |
31 | ||
32 | #define CPUID_IS(a, b, c, ebx, ecx, edx) \ | |
33 | (!((ebx ^ (a))|(edx ^ (b))|(ecx ^ (c)))) | |
34 | ||
35 | /* | |
36 | * In early loading microcode phase on BSP, boot_cpu_data is not set up yet. | |
37 | * x86_vendor() gets vendor id for BSP. | |
38 | * | |
39 | * In 32 bit AP case, accessing boot_cpu_data needs linear address. To simplify | |
40 | * coding, we still use x86_vendor() to get vendor id for AP. | |
41 | * | |
42 | * x86_vendor() gets vendor information directly through cpuid. | |
43 | */ | |
44 | static int __cpuinit x86_vendor(void) | |
45 | { | |
46 | u32 eax = 0x00000000; | |
47 | u32 ebx, ecx = 0, edx; | |
48 | ||
a8ebf6d1 FY |
49 | native_cpuid(&eax, &ebx, &ecx, &edx); |
50 | ||
51 | if (CPUID_IS(CPUID_INTEL1, CPUID_INTEL2, CPUID_INTEL3, ebx, ecx, edx)) | |
52 | return X86_VENDOR_INTEL; | |
53 | ||
54 | if (CPUID_IS(CPUID_AMD1, CPUID_AMD2, CPUID_AMD3, ebx, ecx, edx)) | |
55 | return X86_VENDOR_AMD; | |
56 | ||
57 | return X86_VENDOR_UNKNOWN; | |
58 | } | |
59 | ||
74c3e3fc PA |
60 | static int __cpuinit x86_family(void) |
61 | { | |
62 | u32 eax = 0x00000001; | |
63 | u32 ebx, ecx = 0, edx; | |
64 | int x86; | |
65 | ||
66 | native_cpuid(&eax, &ebx, &ecx, &edx); | |
67 | ||
68 | x86 = (eax >> 8) & 0xf; | |
69 | if (x86 == 15) | |
70 | x86 += (eax >> 20) & 0xff; | |
71 | ||
72 | return x86; | |
73 | } | |
74 | ||
a8ebf6d1 FY |
75 | void __init load_ucode_bsp(void) |
76 | { | |
74c3e3fc PA |
77 | int vendor, x86; |
78 | ||
79 | if (!have_cpuid_p()) | |
80 | return; | |
a8ebf6d1 | 81 | |
74c3e3fc PA |
82 | vendor = x86_vendor(); |
83 | x86 = x86_family(); | |
84 | ||
757885e9 JS |
85 | switch (vendor) { |
86 | case X86_VENDOR_INTEL: | |
87 | if (x86 >= 6) | |
88 | load_ucode_intel_bsp(); | |
89 | break; | |
90 | case X86_VENDOR_AMD: | |
91 | if (x86 >= 0x10) | |
92 | load_ucode_amd_bsp(); | |
93 | break; | |
94 | default: | |
95 | break; | |
96 | } | |
a8ebf6d1 FY |
97 | } |
98 | ||
99 | void __cpuinit load_ucode_ap(void) | |
100 | { | |
74c3e3fc PA |
101 | int vendor, x86; |
102 | ||
103 | if (!have_cpuid_p()) | |
104 | return; | |
105 | ||
106 | vendor = x86_vendor(); | |
107 | x86 = x86_family(); | |
a8ebf6d1 | 108 | |
757885e9 JS |
109 | switch (vendor) { |
110 | case X86_VENDOR_INTEL: | |
111 | if (x86 >= 6) | |
112 | load_ucode_intel_ap(); | |
113 | break; | |
114 | case X86_VENDOR_AMD: | |
115 | if (x86 >= 0x10) | |
116 | load_ucode_amd_ap(); | |
117 | break; | |
118 | default: | |
119 | break; | |
120 | } | |
a8ebf6d1 | 121 | } |
f2b3ee82 JS |
122 | |
123 | int __init save_microcode_in_initrd(void) | |
124 | { | |
125 | struct cpuinfo_x86 *c = &boot_cpu_data; | |
126 | ||
757885e9 JS |
127 | switch (c->x86_vendor) { |
128 | case X86_VENDOR_INTEL: | |
129 | if (c->x86 >= 6) | |
130 | save_microcode_in_initrd_intel(); | |
131 | break; | |
132 | case X86_VENDOR_AMD: | |
133 | if (c->x86 >= 0x10) | |
134 | save_microcode_in_initrd_amd(); | |
135 | break; | |
136 | default: | |
137 | break; | |
138 | } | |
f2b3ee82 JS |
139 | |
140 | return 0; | |
141 | } |