xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_utils.c (revision db4e81351fb85ff623bd0438d1b5a8fb55fe9fee)
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 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] 32-bit value to be added to the blob.
319  *
320  * datalen [in] The number of bits to be added ot 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 uint8_t *
326 ulp_blob_push_32(struct ulp_blob *blob,
327 		 uint32_t *data,
328 		 uint32_t datalen)
329 {
330 	uint8_t *val = (uint8_t *)data;
331 	uint32_t rc;
332 	uint32_t size = ULP_BITS_2_BYTE(datalen);
333 
334 	if (!data || size > sizeof(uint32_t)) {
335 		BNXT_TF_DBG(ERR, "invalid argument\n");
336 		return 0;
337 	}
338 
339 	rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen);
340 	if (!rc)
341 		return 0;
342 
343 	return &val[sizeof(uint32_t) - size];
344 }
345 
346 /*
347  * Add encap data to the binary blob at the current offset.
348  *
349  * blob [in] The blob that data is added to.  The blob must
350  * be initialized prior to pushing data.
351  *
352  * data [in] value to be added to the blob.
353  *
354  * datalen [in] The number of bits to be added to the blob.
355  *
356  * The offset of the data is updated after each push of data.
357  * NULL returned on error, pointer pushed value otherwise.
358  */
359 uint32_t
360 ulp_blob_push_encap(struct ulp_blob *blob,
361 		    uint8_t *data,
362 		    uint32_t datalen)
363 {
364 	uint8_t		*val = (uint8_t *)data;
365 	uint32_t	initial_size, write_size = datalen;
366 	uint32_t	size = 0;
367 
368 	if (!blob || !data ||
369 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
370 		BNXT_TF_DBG(ERR, "invalid argument\n");
371 		return 0;
372 	}
373 
374 	initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
375 	    (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
376 	while (write_size > 0) {
377 		if (initial_size && write_size > initial_size) {
378 			size = initial_size;
379 			initial_size = 0;
380 		} else if (initial_size && write_size <= initial_size) {
381 			size = write_size;
382 			initial_size = 0;
383 		} else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) {
384 			size = ULP_BYTE_2_BITS(sizeof(uint64_t));
385 		} else {
386 			size = write_size;
387 		}
388 		if (!ulp_blob_push(blob, val, size)) {
389 			BNXT_TF_DBG(ERR, "push field failed\n");
390 			return 0;
391 		}
392 		val += ULP_BITS_2_BYTE(size);
393 		write_size -= size;
394 	}
395 	return datalen;
396 }
397 
398 /*
399  * Adds pad to an initialized blob at the current offset
400  *
401  * blob [in] The blob that data is added to.  The blob must
402  * be initialized prior to pushing data.
403  *
404  * datalen [in] The number of bits of pad to add
405  *
406  * returns the number of pad bits added, -1 on failure
407  */
408 int32_t
409 ulp_blob_pad_push(struct ulp_blob *blob,
410 		  uint32_t datalen)
411 {
412 	if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
413 		BNXT_TF_DBG(ERR, "Pad too large for blob\n");
414 		return 0;
415 	}
416 
417 	blob->write_idx += datalen;
418 	return datalen;
419 }
420 
421 /* Get data from src and put into dst using little-endian format */
422 static void
423 ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
424 {
425 	uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
426 	uint16_t index  = ULP_BITS_2_BYTE_NR(bitpos);
427 	uint8_t mask, partial, shift;
428 
429 	shift = bitoffs;
430 	partial = ULP_BLOB_BYTE - bitoffs;
431 	if (bitoffs + bitlen <= ULP_BLOB_BYTE) {
432 		mask = ((1 << bitlen) - 1) << shift;
433 		*dst = (src[index] & mask) >> shift;
434 	} else {
435 		mask = ((1 << partial) - 1) << shift;
436 		*dst = (src[index] & mask) >> shift;
437 		index++;
438 		partial = bitlen - partial;
439 		mask = ((1 << partial) - 1);
440 		*dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs);
441 	}
442 }
443 
444 /* Assuming that src is in little-Endian Format */
445 static void
446 ulp_bs_pull_lsb(uint8_t *src, uint8_t *dst, uint32_t size,
447 		uint32_t offset, uint32_t len)
448 {
449 	uint32_t idx;
450 	uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
451 
452 	/* iterate bytewise to get data */
453 	for (idx = 0; idx < cnt; idx++) {
454 		ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE,
455 			       &dst[size - 1 - idx]);
456 		offset += ULP_BLOB_BYTE;
457 		len -= ULP_BLOB_BYTE;
458 	}
459 
460 	/* Extract the last reminder data that is not 8 byte boundary */
461 	if (len)
462 		ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]);
463 }
464 
465 /*
466  * Extract data from the binary blob using given offset.
467  *
468  * blob [in] The blob that data is extracted from. The blob must
469  * be initialized prior to pulling data.
470  *
471  * data [in] A pointer to put the data.
472  * data_size [in] size of the data buffer in bytes.
473  *offset [in] - Offset in the blob to extract the data in bits format.
474  * len [in] The number of bits to be pulled from the blob.
475  *
476  * Output: zero on success, -1 on failure
477  */
478 int32_t
479 ulp_blob_pull(struct ulp_blob *blob, uint8_t *data, uint32_t data_size,
480 	      uint16_t offset, uint16_t len)
481 {
482 	/* validate the arguments */
483 	if (!blob || (offset + len) > blob->bitlen ||
484 	    ULP_BYTE_2_BITS(data_size) < len) {
485 		BNXT_TF_DBG(ERR, "invalid argument\n");
486 		return -1; /* failure */
487 	}
488 
489 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) {
490 		BNXT_TF_DBG(ERR, "Big endian pull not implemented\n");
491 		return -1; /* failure */
492 	}
493 	ulp_bs_pull_lsb(blob->data, data, data_size, offset, len);
494 	return 0;
495 }
496 
497 /*
498  * Get the data portion of the binary blob.
499  *
500  * blob [in] The blob's data to be retrieved. The blob must be
501  * initialized prior to pushing data.
502  *
503  * datalen [out] The number of bits to that are filled.
504  *
505  * returns a byte array of the blob data.  Returns NULL on error.
506  */
507 uint8_t *
508 ulp_blob_data_get(struct ulp_blob *blob,
509 		  uint16_t *datalen)
510 {
511 	/* validate the arguments */
512 	if (!blob) {
513 		BNXT_TF_DBG(ERR, "invalid argument\n");
514 		return NULL; /* failure */
515 	}
516 	*datalen = blob->write_idx;
517 	return blob->data;
518 }
519 
520 /*
521  * Set the encap swap start index of the binary blob.
522  *
523  * blob [in] The blob's data to be retrieved. The blob must be
524  * initialized prior to pushing data.
525  *
526  * returns void.
527  */
528 void
529 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
530 {
531 	/* validate the arguments */
532 	if (!blob) {
533 		BNXT_TF_DBG(ERR, "invalid argument\n");
534 		return; /* failure */
535 	}
536 	blob->encap_swap_idx = blob->write_idx;
537 }
538 
539 /*
540  * Perform the encap buffer swap to 64 bit reversal.
541  *
542  * blob [in] The blob's data to be used for swap.
543  *
544  * returns void.
545  */
546 void
547 ulp_blob_perform_encap_swap(struct ulp_blob *blob)
548 {
549 	uint32_t i, idx = 0, end_idx = 0, roundoff;
550 	uint8_t temp_val_1, temp_val_2;
551 
552 	/* validate the arguments */
553 	if (!blob) {
554 		BNXT_TF_DBG(ERR, "invalid argument\n");
555 		return; /* failure */
556 	}
557 	idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx);
558 	end_idx = ULP_BITS_2_BYTE(blob->write_idx);
559 	roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx));
560 	if (roundoff > end_idx) {
561 		blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx);
562 		end_idx = roundoff;
563 	}
564 	while (idx <= end_idx) {
565 		for (i = 0; i < 4; i = i + 2) {
566 			temp_val_1 = blob->data[idx + i];
567 			temp_val_2 = blob->data[idx + i + 1];
568 			blob->data[idx + i] = blob->data[idx + 6 - i];
569 			blob->data[idx + i + 1] = blob->data[idx + 7 - i];
570 			blob->data[idx + 7 - i] = temp_val_2;
571 			blob->data[idx + 6 - i] = temp_val_1;
572 		}
573 		idx += 8;
574 	}
575 }
576 
577 /*
578  * Perform the blob buffer reversal byte wise.
579  * This api makes the first byte the last and
580  * vice-versa.
581  *
582  * blob [in] The blob's data to be used for swap.
583  *
584  * returns void.
585  */
586 void
587 ulp_blob_perform_byte_reverse(struct ulp_blob *blob)
588 {
589 	uint32_t idx = 0, num = 0;
590 	uint8_t xchar;
591 
592 	/* validate the arguments */
593 	if (!blob) {
594 		BNXT_TF_DBG(ERR, "invalid argument\n");
595 		return; /* failure */
596 	}
597 
598 	num = ULP_BITS_2_BYTE_NR(blob->write_idx);
599 	for (idx = 0; idx < (num / 2); idx++) {
600 		xchar = blob->data[idx];
601 		blob->data[idx] = blob->data[(num - 1) - idx];
602 		blob->data[(num - 1) - idx] = xchar;
603 	}
604 }
605 
606 /*
607  * Read data from the operand
608  *
609  * operand [in] A pointer to a 16 Byte operand
610  *
611  * val [in/out] The variable to copy the operand to
612  *
613  * bytes [in] The number of bytes to read into val
614  *
615  * returns number of bits read, zero on error
616  */
617 uint16_t
618 ulp_operand_read(uint8_t *operand,
619 		 uint8_t *val,
620 		 uint16_t bytes)
621 {
622 	/* validate the arguments */
623 	if (!operand || !val) {
624 		BNXT_TF_DBG(ERR, "invalid argument\n");
625 		return 0; /* failure */
626 	}
627 	memcpy(val, operand, bytes);
628 	return bytes;
629 }
630 
631 /*
632  * copy the buffer in the encap format which is 2 bytes.
633  * The MSB of the src is placed at the LSB of dst.
634  *
635  * dst [out] The destination buffer
636  * src [in] The source buffer dst
637  * size[in] size of the buffer.
638  * align[in] The alignment is either 8 or 16.
639  */
640 void
641 ulp_encap_buffer_copy(uint8_t *dst,
642 		      const uint8_t *src,
643 		      uint16_t size,
644 		      uint16_t align)
645 {
646 	uint16_t	idx, tmp_size = 0;
647 
648 	do {
649 		dst += tmp_size;
650 		src += tmp_size;
651 		idx = 0;
652 		if (size > align) {
653 			tmp_size = align;
654 			size -= align;
655 		} else {
656 			tmp_size = size;
657 			size = 0;
658 		}
659 		/* copy 2 bytes at a time. Write MSB to LSB */
660 		while ((idx + sizeof(uint16_t)) <= tmp_size) {
661 			memcpy(&dst[idx],
662 			       &src[tmp_size - idx - sizeof(uint16_t)],
663 			       sizeof(uint16_t));
664 			idx += sizeof(uint16_t);
665 		}
666 	} while (size);
667 }
668 
669 /*
670  * Check the buffer is empty
671  *
672  * buf [in] The buffer
673  * size [in] The size of the buffer
674  *
675  */
676 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
677 {
678 	return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
679 }
680 
681 /* Function to check if bitmap is zero.Return 1 on success */
682 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
683 {
684 	while (size-- > 0) {
685 		if (*bitmap != 0)
686 			return 0;
687 		bitmap++;
688 	}
689 	return 1;
690 }
691 
692 /* Function to check if bitmap is ones. Return 1 on success */
693 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
694 {
695 	while (size-- > 0) {
696 		if (*bitmap != 0xFF)
697 			return 0;
698 		bitmap++;
699 	}
700 	return 1;
701 }
702 
703 /* Function to check if bitmap is not zero. Return 1 on success */
704 uint32_t ulp_bitmap_notzero(uint8_t *bitmap, int32_t size)
705 {
706 	while (size-- > 0) {
707 		if (*bitmap != 0)
708 			return 1;
709 		bitmap++;
710 	}
711 	return 0;
712 }
713