x86, microcode, AMD: Exit early on success
[deliverable/linux.git] / arch / x86 / kernel / microcode_amd.c
CommitLineData
80cc9f10
PO
1/*
2 * AMD CPU Microcode Update Driver for Linux
3 * Copyright (C) 2008 Advanced Micro Devices Inc.
4 *
5 * Author: Peter Oruba <peter.oruba@amd.com>
6 *
7 * Based on work by:
8 * Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
9 *
10 * This driver allows to upgrade microcode on AMD
11 * family 0x10 and 0x11 processors.
12 *
2a3282a7 13 * Licensed under the terms of the GNU General Public
80cc9f10 14 * License version 2. See file COPYING for details.
4bae1967 15 */
f58e1f53
JP
16
17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
4bae1967 19#include <linux/firmware.h>
4bae1967
IM
20#include <linux/pci_ids.h>
21#include <linux/uaccess.h>
22#include <linux/vmalloc.h>
23#include <linux/kernel.h>
24#include <linux/module.h>
80cc9f10 25#include <linux/pci.h>
80cc9f10 26
80cc9f10 27#include <asm/microcode.h>
4bae1967
IM
28#include <asm/processor.h>
29#include <asm/msr.h>
80cc9f10
PO
30
31MODULE_DESCRIPTION("AMD Microcode Update Driver");
3c52204b 32MODULE_AUTHOR("Peter Oruba");
5d7b6052 33MODULE_LICENSE("GPL v2");
80cc9f10
PO
34
35#define UCODE_MAGIC 0x00414d44
36#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
37#define UCODE_UCODE_TYPE 0x00000001
38
18dbc916 39struct equiv_cpu_entry {
5549b94b
AH
40 u32 installed_cpu;
41 u32 fixed_errata_mask;
42 u32 fixed_errata_compare;
43 u16 equiv_cpu;
44 u16 res;
45} __attribute__((packed));
18dbc916
DA
46
47struct microcode_header_amd {
5549b94b
AH
48 u32 data_code;
49 u32 patch_id;
50 u16 mc_patch_data_id;
51 u8 mc_patch_data_len;
52 u8 init_flag;
53 u32 mc_patch_data_checksum;
54 u32 nb_dev_id;
55 u32 sb_dev_id;
56 u16 processor_rev_id;
57 u8 nb_rev_id;
58 u8 sb_rev_id;
59 u8 bios_api_rev;
60 u8 reserved1[3];
61 u32 match_reg[8];
62} __attribute__((packed));
18dbc916
DA
63
64struct microcode_amd {
4bae1967
IM
65 struct microcode_header_amd hdr;
66 unsigned int mpb[0];
18dbc916
DA
67};
68
40b7f3df
BP
69#define SECTION_HDR_SIZE 8
70#define CONTAINER_HDR_SZ 12
80cc9f10 71
a0a29b62 72static struct equiv_cpu_entry *equiv_cpu_table;
80cc9f10 73
96b0ee45
BP
74/* page-sized ucode patch buffer */
75void *patch;
76
d45de409 77static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
80cc9f10 78{
3b2e3d85 79 struct cpuinfo_x86 *c = &cpu_data(cpu);
80cc9f10 80
3b2e3d85 81 if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
258721ef 82 pr_warning("CPU%d: family %d not supported\n", cpu, c->x86);
3b2e3d85
AH
83 return -1;
84 }
258721ef 85
bcb80e53 86 csig->rev = c->microcode;
258721ef
BP
87 pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev);
88
d45de409 89 return 0;
80cc9f10
PO
90}
91
be62adb4
BP
92static unsigned int verify_ucode_size(int cpu, u32 patch_size,
93 unsigned int size)
80cc9f10 94{
be62adb4
BP
95 struct cpuinfo_x86 *c = &cpu_data(cpu);
96 u32 max_size;
97
98#define F1XH_MPB_MAX_SIZE 2048
99#define F14H_MPB_MAX_SIZE 1824
100#define F15H_MPB_MAX_SIZE 4096
101
102 switch (c->x86) {
103 case 0x14:
104 max_size = F14H_MPB_MAX_SIZE;
105 break;
106 case 0x15:
107 max_size = F15H_MPB_MAX_SIZE;
108 break;
109 default:
110 max_size = F1XH_MPB_MAX_SIZE;
111 break;
112 }
113
114 if (patch_size > min_t(u32, size, max_size)) {
115 pr_err("patch size mismatch\n");
116 return 0;
117 }
118
119 return patch_size;
120}
121
122static u16 find_equiv_id(void)
123{
124 unsigned int current_cpu_id, i = 0;
80cc9f10 125
a0a29b62 126 BUG_ON(equiv_cpu_table == NULL);
be62adb4 127
80cc9f10
PO
128 current_cpu_id = cpuid_eax(0x00000001);
129
130 while (equiv_cpu_table[i].installed_cpu != 0) {
be62adb4
BP
131 if (current_cpu_id == equiv_cpu_table[i].installed_cpu)
132 return equiv_cpu_table[i].equiv_cpu;
133
80cc9f10
PO
134 i++;
135 }
be62adb4
BP
136 return 0;
137}
80cc9f10 138
be62adb4
BP
139/*
140 * we signal a good patch is found by returning its size > 0
141 */
142static int get_matching_microcode(int cpu, const u8 *ucode_ptr,
143 unsigned int leftover_size, int rev,
144 unsigned int *current_size)
145{
146 struct microcode_header_amd *mc_hdr;
147 unsigned int actual_size;
148 u16 equiv_cpu_id;
149
150 /* size of the current patch we're staring at */
151 *current_size = *(u32 *)(ucode_ptr + 4) + SECTION_HDR_SIZE;
152
153 equiv_cpu_id = find_equiv_id();
14c56942 154 if (!equiv_cpu_id)
80cc9f10 155 return 0;
80cc9f10 156
be62adb4
BP
157 /*
158 * let's look at the patch header itself now
159 */
160 mc_hdr = (struct microcode_header_amd *)(ucode_ptr + SECTION_HDR_SIZE);
161
7cc27349 162 if (mc_hdr->processor_rev_id != equiv_cpu_id)
80cc9f10 163 return 0;
80cc9f10 164
98415301 165 /* ucode might be chipset specific -- currently we don't support this */
7cc27349 166 if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
258721ef 167 pr_err("CPU%d: chipset specific code not yet supported\n",
f58e1f53 168 cpu);
98415301 169 return 0;
80cc9f10
PO
170 }
171
7cc27349 172 if (mc_hdr->patch_id <= rev)
80cc9f10
PO
173 return 0;
174
be62adb4
BP
175 /*
176 * now that the header looks sane, verify its size
177 */
178 actual_size = verify_ucode_size(cpu, *current_size, leftover_size);
179 if (!actual_size)
180 return 0;
181
182 /* clear the patch buffer */
183 memset(patch, 0, PAGE_SIZE);
184
185 /* all looks ok, get the binary patch */
186 get_ucode_data(patch, ucode_ptr + SECTION_HDR_SIZE, actual_size);
187
188 return actual_size;
80cc9f10
PO
189}
190
871b72dd 191static int apply_microcode_amd(int cpu)
80cc9f10 192{
29d0887f 193 u32 rev, dummy;
80cc9f10
PO
194 int cpu_num = raw_smp_processor_id();
195 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
18dbc916 196 struct microcode_amd *mc_amd = uci->mc;
bcb80e53 197 struct cpuinfo_x86 *c = &cpu_data(cpu);
80cc9f10
PO
198
199 /* We should bind the task to the CPU */
200 BUG_ON(cpu_num != cpu);
201
18dbc916 202 if (mc_amd == NULL)
871b72dd 203 return 0;
80cc9f10 204
f34a10bd 205 wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
80cc9f10 206 /* get patch id after patching */
29d0887f 207 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
80cc9f10
PO
208
209 /* check current patch id and patch's id for match */
18dbc916 210 if (rev != mc_amd->hdr.patch_id) {
258721ef 211 pr_err("CPU%d: update failed for patch_level=0x%08x\n",
f58e1f53 212 cpu, mc_amd->hdr.patch_id);
871b72dd 213 return -1;
80cc9f10
PO
214 }
215
258721ef 216 pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev);
d45de409 217 uci->cpu_sig.rev = rev;
bcb80e53 218 c->microcode = rev;
871b72dd
DA
219
220 return 0;
80cc9f10
PO
221}
222
0657d9eb 223static int install_equiv_cpu_table(const u8 *buf)
80cc9f10 224{
10de52d6
BP
225 unsigned int *ibuf = (unsigned int *)buf;
226 unsigned int type = ibuf[1];
227 unsigned int size = ibuf[2];
80cc9f10 228
10de52d6 229 if (type != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
258721ef
BP
230 pr_err("empty section/"
231 "invalid type field in container file section header\n");
10de52d6 232 return -EINVAL;
80cc9f10
PO
233 }
234
8e5e9521 235 equiv_cpu_table = vmalloc(size);
80cc9f10 236 if (!equiv_cpu_table) {
f58e1f53 237 pr_err("failed to allocate equivalent CPU table\n");
10de52d6 238 return -ENOMEM;
80cc9f10
PO
239 }
240
40b7f3df 241 get_ucode_data(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size);
80cc9f10 242
40b7f3df
BP
243 /* add header length */
244 return size + CONTAINER_HDR_SZ;
80cc9f10
PO
245}
246
a0a29b62 247static void free_equiv_cpu_table(void)
80cc9f10 248{
aeef50bc
F
249 vfree(equiv_cpu_table);
250 equiv_cpu_table = NULL;
a0a29b62 251}
80cc9f10 252
871b72dd
DA
253static enum ucode_state
254generic_load_microcode(int cpu, const u8 *data, size_t size)
a0a29b62
DA
255{
256 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
7cc27349 257 struct microcode_header_amd *mc_hdr = NULL;
be62adb4 258 unsigned int mc_size, leftover, current_size = 0;
1396fa9c 259 int offset;
8c135206
AH
260 const u8 *ucode_ptr = data;
261 void *new_mc = NULL;
258721ef 262 unsigned int new_rev = uci->cpu_sig.rev;
be62adb4 263 enum ucode_state state = UCODE_ERROR;
80cc9f10 264
0657d9eb 265 offset = install_equiv_cpu_table(ucode_ptr);
10de52d6 266 if (offset < 0) {
f58e1f53 267 pr_err("failed to create equivalent cpu table\n");
be62adb4 268 goto out;
80cc9f10 269 }
a0a29b62
DA
270 ucode_ptr += offset;
271 leftover = size - offset;
272
be62adb4
BP
273 if (*(u32 *)ucode_ptr != UCODE_UCODE_TYPE) {
274 pr_err("invalid type field in container file section header\n");
275 goto free_table;
276 }
a0a29b62 277
be62adb4
BP
278 while (leftover) {
279 mc_size = get_matching_microcode(cpu, ucode_ptr, leftover,
280 new_rev, &current_size);
281 if (mc_size) {
282 mc_hdr = patch;
283 new_mc = patch;
7cc27349 284 new_rev = mc_hdr->patch_id;
d733689a 285 goto out_ok;
be62adb4 286 }
d733689a
BP
287
288 ucode_ptr += current_size;
289 leftover -= current_size;
80cc9f10 290 }
a0a29b62 291
7cc27349 292 if (!new_mc) {
871b72dd 293 state = UCODE_NFOUND;
7cc27349
BP
294 goto free_table;
295 }
296
d733689a
BP
297out_ok:
298 uci->mc = new_mc;
299 state = UCODE_OK;
300 pr_debug("CPU%d update ucode (0x%08x -> 0x%08x)\n",
301 cpu, uci->cpu_sig.rev, new_rev);
a0a29b62 302
7cc27349 303free_table:
a0a29b62
DA
304 free_equiv_cpu_table();
305
be62adb4 306out:
871b72dd 307 return state;
a0a29b62
DA
308}
309
ffc7e8ac 310static enum ucode_state request_microcode_amd(int cpu, struct device *device)
a0a29b62 311{
3b2e3d85 312 const char *fw_name = "amd-ucode/microcode_amd.bin";
ffc7e8ac
BP
313 const struct firmware *fw;
314 enum ucode_state ret = UCODE_NFOUND;
a0a29b62 315
ffc7e8ac 316 if (request_firmware(&fw, fw_name, device)) {
258721ef 317 pr_err("failed to load file %s\n", fw_name);
ffc7e8ac 318 goto out;
3b2e3d85 319 }
a0a29b62 320
ffc7e8ac
BP
321 ret = UCODE_ERROR;
322 if (*(u32 *)fw->data != UCODE_MAGIC) {
258721ef 323 pr_err("invalid magic value (0x%08x)\n", *(u32 *)fw->data);
ffc7e8ac 324 goto fw_release;
506f90ee
BP
325 }
326
ffc7e8ac 327 ret = generic_load_microcode(cpu, fw->data, fw->size);
a0a29b62 328
ffc7e8ac
BP
329fw_release:
330 release_firmware(fw);
3b2e3d85 331
ffc7e8ac 332out:
a0a29b62
DA
333 return ret;
334}
335
871b72dd
DA
336static enum ucode_state
337request_microcode_user(int cpu, const void __user *buf, size_t size)
a0a29b62 338{
f58e1f53 339 pr_info("AMD microcode update via /dev/cpu/microcode not supported\n");
871b72dd 340 return UCODE_ERROR;
80cc9f10
PO
341}
342
80cc9f10
PO
343static void microcode_fini_cpu_amd(int cpu)
344{
345 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
346
18dbc916 347 uci->mc = NULL;
80cc9f10
PO
348}
349
350static struct microcode_ops microcode_amd_ops = {
a0a29b62 351 .request_microcode_user = request_microcode_user,
ffc7e8ac 352 .request_microcode_fw = request_microcode_amd,
80cc9f10
PO
353 .collect_cpu_info = collect_cpu_info_amd,
354 .apply_microcode = apply_microcode_amd,
355 .microcode_fini_cpu = microcode_fini_cpu_amd,
356};
357
18dbc916 358struct microcode_ops * __init init_amd_microcode(void)
80cc9f10 359{
96b0ee45
BP
360 patch = (void *)get_zeroed_page(GFP_KERNEL);
361 if (!patch)
362 return NULL;
363
18dbc916 364 return &microcode_amd_ops;
80cc9f10 365}
f72c1a57
BP
366
367void __exit exit_amd_microcode(void)
368{
96b0ee45 369 free_page((unsigned long)patch);
f72c1a57 370}
This page took 0.212433 seconds and 5 git commands to generate.