File Index
Files and directories
Sign in
FILE

coresight-tmc-etf.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hwtracing/coresight/coresight-tmc-etf.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright(C) 2016 Linaro Limited. All rights reserved.
  4 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
  5 */
  6
  7#include <linux/atomic.h>
  8#include <linux/circ_buf.h>
  9#include <linux/coresight.h>
 10#include <linux/perf_event.h>
 11#include <linux/slab.h>
 12#include "coresight-priv.h"
 13#include "coresight-tmc.h"
 14#include "coresight-etm-perf.h"
 15
 16static int tmc_set_etf_buffer(struct coresight_device *csdev,
 17			      struct perf_output_handle *handle);
 18
 19static int __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 20{
 21	int rc = 0;
 22	u32 ffcr;
 23
 24	CS_UNLOCK(drvdata->base);
 25
 26	/* Wait for TMCSReady bit to be set */
 27	rc = tmc_wait_for_tmcready(drvdata);
 28	if (rc) {
 29		dev_err(&drvdata->csdev->dev,
 30			"Failed to enable: TMC not ready\n");
 31		CS_LOCK(drvdata->base);
 32		return rc;
 33	}
 34
 35	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
 36
 37	ffcr = TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | TMC_FFCR_FON_FLIN |
 38		TMC_FFCR_FON_TRIG_EVT | TMC_FFCR_TRIGON_TRIGIN;
 39	if (drvdata->stop_on_flush)
 40		ffcr |= TMC_FFCR_STOP_ON_FLUSH;
 41	writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
 42
 43	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
 44	tmc_enable_hw(drvdata);
 45
 46	CS_LOCK(drvdata->base);
 47	return rc;
 48}
 49
 50static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 51{
 52	int rc = coresight_claim_device(drvdata->csdev);
 53
 54	if (rc)
 55		return rc;
 56
 57	rc = __tmc_etb_enable_hw(drvdata);
 58	if (rc)
 59		coresight_disclaim_device(drvdata->csdev);
 60	return rc;
 61}
 62
 63static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
 64{
 65	char *bufp;
 66	u32 read_data, lost;
 67
 68	/* Check if the buffer wrapped around. */
 69	lost = readl_relaxed(drvdata->base + TMC_STS) & TMC_STS_FULL;
 70	bufp = drvdata->buf;
 71	drvdata->len = 0;
 72	while (1) {
 73		read_data = readl_relaxed(drvdata->base + TMC_RRD);
 74		if (read_data == 0xFFFFFFFF)
 75			break;
 76		memcpy(bufp, &read_data, 4);
 77		bufp += 4;
 78		drvdata->len += 4;
 79	}
 80
 81	if (lost)
 82		coresight_insert_barrier_packet(drvdata->buf);
 83	return;
 84}
 85
 86static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
 87{
 88	CS_UNLOCK(drvdata->base);
 89
 90	tmc_flush_and_stop(drvdata);
 91	/*
 92	 * When operating in sysFS mode the content of the buffer needs to be
 93	 * read before the TMC is disabled.
 94	 */
 95	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
 96		tmc_etb_dump_hw(drvdata);
 97	tmc_disable_hw(drvdata);
 98
 99	CS_LOCK(drvdata->base);
100}
101
102static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
103{
104	__tmc_etb_disable_hw(drvdata);
105	coresight_disclaim_device(drvdata->csdev);
106}
107
108static int __tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
109{
110	int rc = 0;
111
112	CS_UNLOCK(drvdata->base);
113
114	/* Wait for TMCSReady bit to be set */
115	rc = tmc_wait_for_tmcready(drvdata);
116	if (rc) {
117		dev_err(&drvdata->csdev->dev,
118			"Failed to enable : TMC is not ready\n");
119		CS_LOCK(drvdata->base);
120		return rc;
121	}
122
123	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
124	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
125		       drvdata->base + TMC_FFCR);
126	writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
127	tmc_enable_hw(drvdata);
128
129	CS_LOCK(drvdata->base);
130	return rc;
131}
132
133static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
134{
135	int rc = coresight_claim_device(drvdata->csdev);
136
137	if (rc)
138		return rc;
139
140	rc = __tmc_etf_enable_hw(drvdata);
141	if (rc)
142		coresight_disclaim_device(drvdata->csdev);
143	return rc;
144}
145
146static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
147{
148	struct coresight_device *csdev = drvdata->csdev;
149
150	CS_UNLOCK(drvdata->base);
151
152	tmc_flush_and_stop(drvdata);
153	tmc_disable_hw(drvdata);
154	coresight_disclaim_device_unlocked(csdev);
155	CS_LOCK(drvdata->base);
156}
157
158/*
159 * Return the available trace data in the buffer from @pos, with
160 * a maximum limit of @len, updating the @bufpp on where to
161 * find it.
162 */
163ssize_t tmc_etb_get_sysfs_trace(struct tmc_drvdata *drvdata,
164				loff_t pos, size_t len, char **bufpp)
165{
166	ssize_t actual = len;
167
168	/* Adjust the len to available size @pos */
169	if (pos + actual > drvdata->len)
170		actual = drvdata->len - pos;
171	if (actual > 0)
172		*bufpp = drvdata->buf + pos;
173	return actual;
174}
175
176static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
177{
178	int ret = 0;
179	bool used = false;
180	char *buf = NULL;
181	unsigned long flags;
182	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
183
184	/*
185	 * If we don't have a buffer release the lock and allocate memory.
186	 * Otherwise keep the lock and move along.
187	 */
188	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
189	if (!drvdata->buf) {
190		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
191
192		/* Allocating the memory here while outside of the spinlock */
193		buf = kzalloc(drvdata->size, GFP_KERNEL);
194		if (!buf)
195			return -ENOMEM;
196
197		/* Let's try again */
198		raw_spin_lock_irqsave(&drvdata->spinlock, flags);
199	}
200
201	if (drvdata->reading) {
202		ret = -EBUSY;
203		goto out;
204	}
205
206	/*
207	 * In sysFS mode we can have multiple writers per sink.  Since this
208	 * sink is already enabled no memory is needed and the HW need not be
209	 * touched.
210	 */
211	if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
212		csdev->refcnt++;
213		goto out;
214	}
215
216	/*
217	 * If drvdata::buf isn't NULL, memory was allocated for a previous
218	 * trace run but wasn't read.  If so simply zero-out the memory.
219	 * Otherwise use the memory allocated above.
220	 *
221	 * The memory is freed when users read the buffer using the
222	 * /dev/xyz.{etf|etb} interface.  See tmc_read_unprepare_etf() for
223	 * details.
224	 */
225	if (drvdata->buf) {
226		memset(drvdata->buf, 0, drvdata->size);
227	} else {
228		used = true;
229		drvdata->buf = buf;
230	}
231	ret = tmc_etb_enable_hw(drvdata);
232	if (!ret) {
233		coresight_set_mode(csdev, CS_MODE_SYSFS);
234		csdev->refcnt++;
235	} else {
236		/* Free up the buffer if we failed to enable */
237		used = false;
238	}
239out:
240	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
241
242	/* Free memory outside the spinlock if need be */
243	if (!used)
244		kfree(buf);
245
246	return ret;
247}
248
249static int tmc_enable_etf_sink_perf(struct coresight_device *csdev,
250				    struct coresight_path *path)
251{
252	int ret = 0;
253	pid_t pid;
254	unsigned long flags;
255	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
256	struct perf_output_handle *handle = path->handle;
257	struct cs_buffers *buf = etm_perf_sink_config(handle);
258
259	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
260	do {
261		ret = -EINVAL;
262		if (drvdata->reading)
263			break;
264		/*
265		 * No need to continue if the ETB/ETF is already operated
266		 * from sysFS.
267		 */
268		if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
269			ret = -EBUSY;
270			break;
271		}
272
273		/* Get a handle on the pid of the process to monitor */
274		pid = buf->pid;
275
276		if (drvdata->pid != -1 && drvdata->pid != pid) {
277			ret = -EBUSY;
278			break;
279		}
280
281		ret = tmc_set_etf_buffer(csdev, handle);
282		if (ret)
283			break;
284
285		/*
286		 * No HW configuration is needed if the sink is already in
287		 * use for this session.
288		 */
289		if (drvdata->pid == pid) {
290			csdev->refcnt++;
291			break;
292		}
293
294		ret  = tmc_etb_enable_hw(drvdata);
295		if (!ret) {
296			/* Associate with monitored process. */
297			drvdata->pid = pid;
298			coresight_set_mode(csdev, CS_MODE_PERF);
299			csdev->refcnt++;
300		}
301	} while (0);
302	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
303
304	return ret;
305}
306
307static int tmc_enable_etf_sink(struct coresight_device *csdev,
308			       enum cs_mode mode,
309			       struct coresight_path *path)
310{
311	int ret;
312
313	switch (mode) {
314	case CS_MODE_SYSFS:
315		ret = tmc_enable_etf_sink_sysfs(csdev);
316		break;
317	case CS_MODE_PERF:
318		ret = tmc_enable_etf_sink_perf(csdev, path);
319		break;
320	/* We shouldn't be here */
321	default:
322		ret = -EINVAL;
323		break;
324	}
325
326	if (ret)
327		return ret;
328
329	dev_dbg(&csdev->dev, "TMC-ETB/ETF enabled\n");
330	return 0;
331}
332
333static int tmc_disable_etf_sink(struct coresight_device *csdev)
334{
335	unsigned long flags;
336	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
337
338	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
339
340	if (drvdata->reading) {
341		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
342		return -EBUSY;
343	}
344
345	csdev->refcnt--;
346	if (csdev->refcnt) {
347		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
348		return -EBUSY;
349	}
350
351	/* Complain if we (somehow) got out of sync */
352	WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
353	tmc_etb_disable_hw(drvdata);
354	/* Dissociate from monitored process. */
355	drvdata->pid = -1;
356	coresight_set_mode(csdev, CS_MODE_DISABLED);
357
358	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
359
360	dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n");
361	return 0;
362}
363
364static int tmc_enable_etf_link(struct coresight_device *csdev,
365			       struct coresight_connection *in,
366			       struct coresight_connection *out)
367{
368	int ret = 0;
369	unsigned long flags;
370	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
371	bool first_enable = false;
372
373	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
374	if (drvdata->reading) {
375		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
376		return -EBUSY;
377	}
378
379	if (csdev->refcnt == 0) {
380		ret = tmc_etf_enable_hw(drvdata);
381		if (!ret) {
382			coresight_set_mode(csdev, CS_MODE_SYSFS);
383			first_enable = true;
384		}
385	}
386	if (!ret)
387		csdev->refcnt++;
388	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
389
390	if (first_enable)
391		dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
392	return ret;
393}
394
395static void tmc_disable_etf_link(struct coresight_device *csdev,
396				 struct coresight_connection *in,
397				 struct coresight_connection *out)
398{
399	unsigned long flags;
400	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
401	bool last_disable = false;
402
403	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
404	if (drvdata->reading) {
405		raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
406		return;
407	}
408
409	csdev->refcnt--;
410	if (csdev->refcnt == 0) {
411		tmc_etf_disable_hw(drvdata);
412		coresight_set_mode(csdev, CS_MODE_DISABLED);
413		last_disable = true;
414	}
415	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
416
417	if (last_disable)
418		dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
419}
420
421static void *tmc_alloc_etf_buffer(struct coresight_device *csdev,
422				  struct perf_event *event, void **pages,
423				  int nr_pages, bool overwrite)
424{
425	int node;
426	struct cs_buffers *buf;
427
428	node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
429
430	/* Allocate memory structure for interaction with Perf */
431	buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
432	if (!buf)
433		return NULL;
434
435	buf->pid = task_pid_nr(event->owner);
436	buf->snapshot = overwrite;
437	buf->nr_pages = nr_pages;
438	buf->data_pages = pages;
439
440	return buf;
441}
442
443static void tmc_free_etf_buffer(void *config)
444{
445	struct cs_buffers *buf = config;
446
447	kfree(buf);
448}
449
450static int tmc_set_etf_buffer(struct coresight_device *csdev,
451			      struct perf_output_handle *handle)
452{
453	int ret = 0;
454	unsigned long head;
455	struct cs_buffers *buf = etm_perf_sink_config(handle);
456
457	if (!buf)
458		return -EINVAL;
459
460	/* wrap head around to the amount of space we have */
461	head = handle->head & (((unsigned long)buf->nr_pages << PAGE_SHIFT) - 1);
462
463	/* find the page to write to */
464	buf->cur = head / PAGE_SIZE;
465
466	/* and offset within that page */
467	buf->offset = head % PAGE_SIZE;
468
469	local_set(&buf->data_size, 0);
470
471	return ret;
472}
473
474static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
475				  struct perf_output_handle *handle,
476				  void *sink_config)
477{
478	bool lost = false;
479	int i, cur;
480	const u32 *barrier;
481	u32 *buf_ptr;
482	u64 read_ptr, write_ptr;
483	u32 status;
484	unsigned long offset, to_read = 0, flags;
485	struct cs_buffers *buf = sink_config;
486	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
487	struct perf_event *event = handle->event;
488
489	if (!buf)
490		return 0;
491
492	/* This shouldn't happen */
493	if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF))
494		return 0;
495
496	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
497
498	/* Don't do anything if another tracer is using this sink */
499	if (csdev->refcnt != 1)
500		goto out;
501
502	CS_UNLOCK(drvdata->base);
503
504	tmc_flush_and_stop(drvdata);
505
506	read_ptr = tmc_read_rrp(drvdata);
507	write_ptr = tmc_read_rwp(drvdata);
508
509	/*
510	 * Get a hold of the status register and see if a wrap around
511	 * has occurred.  If so adjust things accordingly.
512	 */
513	status = readl_relaxed(drvdata->base + TMC_STS);
514	if (status & TMC_STS_FULL) {
515		lost = true;
516		to_read = drvdata->size;
517	} else {
518		to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
519	}
520
521	/*
522	 * The TMC RAM buffer may be bigger than the space available in the
523	 * perf ring buffer (handle->size).  If so advance the RRP so that we
524	 * get the latest trace data.  In snapshot mode none of that matters
525	 * since we are expected to clobber stale data in favour of the latest
526	 * traces.
527	 */
528	if (!buf->snapshot && to_read > handle->size) {
529		u32 mask = tmc_get_memwidth_mask(drvdata);
530
531		/*
532		 * Make sure the new size is aligned in accordance with the
533		 * requirement explained in function tmc_get_memwidth_mask().
534		 */
535		to_read = handle->size & mask;
536		/* Move the RAM read pointer up */
537		read_ptr = (write_ptr + drvdata->size) - to_read;
538		/* Make sure we are still within our limits */
539		if (read_ptr > (drvdata->size - 1))
540			read_ptr -= drvdata->size;
541		/* Tell the HW */
542		tmc_write_rrp(drvdata, read_ptr);
543		lost = true;
544	}
545
546	/*
547	 * Don't set the TRUNCATED flag in snapshot mode because 1) the
548	 * captured buffer is expected to be truncated and 2) a full buffer
549	 * prevents the event from being re-enabled by the perf core,
550	 * resulting in stale data being send to user space.
551	 */
552	if (!buf->snapshot && lost)
553		perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
554
555	cur = buf->cur;
556	offset = buf->offset;
557	barrier = coresight_barrier_pkt;
558
559	/* for every byte to read */
560	for (i = 0; i < to_read; i += 4) {
561		buf_ptr = buf->data_pages[cur] + offset;
562		*buf_ptr = readl_relaxed(drvdata->base + TMC_RRD);
563
564		if (lost && i < CORESIGHT_BARRIER_PKT_SIZE) {
565			*buf_ptr = *barrier;
566			barrier++;
567		}
568
569		offset += 4;
570		if (offset >= PAGE_SIZE) {
571			offset = 0;
572			cur++;
573			/* wrap around at the end of the buffer */
574			cur &= buf->nr_pages - 1;
575		}
576	}
577
578	/*
579	 * In snapshot mode we simply increment the head by the number of byte
580	 * that were written.  User space will figure out how many bytes to get
581	 * from the AUX buffer based on the position of the head.
582	 */
583	if (buf->snapshot)
584		handle->head += to_read;
585
586	/*
587	 * CS_LOCK() contains mb() so it can ensure visibility of the AUX trace
588	 * data before the aux_head is updated via perf_aux_output_end(), which
589	 * is expected by the perf ring buffer.
590	 */
591	CS_LOCK(drvdata->base);
592
593	/*
594	 * If the event is active, it is triggered during an AUX pause.
595	 * Re-enable the sink so that it is ready when AUX resume is invoked.
596	 */
597	if (!event->hw.state)
598		__tmc_etb_enable_hw(drvdata);
599
600out:
601	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
602
603	return to_read;
604}
605
606static int tmc_panic_sync_etf(struct coresight_device *csdev)
607{
608	u32 val;
609	struct tmc_crash_metadata *mdata;
610	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
611
612	mdata = (struct tmc_crash_metadata *)drvdata->crash_mdata.vaddr;
613
614	/* Make sure we have valid reserved memory */
615	if (!tmc_has_reserved_buffer(drvdata) ||
616	    !tmc_has_crash_mdata_buffer(drvdata))
617		return 0;
618
619	tmc_crashdata_set_invalid(drvdata);
620
621	CS_UNLOCK(drvdata->base);
622
623	/* Proceed only if ETF is enabled or configured as sink */
624	val = readl(drvdata->base + TMC_CTL);
625	if (!(val & TMC_CTL_CAPT_EN))
626		goto out;
627	val = readl(drvdata->base + TMC_MODE);
628	if (val != TMC_MODE_CIRCULAR_BUFFER)
629		goto out;
630
631	val = readl(drvdata->base + TMC_FFSR);
632	/* Do manual flush and stop only if its not auto-stopped */
633	if (!(val & TMC_FFSR_FT_STOPPED)) {
634		dev_dbg(&csdev->dev,
635			 "%s: Triggering manual flush\n", __func__);
636		tmc_flush_and_stop(drvdata);
637	} else
638		tmc_wait_for_tmcready(drvdata);
639
640	/* Sync registers from hardware to metadata region */
641	mdata->tmc_sts = readl(drvdata->base + TMC_STS);
642	mdata->tmc_mode = readl(drvdata->base + TMC_MODE);
643	mdata->tmc_ffcr = readl(drvdata->base + TMC_FFCR);
644	mdata->tmc_ffsr = readl(drvdata->base + TMC_FFSR);
645
646	/* Sync Internal SRAM to reserved trace buffer region */
647	drvdata->buf = drvdata->resrv_buf.vaddr;
648	tmc_etb_dump_hw(drvdata);
649	/* Store as per RSZ register convention */
650	mdata->tmc_ram_size = drvdata->len >> 2;
651
652	/* Other fields for processing trace buffer reads */
653	mdata->tmc_rrp = 0;
654	mdata->tmc_dba = 0;
655	mdata->tmc_rwp = drvdata->len;
656	mdata->trace_paddr = drvdata->resrv_buf.paddr;
657
658	mdata->version = CS_CRASHDATA_VERSION;
659
660	/*
661	 * Make sure all previous writes are ordered,
662	 * before we mark valid
663	 */
664	dmb(sy);
665	mdata->valid = true;
666	/*
667	 * Below order need to maintained, since crc of metadata
668	 * is dependent on first
669	 */
670	mdata->crc32_tdata = find_crash_tracedata_crc(drvdata, mdata);
671	mdata->crc32_mdata = find_crash_metadata_crc(mdata);
672
673	tmc_disable_hw(drvdata);
674
675	dev_dbg(&csdev->dev, "%s: success\n", __func__);
676out:
677	CS_UNLOCK(drvdata->base);
678	return 0;
679}
680
681static const struct coresight_ops_sink tmc_etf_sink_ops = {
682	.enable		= tmc_enable_etf_sink,
683	.disable	= tmc_disable_etf_sink,
684	.alloc_buffer	= tmc_alloc_etf_buffer,
685	.free_buffer	= tmc_free_etf_buffer,
686	.update_buffer	= tmc_update_etf_buffer,
687};
688
689static const struct coresight_ops_link tmc_etf_link_ops = {
690	.enable		= tmc_enable_etf_link,
691	.disable	= tmc_disable_etf_link,
692};
693
694static const struct coresight_ops_panic tmc_etf_sync_ops = {
695	.sync		= tmc_panic_sync_etf,
696};
697
698const struct coresight_ops tmc_etb_cs_ops = {
699	.sink_ops	= &tmc_etf_sink_ops,
700};
701
702const struct coresight_ops tmc_etf_cs_ops = {
703	.sink_ops	= &tmc_etf_sink_ops,
704	.link_ops	= &tmc_etf_link_ops,
705	.panic_ops	= &tmc_etf_sync_ops,
706};
707
708int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
709{
710	enum tmc_mode mode;
711	int ret = 0;
712	unsigned long flags;
713
714	/* config types are set a boot time and never change */
715	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
716			 drvdata->config_type != TMC_CONFIG_TYPE_ETF))
717		return -EINVAL;
718
719	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
720
721	if (drvdata->reading) {
722		ret = -EBUSY;
723		goto out;
724	}
725
726	/* Don't interfere if operated from Perf */
727	if (coresight_get_mode(drvdata->csdev) == CS_MODE_PERF) {
728		ret = -EINVAL;
729		goto out;
730	}
731
732	/* If drvdata::buf is NULL the trace data has been read already */
733	if (drvdata->buf == NULL) {
734		ret = -EINVAL;
735		goto out;
736	}
737
738	/* Disable the TMC if need be */
739	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
740		/* There is no point in reading a TMC in HW FIFO mode */
741		mode = readl_relaxed(drvdata->base + TMC_MODE);
742		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
743			ret = -EINVAL;
744			goto out;
745		}
746		__tmc_etb_disable_hw(drvdata);
747	}
748
749	drvdata->reading = true;
750out:
751	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
752
753	return ret;
754}
755
756int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
757{
758	char *buf = NULL;
759	enum tmc_mode mode;
760	unsigned long flags;
761
762	/* config types are set a boot time and never change */
763	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
764			 drvdata->config_type != TMC_CONFIG_TYPE_ETF))
765		return -EINVAL;
766
767	raw_spin_lock_irqsave(&drvdata->spinlock, flags);
768
769	/* Re-enable the TMC if need be */
770	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
771		/* There is no point in reading a TMC in HW FIFO mode */
772		mode = readl_relaxed(drvdata->base + TMC_MODE);
773		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
774			raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
775			return -EINVAL;
776		}
777		/*
778		 * The trace run will continue with the same allocated trace
779		 * buffer. As such zero-out the buffer so that we don't end
780		 * up with stale data.
781		 *
782		 * Since the tracer is still enabled drvdata::buf
783		 * can't be NULL.
784		 */
785		memset(drvdata->buf, 0, drvdata->size);
786		/*
787		 * Ignore failures to enable the TMC to make sure, we don't
788		 * leave the TMC in a "reading" state.
789		 */
790		__tmc_etb_enable_hw(drvdata);
791	} else {
792		/*
793		 * The ETB/ETF is not tracing and the buffer was just read.
794		 * As such prepare to free the trace buffer.
795		 */
796		buf = drvdata->buf;
797		drvdata->buf = NULL;
798	}
799
800	drvdata->reading = false;
801	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
802
803	/*
804	 * Free allocated memory outside of the spinlock.  There is no need
805	 * to assert the validity of 'buf' since calling kfree(NULL) is safe.
806	 */
807	kfree(buf);
808
809	return 0;
810}
~/ Read-only file preview.