1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2011-2022 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_vinstr.h"
23 #include "hwcnt/mali_kbase_hwcnt_virtualizer.h"
24 #include "hwcnt/mali_kbase_hwcnt_types.h"
25 #include <uapi/gpu/arm/bifrost/mali_kbase_hwcnt_reader.h>
26 #include "hwcnt/mali_kbase_hwcnt_gpu.h"
27 #include "hwcnt/mali_kbase_hwcnt_gpu_narrow.h"
28 #include <uapi/gpu/arm/bifrost/mali_kbase_ioctl.h>
29 #include "mali_malisw.h"
30 #include "mali_kbase_debug.h"
31
32 #include <linux/anon_inodes.h>
33 #include <linux/fcntl.h>
34 #include <linux/fs.h>
35 #include <linux/hrtimer.h>
36 #include <linux/log2.h>
37 #include <linux/mm.h>
38 #include <linux/mutex.h>
39 #include <linux/poll.h>
40 #include <linux/slab.h>
41 #include <linux/version_compat_defs.h>
42 #include <linux/workqueue.h>
43
44 /* Explicitly include epoll header for old kernels. Not required from 4.16. */
45 #if KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE
46 #include <uapi/linux/eventpoll.h>
47 #endif
48
49 /* Hwcnt reader API version */
50 #define HWCNT_READER_API 1
51
52 /* The minimum allowed interval between dumps (equivalent to 10KHz) */
53 #define DUMP_INTERVAL_MIN_NS (100 * NSEC_PER_USEC)
54
55 /* The maximum allowed buffers per client */
56 #define MAX_BUFFER_COUNT 32
57
58 /**
59 * struct kbase_vinstr_context - IOCTL interface for userspace hardware
60 * counters.
61 * @hvirt: Hardware counter virtualizer used by vinstr.
62 * @metadata: Hardware counter metadata provided by virtualizer.
63 * @metadata_user: API compatible hardware counter metadata provided by vinstr.
64 * For compatibility with the user driver interface, this
65 * contains a narrowed version of the HWCNT metadata limited
66 * to 64 entries per block of 32 bits each.
67 * @lock: Lock protecting all vinstr state.
68 * @suspend_count: Suspend reference count. If non-zero, timer and worker are
69 * prevented from being re-scheduled.
70 * @client_count: Number of vinstr clients.
71 * @clients: List of vinstr clients.
72 * @dump_timer: Timer that enqueues dump_work to a workqueue.
73 * @dump_work: Worker for performing periodic counter dumps.
74 */
75 struct kbase_vinstr_context {
76 struct kbase_hwcnt_virtualizer *hvirt;
77 const struct kbase_hwcnt_metadata *metadata;
78 const struct kbase_hwcnt_metadata_narrow *metadata_user;
79 struct mutex lock;
80 size_t suspend_count;
81 size_t client_count;
82 struct list_head clients;
83 struct hrtimer dump_timer;
84 struct work_struct dump_work;
85 };
86
87 /**
88 * struct kbase_vinstr_client - A vinstr client attached to a vinstr context.
89 * @vctx: Vinstr context client is attached to.
90 * @hvcli: Hardware counter virtualizer client.
91 * @node: Node used to attach this client to list in vinstr
92 * context.
93 * @dump_interval_ns: Interval between periodic dumps. If 0, not a periodic
94 * client.
95 * @next_dump_time_ns: Time in ns when this client's next periodic dump must
96 * occur. If 0, not a periodic client.
97 * @enable_map: Counters enable map.
98 * @tmp_buf: Temporary buffer to use before handing dump to client.
99 * @dump_bufs: Array of narrow dump buffers allocated by this client.
100 * @dump_bufs_meta: Metadata of hwcnt reader client buffers.
101 * @meta_idx: Index of metadata being accessed by userspace.
102 * @read_idx: Index of buffer read by userspace.
103 * @write_idx: Index of buffer being written by dump worker.
104 * @waitq: Client's notification queue.
105 */
106 struct kbase_vinstr_client {
107 struct kbase_vinstr_context *vctx;
108 struct kbase_hwcnt_virtualizer_client *hvcli;
109 struct list_head node;
110 u64 next_dump_time_ns;
111 u32 dump_interval_ns;
112 struct kbase_hwcnt_enable_map enable_map;
113 struct kbase_hwcnt_dump_buffer tmp_buf;
114 struct kbase_hwcnt_dump_buffer_narrow_array dump_bufs;
115 struct kbase_hwcnt_reader_metadata *dump_bufs_meta;
116 atomic_t meta_idx;
117 atomic_t read_idx;
118 atomic_t write_idx;
119 wait_queue_head_t waitq;
120 };
121
122 static __poll_t kbasep_vinstr_hwcnt_reader_poll(struct file *filp, poll_table *wait);
123
124 static long kbasep_vinstr_hwcnt_reader_ioctl(
125 struct file *filp,
126 unsigned int cmd,
127 unsigned long arg);
128
129 static int kbasep_vinstr_hwcnt_reader_mmap(
130 struct file *filp,
131 struct vm_area_struct *vma);
132
133 static int kbasep_vinstr_hwcnt_reader_release(
134 struct inode *inode,
135 struct file *filp);
136
137 /* Vinstr client file operations */
138 static const struct file_operations vinstr_client_fops = {
139 .owner = THIS_MODULE,
140 .poll = kbasep_vinstr_hwcnt_reader_poll,
141 .unlocked_ioctl = kbasep_vinstr_hwcnt_reader_ioctl,
142 .compat_ioctl = kbasep_vinstr_hwcnt_reader_ioctl,
143 .mmap = kbasep_vinstr_hwcnt_reader_mmap,
144 .release = kbasep_vinstr_hwcnt_reader_release,
145 };
146
147 /**
148 * kbasep_vinstr_timestamp_ns() - Get the current time in nanoseconds.
149 *
150 * Return: Current time in nanoseconds.
151 */
kbasep_vinstr_timestamp_ns(void)152 static u64 kbasep_vinstr_timestamp_ns(void)
153 {
154 return ktime_get_raw_ns();
155 }
156
157 /**
158 * kbasep_vinstr_next_dump_time_ns() - Calculate the next periodic dump time.
159 * @cur_ts_ns: Current time in nanoseconds.
160 * @interval: Interval between dumps in nanoseconds.
161 *
162 * Return: 0 if interval is 0 (i.e. a non-periodic client), or the next dump
163 * time that occurs after cur_ts_ns.
164 */
kbasep_vinstr_next_dump_time_ns(u64 cur_ts_ns,u32 interval)165 static u64 kbasep_vinstr_next_dump_time_ns(u64 cur_ts_ns, u32 interval)
166 {
167 /* Non-periodic client */
168 if (interval == 0)
169 return 0;
170
171 /*
172 * Return the next interval after the current time relative to t=0.
173 * This means multiple clients with the same period will synchronise,
174 * regardless of when they were started, allowing the worker to be
175 * scheduled less frequently.
176 */
177 do_div(cur_ts_ns, interval);
178 return (cur_ts_ns + 1) * interval;
179 }
180
181 /**
182 * kbasep_vinstr_client_dump() - Perform a dump for a client.
183 * @vcli: Non-NULL pointer to a vinstr client.
184 * @event_id: Event type that triggered the dump.
185 *
186 * Return: 0 on success, else error code.
187 */
kbasep_vinstr_client_dump(struct kbase_vinstr_client * vcli,enum base_hwcnt_reader_event event_id)188 static int kbasep_vinstr_client_dump(
189 struct kbase_vinstr_client *vcli,
190 enum base_hwcnt_reader_event event_id)
191 {
192 int errcode;
193 u64 ts_start_ns;
194 u64 ts_end_ns;
195 unsigned int write_idx;
196 unsigned int read_idx;
197 struct kbase_hwcnt_dump_buffer *tmp_buf;
198 struct kbase_hwcnt_dump_buffer_narrow *dump_buf;
199 struct kbase_hwcnt_reader_metadata *meta;
200 u8 clk_cnt;
201
202 WARN_ON(!vcli);
203 lockdep_assert_held(&vcli->vctx->lock);
204
205 write_idx = atomic_read(&vcli->write_idx);
206 read_idx = atomic_read(&vcli->read_idx);
207
208 /* Check if there is a place to copy HWC block into. */
209 if (write_idx - read_idx == vcli->dump_bufs.buf_cnt)
210 return -EBUSY;
211 write_idx %= vcli->dump_bufs.buf_cnt;
212
213 dump_buf = &vcli->dump_bufs.bufs[write_idx];
214 meta = &vcli->dump_bufs_meta[write_idx];
215 tmp_buf = &vcli->tmp_buf;
216
217 errcode = kbase_hwcnt_virtualizer_client_dump(
218 vcli->hvcli, &ts_start_ns, &ts_end_ns, tmp_buf);
219 if (errcode)
220 return errcode;
221
222 /* Patch the dump buf headers, to hide the counters that other hwcnt
223 * clients are using.
224 */
225 kbase_hwcnt_gpu_patch_dump_headers(tmp_buf, &vcli->enable_map);
226
227 /* Copy the temp buffer to the userspace visible buffer. The strict
228 * variant will explicitly zero any non-enabled counters to ensure
229 * nothing except exactly what the user asked for is made visible.
230 *
231 * A narrow copy is required since virtualizer has a bigger buffer
232 * but user only needs part of it.
233 */
234 kbase_hwcnt_dump_buffer_copy_strict_narrow(dump_buf, tmp_buf,
235 &vcli->enable_map);
236
237 clk_cnt = vcli->vctx->metadata->clk_cnt;
238
239 meta->timestamp = ts_end_ns;
240 meta->event_id = event_id;
241 meta->buffer_idx = write_idx;
242 meta->cycles.top = (clk_cnt > 0) ? dump_buf->clk_cnt_buf[0] : 0;
243 meta->cycles.shader_cores =
244 (clk_cnt > 1) ? dump_buf->clk_cnt_buf[1] : 0;
245
246 /* Notify client. Make sure all changes to memory are visible. */
247 wmb();
248 atomic_inc(&vcli->write_idx);
249 wake_up_interruptible(&vcli->waitq);
250 return 0;
251 }
252
253 /**
254 * kbasep_vinstr_client_clear() - Reset all the client's counters to zero.
255 * @vcli: Non-NULL pointer to a vinstr client.
256 *
257 * Return: 0 on success, else error code.
258 */
kbasep_vinstr_client_clear(struct kbase_vinstr_client * vcli)259 static int kbasep_vinstr_client_clear(struct kbase_vinstr_client *vcli)
260 {
261 u64 ts_start_ns;
262 u64 ts_end_ns;
263
264 WARN_ON(!vcli);
265 lockdep_assert_held(&vcli->vctx->lock);
266
267 /* A virtualizer dump with a NULL buffer will just clear the virtualizer
268 * client's buffer.
269 */
270 return kbase_hwcnt_virtualizer_client_dump(
271 vcli->hvcli, &ts_start_ns, &ts_end_ns, NULL);
272 }
273
274 /**
275 * kbasep_vinstr_reschedule_worker() - Update next dump times for all periodic
276 * vinstr clients, then reschedule the dump
277 * worker appropriately.
278 * @vctx: Non-NULL pointer to the vinstr context.
279 *
280 * If there are no periodic clients, then the dump worker will not be
281 * rescheduled. Else, the dump worker will be rescheduled for the next periodic
282 * client dump.
283 */
kbasep_vinstr_reschedule_worker(struct kbase_vinstr_context * vctx)284 static void kbasep_vinstr_reschedule_worker(struct kbase_vinstr_context *vctx)
285 {
286 u64 cur_ts_ns;
287 u64 earliest_next_ns = U64_MAX;
288 struct kbase_vinstr_client *pos;
289
290 WARN_ON(!vctx);
291 lockdep_assert_held(&vctx->lock);
292
293 cur_ts_ns = kbasep_vinstr_timestamp_ns();
294
295 /*
296 * Update each client's next dump time, and find the earliest next
297 * dump time if any of the clients have a non-zero interval.
298 */
299 list_for_each_entry(pos, &vctx->clients, node) {
300 const u64 cli_next_ns =
301 kbasep_vinstr_next_dump_time_ns(
302 cur_ts_ns, pos->dump_interval_ns);
303
304 /* Non-zero next dump time implies a periodic client */
305 if ((cli_next_ns != 0) && (cli_next_ns < earliest_next_ns))
306 earliest_next_ns = cli_next_ns;
307
308 pos->next_dump_time_ns = cli_next_ns;
309 }
310
311 /* Cancel the timer if it is already pending */
312 hrtimer_cancel(&vctx->dump_timer);
313
314 /* Start the timer if there are periodic clients and vinstr is not
315 * suspended.
316 */
317 if ((earliest_next_ns != U64_MAX) &&
318 (vctx->suspend_count == 0) &&
319 !WARN_ON(earliest_next_ns < cur_ts_ns))
320 hrtimer_start(
321 &vctx->dump_timer,
322 ns_to_ktime(earliest_next_ns - cur_ts_ns),
323 HRTIMER_MODE_REL);
324 }
325
326 /**
327 * kbasep_vinstr_dump_worker()- Dump worker, that dumps all periodic clients
328 * that need to be dumped, then reschedules itself.
329 * @work: Work structure.
330 */
kbasep_vinstr_dump_worker(struct work_struct * work)331 static void kbasep_vinstr_dump_worker(struct work_struct *work)
332 {
333 struct kbase_vinstr_context *vctx =
334 container_of(work, struct kbase_vinstr_context, dump_work);
335 struct kbase_vinstr_client *pos;
336 u64 cur_time_ns;
337
338 mutex_lock(&vctx->lock);
339
340 cur_time_ns = kbasep_vinstr_timestamp_ns();
341
342 /* Dump all periodic clients whose next dump time is before the current
343 * time.
344 */
345 list_for_each_entry(pos, &vctx->clients, node) {
346 if ((pos->next_dump_time_ns != 0) &&
347 (pos->next_dump_time_ns < cur_time_ns))
348 kbasep_vinstr_client_dump(
349 pos, BASE_HWCNT_READER_EVENT_PERIODIC);
350 }
351
352 /* Update the next dump times of all periodic clients, then reschedule
353 * this worker at the earliest next dump time.
354 */
355 kbasep_vinstr_reschedule_worker(vctx);
356
357 mutex_unlock(&vctx->lock);
358 }
359
360 /**
361 * kbasep_vinstr_dump_timer() - Dump timer that schedules the dump worker for
362 * execution as soon as possible.
363 * @timer: Timer structure.
364 *
365 * Return: HRTIMER_NORESTART always.
366 */
kbasep_vinstr_dump_timer(struct hrtimer * timer)367 static enum hrtimer_restart kbasep_vinstr_dump_timer(struct hrtimer *timer)
368 {
369 struct kbase_vinstr_context *vctx =
370 container_of(timer, struct kbase_vinstr_context, dump_timer);
371
372 /* We don't need to check vctx->suspend_count here, as the suspend
373 * function will ensure that any worker enqueued here is immediately
374 * cancelled, and the worker itself won't reschedule this timer if
375 * suspend_count != 0.
376 */
377 kbase_hwcnt_virtualizer_queue_work(vctx->hvirt, &vctx->dump_work);
378 return HRTIMER_NORESTART;
379 }
380
381 /**
382 * kbasep_vinstr_client_destroy() - Destroy a vinstr client.
383 * @vcli: vinstr client. Must not be attached to a vinstr context.
384 */
kbasep_vinstr_client_destroy(struct kbase_vinstr_client * vcli)385 static void kbasep_vinstr_client_destroy(struct kbase_vinstr_client *vcli)
386 {
387 if (!vcli)
388 return;
389
390 kbase_hwcnt_virtualizer_client_destroy(vcli->hvcli);
391 kfree(vcli->dump_bufs_meta);
392 kbase_hwcnt_dump_buffer_narrow_array_free(&vcli->dump_bufs);
393 kbase_hwcnt_dump_buffer_free(&vcli->tmp_buf);
394 kbase_hwcnt_enable_map_free(&vcli->enable_map);
395 kfree(vcli);
396 }
397
398 /**
399 * kbasep_vinstr_client_create() - Create a vinstr client. Does not attach to
400 * the vinstr context.
401 * @vctx: Non-NULL pointer to vinstr context.
402 * @setup: Non-NULL pointer to hardware counter ioctl setup structure.
403 * setup->buffer_count must not be 0 and must be a power of 2.
404 * @out_vcli: Non-NULL pointer to where created client will be stored on
405 * success.
406 *
407 * Return: 0 on success, else error code.
408 */
kbasep_vinstr_client_create(struct kbase_vinstr_context * vctx,struct kbase_ioctl_hwcnt_reader_setup * setup,struct kbase_vinstr_client ** out_vcli)409 static int kbasep_vinstr_client_create(
410 struct kbase_vinstr_context *vctx,
411 struct kbase_ioctl_hwcnt_reader_setup *setup,
412 struct kbase_vinstr_client **out_vcli)
413 {
414 int errcode;
415 struct kbase_vinstr_client *vcli;
416 struct kbase_hwcnt_physical_enable_map phys_em;
417
418 WARN_ON(!vctx);
419 WARN_ON(!setup);
420 WARN_ON(setup->buffer_count == 0);
421 WARN_ON(!is_power_of_2(setup->buffer_count));
422
423 vcli = kzalloc(sizeof(*vcli), GFP_KERNEL);
424 if (!vcli)
425 return -ENOMEM;
426
427 vcli->vctx = vctx;
428
429 errcode = kbase_hwcnt_enable_map_alloc(
430 vctx->metadata, &vcli->enable_map);
431 if (errcode)
432 goto error;
433
434 phys_em.fe_bm = setup->fe_bm;
435 phys_em.shader_bm = setup->shader_bm;
436 phys_em.tiler_bm = setup->tiler_bm;
437 phys_em.mmu_l2_bm = setup->mmu_l2_bm;
438 kbase_hwcnt_gpu_enable_map_from_physical(&vcli->enable_map, &phys_em);
439
440 /* Use virtualizer's metadata to alloc tmp buffer which interacts with
441 * the HWC virtualizer.
442 */
443 errcode = kbase_hwcnt_dump_buffer_alloc(vctx->metadata, &vcli->tmp_buf);
444 if (errcode)
445 goto error;
446
447 /* Enable all the available clk_enable_map. */
448 vcli->enable_map.clk_enable_map = (1ull << vctx->metadata->clk_cnt) - 1;
449
450 /* Use vinstr's narrowed metadata to alloc narrow dump buffers which
451 * interact with clients.
452 */
453 errcode = kbase_hwcnt_dump_buffer_narrow_array_alloc(
454 vctx->metadata_user, setup->buffer_count, &vcli->dump_bufs);
455 if (errcode)
456 goto error;
457
458 errcode = -ENOMEM;
459 vcli->dump_bufs_meta = kmalloc_array(
460 setup->buffer_count, sizeof(*vcli->dump_bufs_meta), GFP_KERNEL);
461 if (!vcli->dump_bufs_meta)
462 goto error;
463
464 errcode = kbase_hwcnt_virtualizer_client_create(
465 vctx->hvirt, &vcli->enable_map, &vcli->hvcli);
466 if (errcode)
467 goto error;
468
469 init_waitqueue_head(&vcli->waitq);
470
471 *out_vcli = vcli;
472 return 0;
473 error:
474 kbasep_vinstr_client_destroy(vcli);
475 return errcode;
476 }
477
kbase_vinstr_init(struct kbase_hwcnt_virtualizer * hvirt,struct kbase_vinstr_context ** out_vctx)478 int kbase_vinstr_init(
479 struct kbase_hwcnt_virtualizer *hvirt,
480 struct kbase_vinstr_context **out_vctx)
481 {
482 int errcode;
483 struct kbase_vinstr_context *vctx;
484 const struct kbase_hwcnt_metadata *metadata;
485
486 if (!hvirt || !out_vctx)
487 return -EINVAL;
488
489 metadata = kbase_hwcnt_virtualizer_metadata(hvirt);
490 if (!metadata)
491 return -EINVAL;
492
493 vctx = kzalloc(sizeof(*vctx), GFP_KERNEL);
494 if (!vctx)
495 return -ENOMEM;
496
497 vctx->hvirt = hvirt;
498 vctx->metadata = metadata;
499 errcode = kbase_hwcnt_gpu_metadata_narrow_create(&vctx->metadata_user,
500 metadata);
501 if (errcode)
502 goto err_metadata_create;
503
504 mutex_init(&vctx->lock);
505 INIT_LIST_HEAD(&vctx->clients);
506 hrtimer_init(&vctx->dump_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
507 vctx->dump_timer.function = kbasep_vinstr_dump_timer;
508 INIT_WORK(&vctx->dump_work, kbasep_vinstr_dump_worker);
509
510 *out_vctx = vctx;
511 return 0;
512
513 err_metadata_create:
514 kfree(vctx);
515
516 return errcode;
517 }
518
kbase_vinstr_term(struct kbase_vinstr_context * vctx)519 void kbase_vinstr_term(struct kbase_vinstr_context *vctx)
520 {
521 if (!vctx)
522 return;
523
524 /* Non-zero client count implies client leak */
525 if (WARN_ON(vctx->client_count != 0)) {
526 struct kbase_vinstr_client *pos, *n;
527
528 list_for_each_entry_safe(pos, n, &vctx->clients, node) {
529 list_del(&pos->node);
530 vctx->client_count--;
531 kbasep_vinstr_client_destroy(pos);
532 }
533 }
534
535 cancel_work_sync(&vctx->dump_work);
536 kbase_hwcnt_gpu_metadata_narrow_destroy(vctx->metadata_user);
537
538 WARN_ON(vctx->client_count != 0);
539 kfree(vctx);
540 }
541
kbase_vinstr_suspend(struct kbase_vinstr_context * vctx)542 void kbase_vinstr_suspend(struct kbase_vinstr_context *vctx)
543 {
544 if (WARN_ON(!vctx))
545 return;
546
547 mutex_lock(&vctx->lock);
548
549 if (!WARN_ON(vctx->suspend_count == SIZE_MAX))
550 vctx->suspend_count++;
551
552 mutex_unlock(&vctx->lock);
553
554 /* Always sync cancel the timer and then the worker, regardless of the
555 * new suspend count.
556 *
557 * This ensures concurrent calls to kbase_vinstr_suspend() always block
558 * until vinstr is fully suspended.
559 *
560 * The timer is cancelled before the worker, as the timer
561 * unconditionally re-enqueues the worker, but the worker checks the
562 * suspend_count that we just incremented before rescheduling the timer.
563 *
564 * Therefore if we cancel the worker first, the timer might re-enqueue
565 * the worker before we cancel the timer, but the opposite is not
566 * possible.
567 */
568 hrtimer_cancel(&vctx->dump_timer);
569 cancel_work_sync(&vctx->dump_work);
570 }
571
kbase_vinstr_resume(struct kbase_vinstr_context * vctx)572 void kbase_vinstr_resume(struct kbase_vinstr_context *vctx)
573 {
574 if (WARN_ON(!vctx))
575 return;
576
577 mutex_lock(&vctx->lock);
578
579 if (!WARN_ON(vctx->suspend_count == 0)) {
580 vctx->suspend_count--;
581
582 /* Last resume, so re-enqueue the worker if we have any periodic
583 * clients.
584 */
585 if (vctx->suspend_count == 0) {
586 struct kbase_vinstr_client *pos;
587 bool has_periodic_clients = false;
588
589 list_for_each_entry(pos, &vctx->clients, node) {
590 if (pos->dump_interval_ns != 0) {
591 has_periodic_clients = true;
592 break;
593 }
594 }
595
596 if (has_periodic_clients)
597 kbase_hwcnt_virtualizer_queue_work(
598 vctx->hvirt, &vctx->dump_work);
599 }
600 }
601
602 mutex_unlock(&vctx->lock);
603 }
604
kbase_vinstr_hwcnt_reader_setup(struct kbase_vinstr_context * vctx,struct kbase_ioctl_hwcnt_reader_setup * setup)605 int kbase_vinstr_hwcnt_reader_setup(
606 struct kbase_vinstr_context *vctx,
607 struct kbase_ioctl_hwcnt_reader_setup *setup)
608 {
609 int errcode;
610 int fd;
611 struct kbase_vinstr_client *vcli = NULL;
612
613 if (!vctx || !setup ||
614 (setup->buffer_count == 0) ||
615 (setup->buffer_count > MAX_BUFFER_COUNT) ||
616 !is_power_of_2(setup->buffer_count))
617 return -EINVAL;
618
619 errcode = kbasep_vinstr_client_create(vctx, setup, &vcli);
620 if (errcode)
621 goto error;
622
623 /* Add the new client. No need to reschedule worker, as not periodic */
624 mutex_lock(&vctx->lock);
625
626 vctx->client_count++;
627 list_add(&vcli->node, &vctx->clients);
628
629 mutex_unlock(&vctx->lock);
630
631 /* Expose to user-space only once the client is fully initialized */
632 errcode = anon_inode_getfd(
633 "[mali_vinstr_desc]",
634 &vinstr_client_fops,
635 vcli,
636 O_RDONLY | O_CLOEXEC);
637 if (errcode < 0)
638 goto client_installed_error;
639
640 fd = errcode;
641
642 return fd;
643
644 client_installed_error:
645 mutex_lock(&vctx->lock);
646
647 vctx->client_count--;
648 list_del(&vcli->node);
649
650 mutex_unlock(&vctx->lock);
651 error:
652 kbasep_vinstr_client_destroy(vcli);
653 return errcode;
654 }
655
656 /**
657 * kbasep_vinstr_hwcnt_reader_buffer_ready() - Check if client has ready
658 * buffers.
659 * @cli: Non-NULL pointer to vinstr client.
660 *
661 * Return: Non-zero if client has at least one dumping buffer filled that was
662 * not notified to user yet.
663 */
kbasep_vinstr_hwcnt_reader_buffer_ready(struct kbase_vinstr_client * cli)664 static int kbasep_vinstr_hwcnt_reader_buffer_ready(
665 struct kbase_vinstr_client *cli)
666 {
667 WARN_ON(!cli);
668 return atomic_read(&cli->write_idx) != atomic_read(&cli->meta_idx);
669 }
670
671 /**
672 * kbasep_vinstr_hwcnt_reader_ioctl_dump() - Dump ioctl command.
673 * @cli: Non-NULL pointer to vinstr client.
674 *
675 * Return: 0 on success, else error code.
676 */
kbasep_vinstr_hwcnt_reader_ioctl_dump(struct kbase_vinstr_client * cli)677 static long kbasep_vinstr_hwcnt_reader_ioctl_dump(
678 struct kbase_vinstr_client *cli)
679 {
680 int errcode;
681
682 mutex_lock(&cli->vctx->lock);
683
684 errcode = kbasep_vinstr_client_dump(
685 cli, BASE_HWCNT_READER_EVENT_MANUAL);
686
687 mutex_unlock(&cli->vctx->lock);
688 return errcode;
689 }
690
691 /**
692 * kbasep_vinstr_hwcnt_reader_ioctl_clear() - Clear ioctl command.
693 * @cli: Non-NULL pointer to vinstr client.
694 *
695 * Return: 0 on success, else error code.
696 */
kbasep_vinstr_hwcnt_reader_ioctl_clear(struct kbase_vinstr_client * cli)697 static long kbasep_vinstr_hwcnt_reader_ioctl_clear(
698 struct kbase_vinstr_client *cli)
699 {
700 int errcode;
701
702 mutex_lock(&cli->vctx->lock);
703
704 errcode = kbasep_vinstr_client_clear(cli);
705
706 mutex_unlock(&cli->vctx->lock);
707 return errcode;
708 }
709
710 /**
711 * kbasep_vinstr_hwcnt_reader_ioctl_get_buffer() - Get buffer ioctl command.
712 * @cli: Non-NULL pointer to vinstr client.
713 * @buffer: Non-NULL pointer to userspace buffer.
714 * @size: Size of buffer.
715 *
716 * Return: 0 on success, else error code.
717 */
kbasep_vinstr_hwcnt_reader_ioctl_get_buffer(struct kbase_vinstr_client * cli,void __user * buffer,size_t size)718 static long kbasep_vinstr_hwcnt_reader_ioctl_get_buffer(
719 struct kbase_vinstr_client *cli,
720 void __user *buffer,
721 size_t size)
722 {
723 unsigned int meta_idx = atomic_read(&cli->meta_idx);
724 unsigned int idx = meta_idx % cli->dump_bufs.buf_cnt;
725
726 struct kbase_hwcnt_reader_metadata *meta = &cli->dump_bufs_meta[idx];
727 const size_t meta_size = sizeof(struct kbase_hwcnt_reader_metadata);
728 const size_t min_size = min(size, meta_size);
729
730 /* Metadata sanity check. */
731 WARN_ON(idx != meta->buffer_idx);
732
733 /* Check if there is any buffer available. */
734 if (unlikely(atomic_read(&cli->write_idx) == meta_idx))
735 return -EAGAIN;
736
737 /* Check if previously taken buffer was put back. */
738 if (unlikely(atomic_read(&cli->read_idx) != meta_idx))
739 return -EBUSY;
740
741 /* Clear user buffer to zero. */
742 if (unlikely(meta_size < size && clear_user(buffer, size)))
743 return -EFAULT;
744
745 /* Copy next available buffer's metadata to user. */
746 if (unlikely(copy_to_user(buffer, meta, min_size)))
747 return -EFAULT;
748
749 /* Compare exchange meta idx to protect against concurrent getters */
750 if (meta_idx != atomic_cmpxchg(&cli->meta_idx, meta_idx, meta_idx + 1))
751 return -EBUSY;
752
753 return 0;
754 }
755
756 /**
757 * kbasep_vinstr_hwcnt_reader_ioctl_put_buffer() - Put buffer ioctl command.
758 * @cli: Non-NULL pointer to vinstr client.
759 * @buffer: Non-NULL pointer to userspace buffer.
760 * @size: Size of buffer.
761 *
762 * Return: 0 on success, else error code.
763 */
kbasep_vinstr_hwcnt_reader_ioctl_put_buffer(struct kbase_vinstr_client * cli,void __user * buffer,size_t size)764 static long kbasep_vinstr_hwcnt_reader_ioctl_put_buffer(
765 struct kbase_vinstr_client *cli,
766 void __user *buffer,
767 size_t size)
768 {
769 unsigned int read_idx = atomic_read(&cli->read_idx);
770 unsigned int idx = read_idx % cli->dump_bufs.buf_cnt;
771
772 struct kbase_hwcnt_reader_metadata *meta;
773 const size_t meta_size = sizeof(struct kbase_hwcnt_reader_metadata);
774 const size_t max_size = max(size, meta_size);
775 int ret = 0;
776 u8 stack_kbuf[64];
777 u8 *kbuf = NULL;
778 size_t i;
779
780 /* Check if any buffer was taken. */
781 if (unlikely(atomic_read(&cli->meta_idx) == read_idx))
782 return -EPERM;
783
784 if (likely(max_size <= sizeof(stack_kbuf))) {
785 /* Use stack buffer when the size is small enough. */
786 if (unlikely(meta_size > size))
787 memset(stack_kbuf, 0, sizeof(stack_kbuf));
788 kbuf = stack_kbuf;
789 } else {
790 kbuf = kzalloc(max_size, GFP_KERNEL);
791 if (unlikely(!kbuf))
792 return -ENOMEM;
793 }
794
795 /*
796 * Copy user buffer to zero cleared kernel buffer which has enough
797 * space for both user buffer and kernel metadata.
798 */
799 if (unlikely(copy_from_user(kbuf, buffer, size))) {
800 ret = -EFAULT;
801 goto out;
802 }
803
804 /*
805 * Make sure any "extra" data passed from userspace is zero.
806 * It's meaningful only in case meta_size < size.
807 */
808 for (i = meta_size; i < size; i++) {
809 /* Check if user data beyond meta size is zero. */
810 if (unlikely(kbuf[i] != 0)) {
811 ret = -EINVAL;
812 goto out;
813 }
814 }
815
816 /* Check if correct buffer is put back. */
817 meta = (struct kbase_hwcnt_reader_metadata *)kbuf;
818 if (unlikely(idx != meta->buffer_idx)) {
819 ret = -EINVAL;
820 goto out;
821 }
822
823 /* Compare exchange read idx to protect against concurrent putters */
824 if (read_idx !=
825 atomic_cmpxchg(&cli->read_idx, read_idx, read_idx + 1)) {
826 ret = -EPERM;
827 goto out;
828 }
829
830 out:
831 if (unlikely(kbuf != stack_kbuf))
832 kfree(kbuf);
833 return ret;
834 }
835
836 /**
837 * kbasep_vinstr_hwcnt_reader_ioctl_set_interval() - Set interval ioctl command.
838 * @cli: Non-NULL pointer to vinstr client.
839 * @interval: Periodic dumping interval (disable periodic dumping if 0).
840 *
841 * Return: 0 always.
842 */
kbasep_vinstr_hwcnt_reader_ioctl_set_interval(struct kbase_vinstr_client * cli,u32 interval)843 static long kbasep_vinstr_hwcnt_reader_ioctl_set_interval(
844 struct kbase_vinstr_client *cli,
845 u32 interval)
846 {
847 mutex_lock(&cli->vctx->lock);
848
849 if ((interval != 0) && (interval < DUMP_INTERVAL_MIN_NS))
850 interval = DUMP_INTERVAL_MIN_NS;
851 /* Update the interval, and put in a dummy next dump time */
852 cli->dump_interval_ns = interval;
853 cli->next_dump_time_ns = 0;
854
855 /*
856 * If it's a periodic client, kick off the worker early to do a proper
857 * timer reschedule. Return value is ignored, as we don't care if the
858 * worker is already queued.
859 */
860 if ((interval != 0) && (cli->vctx->suspend_count == 0))
861 kbase_hwcnt_virtualizer_queue_work(cli->vctx->hvirt,
862 &cli->vctx->dump_work);
863
864 mutex_unlock(&cli->vctx->lock);
865
866 return 0;
867 }
868
869 /**
870 * kbasep_vinstr_hwcnt_reader_ioctl_enable_event() - Enable event ioctl command.
871 * @cli: Non-NULL pointer to vinstr client.
872 * @event_id: ID of event to enable.
873 *
874 * Return: 0 always.
875 */
kbasep_vinstr_hwcnt_reader_ioctl_enable_event(struct kbase_vinstr_client * cli,enum base_hwcnt_reader_event event_id)876 static long kbasep_vinstr_hwcnt_reader_ioctl_enable_event(
877 struct kbase_vinstr_client *cli,
878 enum base_hwcnt_reader_event event_id)
879 {
880 /* No-op, as events aren't supported */
881 return 0;
882 }
883
884 /**
885 * kbasep_vinstr_hwcnt_reader_ioctl_disable_event() - Disable event ioctl
886 * command.
887 * @cli: Non-NULL pointer to vinstr client.
888 * @event_id: ID of event to disable.
889 *
890 * Return: 0 always.
891 */
kbasep_vinstr_hwcnt_reader_ioctl_disable_event(struct kbase_vinstr_client * cli,enum base_hwcnt_reader_event event_id)892 static long kbasep_vinstr_hwcnt_reader_ioctl_disable_event(
893 struct kbase_vinstr_client *cli,
894 enum base_hwcnt_reader_event event_id)
895 {
896 /* No-op, as events aren't supported */
897 return 0;
898 }
899
900 /**
901 * kbasep_vinstr_hwcnt_reader_ioctl_get_hwver() - Get HW version ioctl command.
902 * @cli: Non-NULL pointer to vinstr client.
903 * @hwver: Non-NULL pointer to user buffer where HW version will be stored.
904 *
905 * Return: 0 on success, else error code.
906 */
kbasep_vinstr_hwcnt_reader_ioctl_get_hwver(struct kbase_vinstr_client * cli,u32 __user * hwver)907 static long kbasep_vinstr_hwcnt_reader_ioctl_get_hwver(
908 struct kbase_vinstr_client *cli,
909 u32 __user *hwver)
910 {
911 u32 ver = 5;
912 const enum kbase_hwcnt_gpu_group_type type =
913 kbase_hwcnt_metadata_group_type(cli->vctx->metadata, 0);
914
915 if (WARN_ON(type != KBASE_HWCNT_GPU_GROUP_TYPE_V5))
916 return -EINVAL;
917
918 return put_user(ver, hwver);
919 }
920
921 /**
922 * kbasep_vinstr_hwcnt_reader_ioctl_get_api_version() - get API version ioctl
923 * command.
924 * @cli: The non-NULL pointer to the client
925 * @arg: Command's argument.
926 * @size: Size of arg.
927 *
928 * Return: 0 on success, else error code.
929 */
kbasep_vinstr_hwcnt_reader_ioctl_get_api_version(struct kbase_vinstr_client * cli,unsigned long arg,size_t size)930 static long kbasep_vinstr_hwcnt_reader_ioctl_get_api_version(
931 struct kbase_vinstr_client *cli, unsigned long arg, size_t size)
932 {
933 long ret = -EINVAL;
934
935 if (size == sizeof(u32)) {
936 ret = put_user(HWCNT_READER_API, (u32 __user *)arg);
937 } else if (size == sizeof(struct kbase_hwcnt_reader_api_version)) {
938 u8 clk_cnt = cli->vctx->metadata->clk_cnt;
939 unsigned long bytes = 0;
940 struct kbase_hwcnt_reader_api_version api_version = {
941 .version = HWCNT_READER_API,
942 .features = KBASE_HWCNT_READER_API_VERSION_NO_FEATURE,
943 };
944
945 if (clk_cnt > 0)
946 api_version.features |=
947 KBASE_HWCNT_READER_API_VERSION_FEATURE_CYCLES_TOP;
948 if (clk_cnt > 1)
949 api_version.features |=
950 KBASE_HWCNT_READER_API_VERSION_FEATURE_CYCLES_SHADER_CORES;
951
952 bytes = copy_to_user(
953 (void __user *)arg, &api_version, sizeof(api_version));
954
955 /* copy_to_user returns zero in case of success.
956 * If it fails, it returns the number of bytes that could NOT be copied
957 */
958 if (bytes == 0)
959 ret = 0;
960 else
961 ret = -EFAULT;
962 }
963 return ret;
964 }
965
966 /**
967 * kbasep_vinstr_hwcnt_reader_ioctl() - hwcnt reader's ioctl.
968 * @filp: Non-NULL pointer to file structure.
969 * @cmd: User command.
970 * @arg: Command's argument.
971 *
972 * Return: 0 on success, else error code.
973 */
kbasep_vinstr_hwcnt_reader_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)974 static long kbasep_vinstr_hwcnt_reader_ioctl(
975 struct file *filp,
976 unsigned int cmd,
977 unsigned long arg)
978 {
979 long rcode;
980 struct kbase_vinstr_client *cli;
981
982 if (!filp || (_IOC_TYPE(cmd) != KBASE_HWCNT_READER))
983 return -EINVAL;
984
985 cli = filp->private_data;
986 if (!cli)
987 return -EINVAL;
988
989 switch (_IOC_NR(cmd)) {
990 case _IOC_NR(KBASE_HWCNT_READER_GET_API_VERSION):
991 rcode = kbasep_vinstr_hwcnt_reader_ioctl_get_api_version(
992 cli, arg, _IOC_SIZE(cmd));
993 break;
994 case _IOC_NR(KBASE_HWCNT_READER_GET_HWVER):
995 rcode = kbasep_vinstr_hwcnt_reader_ioctl_get_hwver(
996 cli, (u32 __user *)arg);
997 break;
998 case _IOC_NR(KBASE_HWCNT_READER_GET_BUFFER_SIZE):
999 rcode = put_user((u32)cli->vctx->metadata_user->dump_buf_bytes,
1000 (u32 __user *)arg);
1001 break;
1002 case _IOC_NR(KBASE_HWCNT_READER_DUMP):
1003 rcode = kbasep_vinstr_hwcnt_reader_ioctl_dump(cli);
1004 break;
1005 case _IOC_NR(KBASE_HWCNT_READER_CLEAR):
1006 rcode = kbasep_vinstr_hwcnt_reader_ioctl_clear(cli);
1007 break;
1008 case _IOC_NR(KBASE_HWCNT_READER_GET_BUFFER):
1009 rcode = kbasep_vinstr_hwcnt_reader_ioctl_get_buffer(
1010 cli, (void __user *)arg, _IOC_SIZE(cmd));
1011 break;
1012 case _IOC_NR(KBASE_HWCNT_READER_PUT_BUFFER):
1013 rcode = kbasep_vinstr_hwcnt_reader_ioctl_put_buffer(
1014 cli, (void __user *)arg, _IOC_SIZE(cmd));
1015 break;
1016 case _IOC_NR(KBASE_HWCNT_READER_SET_INTERVAL):
1017 rcode = kbasep_vinstr_hwcnt_reader_ioctl_set_interval(
1018 cli, (u32)arg);
1019 break;
1020 case _IOC_NR(KBASE_HWCNT_READER_ENABLE_EVENT):
1021 rcode = kbasep_vinstr_hwcnt_reader_ioctl_enable_event(
1022 cli, (enum base_hwcnt_reader_event)arg);
1023 break;
1024 case _IOC_NR(KBASE_HWCNT_READER_DISABLE_EVENT):
1025 rcode = kbasep_vinstr_hwcnt_reader_ioctl_disable_event(
1026 cli, (enum base_hwcnt_reader_event)arg);
1027 break;
1028 default:
1029 pr_warn("Unknown HWCNT ioctl 0x%x nr:%d", cmd, _IOC_NR(cmd));
1030 rcode = -EINVAL;
1031 break;
1032 }
1033
1034 return rcode;
1035 }
1036
1037 /**
1038 * kbasep_vinstr_hwcnt_reader_poll() - hwcnt reader's poll.
1039 * @filp: Non-NULL pointer to file structure.
1040 * @wait: Non-NULL pointer to poll table.
1041 *
1042 * Return: EPOLLIN | EPOLLRDNORM if data can be read without blocking, 0 if
1043 * data can not be read without blocking, else EPOLLHUP | EPOLLERR.
1044 */
kbasep_vinstr_hwcnt_reader_poll(struct file * filp,poll_table * wait)1045 static __poll_t kbasep_vinstr_hwcnt_reader_poll(struct file *filp, poll_table *wait)
1046 {
1047 struct kbase_vinstr_client *cli;
1048
1049 if (!filp || !wait)
1050 return EPOLLHUP | EPOLLERR;
1051
1052 cli = filp->private_data;
1053 if (!cli)
1054 return EPOLLHUP | EPOLLERR;
1055
1056 poll_wait(filp, &cli->waitq, wait);
1057 if (kbasep_vinstr_hwcnt_reader_buffer_ready(cli))
1058 return EPOLLIN | EPOLLRDNORM;
1059
1060 return (__poll_t)0;
1061 }
1062
1063 /**
1064 * kbasep_vinstr_hwcnt_reader_mmap() - hwcnt reader's mmap.
1065 * @filp: Non-NULL pointer to file structure.
1066 * @vma: Non-NULL pointer to vma structure.
1067 *
1068 * Return: 0 on success, else error code.
1069 */
kbasep_vinstr_hwcnt_reader_mmap(struct file * filp,struct vm_area_struct * vma)1070 static int kbasep_vinstr_hwcnt_reader_mmap(
1071 struct file *filp,
1072 struct vm_area_struct *vma)
1073 {
1074 struct kbase_vinstr_client *cli;
1075 unsigned long vm_size, size, addr, pfn, offset;
1076
1077 if (!filp || !vma)
1078 return -EINVAL;
1079
1080 cli = filp->private_data;
1081 if (!cli)
1082 return -EINVAL;
1083
1084 vm_size = vma->vm_end - vma->vm_start;
1085
1086 /* The mapping is allowed to span the entirety of the page allocation,
1087 * not just the chunk where the dump buffers are allocated.
1088 * This accommodates the corner case where the combined size of the
1089 * dump buffers is smaller than a single page.
1090 * This does not pose a security risk as the pages are zeroed on
1091 * allocation, and anything out of bounds of the dump buffers is never
1092 * written to.
1093 */
1094 size = (1ull << cli->dump_bufs.page_order) * PAGE_SIZE;
1095
1096 if (vma->vm_pgoff > (size >> PAGE_SHIFT))
1097 return -EINVAL;
1098
1099 offset = vma->vm_pgoff << PAGE_SHIFT;
1100 if (vm_size > size - offset)
1101 return -EINVAL;
1102
1103 addr = __pa(cli->dump_bufs.page_addr + offset);
1104 pfn = addr >> PAGE_SHIFT;
1105
1106 return remap_pfn_range(
1107 vma, vma->vm_start, pfn, vm_size, vma->vm_page_prot);
1108 }
1109
1110 /**
1111 * kbasep_vinstr_hwcnt_reader_release() - hwcnt reader's release.
1112 * @inode: Non-NULL pointer to inode structure.
1113 * @filp: Non-NULL pointer to file structure.
1114 *
1115 * Return: 0 always.
1116 */
kbasep_vinstr_hwcnt_reader_release(struct inode * inode,struct file * filp)1117 static int kbasep_vinstr_hwcnt_reader_release(struct inode *inode,
1118 struct file *filp)
1119 {
1120 struct kbase_vinstr_client *vcli = filp->private_data;
1121
1122 mutex_lock(&vcli->vctx->lock);
1123
1124 vcli->vctx->client_count--;
1125 list_del(&vcli->node);
1126
1127 mutex_unlock(&vcli->vctx->lock);
1128
1129 kbasep_vinstr_client_destroy(vcli);
1130
1131 return 0;
1132 }
1133