Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp2469355yba; Mon, 15 Apr 2019 12:17:27 -0700 (PDT) X-Google-Smtp-Source: APXvYqwZ05QfBimKthExd+ceumXgbqe52zpTI235qEYiefTNBngYlhL48LRTmYL7P7/qD00bIVZz X-Received: by 2002:a62:6490:: with SMTP id y138mr77453196pfb.230.1555355847588; Mon, 15 Apr 2019 12:17:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1555355847; cv=none; d=google.com; s=arc-20160816; b=MwaMtZHf8H5C0tlVqrZlAemer74794NzCnHg1aEYHlI53hiu0AhfAFbB60TOQpApAe qkGBBA6151fN1O65NKfBp15FXxEQLBz+demMkYQDGICPErIC64Rb7p+xl+8su4REJb4M +vq0hjyLBb1ZRee/oOBWhRZv7HPZdz9gdA6kiQahk4HBgVPc6D2Y9w1lNbY30Q6d6LCF nBoY4NeXm859Jxns3eQNxjzO1D4k89sEtHY7jrTqAi8IJdqV3soZHV7i6l0eTvsJEdgM u8Td733k+xZh6SnA4aOJ4UE16rPW7r2Ypf4M56KDOL4Kx5GVb3DJ/tVmA0zS2c+BGKe0 VCTQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=XUSPKSMWDzeXDE4etfie5fMlEfVapOJ1dph33Dl8Kuo=; b=vBeRSK4O9k1dr1bVimLxG7CG54lFvqBykz5l1o47WVN+m7slGOQQax4XlCJDqmNNuu dDrHQOz4z2Bx4s8w60X2YvmPjZJHwdLnvJ1z0ob+b3uQjGELh0Audt7PVB/MuvWLXiHU XBxK1BeeP7Z4S5uYBHOgn9AcXCrh1VxgSV7REwqJnHvtvDeisn3oAuiv16yfNipdlkdb KCoVHJtgyZwsBCcTHrICgDg2vmbTcPThVae7ziBsjXvi8JTag1Pivr9zMM0GHC2tsbK7 tSocWQtCeVeIGdaxQ5lpZWvpQp0Po6DYjNjPJKfDQmRfn3r0Yaqm8h58+XgXF1Vkdmj4 Ry1Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=0ZzvCcZ4; 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 q1si43765172pgh.396.2019.04.15.12.17.11; Mon, 15 Apr 2019 12:17:27 -0700 (PDT) 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; dkim=pass header.i=@kernel.org header.s=default header.b=0ZzvCcZ4; 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 S1731604AbfDOTNj (ORCPT + 99 others); Mon, 15 Apr 2019 15:13:39 -0400 Received: from mail.kernel.org ([198.145.29.99]:51522 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728612AbfDOTNi (ORCPT ); Mon, 15 Apr 2019 15:13:38 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 9DC4F20880; Mon, 15 Apr 2019 19:13:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1555355617; bh=1zIPLQNUVnyF+EhKJhy1hc3FEFUBsTLW6w7NuVpOBmw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=0ZzvCcZ4CqQ+4VS7pzlI21WuEcX/lD36BfdbnEwVRh4HZ3pHw9PPFlFdMR0KHPjeC qaEnhlqtr7eVyVa7TKlNZ8pja3qRoi++om+WUfWng5V2sNnZr+ihpO78eq0c0aTbol bSBskLhlsqCRjghOnpye0whEPyKXWfyKAM9rDH78= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Tom Lendacky , "Peter Zijlstra (Intel)" , Alexander Shishkin , Arnaldo Carvalho de Melo , Arnaldo Carvalho de Melo , Borislav Petkov , Jiri Olsa , Linus Torvalds , Namhyung Kim , Stephane Eranian , Thomas Gleixner , Vince Weaver , Ingo Molnar Subject: [PATCH 5.0 103/117] x86/perf/amd: Resolve race condition when disabling PMC Date: Mon, 15 Apr 2019 21:01:13 +0200 Message-Id: <20190415183750.010882166@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415183744.887851196@linuxfoundation.org> References: <20190415183744.887851196@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Lendacky, Thomas commit 914123fa39042e651d79eaf86bbf63a1b938dddf upstream. On AMD processors, the detection of an overflowed counter in the NMI handler relies on the current value of the counter. So, for example, to check for overflow on a 48 bit counter, bit 47 is checked to see if it is 1 (not overflowed) or 0 (overflowed). There is currently a race condition present when disabling and then updating the PMC. Increased NMI latency in newer AMD processors makes this race condition more pronounced. If the counter value has overflowed, it is possible to update the PMC value before the NMI handler can run. The updated PMC value is not an overflowed value, so when the perf NMI handler does run, it will not find an overflowed counter. This may appear as an unknown NMI resulting in either a panic or a series of messages, depending on how the kernel is configured. To eliminate this race condition, the PMC value must be checked after disabling the counter. Add an AMD function, amd_pmu_disable_all(), that will wait for the NMI handler to reset any active and overflowed counter after calling x86_pmu_disable_all(). Signed-off-by: Tom Lendacky Signed-off-by: Peter Zijlstra (Intel) Cc: # 4.14.x- Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: https://lkml.kernel.org/r/Message-ID: Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/amd/core.c | 65 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "../perf_event.h" @@ -429,6 +430,64 @@ static void amd_pmu_cpu_dead(int cpu) } } +/* + * When a PMC counter overflows, an NMI is used to process the event and + * reset the counter. NMI latency can result in the counter being updated + * before the NMI can run, which can result in what appear to be spurious + * NMIs. This function is intended to wait for the NMI to run and reset + * the counter to avoid possible unhandled NMI messages. + */ +#define OVERFLOW_WAIT_COUNT 50 + +static void amd_pmu_wait_on_overflow(int idx) +{ + unsigned int i; + u64 counter; + + /* + * Wait for the counter to be reset if it has overflowed. This loop + * should exit very, very quickly, but just in case, don't wait + * forever... + */ + for (i = 0; i < OVERFLOW_WAIT_COUNT; i++) { + rdmsrl(x86_pmu_event_addr(idx), counter); + if (counter & (1ULL << (x86_pmu.cntval_bits - 1))) + break; + + /* Might be in IRQ context, so can't sleep */ + udelay(1); + } +} + +static void amd_pmu_disable_all(void) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + int idx; + + x86_pmu_disable_all(); + + /* + * This shouldn't be called from NMI context, but add a safeguard here + * to return, since if we're in NMI context we can't wait for an NMI + * to reset an overflowed counter value. + */ + if (in_nmi()) + return; + + /* + * Check each counter for overflow and wait for it to be reset by the + * NMI if it has overflowed. This relies on the fact that all active + * counters are always enabled when this function is caled and + * ARCH_PERFMON_EVENTSEL_INT is always set. + */ + for (idx = 0; idx < x86_pmu.num_counters; idx++) { + if (!test_bit(idx, cpuc->active_mask)) + continue; + + amd_pmu_wait_on_overflow(idx); + } +} + static struct event_constraint * amd_get_event_constraints(struct cpu_hw_events *cpuc, int idx, struct perf_event *event) @@ -622,7 +681,7 @@ static ssize_t amd_event_sysfs_show(char static __initconst const struct x86_pmu amd_pmu = { .name = "AMD", .handle_irq = x86_pmu_handle_irq, - .disable_all = x86_pmu_disable_all, + .disable_all = amd_pmu_disable_all, .enable_all = x86_pmu_enable_all, .enable = x86_pmu_enable_event, .disable = x86_pmu_disable_event, @@ -732,7 +791,7 @@ void amd_pmu_enable_virt(void) cpuc->perf_ctr_virt_mask = 0; /* Reload all events */ - x86_pmu_disable_all(); + amd_pmu_disable_all(); x86_pmu_enable_all(0); } EXPORT_SYMBOL_GPL(amd_pmu_enable_virt); @@ -750,7 +809,7 @@ void amd_pmu_disable_virt(void) cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY; /* Reload all events */ - x86_pmu_disable_all(); + amd_pmu_disable_all(); x86_pmu_enable_all(0); } EXPORT_SYMBOL_GPL(amd_pmu_disable_virt);