All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tingwei Zhang <tingwei@codeaurora.org>
To: Mathieu Poirier <mathieu.poirier@linaro.org>,
	Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: tsoni@codeaurora.org,
	Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>,
	Kim Phillips <kim.phillips@arm.com>,
	Mao Jinlong <jinlmao@codeaurora.org>,
	Alexander Shishkin <alexander.shishkin@linux.intel.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	coresight@lists.linaro.org, Randy Dunlap <rdunlap@infradead.org>,
	Mian Yousaf Kaukab <ykaukab@suse.de>,
	Russell King <linux@armlinux.org.uk>,
	Tingwei Zhang <tingwei@codeaurora.org>,
	Leo Yan <leo.yan@linaro.org>,
	linux-arm-kernel@lists.infradead.org
Subject: [PATCH v1 21/21] coresight: perf: clean up perf event on device unregister path
Date: Wed,  1 Jul 2020 15:14:27 +0800	[thread overview]
Message-ID: <20200701071427.10477-22-tingwei@codeaurora.org> (raw)
In-Reply-To: <20200701071427.10477-1-tingwei@codeaurora.org>

When coresight unreigster is called, check whether this device
is used by any perf event. Stop and release that perf event to
avoid accessing removed coresight device data later.

Signed-off-by: Tingwei Zhang <tingwei@codeaurora.org>
---
 drivers/hwtracing/coresight/coresight-core.c  |   7 +
 .../hwtracing/coresight/coresight-etm-perf.c  | 157 +++++++++++++++++-
 .../hwtracing/coresight/coresight-etm-perf.h  |   2 +
 drivers/hwtracing/coresight/coresight-priv.h  |   4 +-
 kernel/events/core.c                          |   1 +
 5 files changed, 164 insertions(+), 7 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 55ff45a9729e..8261d527c8fb 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1475,9 +1475,16 @@ void coresight_unregister(struct coresight_device *csdev)
 
 	mutex_lock(&coresight_mutex);
 	coresight_disable_with(csdev);
+	/*
+	 * Disable all perf events that have trace path related to csdev.
+	 * Deny any request to create new trace path.
+	 */
+	etm_perf_disable_with(csdev);
 	/* Remove references of that device in the topology */
 	coresight_remove_conns(csdev);
 	coresight_release_platform_data(csdev->pdata);
+	/* New trace path in perf can be established */
+	etm_perf_disable_done();
 	mutex_unlock(&coresight_mutex);
 	device_unregister(&csdev->dev);
 }
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index b466162d8254..95aeb1ca807c 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -23,9 +23,22 @@
 
 static struct pmu etm_pmu;
 static bool etm_perf_up;
+/* Count for on going tasks which are changing coresight topology */
+static atomic_t *cs_updating_cnt;
+
+static DEFINE_MUTEX(cs_path_mutex);
 
 static DEFINE_PER_CPU(struct perf_output_handle, ctx_handle);
 static DEFINE_PER_CPU(struct coresight_device *, csdev_src);
+static DEFINE_PER_CPU(bool, csdev_src_removing);
+
+struct ev_data {
+	struct etm_event_data *event_data;
+	struct list_head link;
+};
+
+/* List for all events */
+static LIST_HEAD(ev_list);
 
 /* ETMv3.5/PTM's ETMCR is 'config' */
 PMU_FORMAT_ATTR(cycacc,		"config:" __stringify(ETM_OPT_CYCACC));
@@ -64,6 +77,8 @@ static const struct attribute_group *etm_pmu_attr_groups[] = {
 	NULL,
 };
 
+static void update_cs_cfg(void *ignored);
+
 static inline struct list_head **
 etm_event_cpu_path_ptr(struct etm_event_data *data, int cpu)
 {
@@ -135,15 +150,35 @@ static void free_sink_buffer(struct etm_event_data *event_data)
 	cpu = cpumask_first(mask);
 	sink = coresight_get_sink(etm_event_cpu_path(event_data, cpu));
 	sink_ops(sink)->free_buffer(event_data->snk_config);
+	event_data->snk_config = NULL;
 }
 
