Received: by 2002:a05:6902:102b:0:0:0:0 with SMTP id x11csp420924ybt; Wed, 17 Jun 2020 04:40:57 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzp5YlSapN7Gsye+idecaoY10A976mBM6/qFQkee+N2icIwb0EgbE2GgnjV5sZ6JhY1nYT0 X-Received: by 2002:a17:906:c155:: with SMTP id dp21mr6884736ejc.92.1592394057123; Wed, 17 Jun 2020 04:40:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1592394057; cv=none; d=google.com; s=arc-20160816; b=SIpz3uWaMzKG7ndKe84I6o7qZiAK+bP+vV/o1/+z2vbORVtCZ5I7IaWPFJplRYnuMC D8ZxuWWEurhOzgbcz8GBLtIoPLgxXZNG2tLT7WmniVHEaWmCSB7C3A3I1idldujsFR6i Ojmu6EZ6+BoFowm6J+jL0+XkUVY7yGBGtCw5QdQQA1vTSbGsb2A5UgcvUTV3WxuHRApc upHkh0wsnKbjwk5kCaBgydo0OyV3NSQJvVW7i8E0w93yvHV5xHL8kPcPcaYz9K4j1xrA guib1eVd034vou85SzdKY1RC3tjvHKIK5ti6/0jC3K1xcKIs1Qz+lXFaIrgj07NRMooy 0WDA== 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 :references:in-reply-to:message-id:date:subject:cc:to:from; bh=Sez9MjdmAl+c61bIJa37Ma8EoADmvNsssy3Tj213kuM=; b=lOQyRoBNqizkIdfpli/gWWGISViGGEI0c5FrU2THvJQtq+fnALr1Y70wV+Syd7hbwf biIYZ9VyyN6q40rU/4mH7oVWa6lxsJkCNRahXYLlJLRuo1w3lsSin/NyL4sZJ0GxQc8h NBIbCOY/0CCTMjMCkr4Wc7BPovrAlINBCpXbV0dPtYW6JEGYm3Ro9EEc0xniFT90SENo 0UNSsrKwGEYQcfDPgn92LW73GBEUaexm1L7HBXrpd6nbm4TwT8KiKQpXVSwkkj2lK2ZU KMgUxTsdLQHNM0dcJfsEtnINwQIKkD6ARO/gB3rfJDnPZHMvGF/QYQGgnYnVdhlaGP4X QVMA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id pw24si13415352ejb.518.2020.06.17.04.40.34; Wed, 17 Jun 2020 04:40:57 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726282AbgFQLi3 (ORCPT + 99 others); Wed, 17 Jun 2020 07:38:29 -0400 Received: from foss.arm.com ([217.140.110.172]:56256 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726943AbgFQLiY (ORCPT ); Wed, 17 Jun 2020 07:38:24 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1EA661042; Wed, 17 Jun 2020 04:38:24 -0700 (PDT) Received: from monolith.arm.com (unknown [10.37.8.7]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 7FF513F71F; Wed, 17 Jun 2020 04:38:21 -0700 (PDT) From: Alexandru Elisei To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, mark.rutland@arm.com, Julien Thierry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Julien Thierry Subject: [PATCH v5 2/7] arm64: perf: Avoid PMXEV* indirection Date: Wed, 17 Jun 2020 12:38:46 +0100 Message-Id: <20200617113851.607706-3-alexandru.elisei@arm.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200617113851.607706-1-alexandru.elisei@arm.com> References: <20200617113851.607706-1-alexandru.elisei@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Mark Rutland Currently we access the counter registers and their respective type registers indirectly. This requires us to write to PMSELR, issue an ISB, then access the relevant PMXEV* registers. This is unfortunate, because: * Under virtualization, accessing one registers requires two traps to the hypervisor, even though we could access the register directly with a single trap. * We have to issue an ISB which we could otherwise avoid the cost of. * When we use NMIs, the NMI handler will have to save/restore the select register in case the code it preempted was attempting to access a counter or its type register. We can avoid these issues by directly accessing the relevant registers. This patch adds helpers to do so. In armv8pmu_enable_event() we still need the ISB to prevent the PE from reordering the write to PMINTENSET_EL1 register. If the interrupt is enabled before we disable the counter and the new event is configured, we might get an interrupt triggered by the previously programmed event overflowing, but which we wrongly attribute to the event that we are enabling. In the process, remove the comment that refers to the ARMv7 PMU. Cc: Julien Thierry Cc: Will Deacon Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Namhyung Kim Cc: Catalin Marinas Signed-off-by: Mark Rutland [Julien T.: Don't inline read/write functions to avoid big code-size increase, remove unused read_pmevtypern function, fix counter index issue.] Signed-off-by: Julien Thierry [Removed comment, removed trailing semicolons in macros, added ISB] Signed-off-by: Alexandru Elisei --- arch/arm64/kernel/perf_event.c | 95 +++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index ee180b2a5b39..e95b5ca70a53 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -323,6 +323,73 @@ static inline bool armv8pmu_event_is_chained(struct perf_event *event) #define ARMV8_IDX_TO_COUNTER(x) \ (((x) - ARMV8_IDX_COUNTER0) & ARMV8_PMU_COUNTER_MASK) +/* + * This code is really good + */ + +#define PMEVN_CASE(n, case_macro) \ + case n: case_macro(n); break + +#define PMEVN_SWITCH(x, case_macro) \ + do { \ + switch (x) { \ + PMEVN_CASE(0, case_macro); \ + PMEVN_CASE(1, case_macro); \ + PMEVN_CASE(2, case_macro); \ + PMEVN_CASE(3, case_macro); \ + PMEVN_CASE(4, case_macro); \ + PMEVN_CASE(5, case_macro); \ + PMEVN_CASE(6, case_macro); \ + PMEVN_CASE(7, case_macro); \ + PMEVN_CASE(8, case_macro); \ + PMEVN_CASE(9, case_macro); \ + PMEVN_CASE(10, case_macro); \ + PMEVN_CASE(11, case_macro); \ + PMEVN_CASE(12, case_macro); \ + PMEVN_CASE(13, case_macro); \ + PMEVN_CASE(14, case_macro); \ + PMEVN_CASE(15, case_macro); \ + PMEVN_CASE(16, case_macro); \ + PMEVN_CASE(17, case_macro); \ + PMEVN_CASE(18, case_macro); \ + PMEVN_CASE(19, case_macro); \ + PMEVN_CASE(20, case_macro); \ + PMEVN_CASE(21, case_macro); \ + PMEVN_CASE(22, case_macro); \ + PMEVN_CASE(23, case_macro); \ + PMEVN_CASE(24, case_macro); \ + PMEVN_CASE(25, case_macro); \ + PMEVN_CASE(26, case_macro); \ + PMEVN_CASE(27, case_macro); \ + PMEVN_CASE(28, case_macro); \ + PMEVN_CASE(29, case_macro); \ + PMEVN_CASE(30, case_macro); \ + default: WARN(1, "Invalid PMEV* index"); \ + } \ + } while (0) + +#define RETURN_READ_PMEVCNTRN(n) \ + return read_sysreg(pmevcntr##n##_el0) +static unsigned long read_pmevcntrn(int n) +{ + PMEVN_SWITCH(n, RETURN_READ_PMEVCNTRN); + return 0; +} + +#define WRITE_PMEVCNTRN(n) \ + write_sysreg(val, pmevcntr##n##_el0) +static void write_pmevcntrn(int n, unsigned long val) +{ + PMEVN_SWITCH(n, WRITE_PMEVCNTRN); +} + +#define WRITE_PMEVTYPERN(n) \ + write_sysreg(val, pmevtyper##n##_el0) +static void write_pmevtypern(int n, unsigned long val) +{ + PMEVN_SWITCH(n, WRITE_PMEVTYPERN); +} + static inline u32 armv8pmu_pmcr_read(void) { return read_sysreg(pmcr_el0); @@ -351,17 +418,11 @@ static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx) return pmnc & BIT(ARMV8_IDX_TO_COUNTER(idx)); } -static inline void armv8pmu_select_counter(int idx) +static inline u32 armv8pmu_read_evcntr(int idx) { u32 counter = ARMV8_IDX_TO_COUNTER(idx); - write_sysreg(counter, pmselr_el0); - isb(); -} -static inline u64 armv8pmu_read_evcntr(int idx) -{ - armv8pmu_select_counter(idx); - return read_sysreg(pmxevcntr_el0); + return read_pmevcntrn(counter); } static inline u64 armv8pmu_read_hw_counter(struct perf_event *event) @@ -433,8 +494,9 @@ static u64 armv8pmu_read_counter(struct perf_event *event) static inline void armv8pmu_write_evcntr(int idx, u64 value) { - armv8pmu_select_counter(idx); - write_sysreg(value, pmxevcntr_el0); + u32 counter = ARMV8_IDX_TO_COUNTER(idx); + + write_pmevcntrn(counter, value); } static inline void armv8pmu_write_hw_counter(struct perf_event *event, @@ -469,9 +531,10 @@ static void armv8pmu_write_counter(struct perf_event *event, u64 value) static inline void armv8pmu_write_evtype(int idx, u32 val) { - armv8pmu_select_counter(idx); + u32 counter = ARMV8_IDX_TO_COUNTER(idx); + val &= ARMV8_PMU_EVTYPE_MASK; - write_sysreg(val, pmxevtyper_el0); + write_pmevtypern(counter, val); } static inline void armv8pmu_write_event_type(struct perf_event *event) @@ -491,7 +554,10 @@ static inline void armv8pmu_write_event_type(struct perf_event *event) armv8pmu_write_evtype(idx - 1, hwc->config_base); armv8pmu_write_evtype(idx, chain_evt); } else { - armv8pmu_write_evtype(idx, hwc->config_base); + if (idx == ARMV8_IDX_CYCLE_COUNTER) + write_sysreg(hwc->config_base, pmccfiltr_el0); + else + armv8pmu_write_evtype(idx, hwc->config_base); } } @@ -595,9 +661,10 @@ static void armv8pmu_enable_event(struct perf_event *event) * Disable counter */ armv8pmu_disable_event_counter(event); + isb(); /* - * Set event (if destined for PMNx counters). + * Set event. */ armv8pmu_write_event_type(event); -- 2.27.0