summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc16
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-core.c15
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c111
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.h3
4 files changed, 131 insertions, 14 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc
index 6aa527296c71..96aafa66b4a5 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc
@@ -91,3 +91,19 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Size of the trace buffer for TMC-ETR when used in SYSFS
mode. Writable only for TMC-ETR configurations. The value
should be aligned to the kernel pagesize.
+
+What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_modes_available
+Date: August 2023
+KernelVersion: 6.7
+Contact: Anshuman Khandual <anshuman.khandual@arm.com>
+Description: (Read) Shows all supported Coresight TMC-ETR buffer modes available
+ for the users to configure explicitly. This file is avaialble only
+ for TMC ETR devices.
+
+What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_mode_preferred
+Date: August 2023
+KernelVersion: 6.7
+Contact: Anshuman Khandual <anshuman.khandual@arm.com>
+Description: (RW) Current Coresight TMC-ETR buffer mode selected. But user could
+ only provide a mode which is supported for a given ETR device. This
+ file is available only for TMC ETR devices.
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index c106d142e632..7ec5365e2b64 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/io.h>
+#include <linux/iommu.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
@@ -344,7 +345,14 @@ static const struct attribute_group coresight_tmc_mgmt_group = {
.name = "mgmt",
};
-static const struct attribute_group *coresight_tmc_groups[] = {
+static const struct attribute_group *coresight_etf_groups[] = {
+ &coresight_tmc_group,
+ &coresight_tmc_mgmt_group,
+ NULL,
+};
+
+static const struct attribute_group *coresight_etr_groups[] = {
+ &coresight_etr_group,
&coresight_tmc_group,
&coresight_tmc_mgmt_group,
NULL,
@@ -465,6 +473,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->memwidth = tmc_get_memwidth(devid);
/* This device is not associated with a session */
drvdata->pid = -1;
+ drvdata->etr_mode = ETR_MODE_AUTO;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
drvdata->size = tmc_etr_get_default_buffer_size(dev);
@@ -474,16 +483,17 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
}
desc.dev = dev;
- desc.groups = coresight_tmc_groups;
switch (drvdata->config_type) {
case TMC_CONFIG_TYPE_ETB:
+ desc.groups = coresight_etf_groups;
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &tmc_etb_cs_ops;
dev_list = &etb_devs;
break;
case TMC_CONFIG_TYPE_ETR:
+ desc.groups = coresight_etr_groups;
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
desc.ops = &tmc_etr_cs_ops;
@@ -496,6 +506,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
dev_list = &etr_devs;
break;
case TMC_CONFIG_TYPE_ETF:
+ desc.groups = coresight_etf_groups;
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 8311e1028ddb..af02ba5d5f15 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -26,6 +26,12 @@ struct etr_flat_buf {
size_t size;
};
+struct etr_buf_hw {
+ bool has_iommu;
+ bool has_etr_sg;
+ bool has_catu;
+};
+
/*
* etr_perf_buffer - Perf buffer used for ETR
* @drvdata - The ETR drvdaga this buffer has been allocated for.
@@ -830,6 +836,22 @@ static inline int tmc_etr_mode_alloc_buf(int mode,
}
}
+static void get_etr_buf_hw(struct device *dev, struct etr_buf_hw *buf_hw)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ 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);
+}
+
+static bool etr_can_use_flat_mode(struct etr_buf_hw *buf_hw, ssize_t etr_buf_size)
+{
+ bool has_sg = buf_hw->has_catu || buf_hw->has_etr_sg;
+
+ return !has_sg || buf_hw->has_iommu || etr_buf_size < SZ_1M;
+}
+
/*
* tmc_alloc_etr_buf: Allocate a buffer use by ETR.
* @drvdata : ETR device details.
@@ -843,23 +865,22 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
int node, void **pages)
{
int rc = -ENOMEM;
- bool has_etr_sg, has_iommu;
- bool has_sg, has_catu;
struct etr_buf *etr_buf;
+ struct etr_buf_hw buf_hw;
struct device *dev = &drvdata->csdev->dev;
- has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
- has_iommu = iommu_get_domain_for_dev(dev->parent);
- has_catu = !!tmc_etr_get_catu_device(drvdata);
-
- has_sg = has_catu || has_etr_sg;
-
+ get_etr_buf_hw(dev, &buf_hw);
etr_buf = kzalloc(sizeof(*etr_buf), GFP_KERNEL);
if (!etr_buf)
return ERR_PTR(-ENOMEM);
etr_buf->size = size;
+ /* If there is user directive for buffer mode, try that first */
+ if (drvdata->etr_mode != ETR_MODE_AUTO)
+ rc = tmc_etr_mode_alloc_buf(drvdata->etr_mode, drvdata,
+ etr_buf, node, pages);
+
/*
* If we have to use an existing list of pages, we cannot reliably
* use a contiguous DMA memory (even if we have an IOMMU). Otherwise,
@@ -872,14 +893,13 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
* Fallback to available mechanisms.
*
*/
- if (!pages &&
- (!has_sg || has_iommu || size < SZ_1M))
+ if (rc && !pages && etr_can_use_flat_mode(&buf_hw, size))
rc = tmc_etr_mode_alloc_buf(ETR_MODE_FLAT, drvdata,
etr_buf, node, pages);
- if (rc && has_etr_sg)
+ if (rc && buf_hw.has_etr_sg)
rc = tmc_etr_mode_alloc_buf(ETR_MODE_ETR_SG, drvdata,
etr_buf, node, pages);
- if (rc && has_catu)
+ if (rc && buf_hw.has_catu)
rc = tmc_etr_mode_alloc_buf(ETR_MODE_CATU, drvdata,
etr_buf, node, pages);
if (rc) {
@@ -1804,3 +1824,70 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
return 0;
}
+
+static const char *const buf_modes_str[] = {
+ [ETR_MODE_FLAT] = "flat",
+ [ETR_MODE_ETR_SG] = "tmc-sg",
+ [ETR_MODE_CATU] = "catu",
+ [ETR_MODE_AUTO] = "auto",
+};
+
+static ssize_t buf_modes_available_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct etr_buf_hw buf_hw;
+ ssize_t size = 0;
+
+ get_etr_buf_hw(dev, &buf_hw);
+ size += sysfs_emit(buf, "%s ", buf_modes_str[ETR_MODE_AUTO]);
+ size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_FLAT]);
+ if (buf_hw.has_etr_sg)
+ size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_ETR_SG]);
+
+ if (buf_hw.has_catu)
+ size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_CATU]);
+
+ size += sysfs_emit_at(buf, size, "\n");
+ return size;
+}
+static DEVICE_ATTR_RO(buf_modes_available);
+
+static ssize_t buf_mode_preferred_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%s\n", buf_modes_str[drvdata->etr_mode]);
+}
+
+static ssize_t buf_mode_preferred_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etr_buf_hw buf_hw;
+
+ get_etr_buf_hw(dev, &buf_hw);
+ if (sysfs_streq(buf, buf_modes_str[ETR_MODE_FLAT]))
+ drvdata->etr_mode = ETR_MODE_FLAT;
+ else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_ETR_SG]) && buf_hw.has_etr_sg)
+ 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_AUTO]))
+ drvdata->etr_mode = ETR_MODE_AUTO;
+ else
+ return -EINVAL;
+ return size;
+}
+static DEVICE_ATTR_RW(buf_mode_preferred);
+
+static struct attribute *coresight_etr_attrs[] = {
+ &dev_attr_buf_modes_available.attr,
+ &dev_attr_buf_mode_preferred.attr,
+ NULL,
+};
+
+const struct attribute_group coresight_etr_group = {
+ .attrs = coresight_etr_attrs,
+};
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 0ee48c5ba764..8dcb426ac3e7 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -135,6 +135,7 @@ 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_AUTO, /* Use the default mechanism */
};
struct etr_buf_operations;
@@ -207,6 +208,7 @@ struct tmc_drvdata {
enum tmc_mem_intf_width memwidth;
u32 trigger_cntr;
u32 etr_caps;
+ enum etr_mode etr_mode;
struct idr idr;
struct mutex idr_mutex;
struct etr_buf *sysfs_buf;
@@ -334,5 +336,6 @@ void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
void tmc_etr_remove_catu_ops(void);
struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
enum cs_mode mode, void *data);
+extern const struct attribute_group coresight_etr_group;
#endif