2573 lines
72 KiB
C
2573 lines
72 KiB
C
/*
|
|
*
|
|
* (C) COPYRIGHT 2015-2017 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 licence.
|
|
*
|
|
* A copy of the licence is included with the program, and can also be obtained
|
|
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/anon_inodes.h>
|
|
#include <linux/atomic.h>
|
|
#include <linux/file.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/string.h>
|
|
#include <linux/stringify.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/wait.h>
|
|
|
|
#include <mali_kbase.h>
|
|
#include <mali_kbase_jm.h>
|
|
#include <mali_kbase_tlstream.h>
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* The version of swtrace protocol used in timeline stream. */
|
|
#define SWTRACE_VERSION 3
|
|
|
|
/* The maximum expected length of string in tracepoint descriptor. */
|
|
#define STRLEN_MAX 64 /* bytes */
|
|
|
|
/* The number of nanoseconds in a second. */
|
|
#define NSECS_IN_SEC 1000000000ull /* ns */
|
|
|
|
/* The period of autoflush checker execution in milliseconds. */
|
|
#define AUTOFLUSH_INTERVAL 1000 /* ms */
|
|
|
|
/* The maximum size of a single packet used by timeline. */
|
|
#define PACKET_SIZE 4096 /* bytes */
|
|
|
|
/* The number of packets used by one timeline stream. */
|
|
#define PACKET_COUNT 16
|
|
|
|
/* The number of bytes reserved for packet header.
|
|
* These value must be defined according to MIPE documentation. */
|
|
#define PACKET_HEADER_SIZE 8 /* bytes */
|
|
|
|
/* The number of bytes reserved for packet sequence number.
|
|
* These value must be defined according to MIPE documentation. */
|
|
#define PACKET_NUMBER_SIZE 4 /* bytes */
|
|
|
|
/* Packet header - first word.
|
|
* These values must be defined according to MIPE documentation. */
|
|
#define PACKET_STREAMID_POS 0
|
|
#define PACKET_STREAMID_LEN 8
|
|
#define PACKET_RSVD1_POS (PACKET_STREAMID_POS + PACKET_STREAMID_LEN)
|
|
#define PACKET_RSVD1_LEN 8
|
|
#define PACKET_TYPE_POS (PACKET_RSVD1_POS + PACKET_RSVD1_LEN)
|
|
#define PACKET_TYPE_LEN 3
|
|
#define PACKET_CLASS_POS (PACKET_TYPE_POS + PACKET_TYPE_LEN)
|
|
#define PACKET_CLASS_LEN 7
|
|
#define PACKET_FAMILY_POS (PACKET_CLASS_POS + PACKET_CLASS_LEN)
|
|
#define PACKET_FAMILY_LEN 6
|
|
|
|
/* Packet header - second word
|
|
* These values must be defined according to MIPE documentation. */
|
|
#define PACKET_LENGTH_POS 0
|
|
#define PACKET_LENGTH_LEN 24
|
|
#define PACKET_SEQBIT_POS (PACKET_LENGTH_POS + PACKET_LENGTH_LEN)
|
|
#define PACKET_SEQBIT_LEN 1
|
|
#define PACKET_RSVD2_POS (PACKET_SEQBIT_POS + PACKET_SEQBIT_LEN)
|
|
#define PACKET_RSVD2_LEN 7
|
|
|
|
/* Types of streams generated by timeline.
|
|
* Order is significant! Header streams must precede respective body streams. */
|
|
enum tl_stream_type {
|
|
TL_STREAM_TYPE_OBJ_HEADER,
|
|
TL_STREAM_TYPE_OBJ_SUMMARY,
|
|
TL_STREAM_TYPE_OBJ,
|
|
TL_STREAM_TYPE_AUX_HEADER,
|
|
TL_STREAM_TYPE_AUX,
|
|
|
|
TL_STREAM_TYPE_COUNT
|
|
};
|
|
|
|
/* Timeline packet family ids.
|
|
* Values are significant! Check MIPE documentation. */
|
|
enum tl_packet_family {
|
|
TL_PACKET_FAMILY_CTRL = 0, /* control packets */
|
|
TL_PACKET_FAMILY_TL = 1, /* timeline packets */
|
|
|
|
TL_PACKET_FAMILY_COUNT
|
|
};
|
|
|
|
/* Packet classes used in timeline streams.
|
|
* Values are significant! Check MIPE documentation. */
|
|
enum tl_packet_class {
|
|
TL_PACKET_CLASS_OBJ = 0, /* timeline objects packet */
|
|
TL_PACKET_CLASS_AUX = 1, /* auxiliary events packet */
|
|
};
|
|
|
|
/* Packet types used in timeline streams.
|
|
* Values are significant! Check MIPE documentation. */
|
|
enum tl_packet_type {
|
|
TL_PACKET_TYPE_HEADER = 0, /* stream's header/directory */
|
|
TL_PACKET_TYPE_BODY = 1, /* stream's body */
|
|
TL_PACKET_TYPE_SUMMARY = 2, /* stream's summary */
|
|
};
|
|
|
|
/* Message ids of trace events that are recorded in the timeline stream. */
|
|
enum tl_msg_id_obj {
|
|
/* Timeline object events. */
|
|
KBASE_TL_NEW_CTX,
|
|
KBASE_TL_NEW_GPU,
|
|
KBASE_TL_NEW_LPU,
|
|
KBASE_TL_NEW_ATOM,
|
|
KBASE_TL_NEW_AS,
|
|
KBASE_TL_DEL_CTX,
|
|
KBASE_TL_DEL_ATOM,
|
|
KBASE_TL_LIFELINK_LPU_GPU,
|
|
KBASE_TL_LIFELINK_AS_GPU,
|
|
KBASE_TL_RET_CTX_LPU,
|
|
KBASE_TL_RET_ATOM_CTX,
|
|
KBASE_TL_RET_ATOM_LPU,
|
|
KBASE_TL_NRET_CTX_LPU,
|
|
KBASE_TL_NRET_ATOM_CTX,
|
|
KBASE_TL_NRET_ATOM_LPU,
|
|
KBASE_TL_RET_AS_CTX,
|
|
KBASE_TL_NRET_AS_CTX,
|
|
KBASE_TL_RET_ATOM_AS,
|
|
KBASE_TL_NRET_ATOM_AS,
|
|
KBASE_TL_DEP_ATOM_ATOM,
|
|
KBASE_TL_NDEP_ATOM_ATOM,
|
|
KBASE_TL_RDEP_ATOM_ATOM,
|
|
KBASE_TL_ATTRIB_ATOM_CONFIG,
|
|
KBASE_TL_ATTRIB_ATOM_PRIORITY,
|
|
KBASE_TL_ATTRIB_ATOM_STATE,
|
|
KBASE_TL_ATTRIB_ATOM_PRIORITY_CHANGE,
|
|
KBASE_TL_ATTRIB_ATOM_JIT,
|
|
KBASE_TL_ATTRIB_AS_CONFIG,
|
|
KBASE_TL_EVENT_LPU_SOFTSTOP,
|
|
KBASE_TL_EVENT_ATOM_SOFTSTOP_EX,
|
|
KBASE_TL_EVENT_ATOM_SOFTSTOP_ISSUE,
|
|
|
|
/* Job dump specific events. */
|
|
KBASE_JD_GPU_SOFT_RESET
|
|
};
|
|
|
|
/* Message ids of trace events that are recorded in the auxiliary stream. */
|
|
enum tl_msg_id_aux {
|
|
KBASE_AUX_PM_STATE,
|
|
KBASE_AUX_PAGEFAULT,
|
|
KBASE_AUX_PAGESALLOC,
|
|
KBASE_AUX_DEVFREQ_TARGET,
|
|
KBASE_AUX_PROTECTED_ENTER_START,
|
|
KBASE_AUX_PROTECTED_ENTER_END,
|
|
KBASE_AUX_PROTECTED_LEAVE_START,
|
|
KBASE_AUX_PROTECTED_LEAVE_END
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
* struct tl_stream - timeline stream structure
|
|
* @lock: message order lock
|
|
* @buffer: array of buffers
|
|
* @wbi: write buffer index
|
|
* @rbi: read buffer index
|
|
* @numbered: if non-zero stream's packets are sequentially numbered
|
|
* @autoflush_counter: counter tracking stream's autoflush state
|
|
*
|
|
* This structure holds information needed to construct proper packets in the
|
|
* timeline stream. Each message in sequence must bear timestamp that is greater
|
|
* to one in previous message in the same stream. For this reason lock is held
|
|
* throughout the process of message creation. Each stream contains set of
|
|
* buffers. Each buffer will hold one MIPE packet. In case there is no free
|
|
* space required to store incoming message the oldest buffer is discarded.
|
|
* Each packet in timeline body stream has sequence number embedded (this value
|
|
* must increment monotonically and is used by packets receiver to discover
|
|
* buffer overflows.
|
|
* Autoflush counter is set to negative number when there is no data pending
|
|
* for flush and it is set to zero on every update of the buffer. Autoflush
|
|
* timer will increment the counter by one on every expiry. In case there will
|
|
* be no activity on the buffer during two consecutive timer expiries, stream
|
|
* buffer will be flushed.
|
|
*/
|
|
struct tl_stream {
|
|
spinlock_t lock;
|
|
|
|
struct {
|
|
atomic_t size; /* number of bytes in buffer */
|
|
char data[PACKET_SIZE]; /* buffer's data */
|
|
} buffer[PACKET_COUNT];
|
|
|
|
atomic_t wbi;
|
|
atomic_t rbi;
|
|
|
|
int numbered;
|
|
atomic_t autoflush_counter;
|
|
};
|
|
|
|
/**
|
|
* struct tp_desc - tracepoint message descriptor structure
|
|
* @id: tracepoint ID identifying message in stream
|
|
* @id_str: human readable version of tracepoint ID
|
|
* @name: tracepoint description
|
|
* @arg_types: tracepoint's arguments types declaration
|
|
* @arg_names: comma separated list of tracepoint's arguments names
|
|
*/
|
|
struct tp_desc {
|
|
u32 id;
|
|
const char *id_str;
|
|
const char *name;
|
|
const char *arg_types;
|
|
const char *arg_names;
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Configuration of timeline streams generated by kernel.
|
|
* Kernel emit only streams containing either timeline object events or
|
|
* auxiliary events. All streams have stream id value of 1 (as opposed to user
|
|
* space streams that have value of 0). */
|
|
static const struct {
|
|
enum tl_packet_family pkt_family;
|
|
enum tl_packet_class pkt_class;
|
|
enum tl_packet_type pkt_type;
|
|
unsigned int stream_id;
|
|
} tl_stream_cfg[TL_STREAM_TYPE_COUNT] = {
|
|
{TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_OBJ, TL_PACKET_TYPE_HEADER, 1},
|
|
{TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_OBJ, TL_PACKET_TYPE_SUMMARY, 1},
|
|
{TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_OBJ, TL_PACKET_TYPE_BODY, 1},
|
|
{TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_AUX, TL_PACKET_TYPE_HEADER, 1},
|
|
{TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_AUX, TL_PACKET_TYPE_BODY, 1}
|
|
};
|
|
|
|
/* The timeline streams generated by kernel. */
|
|
static struct tl_stream *tl_stream[TL_STREAM_TYPE_COUNT];
|
|
|
|
/* Autoflush timer. */
|
|
static struct timer_list autoflush_timer;
|
|
|
|
/* If non-zero autoflush timer is active. */
|
|
static atomic_t autoflush_timer_active;
|
|
|
|
/* Reader lock. Only one reader is allowed to have access to the timeline
|
|
* streams at any given time. */
|
|
static DEFINE_MUTEX(tl_reader_lock);
|
|
|
|
/* Timeline stream event queue. */
|
|
static DECLARE_WAIT_QUEUE_HEAD(tl_event_queue);
|
|
|
|
/* The timeline stream file operations functions. */
|
|
static ssize_t kbasep_tlstream_read(
|
|
struct file *filp,
|
|
char __user *buffer,
|
|
size_t size,
|
|
loff_t *f_pos);
|
|
static unsigned int kbasep_tlstream_poll(struct file *filp, poll_table *wait);
|
|
static int kbasep_tlstream_release(struct inode *inode, struct file *filp);
|
|
|
|
/* The timeline stream file operations structure. */
|
|
static const struct file_operations kbasep_tlstream_fops = {
|
|
.release = kbasep_tlstream_release,
|
|
.read = kbasep_tlstream_read,
|
|
.poll = kbasep_tlstream_poll,
|
|
};
|
|
|
|
/* Descriptors of timeline messages transmitted in object events stream. */
|
|
static const struct tp_desc tp_desc_obj[] = {
|
|
{
|
|
KBASE_TL_NEW_CTX,
|
|
__stringify(KBASE_TL_NEW_CTX),
|
|
"object ctx is created",
|
|
"@pII",
|
|
"ctx,ctx_nr,tgid"
|
|
},
|
|
{
|
|
KBASE_TL_NEW_GPU,
|
|
__stringify(KBASE_TL_NEW_GPU),
|
|
"object gpu is created",
|
|
"@pII",
|
|
"gpu,gpu_id,core_count"
|
|
},
|
|
{
|
|
KBASE_TL_NEW_LPU,
|
|
__stringify(KBASE_TL_NEW_LPU),
|
|
"object lpu is created",
|
|
"@pII",
|
|
"lpu,lpu_nr,lpu_fn"
|
|
},
|
|
{
|
|
KBASE_TL_NEW_ATOM,
|
|
__stringify(KBASE_TL_NEW_ATOM),
|
|
"object atom is created",
|
|
"@pI",
|
|
"atom,atom_nr"
|
|
},
|
|
{
|
|
KBASE_TL_NEW_AS,
|
|
__stringify(KBASE_TL_NEW_AS),
|
|
"address space object is created",
|
|
"@pI",
|
|
"address_space,as_nr"
|
|
},
|
|
{
|
|
KBASE_TL_DEL_CTX,
|
|
__stringify(KBASE_TL_DEL_CTX),
|
|
"context is destroyed",
|
|
"@p",
|
|
"ctx"
|
|
},
|
|
{
|
|
KBASE_TL_DEL_ATOM,
|
|
__stringify(KBASE_TL_DEL_ATOM),
|
|
"atom is destroyed",
|
|
"@p",
|
|
"atom"
|
|
},
|
|
{
|
|
KBASE_TL_LIFELINK_LPU_GPU,
|
|
__stringify(KBASE_TL_LIFELINK_LPU_GPU),
|
|
"lpu is deleted with gpu",
|
|
"@pp",
|
|
"lpu,gpu"
|
|
},
|
|
{
|
|
KBASE_TL_LIFELINK_AS_GPU,
|
|
__stringify(KBASE_TL_LIFELINK_AS_GPU),
|
|
"address space is deleted with gpu",
|
|
"@pp",
|
|
"address_space,gpu"
|
|
},
|
|
{
|
|
KBASE_TL_RET_CTX_LPU,
|
|
__stringify(KBASE_TL_RET_CTX_LPU),
|
|
"context is retained by lpu",
|
|
"@pp",
|
|
"ctx,lpu"
|
|
},
|
|
{
|
|
KBASE_TL_RET_ATOM_CTX,
|
|
__stringify(KBASE_TL_RET_ATOM_CTX),
|
|
"atom is retained by context",
|
|
"@pp",
|
|
"atom,ctx"
|
|
},
|
|
{
|
|
KBASE_TL_RET_ATOM_LPU,
|
|
__stringify(KBASE_TL_RET_ATOM_LPU),
|
|
"atom is retained by lpu",
|
|
"@pps",
|
|
"atom,lpu,attrib_match_list"
|
|
},
|
|
{
|
|
KBASE_TL_NRET_CTX_LPU,
|
|
__stringify(KBASE_TL_NRET_CTX_LPU),
|
|
"context is released by lpu",
|
|
"@pp",
|
|
"ctx,lpu"
|
|
},
|
|
{
|
|
KBASE_TL_NRET_ATOM_CTX,
|
|
__stringify(KBASE_TL_NRET_ATOM_CTX),
|
|
"atom is released by context",
|
|
"@pp",
|
|
"atom,ctx"
|
|
},
|
|
{
|
|
KBASE_TL_NRET_ATOM_LPU,
|
|
__stringify(KBASE_TL_NRET_ATOM_LPU),
|
|
"atom is released by lpu",
|
|
"@pp",
|
|
"atom,lpu"
|
|
},
|
|
{
|
|
KBASE_TL_RET_AS_CTX,
|
|
__stringify(KBASE_TL_RET_AS_CTX),
|
|
"address space is retained by context",
|
|
"@pp",
|
|
"address_space,ctx"
|
|
},
|
|
{
|
|
KBASE_TL_NRET_AS_CTX,
|
|
__stringify(KBASE_TL_NRET_AS_CTX),
|
|
"address space is released by context",
|
|
"@pp",
|
|
"address_space,ctx"
|
|
},
|
|
{
|
|
KBASE_TL_RET_ATOM_AS,
|
|
__stringify(KBASE_TL_RET_ATOM_AS),
|
|
"atom is retained by address space",
|
|
"@pp",
|
|
"atom,address_space"
|
|
},
|
|
{
|
|
KBASE_TL_NRET_ATOM_AS,
|
|
__stringify(KBASE_TL_NRET_ATOM_AS),
|
|
"atom is released by address space",
|
|
"@pp",
|
|
"atom,address_space"
|
|
},
|
|
{
|
|
KBASE_TL_DEP_ATOM_ATOM,
|
|
__stringify(KBASE_TL_DEP_ATOM_ATOM),
|
|
"atom2 depends on atom1",
|
|
"@pp",
|
|
"atom1,atom2"
|
|
},
|
|
{
|
|
KBASE_TL_NDEP_ATOM_ATOM,
|
|
__stringify(KBASE_TL_NDEP_ATOM_ATOM),
|
|
"atom2 no longer depends on atom1",
|
|
"@pp",
|
|
"atom1,atom2"
|
|
},
|
|
{
|
|
KBASE_TL_RDEP_ATOM_ATOM,
|
|
__stringify(KBASE_TL_RDEP_ATOM_ATOM),
|
|
"resolved dependecy of atom2 depending on atom1",
|
|
"@pp",
|
|
"atom1,atom2"
|
|
},
|
|
{
|
|
KBASE_TL_ATTRIB_ATOM_CONFIG,
|
|
__stringify(KBASE_TL_ATTRIB_ATOM_CONFIG),
|
|
"atom job slot attributes",
|
|
"@pLLI",
|
|
"atom,descriptor,affinity,config"
|
|
},
|
|
{
|
|
KBASE_TL_ATTRIB_ATOM_PRIORITY,
|
|
__stringify(KBASE_TL_ATTRIB_ATOM_PRIORITY),
|
|
"atom priority",
|
|
"@pI",
|
|
"atom,prio"
|
|
},
|
|
{
|
|
KBASE_TL_ATTRIB_ATOM_STATE,
|
|
__stringify(KBASE_TL_ATTRIB_ATOM_STATE),
|
|
"atom state",
|
|
"@pI",
|
|
"atom,state"
|
|
},
|
|
{
|
|
KBASE_TL_ATTRIB_ATOM_PRIORITY_CHANGE,
|
|
__stringify(KBASE_TL_ATTRIB_ATOM_PRIORITY_CHANGE),
|
|
"atom caused priority change",
|
|
"@p",
|
|
"atom"
|
|
},
|
|
{
|
|
KBASE_TL_ATTRIB_ATOM_JIT,
|
|
__stringify(KBASE_TL_ATTRIB_ATOM_JIT),
|
|
"jit done for atom",
|
|
"@pLL",
|
|
"atom,edit_addr,new_addr"
|
|
},
|
|
{
|
|
KBASE_TL_ATTRIB_AS_CONFIG,
|
|
__stringify(KBASE_TL_ATTRIB_AS_CONFIG),
|
|
"address space attributes",
|
|
"@pLLL",
|
|
"address_space,transtab,memattr,transcfg"
|
|
},
|
|
{
|
|
KBASE_TL_EVENT_LPU_SOFTSTOP,
|
|
__stringify(KBASE_TL_EVENT_LPU_SOFTSTOP),
|
|
"softstop event on given lpu",
|
|
"@p",
|
|
"lpu"
|
|
},
|
|
{
|
|
KBASE_TL_EVENT_ATOM_SOFTSTOP_EX,
|
|
__stringify(KBASE_TL_EVENT_ATOM_SOFTSTOP_EX),
|
|
"atom softstopped",
|
|
"@p",
|
|
"atom"
|
|
},
|
|
{
|
|
KBASE_TL_EVENT_ATOM_SOFTSTOP_ISSUE,
|
|
__stringify(KBASE_TL_EVENT_SOFTSTOP_ISSUE),
|
|
"atom softstop issued",
|
|
"@p",
|
|
"atom"
|
|
},
|
|
{
|
|
KBASE_JD_GPU_SOFT_RESET,
|
|
__stringify(KBASE_JD_GPU_SOFT_RESET),
|
|
"gpu soft reset",
|
|
"@p",
|
|
"gpu"
|
|
},
|
|
};
|
|
|
|
/* Descriptors of timeline messages transmitted in auxiliary events stream. */
|
|
static const struct tp_desc tp_desc_aux[] = {
|
|
{
|
|
KBASE_AUX_PM_STATE,
|
|
__stringify(KBASE_AUX_PM_STATE),
|
|
"PM state",
|
|
"@IL",
|
|
"core_type,core_state_bitset"
|
|
},
|
|
{
|
|
KBASE_AUX_PAGEFAULT,
|
|
__stringify(KBASE_AUX_PAGEFAULT),
|
|
"Page fault",
|
|
"@IL",
|
|
"ctx_nr,page_cnt_change"
|
|
},
|
|
{
|
|
KBASE_AUX_PAGESALLOC,
|
|
__stringify(KBASE_AUX_PAGESALLOC),
|
|
"Total alloc pages change",
|
|
"@IL",
|
|
"ctx_nr,page_cnt"
|
|
},
|
|
{
|
|
KBASE_AUX_DEVFREQ_TARGET,
|
|
__stringify(KBASE_AUX_DEVFREQ_TARGET),
|
|
"New device frequency target",
|
|
"@L",
|
|
"target_freq"
|
|
},
|
|
{
|
|
KBASE_AUX_PROTECTED_ENTER_START,
|
|
__stringify(KBASE_AUX_PROTECTED_ENTER_START),
|
|
"enter protected mode start",
|
|
"@p",
|
|
"gpu"
|
|
},
|
|
{
|
|
KBASE_AUX_PROTECTED_ENTER_END,
|
|
__stringify(KBASE_AUX_PROTECTED_ENTER_END),
|
|
"enter protected mode end",
|
|
"@p",
|
|
"gpu"
|
|
},
|
|
{
|
|
KBASE_AUX_PROTECTED_LEAVE_START,
|
|
__stringify(KBASE_AUX_PROTECTED_LEAVE_START),
|
|
"leave protected mode start",
|
|
"@p",
|
|
"gpu"
|
|
},
|
|
{
|
|
KBASE_AUX_PROTECTED_LEAVE_END,
|
|
__stringify(KBASE_AUX_PROTECTED_LEAVE_END),
|
|
"leave protected mode end",
|
|
"@p",
|
|
"gpu"
|
|
}
|
|
};
|
|
|
|
#if MALI_UNIT_TEST
|
|
/* Number of bytes read by user. */
|
|
static atomic_t tlstream_bytes_collected = {0};
|
|
|
|
/* Number of bytes generated by tracepoint messages. */
|
|
static atomic_t tlstream_bytes_generated = {0};
|
|
#endif /* MALI_UNIT_TEST */
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Indicator of whether the timeline stream file descriptor is used. */
|
|
atomic_t kbase_tlstream_enabled = {0};
|
|
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
* kbasep_tlstream_get_timestamp - return timestamp
|
|
*
|
|
* Function returns timestamp value based on raw monotonic timer. Value will
|
|
* wrap around zero in case of overflow.
|
|
* Return: timestamp value
|
|
*/
|
|
static u64 kbasep_tlstream_get_timestamp(void)
|
|
{
|
|
struct timespec64 ts;
|
|
u64 timestamp;
|
|
|
|
ktime_get_raw_ts64(&ts);
|
|
timestamp = (u64)ts.tv_sec * NSECS_IN_SEC + ts.tv_nsec;
|
|
return timestamp;
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_write_bytes - write data to message buffer
|
|
* @buffer: buffer where data will be written
|
|
* @pos: position in the buffer where to place data
|
|
* @bytes: pointer to buffer holding data
|
|
* @len: length of data to be written
|
|
*
|
|
* Return: updated position in the buffer
|
|
*/
|
|
static size_t kbasep_tlstream_write_bytes(
|
|
char *buffer,
|
|
size_t pos,
|
|
const void *bytes,
|
|
size_t len)
|
|
{
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
KBASE_DEBUG_ASSERT(bytes);
|
|
|
|
memcpy(&buffer[pos], bytes, len);
|
|
|
|
return pos + len;
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_write_string - write string to message buffer
|
|
* @buffer: buffer where data will be written
|
|
* @pos: position in the buffer where to place data
|
|
* @string: pointer to buffer holding the source string
|
|
* @max_write_size: number of bytes that can be stored in buffer
|
|
*
|
|
* Return: updated position in the buffer
|
|
*/
|
|
static size_t kbasep_tlstream_write_string(
|
|
char *buffer,
|
|
size_t pos,
|
|
const char *string,
|
|
size_t max_write_size)
|
|
{
|
|
u32 string_len;
|
|
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
KBASE_DEBUG_ASSERT(string);
|
|
/* Timeline string consists of at least string length and nul
|
|
* terminator. */
|
|
KBASE_DEBUG_ASSERT(max_write_size >= sizeof(string_len) + sizeof(char));
|
|
max_write_size -= sizeof(string_len);
|
|
|
|
string_len = strlcpy(
|
|
&buffer[pos + sizeof(string_len)],
|
|
string,
|
|
max_write_size);
|
|
string_len += sizeof(char);
|
|
|
|
/* Make sure that the source string fit into the buffer. */
|
|
KBASE_DEBUG_ASSERT(string_len <= max_write_size);
|
|
|
|
/* Update string length. */
|
|
memcpy(&buffer[pos], &string_len, sizeof(string_len));
|
|
|
|
return pos + sizeof(string_len) + string_len;
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_write_timestamp - write timestamp to message buffer
|
|
* @buffer: buffer where data will be written
|
|
* @pos: position in the buffer where to place data
|
|
*
|
|
* Return: updated position in the buffer
|
|
*/
|
|
static size_t kbasep_tlstream_write_timestamp(void *buffer, size_t pos)
|
|
{
|
|
u64 timestamp = kbasep_tlstream_get_timestamp();
|
|
|
|
return kbasep_tlstream_write_bytes(
|
|
buffer, pos,
|
|
×tamp, sizeof(timestamp));
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_put_bits - put bits in a word
|
|
* @word: pointer to the words being modified
|
|
* @value: value that shall be written to given position
|
|
* @bitpos: position where value shall be written (in bits)
|
|
* @bitlen: length of value (in bits)
|
|
*/
|
|
static void kbasep_tlstream_put_bits(
|
|
u32 *word,
|
|
u32 value,
|
|
unsigned int bitpos,
|
|
unsigned int bitlen)
|
|
{
|
|
const u32 mask = ((1 << bitlen) - 1) << bitpos;
|
|
|
|
KBASE_DEBUG_ASSERT(word);
|
|
KBASE_DEBUG_ASSERT((0 != bitlen) && (32 >= bitlen));
|
|
KBASE_DEBUG_ASSERT((bitpos + bitlen) <= 32);
|
|
|
|
*word &= ~mask;
|
|
*word |= ((value << bitpos) & mask);
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_packet_header_setup - setup the packet header
|
|
* @buffer: pointer to the buffer
|
|
* @pkt_family: packet's family
|
|
* @pkt_type: packet's type
|
|
* @pkt_class: packet's class
|
|
* @stream_id: stream id
|
|
* @numbered: non-zero if this stream is numbered
|
|
*
|
|
* Function sets up immutable part of packet header in the given buffer.
|
|
*/
|
|
static void kbasep_tlstream_packet_header_setup(
|
|
char *buffer,
|
|
enum tl_packet_family pkt_family,
|
|
enum tl_packet_class pkt_class,
|
|
enum tl_packet_type pkt_type,
|
|
unsigned int stream_id,
|
|
int numbered)
|
|
{
|
|
u32 word0 = 0;
|
|
u32 word1 = 0;
|
|
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
KBASE_DEBUG_ASSERT(pkt_family == TL_PACKET_FAMILY_TL);
|
|
KBASE_DEBUG_ASSERT(
|
|
(pkt_type == TL_PACKET_TYPE_HEADER) ||
|
|
(pkt_type == TL_PACKET_TYPE_SUMMARY) ||
|
|
(pkt_type == TL_PACKET_TYPE_BODY));
|
|
KBASE_DEBUG_ASSERT(
|
|
(pkt_class == TL_PACKET_CLASS_OBJ) ||
|
|
(pkt_class == TL_PACKET_CLASS_AUX));
|
|
|
|
kbasep_tlstream_put_bits(
|
|
&word0, pkt_family,
|
|
PACKET_FAMILY_POS, PACKET_FAMILY_LEN);
|
|
kbasep_tlstream_put_bits(
|
|
&word0, pkt_class,
|
|
PACKET_CLASS_POS, PACKET_CLASS_LEN);
|
|
kbasep_tlstream_put_bits(
|
|
&word0, pkt_type,
|
|
PACKET_TYPE_POS, PACKET_TYPE_LEN);
|
|
kbasep_tlstream_put_bits(
|
|
&word0, stream_id,
|
|
PACKET_STREAMID_POS, PACKET_STREAMID_LEN);
|
|
|
|
if (numbered)
|
|
kbasep_tlstream_put_bits(
|
|
&word1, 1,
|
|
PACKET_SEQBIT_POS, PACKET_SEQBIT_LEN);
|
|
|
|
memcpy(&buffer[0], &word0, sizeof(word0));
|
|
memcpy(&buffer[sizeof(word0)], &word1, sizeof(word1));
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_packet_header_update - update the packet header
|
|
* @buffer: pointer to the buffer
|
|
* @data_size: amount of data carried in this packet
|
|
*
|
|
* Function updates mutable part of packet header in the given buffer.
|
|
* Note that value of data_size must not including size of the header.
|
|
*/
|
|
static void kbasep_tlstream_packet_header_update(
|
|
char *buffer,
|
|
size_t data_size)
|
|
{
|
|
u32 word0;
|
|
u32 word1;
|
|
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
CSTD_UNUSED(word0);
|
|
|
|
memcpy(&word1, &buffer[sizeof(word0)], sizeof(word1));
|
|
|
|
kbasep_tlstream_put_bits(
|
|
&word1, data_size,
|
|
PACKET_LENGTH_POS, PACKET_LENGTH_LEN);
|
|
|
|
memcpy(&buffer[sizeof(word0)], &word1, sizeof(word1));
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_packet_number_update - update the packet number
|
|
* @buffer: pointer to the buffer
|
|
* @counter: value of packet counter for this packet's stream
|
|
*
|
|
* Function updates packet number embedded within the packet placed in the
|
|
* given buffer.
|
|
*/
|
|
static void kbasep_tlstream_packet_number_update(char *buffer, u32 counter)
|
|
{
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
memcpy(&buffer[PACKET_HEADER_SIZE], &counter, sizeof(counter));
|
|
}
|
|
|
|
/**
|
|
* kbasep_timeline_stream_reset - reset stream
|
|
* @stream: pointer to the stream structure
|
|
*
|
|
* Function discards all pending messages and resets packet counters.
|
|
*/
|
|
static void kbasep_timeline_stream_reset(struct tl_stream *stream)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < PACKET_COUNT; i++) {
|
|
if (stream->numbered)
|
|
atomic_set(
|
|
&stream->buffer[i].size,
|
|
PACKET_HEADER_SIZE +
|
|
PACKET_NUMBER_SIZE);
|
|
else
|
|
atomic_set(&stream->buffer[i].size, PACKET_HEADER_SIZE);
|
|
}
|
|
|
|
atomic_set(&stream->wbi, 0);
|
|
atomic_set(&stream->rbi, 0);
|
|
}
|
|
|
|
/**
|
|
* kbasep_timeline_stream_init - initialize timeline stream
|
|
* @stream: pointer to the stream structure
|
|
* @stream_type: stream type
|
|
*/
|
|
static void kbasep_timeline_stream_init(
|
|
struct tl_stream *stream,
|
|
enum tl_stream_type stream_type)
|
|
{
|
|
unsigned int i;
|
|
|
|
KBASE_DEBUG_ASSERT(stream);
|
|
KBASE_DEBUG_ASSERT(TL_STREAM_TYPE_COUNT > stream_type);
|
|
|
|
spin_lock_init(&stream->lock);
|
|
|
|
/* All packets carrying tracepoints shall be numbered. */
|
|
if (TL_PACKET_TYPE_BODY == tl_stream_cfg[stream_type].pkt_type)
|
|
stream->numbered = 1;
|
|
else
|
|
stream->numbered = 0;
|
|
|
|
for (i = 0; i < PACKET_COUNT; i++)
|
|
kbasep_tlstream_packet_header_setup(
|
|
stream->buffer[i].data,
|
|
tl_stream_cfg[stream_type].pkt_family,
|
|
tl_stream_cfg[stream_type].pkt_class,
|
|
tl_stream_cfg[stream_type].pkt_type,
|
|
tl_stream_cfg[stream_type].stream_id,
|
|
stream->numbered);
|
|
|
|
kbasep_timeline_stream_reset(tl_stream[stream_type]);
|
|
}
|
|
|
|
/**
|
|
* kbasep_timeline_stream_term - terminate timeline stream
|
|
* @stream: pointer to the stream structure
|
|
*/
|
|
static void kbasep_timeline_stream_term(struct tl_stream *stream)
|
|
{
|
|
KBASE_DEBUG_ASSERT(stream);
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_msgbuf_submit - submit packet to the user space
|
|
* @stream: pointer to the stream structure
|
|
* @wb_idx_raw: write buffer index
|
|
* @wb_size: length of data stored in current buffer
|
|
*
|
|
* Function updates currently written buffer with packet header. Then write
|
|
* index is incremented and buffer is handled to user space. Parameters
|
|
* of new buffer are returned using provided arguments.
|
|
*
|
|
* Return: length of data in new buffer
|
|
*
|
|
* Warning: User must update the stream structure with returned value.
|
|
*/
|
|
static size_t kbasep_tlstream_msgbuf_submit(
|
|
struct tl_stream *stream,
|
|
unsigned int wb_idx_raw,
|
|
unsigned int wb_size)
|
|
{
|
|
unsigned int rb_idx_raw = atomic_read(&stream->rbi);
|
|
unsigned int wb_idx = wb_idx_raw % PACKET_COUNT;
|
|
|
|
/* Set stream as flushed. */
|
|
atomic_set(&stream->autoflush_counter, -1);
|
|
|
|
kbasep_tlstream_packet_header_update(
|
|
stream->buffer[wb_idx].data,
|
|
wb_size - PACKET_HEADER_SIZE);
|
|
|
|
if (stream->numbered)
|
|
kbasep_tlstream_packet_number_update(
|
|
stream->buffer[wb_idx].data,
|
|
wb_idx_raw);
|
|
|
|
/* Increasing write buffer index will expose this packet to the reader.
|
|
* As stream->lock is not taken on reader side we must make sure memory
|
|
* is updated correctly before this will happen. */
|
|
smp_wmb();
|
|
wb_idx_raw++;
|
|
atomic_set(&stream->wbi, wb_idx_raw);
|
|
|
|
/* Inform user that packets are ready for reading. */
|
|
wake_up_interruptible(&tl_event_queue);
|
|
|
|
/* Detect and mark overflow in this stream. */
|
|
if (PACKET_COUNT == wb_idx_raw - rb_idx_raw) {
|
|
/* Reader side depends on this increment to correctly handle
|
|
* overflows. The value shall be updated only if it was not
|
|
* modified by the reader. The data holding buffer will not be
|
|
* updated before stream->lock is released, however size of the
|
|
* buffer will. Make sure this increment is globally visible
|
|
* before information about selected write buffer size. */
|
|
atomic_cmpxchg(&stream->rbi, rb_idx_raw, rb_idx_raw + 1);
|
|
}
|
|
|
|
wb_size = PACKET_HEADER_SIZE;
|
|
if (stream->numbered)
|
|
wb_size += PACKET_NUMBER_SIZE;
|
|
|
|
return wb_size;
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_msgbuf_acquire - lock selected stream and reserves buffer
|
|
* @stream_type: type of the stream that shall be locked
|
|
* @msg_size: message size
|
|
* @flags: pointer to store flags passed back on stream release
|
|
*
|
|
* Function will lock the stream and reserve the number of bytes requested
|
|
* in msg_size for the user.
|
|
*
|
|
* Return: pointer to the buffer where message can be stored
|
|
*
|
|
* Warning: Stream must be released with kbasep_tlstream_msgbuf_release().
|
|
* Only atomic operations are allowed while stream is locked
|
|
* (i.e. do not use any operation that may sleep).
|
|
*/
|
|
static char *kbasep_tlstream_msgbuf_acquire(
|
|
enum tl_stream_type stream_type,
|
|
size_t msg_size,
|
|
unsigned long *flags) __acquires(&stream->lock)
|
|
{
|
|
struct tl_stream *stream;
|
|
unsigned int wb_idx_raw;
|
|
unsigned int wb_idx;
|
|
size_t wb_size;
|
|
|
|
KBASE_DEBUG_ASSERT(TL_STREAM_TYPE_COUNT > stream_type);
|
|
KBASE_DEBUG_ASSERT(
|
|
PACKET_SIZE - PACKET_HEADER_SIZE - PACKET_NUMBER_SIZE >=
|
|
msg_size);
|
|
|
|
stream = tl_stream[stream_type];
|
|
|
|
spin_lock_irqsave(&stream->lock, *flags);
|
|
|
|
wb_idx_raw = atomic_read(&stream->wbi);
|
|
wb_idx = wb_idx_raw % PACKET_COUNT;
|
|
wb_size = atomic_read(&stream->buffer[wb_idx].size);
|
|
|
|
/* Select next buffer if data will not fit into current one. */
|
|
if (PACKET_SIZE < wb_size + msg_size) {
|
|
wb_size = kbasep_tlstream_msgbuf_submit(
|
|
stream, wb_idx_raw, wb_size);
|
|
wb_idx = (wb_idx_raw + 1) % PACKET_COUNT;
|
|
}
|
|
|
|
/* Reserve space in selected buffer. */
|
|
atomic_set(&stream->buffer[wb_idx].size, wb_size + msg_size);
|
|
|
|
#if MALI_UNIT_TEST
|
|
atomic_add(msg_size, &tlstream_bytes_generated);
|
|
#endif /* MALI_UNIT_TEST */
|
|
|
|
return &stream->buffer[wb_idx].data[wb_size];
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_msgbuf_release - unlock selected stream
|
|
* @stream_type: type of the stream that shall be locked
|
|
* @flags: value obtained during stream acquire
|
|
*
|
|
* Function releases stream that has been previously locked with a call to
|
|
* kbasep_tlstream_msgbuf_acquire().
|
|
*/
|
|
static void kbasep_tlstream_msgbuf_release(
|
|
enum tl_stream_type stream_type,
|
|
unsigned long flags) __releases(&stream->lock)
|
|
{
|
|
struct tl_stream *stream;
|
|
|
|
KBASE_DEBUG_ASSERT(TL_STREAM_TYPE_COUNT > stream_type);
|
|
|
|
stream = tl_stream[stream_type];
|
|
|
|
/* Mark stream as containing unflushed data. */
|
|
atomic_set(&stream->autoflush_counter, 0);
|
|
|
|
spin_unlock_irqrestore(&stream->lock, flags);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
* kbasep_tlstream_flush_stream - flush stream
|
|
* @stype: type of stream to be flushed
|
|
*
|
|
* Flush pending data in timeline stream.
|
|
*/
|
|
static void kbasep_tlstream_flush_stream(enum tl_stream_type stype)
|
|
{
|
|
struct tl_stream *stream = tl_stream[stype];
|
|
unsigned long flags;
|
|
unsigned int wb_idx_raw;
|
|
unsigned int wb_idx;
|
|
size_t wb_size;
|
|
size_t min_size = PACKET_HEADER_SIZE;
|
|
|
|
if (stream->numbered)
|
|
min_size += PACKET_NUMBER_SIZE;
|
|
|
|
spin_lock_irqsave(&stream->lock, flags);
|
|
|
|
wb_idx_raw = atomic_read(&stream->wbi);
|
|
wb_idx = wb_idx_raw % PACKET_COUNT;
|
|
wb_size = atomic_read(&stream->buffer[wb_idx].size);
|
|
|
|
if (wb_size > min_size) {
|
|
wb_size = kbasep_tlstream_msgbuf_submit(
|
|
stream, wb_idx_raw, wb_size);
|
|
wb_idx = (wb_idx_raw + 1) % PACKET_COUNT;
|
|
atomic_set(&stream->buffer[wb_idx].size, wb_size);
|
|
}
|
|
spin_unlock_irqrestore(&stream->lock, flags);
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_autoflush_timer_callback - autoflush timer callback
|
|
* @data: unused
|
|
*
|
|
* Timer is executed periodically to check if any of the stream contains
|
|
* buffer ready to be submitted to user space.
|
|
*/
|
|
static void kbasep_tlstream_autoflush_timer_callback(struct timer_list *t)
|
|
{
|
|
enum tl_stream_type stype;
|
|
int rcode;
|
|
|
|
CSTD_UNUSED(t);
|
|
|
|
for (stype = 0; stype < TL_STREAM_TYPE_COUNT; stype++) {
|
|
struct tl_stream *stream = tl_stream[stype];
|
|
unsigned long flags;
|
|
unsigned int wb_idx_raw;
|
|
unsigned int wb_idx;
|
|
size_t wb_size;
|
|
size_t min_size = PACKET_HEADER_SIZE;
|
|
|
|
int af_cnt = atomic_read(&stream->autoflush_counter);
|
|
|
|
/* Check if stream contain unflushed data. */
|
|
if (0 > af_cnt)
|
|
continue;
|
|
|
|
/* Check if stream should be flushed now. */
|
|
if (af_cnt != atomic_cmpxchg(
|
|
&stream->autoflush_counter,
|
|
af_cnt,
|
|
af_cnt + 1))
|
|
continue;
|
|
if (!af_cnt)
|
|
continue;
|
|
|
|
/* Autoflush this stream. */
|
|
if (stream->numbered)
|
|
min_size += PACKET_NUMBER_SIZE;
|
|
|
|
spin_lock_irqsave(&stream->lock, flags);
|
|
|
|
wb_idx_raw = atomic_read(&stream->wbi);
|
|
wb_idx = wb_idx_raw % PACKET_COUNT;
|
|
wb_size = atomic_read(&stream->buffer[wb_idx].size);
|
|
|
|
if (wb_size > min_size) {
|
|
wb_size = kbasep_tlstream_msgbuf_submit(
|
|
stream, wb_idx_raw, wb_size);
|
|
wb_idx = (wb_idx_raw + 1) % PACKET_COUNT;
|
|
atomic_set(&stream->buffer[wb_idx].size,
|
|
wb_size);
|
|
}
|
|
spin_unlock_irqrestore(&stream->lock, flags);
|
|
}
|
|
|
|
if (atomic_read(&autoflush_timer_active))
|
|
rcode = mod_timer(
|
|
&autoflush_timer,
|
|
jiffies + msecs_to_jiffies(AUTOFLUSH_INTERVAL));
|
|
CSTD_UNUSED(rcode);
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_packet_pending - check timeline streams for pending packets
|
|
* @stype: pointer to variable where stream type will be placed
|
|
* @rb_idx_raw: pointer to variable where read buffer index will be placed
|
|
*
|
|
* Function checks all streams for pending packets. It will stop as soon as
|
|
* packet ready to be submitted to user space is detected. Variables under
|
|
* pointers, passed as the parameters to this function will be updated with
|
|
* values pointing to right stream and buffer.
|
|
*
|
|
* Return: non-zero if any of timeline streams has at last one packet ready
|
|
*/
|
|
static int kbasep_tlstream_packet_pending(
|
|
enum tl_stream_type *stype,
|
|
unsigned int *rb_idx_raw)
|
|
{
|
|
int pending = 0;
|
|
|
|
KBASE_DEBUG_ASSERT(stype);
|
|
KBASE_DEBUG_ASSERT(rb_idx_raw);
|
|
|
|
for (
|
|
*stype = 0;
|
|
(*stype < TL_STREAM_TYPE_COUNT) && !pending;
|
|
(*stype)++) {
|
|
if (NULL != tl_stream[*stype]) {
|
|
*rb_idx_raw = atomic_read(&tl_stream[*stype]->rbi);
|
|
/* Read buffer index may be updated by writer in case of
|
|
* overflow. Read and write buffer indexes must be
|
|
* loaded in correct order. */
|
|
smp_rmb();
|
|
if (atomic_read(&tl_stream[*stype]->wbi) != *rb_idx_raw)
|
|
pending = 1;
|
|
}
|
|
}
|
|
(*stype)--;
|
|
|
|
return pending;
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_read - copy data from streams to buffer provided by user
|
|
* @filp: pointer to file structure (unused)
|
|
* @buffer: pointer to the buffer provided by user
|
|
* @size: maximum amount of data that can be stored in the buffer
|
|
* @f_pos: pointer to file offset (unused)
|
|
*
|
|
* Return: number of bytes stored in the buffer
|
|
*/
|
|
static ssize_t kbasep_tlstream_read(
|
|
struct file *filp,
|
|
char __user *buffer,
|
|
size_t size,
|
|
loff_t *f_pos)
|
|
{
|
|
ssize_t copy_len = 0;
|
|
|
|
KBASE_DEBUG_ASSERT(filp);
|
|
KBASE_DEBUG_ASSERT(f_pos);
|
|
|
|
if (!buffer)
|
|
return -EINVAL;
|
|
|
|
if ((0 > *f_pos) || (PACKET_SIZE > size))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&tl_reader_lock);
|
|
|
|
while (copy_len < size) {
|
|
enum tl_stream_type stype;
|
|
unsigned int rb_idx_raw = 0;
|
|
unsigned int rb_idx;
|
|
size_t rb_size;
|
|
|
|
/* If we don't have any data yet, wait for packet to be
|
|
* submitted. If we already read some packets and there is no
|
|
* packet pending return back to user. */
|
|
if (0 < copy_len) {
|
|
if (!kbasep_tlstream_packet_pending(
|
|
&stype,
|
|
&rb_idx_raw))
|
|
break;
|
|
} else {
|
|
if (wait_event_interruptible(
|
|
tl_event_queue,
|
|
kbasep_tlstream_packet_pending(
|
|
&stype,
|
|
&rb_idx_raw))) {
|
|
copy_len = -ERESTARTSYS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Check if this packet fits into the user buffer.
|
|
* If so copy its content. */
|
|
rb_idx = rb_idx_raw % PACKET_COUNT;
|
|
rb_size = atomic_read(&tl_stream[stype]->buffer[rb_idx].size);
|
|
if (rb_size > size - copy_len)
|
|
break;
|
|
if (copy_to_user(
|
|
&buffer[copy_len],
|
|
tl_stream[stype]->buffer[rb_idx].data,
|
|
rb_size)) {
|
|
copy_len = -EFAULT;
|
|
break;
|
|
}
|
|
|
|
/* If the rbi still points to the packet we just processed
|
|
* then there was no overflow so we add the copied size to
|
|
* copy_len and move rbi on to the next packet
|
|
*/
|
|
smp_rmb();
|
|
if (atomic_read(&tl_stream[stype]->rbi) == rb_idx_raw) {
|
|
copy_len += rb_size;
|
|
atomic_inc(&tl_stream[stype]->rbi);
|
|
|
|
#if MALI_UNIT_TEST
|
|
atomic_add(rb_size, &tlstream_bytes_collected);
|
|
#endif /* MALI_UNIT_TEST */
|
|
}
|
|
}
|
|
|
|
mutex_unlock(&tl_reader_lock);
|
|
|
|
return copy_len;
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_poll - poll timeline stream for packets
|
|
* @filp: pointer to file structure
|
|
* @wait: pointer to poll table
|
|
* Return: POLLIN if data can be read without blocking, otherwise zero
|
|
*/
|
|
static unsigned int kbasep_tlstream_poll(struct file *filp, poll_table *wait)
|
|
{
|
|
enum tl_stream_type stream_type;
|
|
unsigned int rb_idx;
|
|
|
|
KBASE_DEBUG_ASSERT(filp);
|
|
KBASE_DEBUG_ASSERT(wait);
|
|
|
|
poll_wait(filp, &tl_event_queue, wait);
|
|
if (kbasep_tlstream_packet_pending(&stream_type, &rb_idx))
|
|
return POLLIN;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_release - release timeline stream descriptor
|
|
* @inode: pointer to inode structure
|
|
* @filp: pointer to file structure
|
|
*
|
|
* Return always return zero
|
|
*/
|
|
static int kbasep_tlstream_release(struct inode *inode, struct file *filp)
|
|
{
|
|
KBASE_DEBUG_ASSERT(inode);
|
|
KBASE_DEBUG_ASSERT(filp);
|
|
CSTD_UNUSED(inode);
|
|
CSTD_UNUSED(filp);
|
|
|
|
/* Stop autoflush timer before releasing access to streams. */
|
|
atomic_set(&autoflush_timer_active, 0);
|
|
del_timer_sync(&autoflush_timer);
|
|
|
|
atomic_set(&kbase_tlstream_enabled, 0);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* kbasep_tlstream_timeline_header - prepare timeline header stream packet
|
|
* @stream_type: type of the stream that will carry header data
|
|
* @tp_desc: pointer to array with tracepoint descriptors
|
|
* @tp_count: number of descriptors in the given array
|
|
*
|
|
* Functions fills in information about tracepoints stored in body stream
|
|
* associated with this header stream.
|
|
*/
|
|
static void kbasep_tlstream_timeline_header(
|
|
enum tl_stream_type stream_type,
|
|
const struct tp_desc *tp_desc,
|
|
u32 tp_count)
|
|
{
|
|
const u8 tv = SWTRACE_VERSION; /* protocol version */
|
|
const u8 ps = sizeof(void *); /* pointer size */
|
|
size_t msg_size = sizeof(tv) + sizeof(ps) + sizeof(tp_count);
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
unsigned long flags;
|
|
unsigned int i;
|
|
|
|
KBASE_DEBUG_ASSERT(TL_STREAM_TYPE_COUNT > stream_type);
|
|
KBASE_DEBUG_ASSERT(tp_desc);
|
|
|
|
/* Calculate the size of the timeline message. */
|
|
for (i = 0; i < tp_count; i++) {
|
|
msg_size += sizeof(tp_desc[i].id);
|
|
msg_size +=
|
|
strnlen(tp_desc[i].id_str, STRLEN_MAX) +
|
|
sizeof(char) + sizeof(u32);
|
|
msg_size +=
|
|
strnlen(tp_desc[i].name, STRLEN_MAX) +
|
|
sizeof(char) + sizeof(u32);
|
|
msg_size +=
|
|
strnlen(tp_desc[i].arg_types, STRLEN_MAX) +
|
|
sizeof(char) + sizeof(u32);
|
|
msg_size +=
|
|
strnlen(tp_desc[i].arg_names, STRLEN_MAX) +
|
|
sizeof(char) + sizeof(u32);
|
|
}
|
|
|
|
KBASE_DEBUG_ASSERT(PACKET_SIZE - PACKET_HEADER_SIZE >= msg_size);
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(stream_type, msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &tv, sizeof(tv));
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &ps, sizeof(ps));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &tp_count, sizeof(tp_count));
|
|
|
|
for (i = 0; i < tp_count; i++) {
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos,
|
|
&tp_desc[i].id, sizeof(tp_desc[i].id));
|
|
pos = kbasep_tlstream_write_string(
|
|
buffer, pos,
|
|
tp_desc[i].id_str, msg_size - pos);
|
|
pos = kbasep_tlstream_write_string(
|
|
buffer, pos,
|
|
tp_desc[i].name, msg_size - pos);
|
|
pos = kbasep_tlstream_write_string(
|
|
buffer, pos,
|
|
tp_desc[i].arg_types, msg_size - pos);
|
|
pos = kbasep_tlstream_write_string(
|
|
buffer, pos,
|
|
tp_desc[i].arg_names, msg_size - pos);
|
|
}
|
|
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(stream_type, flags);
|
|
|
|
/* We don't expect any more data to be read in this stream.
|
|
* As header stream must be read before its associated body stream,
|
|
* make this packet visible to the user straightaway. */
|
|
kbasep_tlstream_flush_stream(stream_type);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int kbase_tlstream_init(void)
|
|
{
|
|
enum tl_stream_type i;
|
|
|
|
/* Prepare stream structures. */
|
|
for (i = 0; i < TL_STREAM_TYPE_COUNT; i++) {
|
|
tl_stream[i] = kmalloc(sizeof(**tl_stream), GFP_KERNEL);
|
|
if (!tl_stream[i])
|
|
break;
|
|
kbasep_timeline_stream_init(tl_stream[i], i);
|
|
}
|
|
if (TL_STREAM_TYPE_COUNT > i) {
|
|
for (; i > 0; i--) {
|
|
kbasep_timeline_stream_term(tl_stream[i - 1]);
|
|
kfree(tl_stream[i - 1]);
|
|
}
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Initialize autoflush timer. */
|
|
atomic_set(&autoflush_timer_active, 0);
|
|
timer_setup(&autoflush_timer,
|
|
kbasep_tlstream_autoflush_timer_callback,
|
|
0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void kbase_tlstream_term(void)
|
|
{
|
|
enum tl_stream_type i;
|
|
|
|
for (i = 0; i < TL_STREAM_TYPE_COUNT; i++) {
|
|
kbasep_timeline_stream_term(tl_stream[i]);
|
|
kfree(tl_stream[i]);
|
|
}
|
|
}
|
|
|
|
static void kbase_create_timeline_objects(struct kbase_context *kctx)
|
|
{
|
|
struct kbase_device *kbdev = kctx->kbdev;
|
|
unsigned int lpu_id;
|
|
unsigned int as_nr;
|
|
struct kbasep_kctx_list_element *element;
|
|
|
|
/* Create LPU objects. */
|
|
for (lpu_id = 0; lpu_id < kbdev->gpu_props.num_job_slots; lpu_id++) {
|
|
u32 *lpu =
|
|
&kbdev->gpu_props.props.raw_props.js_features[lpu_id];
|
|
KBASE_TLSTREAM_TL_SUMMARY_NEW_LPU(lpu, lpu_id, *lpu);
|
|
}
|
|
|
|
/* Create Address Space objects. */
|
|
for (as_nr = 0; as_nr < kbdev->nr_hw_address_spaces; as_nr++)
|
|
KBASE_TLSTREAM_TL_SUMMARY_NEW_AS(&kbdev->as[as_nr], as_nr);
|
|
|
|
/* Create GPU object and make it retain all LPUs and address spaces. */
|
|
KBASE_TLSTREAM_TL_SUMMARY_NEW_GPU(
|
|
kbdev,
|
|
kbdev->gpu_props.props.raw_props.gpu_id,
|
|
kbdev->gpu_props.num_cores);
|
|
|
|
for (lpu_id = 0; lpu_id < kbdev->gpu_props.num_job_slots; lpu_id++) {
|
|
void *lpu =
|
|
&kbdev->gpu_props.props.raw_props.js_features[lpu_id];
|
|
KBASE_TLSTREAM_TL_SUMMARY_LIFELINK_LPU_GPU(lpu, kbdev);
|
|
}
|
|
for (as_nr = 0; as_nr < kbdev->nr_hw_address_spaces; as_nr++)
|
|
KBASE_TLSTREAM_TL_SUMMARY_LIFELINK_AS_GPU(
|
|
&kbdev->as[as_nr],
|
|
kbdev);
|
|
|
|
/* Create object for each known context. */
|
|
mutex_lock(&kbdev->kctx_list_lock);
|
|
list_for_each_entry(element, &kbdev->kctx_list, link) {
|
|
KBASE_TLSTREAM_TL_SUMMARY_NEW_CTX(
|
|
element->kctx,
|
|
(u32)(element->kctx->id),
|
|
(u32)(element->kctx->tgid));
|
|
}
|
|
/* Before releasing the lock, reset body stream buffers.
|
|
* This will prevent context creation message to be directed to both
|
|
* summary and body stream.
|
|
*/
|
|
kbase_tlstream_reset_body_streams();
|
|
mutex_unlock(&kbdev->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_tlstream_flush_streams();
|
|
}
|
|
|
|
int kbase_tlstream_acquire(struct kbase_context *kctx, u32 flags)
|
|
{
|
|
int ret;
|
|
u32 tlstream_enabled = TLSTREAM_ENABLED | flags;
|
|
|
|
if (0 == atomic_cmpxchg(&kbase_tlstream_enabled, 0, tlstream_enabled)) {
|
|
int rcode;
|
|
|
|
ret = anon_inode_getfd(
|
|
"[mali_tlstream]",
|
|
&kbasep_tlstream_fops,
|
|
kctx,
|
|
O_RDONLY | O_CLOEXEC);
|
|
if (ret < 0) {
|
|
atomic_set(&kbase_tlstream_enabled, 0);
|
|
return ret;
|
|
}
|
|
|
|
/* Reset and initialize header streams. */
|
|
kbasep_timeline_stream_reset(
|
|
tl_stream[TL_STREAM_TYPE_OBJ_HEADER]);
|
|
kbasep_timeline_stream_reset(
|
|
tl_stream[TL_STREAM_TYPE_OBJ_SUMMARY]);
|
|
kbasep_timeline_stream_reset(
|
|
tl_stream[TL_STREAM_TYPE_AUX_HEADER]);
|
|
kbasep_tlstream_timeline_header(
|
|
TL_STREAM_TYPE_OBJ_HEADER,
|
|
tp_desc_obj,
|
|
ARRAY_SIZE(tp_desc_obj));
|
|
kbasep_tlstream_timeline_header(
|
|
TL_STREAM_TYPE_AUX_HEADER,
|
|
tp_desc_aux,
|
|
ARRAY_SIZE(tp_desc_aux));
|
|
|
|
/* Start autoflush timer. */
|
|
atomic_set(&autoflush_timer_active, 1);
|
|
rcode = mod_timer(
|
|
&autoflush_timer,
|
|
jiffies + msecs_to_jiffies(AUTOFLUSH_INTERVAL));
|
|
CSTD_UNUSED(rcode);
|
|
|
|
/* If job dumping is enabled, readjust the software event's
|
|
* timeout as the default value of 3 seconds is often
|
|
* insufficient. */
|
|
if (flags & BASE_TLSTREAM_JOB_DUMPING_ENABLED) {
|
|
dev_info(kctx->kbdev->dev,
|
|
"Job dumping is enabled, readjusting the software event's timeout\n");
|
|
atomic_set(&kctx->kbdev->js_data.soft_job_timeout_ms,
|
|
1800000);
|
|
}
|
|
|
|
/* Summary stream was cleared during acquire.
|
|
* Create static timeline objects that will be
|
|
* read by client.
|
|
*/
|
|
kbase_create_timeline_objects(kctx);
|
|
|
|
} else {
|
|
ret = -EBUSY;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void kbase_tlstream_flush_streams(void)
|
|
{
|
|
enum tl_stream_type stype;
|
|
|
|
for (stype = 0; stype < TL_STREAM_TYPE_COUNT; stype++)
|
|
kbasep_tlstream_flush_stream(stype);
|
|
}
|
|
|
|
void kbase_tlstream_reset_body_streams(void)
|
|
{
|
|
kbasep_timeline_stream_reset(
|
|
tl_stream[TL_STREAM_TYPE_OBJ]);
|
|
kbasep_timeline_stream_reset(
|
|
tl_stream[TL_STREAM_TYPE_AUX]);
|
|
}
|
|
|
|
#if MALI_UNIT_TEST
|
|
void kbase_tlstream_stats(u32 *bytes_collected, u32 *bytes_generated)
|
|
{
|
|
KBASE_DEBUG_ASSERT(bytes_collected);
|
|
KBASE_DEBUG_ASSERT(bytes_generated);
|
|
*bytes_collected = atomic_read(&tlstream_bytes_collected);
|
|
*bytes_generated = atomic_read(&tlstream_bytes_generated);
|
|
}
|
|
#endif /* MALI_UNIT_TEST */
|
|
|
|
/*****************************************************************************/
|
|
|
|
void __kbase_tlstream_tl_summary_new_ctx(void *context, u32 nr, u32 tgid)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NEW_CTX;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(context) + sizeof(nr) +
|
|
sizeof(tgid);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ_SUMMARY,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &context, sizeof(context));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &nr, sizeof(nr));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &tgid, sizeof(tgid));
|
|
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_summary_new_gpu(void *gpu, u32 id, u32 core_count)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NEW_GPU;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(gpu) + sizeof(id) +
|
|
sizeof(core_count);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ_SUMMARY,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &gpu, sizeof(gpu));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &id, sizeof(id));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &core_count, sizeof(core_count));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_summary_new_lpu(void *lpu, u32 nr, u32 fn)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NEW_LPU;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(lpu) + sizeof(nr) +
|
|
sizeof(fn);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ_SUMMARY,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &lpu, sizeof(lpu));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &nr, sizeof(nr));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &fn, sizeof(fn));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_summary_lifelink_lpu_gpu(void *lpu, void *gpu)
|
|
{
|
|
const u32 msg_id = KBASE_TL_LIFELINK_LPU_GPU;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(lpu) + sizeof(gpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ_SUMMARY,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &lpu, sizeof(lpu));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &gpu, sizeof(gpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_summary_new_as(void *as, u32 nr)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NEW_AS;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(as) + sizeof(nr);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ_SUMMARY,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &as, sizeof(as));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &nr, sizeof(nr));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_summary_lifelink_as_gpu(void *as, void *gpu)
|
|
{
|
|
const u32 msg_id = KBASE_TL_LIFELINK_AS_GPU;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(as) + sizeof(gpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ_SUMMARY,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &as, sizeof(as));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &gpu, sizeof(gpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void __kbase_tlstream_tl_new_ctx(void *context, u32 nr, u32 tgid)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NEW_CTX;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(context) + sizeof(nr) +
|
|
sizeof(tgid);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &context, sizeof(context));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &nr, sizeof(nr));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &tgid, sizeof(tgid));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_new_atom(void *atom, u32 nr)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NEW_ATOM;
|
|
const size_t msg_size = sizeof(msg_id) + sizeof(u64) + sizeof(atom) +
|
|
sizeof(nr);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &nr, sizeof(nr));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_del_ctx(void *context)
|
|
{
|
|
const u32 msg_id = KBASE_TL_DEL_CTX;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(context);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &context, sizeof(context));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_del_atom(void *atom)
|
|
{
|
|
const u32 msg_id = KBASE_TL_DEL_ATOM;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_ret_ctx_lpu(void *context, void *lpu)
|
|
{
|
|
const u32 msg_id = KBASE_TL_RET_CTX_LPU;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(context) + sizeof(lpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &context, sizeof(context));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &lpu, sizeof(lpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_ret_atom_ctx(void *atom, void *context)
|
|
{
|
|
const u32 msg_id = KBASE_TL_RET_ATOM_CTX;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(context);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &context, sizeof(context));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_ret_atom_lpu(
|
|
void *atom, void *lpu, const char *attrib_match_list)
|
|
{
|
|
const u32 msg_id = KBASE_TL_RET_ATOM_LPU;
|
|
const size_t msg_s0 = sizeof(u32) + sizeof(char) +
|
|
strnlen(attrib_match_list, STRLEN_MAX);
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) +
|
|
sizeof(atom) + sizeof(lpu) + msg_s0;
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &lpu, sizeof(lpu));
|
|
pos = kbasep_tlstream_write_string(
|
|
buffer, pos, attrib_match_list, msg_s0);
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_nret_ctx_lpu(void *context, void *lpu)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NRET_CTX_LPU;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(context) + sizeof(lpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &context, sizeof(context));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &lpu, sizeof(lpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_nret_atom_ctx(void *atom, void *context)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NRET_ATOM_CTX;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(context);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &context, sizeof(context));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_dep_atom_atom(void *atom1, void *atom2)
|
|
{
|
|
const u32 msg_id = KBASE_TL_DEP_ATOM_ATOM;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom1) + sizeof(atom2);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom1, sizeof(atom1));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom2, sizeof(atom2));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_ndep_atom_atom(void *atom1, void *atom2)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NDEP_ATOM_ATOM;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom1) + sizeof(atom2);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom1, sizeof(atom1));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom2, sizeof(atom2));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_rdep_atom_atom(void *atom1, void *atom2)
|
|
{
|
|
const u32 msg_id = KBASE_TL_RDEP_ATOM_ATOM;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom1) + sizeof(atom2);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom1, sizeof(atom1));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom2, sizeof(atom2));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_nret_atom_lpu(void *atom, void *lpu)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NRET_ATOM_LPU;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(lpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &lpu, sizeof(lpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_ret_as_ctx(void *as, void *ctx)
|
|
{
|
|
const u32 msg_id = KBASE_TL_RET_AS_CTX;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(as) + sizeof(ctx);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &as, sizeof(as));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &ctx, sizeof(ctx));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_nret_as_ctx(void *as, void *ctx)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NRET_AS_CTX;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(as) + sizeof(ctx);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &as, sizeof(as));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &ctx, sizeof(ctx));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_ret_atom_as(void *atom, void *as)
|
|
{
|
|
const u32 msg_id = KBASE_TL_RET_ATOM_AS;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(as);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &as, sizeof(as));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_nret_atom_as(void *atom, void *as)
|
|
{
|
|
const u32 msg_id = KBASE_TL_NRET_ATOM_AS;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(as);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &as, sizeof(as));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_attrib_atom_config(
|
|
void *atom, u64 jd, u64 affinity, u32 config)
|
|
{
|
|
const u32 msg_id = KBASE_TL_ATTRIB_ATOM_CONFIG;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom) +
|
|
sizeof(jd) + sizeof(affinity) + sizeof(config);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &jd, sizeof(jd));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &affinity, sizeof(affinity));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &config, sizeof(config));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_attrib_atom_priority(void *atom, u32 prio)
|
|
{
|
|
const u32 msg_id = KBASE_TL_ATTRIB_ATOM_PRIORITY;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(prio);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &prio, sizeof(prio));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_attrib_atom_state(void *atom, u32 state)
|
|
{
|
|
const u32 msg_id = KBASE_TL_ATTRIB_ATOM_STATE;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(state);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &state, sizeof(state));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_attrib_atom_priority_change(void *atom)
|
|
{
|
|
const u32 msg_id = KBASE_TL_ATTRIB_ATOM_PRIORITY_CHANGE;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_attrib_atom_jit(
|
|
void *atom, u64 edit_addr, u64 new_addr)
|
|
{
|
|
const u32 msg_id = KBASE_TL_ATTRIB_ATOM_JIT;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom)
|
|
+ sizeof(edit_addr) + sizeof(new_addr);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &edit_addr, sizeof(edit_addr));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &new_addr, sizeof(new_addr));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_attrib_as_config(
|
|
void *as, u64 transtab, u64 memattr, u64 transcfg)
|
|
{
|
|
const u32 msg_id = KBASE_TL_ATTRIB_AS_CONFIG;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(as) +
|
|
sizeof(transtab) + sizeof(memattr) + sizeof(transcfg);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &as, sizeof(as));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &transtab, sizeof(transtab));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &memattr, sizeof(memattr));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &transcfg, sizeof(transcfg));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_event_lpu_softstop(void *lpu)
|
|
{
|
|
const u32 msg_id = KBASE_TL_EVENT_LPU_SOFTSTOP;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(lpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &lpu, sizeof(lpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_event_atom_softstop_ex(void *atom)
|
|
{
|
|
const u32 msg_id = KBASE_TL_EVENT_ATOM_SOFTSTOP_EX;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_tl_event_atom_softstop_issue(void *atom)
|
|
{
|
|
const u32 msg_id = KBASE_TL_EVENT_ATOM_SOFTSTOP_ISSUE;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(atom);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &atom, sizeof(atom));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_jd_gpu_soft_reset(void *gpu)
|
|
{
|
|
const u32 msg_id = KBASE_JD_GPU_SOFT_RESET;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(gpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_OBJ,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &gpu, sizeof(gpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void __kbase_tlstream_aux_pm_state(u32 core_type, u64 state)
|
|
{
|
|
const u32 msg_id = KBASE_AUX_PM_STATE;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(core_type) +
|
|
sizeof(state);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_AUX,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &core_type, sizeof(core_type));
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &state, sizeof(state));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_aux_pagefault(u32 ctx_nr, u64 page_count_change)
|
|
{
|
|
const u32 msg_id = KBASE_AUX_PAGEFAULT;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(ctx_nr) +
|
|
sizeof(page_count_change);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_AUX, msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &ctx_nr, sizeof(ctx_nr));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos,
|
|
&page_count_change, sizeof(page_count_change));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_aux_pagesalloc(u32 ctx_nr, u64 page_count)
|
|
{
|
|
const u32 msg_id = KBASE_AUX_PAGESALLOC;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(ctx_nr) +
|
|
sizeof(page_count);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_AUX, msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &ctx_nr, sizeof(ctx_nr));
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &page_count, sizeof(page_count));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_aux_devfreq_target(u64 target_freq)
|
|
{
|
|
const u32 msg_id = KBASE_AUX_DEVFREQ_TARGET;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(target_freq);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_AUX, msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &target_freq, sizeof(target_freq));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_aux_protected_enter_start(void *gpu)
|
|
{
|
|
const u32 msg_id = KBASE_AUX_PROTECTED_ENTER_START;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(gpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_AUX,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &gpu, sizeof(gpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
|
|
}
|
|
void __kbase_tlstream_aux_protected_enter_end(void *gpu)
|
|
{
|
|
const u32 msg_id = KBASE_AUX_PROTECTED_ENTER_END;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(gpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_AUX,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &gpu, sizeof(gpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
|
|
}
|
|
|
|
void __kbase_tlstream_aux_protected_leave_start(void *gpu)
|
|
{
|
|
const u32 msg_id = KBASE_AUX_PROTECTED_LEAVE_START;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(gpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_AUX,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &gpu, sizeof(gpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
|
|
}
|
|
void __kbase_tlstream_aux_protected_leave_end(void *gpu)
|
|
{
|
|
const u32 msg_id = KBASE_AUX_PROTECTED_LEAVE_END;
|
|
const size_t msg_size =
|
|
sizeof(msg_id) + sizeof(u64) + sizeof(gpu);
|
|
unsigned long flags;
|
|
char *buffer;
|
|
size_t pos = 0;
|
|
|
|
buffer = kbasep_tlstream_msgbuf_acquire(
|
|
TL_STREAM_TYPE_AUX,
|
|
msg_size, &flags);
|
|
KBASE_DEBUG_ASSERT(buffer);
|
|
|
|
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
|
|
pos = kbasep_tlstream_write_timestamp(buffer, pos);
|
|
pos = kbasep_tlstream_write_bytes(
|
|
buffer, pos, &gpu, sizeof(gpu));
|
|
KBASE_DEBUG_ASSERT(msg_size == pos);
|
|
|
|
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
|
|
}
|