|
@@ -219,7 +219,7 @@ static int microcode_sanity_check(void *mc)
|
|
|
/* check extended table checksum */
|
|
|
if (ext_table_size) {
|
|
|
int ext_table_sum = 0;
|
|
|
- int * ext_tablep = (int *)ext_header;
|
|
|
+ int *ext_tablep = (int *)ext_header;
|
|
|
|
|
|
i = ext_table_size / DWSIZE;
|
|
|
while (i--)
|
|
@@ -386,7 +386,7 @@ static int do_microcode_update (void)
|
|
|
{
|
|
|
long cursor = 0;
|
|
|
int error = 0;
|
|
|
- void * new_mc;
|
|
|
+ void *new_mc;
|
|
|
int cpu;
|
|
|
cpumask_t old;
|
|
|
|
|
@@ -531,7 +531,7 @@ static int cpu_request_microcode(int cpu)
|
|
|
char name[30];
|
|
|
struct cpuinfo_x86 *c = cpu_data + cpu;
|
|
|
const struct firmware *firmware;
|
|
|
- void * buf;
|
|
|
+ void *buf;
|
|
|
unsigned long size;
|
|
|
long offset = 0;
|
|
|
int error;
|
|
@@ -602,6 +602,136 @@ static void microcode_fini_cpu(int cpu)
|
|
|
mutex_unlock(µcode_mutex);
|
|
|
}
|
|
|
|
|
|
+static ssize_t reload_store(struct sys_device *dev, const char *buf, size_t sz)
|
|
|
+{
|
|
|
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
|
|
|
+ char *end;
|
|
|
+ unsigned long val = simple_strtoul(buf, &end, 0);
|
|
|
+ int err = 0;
|
|
|
+ int cpu = dev->id;
|
|
|
+
|
|
|
+ if (end == buf)
|
|
|
+ return -EINVAL;
|
|
|
+ if (val == 1) {
|
|
|
+ cpumask_t old;
|
|
|
+
|
|
|
+ old = current->cpus_allowed;
|
|
|
+
|
|
|
+ lock_cpu_hotplug();
|
|
|
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
|
|
|
+
|
|
|
+ mutex_lock(µcode_mutex);
|
|
|
+ if (uci->valid)
|
|
|
+ err = cpu_request_microcode(cpu);
|
|
|
+ mutex_unlock(µcode_mutex);
|
|
|
+ unlock_cpu_hotplug();
|
|
|
+ set_cpus_allowed(current, old);
|
|
|
+ }
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+ return sz;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t version_show(struct sys_device *dev, char *buf)
|
|
|
+{
|
|
|
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
|
|
|
+
|
|
|
+ return sprintf(buf, "0x%x\n", uci->rev);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t pf_show(struct sys_device *dev, char *buf)
|
|
|
+{
|
|
|
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
|
|
|
+
|
|
|
+ return sprintf(buf, "0x%x\n", uci->pf);
|
|
|
+}
|
|
|
+
|
|
|
+static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
|
|
|
+static SYSDEV_ATTR(version, 0400, version_show, NULL);
|
|
|
+static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
|
|
|
+
|
|
|
+static struct attribute *mc_default_attrs[] = {
|
|
|
+ &attr_reload.attr,
|
|
|
+ &attr_version.attr,
|
|
|
+ &attr_processor_flags.attr,
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group mc_attr_group = {
|
|
|
+ .attrs = mc_default_attrs,
|
|
|
+ .name = "microcode",
|
|
|
+};
|
|
|
+
|
|
|
+static int mc_sysdev_add(struct sys_device *sys_dev)
|
|
|
+{
|
|
|
+ int cpu = sys_dev->id;
|
|
|
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
|
|
|
+
|
|
|
+ if (!cpu_online(cpu))
|
|
|
+ return 0;
|
|
|
+ pr_debug("Microcode:CPU %d added\n", cpu);
|
|
|
+ memset(uci, 0, sizeof(*uci));
|
|
|
+ sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
|
|
|
+
|
|
|
+ microcode_init_cpu(cpu);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int mc_sysdev_remove(struct sys_device *sys_dev)
|
|
|
+{
|
|
|
+ int cpu = sys_dev->id;
|
|
|
+
|
|
|
+ if (!cpu_online(cpu))
|
|
|
+ return 0;
|
|
|
+ pr_debug("Microcode:CPU %d removed\n", cpu);
|
|
|
+ microcode_fini_cpu(cpu);
|
|
|
+ sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int mc_sysdev_resume(struct sys_device *dev)
|
|
|
+{
|
|
|
+ int cpu = dev->id;
|
|
|
+
|
|
|
+ if (!cpu_online(cpu))
|
|
|
+ return 0;
|
|
|
+ pr_debug("Microcode:CPU %d resumed\n", cpu);
|
|
|
+ /* only CPU 0 will apply ucode here */
|
|
|
+ apply_microcode(0);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct sysdev_driver mc_sysdev_driver = {
|
|
|
+ .add = mc_sysdev_add,
|
|
|
+ .remove = mc_sysdev_remove,
|
|
|
+ .resume = mc_sysdev_resume,
|
|
|
+};
|
|
|
+
|
|
|
+#ifdef CONFIG_HOTPLUG_CPU
|
|
|
+static __cpuinit int
|
|
|
+mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
|
|
|
+{
|
|
|
+ unsigned int cpu = (unsigned long)hcpu;
|
|
|
+ struct sys_device *sys_dev;
|
|
|
+
|
|
|
+ sys_dev = get_cpu_sysdev(cpu);
|
|
|
+ switch (action) {
|
|
|
+ case CPU_ONLINE:
|
|
|
+ case CPU_DOWN_FAILED:
|
|
|
+ mc_sysdev_add(sys_dev);
|
|
|
+ break;
|
|
|
+ case CPU_DOWN_PREPARE:
|
|
|
+ mc_sysdev_remove(sys_dev);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return NOTIFY_OK;
|
|
|
+}
|
|
|
+
|
|
|
+static struct notifier_block mc_cpu_notifier = {
|
|
|
+ .notifier_call = mc_cpu_callback,
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
static int __init microcode_init (void)
|
|
|
{
|
|
|
int error;
|
|
@@ -616,6 +746,17 @@ static int __init microcode_init (void)
|
|
|
return PTR_ERR(microcode_pdev);
|
|
|
}
|
|
|
|
|
|
+ lock_cpu_hotplug();
|
|
|
+ error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
|
|
|
+ unlock_cpu_hotplug();
|
|
|
+ if (error) {
|
|
|
+ microcode_dev_exit();
|
|
|
+ platform_device_unregister(microcode_pdev);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ register_hotcpu_notifier(&mc_cpu_notifier);
|
|
|
+
|
|
|
printk(KERN_INFO
|
|
|
"IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
|
|
|
return 0;
|
|
@@ -624,6 +765,13 @@ static int __init microcode_init (void)
|
|
|
static void __exit microcode_exit (void)
|
|
|
{
|
|
|
microcode_dev_exit();
|
|
|
+
|
|
|
+ unregister_hotcpu_notifier(&mc_cpu_notifier);
|
|
|
+
|
|
|
+ lock_cpu_hotplug();
|
|
|
+ sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
|
|
|
+ unlock_cpu_hotplug();
|
|
|
+
|
|
|
platform_device_unregister(microcode_pdev);
|
|
|
}
|
|
|
|