Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1/*
  2 * Copyright(C) 2016 Linaro Limited. All rights reserved.
  3 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
  4 *
  5 * This program is free software; you can redistribute it and/or modify it
  6 * under the terms of the GNU General Public License version 2 as published by
  7 * the Free Software Foundation.
  8 *
  9 * This program is distributed in the hope that it will be useful, but WITHOUT
 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 12 * more details.
 13 *
 14 * You should have received a copy of the GNU General Public License along with
 15 * this program.  If not, see <http://www.gnu.org/licenses/>.
 16 */
 17
 18#include <linux/coresight.h>
 19#include <linux/dma-mapping.h>
 20#include "coresight-priv.h"
 21#include "coresight-tmc.h"
 22
 23static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
 24{
 25	u32 axictl, sts;
 26
 27	/* Zero out the memory to help with debug */
 28	memset(drvdata->vaddr, 0, drvdata->size);
 29
 30	CS_UNLOCK(drvdata->base);
 31
 32	/* Wait for TMCSReady bit to be set */
 33	tmc_wait_for_tmcready(drvdata);
 34
 35	writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
 36	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
 37
 38	axictl = readl_relaxed(drvdata->base + TMC_AXICTL);
 39	axictl &= ~TMC_AXICTL_CLEAR_MASK;
 40	axictl |= (TMC_AXICTL_PROT_CTL_B1 | TMC_AXICTL_WR_BURST_16);
 41	axictl |= TMC_AXICTL_AXCACHE_OS;
 42
 43	if (tmc_etr_has_cap(drvdata, TMC_ETR_AXI_ARCACHE)) {
 44		axictl &= ~TMC_AXICTL_ARCACHE_MASK;
 45		axictl |= TMC_AXICTL_ARCACHE_OS;
 46	}
 47
 48	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
 49	tmc_write_dba(drvdata, drvdata->paddr);
 50	/*
 51	 * If the TMC pointers must be programmed before the session,
 52	 * we have to set it properly (i.e, RRP/RWP to base address and
 53	 * STS to "not full").
 54	 */
 55	if (tmc_etr_has_cap(drvdata, TMC_ETR_SAVE_RESTORE)) {
 56		tmc_write_rrp(drvdata, drvdata->paddr);
 57		tmc_write_rwp(drvdata, drvdata->paddr);
 58		sts = readl_relaxed(drvdata->base + TMC_STS) & ~TMC_STS_FULL;
 59		writel_relaxed(sts, drvdata->base + TMC_STS);
 60	}
 61
 62	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
 63		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
 64		       TMC_FFCR_TRIGON_TRIGIN,
 65		       drvdata->base + TMC_FFCR);
 66	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
 67	tmc_enable_hw(drvdata);
 68
 69	CS_LOCK(drvdata->base);
 70}
 71
 72static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
 73{
 74	const u32 *barrier;
 75	u32 val;
 76	u32 *temp;
 77	u64 rwp;
 78
 79	rwp = tmc_read_rwp(drvdata);
 80	val = readl_relaxed(drvdata->base + TMC_STS);
 81
 82	/*
 83	 * Adjust the buffer to point to the beginning of the trace data
 84	 * and update the available trace data.
 85	 */
 86	if (val & TMC_STS_FULL) {
 87		drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
 88		drvdata->len = drvdata->size;
 89
 90		barrier = barrier_pkt;
 91		temp = (u32 *)drvdata->buf;
 92
 93		while (*barrier) {
 94			*temp = *barrier;
 95			temp++;
 96			barrier++;
 97		}
 98
 99	} else {
100		drvdata->buf = drvdata->vaddr;
101		drvdata->len = rwp - drvdata->paddr;
102	}
103}
104
105static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
106{
107	CS_UNLOCK(drvdata->base);
108
109	tmc_flush_and_stop(drvdata);
110	/*
111	 * When operating in sysFS mode the content of the buffer needs to be
112	 * read before the TMC is disabled.
113	 */
114	if (drvdata->mode == CS_MODE_SYSFS)
115		tmc_etr_dump_hw(drvdata);
116	tmc_disable_hw(drvdata);
117
118	CS_LOCK(drvdata->base);
119}
120
121static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
122{
123	int ret = 0;
124	bool used = false;
125	unsigned long flags;
126	void __iomem *vaddr = NULL;
127	dma_addr_t paddr;
128	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
129
130
131	/*
132	 * If we don't have a buffer release the lock and allocate memory.
133	 * Otherwise keep the lock and move along.
134	 */
135	spin_lock_irqsave(&drvdata->spinlock, flags);
136	if (!drvdata->vaddr) {
137		spin_unlock_irqrestore(&drvdata->spinlock, flags);
138
139		/*
140		 * Contiguous  memory can't be allocated while a spinlock is
141		 * held.  As such allocate memory here and free it if a buffer
142		 * has already been allocated (from a previous session).
143		 */
144		vaddr = dma_alloc_coherent(drvdata->dev, drvdata->size,
145					   &paddr, GFP_KERNEL);
146		if (!vaddr)
147			return -ENOMEM;
148
149		/* Let's try again */
150		spin_lock_irqsave(&drvdata->spinlock, flags);
151	}
152
153	if (drvdata->reading) {
154		ret = -EBUSY;
155		goto out;
156	}
157
158	/*
159	 * In sysFS mode we can have multiple writers per sink.  Since this
160	 * sink is already enabled no memory is needed and the HW need not be
161	 * touched.
162	 */
163	if (drvdata->mode == CS_MODE_SYSFS)
164		goto out;
165
166	/*
167	 * If drvdata::buf == NULL, use the memory allocated above.
168	 * Otherwise a buffer still exists from a previous session, so
169	 * simply use that.
170	 */
171	if (drvdata->buf == NULL) {
172		used = true;
173		drvdata->vaddr = vaddr;
174		drvdata->paddr = paddr;
175		drvdata->buf = drvdata->vaddr;
176	}
177
178	drvdata->mode = CS_MODE_SYSFS;
179	tmc_etr_enable_hw(drvdata);
180out:
181	spin_unlock_irqrestore(&drvdata->spinlock, flags);
182
183	/* Free memory outside the spinlock if need be */
184	if (!used && vaddr)
185		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
186
187	if (!ret)
188		dev_info(drvdata->dev, "TMC-ETR enabled\n");
189
190	return ret;
191}
192
193static int tmc_enable_etr_sink_perf(struct coresight_device *csdev)
194{
195	int ret = 0;
196	unsigned long flags;
197	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
198
199	spin_lock_irqsave(&drvdata->spinlock, flags);
200	if (drvdata->reading) {
201		ret = -EINVAL;
202		goto out;
203	}
204
205	/*
206	 * In Perf mode there can be only one writer per sink.  There
207	 * is also no need to continue if the ETR is already operated
208	 * from sysFS.
209	 */
210	if (drvdata->mode != CS_MODE_DISABLED) {
211		ret = -EINVAL;
212		goto out;
213	}
214
215	drvdata->mode = CS_MODE_PERF;
216	tmc_etr_enable_hw(drvdata);
217out:
218	spin_unlock_irqrestore(&drvdata->spinlock, flags);
219
220	return ret;
221}
222
223static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
224{
225	switch (mode) {
226	case CS_MODE_SYSFS:
227		return tmc_enable_etr_sink_sysfs(csdev);
228	case CS_MODE_PERF:
229		return tmc_enable_etr_sink_perf(csdev);
230	}
231
232	/* We shouldn't be here */
233	return -EINVAL;
234}
235
236static void tmc_disable_etr_sink(struct coresight_device *csdev)
237{
238	unsigned long flags;
239	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
240
241	spin_lock_irqsave(&drvdata->spinlock, flags);
242	if (drvdata->reading) {
243		spin_unlock_irqrestore(&drvdata->spinlock, flags);
244		return;
245	}
246
247	/* Disable the TMC only if it needs to */
248	if (drvdata->mode != CS_MODE_DISABLED) {
249		tmc_etr_disable_hw(drvdata);
250		drvdata->mode = CS_MODE_DISABLED;
251	}
252
253	spin_unlock_irqrestore(&drvdata->spinlock, flags);
254
255	dev_info(drvdata->dev, "TMC-ETR disabled\n");
256}
257
258static const struct coresight_ops_sink tmc_etr_sink_ops = {
259	.enable		= tmc_enable_etr_sink,
260	.disable	= tmc_disable_etr_sink,
261};
262
263const struct coresight_ops tmc_etr_cs_ops = {
264	.sink_ops	= &tmc_etr_sink_ops,
265};
266
267int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
268{
269	int ret = 0;
270	unsigned long flags;
271
272	/* config types are set a boot time and never change */
273	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
274		return -EINVAL;
275
276	spin_lock_irqsave(&drvdata->spinlock, flags);
277	if (drvdata->reading) {
278		ret = -EBUSY;
279		goto out;
280	}
281
282	/* Don't interfere if operated from Perf */
283	if (drvdata->mode == CS_MODE_PERF) {
284		ret = -EINVAL;
285		goto out;
286	}
287
288	/* If drvdata::buf is NULL the trace data has been read already */
289	if (drvdata->buf == NULL) {
290		ret = -EINVAL;
291		goto out;
292	}
293
294	/* Disable the TMC if need be */
295	if (drvdata->mode == CS_MODE_SYSFS)
296		tmc_etr_disable_hw(drvdata);
297
298	drvdata->reading = true;
299out:
300	spin_unlock_irqrestore(&drvdata->spinlock, flags);
301
302	return ret;
303}
304
305int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
306{
307	unsigned long flags;
308	dma_addr_t paddr;
309	void __iomem *vaddr = NULL;
310
311	/* config types are set a boot time and never change */
312	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
313		return -EINVAL;
314
315	spin_lock_irqsave(&drvdata->spinlock, flags);
316
317	/* RE-enable the TMC if need be */
318	if (drvdata->mode == CS_MODE_SYSFS) {
319		/*
320		 * The trace run will continue with the same allocated trace
321		 * buffer. The trace buffer is cleared in tmc_etr_enable_hw(),
322		 * so we don't have to explicitly clear it. Also, since the
323		 * tracer is still enabled drvdata::buf can't be NULL.
324		 */
325		tmc_etr_enable_hw(drvdata);
326	} else {
327		/*
328		 * The ETR is not tracing and the buffer was just read.
329		 * As such prepare to free the trace buffer.
330		 */
331		vaddr = drvdata->vaddr;
332		paddr = drvdata->paddr;
333		drvdata->buf = drvdata->vaddr = NULL;
334	}
335
336	drvdata->reading = false;
337	spin_unlock_irqrestore(&drvdata->spinlock, flags);
338
339	/* Free allocated memory out side of the spinlock */
340	if (vaddr)
341		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
342
343	return 0;
344}