summaryrefslogtreecommitdiff
path: root/drivers/hwtracing
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwtracing')
-rw-r--r--drivers/hwtracing/coresight/Kconfig12
-rw-r--r--drivers/hwtracing/coresight/Makefile4
-rw-r--r--drivers/hwtracing/coresight/coresight-catu.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-cfg-preload.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-cfg-preload.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-cfg-pstop.c83
-rw-r--r--drivers/hwtracing/coresight/coresight-config.c8
-rw-r--r--drivers/hwtracing/coresight/coresight-config.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c192
-rw-r--r--drivers/hwtracing/coresight/coresight-ctcu-core.c326
-rw-r--r--drivers/hwtracing/coresight/coresight-ctcu.h39
-rw-r--r--drivers/hwtracing/coresight/coresight-cti-core.c44
-rw-r--r--drivers/hwtracing/coresight/coresight-cti-sysfs.c76
-rw-r--r--drivers/hwtracing/coresight/coresight-cti.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-dummy.c15
-rw-r--r--drivers/hwtracing/coresight/coresight-etb10.c26
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.c27
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-etm.h1
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-core.c55
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-sysfs.c3
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-core.c124
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-sysfs.c254
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.h3
-rw-r--r--drivers/hwtracing/coresight/coresight-funnel.c12
-rw-r--r--drivers/hwtracing/coresight/coresight-priv.h14
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator.c12
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c13
-rw-r--r--drivers/hwtracing/coresight/coresight-syscfg-configfs.c12
-rw-r--r--drivers/hwtracing/coresight/coresight-syscfg.c26
-rw-r--r--drivers/hwtracing/coresight/coresight-sysfs.c17
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-core.c327
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etf.c140
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c224
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.h106
-rw-r--r--drivers/hwtracing/coresight/coresight-tpda.c20
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.c124
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.h33
-rw-r--r--drivers/hwtracing/coresight/coresight-trace-id.c22
-rw-r--r--drivers/hwtracing/coresight/ultrasoc-smb.c12
-rw-r--r--drivers/hwtracing/coresight/ultrasoc-smb.h2
-rw-r--r--drivers/hwtracing/stm/heartbeat.c6
42 files changed, 1907 insertions, 521 deletions
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 06f0a7594169..ecd7086a5b83 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -133,6 +133,18 @@ config CORESIGHT_STM
To compile this driver as a module, choose M here: the
module will be called coresight-stm.
+config CORESIGHT_CTCU
+ tristate "CoreSight TMC Control Unit driver"
+ depends on CORESIGHT_LINK_AND_SINK_TMC
+ help
+ This driver provides support for CoreSight TMC Control Unit
+ that hosts miscellaneous configuration registers. This is
+ primarily used for controlling the behaviors of the TMC
+ ETR device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called coresight-ctcu.
+
config CORESIGHT_CPU_DEBUG
tristate "CoreSight CPU Debug driver"
depends on ARM || ARM64
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 4ba478211b31..8e62c3150aeb 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -25,7 +25,7 @@ subdir-ccflags-y += $(condflags)
obj-$(CONFIG_CORESIGHT) += coresight.o
coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o coresight-config.o \
- coresight-cfg-preload.o coresight-cfg-afdo.o \
+ coresight-cfg-preload.o coresight-cfg-afdo.o coresight-cfg-pstop.o \
coresight-syscfg-configfs.o coresight-trace-id.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \
@@ -51,3 +51,5 @@ coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \
coresight-cti-sysfs.o
obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
+obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
+coresight-ctcu-y := coresight-ctcu-core.o
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
index 275cc0d9f505..fa170c966bc3 100644
--- a/drivers/hwtracing/coresight/coresight-catu.c
+++ b/drivers/hwtracing/coresight/coresight-catu.c
@@ -269,7 +269,7 @@ catu_init_sg_table(struct device *catu_dev, int node,
* Each table can address upto 1MB and we can have
* CATU_PAGES_PER_SYSPAGE tables in a system page.
*/
- nr_tpages = DIV_ROUND_UP(size, SZ_1M) / CATU_PAGES_PER_SYSPAGE;
+ nr_tpages = DIV_ROUND_UP(size, CATU_PAGES_PER_SYSPAGE * SZ_1M);
catu_table = tmc_alloc_sg_table(catu_dev, node, nr_tpages,
size >> PAGE_SHIFT, pages);
if (IS_ERR(catu_table))
@@ -594,7 +594,7 @@ static void catu_remove(struct amba_device *adev)
__catu_remove(&adev->dev);
}
-static struct amba_id catu_ids[] = {
+static const struct amba_id catu_ids[] = {
CS_AMBA_ID(0x000bb9ee),
{},
};
diff --git a/drivers/hwtracing/coresight/coresight-cfg-preload.c b/drivers/hwtracing/coresight/coresight-cfg-preload.c
index e237a4edfa09..4980e68483c5 100644
--- a/drivers/hwtracing/coresight/coresight-cfg-preload.c
+++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c
@@ -13,6 +13,7 @@
static struct cscfg_feature_desc *preload_feats[] = {
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
&strobe_etm4x,
+ &gen_etrig_etm4x,
#endif
NULL
};
@@ -20,6 +21,7 @@ static struct cscfg_feature_desc *preload_feats[] = {
static struct cscfg_config_desc *preload_cfgs[] = {
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
&afdo_etm4x,
+ &pstop_etm4x,
#endif
NULL
};
diff --git a/drivers/hwtracing/coresight/coresight-cfg-preload.h b/drivers/hwtracing/coresight/coresight-cfg-preload.h
index 21299e175477..291ba530a6a5 100644
--- a/drivers/hwtracing/coresight/coresight-cfg-preload.h
+++ b/drivers/hwtracing/coresight/coresight-cfg-preload.h
@@ -10,4 +10,6 @@
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
extern struct cscfg_feature_desc strobe_etm4x;
extern struct cscfg_config_desc afdo_etm4x;
+extern struct cscfg_feature_desc gen_etrig_etm4x;
+extern struct cscfg_config_desc pstop_etm4x;
#endif
diff --git a/drivers/hwtracing/coresight/coresight-cfg-pstop.c b/drivers/hwtracing/coresight/coresight-cfg-pstop.c
new file mode 100644
index 000000000000..c2bfbd07bfaf
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-cfg-pstop.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright(C) 2023 Marvell.
+ * Based on coresight-cfg-afdo.c
+ */
+
+#include "coresight-config.h"
+
+/* ETMv4 includes and features */
+#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
+#include "coresight-etm4x-cfg.h"
+
+/* preload configurations and features */
+
+/* preload in features for ETMv4 */
+
+/* panic_stop feature */
+static struct cscfg_parameter_desc gen_etrig_params[] = {
+ {
+ .name = "address",
+ .value = (u64)panic,
+ },
+};
+
+static struct cscfg_regval_desc gen_etrig_regs[] = {
+ /* resource selector */
+ {
+ .type = CS_CFG_REG_TYPE_RESOURCE,
+ .offset = TRCRSCTLRn(2),
+ .hw_info = ETM4_CFG_RES_SEL,
+ .val32 = 0x40001,
+ },
+ /* single address comparator */
+ {
+ .type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_64BIT |
+ CS_CFG_REG_TYPE_VAL_PARAM,
+ .offset = TRCACVRn(0),
+ .val32 = 0x0,
+ },
+ {
+ .type = CS_CFG_REG_TYPE_RESOURCE,
+ .offset = TRCACATRn(0),
+ .val64 = 0xf00,
+ },
+ /* Driver external output[0] with comparator out */
+ {
+ .type = CS_CFG_REG_TYPE_RESOURCE,
+ .offset = TRCEVENTCTL0R,
+ .val32 = 0x2,
+ },
+ /* end of regs */
+};
+
+struct cscfg_feature_desc gen_etrig_etm4x = {
+ .name = "gen_etrig",
+ .description = "Generate external trigger on address match\n"
+ "parameter \'address\': address of kernel address\n",
+ .match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
+ .nr_params = ARRAY_SIZE(gen_etrig_params),
+ .params_desc = gen_etrig_params,
+ .nr_regs = ARRAY_SIZE(gen_etrig_regs),
+ .regs_desc = gen_etrig_regs,
+};
+
+/* create a panic stop configuration */
+
+/* the total number of parameters in used features */
+#define PSTOP_NR_PARAMS ARRAY_SIZE(gen_etrig_params)
+
+static const char *pstop_ref_names[] = {
+ "gen_etrig",
+};
+
+struct cscfg_config_desc pstop_etm4x = {
+ .name = "panicstop",
+ .description = "Stop ETM on kernel panic\n",
+ .nr_feat_refs = ARRAY_SIZE(pstop_ref_names),
+ .feat_ref_names = pstop_ref_names,
+ .nr_total_params = PSTOP_NR_PARAMS,
+};
+
+/* end of ETM4x configurations */
+#endif /* IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) */
diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c
index 4723bf7402a2..4f72ae71b696 100644
--- a/drivers/hwtracing/coresight/coresight-config.c
+++ b/drivers/hwtracing/coresight/coresight-config.c
@@ -76,10 +76,10 @@ static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat_csdev)
unsigned long flags;
int i;
- spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
+ raw_spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
for (i = 0; i < feat_csdev->nr_regs; i++)
cscfg_set_reg(&feat_csdev->regs_csdev[i]);
- spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
+ raw_spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
feat_csdev->feat_desc->name, "set on enable");
return 0;
@@ -91,10 +91,10 @@ static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat_csdev)
unsigned long flags;
int i;
- spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
+ raw_spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
for (i = 0; i < feat_csdev->nr_regs; i++)
cscfg_save_reg(&feat_csdev->regs_csdev[i]);
- spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
+ raw_spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
feat_csdev->feat_desc->name, "save on disable");
}
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h
index 6ba013975741..b9ebc9fcfb7f 100644
--- a/drivers/hwtracing/coresight/coresight-config.h
+++ b/drivers/hwtracing/coresight/coresight-config.h
@@ -206,7 +206,7 @@ struct cscfg_feature_csdev {
const struct cscfg_feature_desc *feat_desc;
struct coresight_device *csdev;
struct list_head node;
- spinlock_t *drv_spinlock;
+ raw_spinlock_t *drv_spinlock;
int nr_params;
struct cscfg_parameter_csdev *params_csdev;
int nr_regs;
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 0a9380350fb5..fb43ef6a3b1f 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -19,10 +19,12 @@
#include <linux/property.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
+#include <linux/panic_notifier.h>
#include "coresight-etm-perf.h"
#include "coresight-priv.h"
#include "coresight-syscfg.h"
+#include "coresight-trace-id.h"
/*
* Mutex used to lock all sysfs enable and disable actions and loading and
@@ -75,14 +77,14 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
}
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
-static struct coresight_device *coresight_get_source(struct list_head *path)
+static struct coresight_device *coresight_get_source(struct coresight_path *path)
{
struct coresight_device *csdev;
if (!path)
return NULL;
- csdev = list_first_entry(path, struct coresight_node, link)->csdev;
+ csdev = list_first_entry(&path->path_list, struct coresight_node, link)->csdev;
if (!coresight_is_device_source(csdev))
return NULL;
@@ -331,12 +333,12 @@ static int coresight_enable_helper(struct coresight_device *csdev,
return helper_ops(csdev)->enable(csdev, mode, data);
}
-static void coresight_disable_helper(struct coresight_device *csdev)
+static void coresight_disable_helper(struct coresight_device *csdev, void *data)
{
- helper_ops(csdev)->disable(csdev, NULL);
+ helper_ops(csdev)->disable(csdev, data);
}
-static void coresight_disable_helpers(struct coresight_device *csdev)
+static void coresight_disable_helpers(struct coresight_device *csdev, void *data)
{
int i;
struct coresight_device *helper;
@@ -344,7 +346,7 @@ static void coresight_disable_helpers(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
helper = csdev->pdata->out_conns[i]->dest_dev;
if (helper && coresight_is_helper(helper))
- coresight_disable_helper(helper);
+ coresight_disable_helper(helper, data);
}
}
@@ -361,7 +363,7 @@ static void coresight_disable_helpers(struct coresight_device *csdev)
void coresight_disable_source(struct coresight_device *csdev, void *data)
{
source_ops(csdev)->disable(csdev, data);
- coresight_disable_helpers(csdev);
+ coresight_disable_helpers(csdev, NULL);
}
EXPORT_SYMBOL_GPL(coresight_disable_source);
@@ -370,16 +372,16 @@ EXPORT_SYMBOL_GPL(coresight_disable_source);
* @nd in the list. If @nd is NULL, all the components, except the SOURCE are
* disabled.
*/
-static void coresight_disable_path_from(struct list_head *path,
+static void coresight_disable_path_from(struct coresight_path *path,
struct coresight_node *nd)
{
u32 type;
struct coresight_device *csdev, *parent, *child;
if (!nd)
- nd = list_first_entry(path, struct coresight_node, link);
+ nd = list_first_entry(&path->path_list, struct coresight_node, link);
- list_for_each_entry_continue(nd, path, link) {
+ list_for_each_entry_continue(nd, &path->path_list, link) {
csdev = nd->csdev;
type = csdev->type;
@@ -417,11 +419,11 @@ static void coresight_disable_path_from(struct list_head *path,
}
/* Disable all helpers adjacent along the path last */
- coresight_disable_helpers(csdev);
+ coresight_disable_helpers(csdev, path);
}
}
-void coresight_disable_path(struct list_head *path)
+void coresight_disable_path(struct coresight_path *path)
{
coresight_disable_path_from(path, NULL);
}
@@ -446,7 +448,7 @@ static int coresight_enable_helpers(struct coresight_device *csdev,
return 0;
}
-int coresight_enable_path(struct list_head *path, enum cs_mode mode,
+int coresight_enable_path(struct coresight_path *path, enum cs_mode mode,
void *sink_data)
{
int ret = 0;
@@ -456,12 +458,12 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
struct coresight_device *source;
source = coresight_get_source(path);
- list_for_each_entry_reverse(nd, path, link) {
+ list_for_each_entry_reverse(nd, &path->path_list, link) {
csdev = nd->csdev;
type = csdev->type;
/* Enable all helpers adjacent to the path first */
- ret = coresight_enable_helpers(csdev, mode, sink_data);
+ ret = coresight_enable_helpers(csdev, mode, path);
if (ret)
goto err;
/*
@@ -509,20 +511,21 @@ err:
goto out;
}
-struct coresight_device *coresight_get_sink(struct list_head *path)
+struct coresight_device *coresight_get_sink(struct coresight_path *path)
{
struct coresight_device *csdev;
if (!path)
return NULL;
- csdev = list_last_entry(path, struct coresight_node, link)->csdev;
+ csdev = list_last_entry(&path->path_list, struct coresight_node, link)->csdev;
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
return NULL;
return csdev;
}
+EXPORT_SYMBOL_GPL(coresight_get_sink);
u32 coresight_get_sink_id(struct coresight_device *csdev)
{
@@ -653,6 +656,50 @@ static void coresight_drop_device(struct coresight_device *csdev)
}
}
+/*
+ * coresight device will read their existing or alloc a trace ID, if their trace_id
+ * callback is set.
+ *
+ * Return 0 if the trace_id callback is not set.
+ * Return the result of the trace_id callback if it is set. The return value
+ * will be the trace_id if successful, and an error number if it fails.
+ */
+static int coresight_get_trace_id(struct coresight_device *csdev,
+ enum cs_mode mode,
+ struct coresight_device *sink)
+{
+ if (coresight_ops(csdev)->trace_id)
+ return coresight_ops(csdev)->trace_id(csdev, mode, sink);
+
+ return 0;
+}
+
+/*
+ * Call this after creating the path and before enabling it. This leaves
+ * the trace ID set on the path, or it remains 0 if it couldn't be assigned.
+ */
+void coresight_path_assign_trace_id(struct coresight_path *path,
+ enum cs_mode mode)
+{
+ struct coresight_device *sink = coresight_get_sink(path);
+ struct coresight_node *nd;
+ int trace_id;
+
+ list_for_each_entry(nd, &path->path_list, link) {
+ /* Assign a trace ID to the path for the first device that wants to do it */
+ trace_id = coresight_get_trace_id(nd->csdev, mode, sink);
+
+ /*
+ * 0 in this context is that it didn't want to assign so keep searching.
+ * Non 0 is either success or fail.
+ */
+ if (trace_id != 0) {
+ path->trace_id = trace_id;
+ return;
+ }
+ }
+}
+
/**
* _coresight_build_path - recursively build a path from a @csdev to a sink.
* @csdev: The device to start from.
@@ -668,7 +715,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
static int _coresight_build_path(struct coresight_device *csdev,
struct coresight_device *source,
struct coresight_device *sink,
- struct list_head *path)
+ struct coresight_path *path)
{
int i, ret;
bool found = false;
@@ -721,25 +768,25 @@ out:
return -ENOMEM;
node->csdev = csdev;
- list_add(&node->link, path);
+ list_add(&node->link, &path->path_list);
return 0;
}
-struct list_head *coresight_build_path(struct coresight_device *source,
+struct coresight_path *coresight_build_path(struct coresight_device *source,
struct coresight_device *sink)
{
- struct list_head *path;
+ struct coresight_path *path;
int rc;
if (!sink)
return ERR_PTR(-EINVAL);
- path = kzalloc(sizeof(struct list_head), GFP_KERNEL);
+ path = kzalloc(sizeof(struct coresight_path), GFP_KERNEL);
if (!path)
return ERR_PTR(-ENOMEM);
- INIT_LIST_HEAD(path);
+ INIT_LIST_HEAD(&path->path_list);
rc = _coresight_build_path(source, source, sink, path);
if (rc) {
@@ -757,12 +804,12 @@ struct list_head *coresight_build_path(struct coresight_device *source,
* Go through all the elements of a path and 1) removed it from the list and
* 2) free the memory allocated for each node.
*/
-void coresight_release_path(struct list_head *path)
+void coresight_release_path(struct coresight_path *path)
{
struct coresight_device *csdev;
struct coresight_node *nd, *next;
- list_for_each_entry_safe(nd, next, path, link) {
+ list_for_each_entry_safe(nd, next, &path->path_list, link) {
csdev = nd->csdev;
coresight_drop_device(csdev);
@@ -1092,18 +1139,20 @@ static void coresight_remove_conns(struct coresight_device *csdev)
}
/**
- * coresight_timeout - loop until a bit has changed to a specific register
- * state.
+ * coresight_timeout_action - loop until a bit has changed to a specific register
+ * state, with a callback after every trial.
* @csa: coresight device access for the device
* @offset: Offset of the register from the base of the device.
* @position: the position of the bit of interest.
* @value: the value the bit should have.
+ * @cb: Call back after each trial.
*
* Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
* TIMEOUT_US has elapsed, which ever happens first.
*/
-int coresight_timeout(struct csdev_access *csa, u32 offset,
- int position, int value)
+int coresight_timeout_action(struct csdev_access *csa, u32 offset,
+ int position, int value,
+ coresight_timeout_cb_t cb)
{
int i;
u32 val;
@@ -1119,7 +1168,8 @@ int coresight_timeout(struct csdev_access *csa, u32 offset,
if (!(val & BIT(position)))
return 0;
}
-
+ if (cb)
+ cb(csa, offset, position, value);
/*
* Delay is arbitrary - the specification doesn't say how long
* we are expected to wait. Extra check required to make sure
@@ -1131,6 +1181,13 @@ int coresight_timeout(struct csdev_access *csa, u32 offset,
return -EAGAIN;
}
+EXPORT_SYMBOL_GPL(coresight_timeout_action);
+
+int coresight_timeout(struct csdev_access *csa, u32 offset,
+ int position, int value)
+{
+ return coresight_timeout_action(csa, offset, position, value, NULL);
+}
EXPORT_SYMBOL_GPL(coresight_timeout);
u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset)
@@ -1239,7 +1296,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) {
- spin_lock_init(&csdev->perf_sink_id_map.lock);
+ raw_spin_lock_init(&csdev->perf_sink_id_map.lock);
csdev->perf_sink_id_map.cpu_map = alloc_percpu(atomic_t);
if (!csdev->perf_sink_id_map.cpu_map) {
kfree(csdev);
@@ -1453,6 +1510,36 @@ const struct bus_type coresight_bustype = {
.name = "coresight",
};
+static int coresight_panic_sync(struct device *dev, void *data)
+{
+ int mode;
+ struct coresight_device *csdev;
+
+ /* Run through panic sync handlers for all enabled devices */
+ csdev = container_of(dev, struct coresight_device, dev);
+ mode = coresight_get_mode(csdev);
+
+ if ((mode == CS_MODE_SYSFS) || (mode == CS_MODE_PERF)) {
+ if (panic_ops(csdev))
+ panic_ops(csdev)->sync(csdev);
+ }
+
+ return 0;
+}
+
+static int coresight_panic_cb(struct notifier_block *self,
+ unsigned long v, void *p)
+{
+ bus_for_each_dev(&coresight_bustype, NULL, NULL,
+ coresight_panic_sync);
+
+ return 0;
+}
+
+static struct notifier_block coresight_notifier = {
+ .notifier_call = coresight_panic_cb,
+};
+
static int __init coresight_init(void)
{
int ret;
@@ -1465,11 +1552,20 @@ static int __init coresight_init(void)
if (ret)
goto exit_bus_unregister;
+ /* Register function to be called for panic */
+ ret = atomic_notifier_chain_register(&panic_notifier_list,
+ &coresight_notifier);
+ if (ret)
+ goto exit_perf;
+
/* initialise the coresight syscfg API */
ret = cscfg_init();
if (!ret)
return 0;
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &coresight_notifier);
+exit_perf:
etm_perf_exit();
exit_bus_unregister:
bus_unregister(&coresight_bustype);
@@ -1479,6 +1575,8 @@ exit_bus_unregister:
static void __exit coresight_exit(void)
{
cscfg_exit();
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &coresight_notifier);
etm_perf_exit();
bus_unregister(&coresight_bustype);
}
@@ -1515,6 +1613,38 @@ void coresight_remove_driver(struct amba_driver *amba_drv,
}
EXPORT_SYMBOL_GPL(coresight_remove_driver);
+int coresight_etm_get_trace_id(struct coresight_device *csdev, enum cs_mode mode,
+ struct coresight_device *sink)
+{
+ int cpu, trace_id;
+
+ if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE || !source_ops(csdev)->cpu_id)
+ return -EINVAL;
+
+ cpu = source_ops(csdev)->cpu_id(csdev);
+ switch (mode) {
+ case CS_MODE_SYSFS:
+ trace_id = coresight_trace_id_get_cpu_id(cpu);
+ break;
+ case CS_MODE_PERF:
+ if (WARN_ON(!sink))
+ return -EINVAL;
+
+ trace_id = coresight_trace_id_get_cpu_id_map(cpu, &sink->perf_sink_id_map);
+ break;
+ default:
+ trace_id = -EINVAL;
+ break;
+ }
+
+ if (!IS_VALID_CS_TRACE_ID(trace_id))
+ dev_err(&csdev->dev,
+ "Failed to allocate trace ID on CPU%d\n", cpu);
+
+ return trace_id;
+}
+EXPORT_SYMBOL_GPL(coresight_etm_get_trace_id);
+
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c
new file mode 100644
index 000000000000..c6bafc96db96
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/coresight.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include "coresight-ctcu.h"
+#include "coresight-priv.h"
+
+DEFINE_CORESIGHT_DEVLIST(ctcu_devs, "ctcu");
+
+#define ctcu_writel(drvdata, val, offset) __raw_writel((val), drvdata->base + offset)
+#define ctcu_readl(drvdata, offset) __raw_readl(drvdata->base + offset)
+
+/*
+ * The TMC Coresight Control Unit utilizes four ATID registers to control the data
+ * filter function based on the trace ID for each TMC ETR sink. The length of each
+ * ATID register is 32 bits. Therefore, an ETR device has a 128-bit long field
+ * in CTCU. Each trace ID is represented by one bit in that filed.
+ * e.g. ETR0ATID0 layout, set bit 5 for traceid 5
+ * bit5
+ * ------------------------------------------------------
+ * | |28| |24| |20| |16| |12| |8| 1|4| |0|
+ * ------------------------------------------------------
+ *
+ * e.g. ETR0:
+ * 127 0 from ATID_offset for ETR0ATID0
+ * -------------------------
+ * |ATID3|ATID2|ATID1|ATID0|
+ */
+#define CTCU_ATID_REG_OFFSET(traceid, atid_offset) \
+ ((traceid / 32) * 4 + atid_offset)
+
+#define CTCU_ATID_REG_BIT(traceid) (traceid % 32)
+#define CTCU_ATID_REG_SIZE 0x10
+#define CTCU_ETR0_ATID0 0xf8
+#define CTCU_ETR1_ATID0 0x108
+
+static const struct ctcu_etr_config sa8775p_etr_cfgs[] = {
+ {
+ .atid_offset = CTCU_ETR0_ATID0,
+ .port_num = 0,
+ },
+ {
+ .atid_offset = CTCU_ETR1_ATID0,
+ .port_num = 1,
+ },
+};
+
+static const struct ctcu_config sa8775p_cfgs = {
+ .etr_cfgs = sa8775p_etr_cfgs,
+ .num_etr_config = ARRAY_SIZE(sa8775p_etr_cfgs),
+};
+
+static void ctcu_program_atid_register(struct ctcu_drvdata *drvdata, u32 reg_offset,
+ u8 bit, bool enable)
+{
+ u32 val;
+
+ CS_UNLOCK(drvdata->base);
+ val = ctcu_readl(drvdata, reg_offset);
+ if (enable)
+ val |= BIT(bit);
+ else
+ val &= ~BIT(bit);
+
+ ctcu_writel(drvdata, val, reg_offset);
+ CS_LOCK(drvdata->base);
+}
+
+/*
+ * __ctcu_set_etr_traceid: Set bit in the ATID register based on trace ID when enable is true.
+ * Reset the bit of the ATID register based on trace ID when enable is false.
+ *
+ * @csdev: coresight_device of CTCU.
+ * @traceid: trace ID of the source tracer.
+ * @port_num: port number connected to TMC ETR sink.
+ * @enable: True for set bit and false for reset bit.
+ *
+ * Returns 0 indicates success. Non-zero result means failure.
+ */
+static int __ctcu_set_etr_traceid(struct coresight_device *csdev, u8 traceid, int port_num,
+ bool enable)
+{
+ struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ u32 atid_offset, reg_offset;
+ u8 refcnt, bit;
+
+ atid_offset = drvdata->atid_offset[port_num];
+ if (atid_offset == 0)
+ return -EINVAL;
+
+ bit = CTCU_ATID_REG_BIT(traceid);
+ reg_offset = CTCU_ATID_REG_OFFSET(traceid, atid_offset);
+ if (reg_offset - atid_offset > CTCU_ATID_REG_SIZE)
+ return -EINVAL;
+
+ guard(raw_spinlock_irqsave)(&drvdata->spin_lock);
+ refcnt = drvdata->traceid_refcnt[port_num][traceid];
+ /* Only program the atid register when the refcnt value is 1 or 0 */
+ if ((enable && !refcnt++) || (!enable && !--refcnt))
+ ctcu_program_atid_register(drvdata, reg_offset, bit, enable);
+
+ drvdata->traceid_refcnt[port_num][traceid] = refcnt;
+
+ return 0;
+}
+
+/*
+ * Searching the sink device from helper's view in case there are multiple helper devices
+ * connected to the sink device.
+ */
+static int ctcu_get_active_port(struct coresight_device *sink, struct coresight_device *helper)
+{
+ struct coresight_platform_data *pdata = helper->pdata;
+ int i;
+
+ for (i = 0; i < pdata->nr_inconns; ++i) {
+ if (pdata->in_conns[i]->src_dev == sink)
+ return pdata->in_conns[i]->dest_port;
+ }
+
+ return -EINVAL;
+}
+
+static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight_path *path,
+ bool enable)
+{
+ struct coresight_device *sink = coresight_get_sink(path);
+ u8 traceid = path->trace_id;
+ int port_num;
+
+ if ((sink == NULL) || !IS_VALID_CS_TRACE_ID(traceid)) {
+ dev_err(&csdev->dev, "Invalid sink device or trace ID\n");
+ return -EINVAL;
+ }
+
+ port_num = ctcu_get_active_port(sink, csdev);
+ if (port_num < 0)
+ return -EINVAL;
+
+ dev_dbg(&csdev->dev, "traceid is %d\n", traceid);
+
+ return __ctcu_set_etr_traceid(csdev, traceid, port_num, enable);
+}
+
+static int ctcu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data)
+{
+ struct coresight_path *path = (struct coresight_path *)data;
+
+ return ctcu_set_etr_traceid(csdev, path, true);
+}
+
+static int ctcu_disable(struct coresight_device *csdev, void *data)
+{
+ struct coresight_path *path = (struct coresight_path *)data;
+
+ return ctcu_set_etr_traceid(csdev, path, false);
+}
+
+static const struct coresight_ops_helper ctcu_helper_ops = {
+ .enable = ctcu_enable,
+ .disable = ctcu_disable,
+};
+
+static const struct coresight_ops ctcu_ops = {
+ .helper_ops = &ctcu_helper_ops,
+};
+
+static int ctcu_probe(struct platform_device *pdev)
+{
+ const struct ctcu_etr_config *etr_cfg;
+ struct coresight_platform_data *pdata;
+ struct coresight_desc desc = { 0 };
+ struct device *dev = &pdev->dev;
+ const struct ctcu_config *cfgs;
+ struct ctcu_drvdata *drvdata;
+ void __iomem *base;
+ int i;
+
+ desc.name = coresight_alloc_device_name(&ctcu_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ dev->platform_data = pdata;
+
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ drvdata->apb_clk = coresight_get_enable_apb_pclk(dev);
+ if (IS_ERR(drvdata->apb_clk))
+ return -ENODEV;
+
+ cfgs = of_device_get_match_data(dev);
+ if (cfgs) {
+ if (cfgs->num_etr_config <= ETR_MAX_NUM) {
+ for (i = 0; i < cfgs->num_etr_config; i++) {
+ etr_cfg = &cfgs->etr_cfgs[i];
+ drvdata->atid_offset[i] = etr_cfg->atid_offset;
+ }
+ }
+ }
+
+ drvdata->base = base;
+ drvdata->dev = dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ desc.type = CORESIGHT_DEV_TYPE_HELPER;
+ desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CTCU;
+ desc.pdata = pdata;
+ desc.dev = dev;
+ desc.ops = &ctcu_ops;
+ desc.access = CSDEV_ACCESS_IOMEM(base);
+
+ drvdata->csdev = coresight_register(&desc);
+ if (IS_ERR(drvdata->csdev)) {
+ if (!IS_ERR_OR_NULL(drvdata->apb_clk))
+ clk_put(drvdata->apb_clk);
+
+ return PTR_ERR(drvdata->csdev);
+ }
+
+ return 0;
+}
+
+static void ctcu_remove(struct platform_device *pdev)
+{
+ struct ctcu_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+}
+
+static int ctcu_platform_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = ctcu_probe(pdev);
+ pm_runtime_put(&pdev->dev);
+ if (ret)
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static void ctcu_platform_remove(struct platform_device *pdev)
+{
+ struct ctcu_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ if (WARN_ON(!drvdata))
+ return;
+
+ ctcu_remove(pdev);
+ pm_runtime_disable(&pdev->dev);
+ if (!IS_ERR_OR_NULL(drvdata->apb_clk))
+ clk_put(drvdata->apb_clk);
+}
+
+#ifdef CONFIG_PM
+static int ctcu_runtime_suspend(struct device *dev)
+{
+ struct ctcu_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (drvdata && !IS_ERR_OR_NULL(drvdata->apb_clk))
+ clk_disable_unprepare(drvdata->apb_clk);
+
+ return 0;
+}
+
+static int ctcu_runtime_resume(struct device *dev)
+{
+ struct ctcu_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (drvdata && !IS_ERR_OR_NULL(drvdata->apb_clk))
+ clk_prepare_enable(drvdata->apb_clk);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops ctcu_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(ctcu_runtime_suspend, ctcu_runtime_resume, NULL)
+};
+
+static const struct of_device_id ctcu_match[] = {
+ {.compatible = "qcom,sa8775p-ctcu", .data = &sa8775p_cfgs},
+ {}
+};
+
+static struct platform_driver ctcu_driver = {
+ .probe = ctcu_platform_probe,
+ .remove = ctcu_platform_remove,
+ .driver = {
+ .name = "coresight-ctcu",
+ .of_match_table = ctcu_match,
+ .pm = &ctcu_dev_pm_ops,
+ .suppress_bind_attrs = true,
+ },
+};
+module_platform_driver(ctcu_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CoreSight TMC Control Unit driver");
diff --git a/drivers/hwtracing/coresight/coresight-ctcu.h b/drivers/hwtracing/coresight/coresight-ctcu.h
new file mode 100644
index 000000000000..e9594c38dd91
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-ctcu.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CORESIGHT_CTCU_H
+#define _CORESIGHT_CTCU_H
+#include "coresight-trace-id.h"
+
+/* Maximum number of supported ETR devices for a single CTCU. */
+#define ETR_MAX_NUM 2
+
+/**
+ * struct ctcu_etr_config
+ * @atid_offset: offset to the ATID0 Register.
+ * @port_num: in-port number of CTCU device that connected to ETR.
+ */
+struct ctcu_etr_config {
+ const u32 atid_offset;
+ const u32 port_num;
+};
+
+struct ctcu_config {
+ const struct ctcu_etr_config *etr_cfgs;
+ int num_etr_config;
+};
+
+struct ctcu_drvdata {
+ void __iomem *base;
+ struct clk *apb_clk;
+ struct device *dev;
+ struct coresight_device *csdev;
+ raw_spinlock_t spin_lock;
+ u32 atid_offset[ETR_MAX_NUM];
+ /* refcnt for each traceid of each sink */
+ u8 traceid_refcnt[ETR_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP];
+};
+
+#endif
diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index d2b5a5718c29..80f6265e3740 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -93,7 +93,7 @@ static int cti_enable_hw(struct cti_drvdata *drvdata)
unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* no need to do anything if enabled or unpowered*/
if (config->hw_enabled || !config->hw_powered)
@@ -108,7 +108,7 @@ static int cti_enable_hw(struct cti_drvdata *drvdata)
config->hw_enabled = true;
drvdata->config.enable_req_count++;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return rc;
cti_state_unchanged:
@@ -116,7 +116,7 @@ cti_state_unchanged:
/* cannot enable due to error */
cti_err_not_enabled:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return rc;
}
@@ -125,7 +125,7 @@ static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)
{
struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->hw_powered = true;
/* no need to do anything if no enable request */
@@ -138,12 +138,12 @@ static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)
cti_write_all_hw_regs(drvdata);
config->hw_enabled = true;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return;
/* did not re-enable due to no claim / no request */
cti_hp_not_enabled:
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
}
/* disable hardware */
@@ -153,7 +153,7 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
struct coresight_device *csdev = drvdata->csdev;
int ret = 0;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* don't allow negative refcounts, return an error */
if (!drvdata->config.enable_req_count) {
@@ -177,12 +177,12 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
coresight_disclaim_device_unlocked(csdev);
CS_LOCK(drvdata->base);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return ret;
/* not disabled this call */
cti_not_disabled:
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return ret;
}
@@ -198,11 +198,11 @@ void cti_write_intack(struct device *dev, u32 ackval)
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* write if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIINTACK, ackval);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
}
/*
@@ -369,7 +369,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
CTIOUTEN(trigger_idx));
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* read - modify write - the trigger / channel enable value */
reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] :
@@ -388,7 +388,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return 0;
}
@@ -406,7 +406,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
chan_bitmask = BIT(channel_idx);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
reg_value = config->ctigate;
switch (op) {
case CTI_GATE_CHAN_ENABLE:
@@ -426,7 +426,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
if (cti_active(config))
cti_write_single_reg(drvdata, CTIGATE, reg_value);
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return err;
}
@@ -445,7 +445,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
chan_bitmask = BIT(channel_idx);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
reg_value = config->ctiappset;
switch (op) {
case CTI_CHAN_SET:
@@ -473,7 +473,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
if ((err == 0) && cti_active(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return err;
}
@@ -676,7 +676,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu))
return NOTIFY_BAD;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
switch (cmd) {
case CPU_PM_ENTER:
@@ -716,7 +716,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
}
cti_notify_exit:
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return notify_res;
}
@@ -743,11 +743,11 @@ static int cti_dying_cpu(unsigned int cpu)
if (!drvdata)
return 0;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
drvdata->config.hw_powered = false;
if (drvdata->config.hw_enabled)
coresight_disclaim_device(drvdata->csdev);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return 0;
}
@@ -888,7 +888,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->ctidev.ctm_id = 0;
INIT_LIST_HEAD(&drvdata->ctidev.trig_cons);
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
/* initialise CTI driver config values */
cti_set_default_config(dev, drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index d25dd2737b49..572b80ee96fb 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -84,11 +84,11 @@ static ssize_t enable_show(struct device *dev,
bool enabled, powered;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
enable_req = drvdata->config.enable_req_count;
powered = drvdata->config.hw_powered;
enabled = drvdata->config.hw_enabled;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
if (powered)
return sprintf(buf, "%d\n", enabled);
@@ -134,9 +134,9 @@ static ssize_t powered_show(struct device *dev,
bool powered;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
powered = drvdata->config.hw_powered;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%d\n", powered);
}
@@ -181,10 +181,10 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
u32 val = 0;
pm_runtime_get_sync(dev->parent);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
if (drvdata->config.hw_powered)
val = readl_relaxed(drvdata->base + cti_attr->off);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
pm_runtime_put_sync(dev->parent);
return sysfs_emit(buf, "0x%x\n", val);
}
@@ -202,10 +202,10 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
return -EINVAL;
pm_runtime_get_sync(dev->parent);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
if (drvdata->config.hw_powered)
cti_write_single_reg(drvdata, cti_attr->off, val);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
pm_runtime_put_sync(dev->parent);
return size;
}
@@ -264,7 +264,7 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf,
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
if ((reg_offset >= 0) && cti_active(config)) {
CS_UNLOCK(drvdata->base);
val = readl_relaxed(drvdata->base + reg_offset);
@@ -274,7 +274,7 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf,
} else if (pcached_val) {
val = *pcached_val;
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#x\n", val);
}
@@ -293,7 +293,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* local store */
if (pcached_val)
*pcached_val = (u32)val;
@@ -301,7 +301,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,
/* write through if offset and enabled */
if ((reg_offset >= 0) && cti_active(config))
cti_write_single_reg(drvdata, reg_offset, val);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -349,9 +349,9 @@ static ssize_t inout_sel_store(struct device *dev,
if (val > (CTIINOUTEN_MAX - 1))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
drvdata->config.ctiinout_sel = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(inout_sel);
@@ -364,10 +364,10 @@ static ssize_t inen_show(struct device *dev,
int index;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
index = drvdata->config.ctiinout_sel;
val = drvdata->config.ctiinen[index];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -383,14 +383,14 @@ static ssize_t inen_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
index = config->ctiinout_sel;
config->ctiinen[index] = val;
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIINEN(index), val);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(inen);
@@ -403,10 +403,10 @@ static ssize_t outen_show(struct device *dev,
int index;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
index = drvdata->config.ctiinout_sel;
val = drvdata->config.ctiouten[index];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -422,14 +422,14 @@ static ssize_t outen_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
index = config->ctiinout_sel;
config->ctiouten[index] = val;
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIOUTEN(index), val);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(outen);
@@ -463,7 +463,7 @@ static ssize_t appclear_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* a 1'b1 in appclr clears down the same bit in appset*/
config->ctiappset &= ~val;
@@ -471,7 +471,7 @@ static ssize_t appclear_store(struct device *dev,
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_WO(appclear);
@@ -487,12 +487,12 @@ static ssize_t apppulse_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIAPPPULSE, val);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_WO(apppulse);
@@ -681,9 +681,9 @@ static ssize_t trig_filter_enable_show(struct device *dev,
u32 val;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = drvdata->config.trig_filter_enable;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%d\n", val);
}
@@ -697,9 +697,9 @@ static ssize_t trig_filter_enable_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
drvdata->config.trig_filter_enable = !!val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(trig_filter_enable);
@@ -728,7 +728,7 @@ static ssize_t chan_xtrigs_reset_store(struct device *dev,
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* clear the CTI trigger / channel programming registers */
for (i = 0; i < config->nr_trig_max; i++) {
@@ -747,7 +747,7 @@ static ssize_t chan_xtrigs_reset_store(struct device *dev,
if (cti_active(config))
cti_write_all_hw_regs(drvdata);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_WO(chan_xtrigs_reset);
@@ -768,9 +768,9 @@ static ssize_t chan_xtrigs_sel_store(struct device *dev,
if (val > (drvdata->config.nr_ctm_channels - 1))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
drvdata->config.xtrig_rchan_sel = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -781,9 +781,9 @@ static ssize_t chan_xtrigs_sel_show(struct device *dev,
unsigned long val;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = drvdata->config.xtrig_rchan_sel;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%ld\n", val);
}
@@ -838,12 +838,12 @@ static ssize_t print_chan_list(struct device *dev,
unsigned long inuse_bits = 0, chan_mask;
/* scan regs to get bitmap of channels in use. */
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
for (i = 0; i < config->nr_trig_max; i++) {
inuse_bits |= config->ctiinen[i];
inuse_bits |= config->ctiouten[i];
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
/* inverse bits if printing free channels */
if (!inuse)
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index cb9ee616d01f..16e310e7e9d4 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -175,7 +175,7 @@ struct cti_drvdata {
void __iomem *base;
struct coresight_device *csdev;
struct cti_device ctidev;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
struct cti_config config;
struct list_head node;
void (*csdev_release)(struct device *dev);
diff --git a/drivers/hwtracing/coresight/coresight-dummy.c b/drivers/hwtracing/coresight/coresight-dummy.c
index 9be53be8964b..aaa92b5081e3 100644
--- a/drivers/hwtracing/coresight/coresight-dummy.c
+++ b/drivers/hwtracing/coresight/coresight-dummy.c
@@ -24,7 +24,7 @@ DEFINE_CORESIGHT_DEVLIST(sink_devs, "dummy_sink");
static int dummy_source_enable(struct coresight_device *csdev,
struct perf_event *event, enum cs_mode mode,
- __maybe_unused struct coresight_trace_id_map *id_map)
+ __maybe_unused struct coresight_path *path)
{
if (!coresight_take_mode(csdev, mode))
return -EBUSY;
@@ -41,6 +41,16 @@ static void dummy_source_disable(struct coresight_device *csdev,
dev_dbg(csdev->dev.parent, "Dummy source disabled\n");
}
+static int dummy_source_trace_id(struct coresight_device *csdev, __maybe_unused enum cs_mode mode,
+ __maybe_unused struct coresight_device *sink)
+{
+ struct dummy_drvdata *drvdata;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ return drvdata->traceid;
+}
+
static int dummy_sink_enable(struct coresight_device *csdev, enum cs_mode mode,
void *data)
{
@@ -62,7 +72,8 @@ static const struct coresight_ops_source dummy_source_ops = {
};
static const struct coresight_ops dummy_source_cs_ops = {
- .source_ops = &dummy_source_ops,
+ .trace_id = dummy_source_trace_id,
+ .source_ops = &dummy_source_ops,
};
static const struct coresight_ops_sink dummy_sink_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index aea9ac9c4bd0..7948597d483d 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -84,7 +84,7 @@ struct etb_drvdata {
struct clk *atclk;
struct coresight_device *csdev;
struct miscdevice miscdev;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
local_t reading;
pid_t pid;
u8 *buf;
@@ -145,7 +145,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
unsigned long flags;
struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't messup with perf sessions. */
if (coresight_get_mode(csdev) == CS_MODE_PERF) {
@@ -163,7 +163,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
csdev->refcnt++;
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
@@ -176,7 +176,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
struct perf_output_handle *handle = data;
struct cs_buffers *buf = etm_perf_sink_config(handle);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* No need to continue if the component is already in used by sysFS. */
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
@@ -219,7 +219,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
}
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
@@ -352,11 +352,11 @@ static int etb_disable(struct coresight_device *csdev)
struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
unsigned long flags;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
csdev->refcnt--;
if (csdev->refcnt) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -366,7 +366,7 @@ static int etb_disable(struct coresight_device *csdev)
/* Dissociate from monitored process. */
drvdata->pid = -1;
coresight_set_mode(csdev, CS_MODE_DISABLED);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_dbg(&csdev->dev, "ETB disabled\n");
return 0;
@@ -443,7 +443,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */
if (csdev->refcnt != 1)
@@ -566,7 +566,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
__etb_enable_hw(drvdata);
CS_LOCK(drvdata->base);
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return to_read;
}
@@ -587,13 +587,13 @@ static void etb_dump(struct etb_drvdata *drvdata)
{
unsigned long flags;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
__etb_disable_hw(drvdata);
etb_dump_hw(drvdata);
__etb_enable_hw(drvdata);
}
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_dbg(&drvdata->csdev->dev, "ETB dumped\n");
}
@@ -746,7 +746,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->base = base;
desc.access = CSDEV_ACCESS_IOMEM(base);
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index ad6a8f4b70b6..f4cccd68e625 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -136,13 +136,13 @@ static const struct attribute_group *etm_pmu_attr_groups[] = {
NULL,
};
-static inline struct list_head **
+static inline struct coresight_path **
etm_event_cpu_path_ptr(struct etm_event_data *data, int cpu)
{
return per_cpu_ptr(data->path, cpu);
}
-static inline struct list_head *
+static inline struct coresight_path *
etm_event_cpu_path(struct etm_event_data *data, int cpu)
{
return *etm_event_cpu_path_ptr(data, cpu);
@@ -226,7 +226,7 @@ static void free_event_data(struct work_struct *work)
cscfg_deactivate_config(event_data->cfg_hash);
for_each_cpu(cpu, mask) {
- struct list_head **ppath;
+ struct coresight_path **ppath;
ppath = etm_event_cpu_path_ptr(event_data, cpu);
if (!(IS_ERR_OR_NULL(*ppath))) {
@@ -276,7 +276,7 @@ static void *alloc_event_data(int cpu)
* unused memory when dealing with single CPU trace scenarios is small
* compared to the cost of searching through an optimized array.
*/
- event_data->path = alloc_percpu(struct list_head *);
+ event_data->path = alloc_percpu(struct coresight_path *);
if (!event_data->path) {
kfree(event_data);
@@ -317,7 +317,6 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
{
u32 id, cfg_hash;
int cpu = event->cpu;
- int trace_id;
cpumask_t *mask;
struct coresight_device *sink = NULL;
struct coresight_device *user_sink = NULL, *last_sink = NULL;
@@ -352,7 +351,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
* CPUs, we can handle it and fail the session.
*/
for_each_cpu(cpu, mask) {
- struct list_head *path;
+ struct coresight_path *path;
struct coresight_device *csdev;
csdev = per_cpu(csdev_src, cpu);
@@ -407,8 +406,8 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
}
/* ensure we can allocate a trace ID for this CPU */
- trace_id = coresight_trace_id_get_cpu_id_map(cpu, &sink->perf_sink_id_map);
- if (!IS_VALID_CS_TRACE_ID(trace_id)) {
+ coresight_path_assign_trace_id(path, CS_MODE_PERF);
+ if (!IS_VALID_CS_TRACE_ID(path->trace_id)) {
cpumask_clear_cpu(cpu, mask);
coresight_release_path(path);
continue;
@@ -458,9 +457,8 @@ static void etm_event_start(struct perf_event *event, int flags)
struct etm_ctxt *ctxt = this_cpu_ptr(&etm_ctxt);
struct perf_output_handle *handle = &ctxt->handle;
struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
- struct list_head *path;
+ struct coresight_path *path;
u64 hw_id;
- u8 trace_id;
if (!csdev)
goto fail;
@@ -503,8 +501,7 @@ static void etm_event_start(struct perf_event *event, int flags)
goto fail_end_stop;
/* Finally enable the tracer */
- if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF,
- &sink->perf_sink_id_map))
+ if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF, path))
goto fail_disable_path;
/*
@@ -514,13 +511,11 @@ static void etm_event_start(struct perf_event *event, int flags)
if (!cpumask_test_cpu(cpu, &event_data->aux_hwid_done)) {
cpumask_set_cpu(cpu, &event_data->aux_hwid_done);
- trace_id = coresight_trace_id_read_cpu_id_map(cpu, &sink->perf_sink_id_map);
-
hw_id = FIELD_PREP(CS_AUX_HW_ID_MAJOR_VERSION_MASK,
CS_AUX_HW_ID_MAJOR_VERSION);
hw_id |= FIELD_PREP(CS_AUX_HW_ID_MINOR_VERSION_MASK,
CS_AUX_HW_ID_MINOR_VERSION);
- hw_id |= FIELD_PREP(CS_AUX_HW_ID_TRACE_ID_MASK, trace_id);
+ hw_id |= FIELD_PREP(CS_AUX_HW_ID_TRACE_ID_MASK, path->trace_id);
hw_id |= FIELD_PREP(CS_AUX_HW_ID_SINK_ID_MASK, coresight_get_sink_id(sink));
perf_report_aux_output_id(event, hw_id);
@@ -558,7 +553,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
struct etm_ctxt *ctxt = this_cpu_ptr(&etm_ctxt);
struct perf_output_handle *handle = &ctxt->handle;
struct etm_event_data *event_data;
- struct list_head *path;
+ struct coresight_path *path;
/*
* If we still have access to the event_data via handle,
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h
index 744531158d6b..5febbcdb8696 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.h
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.h
@@ -59,7 +59,7 @@ struct etm_event_data {
cpumask_t aux_hwid_done;
void *snk_config;
u32 cfg_hash;
- struct list_head * __percpu *path;
+ struct coresight_path * __percpu *path;
};
int etm_perf_symlink(struct coresight_device *csdev, bool link);
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index e02c3ea972c9..171f1384f7c0 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -284,6 +284,5 @@ extern const struct attribute_group *coresight_etm_groups[];
void etm_set_default(struct etm_config *config);
void etm_config_trace_mode(struct etm_config *config);
struct etm_config *get_etm_config(struct etm_drvdata *drvdata);
-int etm_read_alloc_trace_id(struct etm_drvdata *drvdata);
void etm_release_trace_id(struct etm_drvdata *drvdata);
#endif
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index c103f4c70f5d..8927bfaf3af2 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -455,26 +455,6 @@ static int etm_cpu_id(struct coresight_device *csdev)
return drvdata->cpu;
}
-int etm_read_alloc_trace_id(struct etm_drvdata *drvdata)
-{
- int trace_id;
-
- /*
- * This will allocate a trace ID to the cpu,
- * or return the one currently allocated.
- *
- * trace id function has its own lock
- */
- trace_id = coresight_trace_id_get_cpu_id(drvdata->cpu);
- if (IS_VALID_CS_TRACE_ID(trace_id))
- drvdata->traceid = (u8)trace_id;
- else
- dev_err(&drvdata->csdev->dev,
- "Failed to allocate trace ID for %s on CPU%d\n",
- dev_name(&drvdata->csdev->dev), drvdata->cpu);
- return trace_id;
-}
-
void etm_release_trace_id(struct etm_drvdata *drvdata)
{
coresight_trace_id_put_cpu_id(drvdata->cpu);
@@ -482,38 +462,22 @@ void etm_release_trace_id(struct etm_drvdata *drvdata)
static int etm_enable_perf(struct coresight_device *csdev,
struct perf_event *event,
- struct coresight_trace_id_map *id_map)
+ struct coresight_path *path)
{
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- int trace_id;
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
return -EINVAL;
/* Configure the tracer based on the session's specifics */
etm_parse_event_config(drvdata, event);
-
- /*
- * perf allocates cpu ids as part of _setup_aux() - device needs to use
- * the allocated ID. This reads the current version without allocation.
- *
- * This does not use the trace id lock to prevent lock_dep issues
- * with perf locks - we know the ID cannot change until perf shuts down
- * the session
- */
- trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu, id_map);
- if (!IS_VALID_CS_TRACE_ID(trace_id)) {
- dev_err(&drvdata->csdev->dev, "Failed to set trace ID for %s on CPU%d\n",
- dev_name(&drvdata->csdev->dev), drvdata->cpu);
- return -EINVAL;
- }
- drvdata->traceid = (u8)trace_id;
+ drvdata->traceid = path->trace_id;
/* And enable it */
return etm_enable_hw(drvdata);
}
-static int etm_enable_sysfs(struct coresight_device *csdev)
+static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_path *path)
{
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct etm_enable_arg arg = { };
@@ -521,10 +485,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
spin_lock(&drvdata->spinlock);
- /* sysfs needs to allocate and set a trace ID */
- ret = etm_read_alloc_trace_id(drvdata);
- if (ret < 0)
- goto unlock_enable_sysfs;
+ drvdata->traceid = path->trace_id;
/*
* Configure the ETM only if the CPU is online. If it isn't online
@@ -545,7 +506,6 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
if (ret)
etm_release_trace_id(drvdata);
-unlock_enable_sysfs:
spin_unlock(&drvdata->spinlock);
if (!ret)
@@ -554,7 +514,7 @@ unlock_enable_sysfs:
}
static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
- enum cs_mode mode, struct coresight_trace_id_map *id_map)
+ enum cs_mode mode, struct coresight_path *path)
{
int ret;
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -566,10 +526,10 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
switch (mode) {
case CS_MODE_SYSFS:
- ret = etm_enable_sysfs(csdev);
+ ret = etm_enable_sysfs(csdev, path);
break;
case CS_MODE_PERF:
- ret = etm_enable_perf(csdev, event, id_map);
+ ret = etm_enable_perf(csdev, event, path);
break;
default:
ret = -EINVAL;
@@ -704,6 +664,7 @@ static const struct coresight_ops_source etm_source_ops = {
};
static const struct coresight_ops etm_cs_ops = {
+ .trace_id = coresight_etm_get_trace_id,
.source_ops = &etm_source_ops,
};
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 68c644be9813..b9006451f515 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -1190,10 +1190,9 @@ static DEVICE_ATTR_RO(cpu);
static ssize_t traceid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int trace_id;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ int trace_id = coresight_etm_get_trace_id(drvdata->csdev, CS_MODE_SYSFS, NULL);
- trace_id = etm_read_alloc_trace_id(drvdata);
if (trace_id < 0)
return trace_id;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 2c1a60577728..2b8f10463840 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -24,7 +24,6 @@
#include <linux/cpu_pm.h>
#include <linux/coresight.h>
#include <linux/coresight-pmu.h>
-#include <linux/pm_wakeup.h>
#include <linux/amba/bus.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
@@ -233,25 +232,6 @@ static int etm4_cpu_id(struct coresight_device *csdev)
return drvdata->cpu;
}
-int etm4_read_alloc_trace_id(struct etmv4_drvdata *drvdata)
-{
- int trace_id;
-
- /*
- * This will allocate a trace ID to the cpu,
- * or return the one currently allocated.
- * The trace id function has its own lock
- */
- trace_id = coresight_trace_id_get_cpu_id(drvdata->cpu);
- if (IS_VALID_CS_TRACE_ID(trace_id))
- drvdata->trcid = (u8)trace_id;
- else
- dev_err(&drvdata->csdev->dev,
- "Failed to allocate trace ID for %s on CPU%d\n",
- dev_name(&drvdata->csdev->dev), drvdata->cpu);
- return trace_id;
-}
-
void etm4_release_trace_id(struct etmv4_drvdata *drvdata)
{
coresight_trace_id_put_cpu_id(drvdata->cpu);
@@ -428,6 +408,29 @@ static void etm4_check_arch_features(struct etmv4_drvdata *drvdata,
}
#endif /* CONFIG_ETM4X_IMPDEF_FEATURE */
+static void etm4x_sys_ins_barrier(struct csdev_access *csa, u32 offset, int pos, int val)
+{
+ if (!csa->io_mem)
+ isb();
+}
+
+/*
+ * etm4x_wait_status: Poll for TRCSTATR.<pos> == <val>. While using system
+ * instruction to access the trace unit, each access must be separated by a
+ * synchronization barrier. See ARM IHI0064H.b section "4.3.7 Synchronization of
+ * register updates", for system instructions section, in "Notes":
+ *
+ * "In particular, whenever disabling or enabling the trace unit, a poll of
+ * TRCSTATR needs explicit synchronization between each read of TRCSTATR"
+ */
+static int etm4x_wait_status(struct csdev_access *csa, int pos, int val)
+{
+ if (!csa->io_mem)
+ return coresight_timeout_action(csa, TRCSTATR, pos, val,
+ etm4x_sys_ins_barrier);
+ return coresight_timeout(csa, TRCSTATR, pos, val);
+}
+
static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
{
int i, rc;
@@ -459,7 +462,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
isb();
/* wait for TRCSTATR.IDLE to go up */
- if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 1))
+ if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1))
dev_err(etm_dev,
"timeout while waiting for Idle Trace Status\n");
if (drvdata->nr_pe)
@@ -552,7 +555,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
isb();
/* wait for TRCSTATR.IDLE to go back down to '0' */
- if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 0))
+ if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 0))
dev_err(etm_dev,
"timeout while waiting for Idle Trace Status\n");
@@ -788,9 +791,9 @@ out:
static int etm4_enable_perf(struct coresight_device *csdev,
struct perf_event *event,
- struct coresight_trace_id_map *id_map)
+ struct coresight_path *path)
{
- int ret = 0, trace_id;
+ int ret = 0;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) {
@@ -803,22 +806,7 @@ static int etm4_enable_perf(struct coresight_device *csdev,
if (ret)
goto out;
- /*
- * perf allocates cpu ids as part of _setup_aux() - device needs to use
- * the allocated ID. This reads the current version without allocation.
- *
- * This does not use the trace id lock to prevent lock_dep issues
- * with perf locks - we know the ID cannot change until perf shuts down
- * the session
- */
- trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu, id_map);
- if (!IS_VALID_CS_TRACE_ID(trace_id)) {
- dev_err(&drvdata->csdev->dev, "Failed to set trace ID for %s on CPU%d\n",
- dev_name(&drvdata->csdev->dev), drvdata->cpu);
- ret = -EINVAL;
- goto out;
- }
- drvdata->trcid = (u8)trace_id;
+ drvdata->trcid = path->trace_id;
/* And enable it */
ret = etm4_enable_hw(drvdata);
@@ -827,7 +815,7 @@ out:
return ret;
}
-static int etm4_enable_sysfs(struct coresight_device *csdev)
+static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_path *path)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct etm4_enable_arg arg = { };
@@ -842,12 +830,9 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
return ret;
}
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
- /* sysfs needs to read and allocate a trace ID */
- ret = etm4_read_alloc_trace_id(drvdata);
- if (ret < 0)
- goto unlock_sysfs_enable;
+ drvdata->trcid = path->trace_id;
/*
* Executing etm4_enable_hw on the cpu whose ETM is being enabled
@@ -864,8 +849,7 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
if (ret)
etm4_release_trace_id(drvdata);
-unlock_sysfs_enable:
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
if (!ret)
dev_dbg(&csdev->dev, "ETM tracing enabled\n");
@@ -873,7 +857,7 @@ unlock_sysfs_enable:
}
static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
- enum cs_mode mode, struct coresight_trace_id_map *id_map)
+ enum cs_mode mode, struct coresight_path *path)
{
int ret;
@@ -884,10 +868,10 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
switch (mode) {
case CS_MODE_SYSFS:
- ret = etm4_enable_sysfs(csdev);
+ ret = etm4_enable_sysfs(csdev, path);
break;
case CS_MODE_PERF:
- ret = etm4_enable_perf(csdev, event, id_map);
+ ret = etm4_enable_perf(csdev, event, path);
break;
default:
ret = -EINVAL;
@@ -941,10 +925,25 @@ static void etm4_disable_hw(void *info)
tsb_csync();
etm4x_relaxed_write32(csa, control, TRCPRGCTLR);
+ /*
+ * As recommended by section 4.3.7 ("Synchronization when using system
+ * instructions to progrom the trace unit") of ARM IHI 0064H.b, the
+ * self-hosted trace analyzer must perform a Context synchronization
+ * event between writing to the TRCPRGCTLR and reading the TRCSTATR.
+ */
+ if (!csa->io_mem)
+ isb();
+
/* wait for TRCSTATR.PMSTABLE to go to '1' */
- if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1))
+ if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1))
dev_err(etm_dev,
"timeout while waiting for PM stable Trace Status\n");
+ /*
+ * As recommended by section 4.3.7 (Synchronization of register updates)
+ * of ARM IHI 0064H.b.
+ */
+ isb();
+
/* read the status of the single shot comparators */
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
config->ss_status[i] =
@@ -1012,7 +1011,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
* DYING hotplug callback is serviced by the ETM driver.
*/
cpus_read_lock();
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/*
* Executing etm4_disable_hw on the cpu whose ETM is being disabled
@@ -1020,7 +1019,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
*/
smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
/*
@@ -1067,6 +1066,7 @@ static const struct coresight_ops_source etm4_source_ops = {
};
static const struct coresight_ops etm4_cs_ops = {
+ .trace_id = coresight_etm_get_trace_id,
.source_ops = &etm4_source_ops,
};
@@ -1216,7 +1216,7 @@ static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
* recorded value for 'drvdata->ccitmin' to workaround
* this problem.
*/
- if (is_midr_in_range_list(read_cpuid_id(), etm_wrong_ccitmin_cpus)) {
+ if (is_midr_in_range_list(etm_wrong_ccitmin_cpus)) {
if (drvdata->ccitmin == 256)
drvdata->ccitmin = 4;
}
@@ -1698,13 +1698,13 @@ static int etm4_starting_cpu(unsigned int cpu)
if (!etmdrvdata[cpu])
return 0;
- spin_lock(&etmdrvdata[cpu]->spinlock);
+ raw_spin_lock(&etmdrvdata[cpu]->spinlock);
if (!etmdrvdata[cpu]->os_unlock)
etm4_os_unlock(etmdrvdata[cpu]);
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm4_enable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
+ raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
@@ -1713,10 +1713,10 @@ static int etm4_dying_cpu(unsigned int cpu)
if (!etmdrvdata[cpu])
return 0;
- spin_lock(&etmdrvdata[cpu]->spinlock);
+ raw_spin_lock(&etmdrvdata[cpu]->spinlock);
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm4_disable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
+ raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
@@ -1746,7 +1746,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
etm4_os_lock(drvdata);
/* wait for TRCSTATR.PMSTABLE to go up */
- if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1)) {
+ if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1)) {
dev_err(etm_dev,
"timeout while waiting for PM Stable Status\n");
etm4_os_unlock(drvdata);
@@ -1837,7 +1837,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
state->trcpdcr = etm4x_read32(csa, TRCPDCR);
/* wait for TRCSTATR.IDLE to go up */
- if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) {
+ if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1)) {
dev_err(etm_dev,
"timeout while waiting for Idle Trace Status\n");
etm4_os_unlock(drvdata);
@@ -2160,7 +2160,7 @@ static int etm4_probe(struct device *dev)
return -ENOMEM;
}
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
drvdata->cpu = coresight_get_cpu(dev);
if (drvdata->cpu < 0)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index c767f8ae4cf1..fdd0956fecb3 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -4,6 +4,7 @@
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*/
+#include <linux/coresight.h>
#include <linux/pid_namespace.h>
#include <linux/pm_runtime.h>
#include <linux/sysfs.h>
@@ -174,7 +175,7 @@ static ssize_t reset_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
if (val)
config->mode = 0x0;
@@ -266,7 +267,7 @@ static ssize_t reset_store(struct device *dev,
config->vmid_mask0 = 0x0;
config->vmid_mask1 = 0x0;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
/* for sysfs - only release trace id when resetting */
etm4_release_trace_id(drvdata);
@@ -300,7 +301,7 @@ static ssize_t mode_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->mode = val & ETMv4_MODE_ALL;
if (drvdata->instrp0 == true) {
@@ -437,7 +438,7 @@ static ssize_t mode_store(struct device *dev,
if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
etm4_config_trace_mode(config);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -466,14 +467,14 @@ static ssize_t pe_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
if (val > drvdata->nr_pe) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
config->pe_sel = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(pe);
@@ -501,7 +502,7 @@ static ssize_t event_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
switch (drvdata->nr_event) {
case 0x0:
/* EVENT0, bits[7:0] */
@@ -522,7 +523,7 @@ static ssize_t event_store(struct device *dev,
default:
break;
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(event);
@@ -550,7 +551,7 @@ static ssize_t event_instren_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* start by clearing all instruction event enable bits */
config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
switch (drvdata->nr_event) {
@@ -578,7 +579,7 @@ static ssize_t event_instren_store(struct device *dev,
default:
break;
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(event_instren);
@@ -739,11 +740,11 @@ static ssize_t event_vinst_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val &= TRCVICTLR_EVENT_MASK >> __bf_shf(TRCVICTLR_EVENT_MASK);
config->vinst_ctrl &= ~TRCVICTLR_EVENT_MASK;
config->vinst_ctrl |= FIELD_PREP(TRCVICTLR_EVENT_MASK, val);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(event_vinst);
@@ -771,13 +772,13 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* clear all EXLEVEL_S bits */
config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_S_MASK;
/* enable instruction tracing for corresponding exception level */
val &= drvdata->s_ex_level;
config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_S_MASK);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(s_exlevel_vinst);
@@ -806,13 +807,13 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/* clear EXLEVEL_NS bits */
config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_NS_MASK;
/* enable instruction tracing for corresponding exception level */
val &= drvdata->ns_ex_level;
config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_NS_MASK);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(ns_exlevel_vinst);
@@ -846,9 +847,9 @@ static ssize_t addr_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->addr_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_idx);
@@ -862,7 +863,7 @@ static ssize_t addr_instdatatype_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
val = FIELD_GET(TRCACATRn_TYPE_MASK, config->addr_acc[idx]);
len = scnprintf(buf, PAGE_SIZE, "%s\n",
@@ -870,7 +871,7 @@ static ssize_t addr_instdatatype_show(struct device *dev,
(val == TRCACATRn_TYPE_DATA_LOAD_ADDR ? "data_load" :
(val == TRCACATRn_TYPE_DATA_STORE_ADDR ? "data_store" :
"data_load_store")));
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return len;
}
@@ -888,13 +889,13 @@ static ssize_t addr_instdatatype_store(struct device *dev,
if (sscanf(buf, "%s", str) != 1)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!strcmp(str, "instr"))
/* TYPE, bits[1:0] */
config->addr_acc[idx] &= ~TRCACATRn_TYPE_MASK;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_instdatatype);
@@ -909,14 +910,14 @@ static ssize_t addr_single_show(struct device *dev,
struct etmv4_config *config = &drvdata->config;
idx = config->addr_idx;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val = (unsigned long)config->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -932,17 +933,17 @@ static ssize_t addr_single_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
config->addr_val[idx] = (u64)val;
config->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_single);
@@ -956,23 +957,23 @@ static ssize_t addr_range_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (idx % 2 != 0) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
(config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val1 = (unsigned long)config->addr_val[idx];
val2 = (unsigned long)config->addr_val[idx + 1];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
}
@@ -995,10 +996,10 @@ static ssize_t addr_range_store(struct device *dev,
if (val1 > val2)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (idx % 2 != 0) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
@@ -1006,7 +1007,7 @@ static ssize_t addr_range_store(struct device *dev,
config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
(config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
@@ -1023,7 +1024,7 @@ static ssize_t addr_range_store(struct device *dev,
exclude = config->mode & ETM_MODE_EXCLUDE;
etm4_set_mode_exclude(drvdata, exclude ? true : false);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_range);
@@ -1037,17 +1038,17 @@ static ssize_t addr_start_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val = (unsigned long)config->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1063,22 +1064,22 @@ static ssize_t addr_start_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!drvdata->nr_addr_cmp) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
config->addr_val[idx] = (u64)val;
config->addr_type[idx] = ETM_ADDR_TYPE_START;
config->vissctlr |= BIT(idx);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_start);
@@ -1092,17 +1093,17 @@ static ssize_t addr_stop_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val = (unsigned long)config->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1118,22 +1119,22 @@ static ssize_t addr_stop_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!drvdata->nr_addr_cmp) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
config->addr_val[idx] = (u64)val;
config->addr_type[idx] = ETM_ADDR_TYPE_STOP;
config->vissctlr |= BIT(idx + 16);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_stop);
@@ -1147,14 +1148,14 @@ static ssize_t addr_ctxtype_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
/* CONTEXTTYPE, bits[3:2] */
val = FIELD_GET(TRCACATRn_CONTEXTTYPE_MASK, config->addr_acc[idx]);
len = scnprintf(buf, PAGE_SIZE, "%s\n", val == ETM_CTX_NONE ? "none" :
(val == ETM_CTX_CTXID ? "ctxid" :
(val == ETM_CTX_VMID ? "vmid" : "all")));
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return len;
}
@@ -1172,7 +1173,7 @@ static ssize_t addr_ctxtype_store(struct device *dev,
if (sscanf(buf, "%s", str) != 1)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!strcmp(str, "none"))
/* start by clearing context type bits */
@@ -1199,7 +1200,7 @@ static ssize_t addr_ctxtype_store(struct device *dev,
if (drvdata->numvmidc)
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_ctxtype);
@@ -1213,11 +1214,11 @@ static ssize_t addr_context_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
/* context ID comparator bits[6:4] */
val = FIELD_GET(TRCACATRn_CONTEXT_MASK, config->addr_acc[idx]);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1238,12 +1239,12 @@ static ssize_t addr_context_store(struct device *dev,
drvdata->numcidc : drvdata->numvmidc))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
/* clear context ID comparator bits[6:4] */
config->addr_acc[idx] &= ~TRCACATRn_CONTEXT_MASK;
config->addr_acc[idx] |= val << __bf_shf(TRCACATRn_CONTEXT_MASK);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_context);
@@ -1257,10 +1258,10 @@ static ssize_t addr_exlevel_s_ns_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
val = FIELD_GET(TRCACATRn_EXLEVEL_MASK, config->addr_acc[idx]);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1279,12 +1280,12 @@ static ssize_t addr_exlevel_s_ns_store(struct device *dev,
if (val & ~(TRCACATRn_EXLEVEL_MASK >> __bf_shf(TRCACATRn_EXLEVEL_MASK)))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
/* clear Exlevel_ns & Exlevel_s bits[14:12, 11:8], bit[15] is res0 */
config->addr_acc[idx] &= ~TRCACATRn_EXLEVEL_MASK;
config->addr_acc[idx] |= val << __bf_shf(TRCACATRn_EXLEVEL_MASK);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(addr_exlevel_s_ns);
@@ -1307,7 +1308,7 @@ static ssize_t addr_cmp_view_show(struct device *dev,
int size = 0;
bool exclude = false;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
addr_v = config->addr_val[idx];
addr_ctrl = config->addr_acc[idx];
@@ -1322,7 +1323,7 @@ static ssize_t addr_cmp_view_show(struct device *dev,
}
exclude = config->viiectlr & BIT(idx / 2 + 16);
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
if (addr_type) {
size = scnprintf(buf, PAGE_SIZE, "addr_cmp[%i] %s %#lx", idx,
addr_type_names[addr_type], addr_v);
@@ -1366,9 +1367,9 @@ static ssize_t vinst_pe_cmp_start_stop_store(struct device *dev,
if (!drvdata->nr_pe_cmp)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->vipcssctlr = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(vinst_pe_cmp_start_stop);
@@ -1402,9 +1403,9 @@ static ssize_t seq_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->seq_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(seq_idx);
@@ -1448,10 +1449,10 @@ static ssize_t seq_event_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->seq_idx;
val = config->seq_ctrl[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1467,11 +1468,11 @@ static ssize_t seq_event_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->seq_idx;
/* Seq control has two masks B[15:8] F[7:0] */
config->seq_ctrl[idx] = val & 0xFFFF;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(seq_event);
@@ -1535,9 +1536,9 @@ static ssize_t cntr_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->cntr_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(cntr_idx);
@@ -1551,10 +1552,10 @@ static ssize_t cntrldvr_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->cntr_idx;
val = config->cntrldvr[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1572,10 +1573,10 @@ static ssize_t cntrldvr_store(struct device *dev,
if (val > ETM_CNTR_MAX_VAL)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->cntr_idx;
config->cntrldvr[idx] = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(cntrldvr);
@@ -1589,10 +1590,10 @@ static ssize_t cntr_val_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->cntr_idx;
val = config->cntr_val[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1610,10 +1611,10 @@ static ssize_t cntr_val_store(struct device *dev,
if (val > ETM_CNTR_MAX_VAL)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->cntr_idx;
config->cntr_val[idx] = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(cntr_val);
@@ -1627,10 +1628,10 @@ static ssize_t cntr_ctrl_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->cntr_idx;
val = config->cntr_ctrl[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1646,10 +1647,10 @@ static ssize_t cntr_ctrl_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->cntr_idx;
config->cntr_ctrl[idx] = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(cntr_ctrl);
@@ -1687,9 +1688,9 @@ static ssize_t res_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->res_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(res_idx);
@@ -1703,10 +1704,10 @@ static ssize_t res_ctrl_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->res_idx;
val = config->res_ctrl[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1722,7 +1723,7 @@ static ssize_t res_ctrl_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->res_idx;
/* For odd idx pair inversal bit is RES0 */
if (idx % 2 != 0)
@@ -1732,7 +1733,7 @@ static ssize_t res_ctrl_store(struct device *dev,
TRCRSCTLRn_INV |
TRCRSCTLRn_GROUP_MASK |
TRCRSCTLRn_SELECT_MASK);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(res_ctrl);
@@ -1761,9 +1762,9 @@ static ssize_t sshot_idx_store(struct device *dev,
if (val >= drvdata->nr_ss_cmp)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->ss_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(sshot_idx);
@@ -1776,9 +1777,9 @@ static ssize_t sshot_ctrl_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = config->ss_ctrl[config->ss_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1794,12 +1795,12 @@ static ssize_t sshot_ctrl_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->ss_idx;
config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
/* must clear bit 31 in related status register on programming */
config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(sshot_ctrl);
@@ -1811,9 +1812,9 @@ static ssize_t sshot_status_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = config->ss_status[config->ss_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(sshot_status);
@@ -1826,9 +1827,9 @@ static ssize_t sshot_pe_ctrl_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = config->ss_pe_cmp[config->ss_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1844,12 +1845,12 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->ss_idx;
config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
/* must clear bit 31 in related status register on programming */
config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(sshot_pe_ctrl);
@@ -1883,9 +1884,9 @@ static ssize_t ctxid_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->ctxid_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(ctxid_idx);
@@ -1906,10 +1907,10 @@ static ssize_t ctxid_pid_show(struct device *dev,
if (task_active_pid_ns(current) != &init_pid_ns)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->ctxid_idx;
val = (unsigned long)config->ctxid_pid[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1944,10 +1945,10 @@ static ssize_t ctxid_pid_store(struct device *dev,
if (kstrtoul(buf, 16, &pid))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->ctxid_idx;
config->ctxid_pid[idx] = (u64)pid;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(ctxid_pid);
@@ -1967,10 +1968,10 @@ static ssize_t ctxid_masks_show(struct device *dev,
if (task_active_pid_ns(current) != &init_pid_ns)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val1 = config->ctxid_mask0;
val2 = config->ctxid_mask1;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
}
@@ -2003,7 +2004,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
if ((drvdata->numcidc > 4) && (nr_inputs != 2))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/*
* each byte[0..3] controls mask value applied to ctxid
* comparator[0..3]
@@ -2075,7 +2076,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
mask >>= 0x8;
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(ctxid_masks);
@@ -2109,9 +2110,9 @@ static ssize_t vmid_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->vmid_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(vmid_idx);
@@ -2131,9 +2132,9 @@ static ssize_t vmid_val_show(struct device *dev,
if (!task_is_in_init_pid_ns(current))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = (unsigned long)config->vmid_val[config->vmid_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -2161,9 +2162,9 @@ static ssize_t vmid_val_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->vmid_val[config->vmid_idx] = (u64)val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(vmid_val);
@@ -2182,10 +2183,10 @@ static ssize_t vmid_masks_show(struct device *dev,
if (!task_is_in_init_pid_ns(current))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val1 = config->vmid_mask0;
val2 = config->vmid_mask1;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
}
@@ -2217,7 +2218,7 @@ static ssize_t vmid_masks_store(struct device *dev,
if ((drvdata->numvmidc > 4) && (nr_inputs != 2))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/*
* each byte[0..3] controls mask value applied to vmid
@@ -2290,7 +2291,7 @@ static ssize_t vmid_masks_store(struct device *dev,
else
mask >>= 0x8;
}
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(vmid_masks);
@@ -2402,10 +2403,9 @@ static ssize_t trctraceid_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int trace_id;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ int trace_id = coresight_etm_get_trace_id(drvdata->csdev, CS_MODE_SYSFS, NULL);
- trace_id = etm4_read_alloc_trace_id(drvdata);
if (trace_id < 0)
return trace_id;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 1119762b5cec..bd7db36ba197 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -989,7 +989,7 @@ struct etmv4_drvdata {
struct clk *pclk;
void __iomem *base;
struct coresight_device *csdev;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
int cpu;
u8 arch;
u8 nr_pe;
@@ -1066,6 +1066,5 @@ static inline bool etm4x_is_ete(struct etmv4_drvdata *drvdata)
return drvdata->arch >= ETM_ARCH_ETE;
}
-int etm4_read_alloc_trace_id(struct etmv4_drvdata *drvdata);
void etm4_release_trace_id(struct etmv4_drvdata *drvdata);
#endif
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 8faf51469bb8..0541712b2bcb 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -47,7 +47,7 @@ struct funnel_drvdata {
struct clk *pclk;
struct coresight_device *csdev;
unsigned long priority;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
};
static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
@@ -85,7 +85,7 @@ static int funnel_enable(struct coresight_device *csdev,
unsigned long flags;
bool first_enable = false;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (in->dest_refcnt == 0) {
if (drvdata->base)
rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
@@ -94,7 +94,7 @@ static int funnel_enable(struct coresight_device *csdev,
}
if (!rc)
in->dest_refcnt++;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (first_enable)
dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n",
@@ -129,13 +129,13 @@ static void funnel_disable(struct coresight_device *csdev,
unsigned long flags;
bool last_disable = false;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (--in->dest_refcnt == 0) {
if (drvdata->base)
dynamic_funnel_disable_hw(drvdata, in->dest_port);
last_disable = true;
}
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (last_disable)
dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n",
@@ -266,7 +266,7 @@ static int funnel_probe(struct device *dev, struct resource *res)
}
dev->platform_data = pdata;
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
desc.type = CORESIGHT_DEV_TYPE_LINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
desc.ops = &funnel_cs_ops;
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 76403530f33e..82644aff8d2b 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -132,16 +132,16 @@ static inline void CS_UNLOCK(void __iomem *addr)
} while (0);
}
-void coresight_disable_path(struct list_head *path);
-int coresight_enable_path(struct list_head *path, enum cs_mode mode,
+void coresight_disable_path(struct coresight_path *path);
+int coresight_enable_path(struct coresight_path *path, enum cs_mode mode,
void *sink_data);
-struct coresight_device *coresight_get_sink(struct list_head *path);
+struct coresight_device *coresight_get_sink(struct coresight_path *path);
struct coresight_device *coresight_get_sink_by_id(u32 id);
struct coresight_device *
coresight_find_default_sink(struct coresight_device *csdev);
-struct list_head *coresight_build_path(struct coresight_device *csdev,
- struct coresight_device *sink);
-void coresight_release_path(struct list_head *path);
+struct coresight_path *coresight_build_path(struct coresight_device *csdev,
+ struct coresight_device *sink);
+void coresight_release_path(struct coresight_path *path);
int coresight_add_sysfs_link(struct coresight_sysfs_link *info);
void coresight_remove_sysfs_link(struct coresight_sysfs_link *info);
int coresight_create_conns_sysfs_group(struct coresight_device *csdev);
@@ -152,6 +152,8 @@ int coresight_make_links(struct coresight_device *orig,
void coresight_remove_links(struct coresight_device *orig,
struct coresight_connection *conn);
u32 coresight_get_sink_id(struct coresight_device *csdev);
+void coresight_path_assign_trace_id(struct coresight_path *path,
+ enum cs_mode mode);
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
extern int etm_readl_cp14(u32 off, unsigned int *val);
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index a1181c9048c0..ee7ee79f6cf7 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -41,7 +41,7 @@ struct replicator_drvdata {
struct clk *atclk;
struct clk *pclk;
struct coresight_device *csdev;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
bool check_idfilter_val;
};
@@ -125,7 +125,7 @@ static int replicator_enable(struct coresight_device *csdev,
unsigned long flags;
bool first_enable = false;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (out->src_refcnt == 0) {
if (drvdata->base)
rc = dynamic_replicator_enable(drvdata, in->dest_port,
@@ -135,7 +135,7 @@ static int replicator_enable(struct coresight_device *csdev,
}
if (!rc)
out->src_refcnt++;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (first_enable)
dev_dbg(&csdev->dev, "REPLICATOR enabled\n");
@@ -179,14 +179,14 @@ static void replicator_disable(struct coresight_device *csdev,
unsigned long flags;
bool last_disable = false;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (--out->src_refcnt == 0) {
if (drvdata->base)
dynamic_replicator_disable(drvdata, in->dest_port,
out->src_port);
last_disable = true;
}
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (last_disable)
dev_dbg(&csdev->dev, "REPLICATOR disabled\n");
@@ -277,7 +277,7 @@ static int replicator_probe(struct device *dev, struct resource *res)
}
dev->platform_data = pdata;
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
desc.type = CORESIGHT_DEV_TYPE_LINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc.ops = &replicator_cs_ops;
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index b581a30a1cd9..26f9339f38b9 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -195,7 +195,7 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
static int stm_enable(struct coresight_device *csdev, struct perf_event *event,
enum cs_mode mode,
- __maybe_unused struct coresight_trace_id_map *trace_id)
+ __maybe_unused struct coresight_path *path)
{
struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -281,12 +281,23 @@ static void stm_disable(struct coresight_device *csdev,
}
}
+static int stm_trace_id(struct coresight_device *csdev, __maybe_unused enum cs_mode mode,
+ __maybe_unused struct coresight_device *sink)
+{
+ struct stm_drvdata *drvdata;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ return drvdata->traceid;
+}
+
static const struct coresight_ops_source stm_source_ops = {
.enable = stm_enable,
.disable = stm_disable,
};
static const struct coresight_ops stm_cs_ops = {
+ .trace_id = stm_trace_id,
.source_ops = &stm_source_ops,
};
diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
index 433ede94dd63..213b4159b062 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
@@ -160,7 +160,7 @@ static struct configfs_attribute *cscfg_config_view_attrs[] = {
NULL,
};
-static struct config_item_type cscfg_config_view_type = {
+static const struct config_item_type cscfg_config_view_type = {
.ct_owner = THIS_MODULE,
.ct_attrs = cscfg_config_view_attrs,
};
@@ -170,7 +170,7 @@ static struct configfs_attribute *cscfg_config_preset_attrs[] = {
NULL,
};
-static struct config_item_type cscfg_config_preset_type = {
+static const struct config_item_type cscfg_config_preset_type = {
.ct_owner = THIS_MODULE,
.ct_attrs = cscfg_config_preset_attrs,
};
@@ -272,7 +272,7 @@ static struct configfs_attribute *cscfg_feature_view_attrs[] = {
NULL,
};
-static struct config_item_type cscfg_feature_view_type = {
+static const struct config_item_type cscfg_feature_view_type = {
.ct_owner = THIS_MODULE,
.ct_attrs = cscfg_feature_view_attrs,
};
@@ -309,7 +309,7 @@ static struct configfs_attribute *cscfg_param_view_attrs[] = {
NULL,
};
-static struct config_item_type cscfg_param_view_type = {
+static const struct config_item_type cscfg_param_view_type = {
.ct_owner = THIS_MODULE,
.ct_attrs = cscfg_param_view_attrs,
};
@@ -380,7 +380,7 @@ static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc
return &feat_view->group;
}
-static struct config_item_type cscfg_configs_type = {
+static const struct config_item_type cscfg_configs_type = {
.ct_owner = THIS_MODULE,
};
@@ -414,7 +414,7 @@ void cscfg_configfs_del_config(struct cscfg_config_desc *config_desc)
}
}
-static struct config_item_type cscfg_features_type = {
+static const struct config_item_type cscfg_features_type = {
.ct_owner = THIS_MODULE,
};
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
index 11138a9762b0..a70c1454b410 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg.c
@@ -89,9 +89,9 @@ static int cscfg_add_csdev_cfg(struct coresight_device *csdev,
}
/* if matched features, add config to device.*/
if (config_csdev) {
- spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_add(&config_csdev->node, &csdev->config_csdev_list);
- spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
return 0;
@@ -194,9 +194,9 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
/* add to internal csdev feature list & initialise using reset call */
cscfg_reset_feat(feat_csdev);
- spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_add(&feat_csdev->node, &csdev->feature_csdev_list);
- spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
return 0;
}
@@ -765,7 +765,7 @@ static int cscfg_list_add_csdev(struct coresight_device *csdev,
INIT_LIST_HEAD(&csdev->feature_csdev_list);
INIT_LIST_HEAD(&csdev->config_csdev_list);
- spin_lock_init(&csdev->cscfg_csdev_lock);
+ raw_spin_lock_init(&csdev->cscfg_csdev_lock);
return 0;
}
@@ -855,7 +855,7 @@ void cscfg_csdev_reset_feats(struct coresight_device *csdev)
struct cscfg_feature_csdev *feat_csdev;
unsigned long flags;
- spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
if (list_empty(&csdev->feature_csdev_list))
goto unlock_exit;
@@ -863,7 +863,7 @@ void cscfg_csdev_reset_feats(struct coresight_device *csdev)
cscfg_reset_feat(feat_csdev);
unlock_exit:
- spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
@@ -1059,7 +1059,7 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
* Look for matching configuration - set the active configuration
* context if found.
*/
- spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
config_desc = config_csdev_item->config_desc;
if ((atomic_read(&config_desc->active_cnt)) &&
@@ -1069,7 +1069,7 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
break;
}
}
- spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
/*
* If found, attempt to enable
@@ -1090,12 +1090,12 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
*
* Set enabled if OK, err if not.
*/
- spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
if (csdev->active_cscfg_ctxt)
config_csdev_active->enabled = true;
else
err = -EBUSY;
- spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
}
return err;
@@ -1124,7 +1124,7 @@ void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
* If it was not enabled, we have no work to do, otherwise mark as disabled.
* Clear the active config pointer.
*/
- spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
if (config_csdev) {
if (!config_csdev->enabled)
@@ -1133,7 +1133,7 @@ void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
config_csdev->enabled = false;
}
csdev->active_cscfg_ctxt = NULL;
- spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
+ raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
/* true if there was an enabled active config */
if (config_csdev)
diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index a01c9e54e2ed..feadaf065b53 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -22,7 +22,7 @@ static DEFINE_IDR(path_idr);
* When operating Coresight drivers from the sysFS interface, only a single
* path can exist from a tracer (associated to a CPU) to a sink.
*/
-static DEFINE_PER_CPU(struct list_head *, tracer_path);
+static DEFINE_PER_CPU(struct coresight_path *, tracer_path);
ssize_t coresight_simple_show_pair(struct device *_dev,
struct device_attribute *attr, char *buf)
@@ -53,7 +53,8 @@ ssize_t coresight_simple_show32(struct device *_dev,
EXPORT_SYMBOL_GPL(coresight_simple_show32);
static int coresight_enable_source_sysfs(struct coresight_device *csdev,
- enum cs_mode mode, void *data)
+ enum cs_mode mode,
+ struct coresight_path *path)
{
int ret;
@@ -64,7 +65,7 @@ static int coresight_enable_source_sysfs(struct coresight_device *csdev,
*/
lockdep_assert_held(&coresight_mutex);
if (coresight_get_mode(csdev) != CS_MODE_SYSFS) {
- ret = source_ops(csdev)->enable(csdev, data, mode, NULL);
+ ret = source_ops(csdev)->enable(csdev, NULL, mode, path);
if (ret)
return ret;
}
@@ -167,7 +168,7 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
{
int cpu, ret = 0;
struct coresight_device *sink;
- struct list_head *path;
+ struct coresight_path *path;
enum coresight_dev_subtype_source subtype;
u32 hash;
@@ -209,11 +210,15 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
goto out;
}
+ coresight_path_assign_trace_id(path, CS_MODE_SYSFS);
+ if (!IS_VALID_CS_TRACE_ID(path->trace_id))
+ goto err_path;
+
ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
if (ret)
goto err_path;
- ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, NULL);
+ ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, path);
if (ret)
goto err_source;
@@ -262,7 +267,7 @@ EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
void coresight_disable_sysfs(struct coresight_device *csdev)
{
int cpu, ret;
- struct list_head *path = NULL;
+ struct coresight_path *path = NULL;
u32 hash;
mutex_lock(&coresight_mutex);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index e9876252a789..a7814e8e657b 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/coresight.h>
#include <linux/amba/bus.h>
#include <linux/platform_device.h>
@@ -104,6 +105,128 @@ u32 tmc_get_memwidth_mask(struct tmc_drvdata *drvdata)
return mask;
}
+static bool is_tmc_crashdata_valid(struct tmc_drvdata *drvdata)
+{
+ struct tmc_crash_metadata *mdata;
+
+ if (!tmc_has_reserved_buffer(drvdata) ||
+ !tmc_has_crash_mdata_buffer(drvdata))
+ return false;
+
+ mdata = drvdata->crash_mdata.vaddr;
+
+ /* Check version match */
+ if (mdata->version != CS_CRASHDATA_VERSION)
+ return false;
+
+ /* Check for valid metadata */
+ if (!mdata->valid) {
+ dev_dbg(&drvdata->csdev->dev,
+ "Data invalid in tmc crash metadata\n");
+ return false;
+ }
+
+ /*
+ * Buffer address given by metadata for retrieval of trace data
+ * from previous boot is expected to be same as the reserved
+ * trace buffer memory region provided through DTS
+ */
+ if (drvdata->resrv_buf.paddr != mdata->trace_paddr) {
+ dev_dbg(&drvdata->csdev->dev,
+ "Trace buffer address of previous boot invalid\n");
+ return false;
+ }
+
+ /* Check data integrity of metadata */
+ if (mdata->crc32_mdata != find_crash_metadata_crc(mdata)) {
+ dev_err(&drvdata->csdev->dev,
+ "CRC mismatch in tmc crash metadata\n");
+ return false;
+ }
+ /* Check data integrity of tracedata */
+ if (mdata->crc32_tdata != find_crash_tracedata_crc(drvdata, mdata)) {
+ dev_err(&drvdata->csdev->dev,
+ "CRC mismatch in tmc crash tracedata\n");
+ return false;
+ }
+
+ return true;
+}
+
+static inline ssize_t tmc_get_resvbuf_trace(struct tmc_drvdata *drvdata,
+ loff_t pos, size_t len, char **bufpp)
+{
+ s64 offset;
+ ssize_t actual = len;
+ struct tmc_resrv_buf *rbuf = &drvdata->resrv_buf;
+
+ if (pos + actual > rbuf->len)
+ actual = rbuf->len - pos;
+ if (actual <= 0)
+ return 0;
+
+ /* Compute the offset from which we read the data */
+ offset = rbuf->offset + pos;
+ if (offset >= rbuf->size)
+ offset -= rbuf->size;
+
+ /* Adjust the length to limit this transaction to end of buffer */
+ actual = (actual < (rbuf->size - offset)) ?
+ actual : rbuf->size - offset;
+
+ *bufpp = (char *)rbuf->vaddr + offset;
+
+ return actual;
+}
+
+static int tmc_prepare_crashdata(struct tmc_drvdata *drvdata)
+{
+ char *bufp;
+ ssize_t len;
+ u32 status, size;
+ u64 rrp, rwp, dba;
+ struct tmc_resrv_buf *rbuf;
+ struct tmc_crash_metadata *mdata;
+
+ mdata = drvdata->crash_mdata.vaddr;
+ rbuf = &drvdata->resrv_buf;
+
+ rrp = mdata->tmc_rrp;
+ rwp = mdata->tmc_rwp;
+ dba = mdata->tmc_dba;
+ status = mdata->tmc_sts;
+ size = mdata->tmc_ram_size << 2;
+
+ /* Sync the buffer pointers */
+ rbuf->offset = rrp - dba;
+ if (status & TMC_STS_FULL)
+ rbuf->len = size;
+ else
+ rbuf->len = rwp - rrp;
+
+ /* Additional sanity checks for validating metadata */
+ if ((rbuf->offset > size) ||
+ (rbuf->len > size)) {
+ dev_dbg(&drvdata->csdev->dev,
+ "Offset and length invalid in tmc crash metadata\n");
+ return -EINVAL;
+ }
+
+ if (status & TMC_STS_FULL) {
+ len = tmc_get_resvbuf_trace(drvdata, 0x0,
+ CORESIGHT_BARRIER_PKT_SIZE, &bufp);
+ if (len >= CORESIGHT_BARRIER_PKT_SIZE) {
+ coresight_insert_barrier_packet(bufp);
+ /* Recalculate crc */
+ mdata->crc32_tdata = find_crash_tracedata_crc(drvdata,
+ mdata);
+ mdata->crc32_mdata = find_crash_metadata_crc(mdata);
+ }
+ }
+
+ return 0;
+}
+
static int tmc_read_prepare(struct tmc_drvdata *drvdata)
{
int ret = 0;
@@ -222,6 +345,84 @@ static const struct file_operations tmc_fops = {
.release = tmc_release,
};
+static int tmc_crashdata_open(struct inode *inode, struct file *file)
+{
+ int err = 0;
+ unsigned long flags;
+ struct tmc_resrv_buf *rbuf;
+ struct tmc_crash_metadata *mdata;
+ struct tmc_drvdata *drvdata = container_of(file->private_data,
+ struct tmc_drvdata,
+ crashdev);
+
+ mdata = drvdata->crash_mdata.vaddr;
+ rbuf = &drvdata->resrv_buf;
+
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ if (mdata->valid)
+ rbuf->reading = true;
+ else
+ err = -ENOENT;
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ if (err)
+ goto exit;
+
+ nonseekable_open(inode, file);
+ dev_dbg(&drvdata->csdev->dev, "%s: successfully opened\n", __func__);
+exit:
+ return err;
+}
+
+static ssize_t tmc_crashdata_read(struct file *file, char __user *data,
+ size_t len, loff_t *ppos)
+{
+ char *bufp;
+ ssize_t actual;
+ struct tmc_drvdata *drvdata = container_of(file->private_data,
+ struct tmc_drvdata,
+ crashdev);
+
+ actual = tmc_get_resvbuf_trace(drvdata, *ppos, len, &bufp);
+ if (actual <= 0)
+ return 0;
+
+ if (copy_to_user(data, bufp, actual)) {
+ dev_dbg(&drvdata->csdev->dev,
+ "%s: copy_to_user failed\n", __func__);
+ return -EFAULT;
+ }
+
+ *ppos += actual;
+ dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual);
+
+ return actual;
+}
+
+static int tmc_crashdata_release(struct inode *inode, struct file *file)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct tmc_resrv_buf *rbuf;
+ struct tmc_drvdata *drvdata = container_of(file->private_data,
+ struct tmc_drvdata,
+ crashdev);
+
+ rbuf = &drvdata->resrv_buf;
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ rbuf->reading = false;
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+ dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__);
+ return ret;
+}
+
+static const struct file_operations tmc_crashdata_fops = {
+ .owner = THIS_MODULE,
+ .open = tmc_crashdata_open,
+ .read = tmc_crashdata_read,
+ .release = tmc_crashdata_release,
+};
+
static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid)
{
enum tmc_mem_intf_width memwidth;
@@ -331,9 +532,40 @@ static ssize_t buffer_size_store(struct device *dev,
static DEVICE_ATTR_RW(buffer_size);
+static ssize_t stop_on_flush_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sprintf(buf, "%#x\n", drvdata->stop_on_flush);
+}
+
+static ssize_t stop_on_flush_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ u8 val;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ ret = kstrtou8(buf, 0, &val);
+ if (ret)
+ return ret;
+ if (val)
+ drvdata->stop_on_flush = true;
+ else
+ drvdata->stop_on_flush = false;
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(stop_on_flush);
+
+
static struct attribute *coresight_tmc_attrs[] = {
&dev_attr_trigger_cntr.attr,
&dev_attr_buffer_size.attr,
+ &dev_attr_stop_on_flush.attr,
NULL,
};
@@ -398,6 +630,67 @@ static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata)
static const struct amba_id tmc_ids[];
+static int of_tmc_get_reserved_resource_by_name(struct device *dev,
+ const char *name,
+ struct resource *res)
+{
+ int index, rc = -ENODEV;
+ struct device_node *node;
+
+ if (!is_of_node(dev->fwnode))
+ return -ENODEV;
+
+ index = of_property_match_string(dev->of_node, "memory-region-names",
+ name);
+ if (index < 0)
+ return rc;
+
+ node = of_parse_phandle(dev->of_node, "memory-region", index);
+ if (!node)
+ return rc;
+
+ if (!of_address_to_resource(node, 0, res) &&
+ res->start != 0 && resource_size(res) != 0)
+ rc = 0;
+ of_node_put(node);
+
+ return rc;
+}
+
+static void tmc_get_reserved_region(struct device *parent)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(parent);
+ struct resource res;
+
+ if (of_tmc_get_reserved_resource_by_name(parent, "tracedata", &res))
+ return;
+
+ drvdata->resrv_buf.vaddr = memremap(res.start,
+ resource_size(&res),
+ MEMREMAP_WC);
+ if (IS_ERR_OR_NULL(drvdata->resrv_buf.vaddr)) {
+ dev_err(parent, "Reserved trace buffer mapping failed\n");
+ return;
+ }
+
+ drvdata->resrv_buf.paddr = res.start;
+ drvdata->resrv_buf.size = resource_size(&res);
+
+ if (of_tmc_get_reserved_resource_by_name(parent, "metadata", &res))
+ return;
+
+ drvdata->crash_mdata.vaddr = memremap(res.start,
+ resource_size(&res),
+ MEMREMAP_WC);
+ if (IS_ERR_OR_NULL(drvdata->crash_mdata.vaddr)) {
+ dev_err(parent, "Metadata memory mapping failed\n");
+ return;
+ }
+
+ drvdata->crash_mdata.paddr = res.start;
+ drvdata->crash_mdata.size = resource_size(&res);
+}
+
/* Detect and initialise the capabilities of a TMC ETR */
static int tmc_etr_setup_caps(struct device *parent, u32 devid,
struct csdev_access *access)
@@ -470,6 +763,22 @@ static u32 tmc_etr_get_max_burst_size(struct device *dev)
return burst_size;
}
+static void register_crash_dev_interface(struct tmc_drvdata *drvdata,
+ const char *name)
+{
+ drvdata->crashdev.name =
+ devm_kasprintf(&drvdata->csdev->dev, GFP_KERNEL, "%s_%s", "crash", name);
+ drvdata->crashdev.minor = MISC_DYNAMIC_MINOR;
+ drvdata->crashdev.fops = &tmc_crashdata_fops;
+ if (misc_register(&drvdata->crashdev)) {
+ dev_dbg(&drvdata->csdev->dev,
+ "Failed to setup user interface for crashdata\n");
+ drvdata->crashdev.fops = NULL;
+ } else
+ dev_info(&drvdata->csdev->dev,
+ "Valid crash tracedata found\n");
+}
+
static int __tmc_probe(struct device *dev, struct resource *res)
{
int ret = 0;
@@ -492,7 +801,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
drvdata->base = base;
desc.access = CSDEV_ACCESS_IOMEM(base);
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
drvdata->config_type = BMVAL(devid, 6, 7);
@@ -508,6 +817,8 @@ static int __tmc_probe(struct device *dev, struct resource *res)
drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
}
+ tmc_get_reserved_region(dev);
+
desc.dev = dev;
switch (drvdata->config_type) {
@@ -568,9 +879,15 @@ static int __tmc_probe(struct device *dev, struct resource *res)
drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
drvdata->miscdev.fops = &tmc_fops;
ret = misc_register(&drvdata->miscdev);
- if (ret)
+ if (ret) {
coresight_unregister(drvdata->csdev);
+ goto out;
+ }
+
out:
+ if (is_tmc_crashdata_valid(drvdata) &&
+ !tmc_prepare_crashdata(drvdata))
+ register_crash_dev_interface(drvdata, desc.name);
return ret;
}
@@ -596,7 +913,7 @@ static void tmc_shutdown(struct amba_device *adev)
unsigned long flags;
struct tmc_drvdata *drvdata = amba_get_drvdata(adev);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED)
goto out;
@@ -610,7 +927,7 @@ static void tmc_shutdown(struct amba_device *adev)
* the system is going down after this.
*/
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
}
static void __tmc_remove(struct device *dev)
@@ -623,6 +940,8 @@ static void __tmc_remove(struct device *dev)
* handler to this device is closed.
*/
misc_deregister(&drvdata->miscdev);
+ if (drvdata->crashdev.fops)
+ misc_deregister(&drvdata->crashdev);
coresight_unregister(drvdata->csdev);
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index d4f641cd9de6..d858740001c2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -19,6 +19,7 @@ static int tmc_set_etf_buffer(struct coresight_device *csdev,
static int __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
{
int rc = 0;
+ u32 ffcr;
CS_UNLOCK(drvdata->base);
@@ -32,10 +33,12 @@ static int __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
}
writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
- writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
- TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
- TMC_FFCR_TRIGON_TRIGIN,
- drvdata->base + TMC_FFCR);
+
+ ffcr = TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | TMC_FFCR_FON_FLIN |
+ TMC_FFCR_FON_TRIG_EVT | TMC_FFCR_TRIGON_TRIGIN;
+ if (drvdata->stop_on_flush)
+ ffcr |= TMC_FFCR_STOP_ON_FLUSH;
+ writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
tmc_enable_hw(drvdata);
@@ -182,9 +185,9 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
* If we don't have a buffer release the lock and allocate memory.
* Otherwise keep the lock and move along.
*/
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (!drvdata->buf) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Allocating the memory here while outside of the spinlock */
buf = kzalloc(drvdata->size, GFP_KERNEL);
@@ -192,7 +195,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
return -ENOMEM;
/* Let's try again */
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
}
if (drvdata->reading) {
@@ -225,7 +228,6 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
used = true;
drvdata->buf = buf;
}
-
ret = tmc_etb_enable_hw(drvdata);
if (!ret) {
coresight_set_mode(csdev, CS_MODE_SYSFS);
@@ -235,7 +237,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
used = false;
}
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free memory outside the spinlock if need be */
if (!used)
@@ -253,7 +255,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
struct perf_output_handle *handle = data;
struct cs_buffers *buf = etm_perf_sink_config(handle);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
do {
ret = -EINVAL;
if (drvdata->reading)
@@ -296,7 +298,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
csdev->refcnt++;
}
} while (0);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
@@ -331,16 +333,16 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
csdev->refcnt--;
if (csdev->refcnt) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -351,7 +353,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
drvdata->pid = -1;
coresight_set_mode(csdev, CS_MODE_DISABLED);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n");
return 0;
@@ -366,9 +368,9 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
bool first_enable = false;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -381,7 +383,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
}
if (!ret)
csdev->refcnt++;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (first_enable)
dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
@@ -396,9 +398,9 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
bool last_disable = false;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return;
}
@@ -408,7 +410,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
coresight_set_mode(csdev, CS_MODE_DISABLED);
last_disable = true;
}
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (last_disable)
dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
@@ -488,7 +490,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF))
return 0;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */
if (csdev->refcnt != 1)
@@ -585,11 +587,86 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
*/
CS_LOCK(drvdata->base);
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return to_read;
}
+static int tmc_panic_sync_etf(struct coresight_device *csdev)
+{
+ u32 val;
+ struct tmc_crash_metadata *mdata;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ mdata = (struct tmc_crash_metadata *)drvdata->crash_mdata.vaddr;
+
+ /* Make sure we have valid reserved memory */
+ if (!tmc_has_reserved_buffer(drvdata) ||
+ !tmc_has_crash_mdata_buffer(drvdata))
+ return 0;
+
+ tmc_crashdata_set_invalid(drvdata);
+
+ CS_UNLOCK(drvdata->base);
+
+ /* Proceed only if ETF is enabled or configured as sink */
+ val = readl(drvdata->base + TMC_CTL);
+ if (!(val & TMC_CTL_CAPT_EN))
+ goto out;
+ val = readl(drvdata->base + TMC_MODE);
+ if (val != TMC_MODE_CIRCULAR_BUFFER)
+ goto out;
+
+ val = readl(drvdata->base + TMC_FFSR);
+ /* Do manual flush and stop only if its not auto-stopped */
+ if (!(val & TMC_FFSR_FT_STOPPED)) {
+ dev_dbg(&csdev->dev,
+ "%s: Triggering manual flush\n", __func__);
+ tmc_flush_and_stop(drvdata);
+ } else
+ tmc_wait_for_tmcready(drvdata);
+
+ /* Sync registers from hardware to metadata region */
+ mdata->tmc_sts = readl(drvdata->base + TMC_STS);
+ mdata->tmc_mode = readl(drvdata->base + TMC_MODE);
+ mdata->tmc_ffcr = readl(drvdata->base + TMC_FFCR);
+ mdata->tmc_ffsr = readl(drvdata->base + TMC_FFSR);
+
+ /* Sync Internal SRAM to reserved trace buffer region */
+ drvdata->buf = drvdata->resrv_buf.vaddr;
+ tmc_etb_dump_hw(drvdata);
+ /* Store as per RSZ register convention */
+ mdata->tmc_ram_size = drvdata->len >> 2;
+
+ /* Other fields for processing trace buffer reads */
+ mdata->tmc_rrp = 0;
+ mdata->tmc_dba = 0;
+ mdata->tmc_rwp = drvdata->len;
+ mdata->trace_paddr = drvdata->resrv_buf.paddr;
+
+ mdata->version = CS_CRASHDATA_VERSION;
+
+ /*
+ * Make sure all previous writes are ordered,
+ * before we mark valid
+ */
+ dmb(sy);
+ mdata->valid = true;
+ /*
+ * Below order need to maintained, since crc of metadata
+ * is dependent on first
+ */
+ mdata->crc32_tdata = find_crash_tracedata_crc(drvdata, mdata);
+ mdata->crc32_mdata = find_crash_metadata_crc(mdata);
+
+ tmc_disable_hw(drvdata);
+
+ dev_dbg(&csdev->dev, "%s: success\n", __func__);
+out:
+ CS_UNLOCK(drvdata->base);
+ return 0;
+}
+
static const struct coresight_ops_sink tmc_etf_sink_ops = {
.enable = tmc_enable_etf_sink,
.disable = tmc_disable_etf_sink,
@@ -603,6 +680,10 @@ static const struct coresight_ops_link tmc_etf_link_ops = {
.disable = tmc_disable_etf_link,
};
+static const struct coresight_ops_panic tmc_etf_sync_ops = {
+ .sync = tmc_panic_sync_etf,
+};
+
const struct coresight_ops tmc_etb_cs_ops = {
.sink_ops = &tmc_etf_sink_ops,
};
@@ -610,6 +691,7 @@ const struct coresight_ops tmc_etb_cs_ops = {
const struct coresight_ops tmc_etf_cs_ops = {
.sink_ops = &tmc_etf_sink_ops,
.link_ops = &tmc_etf_link_ops,
+ .panic_ops = &tmc_etf_sync_ops,
};
int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
@@ -623,7 +705,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
drvdata->config_type != TMC_CONFIG_TYPE_ETF))
return -EINVAL;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
ret = -EBUSY;
@@ -655,7 +737,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
drvdata->reading = true;
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
@@ -672,14 +754,14 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
drvdata->config_type != TMC_CONFIG_TYPE_ETF))
return -EINVAL;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Re-enable the TMC if need be */
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
/* There is no point in reading a TMC in HW FIFO mode */
mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EINVAL;
}
/*
@@ -693,7 +775,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
memset(drvdata->buf, 0, drvdata->size);
rc = __tmc_etb_enable_hw(drvdata);
if (rc) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return rc;
}
} else {
@@ -706,7 +788,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
}
drvdata->reading = false;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/*
* Free allocated memory outside of the spinlock. There is no need
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index a48bb85d0e7f..76a8cb29b68a 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -30,6 +30,7 @@ struct etr_buf_hw {
bool has_iommu;
bool has_etr_sg;
bool has_catu;
+ bool has_resrv;
};
/*
@@ -696,6 +697,75 @@ static const struct etr_buf_operations etr_flat_buf_ops = {
};
/*
+ * tmc_etr_alloc_resrv_buf: Allocate a contiguous DMA buffer from reserved region.
+ */
+static int tmc_etr_alloc_resrv_buf(struct tmc_drvdata *drvdata,
+ struct etr_buf *etr_buf, int node,
+ void **pages)
+{
+ struct etr_flat_buf *resrv_buf;
+ struct device *real_dev = drvdata->csdev->dev.parent;
+
+ /* We cannot reuse existing pages for resrv buf */
+ if (pages)
+ return -EINVAL;
+
+ resrv_buf = kzalloc(sizeof(*resrv_buf), GFP_KERNEL);
+ if (!resrv_buf)
+ return -ENOMEM;
+
+ resrv_buf->daddr = dma_map_resource(real_dev, drvdata->resrv_buf.paddr,
+ drvdata->resrv_buf.size,
+ DMA_FROM_DEVICE, 0);
+ if (dma_mapping_error(real_dev, resrv_buf->daddr)) {
+ dev_err(real_dev, "failed to map source buffer address\n");
+ kfree(resrv_buf);
+ return -ENOMEM;
+ }
+
+ resrv_buf->vaddr = drvdata->resrv_buf.vaddr;
+ resrv_buf->size = etr_buf->size = drvdata->resrv_buf.size;
+ resrv_buf->dev = &drvdata->csdev->dev;
+ etr_buf->hwaddr = resrv_buf->daddr;
+ etr_buf->mode = ETR_MODE_RESRV;
+ etr_buf->private = resrv_buf;
+ return 0;
+}
+
+static void tmc_etr_free_resrv_buf(struct etr_buf *etr_buf)
+{
+ struct etr_flat_buf *resrv_buf = etr_buf->private;
+
+ if (resrv_buf && resrv_buf->daddr) {
+ struct device *real_dev = resrv_buf->dev->parent;
+
+ dma_unmap_resource(real_dev, resrv_buf->daddr,
+ resrv_buf->size, DMA_FROM_DEVICE, 0);
+ }
+ kfree(resrv_buf);
+}
+
+static void tmc_etr_sync_resrv_buf(struct etr_buf *etr_buf, u64 rrp, u64 rwp)
+{
+ /*
+ * Adjust the buffer to point to the beginning of the trace data
+ * and update the available trace data.
+ */
+ etr_buf->offset = rrp - etr_buf->hwaddr;
+ if (etr_buf->full)
+ etr_buf->len = etr_buf->size;
+ else
+ etr_buf->len = rwp - rrp;
+}
+
+static const struct etr_buf_operations etr_resrv_buf_ops = {
+ .alloc = tmc_etr_alloc_resrv_buf,
+ .free = tmc_etr_free_resrv_buf,
+ .sync = tmc_etr_sync_resrv_buf,
+ .get_data = tmc_etr_get_data_flat_buf,
+};
+
+/*
* tmc_etr_alloc_sg_buf: Allocate an SG buf @etr_buf. Setup the parameters
* appropriately.
*/
@@ -801,6 +871,7 @@ static const struct etr_buf_operations *etr_buf_ops[] = {
[ETR_MODE_FLAT] = &etr_flat_buf_ops,
[ETR_MODE_ETR_SG] = &etr_sg_buf_ops,
[ETR_MODE_CATU] = NULL,
+ [ETR_MODE_RESRV] = &etr_resrv_buf_ops
};
void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu)
@@ -826,6 +897,7 @@ static inline int tmc_etr_mode_alloc_buf(int mode,
case ETR_MODE_FLAT:
case ETR_MODE_ETR_SG:
case ETR_MODE_CATU:
+ case ETR_MODE_RESRV:
if (etr_buf_ops[mode] && etr_buf_ops[mode]->alloc)
rc = etr_buf_ops[mode]->alloc(drvdata, etr_buf,
node, pages);
@@ -844,6 +916,7 @@ static void get_etr_buf_hw(struct device *dev, struct etr_buf_hw *buf_hw)
buf_hw->has_iommu = iommu_get_domain_for_dev(dev->parent);
buf_hw->has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
buf_hw->has_catu = !!tmc_etr_get_catu_device(drvdata);
+ buf_hw->has_resrv = tmc_has_reserved_buffer(drvdata);
}
static bool etr_can_use_flat_mode(struct etr_buf_hw *buf_hw, ssize_t etr_buf_size)
@@ -987,7 +1060,7 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata)
static int __tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
{
- u32 axictl, sts;
+ u32 axictl, sts, ffcr;
struct etr_buf *etr_buf = drvdata->etr_buf;
int rc = 0;
@@ -1033,10 +1106,12 @@ static int __tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
writel_relaxed(sts, drvdata->base + TMC_STS);
}
- writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
- TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
- TMC_FFCR_TRIGON_TRIGIN,
- drvdata->base + TMC_FFCR);
+ ffcr = TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | TMC_FFCR_FON_FLIN |
+ TMC_FFCR_FON_TRIG_EVT | TMC_FFCR_TRIGON_TRIGIN;
+ if (drvdata->stop_on_flush)
+ ffcr |= TMC_FFCR_STOP_ON_FLUSH;
+ writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
+
writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
tmc_enable_hw(drvdata);
@@ -1176,10 +1251,10 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
* buffer, provided the size matches. Any allocation has to be done
* with the lock released.
*/
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Allocate memory with the locks released */
free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata);
@@ -1187,7 +1262,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
return new_buf;
/* Let's try again */
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
}
if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) {
@@ -1206,7 +1281,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
}
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free memory outside the spinlock if need be */
if (free_buf)
@@ -1224,7 +1299,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
if (IS_ERR(sysfs_buf))
return PTR_ERR(sysfs_buf);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/*
* In sysFS mode we can have multiple writers per sink. Since this
@@ -1243,7 +1318,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
}
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (!ret)
dev_dbg(&csdev->dev, "TMC-ETR enabled\n");
@@ -1562,17 +1637,17 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
struct etr_perf_buffer *etr_perf = config;
struct etr_buf *etr_buf = etr_perf->etr_buf;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */
if (csdev->refcnt != 1) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
goto out;
}
if (WARN_ON(drvdata->perf_buf != etr_buf)) {
lost = true;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
goto out;
}
@@ -1582,7 +1657,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
tmc_sync_etr_buf(drvdata);
CS_LOCK(drvdata->base);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
lost = etr_buf->full;
offset = etr_buf->offset;
@@ -1651,7 +1726,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
struct perf_output_handle *handle = data;
struct etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't use this sink if it is already claimed by sysFS */
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
rc = -EBUSY;
@@ -1691,7 +1766,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
}
unlock_out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return rc;
}
@@ -1713,16 +1788,16 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
csdev->refcnt--;
if (csdev->refcnt) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -1735,12 +1810,80 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
/* Reset perf specific data */
drvdata->perf_buf = NULL;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_dbg(&csdev->dev, "TMC-ETR disabled\n");
return 0;
}
+static int tmc_panic_sync_etr(struct coresight_device *csdev)
+{
+ u32 val;
+ struct tmc_crash_metadata *mdata;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ mdata = (struct tmc_crash_metadata *)drvdata->crash_mdata.vaddr;
+
+ if (!drvdata->etr_buf)
+ return 0;
+
+ /* Being in RESRV mode implies valid reserved memory as well */
+ if (drvdata->etr_buf->mode != ETR_MODE_RESRV)
+ return 0;
+
+ if (!tmc_has_crash_mdata_buffer(drvdata))
+ return 0;
+
+ CS_UNLOCK(drvdata->base);
+
+ /* Proceed only if ETR is enabled */
+ val = readl(drvdata->base + TMC_CTL);
+ if (!(val & TMC_CTL_CAPT_EN))
+ goto out;
+
+ val = readl(drvdata->base + TMC_FFSR);
+ /* Do manual flush and stop only if its not auto-stopped */
+ if (!(val & TMC_FFSR_FT_STOPPED)) {
+ dev_dbg(&csdev->dev,
+ "%s: Triggering manual flush\n", __func__);
+ tmc_flush_and_stop(drvdata);
+ } else
+ tmc_wait_for_tmcready(drvdata);
+
+ /* Sync registers from hardware to metadata region */
+ mdata->tmc_ram_size = readl(drvdata->base + TMC_RSZ);
+ mdata->tmc_sts = readl(drvdata->base + TMC_STS);
+ mdata->tmc_mode = readl(drvdata->base + TMC_MODE);
+ mdata->tmc_ffcr = readl(drvdata->base + TMC_FFCR);
+ mdata->tmc_ffsr = readl(drvdata->base + TMC_FFSR);
+ mdata->tmc_rrp = tmc_read_rrp(drvdata);
+ mdata->tmc_rwp = tmc_read_rwp(drvdata);
+ mdata->tmc_dba = tmc_read_dba(drvdata);
+ mdata->trace_paddr = drvdata->resrv_buf.paddr;
+ mdata->version = CS_CRASHDATA_VERSION;
+
+ /*
+ * Make sure all previous writes are ordered,
+ * before we mark valid
+ */
+ dmb(sy);
+ mdata->valid = true;
+ /*
+ * Below order need to maintained, since crc of metadata
+ * is dependent on first
+ */
+ mdata->crc32_tdata = find_crash_tracedata_crc(drvdata, mdata);
+ mdata->crc32_mdata = find_crash_metadata_crc(mdata);
+
+ tmc_disable_hw(drvdata);
+
+ dev_dbg(&csdev->dev, "%s: success\n", __func__);
+out:
+ CS_UNLOCK(drvdata->base);
+
+ return 0;
+}
+
static const struct coresight_ops_sink tmc_etr_sink_ops = {
.enable = tmc_enable_etr_sink,
.disable = tmc_disable_etr_sink,
@@ -1749,8 +1892,13 @@ static const struct coresight_ops_sink tmc_etr_sink_ops = {
.free_buffer = tmc_free_etr_buffer,
};
+static const struct coresight_ops_panic tmc_etr_sync_ops = {
+ .sync = tmc_panic_sync_etr,
+};
+
const struct coresight_ops tmc_etr_cs_ops = {
.sink_ops = &tmc_etr_sink_ops,
+ .panic_ops = &tmc_etr_sync_ops,
};
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
@@ -1762,7 +1910,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
return -EINVAL;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
ret = -EBUSY;
goto out;
@@ -1784,7 +1932,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
drvdata->reading = true;
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
@@ -1798,7 +1946,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
return -EINVAL;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* RE-enable the TMC if need be */
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
@@ -1818,7 +1966,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
}
drvdata->reading = false;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free allocated memory out side of the spinlock */
if (sysfs_buf)
@@ -1831,6 +1979,7 @@ static const char *const buf_modes_str[] = {
[ETR_MODE_FLAT] = "flat",
[ETR_MODE_ETR_SG] = "tmc-sg",
[ETR_MODE_CATU] = "catu",
+ [ETR_MODE_RESRV] = "resrv",
[ETR_MODE_AUTO] = "auto",
};
@@ -1849,6 +1998,9 @@ static ssize_t buf_modes_available_show(struct device *dev,
if (buf_hw.has_catu)
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_CATU]);
+ if (buf_hw.has_resrv)
+ size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_RESRV]);
+
size += sysfs_emit_at(buf, size, "\n");
return size;
}
@@ -1862,6 +2014,26 @@ static ssize_t buf_mode_preferred_show(struct device *dev,
return sysfs_emit(buf, "%s\n", buf_modes_str[drvdata->etr_mode]);
}
+static int buf_mode_set_resrv(struct tmc_drvdata *drvdata)
+{
+ int err = -EBUSY;
+ unsigned long flags;
+ struct tmc_resrv_buf *rbuf;
+
+ rbuf = &drvdata->resrv_buf;
+
+ /* Ensure there are no active crashdata read sessions */
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ if (!rbuf->reading) {
+ tmc_crashdata_set_invalid(drvdata);
+ rbuf->len = 0;
+ drvdata->etr_mode = ETR_MODE_RESRV;
+ err = 0;
+ }
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return err;
+}
+
static ssize_t buf_mode_preferred_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
@@ -1876,6 +2048,8 @@ static ssize_t buf_mode_preferred_store(struct device *dev,
drvdata->etr_mode = ETR_MODE_ETR_SG;
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_CATU]) && buf_hw.has_catu)
drvdata->etr_mode = ETR_MODE_CATU;
+ else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_RESRV]) && buf_hw.has_resrv)
+ return buf_mode_set_resrv(drvdata) ? : size;
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_AUTO]))
drvdata->etr_mode = ETR_MODE_AUTO;
else
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 2671926be62a..6541a27a018e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -12,6 +12,7 @@
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/refcount.h>
+#include <linux/crc32.h>
#define TMC_RSZ 0x004
#define TMC_STS 0x00c
@@ -76,6 +77,9 @@
#define TMC_AXICTL_AXCACHE_OS (0xf << 2)
#define TMC_AXICTL_ARCACHE_OS (0xf << 16)
+/* TMC_FFSR - 0x300 */
+#define TMC_FFSR_FT_STOPPED BIT(1)
+
/* TMC_FFCR - 0x304 */
#define TMC_FFCR_FLUSHMAN_BIT 6
#define TMC_FFCR_EN_FMT BIT(0)
@@ -94,6 +98,9 @@
#define TMC_AUTH_NSID_MASK GENMASK(1, 0)
+/* Major version 1 Minor version 0 */
+#define CS_CRASHDATA_VERSION (1 << 16)
+
enum tmc_config_type {
TMC_CONFIG_TYPE_ETB,
TMC_CONFIG_TYPE_ETR,
@@ -131,10 +138,30 @@ enum tmc_mem_intf_width {
#define CORESIGHT_SOC_600_ETR_CAPS \
(TMC_ETR_SAVE_RESTORE | TMC_ETR_AXI_ARCACHE)
+/* TMC metadata region for ETR and ETF configurations */
+struct tmc_crash_metadata {
+ uint32_t crc32_mdata; /* crc of metadata */
+ uint32_t crc32_tdata; /* crc of tracedata */
+ uint32_t version; /* 31:16 Major version, 15:0 Minor version */
+ uint32_t valid; /* Indicate if this ETF/ETR was enabled */
+ uint32_t tmc_ram_size; /* Ram Size register */
+ uint32_t tmc_sts; /* Status register */
+ uint32_t tmc_mode; /* Mode register */
+ uint32_t tmc_ffcr; /* Formatter and flush control register */
+ uint32_t tmc_ffsr; /* Formatter and flush status register */
+ uint32_t reserved32;
+ uint64_t tmc_rrp; /* Ram Read pointer register */
+ uint64_t tmc_rwp; /* Ram Write pointer register */
+ uint64_t tmc_dba; /* Data buffer address register */
+ uint64_t trace_paddr; /* Phys address of trace buffer */
+ uint64_t reserved64[3];
+};
+
enum etr_mode {
ETR_MODE_FLAT, /* Uses contiguous flat buffer */
ETR_MODE_ETR_SG, /* Uses in-built TMC ETR SG mechanism */
ETR_MODE_CATU, /* Use SG mechanism in CATU */
+ ETR_MODE_RESRV, /* Use reserved region contiguous buffer */
ETR_MODE_AUTO, /* Use the default mechanism */
};
@@ -165,15 +192,35 @@ struct etr_buf {
};
/**
+ * @paddr : Start address of reserved memory region.
+ * @vaddr : Corresponding CPU virtual address.
+ * @size : Size of reserved memory region.
+ * @offset : Offset of the trace data in the buffer for consumption.
+ * @reading : Flag to indicate if reading is active
+ * @len : Available trace data @buf (may round up to the beginning).
+ */
+struct tmc_resrv_buf {
+ phys_addr_t paddr;
+ void *vaddr;
+ size_t size;
+ unsigned long offset;
+ bool reading;
+ s64 len;
+};
+
+/**
* struct tmc_drvdata - specifics associated to an TMC component
* @pclk: APB clock if present, otherwise NULL
* @base: memory mapped base address for this component.
* @csdev: component vitals needed by the framework.
* @miscdev: specifics to handle "/dev/xyz.tmc" entry.
+ * @crashdev: specifics to handle "/dev/crash_tmc_xyz" entry for reading
+ * crash tracedata.
* @spinlock: only one at a time pls.
* @pid: Process ID of the process that owns the session that is using
* this component. For example this would be the pid of the Perf
* process.
+ * @stop_on_flush: Stop on flush trigger user configuration.
* @buf: Snapshot of the trace data for ETF/ETB.
* @etr_buf: details of buffer used in TMC-ETR
* @len: size of the available trace for ETF/ETB.
@@ -189,15 +236,23 @@ struct etr_buf {
* @idr_mutex: Access serialisation for idr.
* @sysfs_buf: SYSFS buffer for ETR.
* @perf_buf: PERF buffer for ETR.
+ * @resrv_buf: Used by ETR as hardware trace buffer and for trace data
+ * retention (after crash) only when ETR_MODE_RESRV buffer
+ * mode is enabled. Used by ETF for trace data retention
+ * (after crash) by default.
+ * @crash_mdata: Reserved memory for storing tmc crash metadata.
+ * Used by ETR/ETF.
*/
struct tmc_drvdata {
struct clk *pclk;
void __iomem *base;
struct coresight_device *csdev;
struct miscdevice miscdev;
- spinlock_t spinlock;
+ struct miscdevice crashdev;
+ raw_spinlock_t spinlock;
pid_t pid;
bool reading;
+ bool stop_on_flush;
union {
char *buf; /* TMC ETB */
struct etr_buf *etr_buf; /* TMC ETR */
@@ -214,6 +269,8 @@ struct tmc_drvdata {
struct mutex idr_mutex;
struct etr_buf *sysfs_buf;
struct etr_buf *perf_buf;
+ struct tmc_resrv_buf resrv_buf;
+ struct tmc_resrv_buf crash_mdata;
};
struct etr_buf_operations {
@@ -263,6 +320,7 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata);
void tmc_enable_hw(struct tmc_drvdata *drvdata);
void tmc_disable_hw(struct tmc_drvdata *drvdata);
u32 tmc_get_memwidth_mask(struct tmc_drvdata *drvdata);
+int tmc_read_prepare_crashdata(struct tmc_drvdata *drvdata);
/* ETB/ETF functions */
int tmc_read_prepare_etb(struct tmc_drvdata *drvdata);
@@ -325,12 +383,58 @@ void tmc_sg_table_sync_data_range(struct tmc_sg_table *table,
u64 offset, u64 size);
ssize_t tmc_sg_table_get_data(struct tmc_sg_table *sg_table,
u64 offset, size_t len, char **bufpp);
+
static inline unsigned long
tmc_sg_table_buf_size(struct tmc_sg_table *sg_table)
{
return (unsigned long)sg_table->data_pages.nr_pages << PAGE_SHIFT;
}
+static inline bool tmc_has_reserved_buffer(struct tmc_drvdata *drvdata)
+{
+ if (drvdata->resrv_buf.vaddr &&
+ drvdata->resrv_buf.size)
+ return true;
+ return false;
+}
+
+static inline bool tmc_has_crash_mdata_buffer(struct tmc_drvdata *drvdata)
+{
+ if (drvdata->crash_mdata.vaddr &&
+ drvdata->crash_mdata.size)
+ return true;
+ return false;
+}
+
+static inline void tmc_crashdata_set_invalid(struct tmc_drvdata *drvdata)
+{
+ struct tmc_crash_metadata *mdata;
+
+ mdata = (struct tmc_crash_metadata *)drvdata->crash_mdata.vaddr;
+
+ if (tmc_has_crash_mdata_buffer(drvdata))
+ mdata->valid = false;
+}
+
+static inline uint32_t find_crash_metadata_crc(struct tmc_crash_metadata *md)
+{
+ unsigned long crc_size;
+
+ crc_size = sizeof(struct tmc_crash_metadata) -
+ offsetof(struct tmc_crash_metadata, crc32_tdata);
+ return crc32_le(0, (void *)&md->crc32_tdata, crc_size);
+}
+
+static inline uint32_t find_crash_tracedata_crc(struct tmc_drvdata *drvdata,
+ struct tmc_crash_metadata *md)
+{
+ unsigned long crc_size;
+
+ /* Take CRC of configured buffer size to keep it simple */
+ crc_size = md->tmc_ram_size << 2;
+ return crc32_le(0, (void *)drvdata->resrv_buf.vaddr, crc_size);
+}
+
struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);
void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 189a4abc2561..0633f04beb24 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/amba/bus.h>
@@ -68,11 +68,12 @@ static int tpdm_read_element_size(struct tpda_drvdata *drvdata,
int rc = -EINVAL;
struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent);
- if (tpdm_has_dsb_dataset(tpdm_data)) {
+ if (tpdm_data->dsb) {
rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
"qcom,dsb-element-bits", &drvdata->dsb_esize);
}
- if (tpdm_has_cmb_dataset(tpdm_data)) {
+
+ if (tpdm_data->cmb) {
rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
"qcom,cmb-element-bits", &drvdata->cmb_esize);
}
@@ -241,12 +242,23 @@ static void tpda_disable(struct coresight_device *csdev,
dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
}
+static int tpda_trace_id(struct coresight_device *csdev, __maybe_unused enum cs_mode mode,
+ __maybe_unused struct coresight_device *sink)
+{
+ struct tpda_drvdata *drvdata;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ return drvdata->atid;
+}
+
static const struct coresight_ops_link tpda_link_ops = {
.enable = tpda_enable,
.disable = tpda_disable,
};
static const struct coresight_ops tpda_cs_ops = {
+ .trace_id = tpda_trace_id,
.link_ops = &tpda_link_ops,
};
@@ -331,7 +343,7 @@ static void tpda_remove(struct amba_device *adev)
* Different TPDA has different periph id.
* The difference is 0-7 bits' value. So ignore 0-7 bits.
*/
-static struct amba_id tpda_ids[] = {
+static const struct amba_id tpda_ids[] = {
{
.id = 0x000f0f00,
.mask = 0x000fff00,
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index c38f9701665e..7214e65097ec 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/amba/bus.h>
@@ -21,6 +21,21 @@
DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm");
+static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
+{
+ return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
+}
+
+static bool tpdm_has_cmb_dataset(struct tpdm_drvdata *drvdata)
+{
+ return (drvdata->datasets & TPDM_PIDR0_DS_CMB);
+}
+
+static bool tpdm_has_mcmb_dataset(struct tpdm_drvdata *drvdata)
+{
+ return (drvdata->datasets & TPDM_PIDR0_DS_MCMB);
+}
+
/* Read dataset array member with the index number */
static ssize_t tpdm_simple_dataset_show(struct device *dev,
struct device_attribute *attr,
@@ -198,7 +213,7 @@ static umode_t tpdm_cmb_is_visible(struct kobject *kobj,
struct device *dev = kobj_to_dev(kobj);
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (drvdata && tpdm_has_cmb_dataset(drvdata))
+ if (drvdata && drvdata->cmb)
return attr->mode;
return 0;
@@ -237,6 +252,18 @@ static umode_t tpdm_cmb_msr_is_visible(struct kobject *kobj,
return 0;
}
+static umode_t tpdm_mcmb_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ if (drvdata && tpdm_has_mcmb_dataset(drvdata))
+ return attr->mode;
+
+ return 0;
+}
+
static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
{
if (tpdm_has_dsb_dataset(drvdata)) {
@@ -388,7 +415,7 @@ static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata)
{
u32 val, i;
- if (!tpdm_has_cmb_dataset(drvdata))
+ if (!drvdata->cmb)
return;
/* Configure pattern registers */
@@ -415,6 +442,19 @@ static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata)
val |= TPDM_CMB_CR_MODE;
else
val &= ~TPDM_CMB_CR_MODE;
+
+ if (tpdm_has_mcmb_dataset(drvdata)) {
+ val &= ~TPDM_CMB_CR_XTRIG_LNSEL;
+ /* Set the lane participates in the output pattern */
+ val |= FIELD_PREP(TPDM_CMB_CR_XTRIG_LNSEL,
+ drvdata->cmb->mcmb.trig_lane);
+
+ /* Set the enablement of the lane */
+ val &= ~TPDM_CMB_CR_E_LN;
+ val |= FIELD_PREP(TPDM_CMB_CR_E_LN,
+ drvdata->cmb->mcmb.lane_select);
+ }
+
/* Set the enable bit of CMB control register to 1 */
val |= TPDM_CMB_CR_ENA;
writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
@@ -440,7 +480,7 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata)
static int tpdm_enable(struct coresight_device *csdev, struct perf_event *event,
enum cs_mode mode,
- __maybe_unused struct coresight_trace_id_map *id_map)
+ __maybe_unused struct coresight_path *path)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -480,7 +520,7 @@ static void tpdm_disable_cmb(struct tpdm_drvdata *drvdata)
{
u32 val;
- if (!tpdm_has_cmb_dataset(drvdata))
+ if (!drvdata->cmb)
return;
val = readl_relaxed(drvdata->base + TPDM_CMB_CR);
@@ -542,12 +582,14 @@ static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata)
if (!drvdata->dsb)
return -ENOMEM;
}
- if (tpdm_has_cmb_dataset(drvdata) && (!drvdata->cmb)) {
+ if ((tpdm_has_cmb_dataset(drvdata) || tpdm_has_mcmb_dataset(drvdata))
+ && (!drvdata->cmb)) {
drvdata->cmb = devm_kzalloc(drvdata->dev,
sizeof(*drvdata->cmb), GFP_KERNEL);
if (!drvdata->cmb)
return -ENOMEM;
}
+
tpdm_reset_datasets(drvdata);
return 0;
@@ -990,6 +1032,62 @@ static ssize_t cmb_trig_ts_store(struct device *dev,
}
static DEVICE_ATTR_RW(cmb_trig_ts);
+static ssize_t mcmb_trig_lane_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->cmb->mcmb.trig_lane);
+}
+
+static ssize_t mcmb_trig_lane_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val >= TPDM_MCMB_MAX_LANES))
+ return -EINVAL;
+
+ guard(spinlock)(&drvdata->spinlock);
+ drvdata->cmb->mcmb.trig_lane = val;
+
+ return size;
+}
+static DEVICE_ATTR_RW(mcmb_trig_lane);
+
+static ssize_t mcmb_lanes_select_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->cmb->mcmb.lane_select);
+}
+
+static ssize_t mcmb_lanes_select_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if (kstrtoul(buf, 0, &val) || (val & ~TPDM_MCMB_E_LN_MASK))
+ return -EINVAL;
+
+ guard(spinlock)(&drvdata->spinlock);
+ drvdata->cmb->mcmb.lane_select = val & TPDM_MCMB_E_LN_MASK;
+
+ return size;
+}
+static DEVICE_ATTR_RW(mcmb_lanes_select);
+
static struct attribute *tpdm_dsb_edge_attrs[] = {
&dev_attr_ctrl_idx.attr,
&dev_attr_ctrl_val.attr,
@@ -1152,6 +1250,12 @@ static struct attribute *tpdm_cmb_msr_attrs[] = {
NULL,
};
+static struct attribute *tpdm_mcmb_attrs[] = {
+ &dev_attr_mcmb_trig_lane.attr,
+ &dev_attr_mcmb_lanes_select.attr,
+ NULL,
+};
+
static struct attribute *tpdm_dsb_attrs[] = {
&dev_attr_dsb_mode.attr,
&dev_attr_dsb_trig_ts.attr,
@@ -1218,6 +1322,11 @@ static struct attribute_group tpdm_cmb_msr_grp = {
.name = "cmb_msr",
};
+static struct attribute_group tpdm_mcmb_attr_grp = {
+ .attrs = tpdm_mcmb_attrs,
+ .is_visible = tpdm_mcmb_is_visible,
+};
+
static const struct attribute_group *tpdm_attr_grps[] = {
&tpdm_attr_grp,
&tpdm_dsb_attr_grp,
@@ -1229,6 +1338,7 @@ static const struct attribute_group *tpdm_attr_grps[] = {
&tpdm_cmb_trig_patt_grp,
&tpdm_cmb_patt_grp,
&tpdm_cmb_msr_grp,
+ &tpdm_mcmb_attr_grp,
NULL,
};
@@ -1305,7 +1415,7 @@ static void tpdm_remove(struct amba_device *adev)
* Different TPDM has different periph id.
* The difference is 0-7 bits' value. So ignore 0-7 bits.
*/
-static struct amba_id tpdm_ids[] = {
+static const struct amba_id tpdm_ids[] = {
{
.id = 0x001f0e00,
.mask = 0x00ffff00,
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h
index e08d212642e3..b11754389734 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.h
+++ b/drivers/hwtracing/coresight/coresight-tpdm.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CORESIGHT_CORESIGHT_TPDM_H
@@ -9,7 +9,7 @@
/* The max number of the datasets that TPDM supports */
#define TPDM_DATASETS 7
-/* CMB Subunit Registers */
+/* CMB/MCMB Subunit Registers */
#define TPDM_CMB_CR (0xA00)
/* CMB subunit timestamp insertion enable register */
#define TPDM_CMB_TIER (0xA04)
@@ -28,6 +28,10 @@
#define TPDM_CMB_CR_ENA BIT(0)
/* Trace collection mode for CMB subunit */
#define TPDM_CMB_CR_MODE BIT(1)
+/* MCMB trigger lane select */
+#define TPDM_CMB_CR_XTRIG_LNSEL GENMASK(20, 18)
+/* MCMB lane enablement */
+#define TPDM_CMB_CR_E_LN GENMASK(17, 10)
/* Timestamp control for pattern match */
#define TPDM_CMB_TIER_PATT_TSENAB BIT(0)
/* CMB CTI timestamp request */
@@ -41,6 +45,12 @@
/* MAX number of DSB MSR */
#define TPDM_CMB_MAX_MSR 32
+/* MAX lanes in the output pattern for MCMB configurations*/
+#define TPDM_MCMB_MAX_LANES 8
+
+/* Filter bit 0~7 from the value for CR_E_LN */
+#define TPDM_MCMB_E_LN_MASK GENMASK(7, 0)
+
/* DSB Subunit Registers */
#define TPDM_DSB_CR (0x780)
#define TPDM_DSB_TIER (0x784)
@@ -112,11 +122,13 @@
* PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0
* PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0
* PERIPHIDR0[2] : Fix to 1 if CMB subunit present, else 0
+ * PERIPHIDR0[6] : Fix to 1 if MCMB subunit present, else 0
*/
#define TPDM_PIDR0_DS_IMPDEF BIT(0)
#define TPDM_PIDR0_DS_DSB BIT(1)
#define TPDM_PIDR0_DS_CMB BIT(2)
+#define TPDM_PIDR0_DS_MCMB BIT(6)
#define TPDM_DSB_MAX_LINES 256
/* MAX number of EDCR registers */
@@ -256,6 +268,9 @@ struct dsb_dataset {
* @patt_ts: Indicates if pattern match for timestamp is enabled.
* @trig_ts: Indicates if CTI trigger for timestamp is enabled.
* @ts_all: Indicates if timestamp is enabled for all packets.
+ * struct mcmb_dataset
+ * @mcmb_trig_lane: Save data for trigger lane
+ * @mcmb_lane_select: Save data for lane enablement
*/
struct cmb_dataset {
u32 trace_mode;
@@ -267,6 +282,10 @@ struct cmb_dataset {
bool patt_ts;
bool trig_ts;
bool ts_all;
+ struct {
+ u8 trig_lane;
+ u8 lane_select;
+ } mcmb;
};
/**
@@ -324,14 +343,4 @@ struct tpdm_dataset_attribute {
enum dataset_mem mem;
u32 idx;
};
-
-static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
-{
- return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
-}
-
-static bool tpdm_has_cmb_dataset(struct tpdm_drvdata *drvdata)
-{
- return (drvdata->datasets & TPDM_PIDR0_DS_CMB);
-}
#endif /* _CORESIGHT_CORESIGHT_TPDM_H */
diff --git a/drivers/hwtracing/coresight/coresight-trace-id.c b/drivers/hwtracing/coresight/coresight-trace-id.c
index 378af743be45..7ed337d54d3e 100644
--- a/drivers/hwtracing/coresight/coresight-trace-id.c
+++ b/drivers/hwtracing/coresight/coresight-trace-id.c
@@ -22,7 +22,7 @@ enum trace_id_flags {
static DEFINE_PER_CPU(atomic_t, id_map_default_cpu_ids) = ATOMIC_INIT(0);
static struct coresight_trace_id_map id_map_default = {
.cpu_map = &id_map_default_cpu_ids,
- .lock = __SPIN_LOCK_UNLOCKED(id_map_default.lock)
+ .lock = __RAW_SPIN_LOCK_UNLOCKED(id_map_default.lock)
};
/* #define TRACE_ID_DEBUG 1 */
@@ -131,11 +131,11 @@ static void coresight_trace_id_release_all(struct coresight_trace_id_map *id_map
unsigned long flags;
int cpu;
- spin_lock_irqsave(&id_map->lock, flags);
+ raw_spin_lock_irqsave(&id_map->lock, flags);
bitmap_zero(id_map->used_ids, CORESIGHT_TRACE_IDS_MAX);
for_each_possible_cpu(cpu)
atomic_set(per_cpu_ptr(id_map->cpu_map, cpu), 0);
- spin_unlock_irqrestore(&id_map->lock, flags);
+ raw_spin_unlock_irqrestore(&id_map->lock, flags);
DUMP_ID_MAP(id_map);
}
@@ -144,7 +144,7 @@ static int _coresight_trace_id_get_cpu_id(int cpu, struct coresight_trace_id_map
unsigned long flags;
int id;
- spin_lock_irqsave(&id_map->lock, flags);
+ raw_spin_lock_irqsave(&id_map->lock, flags);
/* check for existing allocation for this CPU */
id = _coresight_trace_id_read_cpu_id(cpu, id_map);
@@ -171,7 +171,7 @@ static int _coresight_trace_id_get_cpu_id(int cpu, struct coresight_trace_id_map
atomic_set(per_cpu_ptr(id_map->cpu_map, cpu), id);
get_cpu_id_out_unlock:
- spin_unlock_irqrestore(&id_map->lock, flags);
+ raw_spin_unlock_irqrestore(&id_map->lock, flags);
DUMP_ID_CPU(cpu, id);
DUMP_ID_MAP(id_map);
@@ -188,12 +188,12 @@ static void _coresight_trace_id_put_cpu_id(int cpu, struct coresight_trace_id_ma
if (!id)
return;
- spin_lock_irqsave(&id_map->lock, flags);
+ raw_spin_lock_irqsave(&id_map->lock, flags);
coresight_trace_id_free(id, id_map);
atomic_set(per_cpu_ptr(id_map->cpu_map, cpu), 0);
- spin_unlock_irqrestore(&id_map->lock, flags);
+ raw_spin_unlock_irqrestore(&id_map->lock, flags);
DUMP_ID_CPU(cpu, id);
DUMP_ID_MAP(id_map);
}
@@ -204,9 +204,9 @@ static int coresight_trace_id_map_get_system_id(struct coresight_trace_id_map *i
unsigned long flags;
int id;
- spin_lock_irqsave(&id_map->lock, flags);
+ raw_spin_lock_irqsave(&id_map->lock, flags);
id = coresight_trace_id_alloc_new_id(id_map, preferred_id, traceid_flags);
- spin_unlock_irqrestore(&id_map->lock, flags);
+ raw_spin_unlock_irqrestore(&id_map->lock, flags);
DUMP_ID(id);
DUMP_ID_MAP(id_map);
@@ -217,9 +217,9 @@ static void coresight_trace_id_map_put_system_id(struct coresight_trace_id_map *
{
unsigned long flags;
- spin_lock_irqsave(&id_map->lock, flags);
+ raw_spin_lock_irqsave(&id_map->lock, flags);
coresight_trace_id_free(id, id_map);
- spin_unlock_irqrestore(&id_map->lock, flags);
+ raw_spin_unlock_irqrestore(&id_map->lock, flags);
DUMP_ID(id);
DUMP_ID_MAP(id_map);
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
index dc3c9504dd7c..26cfc939e5bd 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.c
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
@@ -98,7 +98,7 @@ static int smb_open(struct inode *inode, struct file *file)
struct smb_drv_data *drvdata = container_of(file->private_data,
struct smb_drv_data, miscdev);
- guard(spinlock)(&drvdata->spinlock);
+ guard(raw_spinlock)(&drvdata->spinlock);
if (drvdata->reading)
return -EBUSY;
@@ -152,7 +152,7 @@ static int smb_release(struct inode *inode, struct file *file)
struct smb_drv_data *drvdata = container_of(file->private_data,
struct smb_drv_data, miscdev);
- guard(spinlock)(&drvdata->spinlock);
+ guard(raw_spinlock)(&drvdata->spinlock);
drvdata->reading = false;
return 0;
@@ -245,7 +245,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret = 0;
- guard(spinlock)(&drvdata->spinlock);
+ guard(raw_spinlock)(&drvdata->spinlock);
/* Do nothing, the trace data is reading by other interface now */
if (drvdata->reading)
@@ -280,7 +280,7 @@ static int smb_disable(struct coresight_device *csdev)
{
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
- guard(spinlock)(&drvdata->spinlock);
+ guard(raw_spinlock)(&drvdata->spinlock);
if (drvdata->reading)
return -EBUSY;
@@ -378,7 +378,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
if (!buf)
return 0;
- guard(spinlock)(&drvdata->spinlock);
+ guard(raw_spinlock)(&drvdata->spinlock);
/* Don't do anything if another tracer is using this sink. */
if (csdev->refcnt != 1)
@@ -563,7 +563,7 @@ static int smb_probe(struct platform_device *pdev)
smb_reset_buffer(drvdata);
platform_set_drvdata(pdev, drvdata);
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
drvdata->pid = -1;
ret = smb_register_sink(pdev, drvdata);
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.h b/drivers/hwtracing/coresight/ultrasoc-smb.h
index a91d39cfccb8..c4c111275627 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.h
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.h
@@ -115,7 +115,7 @@ struct smb_drv_data {
struct coresight_device *csdev;
struct smb_data_buffer sdb;
struct miscdevice miscdev;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
bool reading;
pid_t pid;
};
diff --git a/drivers/hwtracing/stm/heartbeat.c b/drivers/hwtracing/stm/heartbeat.c
index e9496fe97baa..495eb1dc8ac5 100644
--- a/drivers/hwtracing/stm/heartbeat.c
+++ b/drivers/hwtracing/stm/heartbeat.c
@@ -81,10 +81,8 @@ static int stm_heartbeat_init(void)
stm_heartbeat[i].data.type = STM_USER;
stm_heartbeat[i].data.link = stm_heartbeat_link;
stm_heartbeat[i].data.unlink = stm_heartbeat_unlink;
- hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC,
- HRTIMER_MODE_ABS);
- stm_heartbeat[i].hrtimer.function =
- stm_heartbeat_hrtimer_handler;
+ hrtimer_setup(&stm_heartbeat[i].hrtimer, stm_heartbeat_hrtimer_handler,
+ CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
ret = stm_source_register_device(NULL, &stm_heartbeat[i].data);
if (ret)