-static void free_event_data(struct work_struct *work)
+static void del_event_from_list(struct etm_event_data *event_data,
+				struct ev_data *del_ev_data)
+{
+	struct ev_data *ev_data = NULL;
+	struct ev_data *ev_data_next = NULL;
+
+	if (IS_ERR_OR_NULL(del_ev_data)) {
+		list_for_each_entry_safe(ev_data, ev_data_next, &ev_list, link) {
+			if (ev_data->event_data == event_data) {
+				del_ev_data = ev_data;
+				break;
+			}
+		}
+	}
+	if (!(IS_ERR_OR_NULL(del_ev_data))) {
+		list_del(&del_ev_data->link);
+		kfree(del_ev_data);
+	}
+}
+
+static void _free_event_data(struct etm_event_data *event_data,
+				struct ev_data *ev_data)
 {
 	int cpu;
 	cpumask_t *mask;
-	struct etm_event_data *event_data;
 
-	event_data = container_of(work, struct etm_event_data, work);
 	mask = &event_data->mask;
 
 	/* Free the sink buffers, if there are any */
@@ -159,6 +194,20 @@ static void free_event_data(struct work_struct *work)
 	}
 
 	free_percpu(event_data->path);
+	del_event_from_list(event_data, ev_data);
+}
+
+static void free_event_data(struct work_struct *work)
+{
+	struct etm_event_data *event_data;
+
+	event_data = container_of(work, struct etm_event_data, work);
+
+	mutex_lock(&cs_path_mutex);
+	if (event_data->snk_config)
+		_free_event_data(event_data, NULL);
+	mutex_unlock(&cs_path_mutex);
+
 	kfree(event_data);
 }
 
@@ -212,7 +261,10 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
 	cpumask_t *mask;
 	struct coresight_device *sink;
 	struct etm_event_data *event_data = NULL;
+	struct ev_data *ev_data;
 
+	if (atomic_read(cs_updating_cnt))
+		return NULL;
 	event_data = alloc_event_data(cpu);
 	if (!event_data)
 		return NULL;
@@ -231,6 +283,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
 
 	mask = &event_data->mask;
 
+	mutex_lock(&cs_path_mutex);
 	/*
 	 * Setup the path for each CPU in a trace session. We try to build
 	 * trace path for each CPU in the mask. If we don't find an ETM
@@ -282,10 +335,19 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
 	if (!event_data->snk_config)
 		goto err;
 
+	ev_data = kzalloc(sizeof(struct ev_data), GFP_KERNEL);
+	if (!ev_data) {
+		*etm_event_cpu_path_ptr(event_data, cpu) = NULL;
+		goto err;
+	}
+	ev_data->event_data = event_data;
+	list_add(&ev_data->link, &ev_list);
+	mutex_unlock(&cs_path_mutex);
 out:
 	return event_data;
 
 err:
+	mutex_unlock(&cs_path_mutex);
 	etm_free_aux(event_data);
 	event_data = NULL;
 	goto out;
@@ -299,7 +361,7 @@ static void etm_event_start(struct perf_event *event, int flags)
 	struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
 	struct list_head *path;
 
-	if (!csdev)
+	if (!csdev || atomic_read(cs_updating_cnt))
 		goto fail;
 
 	/*
@@ -310,6 +372,9 @@ static void etm_event_start(struct perf_event *event, int flags)
 	if (!event_data)
 		goto fail;
 
+	if (!event_data->snk_config)
+		goto fail;
+
 	path = etm_event_cpu_path(event_data, cpu);
 	/* We need a sink, no need to continue without one */
 	sink = coresight_get_sink(path);
@@ -391,7 +456,7 @@ static int etm_event_add(struct perf_event *event, int mode)
 	int ret = 0;
 	struct hw_perf_event *hwc = &event->hw;
 
