aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwtracing
diff options
context:
space:
mode:
authorMathieu Poirier <mathieu.poirier@linaro.org>2016-05-03 13:33:56 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-05-03 17:59:30 -0400
commitb217601e9adce4d2dccc95a9e6814bdbf5a4a815 (patch)
treea6c1cd5a50bfd30848084c5773f243dd473a162b /drivers/hwtracing
parenta40318fb01e98e72175bd9891208541148633d42 (diff)
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>
Diffstat (limited to 'drivers/hwtracing')
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etf.c60
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c62
2 files changed, 117 insertions, 5 deletions
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index b5e5e6ac67eb..b11c52be54a9 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)
111 CS_LOCK(drvdata->base); 111 CS_LOCK(drvdata->base);
112} 112}
113 113
114static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode) 114static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
115{ 115{
116 int ret = 0; 116 int ret = 0;
117 bool used = false; 117 bool used = false;
@@ -185,6 +185,54 @@ out:
185 return ret; 185 return ret;
186} 186}
187 187
188static 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);
217out:
218 spin_unlock_irqrestore(&drvdata->spinlock, flags);
219
220 return ret;
221}
222
223static 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
188static void tmc_disable_etf_sink(struct coresight_device *csdev) 236static void tmc_disable_etf_sink(struct coresight_device *csdev)
189{ 237{
190 long val; 238 long val;
@@ -267,6 +315,7 @@ const struct coresight_ops tmc_etf_cs_ops = {
267 315
268int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) 316int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
269{ 317{
318 long val;
270 enum tmc_mode mode; 319 enum tmc_mode mode;
271 int ret = 0; 320 int ret = 0;
272 unsigned long flags; 321 unsigned long flags;
@@ -290,6 +339,13 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
290 goto out; 339 goto out;
291 } 340 }
292 341
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
293 /* If drvdata::buf is NULL the trace data has been read already */ 349 /* If drvdata::buf is NULL the trace data has been read already */
294 if (drvdata->buf == NULL) { 350 if (drvdata->buf == NULL) {
295 ret = -EINVAL; 351 ret = -EINVAL;
@@ -297,7 +353,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
297 } 353 }
298 354
299 /* Disable the TMC if need be */ 355 /* Disable the TMC if need be */
300 if (local_read(&drvdata->mode) == CS_MODE_SYSFS) 356 if (val == CS_MODE_SYSFS)
301 tmc_etb_disable_hw(drvdata); 357 tmc_etb_disable_hw(drvdata);
302 358
303 drvdata->reading = true; 359 drvdata->reading = true;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 7208584d0da7..847d1b5f2c13 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)
87 CS_LOCK(drvdata->base); 87 CS_LOCK(drvdata->base);
88} 88}
89 89
90static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode) 90static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
91{ 91{
92 int ret = 0; 92 int ret = 0;
93 bool used = false; 93 bool used = false;
@@ -165,6 +165,54 @@ out:
165 return ret; 165 return ret;
166} 166}
167 167
168static 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);
197out:
198 spin_unlock_irqrestore(&drvdata->spinlock, flags);
199
200 return ret;
201}
202
203static 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
168static void tmc_disable_etr_sink(struct coresight_device *csdev) 216static void tmc_disable_etr_sink(struct coresight_device *csdev)
169{ 217{
170 long val; 218 long val;
@@ -199,6 +247,7 @@ const struct coresight_ops tmc_etr_cs_ops = {
199int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) 247int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
200{ 248{
201 int ret = 0; 249 int ret = 0;
250 long val;
202 unsigned long flags; 251 unsigned long flags;
203 252
204 /* config types are set a boot time and never change */ 253 /* config types are set a boot time and never change */
@@ -211,6 +260,13 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
211 goto out; 260 goto out;
212 } 261 }
213 262
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
214 /* If drvdata::buf is NULL the trace data has been read already */ 270 /* If drvdata::buf is NULL the trace data has been read already */
215 if (drvdata->buf == NULL) { 271 if (drvdata->buf == NULL) {
216 ret = -EINVAL; 272 ret = -EINVAL;
@@ -218,14 +274,14 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
218 } 274 }
219 275
220 /* Disable the TMC if need be */ 276 /* Disable the TMC if need be */
221 if (local_read(&drvdata->mode) == CS_MODE_SYSFS) 277 if (val == CS_MODE_SYSFS)
222 tmc_etr_disable_hw(drvdata); 278 tmc_etr_disable_hw(drvdata);
223 279
224 drvdata->reading = true; 280 drvdata->reading = true;
225out: 281out:
226 spin_unlock_irqrestore(&drvdata->spinlock, flags); 282 spin_unlock_irqrestore(&drvdata->spinlock, flags);
227 283
228 return 0; 284 return ret;
229} 285}
230 286
231int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) 287int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)