aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwtracing/coresight/coresight-tmc.h
blob: b66c82d271fa52163e36374ca0e0556f7c966a65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright(C) 2015 Linaro Limited. All rights reserved.
 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
 */

#ifndef _CORESIGHT_TMC_H
#define _CORESIGHT_TMC_H

#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/refcount.h>
#include <linux/arm-smccc.h>

#define TMC_RSZ			0x004
#define TMC_STS			0x00c
#define TMC_RRD			0x010
#define TMC_RRP			0x014
#define TMC_RWP			0x018
#define TMC_TRG			0x01c
#define TMC_CTL			0x020
#define TMC_RWD			0x024
#define TMC_MODE		0x028
#define TMC_LBUFLEVEL		0x02c
#define TMC_CBUFLEVEL		0x030
#define TMC_BUFWM		0x034
#define TMC_RRPHI		0x038
#define TMC_RWPHI		0x03c
#define TMC_AXICTL		0x110
#define TMC_DBALO		0x118
#define TMC_DBAHI		0x11c
#define TMC_FFSR		0x300
#define TMC_FFCR		0x304
#define TMC_PSCR		0x308
#define TMC_ITMISCOP0		0xee0
#define TMC_ITTRFLIN		0xee8
#define TMC_ITATBDATA0		0xeec
#define TMC_ITATBCTR2		0xef0
#define TMC_ITATBCTR1		0xef4
#define TMC_ITATBCTR0		0xef8

/* register description */
/* TMC_CTL - 0x020 */
#define TMC_CTL_CAPT_EN		BIT(0)
/* TMC_STS - 0x00C */
#define TMC_STS_TMCREADY_BIT	2
#define TMC_STS_FULL		BIT(0)
#define TMC_STS_TRIGGERED	BIT(1)
/*
 * TMC_AXICTL - 0x110
 *
 * TMC AXICTL format for SoC-400
 *	Bits [0-1]	: ProtCtrlBit0-1
 *	Bits [2-5]	: CacheCtrlBits 0-3 (AXCACHE)
 *	Bit  6		: Reserved
 *	Bit  7		: ScatterGatherMode
 *	Bits [8-11]	: WrBurstLen
 *	Bits [12-31]	: Reserved.
 * TMC AXICTL format for SoC-600, as above except:
 *	Bits [2-5]	: AXI WCACHE
 *	Bits [16-19]	: AXI RCACHE
 *	Bits [20-31]	: Reserved
 */
#define TMC_AXICTL_CLEAR_MASK 0xfbf
#define TMC_AXICTL_ARCACHE_MASK (0xf << 16)

#define TMC_AXICTL_PROT_CTL_B0	BIT(0)
#define TMC_AXICTL_PROT_CTL_B1	BIT(1)
#define TMC_AXICTL_SCT_GAT_MODE	BIT(7)
#define TMC_AXICTL_WR_BURST_16	0xF00
/* Write-back Read and Write-allocate */
#define TMC_AXICTL_AXCACHE_OS	(0xf << 2)
#define TMC_AXICTL_ARCACHE_OS	(0xf << 16)

/* TMC_FFSR - 0x300 */
#define TMC_FFSR_FT_NOT_PRESENT	BIT(4)

/* TMC_FFCR - 0x304 */
#define TMC_FFCR_FLUSHMAN_BIT	6
#define TMC_FFCR_EN_FMT		BIT(0)
#define TMC_FFCR_EN_TI		BIT(1)
#define TMC_FFCR_FON_FLIN	BIT(4)
#define TMC_FFCR_FON_TRIG_EVT	BIT(5)
#define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
#define TMC_FFCR_STOP_ON_FLUSH	BIT(12)


#define TMC_DEVID_NOSCAT	BIT(24)

#define TMC_DEVID_AXIAW_VALID	BIT(16)
#define TMC_DEVID_AXIAW_SHIFT	17
#define TMC_DEVID_AXIAW_MASK	0x7f

enum tmc_config_type {
	TMC_CONFIG_TYPE_ETB,
	TMC_CONFIG_TYPE_ETR,
	TMC_CONFIG_TYPE_ETF,
};

enum tmc_mode {
	TMC_MODE_CIRCULAR_BUFFER,
	TMC_MODE_SOFTWARE_FIFO,
	TMC_MODE_HARDWARE_FIFO,
};

