blob: 84fabac9f491fb1dec45b11009add776b6a01d31 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
*
* (C) COPYRIGHT 2019-2022 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 <uapi/gpu/arm/midgard/mali_kbase_kinstr_jm_reader.h>
#ifdef __KERNEL__
#include <linux/version.h>
#include <linux/static_key.h>
#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_ */