Skip to content

Commit 91a2086

Browse files
Linu CherianSuzuki K Poulose
authored andcommitted
coresight: tmc-etr: Add support to use reserved trace memory
Add support to use reserved memory for coresight ETR trace buffer. Introduce a new ETR buffer mode called ETR_MODE_RESRV, which becomes available when ETR device tree node is supplied with a valid reserved memory region. ETR_MODE_RESRV can be selected only by explicit user request. $ echo resrv >/sys/bus/coresight/devices/tmc_etr<N>/buf_mode_preferred Signed-off-by: Anil Kumar Reddy <[email protected]> Signed-off-by: Linu Cherian <[email protected]> Reviewed-by: James Clark <[email protected]> Signed-off-by: Suzuki K Poulose <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 87b8166 commit 91a2086

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

drivers/hwtracing/coresight/coresight-tmc-core.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/spinlock.h>
2424
#include <linux/pm_runtime.h>
2525
#include <linux/of.h>
26+
#include <linux/of_address.h>
2627
#include <linux/coresight.h>
2728
#include <linux/amba/bus.h>
2829
#include <linux/platform_device.h>
@@ -398,6 +399,53 @@ static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata)
398399

399400
static const struct amba_id tmc_ids[];
400401

402+
static int of_tmc_get_reserved_resource_by_name(struct device *dev,
403+
const char *name,
404+
struct resource *res)
405+
{
406+
int index, rc = -ENODEV;
407+
struct device_node *node;
408+
409+
if (!is_of_node(dev->fwnode))
410+
return -ENODEV;
411+
412+
index = of_property_match_string(dev->of_node, "memory-region-names",
413+
name);
414+
if (index < 0)
415+
return rc;
416+
417+
node = of_parse_phandle(dev->of_node, "memory-region", index);
418+
if (!node)
419+
return rc;
420+
421+
if (!of_address_to_resource(node, 0, res) &&
422+
res->start != 0 && resource_size(res) != 0)
423+
rc = 0;
424+
of_node_put(node);
425+
426+
return rc;
427+
}
428+
429+
static void tmc_get_reserved_region(struct device *parent)
430+
{
431+
struct tmc_drvdata *drvdata = dev_get_drvdata(parent);
432+
struct resource res;
433+
434+
if (of_tmc_get_reserved_resource_by_name(parent, "tracedata", &res))
435+
return;
436+
437+
drvdata->resrv_buf.vaddr = memremap(res.start,
438+
resource_size(&res),
439+
MEMREMAP_WC);
440+
if (IS_ERR_OR_NULL(drvdata->resrv_buf.vaddr)) {
441+
dev_err(parent, "Reserved trace buffer mapping failed\n");
442+
return;
443+
}
444+
445+
drvdata->resrv_buf.paddr = res.start;
446+
drvdata->resrv_buf.size = resource_size(&res);
447+
}
448+
401449
/* Detect and initialise the capabilities of a TMC ETR */
402450
static int tmc_etr_setup_caps(struct device *parent, u32 devid,
403451
struct csdev_access *access)
@@ -508,6 +556,8 @@ static int __tmc_probe(struct device *dev, struct resource *res)
508556
drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
509557
}
510558

559+
tmc_get_reserved_region(dev);
560+
511561
desc.dev = dev;
512562

