coresight: tmc: keep track of memory width
[firefly-linux-kernel-4.4.55.git] / drivers / hwtracing / coresight / coresight-tmc-etf.c
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/slab.h>
20 #include "coresight-priv.h"
21 #include "coresight-tmc.h"
22
23 void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
24 {
25         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
42 static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
43 {
44         char *bufp;
45         u32 read_data;
46         int i;
47
48         bufp = drvdata->buf;
49         while (1) {
50                 for (i = 0; i < drvdata->memwidth; i++) {
51                         read_data = readl_relaxed(drvdata->base + TMC_RRD);
52                         if (read_data == 0xFFFFFFFF)
53                                 return;
54                         memcpy(bufp, &read_data, 4);
55                         bufp += 4;
56                 }
57         }
58 }
59
60 static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
61 {
62         CS_UNLOCK(drvdata->base);
63
64         tmc_flush_and_stop(drvdata);
65         /*
66          * When operating in sysFS mode the content of the buffer needs to be
67          * read before the TMC is disabled.
68          */
69         if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
70                 tmc_etb_dump_hw(drvdata);
71         tmc_disable_hw(drvdata);
72
73         CS_LOCK(drvdata->base);
74 }
75
76 static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
77 {
78         CS_UNLOCK(drvdata->base);
79
80         /* Wait for TMCSReady bit to be set */
81         tmc_wait_for_tmcready(drvdata);
82
83         writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
84         writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
85                        drvdata->base + TMC_FFCR);
86         writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
87         tmc_enable_hw(drvdata);
88
89         CS_LOCK(drvdata->base);
90 }
91
92 static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
93 {
94         CS_UNLOCK(drvdata->base);
95
96         tmc_flush_and_stop(drvdata);
97         tmc_disable_hw(drvdata);
98
99         CS_LOCK(drvdata->base);
100 }
101
102 static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
103 {
104         int ret = 0;
105         bool used = false;
106         char *buf = NULL;
107         long val;
108         unsigned long flags;
109         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
110
111          /* This shouldn't be happening */
112         if (WARN_ON(mode != CS_MODE_SYSFS))
113                 return -EINVAL;
114
115         /*
116          * If we don't have a buffer release the lock and allocate memory.
117          * Otherwise keep the lock and move along.
118          */
119         spin_lock_irqsave(&drvdata->spinlock, flags);
120         if (!drvdata->buf) {
121                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
122
123                 /* Allocating the memory here while outside of the spinlock */
124                 buf = kzalloc(drvdata->size, GFP_KERNEL);
125                 if (!buf)
126                         return -ENOMEM;
127
128                 /* Let's try again */
129                 spin_lock_irqsave(&drvdata->spinlock, flags);
130         }
131
132         if (drvdata->reading) {
133                 ret = -EBUSY;
134                 goto out;
135         }
136
137         val = local_xchg(&drvdata->mode, mode);
138         /*
139          * In sysFS mode we can have multiple writers per sink.  Since this
140          * sink is already enabled no memory is needed and the HW need not be
141          * touched.
142          */
143         if (val == CS_MODE_SYSFS)
144                 goto out;
145
146         /*
147          * If drvdata::buf isn't NULL, memory was allocated for a previous
148          * trace run but wasn't read.  If so simply zero-out the memory.
149          * Otherwise use the memory allocated above.
150          *
151          * The memory is freed when users read the buffer using the
152          * /dev/xyz.{etf|etb} interface.  See tmc_read_unprepare_etf() for
153          * details.
154          */
155         if (drvdata->buf) {
156                 memset(drvdata->buf, 0, drvdata->size);
157         } else {
158                 used = true;
159                 drvdata->buf = buf;
160         }
161
162         tmc_etb_enable_hw(drvdata);
163 out:
164         spin_unlock_irqrestore(&drvdata->spinlock, flags);
165
166         /* Free memory outside the spinlock if need be */
167         if (!used && buf)
168                 kfree(buf);
169
170         if (!ret)
171                 dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
172
173         return ret;
174 }
175
176 static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
177 {
178         int ret = 0;
179         long val;
180         unsigned long flags;
181         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
182
183          /* This shouldn't be happening */
184         if (WARN_ON(mode != CS_MODE_PERF))
185                 return -EINVAL;
186
187         spin_lock_irqsave(&drvdata->spinlock, flags);
188         if (drvdata->reading) {
189                 ret = -EINVAL;
190                 goto out;
191         }
192
193         val = local_xchg(&drvdata->mode, mode);
194         /*
195          * In Perf mode there can be only one writer per sink.  There
196          * is also no need to continue if the ETB/ETR is already operated
197          * from sysFS.
198          */
199         if (val != CS_MODE_DISABLED) {
200                 ret = -EINVAL;
201                 goto out;
202         }
203
204         tmc_etb_enable_hw(drvdata);
205 out:
206         spin_unlock_irqrestore(&drvdata->spinlock, flags);
207
208         return ret;
209 }
210
211 static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
212 {
213         switch (mode) {
214         case CS_MODE_SYSFS:
215                 return tmc_enable_etf_sink_sysfs(csdev, mode);
216         case CS_MODE_PERF:
217                 return tmc_enable_etf_sink_perf(csdev, mode);
218         }
219
220         /* We shouldn't be here */
221         return -EINVAL;
222 }
223
224 static void tmc_disable_etf_sink(struct coresight_device *csdev)
225 {
226         long val;
227         unsigned long flags;
228         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
229
230         spin_lock_irqsave(&drvdata->spinlock, flags);
231         if (drvdata->reading) {
232                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
233                 return;
234         }
235
236         val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
237         /* Disable the TMC only if it needs to */
238         if (val != CS_MODE_DISABLED)
239                 tmc_etb_disable_hw(drvdata);
240
241         spin_unlock_irqrestore(&drvdata->spinlock, flags);
242
243         dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
244 }
245
246 static int tmc_enable_etf_link(struct coresight_device *csdev,
247                                int inport, int outport)
248 {
249         unsigned long flags;
250         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
251
252         spin_lock_irqsave(&drvdata->spinlock, flags);
253         if (drvdata->reading) {
254                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
255                 return -EBUSY;
256         }
257
258         tmc_etf_enable_hw(drvdata);
259         local_set(&drvdata->mode, CS_MODE_SYSFS);
260         spin_unlock_irqrestore(&drvdata->spinlock, flags);
261
262         dev_info(drvdata->dev, "TMC-ETF enabled\n");
263         return 0;
264 }
265
266 static void tmc_disable_etf_link(struct coresight_device *csdev,
267                                  int inport, int outport)
268 {
269         unsigned long flags;
270         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
271
272         spin_lock_irqsave(&drvdata->spinlock, flags);
273         if (drvdata->reading) {
274                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
275                 return;
276         }
277
278         tmc_etf_disable_hw(drvdata);
279         local_set(&drvdata->mode, CS_MODE_DISABLED);
280         spin_unlock_irqrestore(&drvdata->spinlock, flags);
281
282         dev_info(drvdata->dev, "TMC disabled\n");
283 }
284
285 static const struct coresight_ops_sink tmc_etf_sink_ops = {
286         .enable         = tmc_enable_etf_sink,
287         .disable        = tmc_disable_etf_sink,
288 };
289
290 static const struct coresight_ops_link tmc_etf_link_ops = {
291         .enable         = tmc_enable_etf_link,
292         .disable        = tmc_disable_etf_link,
293 };
294
295 const struct coresight_ops tmc_etb_cs_ops = {
296         .sink_ops       = &tmc_etf_sink_ops,
297 };
298
299 const struct coresight_ops tmc_etf_cs_ops = {
300         .sink_ops       = &tmc_etf_sink_ops,
301         .link_ops       = &tmc_etf_link_ops,
302 };
303
304 int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
305 {
306         long val;
307         enum tmc_mode mode;
308         int ret = 0;
309         unsigned long flags;
310
311         /* config types are set a boot time and never change */
312         if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
313                          drvdata->config_type != TMC_CONFIG_TYPE_ETF))
314                 return -EINVAL;
315
316         spin_lock_irqsave(&drvdata->spinlock, flags);
317
318         if (drvdata->reading) {
319                 ret = -EBUSY;
320                 goto out;
321         }
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                 ret = -EINVAL;
327                 goto out;
328         }
329
330         val = local_read(&drvdata->mode);
331         /* Don't interfere if operated from Perf */
332         if (val == CS_MODE_PERF) {
333                 ret = -EINVAL;
334                 goto out;
335         }
336
337         /* If drvdata::buf is NULL the trace data has been read already */
338         if (drvdata->buf == NULL) {
339                 ret = -EINVAL;
340                 goto out;
341         }
342
343         /* Disable the TMC if need be */
344         if (val == CS_MODE_SYSFS)
345                 tmc_etb_disable_hw(drvdata);
346
347         drvdata->reading = true;
348 out:
349         spin_unlock_irqrestore(&drvdata->spinlock, flags);
350
351         return ret;
352 }
353
354 int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
355 {
356         char *buf = NULL;
357         enum tmc_mode mode;
358         unsigned long flags;
359
360         /* config types are set a boot time and never change */
361         if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
362                          drvdata->config_type != TMC_CONFIG_TYPE_ETF))
363                 return -EINVAL;
364
365         spin_lock_irqsave(&drvdata->spinlock, flags);
366
367         /* There is no point in reading a TMC in HW FIFO mode */
368         mode = readl_relaxed(drvdata->base + TMC_MODE);
369         if (mode != TMC_MODE_CIRCULAR_BUFFER) {
370                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
371                 return -EINVAL;
372         }
373
374         /* Re-enable the TMC if need be */
375         if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
376                 /*
377                  * The trace run will continue with the same allocated trace
378                  * buffer. As such zero-out the buffer so that we don't end
379                  * up with stale data.
380                  *
381                  * Since the tracer is still enabled drvdata::buf
382                  * can't be NULL.
383                  */
384                 memset(drvdata->buf, 0, drvdata->size);
385                 tmc_etb_enable_hw(drvdata);
386         } else {
387                 /*
388                  * The ETB/ETF is not tracing and the buffer was just read.
389                  * As such prepare to free the trace buffer.
390                  */
391                 buf = drvdata->buf;
392                 drvdata->buf = NULL;
393         }
394
395         drvdata->reading = false;
396         spin_unlock_irqrestore(&drvdata->spinlock, flags);
397
398         /*
399          * Free allocated memory outside of the spinlock.  There is no need
400          * to assert the validity of 'buf' since calling kfree(NULL) is safe.
401          */
402         kfree(buf);
403
404         return 0;
405 }