// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * * (C) COPYRIGHT 2018, 2020-2021 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software * Foundation, and any use by you of this program is subject to the terms * of such GNU license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you can access it online at * http://www.gnu.org/licenses/gpl-2.0.html. * */ #include "mali_kbase_hwcnt_legacy.h" #include "mali_kbase_hwcnt_virtualizer.h" #include "mali_kbase_hwcnt_types.h" #include "mali_kbase_hwcnt_gpu.h" #include #include #include /** * struct kbase_hwcnt_legacy_client - Legacy hardware counter client. * @user_dump_buf: Pointer to a non-NULL user buffer, where dumps are returned. * @enable_map: Counter enable map. * @dump_buf: Dump buffer used to manipulate dumps before copied to user. * @hvcli: Hardware counter virtualizer client. */ struct kbase_hwcnt_legacy_client { void __user *user_dump_buf; struct kbase_hwcnt_enable_map enable_map; struct kbase_hwcnt_dump_buffer dump_buf; struct kbase_hwcnt_virtualizer_client *hvcli; }; int kbase_hwcnt_legacy_client_create( struct kbase_hwcnt_virtualizer *hvirt, struct kbase_ioctl_hwcnt_enable *enable, struct kbase_hwcnt_legacy_client **out_hlcli) { int errcode; struct kbase_hwcnt_legacy_client *hlcli; const struct kbase_hwcnt_metadata *metadata; struct kbase_hwcnt_physical_enable_map phys_em; if (!hvirt || !enable || !enable->dump_buffer || !out_hlcli) return -EINVAL; metadata = kbase_hwcnt_virtualizer_metadata(hvirt); hlcli = kzalloc(sizeof(*hlcli), GFP_KERNEL); if (!hlcli) return -ENOMEM; hlcli->user_dump_buf = (void __user *)(uintptr_t)enable->dump_buffer; errcode = kbase_hwcnt_enable_map_alloc(metadata, &hlcli->enable_map); if (errcode) goto error; /* Translate from the ioctl enable map to the internal one */ phys_em.fe_bm = enable->fe_bm; phys_em.shader_bm = enable->shader_bm; phys_em.tiler_bm = enable->tiler_bm; phys_em.mmu_l2_bm = enable->mmu_l2_bm; kbase_hwcnt_gpu_enable_map_from_physical(&hlcli->enable_map, &phys_em); errcode = kbase_hwcnt_dump_buffer_alloc(metadata, &hlcli->dump_buf); if (errcode) goto error; errcode = kbase_hwcnt_virtualizer_client_create( hvirt, &hlcli->enable_map, &hlcli->hvcli); if (errcode) goto error; *out_hlcli = hlcli; return 0; error: kbase_hwcnt_legacy_client_destroy(hlcli); return errcode; } void kbase_hwcnt_legacy_client_destroy(struct kbase_hwcnt_legacy_client *hlcli) { if (!hlcli) return; kbase_hwcnt_virtualizer_client_destroy(hlcli->hvcli); kbase_hwcnt_dump_buffer_free(&hlcli->dump_buf); kbase_hwcnt_enable_map_free(&hlcli->enable_map); kfree(hlcli); } int kbase_hwcnt_legacy_client_dump(struct kbase_hwcnt_legacy_client *hlcli) { int errcode; u64 ts_start_ns; u64 ts_end_ns; if (!hlcli) return -EINVAL; /* Dump into the kernel buffer */ errcode = kbase_hwcnt_virtualizer_client_dump(hlcli->hvcli, &ts_start_ns, &ts_end_ns, &hlcli->dump_buf); if (errcode) return errcode; /* Patch the dump buf headers, to hide the counters that other hwcnt * clients are using. */ kbase_hwcnt_gpu_patch_dump_headers( &hlcli->dump_buf, &hlcli->enable_map); /* Zero all non-enabled counters (current values are undefined) */ kbase_hwcnt_dump_buffer_zero_non_enabled( &hlcli->dump_buf, &hlcli->enable_map); /* Copy into the user's buffer */ errcode = copy_to_user(hlcli->user_dump_buf, hlcli->dump_buf.dump_buf, hlcli->dump_buf.metadata->dump_buf_bytes); /* Non-zero errcode implies user buf was invalid or too small */ if (errcode) return -EFAULT; return 0; } int kbase_hwcnt_legacy_client_clear(struct kbase_hwcnt_legacy_client *hlcli) { u64 ts_start_ns; u64 ts_end_ns; if (!hlcli) return -EINVAL; /* Dump with a NULL buffer to clear this client's counters */ return kbase_hwcnt_virtualizer_client_dump(hlcli->hvcli, &ts_start_ns, &ts_end_ns, NULL); }