Received: by 2002:a05:6a10:af89:0:0:0:0 with SMTP id iu9csp4524760pxb; Tue, 25 Jan 2022 12:15:03 -0800 (PST) X-Google-Smtp-Source: ABdhPJx1nwLZvsMUFXKMEm4i4RV14PaPQRXlaiOWDf1VfUqgIzqpSebWzfdVo1JcwNihai1M+KZO X-Received: by 2002:a17:90a:8b82:: with SMTP id z2mr5202286pjn.146.1643141703309; Tue, 25 Jan 2022 12:15:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1643141703; cv=none; d=google.com; s=arc-20160816; b=FWOBdV7U+I0hk9sXEzGcxccnkgmojXpXckpNpTmkTOFSMJgUB8Dp4ieZaXNVXDC9gz 5Z+xoD4K1buCibCI8swD2j6HU37WckG0tps2IUXZ8EY4CDXjpnnUbNEwq3X165LamgRe z/wTBYICqsuPr2U8G1srJWRWCy03Goj6YlMjGVJY4ZGChZSfVCnvY7OgYuT4IYUs7iKq Qz2KwPwsG/rj8+QZjtmIqydOC5d1sa7EMV4cTNwvtyj+3Os6ePc4wBrIicwQ9ByMXusN /Jrjfi/AbRs722+5aRHnyhB0U2nRk+nI2p8mWBqQTnObXPBdEIy5TeHGXWuJZEMI3X03 cUYw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from; bh=LRErMjVOeBxVmukXAcjOmsQaTsq2ksd//jXPEwN4RYc=; b=T1kY6kRBdEi8gAdUEw70a1FLLuaymt85i3PsclS3lEEwYM6mkAZiB9m995VPc8RkhU D3EOIXRTHxKzSv/z9WLkooXdpWs7JVt+/0qS9yFXkT8K8uMPtZvex85M3BfidQ5CGdLi KOyNHixgZCLiaPYyyQ/m74q/xs+Ae/s4zfWFOlTUXKrfK76GMvop8hdEpfnde50Fr51i EDqXAro9+5WTWGIs4leNhfkikt3+bYNZExUaCz6HbJNodCkxGhN++k3D2kTCFQQ6cfBJ muiyyI1sX/UvMVSYsrc+X8Be4jZhEzWP7yVnnNO+m+5YcGQNIBmDiav/hHl9q5GqMNzo eZKA== 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id x2si13416263pgl.693.2022.01.25.12.14.51; Tue, 25 Jan 2022 12:15:03 -0800 (PST) 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235107AbiAYOaO (ORCPT + 99 others); Tue, 25 Jan 2022 09:30:14 -0500 Received: from foss.arm.com ([217.140.110.172]:46654 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1579099AbiAYOXH (ORCPT ); Tue, 25 Jan 2022 09:23:07 -0500 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 5FBE41396; Tue, 25 Jan 2022 06:21:20 -0800 (PST) Received: from p8cg001049571a15.arm.com (unknown [10.163.42.158]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 427943F793; Tue, 25 Jan 2022 06:21:15 -0800 (PST) From: Anshuman Khandual To: linux-arm-kernel@lists.infradead.org Cc: Anshuman Khandual , Catalin Marinas , Will Deacon , Mathieu Poirier , Suzuki Poulose , coresight@lists.linaro.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH V3 RESEND 5/7] coresight: trbe: Work around the ignored system register writes Date: Tue, 25 Jan 2022 19:50:35 +0530 Message-Id: <1643120437-14352-6-git-send-email-anshuman.khandual@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1643120437-14352-1-git-send-email-anshuman.khandual@arm.com> References: <1643120437-14352-1-git-send-email-anshuman.khandual@arm.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org TRBE implementations affected by Arm erratum #2064142 might fail to write into certain system registers after the TRBE has been disabled. Under some conditions after TRBE has been disabled, writes into certain TRBE registers TRBLIMITR_EL1, TRBPTR_EL1, TRBBASER_EL1, TRBSR_EL1 and TRBTRG_EL1 will be ignored and not be effected. Work around this problem in the TRBE driver by executing TSB CSYNC and DSB just after the trace collection has stopped and before performing a system register write to one of the affected registers. This just updates the TRBE driver as required. Cc: Catalin Marinas Cc: Will Deacon Cc: Mathieu Poirier Cc: Suzuki Poulose Cc: coresight@lists.linaro.org Cc: linux-doc@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Suzuki K Poulose Signed-off-by: Anshuman Khandual --- arch/arm64/Kconfig | 2 +- drivers/hwtracing/coresight/coresight-trbe.c | 54 ++++++++++++++------ drivers/hwtracing/coresight/coresight-trbe.h | 8 --- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 9c3cf3875785..823f7cb128dc 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -780,7 +780,7 @@ config ARM64_ERRATUM_2224489 config ARM64_ERRATUM_2064142 bool "Cortex-A510: 2064142: workaround TRBE register writes while disabled" - depends on COMPILE_TEST # Until the CoreSight TRBE driver changes are in + depends on CORESIGHT_TRBE default y help This option adds the workaround for ARM Cortex-A510 erratum 2064142. diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c index 276862c07e32..4ef944971d8e 100644 --- a/drivers/hwtracing/coresight/coresight-trbe.c +++ b/drivers/hwtracing/coresight/coresight-trbe.c @@ -91,10 +91,12 @@ struct trbe_buf { */ #define TRBE_WORKAROUND_OVERWRITE_FILL_MODE 0 #define TRBE_WORKAROUND_WRITE_OUT_OF_RANGE 1 +#define TRBE_NEEDS_DRAIN_AFTER_DISABLE 2 static int trbe_errata_cpucaps[] = { [TRBE_WORKAROUND_OVERWRITE_FILL_MODE] = ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE, [TRBE_WORKAROUND_WRITE_OUT_OF_RANGE] = ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE, + [TRBE_NEEDS_DRAIN_AFTER_DISABLE] = ARM64_WORKAROUND_2064142, -1, /* Sentinel, must be the last entry */ }; @@ -167,6 +169,16 @@ static inline bool trbe_may_write_out_of_range(struct trbe_cpudata *cpudata) return trbe_has_erratum(cpudata, TRBE_WORKAROUND_WRITE_OUT_OF_RANGE); } +static inline bool trbe_needs_drain_after_disable(struct trbe_cpudata *cpudata) +{ + /* + * Errata affected TRBE implementation will need TSB CSYNC and + * DSB in order to prevent subsequent writes into certain TRBE + * system registers from being ignored and not effected. + */ + return trbe_has_erratum(cpudata, TRBE_NEEDS_DRAIN_AFTER_DISABLE); +} + static int trbe_alloc_node(struct perf_event *event) { if (event->cpu == -1) @@ -174,30 +186,37 @@ static int trbe_alloc_node(struct perf_event *event) return cpu_to_node(event->cpu); } -static void trbe_drain_buffer(void) +static inline void trbe_drain_buffer(void) { tsb_csync(); dsb(nsh); } -static void trbe_drain_and_disable_local(void) +static inline void set_trbe_disabled(struct trbe_cpudata *cpudata) { u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1); - trbe_drain_buffer(); - /* * Disable the TRBE without clearing LIMITPTR which * might be required for fetching the buffer limits. */ trblimitr &= ~TRBLIMITR_ENABLE; write_sysreg_s(trblimitr, SYS_TRBLIMITR_EL1); + + if (trbe_needs_drain_after_disable(cpudata)) + trbe_drain_buffer(); isb(); } -static void trbe_reset_local(void) +static void trbe_drain_and_disable_local(struct trbe_cpudata *cpudata) { - trbe_drain_and_disable_local(); + trbe_drain_buffer(); + set_trbe_disabled(cpudata); +} + +static void trbe_reset_local(struct trbe_cpudata *cpudata) +{ + trbe_drain_and_disable_local(cpudata); write_sysreg_s(0, SYS_TRBLIMITR_EL1); write_sysreg_s(0, SYS_TRBPTR_EL1); write_sysreg_s(0, SYS_TRBBASER_EL1); @@ -234,7 +253,7 @@ static void trbe_stop_and_truncate_event(struct perf_output_handle *handle) * at event_stop(). So disable the TRBE here and leave * the update_buffer() to return a 0 size. */ - trbe_drain_and_disable_local(); + trbe_drain_and_disable_local(buf->cpudata); perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); perf_aux_output_end(handle, 0); *this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL; @@ -579,8 +598,7 @@ static void trbe_enable_hw(struct trbe_buf *buf) WARN_ON(buf->trbe_hw_base < buf->trbe_base); WARN_ON(buf->trbe_write < buf->trbe_hw_base); WARN_ON(buf->trbe_write >= buf->trbe_limit); - set_trbe_disabled(); - isb(); + set_trbe_disabled(buf->cpudata); clr_trbe_status(); set_trbe_base_pointer(buf->trbe_hw_base); set_trbe_write_pointer(buf->trbe_write); @@ -775,7 +793,7 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev, * the TRBE here will ensure that no IRQ could be generated when the perf * handle gets freed in etm_event_stop(). */ - trbe_drain_and_disable_local(); + trbe_drain_and_disable_local(cpudata); /* Check if there is a pending interrupt and handle it here */ status = read_sysreg_s(SYS_TRBSR_EL1); @@ -986,7 +1004,7 @@ static int arm_trbe_disable(struct coresight_device *csdev) if (cpudata->mode != CS_MODE_PERF) return -EINVAL; - trbe_drain_and_disable_local(); + trbe_drain_and_disable_local(cpudata); buf->cpudata = NULL; cpudata->buf = NULL; cpudata->mode = CS_MODE_DISABLED; @@ -1028,7 +1046,7 @@ static int trbe_handle_overflow(struct perf_output_handle *handle) * is able to detect this with a disconnected handle * (handle->event = NULL). */ - trbe_drain_and_disable_local(); + trbe_drain_and_disable_local(buf->cpudata); *this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL; return -EINVAL; } @@ -1062,6 +1080,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev) { struct perf_output_handle **handle_ptr = dev; struct perf_output_handle *handle = *handle_ptr; + struct trbe_buf *buf = etm_perf_sink_config(handle); enum trbe_fault_action act; u64 status; bool truncated = false; @@ -1082,7 +1101,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev) * Ensure the trace is visible to the CPUs and * any external aborts have been resolved. */ - trbe_drain_and_disable_local(); + trbe_drain_and_disable_local(buf->cpudata); clr_trbe_irq(); isb(); @@ -1167,8 +1186,9 @@ static const struct attribute_group *arm_trbe_groups[] = { static void arm_trbe_enable_cpu(void *info) { struct trbe_drvdata *drvdata = info; + struct trbe_cpudata *cpudata = this_cpu_ptr(drvdata->cpudata); - trbe_reset_local(); + trbe_reset_local(cpudata); enable_percpu_irq(drvdata->irq, IRQ_TYPE_NONE); } @@ -1276,7 +1296,7 @@ static void arm_trbe_remove_coresight_cpu(void *info) struct coresight_device *trbe_csdev = coresight_get_percpu_sink(cpu); disable_percpu_irq(drvdata->irq); - trbe_reset_local(); + trbe_reset_local(cpudata); if (trbe_csdev) { coresight_unregister(trbe_csdev); cpudata->drvdata = NULL; @@ -1349,8 +1369,10 @@ static int arm_trbe_cpu_teardown(unsigned int cpu, struct hlist_node *node) struct trbe_drvdata *drvdata = hlist_entry_safe(node, struct trbe_drvdata, hotplug_node); if (cpumask_test_cpu(cpu, &drvdata->supported_cpus)) { + struct trbe_cpudata *cpudata = per_cpu_ptr(drvdata->cpudata, cpu); + disable_percpu_irq(drvdata->irq); - trbe_reset_local(); + trbe_reset_local(cpudata); } return 0; } diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h index abf3e36082f0..30e4d7db4f8e 100644 --- a/drivers/hwtracing/coresight/coresight-trbe.h +++ b/drivers/hwtracing/coresight/coresight-trbe.h @@ -91,14 +91,6 @@ static inline bool is_trbe_running(u64 trbsr) #define TRBE_FILL_MODE_WRAP 1 #define TRBE_FILL_MODE_CIRCULAR_BUFFER 3 -static inline void set_trbe_disabled(void) -{ - u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1); - - trblimitr &= ~TRBLIMITR_ENABLE; - write_sysreg_s(trblimitr, SYS_TRBLIMITR_EL1); -} - static inline bool get_trbe_flag_update(u64 trbidr) { return trbidr & TRBIDR_FLAG; -- 2.25.1