From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D7D7DC433ED for ; Mon, 26 Apr 2021 01:20:19 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3AAB661042 for ; Mon, 26 Apr 2021 01:20:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3AAB661042 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:References:Message-ID: Subject:Cc:To:From:Date:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=UA8BBWi8rLxC8/RQgfUChQVezphpL1b93TjdMSmZtlI=; b=Bmr50kxhUZIoOPEf6lUeweolc jDR+HgrXBB7XvEEIn+KyisCwnJFcGStVjI76hEXRFMKz29SCg6wK7YMGk3rqxuPws1LalzY0Fcw2z lZs9QA2eRPIrW8FjsxjHwpH/YHS0Gl7JOTNzK2qCJOpX7EJFiOItwDWNVzwKS7mhhsJFSAVDiRXbZ a0smAupcNRgVNtx3ufo87wsF0NVcnZ0Eua0wrvLHb7BkKEgoU1rrL4dfz2rO+3XP7hrtBx8oMFveE vYTeeJXoIxt2lJ5s8HzH+uBA/OWLV/xmR5fGFxVcyEDmug8SiXyilXhzfxVLt6WOFfzQbtITmBJGv fRwkYvkqw==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1laptY-006bMf-3C; Mon, 26 Apr 2021 01:18:40 +0000 Received: from bombadil.infradead.org ([2607:7c80:54:e::133]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1laptT-006bMZ-99 for linux-arm-kernel@desiato.infradead.org; Mon, 26 Apr 2021 01:18:35 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=In-Reply-To:Content-Type:MIME-Version :References:Message-ID:Subject:Cc:To:From:Date:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=p0do8P+3nmDvSZ9W/f/73nH3xo/y2/rUKCTYevU3QrY=; b=LOSZqgPLjbR9Mr9OvpEZhXuHDD 4u1ykmNZPoyPnnv4lZIUi5fH+xqEBEXNB6OFGz3RSgitB3v21sFxSDTtIDPLvWEUFjwfzbOemnlsp wbLr3/ehDtIJNqDIYcVbvI0fBB6Ss7dgok42IPqVeQYXE46+oM+5RLtEIMF2dcOuNWhriqucqQZ2y UTB1l2oelhH5njtl/cHLXtdZ05DhdXvEGnWtarGyQExf60CztJyRnsBrOJwrlZoXS9XS+5oZSfm/y apxHKKlVNeubMrmxUCkxOg+YAp/wN11l1wLfXPcT59l0HXxb5xTKeQeJdNlckwKJiEzN7u6xPYfaT Ul29soRg==; Received: from mail-pl1-x62a.google.com ([2607:f8b0:4864:20::62a]) by bombadil.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1laptO-00Fg9F-Hu for linux-arm-kernel@lists.infradead.org; Mon, 26 Apr 2021 01:18:33 +0000 Received: by mail-pl1-x62a.google.com with SMTP id t3so747944plz.1 for ; Sun, 25 Apr 2021 18:18:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=p0do8P+3nmDvSZ9W/f/73nH3xo/y2/rUKCTYevU3QrY=; b=aUUqm4Ux6/kRHBOXROfNFaUhLhYPYr4U6kaPsoLHwq//w0i/Fc+mdMQD2pOMhdMum+ LchAcFGGqGvzOFhhUs+rj7H9bWmKSxt9gzFor1MI6/HuEYmAeCXBIB5ymAv5XV4RhcWH o+9noUGrDT0lOAjjcirRR7+ez7jZ0z0B/ZMC1BpLbnVKirOrP92vbe6fDKztp2BIbhik kBiozjZDZiS+ePN7xvDrz0MOOdqGFkLzEhdk7JJYvfXtRDKJIAeg0uQkQRVU34gzmV9N H+z83knQYJ0KMR2IQlEo6RSfbnwoxaoWvoHP9dv4rlHBHf8GnkaiuLbYT2pNG2xEPkU4 W8Wg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=p0do8P+3nmDvSZ9W/f/73nH3xo/y2/rUKCTYevU3QrY=; b=fxhdQm/HCoCiKll3SnXQNFIKuuctK6rgrh9LqcCX450CuGuAieGyEjGv9Q24uUXEIF aFY9QgSsGu5L0KIe3VjnfPdXlqfc7R8uyCOU1ympBWkKJU9Ybu9CvolQGiQMg/lXVhWP FAhV3DFlxj06voslj9wqLqszaR6nP/8fVi7NyXzrZvdVcuCgmLUS5OwoDreKMgLqmn8h J01seq734QXdmexCl+XO2RyaLCwjZxI6vBSDElIBZUbGTFSwPa8quRuBib4ohCg1ha0J 67lqKjRyoS3rUdY1xzx/53suT+QjUJyiHIBgOMTtfdHx6epHtg/O5v7bGc/8uHMHFdrI /4hg== X-Gm-Message-State: AOAM530q6ES7p1uB5/Mzj1ZiSmeNhq1Y83QfJROQStuMC1zVBog4k/Mg 0jq46p8Rwlmq2eCHrd6bo8UQBA== X-Google-Smtp-Source: ABdhPJxMQiA4GsrXJjQ4tKYasin1/8xSSHna6SIGekk3ZZotXQj5B7a4+RuVS2SmNyjCQMmL6Tlk8A== X-Received: by 2002:a17:90a:f2c7:: with SMTP id gt7mr20201037pjb.157.1619399909232; Sun, 25 Apr 2021 18:18:29 -0700 (PDT) Received: from leoy-ThinkPad-X240s ([116.206.101.229]) by smtp.gmail.com with ESMTPSA id j23sm9528769pfh.179.2021.04.25.18.18.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 Apr 2021 18:18:28 -0700 (PDT) Date: Mon, 26 Apr 2021 09:18:24 +0800 From: Leo Yan To: Daniel Kiss Cc: mathieu.poirier@linaro.org, suzuki.poulose@arm.com, mike.leach@linaro.org, coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, denik@google.com, Branislav Rankov Subject: Re: [PATCH 4/4] coresight: Add ETR-PERF polling. Message-ID: <20210426011824.GB176271@leoy-ThinkPad-X240s> References: <20210421120413.3110775-1-daniel.kiss@arm.com> <20210421120413.3110775-5-daniel.kiss@arm.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20210421120413.3110775-5-daniel.kiss@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210425_181830_716194_D5E5A335 X-CRM114-Status: GOOD ( 43.84 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On Wed, Apr 21, 2021 at 02:04:13PM +0200, Daniel Kiss wrote: > ETR might fill up the buffer sooner than an event makes perf to trigger > the synchronisation especially in system wide trace. Polling runs > periodically to sync the ETR buffer. Period is configurable via sysfs, > disabled by default. > > Signed-off-by: Daniel Kiss > Signed-off-by: Branislav Rankov > --- > .../testing/sysfs-bus-coresight-devices-tmc | 8 + > drivers/hwtracing/coresight/Makefile | 2 +- > .../hwtracing/coresight/coresight-etm-perf.c | 8 + > .../coresight/coresight-etr-perf-polling.c | 316 ++++++++++++++++++ > .../coresight/coresight-etr-perf-polling.h | 42 +++ > .../hwtracing/coresight/coresight-tmc-core.c | 2 + > .../hwtracing/coresight/coresight-tmc-etr.c | 9 + > 7 files changed, 386 insertions(+), 1 deletion(-) > create mode 100644 drivers/hwtracing/coresight/coresight-etr-perf-polling.c > create mode 100644 drivers/hwtracing/coresight/coresight-etr-perf-polling.h > > diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc > index 6aa527296c710..4ca7af22a3686 100644 > --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc > +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc > @@ -91,3 +91,11 @@ Contact: Mathieu Poirier > Description: (RW) Size of the trace buffer for TMC-ETR when used in SYSFS > mode. Writable only for TMC-ETR configurations. The value > should be aligned to the kernel pagesize. > + > +What: /sys/bus/coresight/devices/.tmc/polling/period > +Date: April 2021 > +KernelVersion: 5.13 > +Contact: Daniel Kiss > +Description: (RW) Time in milliseconds when the TMC-ETR is synced. > + Default value is 0, means the feature is disabled. > + Writable only for TMC-ETR configurations. > diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile > index d60816509755c..4df90b71d98cd 100644 > --- a/drivers/hwtracing/coresight/Makefile > +++ b/drivers/hwtracing/coresight/Makefile > @@ -4,7 +4,7 @@ > # > obj-$(CONFIG_CORESIGHT) += coresight.o > coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ > - coresight-sysfs.o > + coresight-sysfs.o coresight-etr-perf-polling.o > obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o > coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ > coresight-tmc-etr.o > diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c > index 78a55fc2bcab5..910a99944eea8 100644 > --- a/drivers/hwtracing/coresight/coresight-etm-perf.c > +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c > @@ -19,6 +19,7 @@ > #include > > #include "coresight-etm-perf.h" > +#include "coresight-etr-perf-polling.h" > #include "coresight-priv.h" > > static struct pmu etm_pmu; > @@ -438,6 +439,8 @@ static void etm_event_start(struct perf_event *event, int flags) > /* Tell the perf core the event is alive */ > event->hw.state = 0; > > + etr_perf_polling_event_start(event, event_data, handle); > + > /* Finally enable the tracer */ > if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF)) > goto fail_disable_path; > @@ -497,6 +500,8 @@ static void etm_event_stop(struct perf_event *event, int mode) > if (!sink) > return; > > + etr_perf_polling_event_stop(event, event_data); > + > /* stop tracer */ > source_ops(csdev)->disable(csdev, event); > > @@ -741,6 +746,8 @@ int __init etm_perf_init(void) > etm_pmu.addr_filters_validate = etm_addr_filters_validate; > etm_pmu.nr_addr_filters = ETM_ADDR_CMP_MAX; > > + etr_perf_polling_init(); > + > ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1); > if (ret == 0) > etm_perf_up = true; > @@ -750,5 +757,6 @@ int __init etm_perf_init(void) > > void __exit etm_perf_exit(void) > { > + etr_perf_polling_exit(); > perf_pmu_unregister(&etm_pmu); > } > diff --git a/drivers/hwtracing/coresight/coresight-etr-perf-polling.c b/drivers/hwtracing/coresight/coresight-etr-perf-polling.c > new file mode 100644 > index 0000000000000..aa0352908873a > --- /dev/null > +++ b/drivers/hwtracing/coresight/coresight-etr-perf-polling.c > @@ -0,0 +1,316 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright(C) 2021 Arm Limited. All rights reserved. > + * Author: Daniel Kiss > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "coresight-etr-perf-polling.h" > +#include "coresight-priv.h" > +#include "coresight-tmc.h" > + > +#if defined(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) || \ > + defined(CONFIG_CORESIGHT_LINK_AND_SINK_TMC_MODULE) It's good to add a new config "CONFIG_CORESIGHT_ETM_PERF_POLL" and developers can selectively enable it when build kernel. > +struct polling_event_list { > + struct perf_event *perf_event; > + struct etm_event_data *etm_event_data; > + struct perf_output_handle *ctx_handle; > + void (*tmc_etr_reset_hw)(struct tmc_drvdata *); > + struct list_head list; > +}; > + > +struct polling { > + int cpu; > + struct list_head polled_events; Based the structure definition, every CPU has its own polling structure, and there have multiple polled event for one CPU. In theory, should every CPU have only one perf event for polling? If so, it's not necessary to create event list for every CPU; in other words, we can create a list which can be used to maintain all events cross all CPUs. > + struct delayed_work delayed_work; > +}; Every CPU has its own delayed work, a potential issue is it's hard to synchronize within CPUs; and after the CPU number increases, the situation will get worse. For example, when polling for multiple CPUs, there might have no chance to stop all tracers attached to CPUs. I understand this patch simply captures the trace data for the first CPU which reigstered its handler in the driver; IOW, we have no chance to stop all tracers to record a clean tracing data (here "clean" means there have no mixed behaviours that one CPU is reading trace data from ETR buffer and tracers from other CPUs still write data into the ETR buffer). > +static atomic_t period; > +static spinlock_t spinlock_re; > +static struct list_head registered_events; > + > +static DEFINE_PER_CPU(struct polling, polling); > + > +static ssize_t period_show(struct device *dev, struct device_attribute *attr, > + char *buf) > +{ > + int temp; > + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); > + > + if (drvdata->config_type != TMC_CONFIG_TYPE_ETR) > + return -EPERM; IMHO, the checking is redundant. > + > + temp = atomic_read(&period); > + return sprintf(buf, "%i\n", temp); > +} > + > +static ssize_t period_store(struct device *dev, struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + int temp = 0; > + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); > + > + if (drvdata->config_type != TMC_CONFIG_TYPE_ETR) > + return -EPERM; Ditto. > + > + if ((1 == sscanf(buf, "%i", &temp)) && (temp >= 0)) > + atomic_set(&period, temp); > + return count; > +} > + > +static DEVICE_ATTR_RW(period); > + > +static struct attribute *coresight_tmc_polling_attrs[] = { > + &dev_attr_period.attr, > + NULL, > +}; > +const struct attribute_group coresight_tmc_polling_group = { > + .attrs = coresight_tmc_polling_attrs, > + .name = "polling", > +}; > +EXPORT_SYMBOL_GPL(coresight_tmc_polling_group); Don't need to export the symbol. > + > +static inline void polling_sched_worker(struct polling *p) > +{ > + int tickrate = atomic_read(&period); > + if (!list_empty(&p->polled_events) && (tickrate > 0)) > + schedule_delayed_work_on(p->cpu, &p->delayed_work, > + msecs_to_jiffies(tickrate)); > +} > + > +static inline bool is_etr_related(struct etm_event_data *etm_event_data, int cpu) > +{ > + struct list_head *path; > + struct coresight_device *sink; > + struct tmc_drvdata *drvdata; > + path = etm_event_cpu_path(etm_event_data, cpu); > + if (WARN_ON(!path)) > + return false; > + sink = coresight_get_sink(path); > + if (WARN_ON(!sink)) > + return false; > + drvdata = dev_get_drvdata(sink->dev.parent); > + if (drvdata->config_type != TMC_CONFIG_TYPE_ETR) > + return false; > + return true; > +} Understand these operations are from etm_event_start(); we can avoid the duplicate code if arrange code more reasonable. I suggest below flow: - From the function etm_setup_aux(), insert an AUX event into the polling list; - From the function etm_event_start(), enable the AUX event, so this AUX event will be polled periodically; - From the function etm_event_stop(), disable the AUX event, the event will not be polled anymore; - From the function etm_free_AUX(), remove the AUX event from the polling list. > + > +/* > + * Adds the event to the polled events list. > + */ > +void etr_perf_polling_event_start(struct perf_event *event, > + struct etm_event_data *etm_event_data, > + struct perf_output_handle *ctx_handle) > +{ > + int cpu = smp_processor_id(); > + struct polling *p = per_cpu_ptr(&polling, cpu); > + struct polling_event_list *element; > + struct list_head *i, *tmp; > + > + if (!is_etr_related(etm_event_data, cpu)) > + return; > + > + spin_lock(&spinlock_re); > + list_for_each_safe (i, tmp, ®istered_events) { Suprious space before parenthese; and better to use list_for_each_entry_safe(). > + element = list_entry(i, struct polling_event_list, list); > + if (element->ctx_handle == ctx_handle) { > + element->perf_event = event; > + element->etm_event_data = etm_event_data; > + list_del(&element->list); > + spin_unlock(&spinlock_re); > + list_add(&element->list, &p->polled_events); > + polling_sched_worker(p); > + return; > + } > + } > + spin_unlock(&spinlock_re); > +} > +EXPORT_SYMBOL_GPL(etr_perf_polling_event_start); No need to export the symbol. > + > +/* > + * Removes the event from the to be polled events list. > + */ > +void etr_perf_polling_event_stop(struct perf_event *event, > + struct etm_event_data *etm_event_data) > +{ > + int cpu = smp_processor_id(); > + struct list_head *i, *tmp; > + struct polling *p = per_cpu_ptr(&polling, cpu); > + > + if (!is_etr_related(etm_event_data, cpu)) > + return; > + > + list_for_each_safe (i, tmp, &p->polled_events) { > + struct polling_event_list *element = > + list_entry(i, struct polling_event_list, list); > + if (element->perf_event == event) { > + list_del(&element->list); > + element->perf_event = NULL; > + element->etm_event_data = NULL; > + spin_lock(&spinlock_re); > + list_add(&element->list, ®istered_events); > + spin_unlock(&spinlock_re); > + if (list_empty(&p->polled_events)) { > + cancel_delayed_work(&p->delayed_work); > + } > + return; > + } > + } > +} > +EXPORT_SYMBOL_GPL(etr_perf_polling_event_stop); Ditto. > + > +/* > + * The polling worker is a workqueue job which is periodically > + * woken up to update the perf aux buffer from the etr shrink. > + */ > +static void etr_perf_polling_worker(struct work_struct *work) > +{ > + unsigned long flags; > + int cpu = smp_processor_id(); > + struct polling *p = per_cpu_ptr(&polling, cpu); > + struct list_head *i, *tmp; > + > + if (!atomic_read(&period)) > + return; > + > + /* > + * Scheduling would do the same from the perf hooks, > + * this should be done in one go. > + */ > + local_irq_save(flags); > + preempt_disable(); The locking usage is questionable... local_irq_save() will disable the local interrupt, and it also disables preemption; after disabling interrupt, it's needless to disable preemption. Here neither local_irq_save() nor preempt_disable() is the right locking to be used; alternatively, should use the pair functions spinlock(&spinlock_re) / spin_unlock(&spinlock_re), this is because it needs to protect the poll list. > + /* Perf requires rcu lock. */ > + rcu_read_lock(); Though it gives comments, I still don't understand why need to use rcu_read_lock(). Which critical resource it protects? > + > + polling_sched_worker(p); > + > + list_for_each_safe (i, tmp, &p->polled_events) { > + struct list_head *path; > + struct coresight_device *sink; > + struct polling_event_list *element = > + list_entry(i, struct polling_event_list, list); > + > + path = etm_event_cpu_path(element->etm_event_data, cpu); > + if (WARN_ON(!path)) > + continue; > + sink = coresight_get_sink(path); > + if (WARN_ON(!sink)) > + continue; When inserting the event into polling list, it have checked for path and validate sink; so it's no need to check the path again. > + if (sink_ops(sink)->update_buffer) { > + int size, refcnt; > + struct tmc_drvdata *drvdata = dev_get_drvdata(sink->dev.parent); > + > + /* > + * Act as now we are the only users of the sink. Due to the locks > + * we are safe. > + */ > + refcnt = atomic_xchg(sink->refcnt, 1); > + size = sink_ops(sink)->update_buffer( > + sink, element->ctx_handle, > + element->etm_event_data->snk_config); > + refcnt = atomic_xchg(sink->refcnt, refcnt); This is tricky. This change is like a workaround, it's better to refactor the code for "sink->refcnt"; maybe we can refactor the coe to track the sink's reference counter in the polling list rather than in the low level driver. > + /* > + * Restart the trace. > + */ > + if (element->tmc_etr_reset_hw) > + element->tmc_etr_reset_hw(drvdata); > + > + WARN_ON(size < 0); > + if (size > 0) { > + struct etm_event_data *new_event_data; > + > + perf_aux_output_end(element->ctx_handle, size); > + new_event_data = perf_aux_output_begin( > + element->ctx_handle, > + element->perf_event); > + if (WARN_ON(new_event_data == NULL)) > + continue; > + element->etm_event_data = new_event_data; > + WARN_ON(new_event_data->snk_config != > + element->etm_event_data->snk_config); > + } > + } > + } > + > + rcu_read_unlock(); > + preempt_enable(); > + local_irq_restore(flags); > +} > + > +void etr_perf_polling_handle_register(struct perf_output_handle *handle, > + void (*tmc_etr_reset_hw)(struct tmc_drvdata *drvdata)) > +{ > + struct polling_event_list *element; > + > + element = kmalloc(sizeof(*element), GFP_KERNEL); > + if (WARN_ON(!element)) > + return; > + memset(element, 0, sizeof(*element)); > + element->ctx_handle = handle; > + element->tmc_etr_reset_hw = tmc_etr_reset_hw; > + spin_lock(&spinlock_re); > + list_add(&element->list, ®istered_events); > + spin_unlock(&spinlock_re); > +} > +EXPORT_SYMBOL_GPL(etr_perf_polling_handle_register); > + > +void etr_perf_polling_handle_deregister(struct perf_output_handle *handle) > +{ > + struct list_head *i, *tmp; > + > + spin_lock(&spinlock_re); > + list_for_each_safe (i, tmp, ®istered_events) { > + struct polling_event_list *element = > + list_entry(i, struct polling_event_list, list); > + if (element->ctx_handle == handle) { > + list_del(&element->list); > + spin_unlock(&spinlock_re); > + kfree(element); > + return; > + } > + } > + spin_unlock(&spinlock_re); > +} > +EXPORT_SYMBOL_GPL(etr_perf_polling_handle_deregister); > + > +void etr_perf_polling_init(void) > +{ > + int cpu; > + spin_lock_init(&spinlock_re); > + INIT_LIST_HEAD(®istered_events); > + atomic_set(&period, 0); > + for_each_possible_cpu (cpu) { > + struct polling *p = per_cpu_ptr(&polling, cpu); > + p->cpu = cpu; > + INIT_LIST_HEAD(&p->polled_events); > + INIT_DELAYED_WORK(&p->delayed_work, etr_perf_polling_worker); > + } > +} > +EXPORT_SYMBOL_GPL(etr_perf_polling_init); > + > +void etr_perf_polling_exit(void) > +{ > + int cpu; > + for_each_possible_cpu (cpu) { > + struct polling *p = per_cpu_ptr(&polling, cpu); > + cancel_delayed_work_sync(&p->delayed_work); > + WARN_ON(!list_empty(&p->polled_events)); > + } > + WARN_ON(!list_empty(®istered_events)); > +} > +EXPORT_SYMBOL_GPL(etr_perf_polling_exit); > + > +#endif > diff --git a/drivers/hwtracing/coresight/coresight-etr-perf-polling.h b/drivers/hwtracing/coresight/coresight-etr-perf-polling.h > new file mode 100644 > index 0000000000000..5917e1fa408bb > --- /dev/null > +++ b/drivers/hwtracing/coresight/coresight-etr-perf-polling.h > @@ -0,0 +1,42 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright(C) 2021 Arm Limited. All rights reserved. > + * Author: Daniel Kiss > + */ > + > +#ifndef _CORESIGHT_ETM_PERF_POLLING_H > +#define _CORESIGHT_ETM_PERF_POLLING_H > + > +#include > +#include > +#include "coresight-etm-perf.h" > +#include "coresight-tmc.h" > + > +#if defined(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) || \ > + defined(CONFIG_CORESIGHT_LINK_AND_SINK_TMC_MODULE) > + > +void etr_perf_polling_init(void); > +void etr_perf_polling_exit(void); > +void etr_perf_polling_handle_register(struct perf_output_handle *handle, > + void (*tmc_etr_reset_hw)(struct tmc_drvdata *drvdata)); > +void etr_perf_polling_handle_deregister(struct perf_output_handle *handle); > +void etr_perf_polling_event_start(struct perf_event *event, > + struct etm_event_data *etm_event_data, > + struct perf_output_handle *ctx_handle); > +void etr_perf_polling_event_stop(struct perf_event *event, > + struct etm_event_data *etm_event_data); > + > +extern const struct attribute_group coresight_tmc_polling_group; > +#define CORESIGHT_TMP_POLLING_GROUP &coresight_tmc_polling_group, > + > +#else /* !CONFIG_CORESIGHT_LINK_AND_SINK_TMC */ > +#define etr_perf_polling_init() > +#define etr_perf_polling_exit() > +#define etr_perf_polling_handle_register(...) > +#define etr_perf_polling_handle_deregister(...) > +#define etr_perf_polling_event_start(...) > +#define etr_perf_polling_event_stop(...) > +#define CORESIGHT_TMP_POLLING_GROUP > +#endif > + > +#endif > diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c > index 74c6323d4d6ab..51e705ef3ffa3 100644 > --- a/drivers/hwtracing/coresight/coresight-tmc-core.c > +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c > @@ -26,6 +26,7 @@ > > #include "coresight-priv.h" > #include "coresight-tmc.h" > +#include "coresight-etr-perf-polling.h" > > DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb"); > DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf"); > @@ -365,6 +366,7 @@ static const struct attribute_group coresight_tmc_mgmt_group = { > static const struct attribute_group *coresight_tmc_groups[] = { > &coresight_tmc_group, > &coresight_tmc_mgmt_group, > + CORESIGHT_TMP_POLLING_GROUP This is a bit wired for me. It's more readable with: #ifdef CONFIG_CORESIGHT_ETM_PERF_POLL &coresight_tmc_polling_group, #endif > NULL, > }; > > diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c > index bf9f6311d8663..021b594e38e71 100644 > --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c > +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c > @@ -16,6 +16,7 @@ > #include > #include "coresight-catu.h" > #include "coresight-etm-perf.h" > +#include "coresight-etr-perf-polling.h" > #include "coresight-priv.h" > #include "coresight-tmc.h" > > @@ -1139,6 +1140,12 @@ void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) > drvdata->etr_buf = NULL; > } > > +static void tmc_etr_reset_hw(struct tmc_drvdata *drvdata) > +{ > + __tmc_etr_disable_hw(drvdata); > + __tmc_etr_enable_hw(drvdata); > +} > + > static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) > { > int ret = 0; > @@ -1630,6 +1637,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) > drvdata->mode = CS_MODE_PERF; > drvdata->perf_buf = etr_perf->etr_buf; > drvdata->perf_handle = handle; > + etr_perf_polling_handle_register(handle, tmc_etr_reset_hw); > atomic_inc(csdev->refcnt); > } > > @@ -1677,6 +1685,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) > drvdata->mode = CS_MODE_DISABLED; > /* Reset perf specific data */ > drvdata->perf_buf = NULL; > + etr_perf_polling_handle_deregister(drvdata->perf_handle); > drvdata->perf_handle = NULL; > > spin_unlock_irqrestore(&drvdata->spinlock, flags); > -- > 2.25.1 > _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel