diff options
| -rw-r--r-- | arch/x86/Kconfig | 20 | ||||
| -rw-r--r-- | arch/x86/include/asm/microcode.h | 10 | ||||
| -rw-r--r-- | arch/x86/kernel/microcode_amd.c | 357 | ||||
| -rw-r--r-- | arch/x86/kernel/microcode_core.c | 67 | ||||
| -rw-r--r-- | arch/x86/kernel/microcode_intel.c | 3 |
5 files changed, 273 insertions, 184 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6cd6f24e1223..943667050dae 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -986,25 +986,25 @@ config X86_REBOOTFIXUPS | |||
| 986 | Say N otherwise. | 986 | Say N otherwise. |
| 987 | 987 | ||
| 988 | config MICROCODE | 988 | config MICROCODE |
| 989 | tristate "/dev/cpu/microcode - microcode support" | 989 | tristate "CPU microcode loading support" |
| 990 | select FW_LOADER | 990 | select FW_LOADER |
| 991 | ---help--- | 991 | ---help--- |
| 992 | |||
| 992 | If you say Y here, you will be able to update the microcode on | 993 | If you say Y here, you will be able to update the microcode on |
| 993 | certain Intel and AMD processors. The Intel support is for the | 994 | certain Intel and AMD processors. The Intel support is for the |
| 994 | IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, | 995 | IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4, |
| 995 | Pentium 4, Xeon etc. The AMD support is for family 0x10 and | 996 | Xeon etc. The AMD support is for families 0x10 and later. You will |
| 996 | 0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra. | 997 | obviously need the actual microcode binary data itself which is not |
| 997 | You will obviously need the actual microcode binary data itself | 998 | shipped with the Linux kernel. |
| 998 | which is not shipped with the Linux kernel. | ||
| 999 | 999 | ||
| 1000 | This option selects the general module only, you need to select | 1000 | This option selects the general module only, you need to select |
| 1001 | at least one vendor specific module as well. | 1001 | at least one vendor specific module as well. |
| 1002 | 1002 | ||
| 1003 | To compile this driver as a module, choose M here: the | 1003 | To compile this driver as a module, choose M here: the module |
| 1004 | module will be called microcode. | 1004 | will be called microcode. |
| 1005 | 1005 | ||
| 1006 | config MICROCODE_INTEL | 1006 | config MICROCODE_INTEL |
| 1007 | bool "Intel microcode patch loading support" | 1007 | bool "Intel microcode loading support" |
| 1008 | depends on MICROCODE | 1008 | depends on MICROCODE |
| 1009 | default MICROCODE | 1009 | default MICROCODE |
| 1010 | select FW_LOADER | 1010 | select FW_LOADER |
| @@ -1017,7 +1017,7 @@ config MICROCODE_INTEL | |||
| 1017 | <http://www.urbanmyth.org/microcode/>. | 1017 | <http://www.urbanmyth.org/microcode/>. |
| 1018 | 1018 | ||
| 1019 | config MICROCODE_AMD | 1019 | config MICROCODE_AMD |
| 1020 | bool "AMD microcode patch loading support" | 1020 | bool "AMD microcode loading support" |
| 1021 | depends on MICROCODE | 1021 | depends on MICROCODE |
| 1022 | select FW_LOADER | 1022 | select FW_LOADER |
| 1023 | ---help--- | 1023 | ---help--- |
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 4ebe157bf73d..43d921b4752c 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h | |||
| @@ -15,8 +15,8 @@ struct microcode_ops { | |||
| 15 | enum ucode_state (*request_microcode_user) (int cpu, | 15 | enum ucode_state (*request_microcode_user) (int cpu, |
| 16 | const void __user *buf, size_t size); | 16 | const void __user *buf, size_t size); |
| 17 | 17 | ||
| 18 | enum ucode_state (*request_microcode_fw) (int cpu, | 18 | enum ucode_state (*request_microcode_fw) (int cpu, struct device *, |
| 19 | struct device *device); | 19 | bool refresh_fw); |
| 20 | 20 | ||
| 21 | void (*microcode_fini_cpu) (int cpu); | 21 | void (*microcode_fini_cpu) (int cpu); |
| 22 | 22 | ||
| @@ -49,12 +49,6 @@ static inline struct microcode_ops * __init init_intel_microcode(void) | |||
| 49 | #ifdef CONFIG_MICROCODE_AMD | 49 | #ifdef CONFIG_MICROCODE_AMD |
| 50 | extern struct microcode_ops * __init init_amd_microcode(void); | 50 | extern struct microcode_ops * __init init_amd_microcode(void); |
| 51 | extern void __exit exit_amd_microcode(void); | 51 | extern void __exit exit_amd_microcode(void); |
| 52 | |||
| 53 | static inline void get_ucode_data(void *to, const u8 *from, size_t n) | ||
| 54 | { | ||
| 55 | memcpy(to, from, n); | ||
| 56 | } | ||
| 57 | |||
| 58 | #else | 52 | #else |
| 59 | static inline struct microcode_ops * __init init_amd_microcode(void) | 53 | static inline struct microcode_ops * __init init_amd_microcode(void) |
| 60 | { | 54 | { |
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 82746f942cd8..7720ff5a9ee2 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c | |||
| @@ -75,20 +75,113 @@ struct microcode_amd { | |||
| 75 | 75 | ||
| 76 | static struct equiv_cpu_entry *equiv_cpu_table; | 76 | static struct equiv_cpu_entry *equiv_cpu_table; |
| 77 | 77 | ||
| 78 | /* page-sized ucode patch buffer */ | 78 | struct ucode_patch { |
| 79 | void *patch; | 79 | struct list_head plist; |
| 80 | void *data; | ||
| 81 | u32 patch_id; | ||
| 82 | u16 equiv_cpu; | ||
| 83 | }; | ||
| 84 | |||
| 85 | static LIST_HEAD(pcache); | ||
| 86 | |||
| 87 | static u16 find_equiv_id(unsigned int cpu) | ||
| 88 | { | ||
| 89 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
| 90 | int i = 0; | ||
| 91 | |||
| 92 | if (!equiv_cpu_table) | ||
| 93 | return 0; | ||
| 94 | |||
| 95 | while (equiv_cpu_table[i].installed_cpu != 0) { | ||
| 96 | if (uci->cpu_sig.sig == equiv_cpu_table[i].installed_cpu) | ||
| 97 | return equiv_cpu_table[i].equiv_cpu; | ||
| 98 | |||
| 99 | i++; | ||
| 100 | } | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu) | ||
| 105 | { | ||
| 106 | int i = 0; | ||
| 107 | |||
| 108 | BUG_ON(!equiv_cpu_table); | ||
| 109 | |||
| 110 | while (equiv_cpu_table[i].equiv_cpu != 0) { | ||
| 111 | if (equiv_cpu == equiv_cpu_table[i].equiv_cpu) | ||
| 112 | return equiv_cpu_table[i].installed_cpu; | ||
| 113 | i++; | ||
| 114 | } | ||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | /* | ||
| 119 | * a small, trivial cache of per-family ucode patches | ||
| 120 | */ | ||
| 121 | static struct ucode_patch *cache_find_patch(u16 equiv_cpu) | ||
| 122 | { | ||
| 123 | struct ucode_patch *p; | ||
| 124 | |||
| 125 | list_for_each_entry(p, &pcache, plist) | ||
| 126 | if (p->equiv_cpu == equiv_cpu) | ||
| 127 | return p; | ||
| 128 | return NULL; | ||
| 129 | } | ||
| 130 | |||
| 131 | static void update_cache(struct ucode_patch *new_patch) | ||
| 132 | { | ||
| 133 | struct ucode_patch *p; | ||
| 134 | |||
| 135 | list_for_each_entry(p, &pcache, plist) { | ||
| 136 | if (p->equiv_cpu == new_patch->equiv_cpu) { | ||
| 137 | if (p->patch_id >= new_patch->patch_id) | ||
| 138 | /* we already have the latest patch */ | ||
| 139 | return; | ||
| 140 | |||
| 141 | list_replace(&p->plist, &new_patch->plist); | ||
| 142 | kfree(p->data); | ||
| 143 | kfree(p); | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | /* no patch found, add it */ | ||
| 148 | list_add_tail(&new_patch->plist, &pcache); | ||
| 149 | } | ||
| 150 | |||
| 151 | static void free_cache(void) | ||
| 152 | { | ||
| 153 | struct ucode_patch *p, *tmp; | ||
| 154 | |||
| 155 | list_for_each_entry_safe(p, tmp, &pcache, plist) { | ||
| 156 | __list_del(p->plist.prev, p->plist.next); | ||
| 157 | kfree(p->data); | ||
| 158 | kfree(p); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | static struct ucode_patch *find_patch(unsigned int cpu) | ||
| 163 | { | ||
| 164 | u16 equiv_id; | ||
| 165 | |||
| 166 | equiv_id = find_equiv_id(cpu); | ||
| 167 | if (!equiv_id) | ||
| 168 | return NULL; | ||
| 169 | |||
| 170 | return cache_find_patch(equiv_id); | ||
| 171 | } | ||
| 80 | 172 | ||
| 81 | static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) | 173 | static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) |
| 82 | { | 174 | { |
| 83 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 175 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
| 84 | 176 | ||
| 177 | csig->sig = cpuid_eax(0x00000001); | ||
| 85 | csig->rev = c->microcode; | 178 | csig->rev = c->microcode; |
| 86 | pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); | 179 | pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); |
| 87 | 180 | ||
| 88 | return 0; | 181 | return 0; |
| 89 | } | 182 | } |
| 90 | 183 | ||
| 91 | static unsigned int verify_ucode_size(int cpu, u32 patch_size, | 184 | static unsigned int verify_patch_size(int cpu, u32 patch_size, |
| 92 | unsigned int size) | 185 | unsigned int size) |
| 93 | { | 186 | { |
| 94 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 187 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
| @@ -118,95 +211,37 @@ static unsigned int verify_ucode_size(int cpu, u32 patch_size, | |||
| 118 | return patch_size; | 211 | return patch_size; |
| 119 | } | 212 | } |
| 120 | 213 | ||
| 121 | static u16 find_equiv_id(void) | 214 | static int apply_microcode_amd(int cpu) |
| 122 | { | 215 | { |
| 123 | unsigned int current_cpu_id, i = 0; | 216 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
| 124 | 217 | struct microcode_amd *mc_amd; | |
| 125 | BUG_ON(equiv_cpu_table == NULL); | 218 | struct ucode_cpu_info *uci; |
| 126 | 219 | struct ucode_patch *p; | |
| 127 | current_cpu_id = cpuid_eax(0x00000001); | 220 | u32 rev, dummy; |
| 128 | |||
| 129 | while (equiv_cpu_table[i].installed_cpu != 0) { | ||
| 130 | if (current_cpu_id == equiv_cpu_table[i].installed_cpu) | ||
| 131 | return equiv_cpu_table[i].equiv_cpu; | ||
| 132 | |||
| 133 | i++; | ||
| 134 | } | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | 221 | ||
| 138 | /* | 222 | BUG_ON(raw_smp_processor_id() != cpu); |
| 139 | * we signal a good patch is found by returning its size > 0 | ||
| 140 | */ | ||
| 141 | static int get_matching_microcode(int cpu, const u8 *ucode_ptr, | ||
| 142 | unsigned int leftover_size, int rev, | ||
| 143 | unsigned int *current_size) | ||
| 144 | { | ||
| 145 | struct microcode_header_amd *mc_hdr; | ||
| 146 | unsigned int actual_size, patch_size; | ||
| 147 | u16 equiv_cpu_id; | ||
| 148 | 223 | ||
| 149 | /* size of the current patch we're staring at */ | 224 | uci = ucode_cpu_info + cpu; |
| 150 | patch_size = *(u32 *)(ucode_ptr + 4); | ||
| 151 | *current_size = patch_size + SECTION_HDR_SIZE; | ||
| 152 | 225 | ||
| 153 | equiv_cpu_id = find_equiv_id(); | 226 | p = find_patch(cpu); |
| 154 | if (!equiv_cpu_id) | 227 | if (!p) |
| 155 | return 0; | 228 | return 0; |
| 156 | 229 | ||
| 157 | /* | 230 | mc_amd = p->data; |
| 158 | * let's look at the patch header itself now | 231 | uci->mc = p->data; |
| 159 | */ | ||
| 160 | mc_hdr = (struct microcode_header_amd *)(ucode_ptr + SECTION_HDR_SIZE); | ||
| 161 | 232 | ||
| 162 | if (mc_hdr->processor_rev_id != equiv_cpu_id) | 233 | rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); |
| 163 | return 0; | ||
| 164 | 234 | ||
| 165 | /* ucode might be chipset specific -- currently we don't support this */ | 235 | /* need to apply patch? */ |
| 166 | if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) { | 236 | if (rev >= mc_amd->hdr.patch_id) { |
| 167 | pr_err("CPU%d: chipset specific code not yet supported\n", | 237 | c->microcode = rev; |
| 168 | cpu); | ||
| 169 | return 0; | 238 | return 0; |
| 170 | } | 239 | } |
| 171 | 240 | ||
| 172 | if (mc_hdr->patch_id <= rev) | ||
| 173 | return 0; | ||
| 174 | |||
| 175 | /* | ||
| 176 | * now that the header looks sane, verify its size | ||
| 177 | */ | ||
| 178 | actual_size = verify_ucode_size(cpu, patch_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; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int apply_microcode_amd(int cpu) | ||
| 192 | { | ||
| 193 | u32 rev, dummy; | ||
| 194 | int cpu_num = raw_smp_processor_id(); | ||
| 195 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
| 196 | struct microcode_amd *mc_amd = uci->mc; | ||
| 197 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
| 198 | |||
| 199 | /* We should bind the task to the CPU */ | ||
| 200 | BUG_ON(cpu_num != cpu); | ||
| 201 | |||
| 202 | if (mc_amd == NULL) | ||
| 203 | return 0; | ||
| 204 | |||
| 205 | wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); | 241 | wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); |
| 206 | /* get patch id after patching */ | ||
| 207 | rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); | ||
| 208 | 242 | ||
| 209 | /* check current patch id and patch's id for match */ | 243 | /* verify patch application was successful */ |
| 244 | rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); | ||
| 210 | if (rev != mc_amd->hdr.patch_id) { | 245 | if (rev != mc_amd->hdr.patch_id) { |
| 211 | pr_err("CPU%d: update failed for patch_level=0x%08x\n", | 246 | pr_err("CPU%d: update failed for patch_level=0x%08x\n", |
| 212 | cpu, mc_amd->hdr.patch_id); | 247 | cpu, mc_amd->hdr.patch_id); |
| @@ -238,7 +273,7 @@ static int install_equiv_cpu_table(const u8 *buf) | |||
| 238 | return -ENOMEM; | 273 | return -ENOMEM; |
| 239 | } | 274 | } |
| 240 | 275 | ||
| 241 | get_ucode_data(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size); | 276 | memcpy(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size); |
| 242 | 277 | ||
| 243 | /* add header length */ | 278 | /* add header length */ |
| 244 | return size + CONTAINER_HDR_SZ; | 279 | return size + CONTAINER_HDR_SZ; |
| @@ -250,61 +285,113 @@ static void free_equiv_cpu_table(void) | |||
| 250 | equiv_cpu_table = NULL; | 285 | equiv_cpu_table = NULL; |
| 251 | } | 286 | } |
| 252 | 287 | ||
| 253 | static enum ucode_state | 288 | static void cleanup(void) |
| 254 | generic_load_microcode(int cpu, const u8 *data, size_t size) | ||
| 255 | { | 289 | { |
| 256 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 290 | free_equiv_cpu_table(); |
| 257 | struct microcode_header_amd *mc_hdr = NULL; | 291 | free_cache(); |
| 258 | unsigned int mc_size, leftover, current_size = 0; | 292 | } |
| 293 | |||
| 294 | /* | ||
| 295 | * We return the current size even if some of the checks failed so that | ||
| 296 | * we can skip over the next patch. If we return a negative value, we | ||
| 297 | * signal a grave error like a memory allocation has failed and the | ||
| 298 | * driver cannot continue functioning normally. In such cases, we tear | ||
| 299 | * down everything we've used up so far and exit. | ||
| 300 | */ | ||
| 301 | static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover) | ||
| 302 | { | ||
| 303 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
| 304 | struct microcode_header_amd *mc_hdr; | ||
| 305 | struct ucode_patch *patch; | ||
| 306 | unsigned int patch_size, crnt_size, ret; | ||
| 307 | u32 proc_fam; | ||
| 308 | u16 proc_id; | ||
| 309 | |||
| 310 | patch_size = *(u32 *)(fw + 4); | ||
| 311 | crnt_size = patch_size + SECTION_HDR_SIZE; | ||
| 312 | mc_hdr = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE); | ||
| 313 | proc_id = mc_hdr->processor_rev_id; | ||
| 314 | |||
| 315 | proc_fam = find_cpu_family_by_equiv_cpu(proc_id); | ||
| 316 | if (!proc_fam) { | ||
| 317 | pr_err("No patch family for equiv ID: 0x%04x\n", proc_id); | ||
| 318 | return crnt_size; | ||
| 319 | } | ||
| 320 | |||
| 321 | /* check if patch is for the current family */ | ||
| 322 | proc_fam = ((proc_fam >> 8) & 0xf) + ((proc_fam >> 20) & 0xff); | ||
| 323 | if (proc_fam != c->x86) | ||
| 324 | return crnt_size; | ||
| 325 | |||
| 326 | if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) { | ||
| 327 | pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", | ||
| 328 | mc_hdr->patch_id); | ||
| 329 | return crnt_size; | ||
| 330 | } | ||
| 331 | |||
| 332 | ret = verify_patch_size(cpu, patch_size, leftover); | ||
| 333 | if (!ret) { | ||
| 334 | pr_err("Patch-ID 0x%08x: size mismatch.\n", mc_hdr->patch_id); | ||
| 335 | return crnt_size; | ||
| 336 | } | ||
| 337 | |||
| 338 | patch = kzalloc(sizeof(*patch), GFP_KERNEL); | ||
| 339 | if (!patch) { | ||
| 340 | pr_err("Patch allocation failure.\n"); | ||
| 341 | return -EINVAL; | ||
| 342 | } | ||
| 343 | |||
| 344 | patch->data = kzalloc(patch_size, GFP_KERNEL); | ||
| 345 | if (!patch->data) { | ||
| 346 | pr_err("Patch data allocation failure.\n"); | ||
| 347 | kfree(patch); | ||
| 348 | return -EINVAL; | ||
| 349 | } | ||
| 350 | |||
| 351 | /* All looks ok, copy patch... */ | ||
| 352 | memcpy(patch->data, fw + SECTION_HDR_SIZE, patch_size); | ||
| 353 | INIT_LIST_HEAD(&patch->plist); | ||
| 354 | patch->patch_id = mc_hdr->patch_id; | ||
| 355 | patch->equiv_cpu = proc_id; | ||
| 356 | |||
| 357 | /* ... and add to cache. */ | ||
| 358 | update_cache(patch); | ||
| 359 | |||
| 360 | return crnt_size; | ||
| 361 | } | ||
| 362 | |||
| 363 | static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size) | ||
| 364 | { | ||
| 365 | enum ucode_state ret = UCODE_ERROR; | ||
| 366 | unsigned int leftover; | ||
| 367 | u8 *fw = (u8 *)data; | ||
| 368 | int crnt_size = 0; | ||
| 259 | int offset; | 369 | int offset; |
| 260 | const u8 *ucode_ptr = data; | ||
| 261 | void *new_mc = NULL; | ||
| 262 | unsigned int new_rev = uci->cpu_sig.rev; | ||
| 263 | enum ucode_state state = UCODE_ERROR; | ||
| 264 | 370 | ||
| 265 | offset = install_equiv_cpu_table(ucode_ptr); | 371 | offset = install_equiv_cpu_table(data); |
| 266 | if (offset < 0) { | 372 | if (offset < 0) { |
| 267 | pr_err("failed to create equivalent cpu table\n"); | 373 | pr_err("failed to create equivalent cpu table\n"); |
| 268 | goto out; | 374 | return ret; |
| 269 | } | 375 | } |
| 270 | ucode_ptr += offset; | 376 | fw += offset; |
| 271 | leftover = size - offset; | 377 | leftover = size - offset; |
| 272 | 378 | ||
| 273 | if (*(u32 *)ucode_ptr != UCODE_UCODE_TYPE) { | 379 | if (*(u32 *)fw != UCODE_UCODE_TYPE) { |
| 274 | pr_err("invalid type field in container file section header\n"); | 380 | pr_err("invalid type field in container file section header\n"); |
| 275 | goto free_table; | 381 | free_equiv_cpu_table(); |
| 382 | return ret; | ||
| 276 | } | 383 | } |
| 277 | 384 | ||
| 278 | while (leftover) { | 385 | while (leftover) { |
| 279 | mc_size = get_matching_microcode(cpu, ucode_ptr, leftover, | 386 | crnt_size = verify_and_add_patch(cpu, fw, leftover); |
| 280 | new_rev, ¤t_size); | 387 | if (crnt_size < 0) |
| 281 | if (mc_size) { | 388 | return ret; |
| 282 | mc_hdr = patch; | ||
| 283 | new_mc = patch; | ||
| 284 | new_rev = mc_hdr->patch_id; | ||
| 285 | goto out_ok; | ||
| 286 | } | ||
| 287 | |||
| 288 | ucode_ptr += current_size; | ||
| 289 | leftover -= current_size; | ||
| 290 | } | ||
| 291 | 389 | ||
| 292 | if (!new_mc) { | 390 | fw += crnt_size; |
| 293 | state = UCODE_NFOUND; | 391 | leftover -= crnt_size; |
| 294 | goto free_table; | ||
| 295 | } | 392 | } |
| 296 | 393 | ||
| 297 | out_ok: | 394 | return UCODE_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); | ||
| 302 | |||
| 303 | free_table: | ||
| 304 | free_equiv_cpu_table(); | ||
| 305 | |||
| 306 | out: | ||
| 307 | return state; | ||
| 308 | } | 395 | } |
| 309 | 396 | ||
| 310 | /* | 397 | /* |
| @@ -315,7 +402,7 @@ out: | |||
| 315 | * | 402 | * |
| 316 | * This legacy file is always smaller than 2K in size. | 403 | * This legacy file is always smaller than 2K in size. |
| 317 | * | 404 | * |
| 318 | * Starting at family 15h they are in family specific firmware files: | 405 | * Beginning with family 15h, they are in family-specific firmware files: |
| 319 | * | 406 | * |
| 320 | * amd-ucode/microcode_amd_fam15h.bin | 407 | * amd-ucode/microcode_amd_fam15h.bin |
| 321 | * amd-ucode/microcode_amd_fam16h.bin | 408 | * amd-ucode/microcode_amd_fam16h.bin |
| @@ -323,12 +410,17 @@ out: | |||
| 323 | * | 410 | * |
| 324 | * These might be larger than 2K. | 411 | * These might be larger than 2K. |
| 325 | */ | 412 | */ |
| 326 | static enum ucode_state request_microcode_amd(int cpu, struct device *device) | 413 | static enum ucode_state request_microcode_amd(int cpu, struct device *device, |
| 414 | bool refresh_fw) | ||
| 327 | { | 415 | { |
| 328 | char fw_name[36] = "amd-ucode/microcode_amd.bin"; | 416 | char fw_name[36] = "amd-ucode/microcode_amd.bin"; |
| 329 | const struct firmware *fw; | ||
| 330 | enum ucode_state ret = UCODE_NFOUND; | ||
| 331 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 417 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
| 418 | enum ucode_state ret = UCODE_NFOUND; | ||
| 419 | const struct firmware *fw; | ||
| 420 | |||
| 421 | /* reload ucode container only on the boot cpu */ | ||
| 422 | if (!refresh_fw || c->cpu_index != boot_cpu_data.cpu_index) | ||
| 423 | return UCODE_OK; | ||
| 332 | 424 | ||
| 333 | if (c->x86 >= 0x15) | 425 | if (c->x86 >= 0x15) |
| 334 | snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); | 426 | snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); |
| @@ -344,12 +436,17 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device) | |||
| 344 | goto fw_release; | 436 | goto fw_release; |
| 345 | } | 437 | } |
| 346 | 438 | ||
| 347 | ret = generic_load_microcode(cpu, fw->data, fw->size); | 439 | /* free old equiv table */ |
| 440 | free_equiv_cpu_table(); | ||
| 441 | |||
| 442 | ret = load_microcode_amd(cpu, fw->data, fw->size); | ||
| 443 | if (ret != UCODE_OK) | ||
| 444 | cleanup(); | ||
| 348 | 445 | ||
| 349 | fw_release: | 446 | fw_release: |
| 350 | release_firmware(fw); | 447 | release_firmware(fw); |
| 351 | 448 | ||
| 352 | out: | 449 | out: |
| 353 | return ret; | 450 | return ret; |
| 354 | } | 451 | } |
| 355 | 452 | ||
| @@ -383,14 +480,10 @@ struct microcode_ops * __init init_amd_microcode(void) | |||
| 383 | return NULL; | 480 | return NULL; |
| 384 | } | 481 | } |
| 385 | 482 | ||
| 386 | patch = (void *)get_zeroed_page(GFP_KERNEL); | ||
| 387 | if (!patch) | ||
| 388 | return NULL; | ||
| 389 | |||
| 390 | return µcode_amd_ops; | 483 | return µcode_amd_ops; |
| 391 | } | 484 | } |
| 392 | 485 | ||
| 393 | void __exit exit_amd_microcode(void) | 486 | void __exit exit_amd_microcode(void) |
| 394 | { | 487 | { |
| 395 | free_page((unsigned long)patch); | 488 | cleanup(); |
| 396 | } | 489 | } |
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index 9e5bcf1e2376..3a04b224d0c0 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
| @@ -279,19 +279,18 @@ static struct platform_device *microcode_pdev; | |||
| 279 | static int reload_for_cpu(int cpu) | 279 | static int reload_for_cpu(int cpu) |
| 280 | { | 280 | { |
| 281 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 281 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
| 282 | enum ucode_state ustate; | ||
| 282 | int err = 0; | 283 | int err = 0; |
| 283 | 284 | ||
| 284 | if (uci->valid) { | 285 | if (!uci->valid) |
| 285 | enum ucode_state ustate; | 286 | return err; |
| 286 | |||
| 287 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev); | ||
| 288 | if (ustate == UCODE_OK) | ||
| 289 | apply_microcode_on_target(cpu); | ||
| 290 | else | ||
| 291 | if (ustate == UCODE_ERROR) | ||
| 292 | err = -EINVAL; | ||
| 293 | } | ||
| 294 | 287 | ||
| 288 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); | ||
| 289 | if (ustate == UCODE_OK) | ||
| 290 | apply_microcode_on_target(cpu); | ||
| 291 | else | ||
| 292 | if (ustate == UCODE_ERROR) | ||
| 293 | err = -EINVAL; | ||
| 295 | return err; | 294 | return err; |
| 296 | } | 295 | } |
| 297 | 296 | ||
| @@ -373,18 +372,15 @@ static void microcode_fini_cpu(int cpu) | |||
| 373 | 372 | ||
| 374 | static enum ucode_state microcode_resume_cpu(int cpu) | 373 | static enum ucode_state microcode_resume_cpu(int cpu) |
| 375 | { | 374 | { |
| 376 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
| 377 | |||
| 378 | if (!uci->mc) | ||
| 379 | return UCODE_NFOUND; | ||
| 380 | |||
| 381 | pr_debug("CPU%d updated upon resume\n", cpu); | 375 | pr_debug("CPU%d updated upon resume\n", cpu); |
| 382 | apply_microcode_on_target(cpu); | 376 | |
| 377 | if (apply_microcode_on_target(cpu)) | ||
| 378 | return UCODE_ERROR; | ||
| 383 | 379 | ||
| 384 | return UCODE_OK; | 380 | return UCODE_OK; |
| 385 | } | 381 | } |
| 386 | 382 | ||
| 387 | static enum ucode_state microcode_init_cpu(int cpu) | 383 | static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw) |
| 388 | { | 384 | { |
| 389 | enum ucode_state ustate; | 385 | enum ucode_state ustate; |
| 390 | 386 | ||
| @@ -395,7 +391,8 @@ static enum ucode_state microcode_init_cpu(int cpu) | |||
| 395 | if (system_state != SYSTEM_RUNNING) | 391 | if (system_state != SYSTEM_RUNNING) |
| 396 | return UCODE_NFOUND; | 392 | return UCODE_NFOUND; |
| 397 | 393 | ||
| 398 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev); | 394 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, |
| 395 | refresh_fw); | ||
| 399 | 396 | ||
| 400 | if (ustate == UCODE_OK) { | 397 | if (ustate == UCODE_OK) { |
| 401 | pr_debug("CPU%d updated upon init\n", cpu); | 398 | pr_debug("CPU%d updated upon init\n", cpu); |
| @@ -408,14 +405,11 @@ static enum ucode_state microcode_init_cpu(int cpu) | |||
| 408 | static enum ucode_state microcode_update_cpu(int cpu) | 405 | static enum ucode_state microcode_update_cpu(int cpu) |
| 409 | { | 406 | { |
| 410 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 407 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
| 411 | enum ucode_state ustate; | ||
| 412 | 408 | ||
| 413 | if (uci->valid) | 409 | if (uci->valid) |
| 414 | ustate = microcode_resume_cpu(cpu); | 410 | return microcode_resume_cpu(cpu); |
| 415 | else | ||
| 416 | ustate = microcode_init_cpu(cpu); | ||
| 417 | 411 | ||
| 418 | return ustate; | 412 | return microcode_init_cpu(cpu, false); |
| 419 | } | 413 | } |
| 420 | 414 | ||
| 421 | static int mc_device_add(struct device *dev, struct subsys_interface *sif) | 415 | static int mc_device_add(struct device *dev, struct subsys_interface *sif) |
| @@ -431,7 +425,7 @@ static int mc_device_add(struct device *dev, struct subsys_interface *sif) | |||
| 431 | if (err) | 425 | if (err) |
| 432 | return err; | 426 | return err; |
| 433 | 427 | ||
| 434 | if (microcode_init_cpu(cpu) == UCODE_ERROR) | 428 | if (microcode_init_cpu(cpu, true) == UCODE_ERROR) |
| 435 | return -EINVAL; | 429 | return -EINVAL; |
| 436 | 430 | ||
| 437 | return err; | 431 | return err; |
| @@ -480,34 +474,41 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |||
| 480 | struct device *dev; | 474 | struct device *dev; |
| 481 | 475 | ||
| 482 | dev = get_cpu_device(cpu); | 476 | dev = get_cpu_device(cpu); |
| 483 | switch (action) { | 477 | |
| 478 | switch (action & ~CPU_TASKS_FROZEN) { | ||
| 484 | case CPU_ONLINE: | 479 | case CPU_ONLINE: |
| 485 | case CPU_ONLINE_FROZEN: | ||
| 486 | microcode_update_cpu(cpu); | 480 | microcode_update_cpu(cpu); |
| 487 | case CPU_DOWN_FAILED: | ||
| 488 | case CPU_DOWN_FAILED_FROZEN: | ||
| 489 | pr_debug("CPU%d added\n", cpu); | 481 | pr_debug("CPU%d added\n", cpu); |
| 482 | /* | ||
| 483 | * "break" is missing on purpose here because we want to fall | ||
| 484 | * through in order to create the sysfs group. | ||
| 485 | */ | ||
| 486 | |||
| 487 | case CPU_DOWN_FAILED: | ||
| 490 | if (sysfs_create_group(&dev->kobj, &mc_attr_group)) | 488 | if (sysfs_create_group(&dev->kobj, &mc_attr_group)) |
| 491 | pr_err("Failed to create group for CPU%d\n", cpu); | 489 | pr_err("Failed to create group for CPU%d\n", cpu); |
| 492 | break; | 490 | break; |
| 491 | |||
| 493 | case CPU_DOWN_PREPARE: | 492 | case CPU_DOWN_PREPARE: |
| 494 | case CPU_DOWN_PREPARE_FROZEN: | ||
| 495 | /* Suspend is in progress, only remove the interface */ | 493 | /* Suspend is in progress, only remove the interface */ |
| 496 | sysfs_remove_group(&dev->kobj, &mc_attr_group); | 494 | sysfs_remove_group(&dev->kobj, &mc_attr_group); |
| 497 | pr_debug("CPU%d removed\n", cpu); | 495 | pr_debug("CPU%d removed\n", cpu); |
| 498 | break; | 496 | break; |
| 499 | 497 | ||
| 500 | /* | 498 | /* |
| 499 | * case CPU_DEAD: | ||
| 500 | * | ||
| 501 | * When a CPU goes offline, don't free up or invalidate the copy of | 501 | * When a CPU goes offline, don't free up or invalidate the copy of |
| 502 | * the microcode in kernel memory, so that we can reuse it when the | 502 | * the microcode in kernel memory, so that we can reuse it when the |
| 503 | * CPU comes back online without unnecessarily requesting the userspace | 503 | * CPU comes back online without unnecessarily requesting the userspace |
| 504 | * for it again. | 504 | * for it again. |
| 505 | */ | 505 | */ |
| 506 | case CPU_UP_CANCELED_FROZEN: | ||
| 507 | /* The CPU refused to come up during a system resume */ | ||
| 508 | microcode_fini_cpu(cpu); | ||
| 509 | break; | ||
| 510 | } | 506 | } |
| 507 | |||
| 508 | /* The CPU refused to come up during a system resume */ | ||
| 509 | if (action == CPU_UP_CANCELED_FROZEN) | ||
| 510 | microcode_fini_cpu(cpu); | ||
| 511 | |||
| 511 | return NOTIFY_OK; | 512 | return NOTIFY_OK; |
| 512 | } | 513 | } |
| 513 | 514 | ||
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c index 0327e2b3c408..3544aed39338 100644 --- a/arch/x86/kernel/microcode_intel.c +++ b/arch/x86/kernel/microcode_intel.c | |||
| @@ -405,7 +405,8 @@ static int get_ucode_fw(void *to, const void *from, size_t n) | |||
| 405 | return 0; | 405 | return 0; |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | static enum ucode_state request_microcode_fw(int cpu, struct device *device) | 408 | static enum ucode_state request_microcode_fw(int cpu, struct device *device, |
| 409 | bool refresh_fw) | ||
| 409 | { | 410 | { |
| 410 | char name[30]; | 411 | char name[30]; |
| 411 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 412 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
