hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/hwtracing/coresight/coresight-tmc-etf.c
....@@ -37,7 +37,7 @@
3737
3838 static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
3939 {
40
- int rc = coresight_claim_device(drvdata->base);
40
+ int rc = coresight_claim_device(drvdata->csdev);
4141
4242 if (rc)
4343 return rc;
....@@ -50,23 +50,20 @@
5050 {
5151 char *bufp;
5252 u32 read_data, lost;
53
- int i;
5453
5554 /* Check if the buffer wrapped around. */
5655 lost = readl_relaxed(drvdata->base + TMC_STS) & TMC_STS_FULL;
5756 bufp = drvdata->buf;
5857 drvdata->len = 0;
5958 while (1) {
60
- for (i = 0; i < drvdata->memwidth; i++) {
61
- read_data = readl_relaxed(drvdata->base + TMC_RRD);
62
- if (read_data == 0xFFFFFFFF)
63
- goto done;
64
- memcpy(bufp, &read_data, 4);
65
- bufp += 4;
66
- drvdata->len += 4;
67
- }
59
+ read_data = readl_relaxed(drvdata->base + TMC_RRD);
60
+ if (read_data == 0xFFFFFFFF)
61
+ break;
62
+ memcpy(bufp, &read_data, 4);
63
+ bufp += 4;
64
+ drvdata->len += 4;
6865 }
69
-done:
66
+
7067 if (lost)
7168 coresight_insert_barrier_packet(drvdata->buf);
7269 return;
....@@ -90,8 +87,8 @@
9087
9188 static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
9289 {
93
- coresight_disclaim_device(drvdata->base);
9490 __tmc_etb_disable_hw(drvdata);
91
+ coresight_disclaim_device(drvdata->csdev);
9592 }
9693
9794 static void __tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
....@@ -112,7 +109,7 @@
112109
113110 static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
114111 {
115
- int rc = coresight_claim_device(drvdata->base);
112
+ int rc = coresight_claim_device(drvdata->csdev);
116113
117114 if (rc)
118115 return rc;
....@@ -123,11 +120,13 @@
123120
124121 static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
125122 {
123
+ struct coresight_device *csdev = drvdata->csdev;
124
+
126125 CS_UNLOCK(drvdata->base);
127126
128127 tmc_flush_and_stop(drvdata);
129128 tmc_disable_hw(drvdata);
130
- coresight_disclaim_device_unlocked(drvdata->base);
129
+ coresight_disclaim_device_unlocked(csdev);
131130 CS_LOCK(drvdata->base);
132131 }
133132
....@@ -226,9 +225,11 @@
226225 static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
227226 {
228227 int ret = 0;
228
+ pid_t pid;
229229 unsigned long flags;
230230 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
231231 struct perf_output_handle *handle = data;
232
+ struct cs_buffers *buf = etm_perf_sink_config(handle);
232233
233234 spin_lock_irqsave(&drvdata->spinlock, flags);
234235 do {
....@@ -236,18 +237,39 @@
236237 if (drvdata->reading)
237238 break;
238239 /*
239
- * In Perf mode there can be only one writer per sink. There
240
- * is also no need to continue if the ETB/ETF is already
241
- * operated from sysFS.
240
+ * No need to continue if the ETB/ETF is already operated
241
+ * from sysFS.
242242 */
243
- if (drvdata->mode != CS_MODE_DISABLED)
243
+ if (drvdata->mode == CS_MODE_SYSFS) {
244
+ ret = -EBUSY;
244245 break;
246
+ }
247
+
248
+ /* Get a handle on the pid of the process to monitor */
249
+ pid = buf->pid;
250
+
251
+ if (drvdata->pid != -1 && drvdata->pid != pid) {
252
+ ret = -EBUSY;
253
+ break;
254
+ }
245255
246256 ret = tmc_set_etf_buffer(csdev, handle);
247257 if (ret)
248258 break;
259
+
260
+ /*
261
+ * No HW configuration is needed if the sink is already in
262
+ * use for this session.
263
+ */
264
+ if (drvdata->pid == pid) {
265
+ atomic_inc(csdev->refcnt);
266
+ break;
267
+ }
268
+
249269 ret = tmc_etb_enable_hw(drvdata);
250270 if (!ret) {
271
+ /* Associate with monitored process. */
272
+ drvdata->pid = pid;
251273 drvdata->mode = CS_MODE_PERF;
252274 atomic_inc(csdev->refcnt);
253275 }
....@@ -261,7 +283,6 @@
261283 u32 mode, void *data)
262284 {
263285 int ret;
264
- struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
265286
266287 switch (mode) {
267288 case CS_MODE_SYSFS:
....@@ -279,7 +300,7 @@
279300 if (ret)
280301 return ret;
281302
282
- dev_dbg(drvdata->dev, "TMC-ETB/ETF enabled\n");
303
+ dev_dbg(&csdev->dev, "TMC-ETB/ETF enabled\n");
283304 return 0;
284305 }
285306
....@@ -303,11 +324,13 @@
303324 /* Complain if we (somehow) got out of sync */
304325 WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
305326 tmc_etb_disable_hw(drvdata);
327
+ /* Dissociate from monitored process. */
328
+ drvdata->pid = -1;
306329 drvdata->mode = CS_MODE_DISABLED;
307330
308331 spin_unlock_irqrestore(&drvdata->spinlock, flags);
309332
310
- dev_dbg(drvdata->dev, "TMC-ETB/ETF disabled\n");
333
+ dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n");
311334 return 0;
312335 }
313336
....@@ -337,7 +360,7 @@
337360 spin_unlock_irqrestore(&drvdata->spinlock, flags);
338361
339362 if (first_enable)
340
- dev_dbg(drvdata->dev, "TMC-ETF enabled\n");
363
+ dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
341364 return ret;
342365 }
343366
....@@ -362,23 +385,24 @@
362385 spin_unlock_irqrestore(&drvdata->spinlock, flags);
363386
364387 if (last_disable)
365
- dev_dbg(drvdata->dev, "TMC-ETF disabled\n");
388
+ dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
366389 }
367390
368391 static void *tmc_alloc_etf_buffer(struct coresight_device *csdev,
369392 struct perf_event *event, void **pages,
370393 int nr_pages, bool overwrite)
371394 {
372
- int node, cpu = event->cpu;
395
+ int node;
373396 struct cs_buffers *buf;
374397
375
- node = (cpu == -1) ? NUMA_NO_NODE : cpu_to_node(cpu);
398
+ node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
376399
377400 /* Allocate memory structure for interaction with Perf */
378401 buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
379402 if (!buf)
380403 return NULL;
381404
405
+ buf->pid = task_pid_nr(event->owner);
382406 buf->snapshot = overwrite;
383407 buf->nr_pages = nr_pages;
384408 buf->data_pages = pages;
....@@ -427,7 +451,7 @@
427451 u32 *buf_ptr;
428452 u64 read_ptr, write_ptr;
429453 u32 status;
430
- unsigned long offset, to_read, flags;
454
+ unsigned long offset, to_read = 0, flags;
431455 struct cs_buffers *buf = sink_config;
432456 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
433457
....@@ -439,6 +463,11 @@
439463 return 0;
440464
441465 spin_lock_irqsave(&drvdata->spinlock, flags);
466
+
467
+ /* Don't do anything if another tracer is using this sink */
468
+ if (atomic_read(csdev->refcnt) != 1)
469
+ goto out;
470
+
442471 CS_UNLOCK(drvdata->base);
443472
444473 tmc_flush_and_stop(drvdata);
....@@ -494,7 +523,7 @@
494523
495524 cur = buf->cur;
496525 offset = buf->offset;
497
- barrier = barrier_pkt;
526
+ barrier = coresight_barrier_pkt;
498527
499528 /* for every byte to read */
500529 for (i = 0; i < to_read; i += 4) {
....@@ -515,12 +544,17 @@
515544 }
516545 }
517546
518
- /* In snapshot mode we have to update the head */
519
- if (buf->snapshot) {
520
- handle->head = (cur * PAGE_SIZE) + offset;
521
- to_read = buf->nr_pages << PAGE_SHIFT;
522
- }
547
+ /*
548
+ * In snapshot mode we simply increment the head by the number of byte
549
+ * that were written. User space function cs_etm_find_snapshot() will
550
+ * figure out how many bytes to get from the AUX buffer based on the
551
+ * position of the head.
552
+ */
553
+ if (buf->snapshot)
554
+ handle->head += to_read;
555
+
523556 CS_LOCK(drvdata->base);
557
+out:
524558 spin_unlock_irqrestore(&drvdata->spinlock, flags);
525559
526560 return to_read;
....@@ -566,13 +600,6 @@
566600 goto out;
567601 }
568602
569
- /* There is no point in reading a TMC in HW FIFO mode */
570
- mode = readl_relaxed(drvdata->base + TMC_MODE);
571
- if (mode != TMC_MODE_CIRCULAR_BUFFER) {
572
- ret = -EINVAL;
573
- goto out;
574
- }
575
-
576603 /* Don't interfere if operated from Perf */
577604 if (drvdata->mode == CS_MODE_PERF) {
578605 ret = -EINVAL;
....@@ -586,8 +613,15 @@
586613 }
587614
588615 /* Disable the TMC if need be */
589
- if (drvdata->mode == CS_MODE_SYSFS)
616
+ if (drvdata->mode == CS_MODE_SYSFS) {
617
+ /* There is no point in reading a TMC in HW FIFO mode */
618
+ mode = readl_relaxed(drvdata->base + TMC_MODE);
619
+ if (mode != TMC_MODE_CIRCULAR_BUFFER) {
620
+ ret = -EINVAL;
621
+ goto out;
622
+ }
590623 __tmc_etb_disable_hw(drvdata);
624
+ }
591625
592626 drvdata->reading = true;
593627 out: