* Introduce a new mode CS_MODE_READ_PREVBOOT for reading tracedata captured in previous boot.
* Add special handlers for preparing ETR/ETF for this special mode
* User can read the trace data as below
For example, for reading trace data from tmc_etf sink
1. cd /sys/bus/coresight/devices/tmc_etfXX/
2. Change mode to READ_PREVBOOT
#echo 1 > read_prevboot
3. Dump trace buffer data to a file,
#dd if=/dev/tmc_etrXX of=~/cstrace.bin
4. Reset back to normal mode
#echo 0 > read_prevboot
Signed-off-by: Anil Kumar Reddy areddy3@marvell.com Signed-off-by: Tanmay Jagdale tanmay@marvell.com Signed-off-by: Linu Cherian lcherian@marvell.com --- drivers/hwtracing/coresight/coresight-priv.h | 1 + .../hwtracing/coresight/coresight-tmc-core.c | 35 ++++++++++++ .../hwtracing/coresight/coresight-tmc-etf.c | 57 +++++++++++++++++++ .../hwtracing/coresight/coresight-tmc-etr.c | 24 ++++++++ 4 files changed, 117 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 595ce5862056..2b8b83e72849 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -86,6 +86,7 @@ enum cs_mode { CS_MODE_DISABLED, CS_MODE_SYSFS, CS_MODE_PERF, + CS_MODE_READ_PREVBOOT, /* Trace data from previous boot */ };
/** diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 0c1319851182..0a2199423c2d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -152,6 +152,10 @@ static int tmc_open(struct inode *inode, struct file *file) struct tmc_drvdata *drvdata = container_of(file->private_data, struct tmc_drvdata, miscdev);
+ /* Advertise if we are opening with a special mode */ + if (drvdata->mode == CS_MODE_READ_PREVBOOT) + dev_info(&drvdata->csdev->dev, "TMC read mode for previous boot\n"); + ret = tmc_read_prepare(drvdata); if (ret) return ret; @@ -330,9 +334,40 @@ static ssize_t buffer_size_store(struct device *dev,
static DEVICE_ATTR_RW(buffer_size);
+static ssize_t read_prevboot_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->size); +} + +static ssize_t read_prevboot_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret; + unsigned long val; + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + + if (val) + drvdata->mode = CS_MODE_READ_PREVBOOT; + else + drvdata->mode = CS_MODE_DISABLED; + + return size; +} + +static DEVICE_ATTR_RW(read_prevboot); + static struct attribute *coresight_tmc_attrs[] = { &dev_attr_trigger_cntr.attr, &dev_attr_buffer_size.attr, + &dev_attr_read_prevboot.attr, NULL, };
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 6c84b9ca3318..92699610edcd 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -627,6 +627,42 @@ const struct coresight_ops tmc_etf_cs_ops = { .panic_ops = &tmc_etf_sync_ops, };
+/* Prepare for READ_PREVBOOT mode */ +int tmc_prepare_etb_prevboot(struct tmc_drvdata *drvdata) +{ + struct tmc_register_snapshot *reg_ptr; + unsigned long flags; + u64 trace_addr; + int ret = 0; + + spin_lock_irqsave(&drvdata->spinlock, flags); + + if (!drvdata->tmc_metadata.vaddr) { + ret = -ENOMEM; + goto out; + } + + reg_ptr = drvdata->tmc_metadata.vaddr; + trace_addr = reg_ptr->trc_addr | ((u64)reg_ptr->trc_addrhi << 32); + + drvdata->buf = memremap(trace_addr, reg_ptr->size, MEMREMAP_WC); + if (IS_ERR(drvdata->buf)) { + ret = -ENOMEM; + goto out; + } + + drvdata->len = reg_ptr->size; + + if (reg_ptr->sts & 0x1) + coresight_insert_barrier_packet(drvdata->buf); + drvdata->reading = true; + + spin_unlock_irqrestore(&drvdata->spinlock, flags); + +out: + return ret; +} + int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) { enum tmc_mode mode; @@ -638,6 +674,9 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) drvdata->config_type != TMC_CONFIG_TYPE_ETF)) return -EINVAL;
+ if (drvdata->mode == CS_MODE_READ_PREVBOOT) + return tmc_prepare_etb_prevboot(drvdata); + spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) { @@ -674,6 +713,21 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
return ret; } +/* Handle READ_PREVBOOT mode */ +int tmc_unprepare_etb_prevboot(struct tmc_drvdata *drvdata) +{ + unsigned long flags; + + spin_lock_irqsave(&drvdata->spinlock, flags); + + drvdata->reading = false; + memunmap(drvdata->buf); + drvdata->buf = NULL; + + spin_unlock_irqrestore(&drvdata->spinlock, flags); + + return 0; +}
int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) { @@ -687,6 +741,9 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) drvdata->config_type != TMC_CONFIG_TYPE_ETF)) return -EINVAL;
+ if (drvdata->mode == CS_MODE_READ_PREVBOOT) + return tmc_unprepare_etb_prevboot(drvdata); + spin_lock_irqsave(&drvdata->spinlock, flags);
/* Re-enable the TMC if need be */ diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index dc6146012c8c..1a53decd887b 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1795,6 +1795,16 @@ const struct coresight_ops tmc_etr_cs_ops = { .panic_ops = &tmc_etr_sync_ops, };
+/* Prepare for READ_PREVBOOT mode */ +int tmc_prepare_etr_prevboot(struct tmc_drvdata *drvdata) +{ + /* + * TODO : Initialize the ETR buffer and status for trace data read + * using the metadata + */ + + return 0; +}
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) { @@ -1805,6 +1815,9 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) return -EINVAL;
+ if (drvdata->mode == CS_MODE_READ_PREVBOOT) + return tmc_prepare_etr_prevboot(drvdata); + spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { ret = -EBUSY; @@ -1832,6 +1845,14 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) return ret; }
+/* Handle READ_PREVBOOT mode */ +int tmc_unprepare_etr_prevboot(struct tmc_drvdata *drvdata) +{ + /* TODO */ + + return 0; +} + int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) { unsigned long flags; @@ -1841,6 +1862,9 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) return -EINVAL;
+ if (drvdata->mode == CS_MODE_READ_PREVBOOT) + return tmc_unprepare_etr_prevboot(drvdata); + spin_lock_irqsave(&drvdata->spinlock, flags);
/* RE-enable the TMC if need be */