xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/bifrost/tl/mali_kbase_tlstream.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3  *
4  * (C) COPYRIGHT 2015-2021 ARM Limited. All rights reserved.
5  *
6  * This program is free software and is provided to you under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation, and any use by you of this program is subject to the terms
9  * of such GNU license.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you can access it online at
18  * http://www.gnu.org/licenses/gpl-2.0.html.
19  *
20  */
21 
22 #include "mali_kbase_tlstream.h"
23 #include "mali_kbase_tl_serialize.h"
24 #include "mali_kbase_mipe_proto.h"
25 
26 /**
27  * kbasep_packet_header_setup - setup the packet header
28  * @buffer:     pointer to the buffer
29  * @pkt_family: packet's family
30  * @pkt_type:   packet's type
31  * @pkt_class:  packet's class
32  * @stream_id:  stream id
33  * @numbered:   non-zero if this stream is numbered
34  *
35  * Function sets up immutable part of packet header in the given buffer.
36  */
kbasep_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)37 static void kbasep_packet_header_setup(
38 	char                  *buffer,
39 	enum tl_packet_family pkt_family,
40 	enum tl_packet_class  pkt_class,
41 	enum tl_packet_type   pkt_type,
42 	unsigned int          stream_id,
43 	int                   numbered)
44 {
45 	u32 words[2] = {
46 		MIPE_PACKET_HEADER_W0(pkt_family, pkt_class, pkt_type, stream_id),
47 		MIPE_PACKET_HEADER_W1(0, !!numbered),
48 	};
49 	memcpy(buffer, words, sizeof(words));
50 }
51 
52 /**
53  * kbasep_packet_header_update - update the packet header
54  * @buffer:    pointer to the buffer
55  * @data_size: amount of data carried in this packet
56  * @numbered:   non-zero if the stream is numbered
57  *
58  * Function updates mutable part of packet header in the given buffer.
59  * Note that value of data_size must not include size of the header.
60  */
kbasep_packet_header_update(char * buffer,size_t data_size,int numbered)61 static void kbasep_packet_header_update(
62 		char  *buffer,
63 		size_t data_size,
64 		int    numbered)
65 {
66 	u32 word1 = MIPE_PACKET_HEADER_W1((u32)data_size, !!numbered);
67 
68 	KBASE_DEBUG_ASSERT(buffer);
69 
70 	/* we copy the contents of word1 to its respective position in the buffer */
71 	memcpy(&buffer[sizeof(u32)], &word1, sizeof(word1));
72 }
73 
74 /**
75  * kbasep_packet_number_update - update the packet number
76  * @buffer:  pointer to the buffer
77  * @counter: value of packet counter for this packet's stream
78  *
79  * Function updates packet number embedded within the packet placed in the
80  * given buffer.
81  */
kbasep_packet_number_update(char * buffer,u32 counter)82 static void kbasep_packet_number_update(char *buffer, u32 counter)
83 {
84 	KBASE_DEBUG_ASSERT(buffer);
85 
86 	memcpy(&buffer[PACKET_HEADER_SIZE], &counter, sizeof(counter));
87 }
88 
kbase_tlstream_reset(struct kbase_tlstream * stream)89 void kbase_tlstream_reset(struct kbase_tlstream *stream)
90 {
91 	unsigned int i;
92 
93 	for (i = 0; i < PACKET_COUNT; i++) {
94 		if (stream->numbered)
95 			atomic_set(
96 				&stream->buffer[i].size,
97 				PACKET_HEADER_SIZE +
98 				PACKET_NUMBER_SIZE);
99 		else
100 			atomic_set(&stream->buffer[i].size, PACKET_HEADER_SIZE);
101 	}
102 
103 	atomic_set(&stream->wbi, 0);
104 	atomic_set(&stream->rbi, 0);
105 }
106 
107 /* Configuration of timeline streams generated by kernel. */
108 static const struct {
109 	enum tl_packet_family pkt_family;
110 	enum tl_packet_class  pkt_class;
111 	enum tl_packet_type   pkt_type;
112 	enum tl_stream_id     stream_id;
113 } tl_stream_cfg[TL_STREAM_TYPE_COUNT] = {
114 	{
115 		TL_PACKET_FAMILY_TL,
116 		TL_PACKET_CLASS_OBJ,
117 		TL_PACKET_TYPE_SUMMARY,
118 		TL_STREAM_ID_KERNEL,
119 	},
120 	{
121 		TL_PACKET_FAMILY_TL,
122 		TL_PACKET_CLASS_OBJ,
123 		TL_PACKET_TYPE_BODY,
124 		TL_STREAM_ID_KERNEL,
125 	},
126 	{
127 		TL_PACKET_FAMILY_TL,
128 		TL_PACKET_CLASS_AUX,
129 		TL_PACKET_TYPE_BODY,
130 		TL_STREAM_ID_KERNEL,
131 	},
132 #if MALI_USE_CSF
133 	{
134 		TL_PACKET_FAMILY_TL,
135 		TL_PACKET_CLASS_OBJ,
136 		TL_PACKET_TYPE_BODY,
137 		TL_STREAM_ID_CSFFW,
138 	},
139 #endif
140 };
141 
kbase_tlstream_init(struct kbase_tlstream * stream,enum tl_stream_type stream_type,wait_queue_head_t * ready_read)142 void kbase_tlstream_init(
143 	struct kbase_tlstream *stream,
144 	enum tl_stream_type    stream_type,
145 	wait_queue_head_t     *ready_read)
146 {
147 	unsigned int i;
148 
149 	KBASE_DEBUG_ASSERT(stream);
150 	KBASE_DEBUG_ASSERT(stream_type < TL_STREAM_TYPE_COUNT);
151 
152 	spin_lock_init(&stream->lock);
153 
154 	/* All packets carrying tracepoints shall be numbered. */
155 	if (tl_stream_cfg[stream_type].pkt_type == TL_PACKET_TYPE_BODY)
156 		stream->numbered = 1;
157 	else
158 		stream->numbered = 0;
159 
160 	for (i = 0; i < PACKET_COUNT; i++)
161 		kbasep_packet_header_setup(
162 			stream->buffer[i].data,
163 			tl_stream_cfg[stream_type].pkt_family,
164 			tl_stream_cfg[stream_type].pkt_class,
165 			tl_stream_cfg[stream_type].pkt_type,
166 			tl_stream_cfg[stream_type].stream_id,
167 			stream->numbered);
168 
169 #if MALI_UNIT_TEST
170 	atomic_set(&stream->bytes_generated, 0);
171 #endif
172 	stream->ready_read = ready_read;
173 
174 	kbase_tlstream_reset(stream);
175 }
176 
kbase_tlstream_term(struct kbase_tlstream * stream)177 void kbase_tlstream_term(struct kbase_tlstream *stream)
178 {
179 	KBASE_DEBUG_ASSERT(stream);
180 }
181 
182 /**
183  * kbasep_tlstream_msgbuf_submit - submit packet to user space
184  * @stream:     Pointer to the stream structure
185  * @wb_idx_raw: Write buffer index
186  * @wb_size:    Length of data stored in the current buffer
187  *
188  * Updates currently written buffer with the packet header.
189  * Then write index is incremented and the buffer is handed to user space.
190  * Parameters of the new buffer are returned using provided arguments.
191  *
192  * Return: length of data in the new buffer
193  *
194  * Warning: the user must update the stream structure with returned value.
195  */
kbasep_tlstream_msgbuf_submit(struct kbase_tlstream * stream,unsigned int wb_idx_raw,unsigned int wb_size)196 static size_t kbasep_tlstream_msgbuf_submit(
197 		struct kbase_tlstream *stream,
198 		unsigned int      wb_idx_raw,
199 		unsigned int      wb_size)
200 {
201 	unsigned int wb_idx = wb_idx_raw % PACKET_COUNT;
202 
203 	/* Set stream as flushed. */
204 	atomic_set(&stream->autoflush_counter, -1);
205 
206 	kbasep_packet_header_update(
207 		stream->buffer[wb_idx].data,
208 		wb_size - PACKET_HEADER_SIZE,
209 		stream->numbered);
210 
211 	if (stream->numbered)
212 		kbasep_packet_number_update(
213 			stream->buffer[wb_idx].data,
214 			wb_idx_raw);
215 
216 	/* Increasing write buffer index will expose this packet to the reader.
217 	 * As stream->lock is not taken on reader side we must make sure memory
218 	 * is updated correctly before this will happen.
219 	 */
220 	smp_wmb();
221 	atomic_inc(&stream->wbi);
222 
223 	/* Inform user that packets are ready for reading. */
224 	wake_up_interruptible(stream->ready_read);
225 
226 	wb_size = PACKET_HEADER_SIZE;
227 	if (stream->numbered)
228 		wb_size += PACKET_NUMBER_SIZE;
229 
230 	return wb_size;
231 }
232 
kbase_tlstream_msgbuf_acquire(struct kbase_tlstream * stream,size_t msg_size,unsigned long * flags)233 char *kbase_tlstream_msgbuf_acquire(
234 	struct kbase_tlstream *stream,
235 	size_t              msg_size,
236 	unsigned long       *flags) __acquires(&stream->lock)
237 {
238 	unsigned int     wb_idx_raw;
239 	unsigned int     wb_idx;
240 	size_t           wb_size;
241 
242 	KBASE_DEBUG_ASSERT(
243 		PACKET_SIZE - PACKET_HEADER_SIZE - PACKET_NUMBER_SIZE >=
244 		msg_size);
245 
246 	spin_lock_irqsave(&stream->lock, *flags);
247 
248 	wb_idx_raw = atomic_read(&stream->wbi);
249 	wb_idx     = wb_idx_raw % PACKET_COUNT;
250 	wb_size    = atomic_read(&stream->buffer[wb_idx].size);
251 
252 	/* Select next buffer if data will not fit into current one. */
253 	if (wb_size + msg_size > PACKET_SIZE) {
254 		wb_size = kbasep_tlstream_msgbuf_submit(
255 				stream, wb_idx_raw, wb_size);
256 		wb_idx  = (wb_idx_raw + 1) % PACKET_COUNT;
257 	}
258 
259 	/* Reserve space in selected buffer. */
260 	atomic_set(&stream->buffer[wb_idx].size, wb_size + msg_size);
261 
262 #if MALI_UNIT_TEST
263 	atomic_add(msg_size, &stream->bytes_generated);
264 #endif /* MALI_UNIT_TEST */
265 
266 	return &stream->buffer[wb_idx].data[wb_size];
267 }
268 
kbase_tlstream_msgbuf_release(struct kbase_tlstream * stream,unsigned long flags)269 void kbase_tlstream_msgbuf_release(
270 	struct kbase_tlstream *stream,
271 	unsigned long       flags) __releases(&stream->lock)
272 {
273 	/* Mark stream as containing unflushed data. */
274 	atomic_set(&stream->autoflush_counter, 0);
275 
276 	spin_unlock_irqrestore(&stream->lock, flags);
277 }
278 
kbase_tlstream_flush_stream(struct kbase_tlstream * stream)279 size_t kbase_tlstream_flush_stream(
280 	struct kbase_tlstream *stream)
281 {
282 	unsigned long    flags;
283 	unsigned int     wb_idx_raw;
284 	unsigned int     wb_idx;
285 	size_t           wb_size;
286 	size_t           min_size = PACKET_HEADER_SIZE;
287 
288 
289 	if (stream->numbered)
290 		min_size += PACKET_NUMBER_SIZE;
291 
292 	spin_lock_irqsave(&stream->lock, flags);
293 
294 	wb_idx_raw = atomic_read(&stream->wbi);
295 	wb_idx     = wb_idx_raw % PACKET_COUNT;
296 	wb_size    = atomic_read(&stream->buffer[wb_idx].size);
297 
298 	if (wb_size > min_size) {
299 		wb_size = kbasep_tlstream_msgbuf_submit(
300 				stream, wb_idx_raw, wb_size);
301 		wb_idx = (wb_idx_raw + 1) % PACKET_COUNT;
302 		atomic_set(&stream->buffer[wb_idx].size, wb_size);
303 	} else {
304 		/* we return that there is no bytes to be read.*/
305 		/* Timeline io fsync will use this info the decide whether
306 		 * fsync should return an error
307 		 */
308 		wb_size = 0;
309 	}
310 
311 	spin_unlock_irqrestore(&stream->lock, flags);
312 	return wb_size;
313 }
314