• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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