On 25 April 2016 at 08:32, Suzuki K Poulose <suzuki.poul...@arm.com> wrote: > On 22/04/16 18:14, Mathieu Poirier wrote: >> >> The sysFS and Perf access methods can't be allowed to interfere >> with one another. As such introducing guards to access >> functions that prevents moving forward if a TMC is already >> being used. >> >> Signed-off-by: Mathieu Poirier <mathieu.poir...@linaro.org> >> --- >> drivers/hwtracing/coresight/coresight-tmc-etf.c | 60 >> +++++++++++++++++++++- >> drivers/hwtracing/coresight/coresight-tmc-etr.c | 68 >> +++++++++++++++++++++++-- >> 2 files changed, 121 insertions(+), 7 deletions(-) >> >> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c >> b/drivers/hwtracing/coresight/coresight-tmc-etf.c >> index 25fad93b68d4..cc88c15ba45c 100644 >> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c >> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c >> @@ -111,7 +111,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata >> *drvdata) >> CS_LOCK(drvdata->base); >> } >> >> -static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode) >> +static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 >> mode) >> { >> bool used = false; >> char *buf = NULL; >> @@ -190,6 +190,54 @@ spin_unlock: >> return 0; >> } >> >> +static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 >> mode) >> +{ >> + int ret = 0; >> + long val; >> + unsigned long flags; >> + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); >> + >> + /* This shouldn't be happening */ >> + if (WARN_ON(mode != CS_MODE_PERF)) >> + return -EINVAL; >> + >> + spin_lock_irqsave(&drvdata->spinlock, flags); >> + if (drvdata->reading) { >> + ret = -EINVAL; >> + goto out; >> + } >> + >> + val = local_xchg(&drvdata->mode, mode); >> + /* >> + * In Perf mode there can be only one writer per sink. There >> + * is also no need to continue if the ETB/ETR is already operated >> + * from sysFS. >> + */ >> + if (val != CS_MODE_DISABLED) { >> + ret = -EINVAL; >> + goto out; >> + } >> + >> + tmc_etb_enable_hw(drvdata); >> +out: >> + spin_unlock_irqrestore(&drvdata->spinlock, flags); >> + >> + return ret; >> +} >> + >> +static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode) >> +{ >> + switch (mode) { >> + case CS_MODE_SYSFS: >> + return tmc_enable_etf_sink_sysfs(csdev, mode); >> + case CS_MODE_PERF: >> + return tmc_enable_etf_sink_perf(csdev, mode); >> + } >> + >> + /* We shouldn't be here */ >> + return -EINVAL; >> +} >> + >> static void tmc_disable_etf_sink(struct coresight_device *csdev) >> { >> long val; >> @@ -272,6 +320,7 @@ const struct coresight_ops tmc_etf_cs_ops = { >> >> int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) >> { >> + long val; >> enum tmc_mode mode; >> int ret = 0; >> unsigned long flags; >> @@ -290,6 +339,13 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) >> goto out; >> } >> >> + val = local_read(&drvdata->mode); >> + /* Don't interfere if operated from Perf */ >> + if (val == CS_MODE_PERF) { >> + ret = -EINVAL; >> + goto out; >> + } >> + >> /* If drvdata::buf is NULL the trace data has been read already */ >> if (drvdata->buf == NULL) { >> ret = -EINVAL; >> @@ -297,7 +353,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) >> } >> >> /* Disable the TMC if need be */ >> - if (local_read(&drvdata->mode) == CS_MODE_SYSFS) >> + if (val == CS_MODE_SYSFS) >> tmc_etb_disable_hw(drvdata); >> >> drvdata->reading = true; >> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c >> b/drivers/hwtracing/coresight/coresight-tmc-etr.c >> index 4b000f4003a2..a9a94a09186a 100644 >> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c >> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c >> @@ -87,7 +87,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata >> *drvdata) >> CS_LOCK(drvdata->base); >> } >> >> -static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode) >> +static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 >> mode) >> { >> bool used = false; >> long val; >> @@ -167,6 +167,54 @@ spin_unlock: >> return 0; >> } >> >> +static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 >> mode) >> +{ >> + int ret = 0; >> + long val; >> + unsigned long flags; >> + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); >> + >> + /* This shouldn't be happening */ >> + if (WARN_ON(mode != CS_MODE_PERF)) >> + return -EINVAL; >> + >> + spin_lock_irqsave(&drvdata->spinlock, flags); >> + if (drvdata->reading) { >> + ret = -EINVAL; >> + goto out; >> + } >> + >> + val = local_xchg(&drvdata->mode, mode); >> + /* >> + * In Perf mode there can be only one writer per sink. There >> + * is also no need to continue if the ETR is already operated >> + * from sysFS. >> + */ >> + if (val != CS_MODE_DISABLED) { > > > Could val be CS_MODE_PERF ? In other words, should we be checking : > if (val == CS_MODE_SYSFS) instead ?
If we check for CS_MODE_SYSFS we also have to check for CS_MODE_PERF, which is two checks rather than a single one with the current solution. Mathieu > > Suzuki