enum tmc_mem_intf_width {
	TMC_MEM_INTF_WIDTH_32BITS	= 1,
	TMC_MEM_INTF_WIDTH_64BITS	= 2,
	TMC_MEM_INTF_WIDTH_128BITS	= 4,
	TMC_MEM_INTF_WIDTH_256BITS	= 8,
};

/* TMC ETR Capability bit definitions */
#define TMC_ETR_SG			(0x1U << 0)
/* ETR has separate read/write cache encodings */
#define TMC_ETR_AXI_ARCACHE		(0x1U << 1)
/*
 * TMC_ETR_SAVE_RESTORE - Values of RRP/RWP/STS.Full are
 * retained when TMC leaves Disabled state, allowing us to continue
 * the tracing from a point where we stopped. This also implies that
 * the RRP/RWP/STS.Full should always be programmed to the correct
 * value. Unfortunately this is not advertised by the hardware,
 * so we have to rely on PID of the IP to detect the functionality.
 */
#define TMC_ETR_SAVE_RESTORE		(0x1U << 2)

/* Coresight SoC-600 TMC-ETR unadvertised capabilities */
#define CORESIGHT_SOC_600_ETR_CAPS	\
	(TMC_ETR_SAVE_RESTORE | TMC_ETR_AXI_ARCACHE)

/* Marvell OcteonTx CN9xxx TMC-ETR unadvertised capabilities */
#define OCTEONTX_CN9XXX_ETR_CAPS	\
	(TMC_ETR_SAVE_RESTORE)

/* Marvell OcteonTx CN9xxx device */
#define OCTEONTX_CN9XXX_ETR		0x000cc213

/* Marvell OcteonTx CN9xxx HW issues */
#define CORESIGHT_OPTS_BUFFSIZE_8BX	(0x1U << 0) /* 8 byte size multiplier */
#define CORESIGHT_OPTS_SECURE_BUFF	(0x1U << 1) /* Trace buffer is Secure */
#define CORESIGHT_OPTS_RESET_CTL_REG	(0x1U << 2) /* Reset CTL on reset */

/* SMC call ids for managing the secure trace buffer */

/* Args: x1 - size, x2 - cpu, x3 - llc lock flag
 * Returns: x0 - status, x1 - secure buffer address
 */
#define OCTEONTX_TRC_ALLOC_SBUF		0xc2000c05
/* Args: x1 - non secure buffer address, x2 - size */
#define OCTEONTX_TRC_REGISTER_DRVBUF	0xc2000c06
/* Args: x1 - dst(non secure), x2 - src(secure), x3 - size */
#define OCTEONTX_TRC_COPY_TO_DRVBUF	0xc2000c07
/* Args: x1 - secure buffer address, x2 - size */
#define OCTEONTX_TRC_FREE_SBUF		0xc2000c08
/* Args: x1 - non secure buffer address, x2 - size */
#define OCTEONTX_TRC_UNREGISTER_DRVBUF	0xc2000c09

enum etr_mode {
	ETR_MODE_FLAT,		/* Uses contiguous flat buffer */
	ETR_MODE_ETR_SG,	/* Uses in-built TMC ETR SG mechanism */
	ETR_MODE_CATU,		/* Use SG mechanism in CATU */
};

struct etr_buf_operations;

/**
 * struct etr_buf - Details of the buffer used by ETR
 * refcount	; Number of sources currently using this etr_buf.
 * @mode	: Mode of the ETR buffer, contiguous, Scatter Gather etc.
 * @full	: Trace data overflow
 * @size	: Size of the buffer.
 * @hwaddr	: Address to be programmed in the TMC:DBA{LO,HI}
 * @s_paddr	: Secure trace buffer
 * @offset	: Offset of the trace data in the buffer for consumption.
 * @len		: Available trace data @buf (may round up to the beginning).
 * @ops		: ETR buffer operations for the mode.
 * @private	: Backend specific information for the buf
 */
struct etr_buf {
	refcount_t			refcount;
	enum etr_mode			mode;
	bool				full;
	ssize_t				size;
	dma_addr_t			hwaddr;
	dma_addr_t			s_paddr;
	unsigned long			offset;
	s64				len;
	const struct etr_buf_operations	*ops;
	void				*private;
};

