lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAN37VV730N1Z=D7tuMj79yHRPS1QETLmg10+huKUvNq8QtndoQ@mail.gmail.com>
Date: Mon, 9 Feb 2026 17:13:08 +0530
From: Mayuresh Chitale <mchitale@...tanamicro.com>
To: Eric Lin <eric.lin@...ive.com>
Cc: Anup Patel <apatel@...tanamicro.com>, Rob Herring <robh@...nel.org>, 
	Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley <conor+dt@...nel.org>, 
	Paul Walmsley <paul.walmsley@...ive.com>, Palmer Dabbelt <palmer@...belt.com>, 
	Greg KH <gregkh@...uxfoundation.org>, 
	Alexander Shishkin <alexander.shishkin@...ux.intel.com>, Ian Rogers <irogers@...gle.com>, 
	Mark Rutland <mark.rutland@....com>, devicetree@...r.kernel.org, 
	Alexandre Ghiti <alex@...ti.fr>, Atish Patra <atish.patra@...ux.dev>, 
	Peter Zijlstra <peterz@...radead.org>, Anup Patel <anup@...infault.org>, 
	Adrian Hunter <adrian.hunter@...el.com>, linux-kernel@...r.kernel.org, 
	Ingo Molnar <mingo@...hat.com>, Jiri Olsa <jolsa@...nel.org>, 
	Mayuresh Chitale <mchitale@...il.com>, Namhyung Kim <namhyung@...nel.org>, 
	linux-riscv@...ts.infradead.org, Andrew Jones <ajones@...tanamicro.com>, 
	Liang Kan <kan.liang@...ux.intel.com>
Subject: Re: [PATCH v2 09/12] rvtrace: Add perf driver for tracing using perf tool

Hi Eric,

