| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * |
|---|
| 4 | | - * (C) COPYRIGHT 2011-2021 ARM Limited. All rights reserved. |
|---|
| 4 | + * (C) COPYRIGHT 2011-2022 ARM Limited. All rights reserved. |
|---|
| 5 | 5 | * |
|---|
| 6 | 6 | * This program is free software and is provided to you under the terms of the |
|---|
| 7 | 7 | * GNU General Public License version 2 as published by the Free Software |
|---|
| .. | .. |
|---|
| 20 | 20 | */ |
|---|
| 21 | 21 | |
|---|
| 22 | 22 | #include "mali_kbase_vinstr.h" |
|---|
| 23 | | -#include "mali_kbase_hwcnt_virtualizer.h" |
|---|
| 24 | | -#include "mali_kbase_hwcnt_types.h" |
|---|
| 23 | +#include "hwcnt/mali_kbase_hwcnt_virtualizer.h" |
|---|
| 24 | +#include "hwcnt/mali_kbase_hwcnt_types.h" |
|---|
| 25 | 25 | #include <uapi/gpu/arm/bifrost/mali_kbase_hwcnt_reader.h> |
|---|
| 26 | | -#include "mali_kbase_hwcnt_gpu.h" |
|---|
| 26 | +#include "hwcnt/mali_kbase_hwcnt_gpu.h" |
|---|
| 27 | +#include "hwcnt/mali_kbase_hwcnt_gpu_narrow.h" |
|---|
| 27 | 28 | #include <uapi/gpu/arm/bifrost/mali_kbase_ioctl.h> |
|---|
| 28 | 29 | #include "mali_malisw.h" |
|---|
| 29 | 30 | #include "mali_kbase_debug.h" |
|---|
| .. | .. |
|---|
| 37 | 38 | #include <linux/mutex.h> |
|---|
| 38 | 39 | #include <linux/poll.h> |
|---|
| 39 | 40 | #include <linux/slab.h> |
|---|
| 41 | +#include <linux/version_compat_defs.h> |
|---|
| 40 | 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 |
|---|
| 41 | 48 | |
|---|
| 42 | 49 | /* Hwcnt reader API version */ |
|---|
| 43 | 50 | #define HWCNT_READER_API 1 |
|---|
| .. | .. |
|---|
| 55 | 62 | * @metadata: Hardware counter metadata provided by virtualizer. |
|---|
| 56 | 63 | * @metadata_user: API compatible hardware counter metadata provided by vinstr. |
|---|
| 57 | 64 | * For compatibility with the user driver interface, this |
|---|
| 58 | | - * contains a "truncated" version of the HWCNT metadata limited |
|---|
| 59 | | - * to 64 entries per block. NULL when not required. |
|---|
| 65 | + * contains a narrowed version of the HWCNT metadata limited |
|---|
| 66 | + * to 64 entries per block of 32 bits each. |
|---|
| 60 | 67 | * @lock: Lock protecting all vinstr state. |
|---|
| 61 | 68 | * @suspend_count: Suspend reference count. If non-zero, timer and worker are |
|---|
| 62 | 69 | * prevented from being re-scheduled. |
|---|
| .. | .. |
|---|
| 68 | 75 | struct kbase_vinstr_context { |
|---|
| 69 | 76 | struct kbase_hwcnt_virtualizer *hvirt; |
|---|
| 70 | 77 | const struct kbase_hwcnt_metadata *metadata; |
|---|
| 71 | | - const struct kbase_hwcnt_metadata *metadata_user; |
|---|
| 78 | + const struct kbase_hwcnt_metadata_narrow *metadata_user; |
|---|
| 72 | 79 | struct mutex lock; |
|---|
| 73 | 80 | size_t suspend_count; |
|---|
| 74 | 81 | size_t client_count; |
|---|
| .. | .. |
|---|
| 89 | 96 | * occur. If 0, not a periodic client. |
|---|
| 90 | 97 | * @enable_map: Counters enable map. |
|---|
| 91 | 98 | * @tmp_buf: Temporary buffer to use before handing dump to client. |
|---|
| 92 | | - * @dump_bufs: Array of dump buffers allocated by this client. |
|---|
| 93 | | - * @dump_bufs_meta: Metadata of dump buffers. |
|---|
| 99 | + * @dump_bufs: Array of narrow dump buffers allocated by this client. |
|---|
| 100 | + * @dump_bufs_meta: Metadata of hwcnt reader client buffers. |
|---|
| 94 | 101 | * @meta_idx: Index of metadata being accessed by userspace. |
|---|
| 95 | 102 | * @read_idx: Index of buffer read by userspace. |
|---|
| 96 | 103 | * @write_idx: Index of buffer being written by dump worker. |
|---|
| .. | .. |
|---|
| 104 | 111 | u32 dump_interval_ns; |
|---|
| 105 | 112 | struct kbase_hwcnt_enable_map enable_map; |
|---|
| 106 | 113 | struct kbase_hwcnt_dump_buffer tmp_buf; |
|---|
| 107 | | - struct kbase_hwcnt_dump_buffer_array dump_bufs; |
|---|
| 114 | + struct kbase_hwcnt_dump_buffer_narrow_array dump_bufs; |
|---|
| 108 | 115 | struct kbase_hwcnt_reader_metadata *dump_bufs_meta; |
|---|
| 109 | 116 | atomic_t meta_idx; |
|---|
| 110 | 117 | atomic_t read_idx; |
|---|
| .. | .. |
|---|
| 112 | 119 | wait_queue_head_t waitq; |
|---|
| 113 | 120 | }; |
|---|
| 114 | 121 | |
|---|
| 115 | | -static unsigned int kbasep_vinstr_hwcnt_reader_poll( |
|---|
| 116 | | - struct file *filp, |
|---|
| 117 | | - poll_table *wait); |
|---|
| 122 | +static __poll_t kbasep_vinstr_hwcnt_reader_poll(struct file *filp, poll_table *wait); |
|---|
| 118 | 123 | |
|---|
| 119 | 124 | static long kbasep_vinstr_hwcnt_reader_ioctl( |
|---|
| 120 | 125 | struct file *filp, |
|---|
| .. | .. |
|---|
| 190 | 195 | unsigned int write_idx; |
|---|
| 191 | 196 | unsigned int read_idx; |
|---|
| 192 | 197 | struct kbase_hwcnt_dump_buffer *tmp_buf; |
|---|
| 193 | | - struct kbase_hwcnt_dump_buffer *dump_buf; |
|---|
| 198 | + struct kbase_hwcnt_dump_buffer_narrow *dump_buf; |
|---|
| 194 | 199 | struct kbase_hwcnt_reader_metadata *meta; |
|---|
| 195 | 200 | u8 clk_cnt; |
|---|
| 196 | 201 | |
|---|
| .. | .. |
|---|
| 223 | 228 | * variant will explicitly zero any non-enabled counters to ensure |
|---|
| 224 | 229 | * nothing except exactly what the user asked for is made visible. |
|---|
| 225 | 230 | * |
|---|
| 226 | | - * If the metadata in vinstr (vctx->metadata_user) is not NULL, it means |
|---|
| 227 | | - * vinstr has the truncated metadata, so do a narrow copy since |
|---|
| 228 | | - * virtualizer has a bigger buffer but user only needs part of it. |
|---|
| 229 | | - * otherwise we do a full copy. |
|---|
| 231 | + * A narrow copy is required since virtualizer has a bigger buffer |
|---|
| 232 | + * but user only needs part of it. |
|---|
| 230 | 233 | */ |
|---|
| 231 | | - if (vcli->vctx->metadata_user) |
|---|
| 232 | | - kbase_hwcnt_dump_buffer_copy_strict_narrow(dump_buf, tmp_buf, |
|---|
| 233 | | - &vcli->enable_map); |
|---|
| 234 | | - else |
|---|
| 235 | | - kbase_hwcnt_dump_buffer_copy_strict(dump_buf, tmp_buf, |
|---|
| 236 | | - &vcli->enable_map); |
|---|
| 234 | + kbase_hwcnt_dump_buffer_copy_strict_narrow(dump_buf, tmp_buf, |
|---|
| 235 | + &vcli->enable_map); |
|---|
| 237 | 236 | |
|---|
| 238 | 237 | clk_cnt = vcli->vctx->metadata->clk_cnt; |
|---|
| 239 | 238 | |
|---|
| .. | .. |
|---|
| 362 | 361 | * kbasep_vinstr_dump_timer() - Dump timer that schedules the dump worker for |
|---|
| 363 | 362 | * execution as soon as possible. |
|---|
| 364 | 363 | * @timer: Timer structure. |
|---|
| 364 | + * |
|---|
| 365 | + * Return: HRTIMER_NORESTART always. |
|---|
| 365 | 366 | */ |
|---|
| 366 | 367 | static enum hrtimer_restart kbasep_vinstr_dump_timer(struct hrtimer *timer) |
|---|
| 367 | 368 | { |
|---|
| .. | .. |
|---|
| 388 | 389 | |
|---|
| 389 | 390 | kbase_hwcnt_virtualizer_client_destroy(vcli->hvcli); |
|---|
| 390 | 391 | kfree(vcli->dump_bufs_meta); |
|---|
| 391 | | - kbase_hwcnt_dump_buffer_array_free(&vcli->dump_bufs); |
|---|
| 392 | + kbase_hwcnt_dump_buffer_narrow_array_free(&vcli->dump_bufs); |
|---|
| 392 | 393 | kbase_hwcnt_dump_buffer_free(&vcli->tmp_buf); |
|---|
| 393 | 394 | kbase_hwcnt_enable_map_free(&vcli->enable_map); |
|---|
| 394 | 395 | kfree(vcli); |
|---|
| .. | .. |
|---|
| 446 | 447 | /* Enable all the available clk_enable_map. */ |
|---|
| 447 | 448 | vcli->enable_map.clk_enable_map = (1ull << vctx->metadata->clk_cnt) - 1; |
|---|
| 448 | 449 | |
|---|
| 449 | | - if (vctx->metadata_user) |
|---|
| 450 | | - /* Use vinstr's truncated metadata to alloc dump buffers which |
|---|
| 451 | | - * interact with clients. |
|---|
| 452 | | - */ |
|---|
| 453 | | - errcode = |
|---|
| 454 | | - kbase_hwcnt_dump_buffer_array_alloc(vctx->metadata_user, |
|---|
| 455 | | - setup->buffer_count, |
|---|
| 456 | | - &vcli->dump_bufs); |
|---|
| 457 | | - else |
|---|
| 458 | | - /* Use metadata from virtualizer to allocate dump buffers if |
|---|
| 459 | | - * vinstr doesn't have the truncated metadata. |
|---|
| 460 | | - */ |
|---|
| 461 | | - errcode = kbase_hwcnt_dump_buffer_array_alloc( |
|---|
| 462 | | - vctx->metadata, setup->buffer_count, &vcli->dump_bufs); |
|---|
| 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); |
|---|
| 463 | 455 | if (errcode) |
|---|
| 464 | 456 | goto error; |
|---|
| 465 | 457 | |
|---|
| .. | .. |
|---|
| 504 | 496 | |
|---|
| 505 | 497 | vctx->hvirt = hvirt; |
|---|
| 506 | 498 | vctx->metadata = metadata; |
|---|
| 507 | | - vctx->metadata_user = NULL; |
|---|
| 508 | | - errcode = kbase_hwcnt_gpu_metadata_create_truncate_64( |
|---|
| 509 | | - &vctx->metadata_user, metadata); |
|---|
| 499 | + errcode = kbase_hwcnt_gpu_metadata_narrow_create(&vctx->metadata_user, |
|---|
| 500 | + metadata); |
|---|
| 510 | 501 | if (errcode) |
|---|
| 511 | 502 | goto err_metadata_create; |
|---|
| 512 | 503 | |
|---|
| .. | .. |
|---|
| 530 | 521 | if (!vctx) |
|---|
| 531 | 522 | return; |
|---|
| 532 | 523 | |
|---|
| 533 | | - cancel_work_sync(&vctx->dump_work); |
|---|
| 534 | | - |
|---|
| 535 | 524 | /* Non-zero client count implies client leak */ |
|---|
| 536 | 525 | if (WARN_ON(vctx->client_count != 0)) { |
|---|
| 537 | 526 | struct kbase_vinstr_client *pos, *n; |
|---|
| .. | .. |
|---|
| 543 | 532 | } |
|---|
| 544 | 533 | } |
|---|
| 545 | 534 | |
|---|
| 546 | | - if (vctx->metadata_user) |
|---|
| 547 | | - kbase_hwcnt_metadata_destroy(vctx->metadata_user); |
|---|
| 535 | + cancel_work_sync(&vctx->dump_work); |
|---|
| 536 | + kbase_hwcnt_gpu_metadata_narrow_destroy(vctx->metadata_user); |
|---|
| 548 | 537 | |
|---|
| 549 | 538 | WARN_ON(vctx->client_count != 0); |
|---|
| 550 | 539 | kfree(vctx); |
|---|
| .. | .. |
|---|
| 930 | 919 | } |
|---|
| 931 | 920 | |
|---|
| 932 | 921 | /** |
|---|
| 933 | | - * The hwcnt reader's ioctl command - get API version. |
|---|
| 922 | + * kbasep_vinstr_hwcnt_reader_ioctl_get_api_version() - get API version ioctl |
|---|
| 923 | + * command. |
|---|
| 934 | 924 | * @cli: The non-NULL pointer to the client |
|---|
| 935 | 925 | * @arg: Command's argument. |
|---|
| 936 | 926 | * @size: Size of arg. |
|---|
| 937 | 927 | * |
|---|
| 938 | | - * @return 0 on success, else error code. |
|---|
| 928 | + * Return: 0 on success, else error code. |
|---|
| 939 | 929 | */ |
|---|
| 940 | 930 | static long kbasep_vinstr_hwcnt_reader_ioctl_get_api_version( |
|---|
| 941 | 931 | struct kbase_vinstr_client *cli, unsigned long arg, size_t size) |
|---|
| .. | .. |
|---|
| 1006 | 996 | cli, (u32 __user *)arg); |
|---|
| 1007 | 997 | break; |
|---|
| 1008 | 998 | case _IOC_NR(KBASE_HWCNT_READER_GET_BUFFER_SIZE): |
|---|
| 1009 | | - if (cli->vctx->metadata_user) |
|---|
| 1010 | | - rcode = put_user( |
|---|
| 1011 | | - (u32)cli->vctx->metadata_user->dump_buf_bytes, |
|---|
| 1012 | | - (u32 __user *)arg); |
|---|
| 1013 | | - else |
|---|
| 1014 | | - rcode = put_user( |
|---|
| 1015 | | - (u32)cli->vctx->metadata->dump_buf_bytes, |
|---|
| 1016 | | - (u32 __user *)arg); |
|---|
| 999 | + rcode = put_user((u32)cli->vctx->metadata_user->dump_buf_bytes, |
|---|
| 1000 | + (u32 __user *)arg); |
|---|
| 1017 | 1001 | break; |
|---|
| 1018 | 1002 | case _IOC_NR(KBASE_HWCNT_READER_DUMP): |
|---|
| 1019 | 1003 | rcode = kbasep_vinstr_hwcnt_reader_ioctl_dump(cli); |
|---|
| .. | .. |
|---|
| 1055 | 1039 | * @filp: Non-NULL pointer to file structure. |
|---|
| 1056 | 1040 | * @wait: Non-NULL pointer to poll table. |
|---|
| 1057 | 1041 | * |
|---|
| 1058 | | - * Return: POLLIN if data can be read without blocking, 0 if data can not be |
|---|
| 1059 | | - * read without blocking, else error code. |
|---|
| 1042 | + * Return: EPOLLIN | EPOLLRDNORM if data can be read without blocking, 0 if |
|---|
| 1043 | + * data can not be read without blocking, else EPOLLHUP | EPOLLERR. |
|---|
| 1060 | 1044 | */ |
|---|
| 1061 | | -static unsigned int kbasep_vinstr_hwcnt_reader_poll( |
|---|
| 1062 | | - struct file *filp, |
|---|
| 1063 | | - poll_table *wait) |
|---|
| 1045 | +static __poll_t kbasep_vinstr_hwcnt_reader_poll(struct file *filp, poll_table *wait) |
|---|
| 1064 | 1046 | { |
|---|
| 1065 | 1047 | struct kbase_vinstr_client *cli; |
|---|
| 1066 | 1048 | |
|---|
| 1067 | 1049 | if (!filp || !wait) |
|---|
| 1068 | | - return -EINVAL; |
|---|
| 1050 | + return EPOLLHUP | EPOLLERR; |
|---|
| 1069 | 1051 | |
|---|
| 1070 | 1052 | cli = filp->private_data; |
|---|
| 1071 | 1053 | if (!cli) |
|---|
| 1072 | | - return -EINVAL; |
|---|
| 1054 | + return EPOLLHUP | EPOLLERR; |
|---|
| 1073 | 1055 | |
|---|
| 1074 | 1056 | poll_wait(filp, &cli->waitq, wait); |
|---|
| 1075 | 1057 | if (kbasep_vinstr_hwcnt_reader_buffer_ready(cli)) |
|---|
| 1076 | | - return POLLIN; |
|---|
| 1077 | | - return 0; |
|---|
| 1058 | + return EPOLLIN | EPOLLRDNORM; |
|---|
| 1059 | + |
|---|
| 1060 | + return (__poll_t)0; |
|---|
| 1078 | 1061 | } |
|---|
| 1079 | 1062 | |
|---|
| 1080 | 1063 | /** |
|---|