Re: [PATCH V3 13/18] coresight: tmc: make sysFS and Perf mode mutually exclusive

From: Mathieu Poirier
Date: Mon Apr 25 2016 - 10:48:18 EST


On 25 April 2016 at 08:32, Suzuki K Poulose <Suzuki.Poulose@xxxxxxx> 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.poirier@xxxxxxxxxx>
>> ---
>> 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