/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * * (C) COPYRIGHT 2019-2023 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. * */ /* * mali_kbase_kinstr_jm.h * Kernel driver public interface to job manager atom tracing. This API provides * a method to get the atom state changes into user space. * * The flow of operation is: * * | kernel | user | * | ----------------------------------- | ----------------------------------- | * | Initialize API with | | * | kbase_kinstr_jm_init() | | * | | | * | Kernel code injects states with | | * | kbase_kinstr_jm_atom_state_*() APIs | | * | | Call ioctl() to get file descriptor | * | | via KBASE_IOCTL_KINSTR_JM_FD | * | Allocates a reader attached to FD | | * | Allocates circular buffer and | | * | patches, via ASM goto, the | | * | kbase_kinstr_jm_atom_state_*() | | * | | loop: | * | | Call poll() on FD for POLLIN | * | When threshold of changes is hit, | | * | the poll is interrupted with | | * | POLLIN. If circular buffer is | | * | full then store the missed count | | * | and interrupt poll | Call read() to get data from | * | | circular buffer via the fd | * | Kernel advances tail of circular | | * | buffer | | * | | Close file descriptor | * | Deallocates circular buffer | | * | | | * | Terminate API with | | * | kbase_kinstr_jm_term() | | * * All tracepoints are guarded on a static key. The static key is activated when * a user space reader gets created. This means that there is negligible cost * inserting the tracepoints into code when there are no readers. */ #ifndef _KBASE_KINSTR_JM_H_ #define _KBASE_KINSTR_JM_H_ #include #ifdef __KERNEL__ #include #include #else /* empty wrapper macros for userspace */ #define static_branch_unlikely(key) (1) #endif /* __KERNEL__ */ /* Forward declarations */ struct kbase_context; struct kbase_kinstr_jm; struct kbase_jd_atom; union kbase_kinstr_jm_fd; /** * kbase_kinstr_jm_init() - Initialise an instrumentation job manager context. * @ctx: Non-NULL pointer to where the pointer to the created context will * be stored on success. * * Return: 0 on success, else error code. */ int kbase_kinstr_jm_init(struct kbase_kinstr_jm **ctx); /** * kbase_kinstr_jm_term() - Terminate an instrumentation job manager context. * @ctx: Pointer to context to be terminated. */ void kbase_kinstr_jm_term(struct kbase_kinstr_jm *ctx); /** * kbase_kinstr_jm_get_fd() - Retrieves a file descriptor that can be used to * read the atom state changes from userspace * * @ctx: Pointer to the initialized context * @jm_fd_arg: Pointer to the union containing the in/out params * Return: -1 on failure, valid file descriptor on success */ int kbase_kinstr_jm_get_fd(struct kbase_kinstr_jm *const ctx, union kbase_kinstr_jm_fd *jm_fd_arg); /** * kbasep_kinstr_jm_atom_state() - Signifies that an atom has changed state * @atom: The atom that has changed state * @state: The new state of the atom * * This performs the actual storage of the state ready for user space to * read the data. It is only called when the static key is enabled from * kbase_kinstr_jm_atom_state(). There is almost never a need to invoke this * function directly. */ void kbasep_kinstr_jm_atom_state(struct kbase_jd_atom *const atom, const enum kbase_kinstr_jm_reader_atom_state state); /* Allows ASM goto patching to reduce tracing overhead. This is * incremented/decremented when readers are created and terminated. This really * shouldn't be changed externally, but if you do, make sure you use * a static_key_inc()/static_key_dec() pair. */ extern struct static_key_false basep_kinstr_jm_reader_static_key; /** * kbase_kinstr_jm_atom_state() - Signifies that an atom has changed state * @atom: The atom that has changed state * @state: The new state of the atom * * This uses a static key to reduce overhead when tracing is disabled */ static inline void kbase_kinstr_jm_atom_state(struct kbase_jd_atom *const atom, const enum kbase_kinstr_jm_reader_atom_state state) { if (static_branch_unlikely(&basep_kinstr_jm_reader_static_key)) kbasep_kinstr_jm_atom_state(atom, state); } /** * kbase_kinstr_jm_atom_state_queue() - Signifies that an atom has entered a * hardware or software queue. * @atom: The atom that has changed state */ static inline void kbase_kinstr_jm_atom_state_queue(struct kbase_jd_atom *const atom) { kbase_kinstr_jm_atom_state(atom, KBASE_KINSTR_JM_READER_ATOM_STATE_QUEUE); } /** * kbase_kinstr_jm_atom_state_start() - Signifies that work has started on an * atom * @atom: The atom that has changed state */ static inline void kbase_kinstr_jm_atom_state_start(struct kbase_jd_atom *const atom) { kbase_kinstr_jm_atom_state(atom, KBASE_KINSTR_JM_READER_ATOM_STATE_START); } /** * kbase_kinstr_jm_atom_state_stop() - Signifies that work has stopped on an * atom * @atom: The atom that has changed state */ static inline void kbase_kinstr_jm_atom_state_stop(struct kbase_jd_atom *const atom) { kbase_kinstr_jm_atom_state(atom, KBASE_KINSTR_JM_READER_ATOM_STATE_STOP); } /** * kbase_kinstr_jm_atom_state_complete() - Signifies that all work has completed * on an atom * @atom: The atom that has changed state */ static inline void kbase_kinstr_jm_atom_state_complete(struct kbase_jd_atom *const atom) { kbase_kinstr_jm_atom_state(atom, KBASE_KINSTR_JM_READER_ATOM_STATE_COMPLETE); } /** * kbase_kinstr_jm_atom_queue() - A software *or* hardware atom is queued for * execution * @atom: The atom that has changed state */ static inline void kbase_kinstr_jm_atom_queue(struct kbase_jd_atom *const atom) { kbase_kinstr_jm_atom_state_queue(atom); } /** * kbase_kinstr_jm_atom_complete() - A software *or* hardware atom is fully * completed * @atom: The atom that has changed state */ static inline void kbase_kinstr_jm_atom_complete(struct kbase_jd_atom *const atom) { kbase_kinstr_jm_atom_state_complete(atom); } /** * kbase_kinstr_jm_atom_sw_start() - A software atom has started work * @atom: The atom that has changed state */ static inline void kbase_kinstr_jm_atom_sw_start(struct kbase_jd_atom *const atom) { kbase_kinstr_jm_atom_state_start(atom); } /** * kbase_kinstr_jm_atom_sw_stop() - A software atom has stopped work * @atom: The atom that has changed state */ static inline void kbase_kinstr_jm_atom_sw_stop(struct kbase_jd_atom *const atom) { kbase_kinstr_jm_atom_state_stop(atom); } /** * kbasep_kinstr_jm_atom_hw_submit() - A hardware atom has been submitted * @atom: The atom that has been submitted * * This private implementation should not be called directly, it is protected * by a static key in kbase_kinstr_jm_atom_hw_submit(). Use that instead. */ void kbasep_kinstr_jm_atom_hw_submit(struct kbase_jd_atom *const atom); /** * kbase_kinstr_jm_atom_hw_submit() - A hardware atom has been submitted * @atom: The atom that has been submitted */ static inline void kbase_kinstr_jm_atom_hw_submit(struct kbase_jd_atom *const atom) { if (static_branch_unlikely(&basep_kinstr_jm_reader_static_key)) kbasep_kinstr_jm_atom_hw_submit(atom); } /** * kbasep_kinstr_jm_atom_hw_release() - A hardware atom has been released * @atom: The atom that has been released * * This private implementation should not be called directly, it is protected * by a static key in kbase_kinstr_jm_atom_hw_release(). Use that instead. */ void kbasep_kinstr_jm_atom_hw_release(struct kbase_jd_atom *const atom); /** * kbase_kinstr_jm_atom_hw_release() - A hardware atom has been released * @atom: The atom that has been released */ static inline void kbase_kinstr_jm_atom_hw_release(struct kbase_jd_atom *const atom) { if (static_branch_unlikely(&basep_kinstr_jm_reader_static_key)) kbasep_kinstr_jm_atom_hw_release(atom); } #endif /* _KBASE_KINSTR_JM_H_ */