/**
 * struct tmc_drvdata - specifics associated to an TMC component
 * @base:	memory mapped base address for this component.
 * @dev:	the device entity associated to this component.
 * @csdev:	component vitals needed by the framework.
 * @miscdev:	specifics to handle "/dev/xyz.tmc" entry.
 * @spinlock:	only one at a time pls.  * @pid:	Process ID of the process being monitored by the session
 *		that is using this component.
 * @buf:	Snapshot of the trace data for ETF/ETB.
 * @etr_buf:	details of buffer used in TMC-ETR
 * @len:	size of the available trace for ETF/ETB.
 * @size:	trace buffer size for this TMC (common for all modes).
 * @formatter_en: Formatter enable/disable status
 * @cache_lock_en: Cache lock status
 * @mode:	how this TMC is being used.
 * @config_type: TMC variant, must be of type @tmc_config_type.
 * @memwidth:	width of the memory interface databus, in bytes.
 * @trigger_cntr: amount of words to store after a trigger.
 * @etr_caps:	Bitmask of capabilities of the TMC ETR, inferred from the
 *		device configuration register (DEVID)
 * @idr:	Holds etr_bufs allocated for this ETR.
 * @idr_mutex:	Access serialisation for idr.
 * @perf_data:	PERF buffer for ETR.
 * @sysfs_data:	SYSFS buffer for ETR.
 * @etr_options: Bitmask of options to manage Silicon issues
 * @cpu:	CPU id this component is associated with
 */
struct tmc_drvdata {
	void __iomem		*base;
	struct device		*dev;
	struct coresight_device	*csdev;
	struct miscdevice	miscdev;
	spinlock_t		spinlock;
	pid_t			pid;
	bool			reading;
	union {
		char		*buf;		/* TMC ETB */
		struct etr_buf	*etr_buf;	/* TMC ETR */
	};
	bool			formatter_en;
	bool			cache_lock_en;
	u32			len;
	u32			size;
	u32			mode;
	enum tmc_config_type	config_type;
	enum tmc_mem_intf_width	memwidth;
	u32			trigger_cntr;
	u32			etr_caps;
	struct idr		idr;
	struct mutex		idr_mutex;
	struct etr_buf		*sysfs_buf;
	void			*perf_data;
	u32			etr_options;
	int			cpu;
};

struct etr_buf_operations {
	int (*alloc)(struct tmc_drvdata *drvdata, struct etr_buf *etr_buf,
		     int node, void **pages);
	void (*sync)(struct etr_buf *etr_buf, u64 rrp, u64 rwp);
	ssize_t (*get_data)(struct etr_buf *etr_buf, u64 offset, size_t len,
			    char **bufpp);
	void (*free)(struct etr_buf *etr_buf);
};

/**
 * struct tmc_pages - Collection of pages used for SG.
 * @nr_pages:		Number of pages in the list.
 * @daddrs:		Array of DMA'able page address.
 * @pages:		Array pages for the buffer.
 */
struct tmc_pages {
	int nr_pages;
	dma_addr_t	*daddrs;
	struct page	**pages;
};

/*
 * struct tmc_sg_table - Generic SG table for TMC
 * @dev:		Device for DMA allocations
 * @table_vaddr:	Contiguous Virtual address for PageTable
 * @data_vaddr:		Contiguous Virtual address for Data Buffer
 * @table_daddr:	DMA address of the PageTable base
 * @node:		Node for Page allocations
 * @table_pages:	List of pages & dma address for Table
 * @data_pages:		List of pages & dma address for Data
 */
struct tmc_sg_table {
	struct device *dev;
	void *table_vaddr;
	void *data_vaddr;
	dma_addr_t table_daddr;
	int node;
	struct tmc_pages table_pages;
	struct tmc_pages data_pages;
};

/* Generic functions */
void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata);
void tmc_flush_and_stop(struct tmc_drvdata *drvdata);
void tmc_enable_hw(struct tmc_drvdata *drvdata);
void tmc_disable_hw(struct tmc_drvdata *drvdata);

/* ETB/ETF functions */
int tmc_read_prepare_etb(struct tmc_drvdata *drvdata);
int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata);
extern const struct coresight_ops tmc_etb_cs_ops;
extern const struct coresight_ops tmc_etf_cs_ops;

