1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2015-2023 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 #include "mali_kbase_timeline.h"
23 #include "mali_kbase_timeline_priv.h"
24 #include "mali_kbase_tracepoints.h"
25
26 #include <mali_kbase.h>
27 #include <linux/atomic.h>
28 #include <linux/file.h>
29 #include <linux/mutex.h>
30 #include <linux/spinlock.h>
31 #include <linux/string.h>
32 #include <linux/stringify.h>
33 #include <linux/timer.h>
34 #include <linux/wait.h>
35 #include <linux/delay.h>
36
37 /* The period of autoflush checker execution in milliseconds. */
38 #define AUTOFLUSH_INTERVAL 1000 /* ms */
39
40 /*****************************************************************************/
41
42 /* These values are used in mali_kbase_tracepoints.h
43 * to retrieve the streams from a kbase_timeline instance.
44 */
45 const size_t __obj_stream_offset =
46 offsetof(struct kbase_timeline, streams)
47 + sizeof(struct kbase_tlstream) * TL_STREAM_TYPE_OBJ;
48
49 const size_t __aux_stream_offset =
50 offsetof(struct kbase_timeline, streams)
51 + sizeof(struct kbase_tlstream) * TL_STREAM_TYPE_AUX;
52
53 /**
54 * kbasep_timeline_autoflush_timer_callback - autoflush timer callback
55 * @timer: Timer list
56 *
57 * Timer is executed periodically to check if any of the stream contains
58 * buffer ready to be submitted to user space.
59 */
kbasep_timeline_autoflush_timer_callback(struct timer_list * timer)60 static void kbasep_timeline_autoflush_timer_callback(struct timer_list *timer)
61 {
62 enum tl_stream_type stype;
63 int rcode;
64 struct kbase_timeline *timeline =
65 container_of(timer, struct kbase_timeline, autoflush_timer);
66
67 CSTD_UNUSED(timer);
68
69 for (stype = (enum tl_stream_type)0; stype < TL_STREAM_TYPE_COUNT;
70 stype++) {
71 struct kbase_tlstream *stream = &timeline->streams[stype];
72
73 int af_cnt = atomic_read(&stream->autoflush_counter);
74
75 /* Check if stream contain unflushed data. */
76 if (af_cnt < 0)
77 continue;
78
79 /* Check if stream should be flushed now. */
80 if (af_cnt != atomic_cmpxchg(
81 &stream->autoflush_counter,
82 af_cnt,
83 af_cnt + 1))
84 continue;
85 if (!af_cnt)
86 continue;
87
88 /* Autoflush this stream. */
89 kbase_tlstream_flush_stream(stream);
90 }
91
92 if (atomic_read(&timeline->autoflush_timer_active))
93 rcode = mod_timer(
94 &timeline->autoflush_timer,
95 jiffies + msecs_to_jiffies(AUTOFLUSH_INTERVAL));
96 CSTD_UNUSED(rcode);
97 }
98
99
100
101 /*****************************************************************************/
102
kbase_timeline_init(struct kbase_timeline ** timeline,atomic_t * timeline_flags)103 int kbase_timeline_init(struct kbase_timeline **timeline,
104 atomic_t *timeline_flags)
105 {
106 enum tl_stream_type i;
107 struct kbase_timeline *result;
108 #if MALI_USE_CSF
109 struct kbase_tlstream *csffw_stream;
110 #endif
111
112 if (!timeline || !timeline_flags)
113 return -EINVAL;
114
115 result = vzalloc(sizeof(*result));
116 if (!result)
117 return -ENOMEM;
118
119 mutex_init(&result->reader_lock);
120 init_waitqueue_head(&result->event_queue);
121
122 /* Prepare stream structures. */
123 for (i = 0; i < TL_STREAM_TYPE_COUNT; i++)
124 kbase_tlstream_init(&result->streams[i], i,
125 &result->event_queue);
126
127 /* Initialize the kctx list */
128 mutex_init(&result->tl_kctx_list_lock);
129 INIT_LIST_HEAD(&result->tl_kctx_list);
130
131 /* Initialize autoflush timer. */
132 atomic_set(&result->autoflush_timer_active, 0);
133 kbase_timer_setup(&result->autoflush_timer,
134 kbasep_timeline_autoflush_timer_callback);
135 result->timeline_flags = timeline_flags;
136
137 #if MALI_USE_CSF
138 csffw_stream = &result->streams[TL_STREAM_TYPE_CSFFW];
139 kbase_csf_tl_reader_init(&result->csf_tl_reader, csffw_stream);
140 #endif
141
142 *timeline = result;
143 return 0;
144 }
145
kbase_timeline_term(struct kbase_timeline * timeline)146 void kbase_timeline_term(struct kbase_timeline *timeline)
147 {
148 enum tl_stream_type i;
149
150 if (!timeline)
151 return;
152
153 #if MALI_USE_CSF
154 kbase_csf_tl_reader_term(&timeline->csf_tl_reader);
155 #endif
156
157 WARN_ON(!list_empty(&timeline->tl_kctx_list));
158
159 for (i = (enum tl_stream_type)0; i < TL_STREAM_TYPE_COUNT; i++)
160 kbase_tlstream_term(&timeline->streams[i]);
161
162 vfree(timeline);
163 }
164
165 #ifdef CONFIG_MALI_BIFROST_DEVFREQ
kbase_tlstream_current_devfreq_target(struct kbase_device * kbdev)166 static void kbase_tlstream_current_devfreq_target(struct kbase_device *kbdev)
167 {
168 struct devfreq *devfreq = kbdev->devfreq;
169
170 /* Devfreq initialization failure isn't a fatal error, so devfreq might
171 * be null.
172 */
173 if (devfreq) {
174 unsigned long cur_freq = 0;
175
176 mutex_lock(&devfreq->lock);
177 cur_freq = devfreq->last_status.current_frequency;
178 KBASE_TLSTREAM_AUX_DEVFREQ_TARGET(kbdev, (u64)cur_freq);
179 mutex_unlock(&devfreq->lock);
180 }
181 }
182 #endif /* CONFIG_MALI_BIFROST_DEVFREQ */
183
kbase_timeline_acquire(struct kbase_device * kbdev,u32 flags)184 int kbase_timeline_acquire(struct kbase_device *kbdev, u32 flags)
185 {
186 int err = 0;
187 u32 timeline_flags = TLSTREAM_ENABLED | flags;
188 struct kbase_timeline *timeline;
189 int rcode;
190
191 if (WARN_ON(!kbdev) || WARN_ON(flags & ~BASE_TLSTREAM_FLAGS_MASK))
192 return -EINVAL;
193
194 timeline = kbdev->timeline;
195 if (WARN_ON(!timeline))
196 return -EFAULT;
197
198 if (atomic_cmpxchg(timeline->timeline_flags, 0, timeline_flags))
199 return -EBUSY;
200
201 #if MALI_USE_CSF
202 if (flags & BASE_TLSTREAM_ENABLE_CSFFW_TRACEPOINTS) {
203 err = kbase_csf_tl_reader_start(&timeline->csf_tl_reader, kbdev);
204 if (err) {
205 atomic_set(timeline->timeline_flags, 0);
206 return err;
207 }
208 }
209 #endif
210
211 /* Reset and initialize header streams. */
212 kbase_tlstream_reset(&timeline->streams[TL_STREAM_TYPE_OBJ_SUMMARY]);
213
214 timeline->obj_header_btc = obj_desc_header_size;
215 timeline->aux_header_btc = aux_desc_header_size;
216
217 #if !MALI_USE_CSF
218 /* If job dumping is enabled, readjust the software event's
219 * timeout as the default value of 3 seconds is often
220 * insufficient.
221 */
222 if (flags & BASE_TLSTREAM_JOB_DUMPING_ENABLED) {
223 dev_info(kbdev->dev,
224 "Job dumping is enabled, readjusting the software event's timeout\n");
225 atomic_set(&kbdev->js_data.soft_job_timeout_ms, 1800000);
226 }
227 #endif /* !MALI_USE_CSF */
228
229 /* Summary stream was cleared during acquire.
230 * Create static timeline objects that will be
231 * read by client.
232 */
233 kbase_create_timeline_objects(kbdev);
234
235 #ifdef CONFIG_MALI_BIFROST_DEVFREQ
236 /* Devfreq target tracepoints are only fired when the target
237 * changes, so we won't know the current target unless we
238 * send it now.
239 */
240 kbase_tlstream_current_devfreq_target(kbdev);
241 #endif /* CONFIG_MALI_BIFROST_DEVFREQ */
242
243 /* Start the autoflush timer.
244 * We must do this after creating timeline objects to ensure we
245 * don't auto-flush the streams which will be reset during the
246 * summarization process.
247 */
248 atomic_set(&timeline->autoflush_timer_active, 1);
249 rcode = mod_timer(&timeline->autoflush_timer,
250 jiffies + msecs_to_jiffies(AUTOFLUSH_INTERVAL));
251 CSTD_UNUSED(rcode);
252
253 timeline->last_acquire_time = ktime_get_raw();
254
255 return err;
256 }
257
kbase_timeline_release(struct kbase_timeline * timeline)258 void kbase_timeline_release(struct kbase_timeline *timeline)
259 {
260 ktime_t elapsed_time;
261 s64 elapsed_time_ms, time_to_sleep;
262
263 if (WARN_ON(!timeline) || WARN_ON(!atomic_read(timeline->timeline_flags)))
264 return;
265
266 /* Get the amount of time passed since the timeline was acquired and ensure
267 * we sleep for long enough such that it has been at least
268 * TIMELINE_HYSTERESIS_TIMEOUT_MS amount of time between acquire and release.
269 * This prevents userspace from spamming acquire and release too quickly.
270 */
271 elapsed_time = ktime_sub(ktime_get_raw(), timeline->last_acquire_time);
272 elapsed_time_ms = ktime_to_ms(elapsed_time);
273 time_to_sleep = (elapsed_time_ms < 0 ? TIMELINE_HYSTERESIS_TIMEOUT_MS :
274 TIMELINE_HYSTERESIS_TIMEOUT_MS - elapsed_time_ms);
275 if (time_to_sleep > 0)
276 msleep_interruptible(time_to_sleep);
277
278 #if MALI_USE_CSF
279 kbase_csf_tl_reader_stop(&timeline->csf_tl_reader);
280 #endif
281
282 /* Stop autoflush timer before releasing access to streams. */
283 atomic_set(&timeline->autoflush_timer_active, 0);
284 del_timer_sync(&timeline->autoflush_timer);
285
286 atomic_set(timeline->timeline_flags, 0);
287 }
288
kbase_timeline_streams_flush(struct kbase_timeline * timeline)289 int kbase_timeline_streams_flush(struct kbase_timeline *timeline)
290 {
291 enum tl_stream_type stype;
292 bool has_bytes = false;
293 size_t nbytes = 0;
294
295 if (WARN_ON(!timeline))
296 return -EINVAL;
297
298 #if MALI_USE_CSF
299 {
300 int ret = kbase_csf_tl_reader_flush_buffer(&timeline->csf_tl_reader);
301
302 if (ret > 0)
303 has_bytes = true;
304 }
305 #endif
306
307 for (stype = 0; stype < TL_STREAM_TYPE_COUNT; stype++) {
308 nbytes = kbase_tlstream_flush_stream(&timeline->streams[stype]);
309 if (nbytes > 0)
310 has_bytes = true;
311 }
312 return has_bytes ? 0 : -EIO;
313 }
314
kbase_timeline_streams_body_reset(struct kbase_timeline * timeline)315 void kbase_timeline_streams_body_reset(struct kbase_timeline *timeline)
316 {
317 kbase_tlstream_reset(
318 &timeline->streams[TL_STREAM_TYPE_OBJ]);
319 kbase_tlstream_reset(
320 &timeline->streams[TL_STREAM_TYPE_AUX]);
321 #if MALI_USE_CSF
322 kbase_tlstream_reset(
323 &timeline->streams[TL_STREAM_TYPE_CSFFW]);
324 #endif
325 }
326
kbase_timeline_pre_kbase_context_destroy(struct kbase_context * kctx)327 void kbase_timeline_pre_kbase_context_destroy(struct kbase_context *kctx)
328 {
329 struct kbase_device *const kbdev = kctx->kbdev;
330 struct kbase_timeline *timeline = kbdev->timeline;
331
332 /* Remove the context from the list to ensure we don't try and
333 * summarize a context that is being destroyed.
334 *
335 * It's unsafe to try and summarize a context being destroyed as the
336 * locks we might normally attempt to acquire, and the data structures
337 * we would normally attempt to traverse could already be destroyed.
338 *
339 * In the case where the tlstream is acquired between this pre destroy
340 * call and the post destroy call, we will get a context destroy
341 * tracepoint without the corresponding context create tracepoint,
342 * but this will not affect the correctness of the object model.
343 */
344 mutex_lock(&timeline->tl_kctx_list_lock);
345 list_del_init(&kctx->tl_kctx_list_node);
346 mutex_unlock(&timeline->tl_kctx_list_lock);
347 }
348
kbase_timeline_post_kbase_context_create(struct kbase_context * kctx)349 void kbase_timeline_post_kbase_context_create(struct kbase_context *kctx)
350 {
351 struct kbase_device *const kbdev = kctx->kbdev;
352 struct kbase_timeline *timeline = kbdev->timeline;
353
354 /* On context create, add the context to the list to ensure it is
355 * summarized when timeline is acquired
356 */
357 mutex_lock(&timeline->tl_kctx_list_lock);
358
359 list_add(&kctx->tl_kctx_list_node, &timeline->tl_kctx_list);
360
361 /* Fire the tracepoints with the lock held to ensure the tracepoints
362 * are either fired before or after the summarization,
363 * never in parallel with it. If fired in parallel, we could get
364 * duplicate creation tracepoints.
365 */
366 #if MALI_USE_CSF
367 KBASE_TLSTREAM_TL_KBASE_NEW_CTX(
368 kbdev, kctx->id, kbdev->gpu_props.props.raw_props.gpu_id);
369 #endif
370 /* Trace with the AOM tracepoint even in CSF for dumping */
371 KBASE_TLSTREAM_TL_NEW_CTX(kbdev, kctx, kctx->id, 0);
372
373 mutex_unlock(&timeline->tl_kctx_list_lock);
374 }
375
kbase_timeline_post_kbase_context_destroy(struct kbase_context * kctx)376 void kbase_timeline_post_kbase_context_destroy(struct kbase_context *kctx)
377 {
378 struct kbase_device *const kbdev = kctx->kbdev;
379
380 /* Trace with the AOM tracepoint even in CSF for dumping */
381 KBASE_TLSTREAM_TL_DEL_CTX(kbdev, kctx);
382 #if MALI_USE_CSF
383 KBASE_TLSTREAM_TL_KBASE_DEL_CTX(kbdev, kctx->id);
384 #endif
385
386 /* Flush the timeline stream, so the user can see the termination
387 * tracepoints being fired.
388 * The "if" statement below is for optimization. It is safe to call
389 * kbase_timeline_streams_flush when timeline is disabled.
390 */
391 if (atomic_read(&kbdev->timeline_flags) != 0)
392 kbase_timeline_streams_flush(kbdev->timeline);
393 }
394
395 #if MALI_UNIT_TEST
kbase_timeline_stats(struct kbase_timeline * timeline,u32 * bytes_collected,u32 * bytes_generated)396 void kbase_timeline_stats(struct kbase_timeline *timeline,
397 u32 *bytes_collected, u32 *bytes_generated)
398 {
399 enum tl_stream_type stype;
400
401 KBASE_DEBUG_ASSERT(bytes_collected);
402
403 /* Accumulate bytes generated per stream */
404 *bytes_generated = 0;
405 for (stype = (enum tl_stream_type)0; stype < TL_STREAM_TYPE_COUNT;
406 stype++)
407 *bytes_generated += atomic_read(
408 &timeline->streams[stype].bytes_generated);
409
410 *bytes_collected = atomic_read(&timeline->bytes_collected);
411 }
412 #endif /* MALI_UNIT_TEST */
413