blob: b5e5e6ac67ebbc0b3589f0b77cb5c201a3e3d64e [file] [log] [blame]
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -06001/*
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>
Mathieu Poirierde546192016-05-03 11:33:52 -060019#include <linux/slab.h>
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -060020#include "coresight-priv.h"
21#include "coresight-tmc.h"
22
23void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
24{
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -060025 CS_UNLOCK(drvdata->base);
26
27 /* Wait for TMCSReady bit to be set */
28 tmc_wait_for_tmcready(drvdata);
29
30 writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
31 writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
32 TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
33 TMC_FFCR_TRIGON_TRIGIN,
34 drvdata->base + TMC_FFCR);
35
36 writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
37 tmc_enable_hw(drvdata);
38
39 CS_LOCK(drvdata->base);
40}
41
42static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
43{
44 enum tmc_mem_intf_width memwidth;
45 u8 memwords;
46 char *bufp;
47 u32 read_data;
48 int i;
49
50 memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
51 if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
52 memwords = 1;
53 else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
54 memwords = 2;
55 else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
56 memwords = 4;
57 else
58 memwords = 8;
59
60 bufp = drvdata->buf;
61 while (1) {
62 for (i = 0; i < memwords; i++) {
63 read_data = readl_relaxed(drvdata->base + TMC_RRD);
64 if (read_data == 0xFFFFFFFF)
65 return;
66 memcpy(bufp, &read_data, 4);
67 bufp += 4;
68 }
69 }
70}
71
Mathieu Poirier45254122016-05-03 11:33:51 -060072static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -060073{
74 CS_UNLOCK(drvdata->base);
75
76 tmc_flush_and_stop(drvdata);
Mathieu Poiriera40318f2016-05-03 11:33:55 -060077 /*
78 * When operating in sysFS mode the content of the buffer needs to be
79 * read before the TMC is disabled.
80 */
81 if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
82 tmc_etb_dump_hw(drvdata);
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -060083 tmc_disable_hw(drvdata);
84
85 CS_LOCK(drvdata->base);
86}
87
88static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
89{
90 CS_UNLOCK(drvdata->base);
91
92 /* Wait for TMCSReady bit to be set */
93 tmc_wait_for_tmcready(drvdata);
94
95 writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
96 writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
97 drvdata->base + TMC_FFCR);
98 writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
99 tmc_enable_hw(drvdata);
100
101 CS_LOCK(drvdata->base);
102}
103
104static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
105{
106 CS_UNLOCK(drvdata->base);
107
108 tmc_flush_and_stop(drvdata);
109 tmc_disable_hw(drvdata);
110
111 CS_LOCK(drvdata->base);
112}
113
114static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
115{
Mathieu Poirierde546192016-05-03 11:33:52 -0600116 int ret = 0;
117 bool used = false;
118 char *buf = NULL;
Mathieu Poirierf2facc32016-05-03 11:33:54 -0600119 long val;
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600120 unsigned long flags;
121 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
122
Mathieu Poirierde546192016-05-03 11:33:52 -0600123 /* This shouldn't be happening */
124 if (WARN_ON(mode != CS_MODE_SYSFS))
125 return -EINVAL;
126
127 /*
128 * If we don't have a buffer release the lock and allocate memory.
129 * Otherwise keep the lock and move along.
130 */
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600131 spin_lock_irqsave(&drvdata->spinlock, flags);
Mathieu Poirierde546192016-05-03 11:33:52 -0600132 if (!drvdata->buf) {
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600133 spin_unlock_irqrestore(&drvdata->spinlock, flags);
Mathieu Poirierde546192016-05-03 11:33:52 -0600134
135 /* Allocating the memory here while outside of the spinlock */
136 buf = kzalloc(drvdata->size, GFP_KERNEL);
137 if (!buf)
138 return -ENOMEM;
139
140 /* Let's try again */
141 spin_lock_irqsave(&drvdata->spinlock, flags);
142 }
143
144 if (drvdata->reading) {
145 ret = -EBUSY;
146 goto out;
147 }
148
Mathieu Poirierf2facc32016-05-03 11:33:54 -0600149 val = local_xchg(&drvdata->mode, mode);
150 /*
151 * In sysFS mode we can have multiple writers per sink. Since this
152 * sink is already enabled no memory is needed and the HW need not be
153 * touched.
154 */
155 if (val == CS_MODE_SYSFS)
156 goto out;
157
Mathieu Poirierde546192016-05-03 11:33:52 -0600158 /*
159 * If drvdata::buf isn't NULL, memory was allocated for a previous
160 * trace run but wasn't read. If so simply zero-out the memory.
161 * Otherwise use the memory allocated above.
162 *
163 * The memory is freed when users read the buffer using the
164 * /dev/xyz.{etf|etb} interface. See tmc_read_unprepare_etf() for
165 * details.
166 */
167 if (drvdata->buf) {
168 memset(drvdata->buf, 0, drvdata->size);
169 } else {
170 used = true;
171 drvdata->buf = buf;
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600172 }
173
174 tmc_etb_enable_hw(drvdata);
Mathieu Poirierde546192016-05-03 11:33:52 -0600175out:
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600176 spin_unlock_irqrestore(&drvdata->spinlock, flags);
177
Mathieu Poirierde546192016-05-03 11:33:52 -0600178 /* Free memory outside the spinlock if need be */
179 if (!used && buf)
180 kfree(buf);
181
182 if (!ret)
183 dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
184
185 return ret;
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600186}
187
188static void tmc_disable_etf_sink(struct coresight_device *csdev)
189{
Mathieu Poirierf2facc32016-05-03 11:33:54 -0600190 long val;
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600191 unsigned long flags;
192 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
193
194 spin_lock_irqsave(&drvdata->spinlock, flags);
195 if (drvdata->reading) {
196 spin_unlock_irqrestore(&drvdata->spinlock, flags);
197 return;
198 }
199
Mathieu Poirierf2facc32016-05-03 11:33:54 -0600200 val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
201 /* Disable the TMC only if it needs to */
202 if (val != CS_MODE_DISABLED)
203 tmc_etb_disable_hw(drvdata);
204
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600205 spin_unlock_irqrestore(&drvdata->spinlock, flags);
206
207 dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
208}
209
210static int tmc_enable_etf_link(struct coresight_device *csdev,
211 int inport, int outport)
212{
213 unsigned long flags;
214 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
215
216 spin_lock_irqsave(&drvdata->spinlock, flags);
217 if (drvdata->reading) {
218 spin_unlock_irqrestore(&drvdata->spinlock, flags);
219 return -EBUSY;
220 }
221
222 tmc_etf_enable_hw(drvdata);
Mathieu Poirierf2facc32016-05-03 11:33:54 -0600223 local_set(&drvdata->mode, CS_MODE_SYSFS);
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600224 spin_unlock_irqrestore(&drvdata->spinlock, flags);
225
226 dev_info(drvdata->dev, "TMC-ETF enabled\n");
227 return 0;
228}
229
230static void tmc_disable_etf_link(struct coresight_device *csdev,
231 int inport, int outport)
232{
233 unsigned long flags;
234 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
235
236 spin_lock_irqsave(&drvdata->spinlock, flags);
237 if (drvdata->reading) {
238 spin_unlock_irqrestore(&drvdata->spinlock, flags);
239 return;
240 }
241
242 tmc_etf_disable_hw(drvdata);
Mathieu Poirierf2facc32016-05-03 11:33:54 -0600243 local_set(&drvdata->mode, CS_MODE_DISABLED);
Mathieu Poirier6c6ed1e2016-05-03 11:33:50 -0600244 spin_unlock_irqrestore(&drvdata->spinlock, flags);
245
246 dev_info(drvdata->dev, "TMC disabled\n");
247}
248
249static const struct coresight_ops_sink tmc_etf_sink_ops = {
250 .enable = tmc_enable_etf_sink,
251 .disable = tmc_disable_etf_sink,
252};
253
254static const struct coresight_ops_link tmc_etf_link_ops = {
255 .enable = tmc_enable_etf_link,
256 .disable = tmc_disable_etf_link,
257};
258
259const struct coresight_ops tmc_etb_cs_ops = {
260 .sink_ops = &tmc_etf_sink_ops,
261};
262
263const struct coresight_ops tmc_etf_cs_ops = {
264 .sink_ops = &tmc_etf_sink_ops,
265 .link_ops = &tmc_etf_link_ops,
266};
Mathieu Poirier45254122016-05-03 11:33:51 -0600267
268int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
269{
270 enum tmc_mode mode;
271 int ret = 0;
272 unsigned long flags;
273
274 /* config types are set a boot time and never change */
275 if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
276 drvdata->config_type != TMC_CONFIG_TYPE_ETF))
277 return -EINVAL;
278
279 spin_lock_irqsave(&drvdata->spinlock, flags);
280
Mathieu Poirierf74debb2016-05-03 11:33:53 -0600281 if (drvdata->reading) {
282 ret = -EBUSY;
283 goto out;
284 }
285
Mathieu Poirier45254122016-05-03 11:33:51 -0600286 /* There is no point in reading a TMC in HW FIFO mode */
287 mode = readl_relaxed(drvdata->base + TMC_MODE);
288 if (mode != TMC_MODE_CIRCULAR_BUFFER) {
289 ret = -EINVAL;
290 goto out;
291 }
292
Mathieu Poirierde546192016-05-03 11:33:52 -0600293 /* If drvdata::buf is NULL the trace data has been read already */
294 if (drvdata->buf == NULL) {
295 ret = -EINVAL;
296 goto out;
297 }
298
Mathieu Poirier45254122016-05-03 11:33:51 -0600299 /* Disable the TMC if need be */
Mathieu Poirierf2facc32016-05-03 11:33:54 -0600300 if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
Mathieu Poirier45254122016-05-03 11:33:51 -0600301 tmc_etb_disable_hw(drvdata);
302
303 drvdata->reading = true;
304out:
305 spin_unlock_irqrestore(&drvdata->spinlock, flags);
306
307 return ret;
308}
309
310int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
311{
Mathieu Poirierde546192016-05-03 11:33:52 -0600312 char *buf = NULL;
Mathieu Poirier45254122016-05-03 11:33:51 -0600313 enum tmc_mode mode;
314 unsigned long flags;
315
316 /* config types are set a boot time and never change */
317 if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
318 drvdata->config_type != TMC_CONFIG_TYPE_ETF))
319 return -EINVAL;
320
321 spin_lock_irqsave(&drvdata->spinlock, flags);
322
323 /* There is no point in reading a TMC in HW FIFO mode */
324 mode = readl_relaxed(drvdata->base + TMC_MODE);
325 if (mode != TMC_MODE_CIRCULAR_BUFFER) {
326 spin_unlock_irqrestore(&drvdata->spinlock, flags);
327 return -EINVAL;
328 }
329
330 /* Re-enable the TMC if need be */
Mathieu Poirierf2facc32016-05-03 11:33:54 -0600331 if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
Mathieu Poirierde546192016-05-03 11:33:52 -0600332 /*
333 * The trace run will continue with the same allocated trace
334 * buffer. As such zero-out the buffer so that we don't end
335 * up with stale data.
336 *
337 * Since the tracer is still enabled drvdata::buf
338 * can't be NULL.
339 */
340 memset(drvdata->buf, 0, drvdata->size);
Mathieu Poirier45254122016-05-03 11:33:51 -0600341 tmc_etb_enable_hw(drvdata);
Mathieu Poirierde546192016-05-03 11:33:52 -0600342 } else {
343 /*
344 * The ETB/ETF is not tracing and the buffer was just read.
345 * As such prepare to free the trace buffer.
346 */
347 buf = drvdata->buf;
348 drvdata->buf = NULL;
349 }
Mathieu Poirier45254122016-05-03 11:33:51 -0600350
351 drvdata->reading = false;
352 spin_unlock_irqrestore(&drvdata->spinlock, flags);
353
Mathieu Poirierde546192016-05-03 11:33:52 -0600354 /*
355 * Free allocated memory outside of the spinlock. There is no need
356 * to assert the validity of 'buf' since calling kfree(NULL) is safe.
357 */
358 kfree(buf);
359
Mathieu Poirier45254122016-05-03 11:33:51 -0600360 return 0;
361}