-	if (mode & PERF_EF_START) {
+	if (mode & PERF_EF_START && !atomic_read(cs_updating_cnt)) {
 		etm_event_start(event, 0);
 		if (hwc->state & PERF_HES_STOPPED)
 			ret = -EINVAL;
@@ -499,9 +564,14 @@ int etm_perf_symlink(struct coresight_device *csdev, bool link)
 		if (ret)
 			return ret;
 		per_cpu(csdev_src, cpu) = csdev;
+		per_cpu(csdev_src_removing, cpu) = false;
 	} else {
 		sysfs_remove_link(&pmu_dev->kobj, entry);
-		per_cpu(csdev_src, cpu) = NULL;
+		/*
+		 * Set to NULL later when device is unregistered to avoid
+		 * conflict with ongoing event.
+		 */
+		per_cpu(csdev_src_removing, cpu) = true;
 	}
 
 	return 0;
@@ -580,10 +650,79 @@ void etm_perf_del_symlink_sink(struct coresight_device *csdev)
 	csdev->ea = NULL;
 }
 
+static void update_cs_cfg(void *ignored)
+{
+	/*
+	 * Reschedule running events.
+	 * Events will be stopped and coresight path will be disabled.
+	 * Coresight path won't be enabled again until coresight update
+	 * is done.
+	 */
+	perf_pmu_resched(&etm_pmu);
+}
+
+static void update_cs_path(struct coresight_device *csdev)
+{
+	struct ev_data *ev_data = NULL;
+	struct ev_data *ev_data_next = NULL;
+	struct etm_event_data *event_data;
+	unsigned int cpu;
+	cpumask_t *mask;
+	bool ret = false;
+
+	mutex_lock(&cs_path_mutex);
+
+	list_for_each_entry_safe(ev_data, ev_data_next, &ev_list, link) {
+		event_data = ev_data->event_data;
+		if (!event_data->snk_config)
+			continue;
+
+		mask = &event_data->mask;
+
+		for_each_cpu(cpu, mask) {
+			struct list_head **ppath;
+
+			ppath = etm_event_cpu_path_ptr(event_data, cpu);
+			if (!(IS_ERR_OR_NULL(*ppath))) {
+				ret = coresight_dev_on_path(*ppath, csdev);
+				if (ret)
+					break;
+			}
+		}
+
+		if (ret)
+			_free_event_data(event_data, ev_data);
+	}
+
+	mutex_unlock(&cs_path_mutex);
+	for_each_possible_cpu(cpu) {
+		if (per_cpu(csdev_src_removing, cpu)) {
+			per_cpu(csdev_src, cpu) = NULL;
+			per_cpu(csdev_src_removing, cpu) = false;
+		}
+	}
+}
+
+void etm_perf_disable_with(struct coresight_device *csdev)
+{
+	atomic_inc(cs_updating_cnt);
+	get_online_cpus();
+	on_each_cpu(update_cs_cfg, NULL, 1);
+	put_online_cpus();
+	/* Free events which have trace path related to csdev */
+	update_cs_path(csdev);
+}
+
+void etm_perf_disable_done(void)
+{
+	atomic_dec(cs_updating_cnt);
+}
+
 int __init etm_perf_init(void)
 {
 	int ret;
 
+	etm_pmu.module			= THIS_MODULE;
 	etm_pmu.capabilities		= (PERF_PMU_CAP_EXCLUSIVE |
 					   PERF_PMU_CAP_ITRACE);
 
@@ -601,6 +740,11 @@ int __init etm_perf_init(void)
 	etm_pmu.addr_filters_validate	= etm_addr_filters_validate;
 	etm_pmu.nr_addr_filters		= ETM_ADDR_CMP_MAX;
 
+	cs_updating_cnt = kcalloc(1, sizeof(*cs_updating_cnt), GFP_KERNEL);
+	if (!cs_updating_cnt)
+		return -ENOMEM;
+	atomic_set(cs_updating_cnt, 0);
+
 	ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1);
 	if (ret == 0)
 		etm_perf_up = true;
