xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_utils.c (revision e11bdd37745229bf26b557305c07d118c3dbaad7)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2019 Broadcom
3  * All rights reserved.
4  */
5 
6 #include "ulp_utils.h"
7 #include "bnxt_tf_common.h"
8 
9 /*
10  * Initialize the regfile structure for writing
11  *
12  * regfile [in] Ptr to a regfile instance
13  *
14  * returns 0 on error or 1 on success
15  */
16 uint32_t
17 ulp_regfile_init(struct ulp_regfile *regfile)
18 {
19 	/* validate the arguments */
20 	if (!regfile) {
21 		BNXT_TF_DBG(ERR, "invalid argument\n");
22 		return 0; /* failure */
23 	}
24 	memset(regfile, 0, sizeof(struct ulp_regfile));
25 	return 1; /* Success */
26 }
27 
28 /*
29  * Read a value from the regfile
30  *
31  * regfile [in] The regfile instance. Must be initialized prior to being used
32  *
33  * field [in] The field to be read within the regfile.
34  *
35  * data [in/out]
36  *
37  * returns size, zero on failure
38  */
39 uint32_t
40 ulp_regfile_read(struct ulp_regfile *regfile,
41 		 enum bnxt_ulp_regfile_index field,
42 		 uint64_t *data)
43 {
44 	/* validate the arguments */
45 	if (!regfile || field >= BNXT_ULP_REGFILE_INDEX_LAST) {
46 		BNXT_TF_DBG(ERR, "invalid argument\n");
47 		return 0; /* failure */
48 	}
49 
50 	*data = regfile->entry[field].data;
51 	return sizeof(*data);
52 }
53 
54 /*
55  * Write a value to the regfile
56  *
57  * regfile [in] The regfile instance.  Must be initialized prior to being used
58  *
59  * field [in] The field to be written within the regfile.
60  *
61  * data [in] The value is written into this variable.  It is going to be in the
62  * same byte order as it was written.
63  *
64  * size [in] The size in bytes of the value beingritten into this
65  * variable.
66  *
67  * returns 0 on fail
68  */
69 uint32_t
70 ulp_regfile_write(struct ulp_regfile *regfile,
71 		  enum bnxt_ulp_regfile_index field,
72 		  uint64_t data)
73 {
74 	/* validate the arguments */
75 	if (!regfile || field >= BNXT_ULP_REGFILE_INDEX_LAST) {
76 		BNXT_TF_DBG(ERR, "invalid argument\n");
77 		return 0; /* failure */
78 	}
79 
80 	regfile->entry[field].data = data;
81 	return sizeof(data); /* Success */
82 }
83 
84 static void
85 ulp_bs_put_msb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val)
86 {
87 	uint8_t bitoffs = bitpos % 8;
88 	uint16_t index  = bitpos / 8;
89 	uint8_t mask;
90 	uint8_t tmp;
91 	int8_t shift;
92 
93 	tmp = bs[index];
94 	mask = ((uint8_t)-1 >> (8 - bitlen));
95 	shift = 8 - bitoffs - bitlen;
96 	val &= mask;
97 
98 	if (shift >= 0) {
99 		tmp &= ~(mask << shift);
100 		tmp |= val << shift;
101 		bs[index] = tmp;
102 	} else {
103 		tmp &= ~((uint8_t)-1 >> bitoffs);
104 		tmp |= val >> -shift;
105 		bs[index++] = tmp;
106 
107 		tmp = bs[index];
108 		tmp &= ((uint8_t)-1 >> (bitlen - (8 - bitoffs)));
109 		tmp |= val << (8 + shift);
110 		bs[index] = tmp;
111 	}
112 }
113 
114 static void
115 ulp_bs_put_lsb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val)
116 {
117 	uint8_t bitoffs = bitpos % 8;
118 	uint16_t index  = bitpos / 8;
119 	uint8_t mask;
120 	uint8_t tmp;
121 	uint8_t shift;
122 	uint8_t partial;
123 
124 	tmp = bs[index];
125 	shift = bitoffs;
126 
127 	if (bitoffs + bitlen <= 8) {
128 		mask = ((1 << bitlen) - 1) << shift;
129 		tmp &= ~mask;
130 		tmp |= ((val << shift) & mask);
131 		bs[index] = tmp;
132 	} else {
133 		partial = 8 - bitoffs;
134 		mask = ((1 << partial) - 1) << shift;
135 		tmp &= ~mask;
136 		tmp |= ((val << shift) & mask);
137 		bs[index++] = tmp;
138 
139 		val >>= partial;
140 		partial = bitlen - partial;
141 		mask = ((1 << partial) - 1);
142 		tmp = bs[index];
143 		tmp &= ~mask;
144 		tmp |= (val & mask);
145 		bs[index] = tmp;
146 	}
147 }
148 
149 /* Assuming that val is in Big-Endian Format */
150 static uint32_t
151 ulp_bs_push_lsb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
152 {
153 	int i;
154 	int cnt = (len) / 8;
155 	int tlen = len;
156 
157 	if (cnt > 0 && !(len % 8))
158 		cnt -= 1;
159 
160 	for (i = 0; i < cnt; i++) {
161 		ulp_bs_put_lsb(bs, pos, 8, val[cnt - i]);
162 		pos += 8;
163 		tlen -= 8;
164 	}
165 
166 	/* Handle the remainder bits */
167 	if (tlen)
168 		ulp_bs_put_lsb(bs, pos, tlen, val[0]);
169 	return len;
170 }
171 
172 /* Assuming that val is in Big-Endian Format */
173 static uint32_t
174 ulp_bs_push_msb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
175 {
176 	int i;
177 	int cnt = (len + 7) / 8;
178 	int tlen = len;
179 
180 	/* Handle any remainder bits */
181 	int tmp = len % 8;
182 
183 	if (!tmp)
184 		tmp = 8;
185 
186 	ulp_bs_put_msb(bs, pos, tmp, val[0]);
187 
188 	pos += tmp;
189 	tlen -= tmp;
190 
191 	for (i = 1; i < cnt; i++) {
192 		ulp_bs_put_msb(bs, pos, 8, val[i]);
193 		pos += 8;
194 		tlen -= 8;
195 	}
196 
197 	return len;
198 }
199 
200 /*
201  * Initializes the blob structure for creating binary blob
202  *
203  * blob [in] The blob to be initialized
204  *
205  * bitlen [in] The bit length of the blob
206  *
207  * order [in] The byte order for the blob.  Currently only supporting
208  * big endian.  All fields are packed with this order.
209  *
210  * returns 0 on error or 1 on success
211  */
212 uint32_t
213 ulp_blob_init(struct ulp_blob *blob,
214 	      uint16_t bitlen,
215 	      enum bnxt_ulp_byte_order order)
216 {
217 	/* validate the arguments */
218 	if (!blob || bitlen > (8 * sizeof(blob->data))) {
219 		BNXT_TF_DBG(ERR, "invalid argument\n");
220 		return 0; /* failure */
221 	}
222 	blob->bitlen = bitlen;
223 	blob->byte_order = order;
224 	blob->write_idx = 0;
225 	memset(blob->data, 0, sizeof(blob->data));
226 	return 1; /* Success */
227 }
228 
229 /*
230  * Add data to the binary blob at the current offset.
231  *
232  * blob [in] The blob that data is added to.  The blob must
233  * be initialized prior to pushing data.
234  *
235  * data [in] A pointer to bytes to be added to the blob.
236  *
237  * datalen [in] The number of bits to be added to the blob.
238  *
239  * The offset of the data is updated after each push of data.
240  * NULL returned on error.
241  */
242 #define ULP_BLOB_BYTE		8
243 #define ULP_BLOB_BYTE_HEX	0xFF
244 #define BLOB_MASK_CAL(x)	((0xFF << (x)) & 0xFF)
245 uint32_t
246 ulp_blob_push(struct ulp_blob *blob,
247 	      uint8_t *data,
248 	      uint32_t datalen)
249 {
250 	uint32_t rc;
251 
252 	/* validate the arguments */
253 	if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
254 		BNXT_TF_DBG(ERR, "invalid argument\n");
255 		return 0; /* failure */
256 	}
257 
258 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
259 		rc = ulp_bs_push_msb(blob->data,
260 				     blob->write_idx,
261 				     datalen,
262 				     data);
263 	else
264 		rc = ulp_bs_push_lsb(blob->data,
265 				     blob->write_idx,
266 				     datalen,
267 				     data);
268 	if (!rc) {
269 		BNXT_TF_DBG(ERR, "Failed ro write blob\n");
270 		return 0;
271 	}
272 	blob->write_idx += datalen;
273 	return datalen;
274 }
275 
276 /*
277  * Add data to the binary blob at the current offset.
278  *
279  * blob [in] The blob that data is added to.  The blob must
280  * be initialized prior to pushing data.
281  *
282  * data [in] 64-bit value to be added to the blob.
283  *
284  * datalen [in] The number of bits to be added to the blob.
285  *
286  * The offset of the data is updated after each push of data.
287  * NULL returned on error, pointer pushed value otherwise.
288  */
289 uint8_t *
290 ulp_blob_push_64(struct ulp_blob *blob,
291 		 uint64_t *data,
292 		 uint32_t datalen)
293 {
294 	uint8_t *val = (uint8_t *)data;
295 	int rc;
296 
297 	int size = (datalen + 7) / 8;
298 
299 	if (!blob || !data ||
300 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
301 		BNXT_TF_DBG(ERR, "invalid argument\n");
302 		return 0;
303 	}
304 
305 	rc = ulp_blob_push(blob, &val[8 - size], datalen);
306 	if (!rc)
307 		return 0;
308 
309 	return &val[8 - size];
310 }
311 
312 /*
313  * Add encap data to the binary blob at the current offset.
314  *
315  * blob [in] The blob that data is added to.  The blob must
316  * be initialized prior to pushing data.
317  *
318  * data [in] value to be added to the blob.
319  *
320  * datalen [in] The number of bits to be added to the blob.
321  *
322  * The offset of the data is updated after each push of data.
323  * NULL returned on error, pointer pushed value otherwise.
324  */
325 uint32_t
326 ulp_blob_push_encap(struct ulp_blob *blob,
327 		    uint8_t *data,
328 		    uint32_t datalen)
329 {
330 	uint8_t		*val = (uint8_t *)data;
331 	uint32_t	initial_size, write_size = datalen;
332 	uint32_t	size = 0;
333 
334 	if (!blob || !data ||
335 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
336 		BNXT_TF_DBG(ERR, "invalid argument\n");
337 		return 0;
338 	}
339 
340 	initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
341 	    (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
342 	while (write_size > 0) {
343 		if (initial_size && write_size > initial_size) {
344 			size = initial_size;
345 			initial_size = 0;
346 		} else if (initial_size && write_size <= initial_size) {
347 			size = write_size;
348 			initial_size = 0;
349 		} else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) {
350 			size = ULP_BYTE_2_BITS(sizeof(uint64_t));
351 		} else {
352 			size = write_size;
353 		}
354 		if (!ulp_blob_push(blob, val, size)) {
355 			BNXT_TF_DBG(ERR, "push field failed\n");
356 			return 0;
357 		}
358 		val += ULP_BITS_2_BYTE(size);
359 		write_size -= size;
360 	}
361 	return datalen;
362 }
363 
364 /*
365  * Adds pad to an initialized blob at the current offset
366  *
367  * blob [in] The blob that data is added to.  The blob must
368  * be initialized prior to pushing data.
369  *
370  * datalen [in] The number of bits of pad to add
371  *
372  * returns the number of pad bits added, zero on failure
373  */
374 uint32_t
375 ulp_blob_pad_push(struct ulp_blob *blob,
376 		  uint32_t datalen)
377 {
378 	if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
379 		BNXT_TF_DBG(ERR, "Pad too large for blob\n");
380 		return 0;
381 	}
382 
383 	blob->write_idx += datalen;
384 	return datalen;
385 }
386 
387 /*
388  * Get the data portion of the binary blob.
389  *
390  * blob [in] The blob's data to be retrieved. The blob must be
391  * initialized prior to pushing data.
392  *
393  * datalen [out] The number of bits to that are filled.
394  *
395  * returns a byte array of the blob data.  Returns NULL on error.
396  */
397 uint8_t *
398 ulp_blob_data_get(struct ulp_blob *blob,
399 		  uint16_t *datalen)
400 {
401 	/* validate the arguments */
402 	if (!blob) {
403 		BNXT_TF_DBG(ERR, "invalid argument\n");
404 		return NULL; /* failure */
405 	}
406 	*datalen = blob->write_idx;
407 	return blob->data;
408 }
409 
410 /*
411  * Set the encap swap start index of the binary blob.
412  *
413  * blob [in] The blob's data to be retrieved. The blob must be
414  * initialized prior to pushing data.
415  *
416  * returns void.
417  */
418 void
419 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
420 {
421 	/* validate the arguments */
422 	if (!blob) {
423 		BNXT_TF_DBG(ERR, "invalid argument\n");
424 		return; /* failure */
425 	}
426 	blob->encap_swap_idx = blob->write_idx;
427 }
428 
429 /*
430  * Perform the encap buffer swap to 64 bit reversal.
431  *
432  * blob [in] The blob's data to be used for swap.
433  *
434  * returns void.
435  */
436 void
437 ulp_blob_perform_encap_swap(struct ulp_blob *blob)
438 {
439 	uint32_t		i, idx = 0, end_idx = 0;
440 	uint8_t		temp_val_1, temp_val_2;
441 
442 	/* validate the arguments */
443 	if (!blob) {
444 		BNXT_TF_DBG(ERR, "invalid argument\n");
445 		return; /* failure */
446 	}
447 	idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx + 1);
448 	end_idx = ULP_BITS_2_BYTE(blob->write_idx);
449 
450 	while (idx <= end_idx) {
451 		for (i = 0; i < 4; i = i + 2) {
452 			temp_val_1 = blob->data[idx + i];
453 			temp_val_2 = blob->data[idx + i + 1];
454 			blob->data[idx + i] = blob->data[idx + 6 - i];
455 			blob->data[idx + i + 1] = blob->data[idx + 7 - i];
456 			blob->data[idx + 7 - i] = temp_val_2;
457 			blob->data[idx + 6 - i] = temp_val_1;
458 		}
459 		idx += 8;
460 	}
461 }
462 
463 /*
464  * Read data from the operand
465  *
466  * operand [in] A pointer to a 16 Byte operand
467  *
468  * val [in/out] The variable to copy the operand to
469  *
470  * bytes [in] The number of bytes to read into val
471  *
472  * returns number of bits read, zero on error
473  */
474 uint16_t
475 ulp_operand_read(uint8_t *operand,
476 		 uint8_t *val,
477 		 uint16_t bytes)
478 {
479 	/* validate the arguments */
480 	if (!operand || !val) {
481 		BNXT_TF_DBG(ERR, "invalid argument\n");
482 		return 0; /* failure */
483 	}
484 	memcpy(val, operand, bytes);
485 	return bytes;
486 }
487 
488 /*
489  * copy the buffer in the encap format which is 2 bytes.
490  * The MSB of the src is placed at the LSB of dst.
491  *
492  * dst [out] The destination buffer
493  * src [in] The source buffer dst
494  * size[in] size of the buffer.
495  */
496 void
497 ulp_encap_buffer_copy(uint8_t *dst,
498 		      const uint8_t *src,
499 		      uint16_t size)
500 {
501 	uint16_t	idx = 0;
502 
503 	/* copy 2 bytes at a time. Write MSB to LSB */
504 	while ((idx + sizeof(uint16_t)) <= size) {
505 		memcpy(&dst[idx], &src[size - idx - sizeof(uint16_t)],
506 		       sizeof(uint16_t));
507 		idx += sizeof(uint16_t);
508 	}
509 }
510 
511 /*
512  * Check the buffer is empty
513  *
514  * buf [in] The buffer
515  * size [in] The size of the buffer
516  *
517  */
518 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
519 {
520 	return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
521 }
522 
523 /* Function to check if bitmap is zero.Return 1 on success */
524 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
525 {
526 	while (size-- > 0) {
527 		if (*bitmap != 0)
528 			return 0;
529 		bitmap++;
530 	}
531 	return 1;
532 }
533 
534 /* Function to check if bitmap is ones. Return 1 on success */
535 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
536 {
537 	while (size-- > 0) {
538 		if (*bitmap != 0xFF)
539 			return 0;
540 		bitmap++;
541 	}
542 	return 1;
543 }
544 
545 /* Function to check if bitmap is not zero. Return 1 on success */
546 uint32_t ulp_bitmap_notzero(uint8_t *bitmap, int32_t size)
547 {
548 	while (size-- > 0) {
549 		if (*bitmap != 0)
550 			return 1;
551 		bitmap++;
552 	}
553 	return 0;
554 }
555