513563
switch (drvdata->config_type) {

drivers/hwtracing/coresight/coresight-tmc-etr.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct etr_buf_hw {
3030
bool has_iommu;
3131
bool has_etr_sg;
3232
bool has_catu;
33+
bool has_resrv;
3334
};
3435

3536
/*
@@ -695,6 +696,75 @@ static const struct etr_buf_operations etr_flat_buf_ops = {
695696
.get_data = tmc_etr_get_data_flat_buf,
696697
};
697698

699+
/*
700+
* tmc_etr_alloc_resrv_buf: Allocate a contiguous DMA buffer from reserved region.
701+
*/
702+
static int tmc_etr_alloc_resrv_buf(struct tmc_drvdata *drvdata,
703+
struct etr_buf *etr_buf, int node,
704+
void **pages)
705+
{
706+
struct etr_flat_buf *resrv_buf;
707+
struct device *real_dev = drvdata->csdev->dev.parent;
708+
709+
/* We cannot reuse existing pages for resrv buf */
710+
if (pages)
711+
return -EINVAL;
712+
713+
resrv_buf = kzalloc(sizeof(*resrv_buf), GFP_KERNEL);
714+
if (!resrv_buf)
715+
return -ENOMEM;
716+
717+
resrv_buf->daddr = dma_map_resource(real_dev, drvdata->resrv_buf.paddr,
718+
drvdata->resrv_buf.size,
719+
DMA_FROM_DEVICE, 0);
720+
if (dma_mapping_error(real_dev, resrv_buf->daddr)) {
721+
dev_err(real_dev, "failed to map source buffer address\n");
722+
kfree(resrv_buf);
723+
return -ENOMEM;
724+
}
725+
726+
resrv_buf->vaddr = drvdata->resrv_buf.vaddr;
727+
resrv_buf->size = etr_buf->size = drvdata->resrv_buf.size;
728+
resrv_buf->dev = &drvdata->csdev->dev;
729+
etr_buf->hwaddr = resrv_buf->daddr;
730+
etr_buf->mode = ETR_MODE_RESRV;
731+
etr_buf->private = resrv_buf;
732+
return 0;
733+
}
734+
735+
static void tmc_etr_free_resrv_buf(struct etr_buf *etr_buf)
736+
{
737+
struct etr_flat_buf *resrv_buf = etr_buf->private;
738+
739+
if (resrv_buf && resrv_buf->daddr) {
740+
struct device *real_dev = resrv_buf->dev->parent;
741+
742+
dma_unmap_resource(real_dev, resrv_buf->daddr,
743+
resrv_buf->size, DMA_FROM_DEVICE, 0);
744+
}
745+
kfree(resrv_buf);
746+
}
747+
748+
static void tmc_etr_sync_resrv_buf(struct etr_buf *etr_buf, u64 rrp, u64 rwp)
749+
{
750+
/*
751+
* Adjust the buffer to point to the beginning of the trace data
752+
* and update the available trace data.
753+
*/
754+
etr_buf->offset = rrp - etr_buf->hwaddr;
755+
if (etr_buf->full)
756+
etr_buf->len = etr_buf->size;
757+
else
758+
etr_buf->len = rwp - rrp;
759+
}
760+
761+
static const struct etr_buf_operations etr_resrv_buf_ops = {
762+
.alloc = tmc_etr_alloc_resrv_buf,
763+
.free = tmc_etr_free_resrv_buf,
764+
.sync = tmc_etr_sync_resrv_buf,
765+
.get_data = tmc_etr_get_data_flat_buf,
766+
};
767+
698768
/*
699769
* tmc_etr_alloc_sg_buf: Allocate an SG buf @etr_buf. Setup the parameters
700770
* appropriately.
@@ -801,6 +871,7 @@ static const struct etr_buf_operations *etr_buf_ops[] = {
801871
[ETR_MODE_FLAT] = &etr_flat_buf_ops,
802872
[ETR_MODE_ETR_SG] = &etr_sg_buf_ops,
803873
[ETR_MODE_CATU] = NULL,
874+
[ETR_MODE_RESRV] = &etr_resrv_buf_ops
804875
};
805876

806877
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,
826897
case ETR_MODE_FLAT:
827898
case ETR_MODE_ETR_SG:
828899
case ETR_MODE_CATU:
900+
case ETR_MODE_RESRV:
829901
if (etr_buf_ops[mode] && etr_buf_ops[mode]->alloc)
830902
rc = etr_buf_ops[mode]->alloc(drvdata, etr_buf,
831903
node, pages);
@@ -844,6 +916,7 @@ static void get_etr_buf_hw(struct device *dev, struct etr_buf_hw *buf_hw)
844916
buf_hw->has_iommu = iommu_get_domain_for_dev(dev->parent);
845917
buf_hw->has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
846918
buf_hw->has_catu = !!tmc_etr_get_catu_device(drvdata);
919+
buf_hw->has_resrv = tmc_has_reserved_buffer(drvdata);
847920
}
848921

849922
static bool etr_can_use_flat_mode(struct etr_buf_hw *buf_hw, ssize_t etr_buf_size)
@@ -1831,6 +1904,7 @@ static const char *const buf_modes_str[] = {
18311904
[ETR_MODE_FLAT] = "flat",
18321905
[ETR_MODE_ETR_SG] = "tmc-sg",
18331906
[ETR_MODE_CATU] = "catu",
1907+
[ETR_MODE_RESRV] = "resrv",
18341908
[ETR_MODE_AUTO] = "auto",
18351909
};
18361910

@@ -1849,6 +1923,9 @@ static ssize_t buf_modes_available_show(struct device *dev,
18491923
if (buf_hw.has_catu)
18501924
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_CATU]);
18511925

1926+
if (buf_hw.has_resrv)
1927+
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_RESRV]);
1928+
18521929
size += sysfs_emit_at(buf, size, "\n");
18531930
return size;
18541931
}
@@ -1876,6 +1953,8 @@ static ssize_t buf_mode_preferred_store(struct device *dev,
18761953
drvdata->etr_mode = ETR_MODE_ETR_SG;
18771954
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_CATU]) && buf_hw.has_catu)
18781955
drvdata->etr_mode = ETR_MODE_CATU;
1956+
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_RESRV]) && buf_hw.has_resrv)
1957+
drvdata->etr_mode = ETR_MODE_RESRV;
18791958
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_AUTO]))
18801959
drvdata->etr_mode = ETR_MODE_AUTO;
18811960
else

drivers/hwtracing/coresight/coresight-tmc.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ enum etr_mode {
135135
ETR_MODE_FLAT, /* Uses contiguous flat buffer */
136136
ETR_MODE_ETR_SG, /* Uses in-built TMC ETR SG mechanism */
137137
ETR_MODE_CATU, /* Use SG mechanism in CATU */
138+
ETR_MODE_RESRV, /* Use reserved region contiguous buffer */
138139
ETR_MODE_AUTO, /* Use the default mechanism */
139140
};
140141

