Skip to content

Commit 6b21a3e

Browse files
coresight: tmc: make sysFS and Perf mode mutually exclusive
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@linaro.org> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit b217601e9adce4d2dccc95a9e6814bdbf5a4a815)
1 parent 29b1d26 commit 6b21a3e

2 files changed

Lines changed: 117 additions & 5 deletions

File tree

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

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
111111
CS_LOCK(drvdata->base);
112112
}
113113

114-
static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
114+
static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
115115
{
116116
int ret = 0;
117117
bool used = false;
@@ -185,6 +185,54 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
185185
return ret;
186186
}
187187

188+
static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
189+
{
190+
int ret = 0;
191+
long val;
192+
unsigned long flags;
193+
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
194+
195+
/* This shouldn't be happening */
196+
if (WARN_ON(mode != CS_MODE_PERF))
197+
return -EINVAL;
198+
199+
spin_lock_irqsave(&drvdata->spinlock, flags);
200+
if (drvdata->reading) {
201+
ret = -EINVAL;
202+
goto out;
203+
}
204+
205+
val = local_xchg(&drvdata->mode, mode);
206+
/*
207+
* In Perf mode there can be only one writer per sink. There
208+
* is also no need to continue if the ETB/ETR is already operated
209+
* from sysFS.
210+
*/
211+
if (val != CS_MODE_DISABLED) {
212+
ret = -EINVAL;
213+
goto out;
214+
}
215+
216+
tmc_etb_enable_hw(drvdata);
217+
out:
218+
spin_unlock_irqrestore(&drvdata->spinlock, flags);
219+
220+
return ret;
221+
}
222+
223+
static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
224+
{
225+
switch (mode) {
226+
case CS_MODE_SYSFS:
227+
return tmc_enable_etf_sink_sysfs(csdev, mode);
228+
case CS_MODE_PERF:
229+
return tmc_enable_etf_sink_perf(csdev, mode);
230+
}
231+
232+
/* We shouldn't be here */
233+
return -EINVAL;
234+
}
235+
188236
static void tmc_disable_etf_sink(struct coresight_device *csdev)
189237
{
190238
long val;
@@ -267,6 +315,7 @@ const struct coresight_ops tmc_etf_cs_ops = {
267315

268316
int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
269317
{
318+
long val;
270319
enum tmc_mode mode;
271320
int ret = 0;
272321
unsigned long flags;
@@ -290,14 +339,21 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
290339
goto out;
291340
}
292341

342+
val = local_read(&drvdata->mode);
343+
/* Don't interfere if operated from Perf */
344+
if (val == CS_MODE_PERF) {
345+
ret = -EINVAL;
346+
goto out;
347+
}
348+
293349
/* If drvdata::buf is NULL the trace data has been read already */
294350
if (drvdata->buf == NULL) {
295351
ret = -EINVAL;
296352
goto out;
297353
}
298354

299355
/* Disable the TMC if need be */
300-
if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
356+
if (val == CS_MODE_SYSFS)
301357
tmc_etb_disable_hw(drvdata);
302358

303359
drvdata->reading = true;

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

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
8787
CS_LOCK(drvdata->base);
8888
}
8989

90-
static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
90+
static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
9191
{
9292
int ret = 0;
9393
bool used = false;
@@ -165,6 +165,54 @@ static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
165165
return ret;
166166
}
167167

168+
static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 mode)
169+
{
170+
int ret = 0;
171+
long val;
172+
unsigned long flags;
173+
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
174+
175+
/* This shouldn't be happening */
176+
if (WARN_ON(mode != CS_MODE_PERF))
177+
return -EINVAL;
178+
179+
spin_lock_irqsave(&drvdata->spinlock, flags);
180+
if (drvdata->reading) {
181+
ret = -EINVAL;
182+
goto out;
183+
}
184+
185+
val = local_xchg(&drvdata->mode, mode);
186+
/*
187+
* In Perf mode there can be only one writer per sink. There
188+
* is also no need to continue if the ETR is already operated
189+
* from sysFS.
190+
*/
191+
if (val != CS_MODE_DISABLED) {
192+
ret = -EINVAL;
193+
goto out;
194+
}
195+
196+
tmc_etr_enable_hw(drvdata);
197+
out:
198+
spin_unlock_irqrestore(&drvdata->spinlock, flags);
199+
200+
return ret;
201+
}
202+
203+
static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
204+
{
205+
switch (mode) {
206+
case CS_MODE_SYSFS:
207+
return tmc_enable_etr_sink_sysfs(csdev, mode);
208+
case CS_MODE_PERF:
209+
return tmc_enable_etr_sink_perf(csdev, mode);
210+
}
211+
212+
/* We shouldn't be here */
213+
return -EINVAL;
214+
}
215+
168216
static void tmc_disable_etr_sink(struct coresight_device *csdev)
169217
{
170218
long val;
@@ -199,6 +247,7 @@ const struct coresight_ops tmc_etr_cs_ops = {
199247
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
200248
{
201249
int ret = 0;
250+
long val;
202251
unsigned long flags;
203252

204253
/* config types are set a boot time and never change */
@@ -211,21 +260,28 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
211260
goto out;
212261
}
213262

263+
val = local_read(&drvdata->mode);
264+
/* Don't interfere if operated from Perf */
265+
if (val == CS_MODE_PERF) {
266+
ret = -EINVAL;
267+
goto out;
268+
}
269+
214270
/* If drvdata::buf is NULL the trace data has been read already */
215271
if (drvdata->buf == NULL) {
216272
ret = -EINVAL;
217273
goto out;
218274
}
219275

220276
/* Disable the TMC if need be */
221-
if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
277+
if (val == CS_MODE_SYSFS)
222278
tmc_etr_disable_hw(drvdata);
223279

224280
drvdata->reading = true;
225281
out:
226282
spin_unlock_irqrestore(&drvdata->spinlock, flags);
227283

228-
return 0;
284+
return ret;
229285
}
230286

231287
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)

0 commit comments

Comments
 (0)