On Fri, Feb 6, 2026 at 6:37 PM Eric Lin <eric.lin@...ive.com> wrote:
>
> Hi Anup,
>
> On Sat, Nov 1, 2025 at 11:45 PM Anup Patel <apatel@...tanamicro.com> wrote:
> >
> > From: Mayuresh Chitale <mchitale@...tanamicro.com>
> >
> > Add perf driver for RISC-V tracing similar to ARM Coresight and Hisilicon
> > PTT drivers. The driver adds 'rvtrace' event descriptor which can be used
> > by the perf tool to record the RISC-V trace data.
> >
> > Co-developed-by: Anup Patel <apatel@...tanamicro.com>
> > Signed-off-by: Anup Patel <apatel@...tanamicro.com>
> > Signed-off-by: Mayuresh Chitale <mchitale@...tanamicro.com>
> > ---
> >  drivers/hwtracing/rvtrace/Kconfig        |   1 +
> >  drivers/hwtracing/rvtrace/Makefile       |   2 +-
> >  drivers/hwtracing/rvtrace/rvtrace-core.c |   8 +
> >  drivers/hwtracing/rvtrace/rvtrace-perf.c | 343 +++++++++++++++++++++++
> >  include/linux/rvtrace.h                  |   3 +
> >  5 files changed, 356 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/hwtracing/rvtrace/rvtrace-perf.c
> >
> > diff --git a/drivers/hwtracing/rvtrace/Kconfig b/drivers/hwtracing/rvtrace/Kconfig
> > index 0577f9acb858..ba11acf1117d 100644
> > --- a/drivers/hwtracing/rvtrace/Kconfig
> > +++ b/drivers/hwtracing/rvtrace/Kconfig
> > @@ -4,6 +4,7 @@ menuconfig RVTRACE
> >         tristate "RISC-V Trace Support"
> >         depends on RISCV
> >         depends on OF
> > +       select PERF_EVENTS
> >         default RISCV
> >         help
> >           This framework provides a kernel interface for the RISC-V trace
> > diff --git a/drivers/hwtracing/rvtrace/Makefile b/drivers/hwtracing/rvtrace/Makefile
> > index 122e575da9fb..07403f4d94e3 100644
> > --- a/drivers/hwtracing/rvtrace/Makefile
> > +++ b/drivers/hwtracing/rvtrace/Makefile
> > @@ -1,6 +1,6 @@
> >  # SPDX-License-Identifier: GPL-2.0
> >
> >  obj-$(CONFIG_RVTRACE) += rvtrace.o
> > -rvtrace-y := rvtrace-core.o rvtrace-platform.o
> > +rvtrace-y := rvtrace-core.o rvtrace-platform.o rvtrace-perf.o
> >  obj-$(CONFIG_RVTRACE_ENCODER) += rvtrace-encoder.o
> >  obj-$(CONFIG_RVTRACE_RAMSINK) += rvtrace-ramsink.o
> > diff --git a/drivers/hwtracing/rvtrace/rvtrace-core.c b/drivers/hwtracing/rvtrace/rvtrace-core.c
> > index b955e5f3b048..bbe39aaf930d 100644
> > --- a/drivers/hwtracing/rvtrace/rvtrace-core.c
> > +++ b/drivers/hwtracing/rvtrace/rvtrace-core.c
> > @@ -777,11 +777,19 @@ static int __init rvtrace_init(void)
> >                 return ret;
> >         }
> >
> > +       ret = rvtrace_perf_init();
> > +       if (ret) {
> > +               platform_driver_unregister(&rvtrace_platform_driver);
> > +               bus_unregister(&rvtrace_bustype);
> > +               return ret;
> > +       }
> > +
> >         return 0;
> >  }
> >
> >  static void __exit rvtrace_exit(void)
> >  {
> > +       rvtrace_perf_exit();
> >         platform_driver_unregister(&rvtrace_platform_driver);
> >         bus_unregister(&rvtrace_bustype);
> >  }
> > diff --git a/drivers/hwtracing/rvtrace/rvtrace-perf.c b/drivers/hwtracing/rvtrace/rvtrace-perf.c
> > new file mode 100644
> > index 000000000000..2d3039f8b681
> > --- /dev/null
> > +++ b/drivers/hwtracing/rvtrace/rvtrace-perf.c
> > @@ -0,0 +1,343 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright(C) 2025 Ventanamicro Limited. All rights reserved.
> > + * Author: Mayuresh Chitale <mchitale@...anamicro.com>
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/cpumask.h>
> > +#include <linux/device.h>
> > +#include <linux/list.h>
> > +#include <linux/mm.h>
> > +#include <linux/init.h>
> > +#include <linux/perf_event.h>
> > +#include <linux/vmalloc.h>
> > +#include <linux/percpu-defs.h>
> > +#include <linux/slab.h>
> > +#include <linux/stringhash.h>
> > +#include <linux/types.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/rvtrace.h>
> > +
> > +#define RVTRACE_PMU_NAME "rvtrace"
> > +#define RVTRACE_BUF_LEN (4 * 1024 * 1024)
>
> Currently, it seems "RVTRACE_BUF_LEN" is not used. Should we remove it?
Yes, it can be removed.

