diff options
Diffstat (limited to 'arch/x86/kernel/microcode.c')
| -rw-r--r-- | arch/x86/kernel/microcode.c | 84 |
1 files changed, 34 insertions, 50 deletions
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c index b2f84ce5eed3..902dada2eb6d 100644 --- a/arch/x86/kernel/microcode.c +++ b/arch/x86/kernel/microcode.c | |||
| @@ -110,50 +110,28 @@ struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | |||
| 110 | EXPORT_SYMBOL_GPL(ucode_cpu_info); | 110 | EXPORT_SYMBOL_GPL(ucode_cpu_info); |
| 111 | 111 | ||
| 112 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE | 112 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE |
| 113 | void __user *user_buffer; /* user area microcode data buffer */ | 113 | static int do_microcode_update(const void __user *buf, size_t size) |
| 114 | EXPORT_SYMBOL_GPL(user_buffer); | ||
| 115 | unsigned int user_buffer_size; /* it's size */ | ||
| 116 | EXPORT_SYMBOL_GPL(user_buffer_size); | ||
| 117 | |||
| 118 | static int do_microcode_update(void) | ||
| 119 | { | 114 | { |
| 120 | long cursor = 0; | 115 | cpumask_t old; |
| 121 | int error = 0; | 116 | int error = 0; |
| 122 | void *new_mc = NULL; | ||
| 123 | int cpu; | 117 | int cpu; |
| 124 | cpumask_t old; | ||
| 125 | 118 | ||
| 126 | old = current->cpus_allowed; | 119 | old = current->cpus_allowed; |
| 127 | 120 | ||
| 128 | while ((cursor = microcode_ops->get_next_ucode(&new_mc, cursor)) > 0) { | 121 | for_each_online_cpu(cpu) { |
| 129 | if (microcode_ops->microcode_sanity_check != NULL) | 122 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
| 130 | error = microcode_ops->microcode_sanity_check(new_mc); | 123 | |
| 131 | if (error) | 124 | if (!uci->valid) |
| 125 | continue; | ||
| 126 | |||
| 127 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
| 128 | error = microcode_ops->request_microcode_user(cpu, buf, size); | ||
| 129 | if (error < 0) | ||
| 132 | goto out; | 130 | goto out; |
| 133 | /* | 131 | if (!error) |
| 134 | * It's possible the data file has multiple matching ucode, | 132 | microcode_ops->apply_microcode(cpu); |
| 135 | * lets keep searching till the latest version | ||
| 136 | */ | ||
| 137 | for_each_online_cpu(cpu) { | ||
| 138 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
| 139 | |||
| 140 | if (!uci->valid) | ||
| 141 | continue; | ||
| 142 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
| 143 | error = microcode_ops->get_matching_microcode(new_mc, | ||
| 144 | cpu); | ||
| 145 | if (error < 0) | ||
| 146 | goto out; | ||
| 147 | if (error == 1) | ||
| 148 | microcode_ops->apply_microcode(cpu); | ||
| 149 | } | ||
| 150 | vfree(new_mc); | ||
| 151 | } | 133 | } |
| 152 | out: | 134 | out: |
| 153 | if (cursor > 0) | ||
| 154 | vfree(new_mc); | ||
| 155 | if (cursor < 0) | ||
| 156 | error = cursor; | ||
| 157 | set_cpus_allowed_ptr(current, &old); | 135 | set_cpus_allowed_ptr(current, &old); |
| 158 | return error; | 136 | return error; |
| 159 | } | 137 | } |
| @@ -178,10 +156,7 @@ static ssize_t microcode_write(struct file *file, const char __user *buf, | |||
| 178 | get_online_cpus(); | 156 | get_online_cpus(); |
| 179 | mutex_lock(µcode_mutex); | 157 | mutex_lock(µcode_mutex); |
| 180 | 158 | ||
| 181 | user_buffer = (void __user *) buf; | 159 | ret = do_microcode_update(buf, len); |
| 182 | user_buffer_size = (int) len; | ||
| 183 | |||
| 184 | ret = do_microcode_update(); | ||
| 185 | if (!ret) | 160 | if (!ret) |
| 186 | ret = (ssize_t)len; | 161 | ret = (ssize_t)len; |
| 187 | 162 | ||
| @@ -231,7 +206,6 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); | |||
| 231 | 206 | ||
| 232 | /* fake device for request_firmware */ | 207 | /* fake device for request_firmware */ |
| 233 | struct platform_device *microcode_pdev; | 208 | struct platform_device *microcode_pdev; |
| 234 | EXPORT_SYMBOL_GPL(microcode_pdev); | ||
| 235 | 209 | ||
| 236 | static ssize_t reload_store(struct sys_device *dev, | 210 | static ssize_t reload_store(struct sys_device *dev, |
| 237 | struct sysdev_attribute *attr, | 211 | struct sysdev_attribute *attr, |
| @@ -252,8 +226,12 @@ static ssize_t reload_store(struct sys_device *dev, | |||
| 252 | if (cpu_online(cpu)) { | 226 | if (cpu_online(cpu)) { |
| 253 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | 227 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
| 254 | mutex_lock(µcode_mutex); | 228 | mutex_lock(µcode_mutex); |
| 255 | if (uci->valid) | 229 | if (uci->valid) { |
| 256 | err = microcode_ops->cpu_request_microcode(cpu); | 230 | err = microcode_ops->request_microcode_fw(cpu, |
| 231 | µcode_pdev->dev); | ||
| 232 | if (!err) | ||
| 233 | microcode_ops->apply_microcode(cpu); | ||
| 234 | } | ||
| 257 | mutex_unlock(µcode_mutex); | 235 | mutex_unlock(µcode_mutex); |
| 258 | set_cpus_allowed_ptr(current, &old); | 236 | set_cpus_allowed_ptr(current, &old); |
| 259 | } | 237 | } |
| @@ -315,7 +293,7 @@ static void collect_cpu_info(int cpu) | |||
| 315 | uci->valid = 1; | 293 | uci->valid = 1; |
| 316 | } | 294 | } |
| 317 | 295 | ||
| 318 | static void microcode_resume_cpu(int cpu) | 296 | static int microcode_resume_cpu(int cpu) |
| 319 | { | 297 | { |
| 320 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 298 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
| 321 | struct cpu_signature nsig; | 299 | struct cpu_signature nsig; |
| @@ -323,7 +301,7 @@ static void microcode_resume_cpu(int cpu) | |||
| 323 | pr_debug("microcode: CPU%d resumed\n", cpu); | 301 | pr_debug("microcode: CPU%d resumed\n", cpu); |
| 324 | 302 | ||
| 325 | if (!uci->mc.valid_mc) | 303 | if (!uci->mc.valid_mc) |
| 326 | return; | 304 | return 1; |
| 327 | 305 | ||
| 328 | /* | 306 | /* |
| 329 | * Let's verify that the 'cached' ucode does belong | 307 | * Let's verify that the 'cached' ucode does belong |
| @@ -331,21 +309,22 @@ static void microcode_resume_cpu(int cpu) | |||
| 331 | */ | 309 | */ |
| 332 | if (microcode_ops->collect_cpu_info(cpu, &nsig)) { | 310 | if (microcode_ops->collect_cpu_info(cpu, &nsig)) { |
| 333 | microcode_fini_cpu(cpu); | 311 | microcode_fini_cpu(cpu); |
| 334 | return; | 312 | return -1; |
| 335 | } | 313 | } |
| 336 | 314 | ||
| 337 | if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) { | 315 | if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) { |
| 338 | microcode_fini_cpu(cpu); | 316 | microcode_fini_cpu(cpu); |
| 339 | /* Should we look for a new ucode here? */ | 317 | /* Should we look for a new ucode here? */ |
| 340 | return; | 318 | return 1; |
| 341 | } | 319 | } |
| 342 | 320 | ||
| 343 | microcode_ops->apply_microcode(cpu); | 321 | return 0; |
| 344 | } | 322 | } |
| 345 | 323 | ||
| 346 | void microcode_update_cpu(int cpu) | 324 | void microcode_update_cpu(int cpu) |
| 347 | { | 325 | { |
| 348 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 326 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
| 327 | int err = 0; | ||
| 349 | 328 | ||
| 350 | /* We should bind the task to the CPU */ | 329 | /* We should bind the task to the CPU */ |
| 351 | BUG_ON(raw_smp_processor_id() != cpu); | 330 | BUG_ON(raw_smp_processor_id() != cpu); |
| @@ -356,12 +335,17 @@ void microcode_update_cpu(int cpu) | |||
| 356 | * otherwise just request a firmware: | 335 | * otherwise just request a firmware: |
| 357 | */ | 336 | */ |
| 358 | if (uci->valid) { | 337 | if (uci->valid) { |
| 359 | microcode_resume_cpu(cpu); | 338 | err = microcode_resume_cpu(cpu); |
| 360 | } else { | 339 | } else { |
| 361 | collect_cpu_info(cpu); | 340 | collect_cpu_info(cpu); |
| 362 | if (uci->valid && system_state == SYSTEM_RUNNING) | 341 | if (uci->valid && system_state == SYSTEM_RUNNING) |
| 363 | microcode_ops->cpu_request_microcode(cpu); | 342 | err = microcode_ops->request_microcode_fw(cpu, |
| 343 | µcode_pdev->dev); | ||
| 364 | } | 344 | } |
| 345 | |||
| 346 | if (!err) | ||
| 347 | microcode_ops->apply_microcode(cpu); | ||
| 348 | |||
| 365 | mutex_unlock(µcode_mutex); | 349 | mutex_unlock(µcode_mutex); |
| 366 | } | 350 | } |
| 367 | 351 | ||
| @@ -414,7 +398,7 @@ static int mc_sysdev_resume(struct sys_device *dev) | |||
| 414 | return 0; | 398 | return 0; |
| 415 | pr_debug("microcode: CPU%d resumed\n", cpu); | 399 | pr_debug("microcode: CPU%d resumed\n", cpu); |
| 416 | /* only CPU 0 will apply ucode here */ | 400 | /* only CPU 0 will apply ucode here */ |
| 417 | microcode_ops->apply_microcode(0); | 401 | microcode_update_cpu(0); |
| 418 | return 0; | 402 | return 0; |
| 419 | } | 403 | } |
| 420 | 404 | ||
