From nobody Thu Oct 2 20:23:04 2025 Received: from out30-97.freemail.mail.aliyun.com (out30-97.freemail.mail.aliyun.com [115.124.30.97]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 41684322777 for ; Thu, 11 Sep 2025 12:45:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.97 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757594723; cv=none; b=nuMcszMSlBDUkGPcfBy6kCiwVPVaik45laXptNR1AwEeNOTkwxIygZc2X1Udl78FubPn72kIYTSSBT/c41DSyzKdV/xR9RUDK5NP3fBYC/COZtK7B3pWm6Ul8ubvwLU//szt5zMims8nfuhZFF0Iku191271nunFP+WpSQg3bWA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757594723; c=relaxed/simple; bh=xHPpwLc/5dufVUFak3Gb8AXeP/TNv6gYNJWy0YG4Uis=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=j+rGak/Pfzof3NC5mhiOCH1XMUFeYtC1D5tl867DCRm0L+FX2o+5pfmeulxXHKdVENSZDAOq5KtpQ89GtZp0tns6RLdJZyGkh/vjvvcBPpVLEZqGEMkY3oyLlAGdUU7OM7C1eJnI3AqZ9BVfvTCRV9L4VNp695l0k8XZ+x+KjdA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=qG6G3/Ms; arc=none smtp.client-ip=115.124.30.97 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="qG6G3/Ms" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1757594710; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=2BUEuwEcOUukXezOVVtgLhzc2R17kXm8C8GBvwMavA8=; b=qG6G3/MsxdxKPx8rMohkSo0H3qEZ79g/jzW6imo4e5AOY8Eq73YGx1bk8V2t9OjCDe+TrOZOnU+RcHKKNi29diprCh6fw16gMa90Jy8CvqfSpgITs5J/DlaMoaivqWjYdePzaahBbXYu5eKHyu4vo3x7lqTt+zmI8VpdViKlszM= Received: from DESKTOP-S9E58SO.localdomain(mailfrom:cp0613@linux.alibaba.com fp:SMTPD_---0WnmLJhX_1757594708 cluster:ay36) by smtp.aliyun-inc.com; Thu, 11 Sep 2025 20:45:10 +0800 From: cp0613@linux.alibaba.com To: paul.walmsley@sifive.com, palmer@dabbelt.com, aou@eecs.berkeley.edu, alex@ghiti.fr, guoren@kernel.org Cc: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, Chen Pei Subject: [RFC PATCH 1/4] dt-bindings: riscv: Add trace components description Date: Thu, 11 Sep 2025 20:44:45 +0800 Message-ID: <20250911124448.1771-2-cp0613@linux.alibaba.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250911124448.1771-1-cp0613@linux.alibaba.com> References: <20250911124448.1771-1-cp0613@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Chen Pei This patch has added property definitions related to the riscv trace component, providing a foundation for subsequent driver implementations. The RISC-V Trace Control Interface can be found in [1]. Some principles are as follows: 1. Trace has three types of components: 1.1 Encoder: Collects CPU execution information through the Ingress Port and generates Trace Messages. 1.2 Funnel: Used to integrate multiple trace sources. 1.3 Sink: Used to store trace data. 2. Each hart requires one trace encoder. 3. When there are multiple trace sources, a trace funnel component is needed to integrate them. One trace funnel is required for each cluster. 4. When multiple trace funnels are fed into a single trace sink, multiple levels of trace funnels are required. 5. If there is only one cluster, the trace funnel (Level 0) can be connected directly to the trace sink. Taking [cpu0]-->[encoder0]-->[funnel0]-->[sink0] as an example, the DTS configuration is as follows: encoder0: trace_encoder@26001000 { compatible =3D "riscv_trace,encoder-controller"; reg =3D <0x0 0x26001000 0x0 0x1000>; cpu =3D <&cpu0>; output_port { port0 { endpoint =3D <&funnel0>; }; }; }; funnel0: trace_funnel@26404000 { compatible =3D "riscv_trace,funnel-controller"; reg =3D <0x0 0x26404000 0x0 0x1000>; level =3D <1>; input_port { port0 { endpoint =3D <&encoder0>; }; }; output_port { port0 { endpoint =3D <&sink0>; }; }; }; sink0: trace_sink@26401000 { compatible =3D "riscv_trace,sink-controller"; reg =3D <0x0 0x26401000 0x0 0x1000>; input_port { port0 { endpoint =3D <&funnel0>; }; }; }; Note: The detailed property definition of each component will be provided in the subsequent series of patches. [1] https://github.com/riscv-non-isa/tg-nexus-trace.git Signed-off-by: Chen Pei --- .../riscv/trace/riscv,trace,encoder.yaml | 41 +++++++++++++++++ .../riscv/trace/riscv,trace,funnel.yaml | 46 +++++++++++++++++++ .../riscv/trace/riscv,trace,sink.yaml | 37 +++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 Documentation/devicetree/bindings/riscv/trace/riscv,tra= ce,encoder.yaml create mode 100644 Documentation/devicetree/bindings/riscv/trace/riscv,tra= ce,funnel.yaml create mode 100644 Documentation/devicetree/bindings/riscv/trace/riscv,tra= ce,sink.yaml diff --git a/Documentation/devicetree/bindings/riscv/trace/riscv,trace,enco= der.yaml b/Documentation/devicetree/bindings/riscv/trace/riscv,trace,encode= r.yaml new file mode 100644 index 000000000000..e2ec3ce514b2 --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/trace/riscv,trace,encoder.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/riscv/trace/riscv,trace,encoder.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V Trace Encoder Controller + +description: | + riscv trace encoder controller description. + +maintainers: + - Chen Pei + +properties: + compatible: + items: + - const: riscv_trace,encoder-controller + reg: + description: A memory region containing registers for encoder controll= er + + cpu: + description: CPU identifier associated with this encoder + + ports: + description: Output port definitions + +additionalProperties: true + +examples: + - | + encoder0: trace_encoder@26001000 { + compatible =3D "riscv_trace,encoder-controller"; + reg =3D <0x0 0x26001000 0x0 0x1000>; + cpu =3D <&cpu0>; + output_port { + port0 { + endpoint =3D <&funnel0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/riscv/trace/riscv,trace,funn= el.yaml b/Documentation/devicetree/bindings/riscv/trace/riscv,trace,funnel.= yaml new file mode 100644 index 000000000000..5da836997355 --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/trace/riscv,trace,funnel.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/riscv/trace/riscv,trace,funnel.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V Trace Funnel Controller + +description: | + riscv trace funnel controller description. + +maintainers: + - Chen Pei + +properties: + compatible: + items: + - const: riscv_trace,funnel-controller + reg: + description: A memory region containing registers for funnel controller + + ports: + description: Input/Output port definitions + + level: + description: Level of the funnel (e.g., 1 means close to the encoder) + +additionalProperties: true + +examples: + - | + funnel0: trace_funnel@26404000 { + compatible =3D "riscv_trace,funnel-controller"; + reg =3D <0x0 0x26404000 0x0 0x1000>; + level =3D <1>; + input_port { + port0 { + endpoint =3D <&encoder0>; + }; + }; + output_port { + port0 { + endpoint =3D <&sink0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/riscv/trace/riscv,trace,sink= .yaml b/Documentation/devicetree/bindings/riscv/trace/riscv,trace,sink.yaml new file mode 100644 index 000000000000..b42e65988f31 --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/trace/riscv,trace,sink.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/riscv/trace/riscv,trace,sink.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V Trace Sink Controller + +description: | + riscv trace sink controller description. + +maintainers: + - Chen Pei + +properties: + compatible: + items: + - const: riscv_trace,sink-controller + reg: + description: A memory region containing registers for sink controller + + ports: + description: Input port definitions + +additionalProperties: true + +examples: + - | + sink0: trace_sink@26401000 { + compatible =3D "riscv_trace,sink-controller"; + reg =3D <0x0 0x26401000 0x0 0x1000>; + input_port { + port0 { + endpoint =3D <&funnel0>; + }; + }; + }; --=20 2.49.0 From nobody Thu Oct 2 20:23:04 2025 Received: from out30-113.freemail.mail.aliyun.com (out30-113.freemail.mail.aliyun.com [115.124.30.113]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 60CFE32274C for ; Thu, 11 Sep 2025 12:45:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.113 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757594720; cv=none; b=Lx766nUkkXsL2Wj/fwXeha262x9xLFb7cVv4CyrR/38U58r7AI5QMqO01THEjiNgbkNn9NPa1d6LScjYGhyyJxGaDn4aQGz0mci6XEM4qZg2Vfd9hmZJ1q1cTiadOTm9DfhzMkDNDa26LHrybKLpvSqX/nNKRLCszRDsm9iwLP8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757594720; c=relaxed/simple; bh=9VcG8YrS1rXpit2kdOeKu3ZwWcOcC68kO51/Ufmrlho=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WSwiGpJvpDLgJ6FLY+qJ4A6JuH2oVNyK52p7CpOOZ4PB5hs2M51Ds9QPZN4+LfHYtmL5ZH07iRGluZhCXoR3uCTQ9CJK1DRKeDkYf8dNLcwsciXW9UXZyMFavqhBcEdvA7+nsGxjMTGTO2eBoNgfgPAIIMqLbOVhPa5LLmbodLk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=IwYXCmsq; arc=none smtp.client-ip=115.124.30.113 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="IwYXCmsq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1757594711; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=TvDyvUeEGsS0M8RAvpriy4NmYR/Abif6DtPqta6UZk8=; b=IwYXCmsqTRWCcD938fp5PmjkYPygZ8n1xzU30tWQk5huMkcVHVCtdxYQenU6C86Rw8aTtWAH/v92p3R83JL9G9XHyh84+aVhXoKeRzaLc5lh/xYa5RsUE4YzzlIMMhX3BXnklSWXnDlmRqlyGOGxgnaV4uvL0iGU5cCbsYcHs8s= Received: from DESKTOP-S9E58SO.localdomain(mailfrom:cp0613@linux.alibaba.com fp:SMTPD_---0WnmLJic_1757594710 cluster:ay36) by smtp.aliyun-inc.com; Thu, 11 Sep 2025 20:45:11 +0800 From: cp0613@linux.alibaba.com To: paul.walmsley@sifive.com, palmer@dabbelt.com, aou@eecs.berkeley.edu, alex@ghiti.fr, guoren@kernel.org Cc: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, Chen Pei Subject: [RFC PATCH 2/4] riscv: event: Initial riscv trace driver support Date: Thu, 11 Sep 2025 20:44:46 +0800 Message-ID: <20250911124448.1771-3-cp0613@linux.alibaba.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250911124448.1771-1-cp0613@linux.alibaba.com> References: <20250911124448.1771-1-cp0613@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Chen Pei This patch implements the riscv trace perf driver. It's suitable for RISC-V processors that implement the trace specification (N-Trace or E-Trace). Users can specify the riscv_trace driver through the perf program. The driver adds two format attributes, start_addr and stop_addr, to specify the valid instruction range for tracing. It also supports specifying the priv_mode (user and kernel) to specify the valid privilege mode for tracing. The reference commands are as follows: cat /sys/bus/event_source/devices/riscv_trace/format/* perf record -e riscv_trace// ls perf record -e riscv_trace/start_addr=3D0x1234,stop_addr=3D0x5678/ ls perf record -e riscv_trace/start_addr=3D0x1234,stop_addr=3D0x5678/k ls perf report -D Signed-off-by: Chen Pei --- arch/riscv/Kbuild | 1 + arch/riscv/Kconfig | 2 + arch/riscv/events/Kconfig | 11 ++ arch/riscv/events/Makefile | 3 + arch/riscv/events/riscv_trace.c | 145 +++++++++++++++++++++ arch/riscv/events/riscv_trace.h | 123 ++++++++++++++++++ arch/riscv/events/riscv_trace_encoder.c | 109 ++++++++++++++++ arch/riscv/events/riscv_trace_funnel.c | 160 ++++++++++++++++++++++++ arch/riscv/events/riscv_trace_sink.c | 100 +++++++++++++++ 9 files changed, 654 insertions(+) create mode 100644 arch/riscv/events/Kconfig create mode 100644 arch/riscv/events/Makefile create mode 100644 arch/riscv/events/riscv_trace.c create mode 100644 arch/riscv/events/riscv_trace.h create mode 100644 arch/riscv/events/riscv_trace_encoder.c create mode 100644 arch/riscv/events/riscv_trace_funnel.c create mode 100644 arch/riscv/events/riscv_trace_sink.c diff --git a/arch/riscv/Kbuild b/arch/riscv/Kbuild index 126fb738fc44..8107a614c428 100644 --- a/arch/riscv/Kbuild +++ b/arch/riscv/Kbuild @@ -4,6 +4,7 @@ obj-y +=3D kernel/ mm/ net/ obj-$(CONFIG_CRYPTO) +=3D crypto/ obj-y +=3D errata/ obj-$(CONFIG_KVM) +=3D kvm/ +obj-$(CONFIG_PERF_EVENTS) +=3D events/ =20 obj-$(CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY) +=3D purgatory/ =20 diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 51dcd8eaa243..145d3424651b 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -1374,3 +1374,5 @@ endmenu # "CPU Power Management" source "arch/riscv/kvm/Kconfig" =20 source "drivers/acpi/Kconfig" + +source "arch/riscv/events/Kconfig" diff --git a/arch/riscv/events/Kconfig b/arch/riscv/events/Kconfig new file mode 100644 index 000000000000..c6fb073b29b1 --- /dev/null +++ b/arch/riscv/events/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +menu "Performance monitoring" + +config PERF_EVENTS_RISCV_TRACE + tristate "RISCV TRACE events" + depends on PERF_EVENTS && RISCV + default m + help + Include support for riscv trace events. + +endmenu diff --git a/arch/riscv/events/Makefile b/arch/riscv/events/Makefile new file mode 100644 index 000000000000..5014de2847df --- /dev/null +++ b/arch/riscv/events/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PERF_EVENTS_RISCV_TRACE) +=3D riscv_trace_pmu.o +riscv_trace_pmu-objs :=3D riscv_trace.o riscv_trace_encoder.o riscv_trace_= funnel.o riscv_trace_sink.o diff --git a/arch/riscv/events/riscv_trace.c b/arch/riscv/events/riscv_trac= e.c new file mode 100644 index 000000000000..e408d9a4034a --- /dev/null +++ b/arch/riscv/events/riscv_trace.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#include "riscv_trace.h" + +LIST_HEAD(riscv_trace_controllers); +static struct riscv_trace_pmu riscv_trace_pmu; + +PMU_FORMAT_ATTR(start_addr, "config:0-63"); +PMU_FORMAT_ATTR(stop_addr, "config1:0-63"); + +static struct attribute *riscv_trace_filter_attrs[] =3D { + &format_attr_start_addr.attr, + &format_attr_stop_addr.attr, + NULL, +}; + +static struct attribute_group riscv_trace_filter_attr_group =3D { + .name =3D "format", + .attrs =3D riscv_trace_filter_attrs, +}; + +static const struct attribute_group *riscv_trace_attr_groups[] =3D { + &riscv_trace_filter_attr_group, + NULL +}; + +static void riscv_trace_init_filter_attrs(struct perf_event *event) +{ + riscv_trace_pmu.filter_attr.start_addr =3D event->attr.config; + riscv_trace_pmu.filter_attr.stop_addr =3D event->attr.config1; + + if (event->attr.exclude_kernel) + riscv_trace_pmu.filter_attr.priv_mode =3D + RISCV_TRACE_PRIV_MODE_EXCL_KERN; + else if (event->attr.exclude_user) + riscv_trace_pmu.filter_attr.priv_mode =3D + RISCV_TRACE_PRIV_MODE_EXCL_USER; + else + riscv_trace_pmu.filter_attr.priv_mode =3D + RISCV_TRACE_PRIV_MODE_EXCL_NONE; + + pr_info("start_addr=3D0x%llx stop_addr=3D0x%llx priv_mode=3D%d\n", + riscv_trace_pmu.filter_attr.start_addr, + riscv_trace_pmu.filter_attr.stop_addr, + riscv_trace_pmu.filter_attr.priv_mode); +} + +static int riscv_trace_event_init(struct perf_event *event) +{ + if (event->attr.type !=3D riscv_trace_pmu.pmu.type) + return -ENOENT; + + riscv_trace_init_filter_attrs(event); + + return 0; +} + +static int riscv_trace_event_add(struct perf_event *event, int flags) +{ + pr_info("%s:%d\n", __func__, __LINE__); + // TODO: Configuring the trace component + return 0; +} + +static void riscv_trace_event_del(struct perf_event *event, int flags) +{ + // TODO: Reset the trace component + pr_info("%s:%d\n", __func__, __LINE__); +} + +static void riscv_trace_event_start(struct perf_event *event, int flags) +{ + pr_info("%s:%d on_cpu=3D%d cpu=3D%d\n", __func__, __LINE__, + event->oncpu, event->cpu); + // TODO: Enable the trace component +} + +static void riscv_trace_event_stop(struct perf_event *event, int flags) +{ + pr_info("%s:%d on_cpu=3D%d cpu=3D%d\n", __func__, __LINE__, + event->oncpu, event->cpu); + // TODO: Disable the trace component +} + +static int __init riscv_trace_init(void) +{ + struct riscv_trace_component *component; + + riscv_trace_encoder_init(); + riscv_trace_funnel_init(); + riscv_trace_sink_init(); + + if (get_list_count(&riscv_trace_controllers) =3D=3D 0) + return -ENXIO; + + list_for_each_entry(component, &riscv_trace_controllers, list) { + pr_info("type=3D%s in_num=3D%d out_num=3D%d\n", + riscv_trace_type2str(component->type), + component->in_num, component->out_num); + for (int i =3D 0; i < component->in_num; i++) { + pr_info("\t in[%d] type=3D%s base_addr=3D0x%llx\n", i, + riscv_trace_type2str(component->in[i]->type), + component->in[i]->base_addr); + } + for (int j =3D 0; j < component->out_num; j++) { + pr_info("\t out[%d] type=3D%s base_addr=3D0x%llx\n", j, + riscv_trace_type2str(component->out[j]->type), + component->out[j]->base_addr); + } + } + + riscv_trace_pmu.pmu.module =3D THIS_MODULE, + riscv_trace_pmu.pmu.name =3D "riscv_trace", + riscv_trace_pmu.pmu.capabilities =3D PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CA= P_ITRACE; + riscv_trace_pmu.pmu.attr_groups =3D riscv_trace_attr_groups; + riscv_trace_pmu.pmu.task_ctx_nr =3D perf_sw_context, + riscv_trace_pmu.pmu.event_init =3D riscv_trace_event_init; + riscv_trace_pmu.pmu.add =3D riscv_trace_event_add; + riscv_trace_pmu.pmu.del =3D riscv_trace_event_del; + riscv_trace_pmu.pmu.start =3D riscv_trace_event_start; + riscv_trace_pmu.pmu.stop =3D riscv_trace_event_stop; + + return perf_pmu_register(&riscv_trace_pmu.pmu, "riscv_trace", -1); +} + +static void __exit riscv_trace_exit(void) +{ + perf_pmu_unregister(&riscv_trace_pmu.pmu); +} + +module_init(riscv_trace_init); +module_exit(riscv_trace_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Chen Pei "); +MODULE_DESCRIPTION("Driver for RISC-V Trace Device"); diff --git a/arch/riscv/events/riscv_trace.h b/arch/riscv/events/riscv_trac= e.h new file mode 100644 index 000000000000..ef0af0d0b2ee --- /dev/null +++ b/arch/riscv/events/riscv_trace.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __RISCV_TRACE_H__ +#define __RISCV_TRACE_H__ + +#include +#include +#include +#include + +#define RISCV_TRACE_ADDR_MASK GENMASK(63, 0) + +enum RISCV_TRACE_COMPONENT_TYPE { + RISCV_TRACE_ENCODER =3D 0, + RISCV_TRACE_FUNNEL, + RISCV_TRACE_SINK, +}; + +enum RISCV_TRACE_FUNNEL_LEVEL { + LEVEL1_FUNNEL =3D 1, + LEVEL2_FUNNEL =3D 2, +}; + +enum RISCV_TRACE_PRIV_MODE_TYPE { + RISCV_TRACE_PRIV_MODE_EXCL_NONE =3D 0, + RISCV_TRACE_PRIV_MODE_EXCL_KERN, + RISCV_TRACE_PRIV_MODE_EXCL_USER, +}; + +struct riscv_trace_filter_attr { + u64 start_addr; + u64 stop_addr; + u32 priv_mode; // user&kernel +}; + +struct riscv_io_port { + bool is_input; // input=3D1, output=3D0 + u32 endpoint_num; + enum RISCV_TRACE_COMPONENT_TYPE type; + u64 base_addr; +}; + +struct riscv_trace_encoder { + u32 cpu; +}; + +struct riscv_trace_funnel { + enum RISCV_TRACE_FUNNEL_LEVEL level; +}; + +struct riscv_trace_sink { + ; +}; + +struct riscv_trace_component { + enum RISCV_TRACE_COMPONENT_TYPE type; + u64 reg_base; + u64 reg_size; + struct list_head list; + + union { + struct riscv_trace_encoder encoder; + struct riscv_trace_funnel funnel; + struct riscv_trace_sink sink; + }; + + u32 in_num; + u32 out_num; + struct riscv_io_port **in; + struct riscv_io_port **out; +}; + +extern struct list_head riscv_trace_controllers; + +struct riscv_trace_pmu { + struct pmu pmu; + struct riscv_trace_filter_attr filter_attr; +}; + +static inline const char *riscv_trace_type2str(enum RISCV_TRACE_COMPONENT_= TYPE + type) +{ + switch (type) { + case RISCV_TRACE_ENCODER: + return "encoder"; + case RISCV_TRACE_FUNNEL: + return "funnel"; + case RISCV_TRACE_SINK: + return "sink"; + default: + return "none"; + } +} + +static inline int count_device_node_child(struct device_node *parent) +{ + struct device_node *child; + int count =3D 0; + + for_each_child_of_node(parent, child) { + count++; + } + + return count; +} + +static inline int get_list_count(struct list_head *head) +{ + u32 count =3D 0; + struct list_head *pos; + + list_for_each(pos, head) { + count++; + } + + return count; +} + +int riscv_trace_encoder_init(void); +int riscv_trace_funnel_init(void); +int riscv_trace_sink_init(void); + +#endif /* __RISCV_TRACE_H__ */ diff --git a/arch/riscv/events/riscv_trace_encoder.c b/arch/riscv/events/ri= scv_trace_encoder.c new file mode 100644 index 000000000000..fb2c37c3561a --- /dev/null +++ b/arch/riscv/events/riscv_trace_encoder.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt + +#include +#include +#include +#include +#include + +#include "riscv_trace.h" + +static const struct of_device_id riscv_trace_encoder_of_match[] =3D { + {.compatible =3D "riscv_trace,encoder-controller", }, + { }, +}; + +int riscv_trace_encoder_init(void) +{ + struct riscv_trace_component *component; + struct device_node *node, *child_node, *port_node; + struct riscv_io_port *io_port; + resource_size_t base, size; + u32 reg[4]; + int port_nr; + int ret; + + for_each_matching_node(node, riscv_trace_encoder_of_match) { + if (!of_device_is_available(node)) { + of_node_put(node); + continue; + } + + component =3D kzalloc(sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + component->type =3D RISCV_TRACE_ENCODER; + + ret =3D of_property_read_u32_array(node, "reg", ®[0], 4); + if (ret) { + pr_err("Failed to read 'reg'\n"); + of_node_put(node); + return ret; + } + base =3D ((resource_size_t) reg[0] << 32) | reg[1]; + size =3D ((resource_size_t) reg[2] << 32) | reg[3]; + pr_info("base=3D0x%llx size=3D0x%llx\n", base, size); + component->reg_base =3D (u64)ioremap(base, size); + component->reg_size =3D size; + pr_info("reg_base=3D0x%llx reg_size=3D0x%llx\n", + component->reg_base, component->reg_size); + + ret =3D + of_property_read_u32(node, "cpu", &component->encoder.cpu); + if (ret) { + pr_err("Failed to read 'cpu'\n"); + of_node_put(node); + return ret; + } + pr_info("cpu=3D%d\n", component->encoder.cpu); + + child_node =3D of_get_child_by_name(node, "output_port"); + if (!child_node) { + pr_err("Failed to find 'output_port'\n"); + of_node_put(node); + return -ENODEV; + } + component->out_num =3D count_device_node_child(child_node); + if (component->out_num) { + component->out =3D + krealloc_array(component->out, component->out_num, + sizeof(*component->out), GFP_KERNEL); + if (!component->out) + return -ENOMEM; + port_nr =3D 0; + + for_each_child_of_node(child_node, port_node) { + if (!of_device_is_available(port_node)) { + of_node_put(child_node); + continue; + } + pr_info("Found output_port: %pOF\n", port_node); + const struct device_node *endpoint_node =3D + of_parse_phandle(port_node, "endpoint", 0); + pr_info("\t endpoint: %pOF\n", endpoint_node); + + of_property_read_u32_array((struct device_node + *)endpoint_node, + "reg", ®[0], 4); + + io_port =3D + kmalloc(sizeof(struct riscv_io_port), + GFP_KERNEL); + io_port->is_input =3D false; + io_port->endpoint_num =3D port_nr; + io_port->type =3D RISCV_TRACE_FUNNEL; + io_port->base_addr =3D + ((u64) reg[0] << 32) | reg[1]; + component->out[port_nr] =3D io_port; + port_nr++; + } + } + + INIT_LIST_HEAD(&component->list); + list_add_tail(&component->list, &riscv_trace_controllers); + } + + return ret; +} diff --git a/arch/riscv/events/riscv_trace_funnel.c b/arch/riscv/events/ris= cv_trace_funnel.c new file mode 100644 index 000000000000..c6d412fd1f90 --- /dev/null +++ b/arch/riscv/events/riscv_trace_funnel.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt + +#include +#include +#include +#include +#include + +#include "riscv_trace.h" + +static const struct of_device_id riscv_trace_funnel_of_match[] =3D { + {.compatible =3D "riscv_trace,funnel-controller", }, + { }, +}; + +int riscv_trace_funnel_init(void) +{ + struct riscv_trace_component *component; + struct device_node *node, *child_node, *port_node; + struct riscv_io_port *io_port; + resource_size_t base, size; + u32 reg[4]; + int port_nr; + int ret; + + for_each_matching_node(node, riscv_trace_funnel_of_match) { + if (!of_device_is_available(node)) { + of_node_put(node); + continue; + } + + component =3D kzalloc(sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + component->type =3D RISCV_TRACE_FUNNEL; + + ret =3D of_property_read_u32_array(node, "reg", ®[0], 4); + if (ret) { + pr_err("Failed to read 'reg'\n"); + of_node_put(node); + return ret; + } + base =3D ((resource_size_t) reg[0] << 32) | reg[1]; + size =3D ((resource_size_t) reg[2] << 32) | reg[3]; + pr_info("base=3D0x%llx size=3D0x%llx\n", base, size); + component->reg_base =3D (u64)ioremap(base, size); + component->reg_size =3D size; + pr_info("reg_base=3D0x%llx reg_size=3D0x%llx\n", + component->reg_base, component->reg_size); + + ret =3D + of_property_read_u32(node, "level", + &component->funnel.level); + if (ret) + component->funnel.level =3D LEVEL1_FUNNEL; + pr_info("funnel level=3D%d\n", component->funnel.level); + + child_node =3D of_get_child_by_name(node, "input_port"); + if (!child_node) { + pr_err("Failed to find 'input_port'\n"); + of_node_put(node); + return -ENODEV; + } + component->in_num =3D count_device_node_child(child_node); + if (component->in_num) { + component->in =3D + krealloc_array(component->in, component->in_num, + sizeof(*component->in), GFP_KERNEL); + if (!component->in) + return -ENOMEM; + port_nr =3D 0; + + for_each_child_of_node(child_node, port_node) { + if (!of_device_is_available(port_node)) { + of_node_put(child_node); + continue; + } + pr_info("Found input_port: %pOF\n", port_node); + const struct device_node *endpoint_node =3D + of_parse_phandle(port_node, "endpoint", 0); + pr_info("\t endpoint: %pOF\n", endpoint_node); + + of_property_read_u32_array((struct device_node + *)endpoint_node, + "reg", ®[0], 4); + + io_port =3D + kmalloc(sizeof(struct riscv_io_port), + GFP_KERNEL); + io_port->is_input =3D true; + io_port->endpoint_num =3D port_nr; + io_port->type =3D RISCV_TRACE_ENCODER; + io_port->base_addr =3D + ((u64) reg[0] << 32) | reg[1]; + component->in[port_nr] =3D io_port; + port_nr++; + } + } + + child_node =3D of_get_child_by_name(node, "output_port"); + if (!child_node) { + pr_err("Failed to find 'output_port'\n"); + of_node_put(node); + return -ENODEV; + } + component->out_num =3D count_device_node_child(child_node); + if (component->out_num) { + component->out =3D + krealloc_array(component->out, component->out_num, + sizeof(*component->out), GFP_KERNEL); + if (!component->out) + return -ENOMEM; + port_nr =3D 0; + + for_each_child_of_node(child_node, port_node) { + if (!of_device_is_available(port_node)) { + of_node_put(child_node); + continue; + } + pr_info("Found output_port: %pOF\n", port_node); + const struct device_node *endpoint_node =3D + of_parse_phandle(port_node, "endpoint", 0); + pr_info("\t endpoint: %pOF\n", endpoint_node); + + of_property_read_u32_array((struct device_node + *)endpoint_node, + "reg", ®[0], 4); + + io_port =3D + kmalloc(sizeof(struct riscv_io_port), + GFP_KERNEL); + io_port->is_input =3D false; + io_port->endpoint_num =3D port_nr; + io_port->type =3D RISCV_TRACE_SINK; + io_port->base_addr =3D + ((u64) reg[0] << 32) | reg[1]; + component->out[port_nr] =3D io_port; + port_nr++; + } + } + + for (int i =3D 0; i < component->in_num; i++) { + pr_info("\t in[%d]is_input=3D%d endpoint_num=3D%d\n", i, + component->in[i]->is_input, + component->in[i]->endpoint_num); + } + for (int j =3D 0; j < component->out_num; j++) { + pr_info("\t out[%d]is_input=3D%d endpoint_num=3D%d\n", j, + component->out[j]->is_input, + component->out[j]->endpoint_num); + } + + INIT_LIST_HEAD(&component->list); + list_add_tail(&component->list, &riscv_trace_controllers); + } + + return ret; +} diff --git a/arch/riscv/events/riscv_trace_sink.c b/arch/riscv/events/riscv= _trace_sink.c new file mode 100644 index 000000000000..dbdc153d798c --- /dev/null +++ b/arch/riscv/events/riscv_trace_sink.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt + +#include +#include +#include +#include +#include + +#include "riscv_trace.h" + +static const struct of_device_id riscv_trace_sink_of_match[] =3D { + {.compatible =3D "riscv_trace,sink-controller", }, + { }, +}; + +int riscv_trace_sink_init(void) +{ + struct riscv_trace_component *component; + struct device_node *node, *child_node, *port_node; + struct riscv_io_port *io_port; + resource_size_t base, size; + u32 reg[4]; + int port_nr; + int ret; + + for_each_matching_node(node, riscv_trace_sink_of_match) { + if (!of_device_is_available(node)) { + of_node_put(node); + continue; + } + + component =3D kzalloc(sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + component->type =3D RISCV_TRACE_SINK; + + ret =3D of_property_read_u32_array(node, "reg", ®[0], 4); + if (ret) { + pr_err("Failed to read 'reg'\n"); + of_node_put(node); + return ret; + } + base =3D ((resource_size_t) reg[0] << 32) | reg[1]; + size =3D ((resource_size_t) reg[2] << 32) | reg[3]; + pr_info("base=3D0x%llx size=3D0x%llx\n", base, size); + component->reg_base =3D (u64)ioremap(base, size); + component->reg_size =3D size; + pr_info("reg_base=3D0x%llx reg_size=3D0x%llx\n", + component->reg_base, component->reg_size); + + child_node =3D of_get_child_by_name(node, "input_port"); + if (!child_node) { + pr_err("Failed to find 'input_port'\n"); + of_node_put(node); + return -ENODEV; + } + component->in_num =3D count_device_node_child(child_node); + if (component->in_num) { + component->in =3D + krealloc_array(component->in, component->in_num, + sizeof(*component->in), GFP_KERNEL); + if (!component->in) + return -ENOMEM; + port_nr =3D 0; + + for_each_child_of_node(child_node, port_node) { + if (!of_device_is_available(port_node)) { + of_node_put(child_node); + continue; + } + pr_info("Found input_port: %pOF\n", port_node); + const struct device_node *endpoint_node =3D + of_parse_phandle(port_node, "endpoint", 0); + pr_info("\t endpoint: %pOF\n", endpoint_node); + + of_property_read_u32_array((struct device_node + *)endpoint_node, + "reg", ®[0], 4); + + io_port =3D + kmalloc(sizeof(struct riscv_io_port), + GFP_KERNEL); + io_port->is_input =3D true; + io_port->endpoint_num =3D port_nr; + io_port->type =3D RISCV_TRACE_FUNNEL; + io_port->base_addr =3D + ((u64) reg[0] << 32) | reg[1]; + component->in[port_nr] =3D io_port; + port_nr++; + } + } + + INIT_LIST_HEAD(&component->list); + list_add_tail(&component->list, &riscv_trace_controllers); + } + + return ret; +} --=20 2.49.0 From nobody Thu Oct 2 20:23:04 2025 Received: from out30-119.freemail.mail.aliyun.com (out30-119.freemail.mail.aliyun.com [115.124.30.119]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 90F13322A0B for ; Thu, 11 Sep 2025 12:45:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.119 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757594724; cv=none; b=WdPXjBp51+0kmsgaQd5bLk09usomV5Zz/cmBUy7+/uZhaZX0iEUsYkvl7r9/qzIhaKinxcKp39jDVilPv2jIS9wIjoP1Nh1irMa05+VNWdq6bz638pVbJXIKSvLI0EmZBy58qpW0bF9K7f/MJU3jEp1rpztebJ5l2FTDCLY/mrg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757594724; c=relaxed/simple; bh=Y40KNJ4Iscv4xXvptbceaOSSvRBVQbTNlbKyTVagcfA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oC5hmI/AJ5lrakzWaedhvHQYT4qA6K36n4v4B8aiaBiQIDnWdU2xH8oNaZMuqbR/r8sev1cfNFrBQ3+bRG9UmTGsosyM/OIg3fRWGxL4ko/VSluhuvMugH3imPzkiwsgkz1yyQv03E7R387jRGOj7Cux0rhdZ4YHUae3a/pEoKk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=xdV7qw7r; arc=none smtp.client-ip=115.124.30.119 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="xdV7qw7r" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1757594713; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=KlBG/qJSG3l98wLLhwHdyPoQRBJrGWD1/8eAfLJKJ5A=; b=xdV7qw7rEac9kA/Q5FBtNwLHlQDc/lmqWZ+AnuAMPjV1mfnQ6Je/FMDKqYeUmBQMBlghNj8xKZ3Vd8QAWf6Yl5Dt3dNYyOVcgZU9Kch8H+W8fZ48VgXltr4F42H0SPjC93X92SmQabII/Gt8rD1YterbvaqLK89rUNsEV1LcB78= Received: from DESKTOP-S9E58SO.localdomain(mailfrom:cp0613@linux.alibaba.com fp:SMTPD_---0WnmLJjN_1757594711 cluster:ay36) by smtp.aliyun-inc.com; Thu, 11 Sep 2025 20:45:12 +0800 From: cp0613@linux.alibaba.com To: paul.walmsley@sifive.com, palmer@dabbelt.com, aou@eecs.berkeley.edu, alex@ghiti.fr, guoren@kernel.org Cc: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, Chen Pei Subject: [RFC PATCH 3/4] tools: perf: Support perf record with aux buffer for riscv trace Date: Thu, 11 Sep 2025 20:44:47 +0800 Message-ID: <20250911124448.1771-4-cp0613@linux.alibaba.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250911124448.1771-1-cp0613@linux.alibaba.com> References: <20250911124448.1771-1-cp0613@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Chen Pei This patch implements AUXTRACE support for RISC-V Trace. The corresponding driver needs to implement the setup_aux and free_aux PMU driver ops. The aux buffer is a type of ring buffer used in trace scenarios, and RISC-V Trace should also reuse this capability. Signed-off-by: Chen Pei --- arch/riscv/events/riscv_trace.c | 61 ++++++++ arch/riscv/events/riscv_trace.h | 8 + tools/perf/arch/riscv/util/Build | 3 + tools/perf/arch/riscv/util/auxtrace.c | 33 ++++ tools/perf/arch/riscv/util/pmu.c | 18 +++ tools/perf/arch/riscv/util/riscv-trace.c | 183 +++++++++++++++++++++++ tools/perf/arch/riscv/util/tsc.c | 15 ++ tools/perf/util/Build | 1 + tools/perf/util/auxtrace.c | 4 + tools/perf/util/auxtrace.h | 1 + tools/perf/util/riscv-trace.c | 162 ++++++++++++++++++++ tools/perf/util/riscv-trace.h | 18 +++ 12 files changed, 507 insertions(+) create mode 100644 tools/perf/arch/riscv/util/auxtrace.c create mode 100644 tools/perf/arch/riscv/util/pmu.c create mode 100644 tools/perf/arch/riscv/util/riscv-trace.c create mode 100644 tools/perf/arch/riscv/util/tsc.c create mode 100644 tools/perf/util/riscv-trace.c create mode 100644 tools/perf/util/riscv-trace.h diff --git a/arch/riscv/events/riscv_trace.c b/arch/riscv/events/riscv_trac= e.c index e408d9a4034a..3ac4a3be5d3e 100644 --- a/arch/riscv/events/riscv_trace.c +++ b/arch/riscv/events/riscv_trace.c @@ -8,6 +8,7 @@ #include #include #include +#include =20 #include "riscv_trace.h" =20 @@ -81,6 +82,9 @@ static void riscv_trace_event_start(struct perf_event *ev= ent, int flags) { pr_info("%s:%d on_cpu=3D%d cpu=3D%d\n", __func__, __LINE__, event->oncpu, event->cpu); + // TODO: Begin aux buffer + // struct xuantie_ntrace_aux_buf *buf; + // buf =3D perf_aux_output_begin(&riscv_trace_pmu.handle, event); // TODO: Enable the trace component } =20 @@ -89,6 +93,61 @@ static void riscv_trace_event_stop(struct perf_event *ev= ent, int flags) pr_info("%s:%d on_cpu=3D%d cpu=3D%d\n", __func__, __LINE__, event->oncpu, event->cpu); // TODO: Disable the trace component + // TODO: End aux buffer + // struct xuantie_ntrace_aux_buf *buf; + // buf =3D perf_get_aux(&riscv_trace_pmu.handle); + // Fill aux buffer + // perf_aux_output_end(&riscv_trace_pmu.handle, size); +} + +static void *riscv_trace_buffer_setup_aux(struct perf_event *event, void *= *pages, + int nr_pages, bool overwrite) +{ + struct riscv_trace_aux_buf *buf; + struct page **pagelist; + int i; + + if (overwrite) { + pr_warn("Overwrite mode is not supported\n"); + return NULL; + } + + buf =3D kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return NULL; + + pagelist =3D kcalloc(nr_pages, sizeof(*pagelist), GFP_KERNEL); + if (!pagelist) + goto err; + + for (i =3D 0; i < nr_pages; i++) + pagelist[i] =3D virt_to_page(pages[i]); + + buf->base =3D vmap(pagelist, nr_pages, VM_MAP, PAGE_KERNEL); + if (!buf->base) { + kfree(pagelist); + goto err; + } + + buf->nr_pages =3D nr_pages; + buf->length =3D nr_pages * PAGE_SIZE; + buf->pos =3D 0; + + pr_info("nr_pages=3D%d length=3D%d\n", buf->nr_pages, buf->length); + + kfree(pagelist); + return buf; +err: + kfree(buf); + return NULL; +} + +static void riscv_trace_buffer_free_aux(void *aux) +{ + struct riscv_trace_aux_buf *buf =3D aux; + + vunmap(buf->base); + kfree(buf); } =20 static int __init riscv_trace_init(void) @@ -128,6 +187,8 @@ static int __init riscv_trace_init(void) riscv_trace_pmu.pmu.del =3D riscv_trace_event_del; riscv_trace_pmu.pmu.start =3D riscv_trace_event_start; riscv_trace_pmu.pmu.stop =3D riscv_trace_event_stop; + riscv_trace_pmu.pmu.setup_aux =3D riscv_trace_buffer_setup_aux; + riscv_trace_pmu.pmu.free_aux =3D riscv_trace_buffer_free_aux; =20 return perf_pmu_register(&riscv_trace_pmu.pmu, "riscv_trace", -1); } diff --git a/arch/riscv/events/riscv_trace.h b/arch/riscv/events/riscv_trac= e.h index ef0af0d0b2ee..c28216227006 100644 --- a/arch/riscv/events/riscv_trace.h +++ b/arch/riscv/events/riscv_trace.h @@ -75,6 +75,14 @@ extern struct list_head riscv_trace_controllers; struct riscv_trace_pmu { struct pmu pmu; struct riscv_trace_filter_attr filter_attr; + struct perf_output_handle handle; +}; + +struct riscv_trace_aux_buf { + u32 length; + u32 nr_pages; + void *base; + u32 pos; }; =20 static inline const char *riscv_trace_type2str(enum RISCV_TRACE_COMPONENT_= TYPE diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/= Build index 58a672246024..d1599b70ef2f 100644 --- a/tools/perf/arch/riscv/util/Build +++ b/tools/perf/arch/riscv/util/Build @@ -1,5 +1,8 @@ perf-util-y +=3D perf_regs.o perf-util-y +=3D header.o +perf-util-y +=3D tsc.o =20 perf-util-$(CONFIG_LIBTRACEEVENT) +=3D kvm-stat.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) +=3D unwind-libdw.o + +perf-util-$(CONFIG_AUXTRACE) +=3D pmu.o auxtrace.o riscv-trace.o diff --git a/tools/perf/arch/riscv/util/auxtrace.c b/tools/perf/arch/riscv/= util/auxtrace.c new file mode 100644 index 000000000000..51c8dac5ff61 --- /dev/null +++ b/tools/perf/arch/riscv/util/auxtrace.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + +#include "../../../util/auxtrace.h" +#include "../../../util/debug.h" +#include "../../../util/evlist.h" +#include "../../../util/pmu.h" +#include "../../../util/pmus.h" +#include "riscv-trace.h" + +struct auxtrace_record +*auxtrace_record__init(struct evlist *evlist, int *err) +{ + struct perf_pmu *riscv_trace_pmu =3D NULL; + struct evsel *evsel; + bool found_riscv_trace =3D false; + + riscv_trace_pmu =3D perf_pmus__find(RISCV_TRACE_PMU_NAME); + + evlist__for_each_entry(evlist, evsel) { + if (riscv_trace_pmu && evsel->core.attr.type =3D=3D riscv_trace_pmu->typ= e) + found_riscv_trace =3D true; + } + + if (found_riscv_trace) + return riscv_trace_recording_init(err, riscv_trace_pmu); + + return NULL; +} diff --git a/tools/perf/arch/riscv/util/pmu.c b/tools/perf/arch/riscv/util/= pmu.c new file mode 100644 index 000000000000..921b083c4f6b --- /dev/null +++ b/tools/perf/arch/riscv/util/pmu.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#include "riscv-trace.h" +#include "../../../util/pmu.h" + +void perf_pmu__arch_init(struct perf_pmu *pmu) +{ +#ifdef HAVE_AUXTRACE_SUPPORT + if (!strcmp(pmu->name, RISCV_TRACE_PMU_NAME)) { + pmu->auxtrace =3D true; + pmu->selectable =3D true; + } +#endif +} diff --git a/tools/perf/arch/riscv/util/riscv-trace.c b/tools/perf/arch/ris= cv/util/riscv-trace.c new file mode 100644 index 000000000000..0632f1f43c15 --- /dev/null +++ b/tools/perf/arch/riscv/util/riscv-trace.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include + +#include // page_size +#include "../../../util/auxtrace.h" +#include "../../../util/cpumap.h" +#include "../../../util/debug.h" +#include "../../../util/event.h" +#include "../../../util/evlist.h" +#include "../../../util/evsel.h" +#include "../../../util/pmu.h" +#include "../../../util/record.h" +#include "../../../util/session.h" +#include "../../../util/tsc.h" +#include "../../../util/riscv-trace.h" + +#define KiB(x) ((x) * 1024) +#define MiB(x) ((x) * 1024 * 1024) + +struct riscv_trace_recording { + struct auxtrace_record itr; + struct perf_pmu *riscv_trace_pmu; + struct evlist *evlist; +}; + +static size_t +riscv_trace_info_priv_size(struct auxtrace_record *itr __maybe_unused, + struct evlist *evlist __maybe_unused) +{ + return RISCV_TRACE_AUXTRACE_PRIV_SIZE; +} + +static int riscv_trace_info_fill(struct auxtrace_record *itr, + struct perf_session *session, + struct perf_record_auxtrace_info *auxtrace_info, + size_t priv_size) +{ + struct riscv_trace_recording *pttr =3D + container_of(itr, struct riscv_trace_recording, itr); + struct perf_pmu *riscv_trace_pmu =3D pttr->riscv_trace_pmu; + + if (priv_size !=3D RISCV_TRACE_AUXTRACE_PRIV_SIZE) + return -EINVAL; + + if (!session->evlist->core.nr_mmaps) + return -EINVAL; + + auxtrace_info->type =3D PERF_AUXTRACE_RISCV_TRACE; + auxtrace_info->priv[0] =3D riscv_trace_pmu->type; + + return 0; +} + +static int riscv_trace_set_auxtrace_mmap_page(struct record_opts *opts) +{ + bool privileged =3D perf_event_paranoid_check(-1); + + if (!opts->full_auxtrace) + return 0; + + if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { + if (privileged) { + opts->auxtrace_mmap_pages =3D MiB(16) / page_size; + } else { + opts->auxtrace_mmap_pages =3D KiB(128) / page_size; + if (opts->mmap_pages =3D=3D UINT_MAX) + opts->mmap_pages =3D KiB(256) / page_size; + } + } + + /* Validate auxtrace_mmap_pages */ + if (opts->auxtrace_mmap_pages) { + size_t sz =3D opts->auxtrace_mmap_pages * (size_t)page_size; + size_t min_sz =3D KiB(8); + + if (sz < min_sz || !is_power_of_2(sz)) { + pr_err("Invalid mmap size for riscv trace: must be at least %zuKiB and = a power of 2\n", + min_sz / 1024); + return -EINVAL; + } + } + + return 0; +} + +static int riscv_trace_recording_options(struct auxtrace_record *itr, + struct evlist *evlist, + struct record_opts *opts) +{ + struct riscv_trace_recording *pttr =3D + container_of(itr, struct riscv_trace_recording, itr); + struct perf_pmu *riscv_trace_pmu =3D pttr->riscv_trace_pmu; + struct evsel *evsel, *riscv_trace_evsel =3D NULL; + struct evsel *tracking_evsel; + int err; + + pttr->evlist =3D evlist; + evlist__for_each_entry(evlist, evsel) { + if (evsel->core.attr.type =3D=3D riscv_trace_pmu->type) { + if (riscv_trace_evsel) { + pr_err("There may be only one " RISCV_TRACE_PMU_NAME "x event\n"); + return -EINVAL; + } + evsel->core.attr.freq =3D 0; + evsel->core.attr.sample_period =3D 1; + evsel->needs_auxtrace_mmap =3D true; + riscv_trace_evsel =3D evsel; + opts->full_auxtrace =3D true; + } + } + + err =3D riscv_trace_set_auxtrace_mmap_page(opts); + if (err) + return err; + /* + * To obtain the auxtrace buffer file descriptor, the auxtrace event + * must come first. + */ + evlist__to_front(evlist, riscv_trace_evsel); + evsel__set_sample_bit(riscv_trace_evsel, TIME); + + /* Add dummy event to keep tracking */ + err =3D parse_event(evlist, "dummy:u"); + if (err) + return err; + + tracking_evsel =3D evlist__last(evlist); + evlist__set_tracking_event(evlist, tracking_evsel); + + tracking_evsel->core.attr.freq =3D 0; + tracking_evsel->core.attr.sample_period =3D 1; + evsel__set_sample_bit(tracking_evsel, TIME); + + return 0; +} + +static u64 riscv_trace_reference(struct auxtrace_record *itr __maybe_unuse= d) +{ + return rdtsc(); +} + +static void riscv_trace_recording_free(struct auxtrace_record *itr) +{ + struct riscv_trace_recording *pttr =3D + container_of(itr, struct riscv_trace_recording, itr); + + free(pttr); +} + +struct auxtrace_record *riscv_trace_recording_init(int *err, + struct perf_pmu *riscv_trace_pmu) +{ + struct riscv_trace_recording *pttr; + + if (!riscv_trace_pmu) { + *err =3D -ENODEV; + return NULL; + } + + pttr =3D zalloc(sizeof(*pttr)); + if (!pttr) { + *err =3D -ENOMEM; + return NULL; + } + + pttr->riscv_trace_pmu =3D riscv_trace_pmu; + pttr->itr.recording_options =3D riscv_trace_recording_options; + pttr->itr.info_priv_size =3D riscv_trace_info_priv_size; + pttr->itr.info_fill =3D riscv_trace_info_fill; + pttr->itr.free =3D riscv_trace_recording_free; + pttr->itr.reference =3D riscv_trace_reference; + pttr->itr.read_finish =3D auxtrace_record__read_finish; + pttr->itr.alignment =3D 0; + + *err =3D 0; + return &pttr->itr; +} diff --git a/tools/perf/arch/riscv/util/tsc.c b/tools/perf/arch/riscv/util/= tsc.c new file mode 100644 index 000000000000..cf021e423f79 --- /dev/null +++ b/tools/perf/arch/riscv/util/tsc.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#include "../../../util/tsc.h" + +u64 rdtsc(void) +{ + u64 val; + + // https://lore.kernel.org/all/YxIzgYP3MujXdqwj@aurel32.net/T/ + asm volatile("rdtime %0" : "=3Dr"(val)); + + return val; +} diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 4959e7a990e4..4726a100a156 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -136,6 +136,7 @@ perf-util-$(CONFIG_AUXTRACE) +=3D arm-spe-decoder/ perf-util-$(CONFIG_AUXTRACE) +=3D hisi-ptt.o perf-util-$(CONFIG_AUXTRACE) +=3D hisi-ptt-decoder/ perf-util-$(CONFIG_AUXTRACE) +=3D s390-cpumsf.o +perf-util-$(CONFIG_AUXTRACE) +=3D riscv-trace.o =20 ifdef CONFIG_LIBOPENCSD perf-util-$(CONFIG_AUXTRACE) +=3D cs-etm.o diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index ebd32f1b8f12..b4d8f3c5ebb1 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -54,6 +54,7 @@ #include "arm-spe.h" #include "hisi-ptt.h" #include "s390-cpumsf.h" +#include "riscv-trace.h" #include "util/mmap.h" =20 #include @@ -1393,6 +1394,9 @@ int perf_event__process_auxtrace_info(struct perf_ses= sion *session, case PERF_AUXTRACE_HISI_PTT: err =3D hisi_ptt_process_auxtrace_info(event, session); break; + case PERF_AUXTRACE_RISCV_TRACE: + err =3D riscv_trace_process_auxtrace_info(event, session); + break; case PERF_AUXTRACE_UNKNOWN: default: return -EINVAL; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index f001cbb68f8e..5b7ce4a99709 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -50,6 +50,7 @@ enum auxtrace_type { PERF_AUXTRACE_ARM_SPE, PERF_AUXTRACE_S390_CPUMSF, PERF_AUXTRACE_HISI_PTT, + PERF_AUXTRACE_RISCV_TRACE, }; =20 enum itrace_period_type { diff --git a/tools/perf/util/riscv-trace.c b/tools/perf/util/riscv-trace.c new file mode 100644 index 000000000000..c9bc3f6a7857 --- /dev/null +++ b/tools/perf/util/riscv-trace.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "auxtrace.h" +#include "color.h" +#include "debug.h" +#include "evsel.h" +#include "riscv-trace.h" +#include "machine.h" +#include "session.h" +#include "tool.h" +#include + +struct riscv_trace { + struct auxtrace auxtrace; + u32 auxtrace_type; + struct perf_session *session; + struct machine *machine; + u32 pmu_type; +}; + +static void riscv_trace_dump(struct riscv_trace *trace __maybe_unused, + unsigned char *buf, size_t len) +{ + + const char *color =3D PERF_COLOR_BLUE; + + color_fprintf(stdout, color, ". ... %s: buf=3D%p len=3D%zubytes\n", __fun= c__, buf, len); + for (size_t i =3D 0; i < len; i++) + printf("%02x ", buf[i]); +} + +static void riscv_trace_dump_event(struct riscv_trace *trace, unsigned cha= r *buf, + size_t len) +{ + printf(".\n"); + + riscv_trace_dump(trace, buf, len); +} + +static int riscv_trace_process_event(struct perf_session *session __maybe_= unused, + union perf_event *event __maybe_unused, + struct perf_sample *sample __maybe_unused, + const struct perf_tool *tool __maybe_unused) +{ + return 0; +} + +static int riscv_trace_process_auxtrace_event(struct perf_session *session, + union perf_event *event, + const struct perf_tool *tool __maybe_unused) +{ + struct riscv_trace *trace =3D container_of(session->auxtrace, struct risc= v_trace, + auxtrace); + int fd =3D perf_data__fd(session->data); + int size =3D event->auxtrace.size; + void *data =3D malloc(size); + off_t data_offset; + int err; + + if (!data) + return -errno; + + if (perf_data__is_pipe(session->data)) { + data_offset =3D 0; + } else { + data_offset =3D lseek(fd, 0, SEEK_CUR); + if (data_offset =3D=3D -1) { + free(data); + return -errno; + } + } + + err =3D readn(fd, data, size); + if (err !=3D (ssize_t)size) { + free(data); + return -errno; + } + + if (dump_trace) + riscv_trace_dump_event(trace, data, size); + + free(data); + return 0; +} + +static int riscv_trace_flush(struct perf_session *session __maybe_unused, + const struct perf_tool *tool __maybe_unused) +{ + return 0; +} + +static void riscv_trace_free_events(struct perf_session *session __maybe_u= nused) +{ +} + +static void riscv_trace_free(struct perf_session *session) +{ + struct riscv_trace *trace =3D container_of(session->auxtrace, struct risc= v_trace, + auxtrace); + + session->auxtrace =3D NULL; + free(trace); +} + +static bool riscv_trace_evsel_is_auxtrace(struct perf_session *session, + struct evsel *evsel) +{ + struct riscv_trace *trace =3D container_of(session->auxtrace, struct risc= v_trace, auxtrace); + + return evsel->core.attr.type =3D=3D trace->pmu_type; +} + +static void riscv_trace_print_info(__u64 type) +{ + if (!dump_trace) + return; + + fprintf(stdout, " PMU Type %" PRId64 "\n", (s64) type); +} + +int riscv_trace_process_auxtrace_info(union perf_event *event, + struct perf_session *session) +{ + struct perf_record_auxtrace_info *auxtrace_info =3D &event->auxtrace_info; + struct riscv_trace *trace; + + if (auxtrace_info->header.size < RISCV_TRACE_AUXTRACE_PRIV_SIZE + + sizeof(struct perf_record_auxtrace_info)) + return -EINVAL; + + trace =3D zalloc(sizeof(*trace)); + if (!trace) + return -ENOMEM; + + trace->session =3D session; + trace->machine =3D &session->machines.host; /* No kvm support */ + trace->auxtrace_type =3D auxtrace_info->type; + trace->pmu_type =3D auxtrace_info->priv[0]; + + trace->auxtrace.process_event =3D riscv_trace_process_event; + trace->auxtrace.process_auxtrace_event =3D riscv_trace_process_auxtrace_e= vent; + trace->auxtrace.flush_events =3D riscv_trace_flush; + trace->auxtrace.free_events =3D riscv_trace_free_events; + trace->auxtrace.free =3D riscv_trace_free; + trace->auxtrace.evsel_is_auxtrace =3D riscv_trace_evsel_is_auxtrace; + session->auxtrace =3D &trace->auxtrace; + + riscv_trace_print_info(auxtrace_info->priv[0]); + + return 0; +} diff --git a/tools/perf/util/riscv-trace.h b/tools/perf/util/riscv-trace.h new file mode 100644 index 000000000000..4901ea323b77 --- /dev/null +++ b/tools/perf/util/riscv-trace.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef INCLUDE__PERF_RISCV_TRACE_H__ +#define INCLUDE__PERF_RISCV_TRACE_H__ + +#define RISCV_TRACE_PMU_NAME "riscv_trace" +#define RISCV_TRACE_AUXTRACE_PRIV_SIZE sizeof(u64) + +union perf_event; +struct perf_session; +struct perf_pmu; + +struct auxtrace_record *riscv_trace_recording_init(int *err, + struct perf_pmu *riscv_ntrace_pmu); + +int riscv_trace_process_auxtrace_info(union perf_event *event, + struct perf_session *session); + +#endif --=20 2.49.0 From nobody Thu Oct 2 20:23:04 2025 Received: from out30-101.freemail.mail.aliyun.com (out30-101.freemail.mail.aliyun.com [115.124.30.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9474A32276F for ; Thu, 11 Sep 2025 12:45:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757594720; cv=none; b=H+H7AriQG3nGQsF3MNTiWl+hEuXoChpuP/2FwDUjKVI/J1UGoKYjuCmf/XIKjGJxrJ7R9qg2SxesVsMrr8YvtWeitHVm1XrOTcJ14ei3vT9BVRQW+BxsGGY6dErzhLIySFghCeWTtwlJKo2lhLKan8r2KQxm1DYWTUxCaWJXj+g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757594720; c=relaxed/simple; bh=kohYFVXIspoaPKJua62Rblg42hVWuEWH4mMzi3ehyc4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rKLHsZ7Cu/CYSlcb8BQkdEon9ki0jeudf6N3aHBaCsJ5j91d3FjznrfLcsMp6w0ZIgt43Uv43iGdPEvczZBp7vniLy62ntTqPq4vFEllgE+VBp50EGUGl9+lrdxQY1tPQ7PBlW4WeF4FSxpSrjisPVyhpF6nciT7Mhw7xq7wO5M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=Xn8Tawu/; arc=none smtp.client-ip=115.124.30.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="Xn8Tawu/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1757594714; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=klrJ7g5FLgpuRyahGw6eB5ihL1iuaDQ6Jxw1/EVd0js=; b=Xn8Tawu/lSHe5b+OTSAts4Qr+ckhRNC9D/ewvfXDSE1q5MCBFTc2NJ6ESgZahBeI/qDYK9Jf2esy6Q3ifVNszXXBpsMTjZpUQs8/dcOplB7cUm98mdp2kP1F3zGKYLQ0VmwZbRdoiidYWsW0CpnbARpcYZid51UYYyMcWOU1gYs= Received: from DESKTOP-S9E58SO.localdomain(mailfrom:cp0613@linux.alibaba.com fp:SMTPD_---0WnmLJjq_1757594712 cluster:ay36) by smtp.aliyun-inc.com; Thu, 11 Sep 2025 20:45:13 +0800 From: cp0613@linux.alibaba.com To: paul.walmsley@sifive.com, palmer@dabbelt.com, aou@eecs.berkeley.edu, alex@ghiti.fr, guoren@kernel.org Cc: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, Chen Pei Subject: [RFC PATCH 4/4] riscv: trace: Support sink using dma buffer Date: Thu, 11 Sep 2025 20:44:48 +0800 Message-ID: <20250911124448.1771-5-cp0613@linux.alibaba.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250911124448.1771-1-cp0613@linux.alibaba.com> References: <20250911124448.1771-1-cp0613@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Chen Pei In common SoC systems, the trace data by the sink is usually written to the memory, and the memory needs to be a large block. We have two methods to achieve this. One is based on reserved memory. This method requires pre-isolation of memory and is not flexible enough. Therefore, we chose the second method, which is based on IOMMU to map non-contiguous memory to continuous. When implementing the driver, only the DMA alloc related APIs are needed. Signed-off-by: Chen Pei --- arch/riscv/events/riscv_trace.c | 49 ++++++++++++++++++++++++++++++++- arch/riscv/events/riscv_trace.h | 4 ++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/arch/riscv/events/riscv_trace.c b/arch/riscv/events/riscv_trac= e.c index 3ac4a3be5d3e..e8deaefa0180 100644 --- a/arch/riscv/events/riscv_trace.c +++ b/arch/riscv/events/riscv_trace.c @@ -9,6 +9,7 @@ #include #include #include +#include =20 #include "riscv_trace.h" =20 @@ -55,6 +56,44 @@ static void riscv_trace_init_filter_attrs(struct perf_ev= ent *event) riscv_trace_pmu.filter_attr.priv_mode); } =20 +static int riscv_trace_sink_dma_alloc(unsigned long size) +{ + struct riscv_trace_component *component; + dma_addr_t dma_addr; + + list_for_each_entry(component, &riscv_trace_controllers, list) { + if (component->type =3D=3D RISCV_TRACE_SINK) { + component->sink.vaddr =3D + dma_alloc_coherent(riscv_trace_pmu.pmu.dev, size, + &dma_addr, GFP_KERNEL); + if (component->sink.vaddr) { + component->sink.start_addr =3D dma_addr; + component->sink.limit_addr =3D dma_addr + size; + continue; + } else { + pr_err("dma_alloc_coherent failed\n"); + return -ENOMEM; + } + } + } + + return 0; +} + +static void riscv_trace_sink_dma_free(void) +{ + struct riscv_trace_component *component; + + list_for_each_entry(component, &riscv_trace_controllers, list) { + if (component->type =3D=3D RISCV_TRACE_SINK) { + if (component->sink.vaddr) + dma_free_coherent(riscv_trace_pmu.pmu.dev, + component->sink.limit_addr - component->sink.start_addr, + component->sink.vaddr, component->sink.start_addr); + } + } +} + static int riscv_trace_event_init(struct perf_event *event) { if (event->attr.type !=3D riscv_trace_pmu.pmu.type) @@ -105,7 +144,7 @@ static void *riscv_trace_buffer_setup_aux(struct perf_e= vent *event, void **pages { struct riscv_trace_aux_buf *buf; struct page **pagelist; - int i; + int i, ret; =20 if (overwrite) { pr_warn("Overwrite mode is not supported\n"); @@ -135,6 +174,12 @@ static void *riscv_trace_buffer_setup_aux(struct perf_= event *event, void **pages =20 pr_info("nr_pages=3D%d length=3D%d\n", buf->nr_pages, buf->length); =20 + ret =3D riscv_trace_sink_dma_alloc(buf->length); + if (ret) { + kfree(pagelist); + goto err; + } + kfree(pagelist); return buf; err: @@ -148,6 +193,8 @@ static void riscv_trace_buffer_free_aux(void *aux) =20 vunmap(buf->base); kfree(buf); + + riscv_trace_sink_dma_free(); } =20 static int __init riscv_trace_init(void) diff --git a/arch/riscv/events/riscv_trace.h b/arch/riscv/events/riscv_trac= e.h index c28216227006..7819fbeace1f 100644 --- a/arch/riscv/events/riscv_trace.h +++ b/arch/riscv/events/riscv_trace.h @@ -49,7 +49,9 @@ struct riscv_trace_funnel { }; =20 struct riscv_trace_sink { - ; + u64 start_addr; + u64 limit_addr; + void __iomem *vaddr; }; =20 struct riscv_trace_component { --=20 2.49.0