> Best regards,
> Eric Lin
>
> > +
> > +static struct pmu rvtrace_pmu;
> > +static DEFINE_SPINLOCK(perf_buf_lock);
> > +
> > +/**
> > + * struct rvtrace_event_data - RISC-V trace specific perf event data
> > + * @work:              Handle to free allocated memory outside IRQ context.
> > + * @mask:              Hold the CPU(s) this event was set for.
> > + * @aux_hwid_done:     Whether a CPU has emitted the TraceID packet or not.
> > + * @path:              An array of path, each slot for one CPU.
> > + * @buf:               Aux buffer / pages allocated by perf framework.
> > + */
> > +struct rvtrace_event_data {
> > +       struct work_struct work;
> > +       cpumask_t mask;
> > +       cpumask_t aux_hwid_done;
> > +       struct rvtrace_path * __percpu *path;
> > +       struct rvtrace_perf_auxbuf buf;
> > +};
> > +
> > +struct rvtrace_ctxt {
> > +       struct perf_output_handle handle;
> > +       struct rvtrace_event_data *event_data;
> > +};
> > +
> > +static DEFINE_PER_CPU(struct rvtrace_ctxt, rvtrace_ctxt);
> > +
> > +static void *alloc_event_data(int cpu)
> > +{
> > +       struct rvtrace_event_data *event_data;
> > +       cpumask_t *mask;
> > +
> > +       event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
> > +       if (!event_data)
> > +               return NULL;
> > +
> > +       /* Update mask as per selected CPUs */
> > +       mask = &event_data->mask;
> > +       if (cpu != -1)
> > +               cpumask_set_cpu(cpu, mask);
> > +       else
> > +               cpumask_copy(mask, cpu_present_mask);
> > +
> > +       event_data->path = alloc_percpu(struct rvtrace_path *);
> > +       return event_data;
> > +}
> > +
> > +static void rvtrace_free_aux(void *data)
> > +{
> > +       struct rvtrace_event_data *event_data = data;
> > +
> > +       schedule_work(&event_data->work);
> > +}
> > +
> > +static struct rvtrace_path **rvtrace_event_cpu_path_ptr(struct rvtrace_event_data *data,
> > +                                                       int cpu)
> > +{
> > +       return per_cpu_ptr(data->path, cpu);
> > +}
> > +
> > +static void free_event_data(struct work_struct *work)
> > +{
> > +       struct rvtrace_event_data *event_data;
> > +       struct rvtrace_path *path;
> > +       cpumask_t *mask;
> > +       int cpu;
> > +
> > +       event_data = container_of(work, struct rvtrace_event_data, work);
> > +       mask = &event_data->mask;
> > +       for_each_cpu(cpu, mask) {
> > +               path = *rvtrace_event_cpu_path_ptr(event_data, cpu);
> > +               rvtrace_destroy_path(path);
> > +       }
> > +       free_percpu(event_data->path);
> > +       kfree(event_data);
> > +}
> > +
> > +static void *rvtrace_setup_aux(struct perf_event *event, void **pages,
> > +                              int nr_pages, bool overwrite)
> > +{
> > +       struct rvtrace_event_data *event_data = NULL;
> > +       struct page **pagelist;
> > +       int cpu = event->cpu, i;
> > +       cpumask_t *mask;
> > +
> > +       event_data = alloc_event_data(cpu);
> > +       if (!event_data)
> > +               return NULL;
> > +
> > +       INIT_WORK(&event_data->work, free_event_data);
> > +       mask = &event_data->mask;
> > +       /*
> > +        * Create the path for each CPU in the mask. In case of any failure skip the CPU
> > +        */
> > +       for_each_cpu(cpu, mask) {
> > +               struct rvtrace_component *src;
> > +               struct rvtrace_path *path;
> > +
> > +               src = rvtrace_cpu_source(cpu);
> > +               if (!src)
> > +                       continue;
> > +
> > +               path = rvtrace_create_path(src, NULL, RVTRACE_COMPONENT_MODE_PERF);
> > +               if (!path)
> > +                       continue;
> > +
> > +               *rvtrace_event_cpu_path_ptr(event_data, cpu) = path;
> > +       }
> > +
> > +       /* If we don't have any CPUs ready for tracing, abort */
> > +       cpu = cpumask_first(&event_data->mask);
> > +       if (cpu >= nr_cpu_ids)
> > +               goto err;
> > +
> > +       pagelist = kcalloc(nr_pages, sizeof(*pagelist), GFP_KERNEL);
> > +       if (!pagelist)
> > +               goto err;
> > +
> > +       for (i = 0; i < nr_pages; i++)
> > +               pagelist[i] = virt_to_page(pages[i]);
> > +
> > +       event_data->buf.base = vmap(pagelist, nr_pages, VM_MAP, PAGE_KERNEL);
> > +       if (!event_data->buf.base) {
> > +               kfree(pagelist);
> > +               goto err;
> > +       }
> > +
> > +       event_data->buf.nr_pages = nr_pages;
> > +       event_data->buf.length = nr_pages * PAGE_SIZE;
> > +       event_data->buf.pos = 0;
> > +       return event_data;
> > +err:
> > +       rvtrace_free_aux(event_data);
> > +       return NULL;
> > +}
> > +
> > +static void rvtrace_event_read(struct perf_event *event)
> > +{
> > +}
> > +
> > +static void rvtrace_event_destroy(struct perf_event *event)
> > +{
> > +}
> > +
> > +static int rvtrace_event_init(struct perf_event *event)
> > +{
> > +       if (event->attr.type != rvtrace_pmu.type)
> > +               return -EINVAL;
> > +
> > +       event->destroy = rvtrace_event_destroy;
> > +       return 0;
> > +}
> > +
> > +static void rvtrace_event_start(struct perf_event *event, int flags)
> > +{
> > +       struct rvtrace_ctxt *ctxt = this_cpu_ptr(&rvtrace_ctxt);
> > +       struct perf_output_handle *handle = &ctxt->handle;
> > +       struct rvtrace_event_data *event_data;
> > +       int cpu = smp_processor_id();
> > +       struct rvtrace_path *path;
> > +
> > +       if (WARN_ON(ctxt->event_data))
> > +               goto fail;
> > +
> > +       /*
> > +        * Deal with the ring buffer API and get a handle on the
> > +        * session's information.
> > +        */
> > +       event_data = perf_aux_output_begin(handle, event);
> > +       if (!event_data)
> > +               goto fail;
> > +
> > +       if (!cpumask_test_cpu(cpu, &event_data->mask))
> > +               goto out;
> > +
> > +       event_data->buf.pos = handle->head % event_data->buf.length;
> > +       path = *rvtrace_event_cpu_path_ptr(event_data, cpu);
> > +       if (!path) {
> > +               pr_err("Error. Path not found\n");
> > +               return;
> > +       }
> > +
> > +       if (rvtrace_path_start(path)) {
> > +               pr_err("Error. Tracing not started\n");
> > +               return;
> > +       }
> > +
> > +       /*
> > +        * output cpu / trace ID in perf record, once for the lifetime
> > +        * of the event.
> > +        */
> > +       if (!cpumask_test_cpu(cpu, &event_data->aux_hwid_done)) {
> > +               cpumask_set_cpu(cpu, &event_data->aux_hwid_done);
> > +               perf_report_aux_output_id(event, cpu);
> > +       }
> > +
> > +out:
> > +       /* Tell the perf core the event is alive */
> > +       event->hw.state = 0;
> > +       ctxt->event_data = event_data;
> > +       return;
> > +fail:
> > +       event->hw.state = PERF_HES_STOPPED;
> > +}
> > +
> > +static void rvtrace_event_stop(struct perf_event *event, int mode)
> > +{
> > +       struct rvtrace_ctxt *ctxt = this_cpu_ptr(&rvtrace_ctxt);
> > +       struct perf_output_handle *handle = &ctxt->handle;
> > +       struct rvtrace_event_data *event_data;
> > +       int ret, cpu = smp_processor_id();
> > +       struct rvtrace_path *path;
> > +       size_t size;
> > +
> > +       if (event->hw.state == PERF_HES_STOPPED)
> > +               return;
> > +
> > +       if (handle->event &&
> > +           WARN_ON(perf_get_aux(handle) != ctxt->event_data))
> > +               return;
> > +
> > +       event_data = ctxt->event_data;
> > +       ctxt->event_data = NULL;
> > +
> > +       if (WARN_ON(!event_data))
> > +               return;
> > +
> > +       if (handle->event && (mode & PERF_EF_UPDATE) && !cpumask_test_cpu(cpu, &event_data->mask)) {
> > +               event->hw.state = PERF_HES_STOPPED;
> > +               perf_aux_output_end(handle, 0);
> > +               return;
> > +       }
> > +
> > +       /* stop tracing */
> > +       path = *rvtrace_event_cpu_path_ptr(event_data, cpu);
> > +       if (!path) {
> > +               pr_err("Error. Path not found\n");
> > +               return;
> > +       }
> > +
> > +       if (rvtrace_path_stop(path)) {
> > +               pr_err("Error. Tracing not stopped\n");
> > +               return;
> > +       }
> > +
> > +       event->hw.state = PERF_HES_STOPPED;
> > +       if (handle->event && (mode & PERF_EF_UPDATE)) {
> > +               if (WARN_ON_ONCE(handle->event != event))
> > +                       return;
> > +               spin_lock(&perf_buf_lock);
> > +               ret = rvtrace_path_copyto_auxbuf(path, &event_data->buf, &size);
> > +               spin_unlock(&perf_buf_lock);
> > +               WARN_ON_ONCE(ret);
> > +               if (READ_ONCE(handle->event))
> > +                       perf_aux_output_end(handle, size);
> > +               else
> > +                       WARN_ON(size);
> > +       }
> > +}
> > +
> > +static int rvtrace_event_add(struct perf_event *event, int mode)
> > +{
> > +       struct hw_perf_event *hwc = &event->hw;
> > +       int ret = 0;
> > +
> > +       if (mode & PERF_EF_START) {
> > +               rvtrace_event_start(event, 0);
> > +               if (hwc->state & PERF_HES_STOPPED)
> > +                       ret = -EINVAL;
> > +       } else {
> > +               hwc->state = PERF_HES_STOPPED;
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +static void rvtrace_event_del(struct perf_event *event, int mode)
> > +{
> > +       rvtrace_event_stop(event, PERF_EF_UPDATE);
> > +}
> > +
> > +PMU_FORMAT_ATTR(event, "config:0-0");
> > +
> > +static struct attribute *rvtrace_pmu_formats_attr[] = {
> > +       &format_attr_event.attr,
> > +       NULL,
> > +};
> > +
> > +static struct attribute_group rvtrace_pmu_format_group = {
> > +       .name = "format",
> > +       .attrs = rvtrace_pmu_formats_attr,
> > +};
> > +
> > +static const struct attribute_group *rvtrace_pmu_attr_groups[] = {
> > +       &rvtrace_pmu_format_group,
> > +       NULL,
> > +};
> > +
> > +int __init rvtrace_perf_init(void)
> > +{
> > +       rvtrace_pmu.capabilities        = (PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE);
> > +       rvtrace_pmu.attr_groups         = rvtrace_pmu_attr_groups;
> > +       rvtrace_pmu.task_ctx_nr         = perf_sw_context;
> > +       rvtrace_pmu.read                = rvtrace_event_read;
> > +       rvtrace_pmu.event_init          = rvtrace_event_init;
> > +       rvtrace_pmu.setup_aux           = rvtrace_setup_aux;
> > +       rvtrace_pmu.free_aux            = rvtrace_free_aux;
> > +       rvtrace_pmu.start               = rvtrace_event_start;
> > +       rvtrace_pmu.stop                = rvtrace_event_stop;
> > +       rvtrace_pmu.add                 = rvtrace_event_add;
> > +       rvtrace_pmu.del                 = rvtrace_event_del;
> > +       rvtrace_pmu.module              = THIS_MODULE;
> > +
> > +       return perf_pmu_register(&rvtrace_pmu, RVTRACE_PMU_NAME, -1);
> > +}
> > +
> > +void __exit rvtrace_perf_exit(void)
> > +{
> > +       perf_pmu_unregister(&rvtrace_pmu);
> > +}
> > diff --git a/include/linux/rvtrace.h b/include/linux/rvtrace.h
> > index cecf6c153ca6..d5f782ac132f 100644
> > --- a/include/linux/rvtrace.h
> > +++ b/include/linux/rvtrace.h
> > @@ -343,4 +343,7 @@ static inline int rvtrace_comp_is_empty(struct rvtrace_component *comp)
> >                                 comp->pdata->control_poll_timeout_usecs);
> >  }
> >
> > +int rvtrace_perf_init(void);
> > +void rvtrace_perf_exit(void);
> > +
> >  #endif
> > --
> > 2.43.0
> >
> >
> > _______________________________________________
> > linux-riscv mailing list
> > linux-riscv@...ts.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-riscv

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