@@ -164,6 +165,17 @@ struct etr_buf {
164165
void *private;
165166
};
166167

168+
/**
169+
* @paddr : Start address of reserved memory region.
170+
* @vaddr : Corresponding CPU virtual address.
171+
* @size : Size of reserved memory region.
172+
*/
173+
struct tmc_resrv_buf {
174+
phys_addr_t paddr;
175+
void *vaddr;
176+
size_t size;
177+
};
178+
167179
/**
168180
* struct tmc_drvdata - specifics associated to an TMC component
169181
* @pclk: APB clock if present, otherwise NULL
@@ -189,6 +201,10 @@ struct etr_buf {
189201
* @idr_mutex: Access serialisation for idr.
190202
* @sysfs_buf: SYSFS buffer for ETR.
191203
* @perf_buf: PERF buffer for ETR.
204+
* @resrv_buf: Used by ETR as hardware trace buffer and for trace data
205+
* retention (after crash) only when ETR_MODE_RESRV buffer
206+
* mode is enabled. Used by ETF for trace data retention
207+
* (after crash) by default.
192208
*/
193209
struct tmc_drvdata {
194210
struct clk *pclk;
@@ -214,6 +230,7 @@ struct tmc_drvdata {
214230
struct mutex idr_mutex;
215231
struct etr_buf *sysfs_buf;
216232
struct etr_buf *perf_buf;
233+
struct tmc_resrv_buf resrv_buf;
217234
};
218235

219236
struct etr_buf_operations {
@@ -331,6 +348,14 @@ tmc_sg_table_buf_size(struct tmc_sg_table *sg_table)
331348
return (unsigned long)sg_table->data_pages.nr_pages << PAGE_SHIFT;
332349
}
333350

351+
static inline bool tmc_has_reserved_buffer(struct tmc_drvdata *drvdata)
352+
{
353+
if (drvdata->resrv_buf.vaddr &&
354+
drvdata->resrv_buf.size)
355+
return true;
356+
return false;
357+
}
358+
334359
struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);
335360

336361
void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);

0 commit comments

Comments
 (0)