]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/x86/kernel/cpu/microcode/intel.c
Merge branch 'fix/dapm' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[karo-tx-linux.git] / arch / x86 / kernel / cpu / microcode / intel.c
1 /*
2  * Intel CPU Microcode Update Driver for Linux
3  *
4  * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
5  *               2006 Shaohua Li <shaohua.li@intel.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version
10  * 2 of the License, or (at your option) any later version.
11  */
12
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15 #include <linux/firmware.h>
16 #include <linux/uaccess.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/vmalloc.h>
20
21 #include <asm/microcode_intel.h>
22 #include <asm/processor.h>
23 #include <asm/msr.h>
24
25 MODULE_DESCRIPTION("Microcode Update Driver");
26 MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
27 MODULE_LICENSE("GPL");
28
29 static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
30 {
31         struct cpuinfo_x86 *c = &cpu_data(cpu_num);
32         unsigned int val[2];
33
34         memset(csig, 0, sizeof(*csig));
35
36         csig->sig = cpuid_eax(0x00000001);
37
38         if ((c->x86_model >= 5) || (c->x86 > 6)) {
39                 /* get processor flags from MSR 0x17 */
40                 rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
41                 csig->pf = 1 << ((val[1] >> 18) & 7);
42         }
43
44         csig->rev = c->microcode;
45         pr_info("CPU%d sig=0x%x, pf=0x%x, revision=0x%x\n",
46                 cpu_num, csig->sig, csig->pf, csig->rev);
47
48         return 0;
49 }
50
51 /*
52  * return 0 - no update found
53  * return 1 - found update
54  */
55 static int get_matching_mc(struct microcode_intel *mc_intel, int cpu)
56 {
57         struct cpu_signature cpu_sig;
58         unsigned int csig, cpf, crev;
59
60         collect_cpu_info(cpu, &cpu_sig);
61
62         csig = cpu_sig.sig;
63         cpf = cpu_sig.pf;
64         crev = cpu_sig.rev;
65
66         return has_newer_microcode(mc_intel, csig, cpf, crev);
67 }
68
69 static int apply_microcode_intel(int cpu)
70 {
71         struct microcode_intel *mc_intel;
72         struct ucode_cpu_info *uci;
73         unsigned int val[2];
74         int cpu_num = raw_smp_processor_id();
75         struct cpuinfo_x86 *c = &cpu_data(cpu_num);
76
77         uci = ucode_cpu_info + cpu;
78         mc_intel = uci->mc;
79
80         /* We should bind the task to the CPU */
81         BUG_ON(cpu_num != cpu);
82
83         if (mc_intel == NULL)
84                 return 0;
85
86         /*
87          * Microcode on this CPU could be updated earlier. Only apply the
88          * microcode patch in mc_intel when it is newer than the one on this
89          * CPU.
90          */
91         if (get_matching_mc(mc_intel, cpu) == 0)
92                 return 0;
93
94         /* write microcode via MSR 0x79 */
95         wrmsr(MSR_IA32_UCODE_WRITE,
96               (unsigned long) mc_intel->bits,
97               (unsigned long) mc_intel->bits >> 16 >> 16);
98         wrmsr(MSR_IA32_UCODE_REV, 0, 0);
99
100         /* As documented in the SDM: Do a CPUID 1 here */
101         sync_core();
102
103         /* get the current revision from MSR 0x8B */
104         rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
105
106         if (val[1] != mc_intel->hdr.rev) {
107                 pr_err("CPU%d update to revision 0x%x failed\n",
108                        cpu_num, mc_intel->hdr.rev);
109                 return -1;
110         }
111         pr_info("CPU%d updated to revision 0x%x, date = %04x-%02x-%02x\n",
112                 cpu_num, val[1],
113                 mc_intel->hdr.date & 0xffff,
114                 mc_intel->hdr.date >> 24,
115                 (mc_intel->hdr.date >> 16) & 0xff);
116
117         uci->cpu_sig.rev = val[1];
118         c->microcode = val[1];
119
120         return 0;
121 }
122
123 static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
124                                 int (*get_ucode_data)(void *, const void *, size_t))
125 {
126         struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
127         u8 *ucode_ptr = data, *new_mc = NULL, *mc = NULL;
128         int new_rev = uci->cpu_sig.rev;
129         unsigned int leftover = size;
130         enum ucode_state state = UCODE_OK;
131         unsigned int curr_mc_size = 0;
132         unsigned int csig, cpf;
133
134         while (leftover) {
135                 struct microcode_header_intel mc_header;
136                 unsigned int mc_size;
137
138                 if (leftover < sizeof(mc_header)) {
139                         pr_err("error! Truncated header in microcode data file\n");
140                         break;
141                 }
142
143                 if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
144                         break;
145
146                 mc_size = get_totalsize(&mc_header);
147                 if (!mc_size || mc_size > leftover) {
148                         pr_err("error! Bad data in microcode data file\n");
149                         break;
150                 }
151
152                 /* For performance reasons, reuse mc area when possible */
153                 if (!mc || mc_size > curr_mc_size) {
154                         vfree(mc);
155                         mc = vmalloc(mc_size);
156                         if (!mc)
157                                 break;
158                         curr_mc_size = mc_size;
159                 }
160
161                 if (get_ucode_data(mc, ucode_ptr, mc_size) ||
162                     microcode_sanity_check(mc, 1) < 0) {
163                         break;
164                 }
165
166                 csig = uci->cpu_sig.sig;
167                 cpf = uci->cpu_sig.pf;
168                 if (has_newer_microcode(mc, csig, cpf, new_rev)) {
169                         vfree(new_mc);
170                         new_rev = mc_header.rev;
171                         new_mc  = mc;
172                         mc = NULL;      /* trigger new vmalloc */
173                 }
174
175                 ucode_ptr += mc_size;
176                 leftover  -= mc_size;
177         }
178
179         vfree(mc);
180
181         if (leftover) {
182                 vfree(new_mc);
183                 state = UCODE_ERROR;
184                 goto out;
185         }
186
187         if (!new_mc) {
188                 state = UCODE_NFOUND;
189                 goto out;
190         }
191
192         vfree(uci->mc);
193         uci->mc = (struct microcode_intel *)new_mc;
194
195         /*
196          * If early loading microcode is supported, save this mc into
197          * permanent memory. So it will be loaded early when a CPU is hot added
198          * or resumes.
199          */
200         save_mc_for_early(new_mc);
201
202         pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
203                  cpu, new_rev, uci->cpu_sig.rev);
204 out:
205         return state;
206 }
207
208 static int get_ucode_fw(void *to, const void *from, size_t n)
209 {
210         memcpy(to, from, n);
211         return 0;
212 }
213
214 static enum ucode_state request_microcode_fw(int cpu, struct device *device,
215                                              bool refresh_fw)
216 {
217         char name[30];
218         struct cpuinfo_x86 *c = &cpu_data(cpu);
219         const struct firmware *firmware;
220         enum ucode_state ret;
221
222         sprintf(name, "intel-ucode/%02x-%02x-%02x",
223                 c->x86, c->x86_model, c->x86_mask);
224
225         if (request_firmware_direct(&firmware, name, device)) {
226                 pr_debug("data file %s load failed\n", name);
227                 return UCODE_NFOUND;
228         }
229
230         ret = generic_load_microcode(cpu, (void *)firmware->data,
231                                      firmware->size, &get_ucode_fw);
232
233         release_firmware(firmware);
234
235         return ret;
236 }
237
238 static int get_ucode_user(void *to, const void *from, size_t n)
239 {
240         return copy_from_user(to, from, n);
241 }
242
243 static enum ucode_state
244 request_microcode_user(int cpu, const void __user *buf, size_t size)
245 {
246         return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user);
247 }
248
249 static void microcode_fini_cpu(int cpu)
250 {
251         struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
252
253         vfree(uci->mc);
254         uci->mc = NULL;
255 }
256
257 static struct microcode_ops microcode_intel_ops = {
258         .request_microcode_user           = request_microcode_user,
259         .request_microcode_fw             = request_microcode_fw,
260         .collect_cpu_info                 = collect_cpu_info,
261         .apply_microcode                  = apply_microcode_intel,
262         .microcode_fini_cpu               = microcode_fini_cpu,
263 };
264
265 struct microcode_ops * __init init_intel_microcode(void)
266 {
267         struct cpuinfo_x86 *c = &cpu_data(0);
268
269         if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
270             cpu_has(c, X86_FEATURE_IA64)) {
271                 pr_err("Intel CPU family 0x%x not supported\n", c->x86);
272                 return NULL;
273         }
274
275         return &microcode_intel_ops;
276 }
277