On 13/07/2023 14:47, Linu Cherian wrote:
Add support to use reserved memory for coresight ETR trace buffer.
Introduce a new ETR buffer mode called ETR_MODE_RESRV, which gets enabled when ETR device tree node is supplied with a valid reserved memory region.
Signed-off-by: Anil Kumar Reddy areddy3@marvell.com Signed-off-by: Linu Cherian lcherian@marvell.com
.../hwtracing/coresight/coresight-tmc-core.c | 57 ++++++++++++++++ .../hwtracing/coresight/coresight-tmc-etr.c | 67 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-tmc.h | 16 +++++ 3 files changed, 139 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index c106d142e632..b0374ae007d2 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -21,6 +21,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> @@ -362,6 +363,54 @@ static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata) return (auth & TMC_AUTH_NSID_MASK) == 0x3; } +static inline bool is_tmc_reserved_region_valid(struct device *dev) +{
- struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata->resrv_buf.paddr &&
drvdata->resrv_buf.size)
return true;
- return false;
+}
+static void tmc_get_reserved_region(struct device *parent) +{
- struct tmc_drvdata *drvdata = dev_get_drvdata(parent);
- struct device_node *node;
- struct resource res;
- int rc;
- node = of_parse_phandle(parent->of_node, "memory-region", 0);
- if (!node) {
dev_dbg(parent, "No reserved trace buffer specified\n");
goto out;
- }
- rc = of_address_to_resource(node, 0, &res);
- of_node_put(node);
- if (rc || res.start == 0 || resource_size(&res) == 0) {
dev_err(parent, "Reserved trace buffer memory is invalid\n");
goto out;
- }
- drvdata->resrv_buf.vaddr = memremap(res.start,
resource_size(&res),
MEMREMAP_WC);
- if (IS_ERR(drvdata->resrv_buf.vaddr)) {
dev_err(parent, "Reserved trace buffer mapping failed\n");
rc = PTR_ERR(drvdata->resrv_buf.vaddr);
goto out;
- }
- drvdata->resrv_buf.paddr = res.start;
- drvdata->resrv_buf.size = resource_size(&res);
- /* Size of contiguous buffer space for TMC ETR */
- drvdata->size = drvdata->resrv_buf.size;
+out:
- return;
+}
/* Detect and initialise the capabilities of a TMC ETR */ static int tmc_etr_setup_caps(struct device *parent, u32 devid, void *dev_caps) { @@ -378,6 +427,12 @@ static int tmc_etr_setup_caps(struct device *parent, u32 devid, void *dev_caps) if (!(devid & TMC_DEVID_NOSCAT) && tmc_etr_can_use_sg(parent)) tmc_etr_set_cap(drvdata, TMC_ETR_SG);
- /* Get reserved memory region if specified and
* set capability to use reserved memory for trace buffer.
*/
- if (is_tmc_reserved_region_valid(parent))
tmc_etr_set_cap(drvdata, TMC_ETR_RESRV_MEM);
- /* Check if the AXI address width is available */ if (devid & TMC_DEVID_AXIAW_VALID) dma_mask = ((devid >> TMC_DEVID_AXIAW_SHIFT) &
@@ -473,6 +528,8 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; }
- tmc_get_reserved_region(dev);
- desc.dev = dev; desc.groups = coresight_tmc_groups;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index eaa296ced167..857c77d867c5 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -686,6 +686,61 @@ static const struct etr_buf_operations etr_flat_buf_ops = { .get_data = tmc_etr_get_data_flat_buf, }; +/*
- 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,
etr_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;
- 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 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_flat_buf,
- .get_data = tmc_etr_get_data_flat_buf,
+};
/*
- tmc_etr_alloc_sg_buf: Allocate an SG buf @etr_buf. Setup the parameters
- appropriately.
@@ -813,6 +868,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) @@ -838,6 +894,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);
@@ -862,7 +919,7 @@ 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_etr_sg, has_iommu, has_etr_resrv_mem; bool has_sg, has_catu; struct etr_buf *etr_buf; struct device *dev = &drvdata->csdev->dev;
@@ -870,6 +927,7 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata, 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_etr_resrv_mem = tmc_etr_has_cap(drvdata, TMC_ETR_RESRV_MEM);
has_sg = has_catu || has_etr_sg; @@ -891,6 +949,12 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata, * Fallback to available mechanisms. * */
- if (has_etr_resrv_mem) {
rc = tmc_etr_mode_alloc_buf(ETR_MODE_RESRV, drvdata,
etr_buf, node, pages);
if (!rc)
goto done;
- }
Does this mean that you can _only_ use reserved memory if it's specified in the device tree? I'm not sure what all the use cases might be, but would it be better if you could still use Coresight normally if you don't want the panic support? For example if the reserved size was smaller than a user wants.
That also makes me wonder if there should be some subset of CS_MODE_SYSFS, where it's sysfs mode, but it's also using the reserved buffer, so it supports the panic save stuff. Otherwise you could be in sysfs mode but haven't written anything into the reserved buffer so setting the valid panic dump flag would be the wrong thing to do.
if (!pages && (!has_sg || has_iommu || size < SZ_1M)) rc = tmc_etr_mode_alloc_buf(ETR_MODE_FLAT, drvdata, @@ -901,6 +965,7 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata, if (rc && has_catu) rc = tmc_etr_mode_alloc_buf(ETR_MODE_CATU, drvdata, etr_buf, node, pages); +done: if (rc) { kfree(etr_buf); return ERR_PTR(rc); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 01c0382a29c0..3c344a3a8953 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -126,6 +126,8 @@ enum tmc_mem_intf_width {
- so we have to rely on PID of the IP to detect the functionality.
*/ #define TMC_ETR_SAVE_RESTORE (0x1U << 2) +/* TMC ETR to use reserved memory for trace buffer*/ +#define TMC_ETR_RESRV_MEM (0x1U << 3) /* Coresight SoC-600 TMC-ETR unadvertised capabilities */ #define CORESIGHT_SOC_600_ETR_CAPS \ @@ -135,6 +137,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_RESRV, /* Use reserved region contiguous buffer */
}; struct etr_buf_operations; @@ -163,6 +166,17 @@ struct etr_buf { void *private; }; +/**
- @paddr : Start address of reserved memory region.
- @vaddr : Corresponding CPU virtual address.
- @size : Size of reserved memory region.
- */
+struct tmc_resrv_buf {
- phys_addr_t paddr;
- void *vaddr;
- size_t size;
+};
/**
- struct tmc_drvdata - specifics associated to an TMC component
- @base: memory mapped base address for this component.
@@ -187,6 +201,7 @@ struct etr_buf {
- @idr_mutex: Access serialisation for idr.
- @sysfs_buf: SYSFS buffer for ETR.
- @perf_buf: PERF buffer for ETR.
*/
- @resrv_buf: Reserved Memory for trace data buffer. Used by ETR/ETF.
struct tmc_drvdata { void __iomem *base; @@ -211,6 +226,7 @@ struct tmc_drvdata { struct mutex idr_mutex; struct etr_buf *sysfs_buf; struct etr_buf *perf_buf;
- struct tmc_resrv_buf resrv_buf;
}; struct etr_buf_operations {