ssize_t tmc_etb_get_sysfs_trace(struct tmc_drvdata *drvdata,
				loff_t pos, size_t len, char **bufpp);
/* ETR functions */
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata);
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata);
extern const struct coresight_ops tmc_etr_cs_ops;
ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
				loff_t pos, size_t len, char **bufpp);


#define TMC_REG_PAIR(name, lo_off, hi_off)				\
static inline u64							\
tmc_read_##name(struct tmc_drvdata *drvdata)				\
{									\
	return coresight_read_reg_pair(drvdata->base, lo_off, hi_off);	\
}									\
static inline void							\
tmc_write_##name(struct tmc_drvdata *drvdata, u64 val)			\
{									\
	coresight_write_reg_pair(drvdata->base, val, lo_off, hi_off);	\
}

TMC_REG_PAIR(rrp, TMC_RRP, TMC_RRPHI)
TMC_REG_PAIR(rwp, TMC_RWP, TMC_RWPHI)
TMC_REG_PAIR(dba, TMC_DBALO, TMC_DBAHI)

/* Initialise the caps from unadvertised static capabilities of the device */
static inline void tmc_etr_init_caps(struct tmc_drvdata *drvdata, u32 dev_caps)
{
	WARN_ON(drvdata->etr_caps);
	drvdata->etr_caps = dev_caps;
}

static inline void tmc_etr_set_cap(struct tmc_drvdata *drvdata, u32 cap)
{
	drvdata->etr_caps |= cap;
}

static inline bool tmc_etr_has_cap(struct tmc_drvdata *drvdata, u32 cap)
{
	return !!(drvdata->etr_caps & cap);
}

struct tmc_sg_table *tmc_alloc_sg_table(struct device *dev,
					int node,
					int nr_tpages,
					int nr_dpages,
					void **pages);
void tmc_free_sg_table(struct tmc_sg_table *sg_table);
void tmc_sg_table_sync_table(struct tmc_sg_table *sg_table);
void tmc_sg_table_sync_data_range(struct tmc_sg_table *table,
				  u64 offset, u64 size);
ssize_t tmc_sg_table_get_data(struct tmc_sg_table *sg_table,
			      u64 offset, size_t len, char **bufpp);
static inline unsigned long
tmc_sg_table_buf_size(struct tmc_sg_table *sg_table)
{
	return sg_table->data_pages.nr_pages << PAGE_SHIFT;
}

struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);

static inline int tmc_alloc_secbuf(struct tmc_drvdata *drvdata,
				   size_t len, dma_addr_t *s_paddr)
{
	struct arm_smccc_res res;

	arm_smccc_smc(OCTEONTX_TRC_ALLOC_SBUF, len, drvdata->cpu,
		      drvdata->cache_lock_en, 0, 0, 0, 0, &res);
	if (res.a0 != SMCCC_RET_SUCCESS)
		return -EFAULT;

	*s_paddr = res.a1;
	return 0;
}

static inline int tmc_free_secbuf(struct tmc_drvdata *drvdata,
				  dma_addr_t s_paddr, size_t len)
{
	struct arm_smccc_res res;

	arm_smccc_smc(OCTEONTX_TRC_FREE_SBUF, s_paddr, len,
		      0, 0, 0, 0, 0, &res);
	return 0;
}

static inline int tmc_register_drvbuf(struct tmc_drvdata *drvdata,
				      dma_addr_t paddr, size_t len)
{
	struct arm_smccc_res res;

	arm_smccc_smc(OCTEONTX_TRC_REGISTER_DRVBUF, paddr, len,
		      0, 0, 0, 0, 0, &res);
	if (res.a0 != SMCCC_RET_SUCCESS)
		return -EFAULT;

	return 0;
}

static inline int tmc_unregister_drvbuf(struct tmc_drvdata *drvdata,
					dma_addr_t paddr, size_t len)
{
	struct arm_smccc_res res;

	arm_smccc_smc(OCTEONTX_TRC_UNREGISTER_DRVBUF, paddr, len,
		      0, 0, 0, 0, 0, &res);
	return 0;

}

int tmc_copy_secure_buffer(struct tmc_drvdata *drvdata,
					 char *bufp, size_t len);
#endif