@@ -610,5 +754,6 @@ int __init etm_perf_init(void)
 
 void __exit etm_perf_exit(void)
 {
+	kfree(cs_updating_cnt);
 	perf_pmu_unregister(&etm_pmu);
 }
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h
index 3e4f2ad5e193..221831732cb1 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.h
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.h
@@ -61,6 +61,8 @@ struct etm_event_data {
 int etm_perf_symlink(struct coresight_device *csdev, bool link);
 int etm_perf_add_symlink_sink(struct coresight_device *csdev);
 void etm_perf_del_symlink_sink(struct coresight_device *csdev);
+void etm_perf_disable_with(struct coresight_device *csdev);
+void etm_perf_disable_done(void);
 static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
 {
 	struct etm_event_data *data = perf_get_aux(handle);
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 56d677473be4..f91fff8267be 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -151,8 +151,10 @@ struct coresight_device *coresight_get_sink(struct list_head *path);
 struct coresight_device *coresight_get_enabled_sink(bool reset);
 struct coresight_device *coresight_get_sink_by_id(u32 id);
 struct list_head *coresight_build_path(struct coresight_device *csdev,
-				       struct coresight_device *sink);
+				struct coresight_device *sink);
 void coresight_release_path(struct list_head *path);
+bool coresight_dev_on_path(struct list_head *path,
+				struct coresight_device *csdev);
 
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
 extern int etm_readl_cp14(u32 off, unsigned int *val);
diff --git a/kernel/events/core.c b/kernel/events/core.c
index e296c5c59c6f..cce7a2b82a4b 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2723,6 +2723,7 @@ void perf_pmu_resched(struct pmu *pmu)
 	ctx_resched(cpuctx, task_ctx, EVENT_ALL|EVENT_CPU);
 	perf_ctx_unlock(cpuctx, task_ctx);
 }
+EXPORT_SYMBOL_GPL(perf_pmu_resched);
 
 /*
  * Cross CPU call to install and enable a performance event
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

      parent reply	other threads:[~2020-07-01  7:20 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-01  7:14 [PATCH v1 00/21] coresight: allow to build coresight as modules Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 01/21] coresight: cpu_debug: add module name in Kconfig Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 02/21] coresight: cpu_debug: define MODULE_DEVICE_TABLE Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 03/21] coresight: use IS_ENABLED for CONFIGs that may be modules Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 04/21] coresight: add coresight prefix to barrier_pkt Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 05/21] coresight: export global symbols Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 06/21] Allow to build coresight-stm as a module, for ease of development Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 07/21] coresight: allow etm3x to be built as a module Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 08/21] coresight: allow etm4x " Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 09/21] coresight: allow etb " Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 10/21] coresight: allow tpiu " Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 11/21] coresight: allow tmc " Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 12/21] coresight: remove multiple init calls from funnel driver Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 13/21] coresight: remove multiple init calls from replicator driver Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 14/21] coresight: allow funnel and replicator drivers to be built as modules Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 15/21] coresight: cti: add function to register cti associate ops Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 16/21] coresight: allow cti to be built as a module Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 17/21] coresight: tmc-etr: add function to register catu ops Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 18/21] coresight: allow catu drivers to be built as modules Tingwei Zhang
2020-07-01  7:14 ` [PATCH v1 19/21] coresight: disable trace path with device being removed Tingwei Zhang
2020-07-13 22:11   ` Mathieu Poirier
2020-07-14  1:10     ` tingwei
2020-07-01  7:14 ` [PATCH v1 20/21] coresight: allow the coresight core driver to be built as a module Tingwei Zhang
2020-07-01  7:14 ` Tingwei Zhang [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200701071427.10477-22-tingwei@codeaurora.org \
    --to=tingwei@codeaurora.org \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=coresight@lists.linaro.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=jinlmao@codeaurora.org \
    --cc=kim.phillips@arm.com \
    --cc=leo.yan@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux@armlinux.org.uk \
    --cc=mathieu.poirier@linaro.org \
    --cc=rdunlap@infradead.org \
    --cc=saiprakash.ranjan@codeaurora.org \
    --cc=suzuki.poulose@arm.com \
    --cc=tsoni@codeaurora.org \
    --cc=ykaukab@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.