| // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note |
| /* |
| * |
| * (C) COPYRIGHT 2019-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 <tl/mali_kbase_tracepoints.h> |
| #include <tl/mali_kbase_timeline.h> |
| #include <tl/mali_kbase_timeline_priv.h> |
| |
| #include <mali_kbase.h> |
| |
| void kbase_create_timeline_objects(struct kbase_device *kbdev) |
| { |
| unsigned int as_nr; |
| unsigned int slot_i; |
| struct kbase_context *kctx; |
| struct kbase_timeline *timeline = kbdev->timeline; |
| struct kbase_tlstream *summary = |
| &kbdev->timeline->streams[TL_STREAM_TYPE_OBJ_SUMMARY]; |
| |
| /* Summarize the Address Space objects. */ |
| for (as_nr = 0; as_nr < kbdev->nr_hw_address_spaces; as_nr++) |
| __kbase_tlstream_tl_new_as(summary, &kbdev->as[as_nr], as_nr); |
| |
| /* Create Legacy GPU object to track in AOM for dumping */ |
| __kbase_tlstream_tl_new_gpu(summary, |
| kbdev, |
| kbdev->gpu_props.props.raw_props.gpu_id, |
| kbdev->gpu_props.num_cores); |
| |
| |
| for (as_nr = 0; as_nr < kbdev->nr_hw_address_spaces; as_nr++) |
| __kbase_tlstream_tl_lifelink_as_gpu(summary, |
| &kbdev->as[as_nr], |
| kbdev); |
| |
| /* Trace the creation of a new kbase device and set its properties. */ |
| __kbase_tlstream_tl_kbase_new_device(summary, |
| kbdev->gpu_props.props.raw_props.gpu_id, |
| kbdev->gpu_props.num_cores, kbdev->csf.global_iface.group_num, |
| kbdev->nr_hw_address_spaces); |
| |
| /* Lock the context list, to ensure no changes to the list are made |
| * while we're summarizing the contexts and their contents. |
| */ |
| mutex_lock(&timeline->tl_kctx_list_lock); |
| |
| /* Hold the scheduler lock while we emit the current state |
| * We also need to continue holding the lock until after the first body |
| * stream tracepoints are emitted to ensure we don't change the |
| * scheduler until after then |
| */ |
| mutex_lock(&kbdev->csf.scheduler.lock); |
| |
| for (slot_i = 0; slot_i < kbdev->csf.global_iface.group_num; slot_i++) { |
| |
| struct kbase_queue_group *group = |
| kbdev->csf.scheduler.csg_slots[slot_i].resident_group; |
| |
| if (group) |
| __kbase_tlstream_tl_kbase_device_program_csg(summary, |
| kbdev->gpu_props.props.raw_props.gpu_id, |
| group->handle, slot_i); |
| } |
| |
| /* Reset body stream buffers while holding the kctx lock. |
| * As we are holding the lock, we can guarantee that no kctx creation or |
| * deletion tracepoints can be fired from outside of this function by |
| * some other thread. |
| */ |
| kbase_timeline_streams_body_reset(timeline); |
| |
| mutex_unlock(&kbdev->csf.scheduler.lock); |
| |
| /* For each context in the device... */ |
| list_for_each_entry(kctx, &timeline->tl_kctx_list, tl_kctx_list_node) { |
| size_t i; |
| struct kbase_tlstream *body = |
| &timeline->streams[TL_STREAM_TYPE_OBJ]; |
| |
| /* Lock the context's KCPU queues, to ensure no KCPU-queue |
| * related actions can occur in this context from now on. |
| */ |
| mutex_lock(&kctx->csf.kcpu_queues.lock); |
| |
| /* Acquire the MMU lock, to ensure we don't get a concurrent |
| * address space assignment while summarizing this context's |
| * address space. |
| */ |
| mutex_lock(&kbdev->mmu_hw_mutex); |
| |
| /* Trace the context itself into the body stream, not the |
| * summary stream. |
| * We place this in the body to ensure it is ordered after any |
| * other tracepoints related to the contents of the context that |
| * might have been fired before acquiring all of the per-context |
| * locks. |
| * This ensures that those tracepoints will not actually affect |
| * the object model state, as they reference a context that |
| * hasn't been traced yet. They may, however, cause benign |
| * errors to be emitted. |
| */ |
| __kbase_tlstream_tl_kbase_new_ctx(body, kctx->id, |
| kbdev->gpu_props.props.raw_props.gpu_id); |
| |
| /* Also trace with the legacy AOM tracepoint for dumping */ |
| __kbase_tlstream_tl_new_ctx(body, |
| kctx, |
| kctx->id, |
| (u32)(kctx->tgid)); |
| |
| /* Trace the currently assigned address space */ |
| if (kctx->as_nr != KBASEP_AS_NR_INVALID) |
| __kbase_tlstream_tl_kbase_ctx_assign_as(body, kctx->id, |
| kctx->as_nr); |
| |
| |
| /* Trace all KCPU queues in the context into the body stream. |
| * As we acquired the KCPU lock after resetting the body stream, |
| * it's possible that some KCPU-related events for this context |
| * occurred between that reset and now. |
| * These will cause errors to be emitted when parsing the |
| * timeline, but they will not affect the correctness of the |
| * object model. |
| */ |
| for (i = 0; i < KBASEP_MAX_KCPU_QUEUES; i++) { |
| const struct kbase_kcpu_command_queue *kcpu_queue = |
| kctx->csf.kcpu_queues.array[i]; |
| |
| if (kcpu_queue) |
| __kbase_tlstream_tl_kbase_new_kcpuqueue( |
| body, kcpu_queue, kcpu_queue->kctx->id, |
| kcpu_queue->num_pending_cmds); |
| } |
| |
| mutex_unlock(&kbdev->mmu_hw_mutex); |
| mutex_unlock(&kctx->csf.kcpu_queues.lock); |
| |
| /* Now that all per-context locks for this context have been |
| * released, any per-context tracepoints that are fired from |
| * any other threads will go into the body stream after |
| * everything that was just summarised into the body stream in |
| * this iteration of the loop, so will start to correctly update |
| * the object model state. |
| */ |
| } |
| |
| mutex_unlock(&timeline->tl_kctx_list_lock); |
| |
| /* Static object are placed into summary packet that needs to be |
| * transmitted first. Flush all streams to make it available to |
| * user space. |
| */ |
| kbase_timeline_streams_flush(timeline); |
| } |