blob: 10e38897514b706fb7ac96e02af9b013ac9c31b1 [file] [log] [blame]
/*
*
* (C) COPYRIGHT 2015-2018 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.
*
* 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.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#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_ATTRIB_ATOM_CONFIG,
KBASE_TL_ATTRIB_ATOM_PRIORITY,
KBASE_TL_ATTRIB_ATOM_STATE,
KBASE_TL_ATTRIB_ATOM_PRIORITIZED,
KBASE_TL_ATTRIB_ATOM_JIT,
KBASE_TL_ATTRIB_ATOM_JITALLOCINFO,
KBASE_TL_ATTRIB_ATOM_JITFREEINFO,
KBASE_TL_ATTRIB_AS_CONFIG,
KBASE_TL_EVENT_LPU_SOFTSTOP,
KBASE_TL_EVENT_ATOM_SOFTSTOP_EX,
KBASE_TL_EVENT_ATOM_SOFTSTOP_ISSUE,
KBASE_TL_EVENT_ATOM_SOFTJOB_START,
KBASE_TL_EVENT_ATOM_SOFTJOB_END,
/* 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,
KBASE_AUX_JIT_STATS,
};
/*****************************************************************************/
/**
* 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_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_PRIORITIZED,
__stringify(KBASE_TL_ATTRIB_ATOM_PRIORITIZED),
"atom caused priority change",
"@p",
"atom"
},
{
KBASE_TL_ATTRIB_ATOM_JIT,
__stringify(KBASE_TL_ATTRIB_ATOM_JIT),
"jit done for atom",
"@pLLL",
"atom,edit_addr,new_addr,va_pages"
},
{
KBASE_TL_ATTRIB_ATOM_JITALLOCINFO,
__stringify(KBASE_TL_ATTRIB_ATOM_JITALLOCINFO),
"Information about JIT allocations",
"@pLLLIIIII",
"atom,va_pgs,com_pgs,extent,j_id,bin_id,max_allocs,flags,usg_id"
},
{
KBASE_TL_ATTRIB_ATOM_JITFREEINFO,
__stringify(KBASE_TL_ATTRIB_ATOM_JITFREEINFO),
"Information about JIT frees",
"@pI",
"atom,j_id"
},
{
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_TL_EVENT_ATOM_SOFTJOB_START,
__stringify(KBASE_TL_EVENT_ATOM_SOFTJOB_START),
"atom soft job has started",
"@p",
"atom"
},
{
KBASE_TL_EVENT_ATOM_SOFTJOB_END,
__stringify(KBASE_TL_EVENT_ATOM_SOFTJOB_END),
"atom soft job has completed",
"@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"
},
{
KBASE_AUX_JIT_STATS,
__stringify(KBASE_AUX_JIT_STATS),
"per-bin JIT statistics",
"@IIIIII",
"ctx_nr,bid,max_allocs,allocs,va_pages,ph_pages"
}
};
#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 timespec ts;
u64 timestamp;
getrawmonotonic(&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,
&timestamp, 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 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();
atomic_inc(&stream->wbi);
/* Inform user that packets are ready for reading. */
wake_up_interruptible(&tl_event_queue);
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
* @timer: 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 *timer)
{
enum tl_stream_type stype;
int rcode;
CSTD_UNUSED(timer);
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 wb_idx_raw;
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 distance between read buffer index and write
* buffer index became more than PACKET_COUNT, then overflow
* happened and we need to ignore the last portion of bytes
* that we have just sent to user.
*/
smp_rmb();
wb_idx_raw = atomic_read(&tl_stream[stype]->wbi);
if (wb_idx_raw - rb_idx_raw < PACKET_COUNT) {
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 */
} else {
const unsigned int new_rb_idx_raw =
wb_idx_raw - PACKET_COUNT + 1;
/* Adjust read buffer index to the next valid buffer */
atomic_set(&tl_stream[stype]->rbi, new_rb_idx_raw);
}
}
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);
kbase_timer_setup(&autoflush_timer,
kbasep_tlstream_autoflush_timer_callback);
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,
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_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_prioritized(void *atom)
{
const u32 msg_id = KBASE_TL_ATTRIB_ATOM_PRIORITIZED;
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, u64 va_pages)
{
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) + sizeof(va_pages);
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));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &va_pages, sizeof(va_pages));
KBASE_DEBUG_ASSERT(msg_size == pos);
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
}
void __kbase_tlstream_tl_attrib_atom_jitallocinfo(
void *atom, u64 va_pages, u64 commit_pages, u64 extent,
u32 jit_id, u32 bin_id, u32 max_allocations, u32 jit_flags,
u32 usage_id)
{
const u32 msg_id = KBASE_TL_ATTRIB_ATOM_JITALLOCINFO;
const size_t msg_size =
sizeof(msg_id) + sizeof(u64) + sizeof(atom) +
sizeof(va_pages) + sizeof(commit_pages) +
sizeof(extent) + sizeof(jit_id) +
sizeof(bin_id) + sizeof(max_allocations) +
sizeof(jit_flags) + sizeof(usage_id);
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, &va_pages, sizeof(va_pages));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &commit_pages, sizeof(commit_pages));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &extent, sizeof(extent));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &jit_id, sizeof(jit_id));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &bin_id, sizeof(bin_id));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &max_allocations,
sizeof(max_allocations));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &jit_flags, sizeof(jit_flags));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &usage_id, sizeof(usage_id));
KBASE_DEBUG_ASSERT(msg_size == pos);
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
}
void __kbase_tlstream_tl_attrib_atom_jitfreeinfo(void *atom, u32 jit_id)
{
const u32 msg_id = KBASE_TL_ATTRIB_ATOM_JITFREEINFO;
const size_t msg_size =
sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(jit_id);
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, &jit_id, sizeof(jit_id));
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_tl_event_atom_softjob_start(void *atom)
{
const u32 msg_id = KBASE_TL_EVENT_ATOM_SOFTJOB_START;
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_softjob_end(void *atom)
{
const u32 msg_id = KBASE_TL_EVENT_ATOM_SOFTJOB_END;
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);
}
void __kbase_tlstream_aux_jit_stats(u32 ctx_nr, u32 bid,
u32 max_allocs, u32 allocs,
u32 va_pages, u32 ph_pages)
{
const u32 msg_id = KBASE_AUX_JIT_STATS;
const size_t msg_size = sizeof(msg_id) + sizeof(u64) +
sizeof(ctx_nr) + sizeof(bid) +
sizeof(max_allocs) + sizeof(allocs) +
sizeof(va_pages) + sizeof(ph_pages);
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, &bid, sizeof(bid));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &max_allocs, sizeof(max_allocs));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &allocs, sizeof(allocs));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &va_pages, sizeof(va_pages));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &ph_pages, sizeof(ph_pages));
KBASE_DEBUG_ASSERT(msg_size == pos);
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags);
}