Received: by 10.223.185.116 with SMTP id b49csp6015773wrg; Wed, 28 Feb 2018 02:31:08 -0800 (PST) X-Google-Smtp-Source: AH8x226ILy+JnIs7d0FFSbQ22t7ym3XbaDVw97fkUtRvBwpyCpNTmLLG6qQimh1ZfsgHVQ51UZDj X-Received: by 2002:a17:902:4381:: with SMTP id j1-v6mr17306264pld.297.1519813868065; Wed, 28 Feb 2018 02:31:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519813868; cv=none; d=google.com; s=arc-20160816; b=nsLcA9RqgsafuW40TO/BYp6UtbGyX3LtatQ1q89cKaooW9gf87pLv07tuYOrE3ofXE cjD4GqZwjnL03PSRA+jRVm9CgpgEhhIS2q5aKZehwlDIkV0FQFTVdftJZWTY2oaQ9ICL KjZf+f+W1zc7A+GrUSfPMezqXF8pRbltZH3kBhRCF31nZq125Q75z/25OHij9hODahYz OF8OWCn/QvfCc8ZrZBBX1Nic0735zdF91havEmaExnewUjJ7cI3askgM3RETy84Zbydx 5RX7+8YaGIXuPPR7jbNZrzyltYtSG/J6x4dT1T+uQ1PATNfnv2ctAda3VuvdXTMD7R7s 9eXQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=UA5TA4KFupMbto80Dd1nyyovYWw+n7499AgejYYiOaU=; b=HjoBmO4hyBeHi4+vS33tLrx+IcRxnogq6p/GFgkTIH2BzmEgpos2boBqNtFFEX/gC1 aFrVM8XDdeIZEuLUCeNCRJKI0CKM6Ormw0TnYRMsIYsWlEO2INmbMOYh79YPbv1QbWXu +kF/2dbxGiRTvkVYbBpF2ALZZBuWZ9ngc9WVD6s211B53CXVtLzJXwwIqTyYsGLJjmGr /I5LDJ5YDvWZUQ18NqykwcO63rRZ5o2ITg2jRv59mxJObvp4avSWUBWqwyPpdE4oCqVM WggRlD1ruuIa+fRlidDil94OZkjGIDPuTEvvp8x0q4VJkaT+qXDy/EpvYZMTNUjvcrrf op2Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z131si834503pgz.803.2018.02.28.02.30.50; Wed, 28 Feb 2018 02:31:08 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752571AbeB1K3q (ORCPT + 99 others); Wed, 28 Feb 2018 05:29:46 -0500 Received: from mail.skyhub.de ([5.9.137.197]:37154 "EHLO mail.skyhub.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752469AbeB1K3U (ORCPT ); Wed, 28 Feb 2018 05:29:20 -0500 X-Virus-Scanned: Nedap ESD1 at mail.skyhub.de Received: from mail.skyhub.de ([127.0.0.1]) by localhost (blast.alien8.de [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id GWhB_5HQ-yaY; Wed, 28 Feb 2018 11:29:19 +0100 (CET) Received: from pd.tnic (p200300EC2BCC7700C0F39F3CF1943F44.dip0.t-ipconnect.de [IPv6:2003:ec:2bcc:7700:c0f3:9f3c:f194:3f44]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.skyhub.de (SuperMail on ZX Spectrum 128k) with ESMTPSA id D2CC41EC0646; Wed, 28 Feb 2018 11:29:18 +0100 (CET) From: Borislav Petkov To: X86 ML Cc: Arjan Van De Ven , Ashok Raj , Tom Lendacky , LKML Subject: [PATCH 7/7] x86/microcode: Synchronize late microcode loading Date: Wed, 28 Feb 2018 11:28:46 +0100 Message-Id: <20180228102846.13447-8-bp@alien8.de> X-Mailer: git-send-email 2.13.0 In-Reply-To: <20180228102846.13447-1-bp@alien8.de> References: <20180228102846.13447-1-bp@alien8.de> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Ashok Raj Original idea by Ashok, completely rewritten by Borislav. Before you read any further: the early loading method is still the preferred one and you should always do that. The following patch is improving the late loading mechanism for long running jobs and cloud use cases. Gather all cores and serialize the microcode update on them by doing it one-by-one to make the late update process as reliable as possible and avoid potential issues caused by the microcode update. Signed-off-by: Ashok Raj [Rewrite completely. ] Co-developed-by: Borislav Petkov Signed-off-by: Borislav Petkov --- arch/x86/kernel/cpu/microcode/core.c | 118 +++++++++++++++++++++++++++-------- 1 file changed, 92 insertions(+), 26 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 5dd157d48606..70ecbc8099c9 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -22,13 +22,16 @@ #define pr_fmt(fmt) "microcode: " fmt #include +#include #include #include #include #include #include +#include #include #include +#include #include #include @@ -64,6 +67,11 @@ LIST_HEAD(microcode_cache); */ static DEFINE_MUTEX(microcode_mutex); +/* + * Serialize late loading so that CPUs get updated one-by-one. + */ +static DEFINE_SPINLOCK(update_lock); + struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; struct cpu_info_ctx { @@ -486,6 +494,19 @@ static void __exit microcode_dev_exit(void) /* fake device for request_firmware */ static struct platform_device *microcode_pdev; +/* + * Late loading dance. Why the heavy-handed stomp_machine effort? + * + * - HT siblings must be idle and not execute other code while the other sibling + * is loading microcode in order to avoid any negative interactions caused by + * the loading. + * + * - In addition, microcode update on the cores must be serialized until this + * requirement can be relaxed in the future. Right now, this is conservative + * and good. + */ +#define SPINUNIT 100 /* 100 nsec */ + static int check_online_cpus(void) { if (num_online_cpus() == num_present_cpus()) @@ -496,23 +517,85 @@ static int check_online_cpus(void) return -EINVAL; } -static enum ucode_state reload_for_cpu(int cpu) +static atomic_t late_cpus; + +/* + * Returns: + * < 0 - on error + * 0 - no update done + * 1 - microcode was updated + */ +static int __reload_late(void *info) { - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + unsigned int timeout = NSEC_PER_SEC; + int all_cpus = num_online_cpus(); + int cpu = smp_processor_id(); + enum ucode_state err; + int ret = 0; - if (!uci->valid) - return UCODE_OK; + atomic_dec(&late_cpus); + + /* + * Wait for all CPUs to arrive. A load will not be attempted unless all + * CPUs show up. + * */ + while (atomic_read(&late_cpus)) { + if (timeout < SPINUNIT) { + pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", + atomic_read(&late_cpus)); + return -1; + } + + ndelay(SPINUNIT); + timeout -= SPINUNIT; + + touch_nmi_watchdog(); + } + + spin_lock(&update_lock); + apply_microcode_local(&err); + spin_unlock(&update_lock); + + if (err > UCODE_NFOUND) { + pr_warn("Error reloading microcode on CPU %d\n", cpu); + ret = -1; + } else if (err == UCODE_UPDATED) { + ret = 1; + } - return apply_microcode_on_target(cpu); + atomic_inc(&late_cpus); + + while (atomic_read(&late_cpus) != all_cpus) + cpu_relax(); + + return ret; +} + +/* + * Reload microcode late on all CPUs. Wait for a sec until they + * all gather together. + */ +static int microcode_reload_late(void) +{ + int ret; + + atomic_set(&late_cpus, num_online_cpus()); + + ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); + if (ret < 0) + return ret; + else if (ret > 0) + microcode_check(); + + return ret; } static ssize_t reload_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - int cpu, bsp = boot_cpu_data.cpu_index; enum ucode_state tmp_ret = UCODE_OK; - bool do_callback = false; + int bsp = boot_cpu_data.cpu_index; unsigned long val; ssize_t ret = 0; @@ -534,30 +617,13 @@ static ssize_t reload_store(struct device *dev, goto put; mutex_lock(µcode_mutex); - - for_each_online_cpu(cpu) { - tmp_ret = reload_for_cpu(cpu); - if (tmp_ret > UCODE_NFOUND) { - pr_warn("Error reloading microcode on CPU %d\n", cpu); - - /* set retval for the first encountered reload error */ - if (!ret) - ret = -EINVAL; - } - - if (tmp_ret == UCODE_UPDATED) - do_callback = true; - } - - if (!ret && do_callback) - microcode_check(); - + ret = microcode_reload_late(); mutex_unlock(µcode_mutex); put: put_online_cpus(); - if (!ret) + if (ret >= 0) ret = size; return ret; -- 2.13.0