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