xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_utils.c (revision b53d106d34b5c638f5a2cbdfee0da5bd42d4383f)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2021 Broadcom
3  * All rights reserved.
4  */
5 
6 #include <rte_common.h>
7 #include "ulp_utils.h"
8 #include "bnxt_tf_common.h"
9 
10 /*
11  * Initialize the regfile structure for writing
12  *
13  * regfile [in] Ptr to a regfile instance
14  *
15  * returns 0 on error or 1 on success
16  */
17 uint32_t
18 ulp_regfile_init(struct ulp_regfile *regfile)
19 {
20 	/* validate the arguments */
21 	if (!regfile) {
22 		BNXT_TF_DBG(ERR, "invalid argument\n");
23 		return 0; /* failure */
24 	}
25 	memset(regfile, 0, sizeof(struct ulp_regfile));
26 	return 1; /* Success */
27 }
28 
29 /*
30  * Read a value from the regfile
31  *
32  * regfile [in] The regfile instance. Must be initialized prior to being used
33  *
34  * field [in] The field to be read within the regfile.
35  *
36  * data [in/out]
37  *
38  * returns size, zero on failure
39  */
40 uint32_t
41 ulp_regfile_read(struct ulp_regfile *regfile,
42 		 enum bnxt_ulp_rf_idx field,
43 		 uint64_t *data)
44 {
45 	/* validate the arguments */
46 	if (!regfile || field >= BNXT_ULP_RF_IDX_LAST) {
47 		BNXT_TF_DBG(ERR, "invalid argument\n");
48 		return 0; /* failure */
49 	}
50 
51 	*data = regfile->entry[field].data;
52 	return sizeof(*data);
53 }
54 
55 /*
56  * Write a value to the regfile
57  *
58  * regfile [in] The regfile instance.  Must be initialized prior to being used
59  *
60  * field [in] The field to be written within the regfile.
61  *
62  * data [in] The value is written into this variable.  It is going to be in the
63  * same byte order as it was written.
64  *
65  * size [in] The size in bytes of the value being written into this
66  * variable.
67  *
68  * returns 0 on success
69  */
70 int32_t
71 ulp_regfile_write(struct ulp_regfile *regfile,
72 		  enum bnxt_ulp_rf_idx field,
73 		  uint64_t data)
74 {
75 	/* validate the arguments */
76 	if (!regfile || field >= BNXT_ULP_RF_IDX_LAST) {
77 		BNXT_TF_DBG(ERR, "invalid argument\n");
78 		return -EINVAL; /* failure */
79 	}
80 
81 	regfile->entry[field].data = data;
82 	return 0; /* Success */
83 }
84 
85 static void
86 ulp_bs_put_msb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val)
87 {
88 	uint8_t bitoffs = bitpos % 8;
89 	uint16_t index  = bitpos / 8;
90 	uint8_t mask;
91 	uint8_t tmp;
92 	int8_t shift;
93 
94 	tmp = bs[index];
95 	mask = ((uint8_t)-1 >> (8 - bitlen));
96 	shift = 8 - bitoffs - bitlen;
97 	val &= mask;
98 
99 	if (shift >= 0) {
100 		tmp &= ~(mask << shift);
101 		tmp |= val << shift;
102 		bs[index] = tmp;
103 	} else {
104 		tmp &= ~((uint8_t)-1 >> bitoffs);
105 		tmp |= val >> -shift;
106 		bs[index++] = tmp;
107 
108 		tmp = bs[index];
109 		tmp &= ((uint8_t)-1 >> (bitlen - (8 - bitoffs)));
110 		tmp |= val << (8 + shift);
111 		bs[index] = tmp;
112 	}
113 }
114 
115 static void
116 ulp_bs_put_lsb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val)
117 {
118 	uint8_t bitoffs = bitpos % 8;
119 	uint16_t index  = bitpos / 8;
120 	uint8_t mask;
121 	uint8_t tmp;
122 	uint8_t shift;
123 	uint8_t partial;
124 
125 	tmp = bs[index];
126 	shift = bitoffs;
127 
128 	if (bitoffs + bitlen <= 8) {
129 		mask = ((1 << bitlen) - 1) << shift;
130 		tmp &= ~mask;
131 		tmp |= ((val << shift) & mask);
132 		bs[index] = tmp;
133 	} else {
134 		partial = 8 - bitoffs;
135 		mask = ((1 << partial) - 1) << shift;
136 		tmp &= ~mask;
137 		tmp |= ((val << shift) & mask);
138 		bs[index++] = tmp;
139 
140 		val >>= partial;
141 		partial = bitlen - partial;
142 		mask = ((1 << partial) - 1);
143 		tmp = bs[index];
144 		tmp &= ~mask;
145 		tmp |= (val & mask);
146 		bs[index] = tmp;
147 	}
148 }
149 
150 /*
151  * Add data to the byte array in Little endian format.
152  *
153  * bs [in] The byte array where data is pushed
154  *
155  * pos [in] The offset where data is pushed
156  *
157  * len [in] The number of bits to be added to the data array.
158  *
159  * val [in] The data to be added to the data array.
160  *
161  * returns the number of bits pushed.
162  */
163 uint32_t
164 ulp_bs_push_lsb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
165 {
166 	int i;
167 	int cnt = (len) / 8;
168 	int tlen = len;
169 
170 	if (cnt > 0 && !(len % 8))
171 		cnt -= 1;
172 
173 	for (i = 0; i < cnt; i++) {
174 		ulp_bs_put_lsb(bs, pos, 8, val[cnt - i]);
175 		pos += 8;
176 		tlen -= 8;
177 	}
178 
179 	/* Handle the remainder bits */
180 	if (tlen)
181 		ulp_bs_put_lsb(bs, pos, tlen, val[0]);
182 	return len;
183 }
184 
185 /*
186  * Add data to the byte array in Big endian format.
187  *
188  * bs [in] The byte array where data is pushed
189  *
190  * pos [in] The offset where data is pushed
191  *
192  * len [in] The number of bits to be added to the data array.
193  *
194  * val [in] The data to be added to the data array.
195  *
196  * returns the number of bits pushed.
197  */
198 uint32_t
199 ulp_bs_push_msb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
200 {
201 	int i;
202 	int cnt = (len + 7) / 8;
203 
204 	/* Handle any remainder bits */
205 	int tmp = len % 8;
206 
207 	if (!tmp)
208 		tmp = 8;
209 
210 	ulp_bs_put_msb(bs, pos, tmp, val[0]);
211 
212 	pos += tmp;
213 
214 	for (i = 1; i < cnt; i++) {
215 		ulp_bs_put_msb(bs, pos, 8, val[i]);
216 		pos += 8;
217 	}
218 
219 	return len;
220 }
221 
222 /*
223  * Initializes the blob structure for creating binary blob
224  *
225  * blob [in] The blob to be initialized
226  *
227  * bitlen [in] The bit length of the blob
228  *
229  * order [in] The byte order for the blob.  Currently only supporting
230  * big endian.  All fields are packed with this order.
231  *
232  * returns 0 on error or 1 on success
233  * Notes - If bitlen is zero then set it to max.
234  */
235 uint32_t
236 ulp_blob_init(struct ulp_blob *blob,
237 	      uint16_t bitlen,
238 	      enum bnxt_ulp_byte_order order)
239 {
240 	/* validate the arguments */
241 	if (!blob || bitlen > (8 * sizeof(blob->data))) {
242 		BNXT_TF_DBG(ERR, "invalid argument\n");
243 		return 0; /* failure */
244 	}
245 	if (bitlen)
246 		blob->bitlen = bitlen;
247 	else
248 		blob->bitlen = BNXT_ULP_FLMP_BLOB_SIZE_IN_BITS;
249 	blob->byte_order = order;
250 	blob->write_idx = 0;
251 	memset(blob->data, 0, sizeof(blob->data));
252 	return 1; /* Success */
253 }
254 
255 /*
256  * Add data to the binary blob at the current offset.
257  *
258  * blob [in] The blob that data is added to.  The blob must
259  * be initialized prior to pushing data.
260  *
261  * data [in] A pointer to bytes to be added to the blob.
262  *
263  * datalen [in] The number of bits to be added to the blob.
264  *
265  * The offset of the data is updated after each push of data.
266  * NULL returned on error.
267  */
268 #define ULP_BLOB_BYTE		8
269 #define ULP_BLOB_BYTE_HEX	0xFF
270 #define BLOB_MASK_CAL(x)	((0xFF << (x)) & 0xFF)
271 uint32_t
272 ulp_blob_push(struct ulp_blob *blob,
273 	      uint8_t *data,
274 	      uint32_t datalen)
275 {
276 	uint32_t rc;
277 
278 	/* validate the arguments */
279 	if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
280 		BNXT_TF_DBG(ERR, "invalid argument\n");
281 		return 0; /* failure */
282 	}
283 
284 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
285 		rc = ulp_bs_push_msb(blob->data,
286 				     blob->write_idx,
287 				     datalen,
288 				     data);
289 	else
290 		rc = ulp_bs_push_lsb(blob->data,
291 				     blob->write_idx,
292 				     datalen,
293 				     data);
294 	if (!rc) {
295 		BNXT_TF_DBG(ERR, "Failed to write blob\n");
296 		return 0;
297 	}
298 	blob->write_idx += datalen;
299 	return datalen;
300 }
301 
302 /*
303  * Insert data into the binary blob at the given offset.
304  *
305  * blob [in] The blob that data is added to.  The blob must
306  * be initialized prior to pushing data.
307  *
308  * offset [in] The offset where the data needs to be inserted.
309  *
310  * data [in/out] A pointer to bytes to be added to the blob.
311  *
312  * datalen [in] The number of bits to be added to the blob.
313  *
314  * The offset of the data is updated after each push of data.
315  * NULL returned on error.
316  */
317 uint32_t
318 ulp_blob_insert(struct ulp_blob *blob, uint32_t offset,
319 		uint8_t *data, uint32_t datalen)
320 {
321 	uint32_t rc;
322 	uint8_t local_data[BNXT_ULP_FLMP_BLOB_SIZE];
323 	uint16_t mov_len;
324 
325 	/* validate the arguments */
326 	if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx) ||
327 	    offset > blob->write_idx) {
328 		BNXT_TF_DBG(ERR, "invalid argument\n");
329 		return 0; /* failure */
330 	}
331 
332 	mov_len = blob->write_idx - offset;
333 	/* If offset and data len are not 8 bit aligned then return error */
334 	if (ULP_BITS_IS_BYTE_NOT_ALIGNED(offset) ||
335 	    ULP_BITS_IS_BYTE_NOT_ALIGNED(datalen)) {
336 		BNXT_TF_DBG(ERR, "invalid argument, not aligned\n");
337 		return 0; /* failure */
338 	}
339 
340 	/* copy the data so we can move the data */
341 	memcpy(local_data, &blob->data[ULP_BITS_2_BYTE_NR(offset)],
342 	       ULP_BITS_2_BYTE(mov_len));
343 	blob->write_idx = offset;
344 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
345 		rc = ulp_bs_push_msb(blob->data,
346 				     blob->write_idx,
347 				     datalen,
348 				     data);
349 	else
350 		rc = ulp_bs_push_lsb(blob->data,
351 				     blob->write_idx,
352 				     datalen,
353 				     data);
354 	if (!rc) {
355 		BNXT_TF_DBG(ERR, "Failed to write blob\n");
356 		return 0;
357 	}
358 	/* copy the previously stored data */
359 	memcpy(&blob->data[ULP_BITS_2_BYTE_NR(offset + datalen)], local_data,
360 	       ULP_BITS_2_BYTE(mov_len));
361 	blob->write_idx += (mov_len + datalen);
362 	return datalen;
363 }
364 
365 /*
366  * Add data to the binary blob at the current offset.
367  *
368  * blob [in] The blob that data is added to.  The blob must
369  * be initialized prior to pushing data.
370  *
371  * data [in] 64-bit value to be added to the blob.
372  *
373  * datalen [in] The number of bits to be added to the blob.
374  *
375  * The offset of the data is updated after each push of data.
376  * NULL returned on error, pointer pushed value otherwise.
377  */
378 uint8_t *
379 ulp_blob_push_64(struct ulp_blob *blob,
380 		 uint64_t *data,
381 		 uint32_t datalen)
382 {
383 	uint8_t *val = (uint8_t *)data;
384 	int rc;
385 
386 	int size = (datalen + 7) / 8;
387 
388 	if (!blob || !data ||
389 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
390 		BNXT_TF_DBG(ERR, "invalid argument\n");
391 		return 0;
392 	}
393 
394 	rc = ulp_blob_push(blob, &val[8 - size], datalen);
395 	if (!rc)
396 		return 0;
397 
398 	return &val[8 - size];
399 }
400 
401 /*
402  * Add data to the binary blob at the current offset.
403  *
404  * blob [in] The blob that data is added to.  The blob must
405  * be initialized prior to pushing data.
406  *
407  * data [in] 32-bit value to be added to the blob.
408  *
409  * datalen [in] The number of bits to be added to the blob.
410  *
411  * The offset of the data is updated after each push of data.
412  * NULL returned on error, pointer pushed value otherwise.
413  */
414 uint8_t *
415 ulp_blob_push_32(struct ulp_blob *blob,
416 		 uint32_t *data,
417 		 uint32_t datalen)
418 {
419 	uint8_t *val = (uint8_t *)data;
420 	uint32_t rc;
421 	uint32_t size = ULP_BITS_2_BYTE(datalen);
422 
423 	if (!data || size > sizeof(uint32_t)) {
424 		BNXT_TF_DBG(ERR, "invalid argument\n");
425 		return 0;
426 	}
427 
428 	rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen);
429 	if (!rc)
430 		return 0;
431 
432 	return &val[sizeof(uint32_t) - size];
433 }
434 
435 /*
436  * Add encap data to the binary blob at the current offset.
437  *
438  * blob [in] The blob that data is added to.  The blob must
439  * be initialized prior to pushing data.
440  *
441  * data [in] value to be added to the blob.
442  *
443  * datalen [in] The number of bits to be added to the blob.
444  *
445  * The offset of the data is updated after each push of data.
446  * NULL returned on error, pointer pushed value otherwise.
447  */
448 int32_t
449 ulp_blob_push_encap(struct ulp_blob *blob,
450 		    uint8_t *data,
451 		    uint32_t datalen)
452 {
453 	uint8_t		*val = (uint8_t *)data;
454 	uint32_t	initial_size, write_size = datalen;
455 	uint32_t	size = 0;
456 
457 	if (!blob || !data ||
458 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
459 		BNXT_TF_DBG(ERR, "invalid argument\n");
460 		return -1;
461 	}
462 
463 	initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
464 	    (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
465 	while (write_size > 0) {
466 		if (initial_size && write_size > initial_size) {
467 			size = initial_size;
468 			initial_size = 0;
469 		} else if (initial_size && write_size <= initial_size) {
470 			size = write_size;
471 			initial_size = 0;
472 		} else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) {
473 			size = ULP_BYTE_2_BITS(sizeof(uint64_t));
474 		} else {
475 			size = write_size;
476 		}
477 		if (!ulp_blob_push(blob, val, size)) {
478 			BNXT_TF_DBG(ERR, "push field failed\n");
479 			return -1;
480 		}
481 		val += ULP_BITS_2_BYTE(size);
482 		write_size -= size;
483 	}
484 	return datalen;
485 }
486 
487 /*
488  * Adds pad to an initialized blob at the current offset
489  *
490  * blob [in] The blob that data is added to.  The blob must
491  * be initialized prior to pushing data.
492  *
493  * datalen [in] The number of bits of pad to add
494  *
495  * returns the number of pad bits added, -1 on failure
496  */
497 int32_t
498 ulp_blob_pad_push(struct ulp_blob *blob,
499 		  uint32_t datalen)
500 {
501 	if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
502 		BNXT_TF_DBG(ERR, "Pad too large for blob\n");
503 		return -1;
504 	}
505 
506 	blob->write_idx += datalen;
507 	return datalen;
508 }
509 
510 /*
511  * Adds pad to an initialized blob at the current offset based on
512  * the alignment.
513  *
514  * blob [in] The blob that needs to be aligned
515  *
516  * align [in] Alignment in bits.
517  *
518  * returns the number of pad bits added, -1 on failure
519  */
520 int32_t
521 ulp_blob_pad_align(struct ulp_blob *blob,
522 		   uint32_t align)
523 {
524 	int32_t pad = 0;
525 
526 	pad = RTE_ALIGN(blob->write_idx, align) - blob->write_idx;
527 	if (pad > (int32_t)(blob->bitlen - blob->write_idx)) {
528 		BNXT_TF_DBG(ERR, "Pad too large for blob\n");
529 		return -1;
530 	}
531 	blob->write_idx += pad;
532 	return pad;
533 }
534 
535 /* Get data from src and put into dst using little-endian format */
536 static void
537 ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
538 {
539 	uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
540 	uint16_t index  = ULP_BITS_2_BYTE_NR(bitpos);
541 	uint8_t mask, partial, shift;
542 
543 	shift = bitoffs;
544 	partial = ULP_BLOB_BYTE - bitoffs;
545 	if (bitoffs + bitlen <= ULP_BLOB_BYTE) {
546 		mask = ((1 << bitlen) - 1) << shift;
547 		*dst = (src[index] & mask) >> shift;
548 	} else {
549 		mask = ((1 << partial) - 1) << shift;
550 		*dst = (src[index] & mask) >> shift;
551 		index++;
552 		partial = bitlen - partial;
553 		mask = ((1 << partial) - 1);
554 		*dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs);
555 	}
556 }
557 
558 /*
559  * Get data from the byte array in Little endian format.
560  *
561  * src [in] The byte array where data is extracted from
562  *
563  * dst [out] The byte array where data is pulled into
564  *
565  * size [in] The size of dst array in bytes
566  *
567  * offset [in] The offset where data is pulled
568  *
569  * len [in] The number of bits to be extracted from the data array
570  *
571  * returns None.
572  */
573 void
574 ulp_bs_pull_lsb(uint8_t *src, uint8_t *dst, uint32_t size,
575 		uint32_t offset, uint32_t len)
576 {
577 	uint32_t idx;
578 	uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
579 
580 	/* iterate bytewise to get data */
581 	for (idx = 0; idx < cnt; idx++) {
582 		ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE,
583 			       &dst[size - 1 - idx]);
584 		offset += ULP_BLOB_BYTE;
585 		len -= ULP_BLOB_BYTE;
586 	}
587 
588 	/* Extract the last reminder data that is not 8 byte boundary */
589 	if (len)
590 		ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]);
591 }
592 
593 /* Get data from src and put into dst using big-endian format */
594 static void
595 ulp_bs_get_msb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
596 {
597 	uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
598 	uint16_t index  = ULP_BITS_2_BYTE_NR(bitpos);
599 	uint8_t mask;
600 	int32_t shift;
601 
602 	shift = ULP_BLOB_BYTE - bitoffs - bitlen;
603 	if (shift >= 0) {
604 		mask = 0xFF >> -bitlen;
605 		*dst = (src[index] >> shift) & mask;
606 	} else {
607 		*dst = (src[index] & (0xFF >> bitoffs)) << -shift;
608 		*dst |= src[index + 1] >> -shift;
609 	}
610 }
611 
612 /*
613  * Get data from the byte array in Big endian format.
614  *
615  * src [in] The byte array where data is extracted from
616  *
617  * dst [out] The byte array where data is pulled into
618  *
619  * offset [in] The offset where data is pulled
620  *
621  * len [in] The number of bits to be extracted from the data array
622  *
623  * returns None.
624  */
625 void
626 ulp_bs_pull_msb(uint8_t *src, uint8_t *dst,
627 		uint32_t offset, uint32_t len)
628 {
629 	uint32_t idx;
630 	uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
631 
632 	/* iterate bytewise to get data */
633 	for (idx = 0; idx < cnt; idx++) {
634 		ulp_bs_get_msb(src, offset, ULP_BLOB_BYTE, &dst[idx]);
635 		offset += ULP_BLOB_BYTE;
636 		len -= ULP_BLOB_BYTE;
637 	}
638 
639 	/* Extract the last reminder data that is not 8 byte boundary */
640 	if (len)
641 		ulp_bs_get_msb(src, offset, len, &dst[idx]);
642 }
643 
644 /*
645  * Extract data from the binary blob using given offset.
646  *
647  * blob [in] The blob that data is extracted from. The blob must
648  * be initialized prior to pulling data.
649  *
650  * data [in] A pointer to put the data.
651  * data_size [in] size of the data buffer in bytes.
652  *offset [in] - Offset in the blob to extract the data in bits format.
653  * len [in] The number of bits to be pulled from the blob.
654  *
655  * Output: zero on success, -1 on failure
656  */
657 int32_t
658 ulp_blob_pull(struct ulp_blob *blob, uint8_t *data, uint32_t data_size,
659 	      uint16_t offset, uint16_t len)
660 {
661 	/* validate the arguments */
662 	if (!blob || (offset + len) > blob->bitlen ||
663 	    ULP_BYTE_2_BITS(data_size) < len) {
664 		BNXT_TF_DBG(ERR, "invalid argument\n");
665 		return -1; /* failure */
666 	}
667 
668 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
669 		ulp_bs_pull_msb(blob->data, data, offset, len);
670 	else
671 		ulp_bs_pull_lsb(blob->data, data, data_size, offset, len);
672 	return 0;
673 }
674 
675 /*
676  * Get the data portion of the binary blob.
677  *
678  * blob [in] The blob's data to be retrieved. The blob must be
679  * initialized prior to pushing data.
680  *
681  * datalen [out] The number of bits to that are filled.
682  *
683  * returns a byte array of the blob data.  Returns NULL on error.
684  */
685 uint8_t *
686 ulp_blob_data_get(struct ulp_blob *blob,
687 		  uint16_t *datalen)
688 {
689 	/* validate the arguments */
690 	if (!blob) {
691 		BNXT_TF_DBG(ERR, "invalid argument\n");
692 		return NULL; /* failure */
693 	}
694 	*datalen = blob->write_idx;
695 	return blob->data;
696 }
697 
698 /*
699  * Get the data length of the binary blob.
700  *
701  * blob [in] The blob's data len to be retrieved.
702  *
703  * returns length of the binary blob
704  */
705 uint16_t
706 ulp_blob_data_len_get(struct ulp_blob *blob)
707 {
708 	/* validate the arguments */
709 	if (!blob) {
710 		BNXT_TF_DBG(ERR, "invalid argument\n");
711 		return 0; /* failure */
712 	}
713 	return blob->write_idx;
714 }
715 
716 /*
717  * Set the encap swap start index of the binary blob.
718  *
719  * blob [in] The blob's data to be retrieved. The blob must be
720  * initialized prior to pushing data.
721  *
722  * returns void.
723  */
724 void
725 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
726 {
727 	/* validate the arguments */
728 	if (!blob) {
729 		BNXT_TF_DBG(ERR, "invalid argument\n");
730 		return; /* failure */
731 	}
732 	blob->encap_swap_idx = blob->write_idx;
733 }
734 
735 /*
736  * Perform the encap buffer swap to 64 bit reversal.
737  *
738  * blob [in] The blob's data to be used for swap.
739  *
740  * returns void.
741  */
742 void
743 ulp_blob_perform_encap_swap(struct ulp_blob *blob)
744 {
745 	uint32_t i, idx = 0, end_idx = 0, roundoff;
746 	uint8_t temp_val_1, temp_val_2;
747 
748 	/* validate the arguments */
749 	if (!blob) {
750 		BNXT_TF_DBG(ERR, "invalid argument\n");
751 		return; /* failure */
752 	}
753 	idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx);
754 	end_idx = ULP_BITS_2_BYTE(blob->write_idx);
755 	roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx));
756 	if (roundoff > end_idx) {
757 		blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx);
758 		end_idx = roundoff;
759 	}
760 	while (idx <= end_idx) {
761 		for (i = 0; i < 4; i = i + 2) {
762 			temp_val_1 = blob->data[idx + i];
763 			temp_val_2 = blob->data[idx + i + 1];
764 			blob->data[idx + i] = blob->data[idx + 6 - i];
765 			blob->data[idx + i + 1] = blob->data[idx + 7 - i];
766 			blob->data[idx + 7 - i] = temp_val_2;
767 			blob->data[idx + 6 - i] = temp_val_1;
768 		}
769 		idx += 8;
770 	}
771 }
772 
773 /*
774  * Perform the blob buffer reversal byte wise.
775  * This api makes the first byte the last and
776  * vice-versa.
777  *
778  * blob [in] The blob's data to be used for swap.
779  * chunk_size[in] the swap is done within the chunk in bytes
780  *
781  * returns void.
782  */
783 void
784 ulp_blob_perform_byte_reverse(struct ulp_blob *blob,
785 			      uint32_t chunk_size)
786 {
787 	uint32_t idx = 0, jdx = 0, num = 0;
788 	uint8_t xchar;
789 	uint8_t *buff;
790 
791 	/* validate the arguments */
792 	if (!blob) {
793 		BNXT_TF_DBG(ERR, "invalid argument\n");
794 		return; /* failure */
795 	}
796 
797 	buff = blob->data;
798 	num = ULP_BITS_2_BYTE(blob->write_idx) / chunk_size;
799 	for (idx = 0; idx < num; idx++) {
800 		for (jdx = 0; jdx < chunk_size / 2; jdx++) {
801 			xchar = buff[jdx];
802 			buff[jdx] = buff[(chunk_size - 1) - jdx];
803 			buff[(chunk_size - 1) - jdx] = xchar;
804 		}
805 		buff += chunk_size;
806 	}
807 }
808 
809 /*
810  * Perform the blob buffer 64 bit word swap.
811  * This api makes the first 4 bytes the last in
812  * a given 64 bit value and vice-versa.
813  *
814  * blob [in] The blob's data to be used for swap.
815  *
816  * returns void.
817  */
818 void
819 ulp_blob_perform_64B_word_swap(struct ulp_blob *blob)
820 {
821 	uint32_t i, j, num;
822 	uint8_t xchar;
823 	uint32_t word_size = ULP_64B_IN_BYTES / 2;
824 
825 	/* validate the arguments */
826 	if (!blob) {
827 		BNXT_TF_DBG(ERR, "invalid argument\n");
828 		return; /* failure */
829 	}
830 	num = ULP_BITS_2_BYTE(blob->write_idx);
831 	for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
832 		for (j = 0; j < word_size; j++) {
833 			xchar = blob->data[i + j];
834 			blob->data[i + j] = blob->data[i + j + word_size];
835 			blob->data[i + j + word_size] = xchar;
836 		}
837 	}
838 }
839 
840 /*
841  * Perform the blob buffer 64 bit byte swap.
842  * This api makes the first byte the last in
843  * a given 64 bit value and vice-versa.
844  *
845  * blob [in] The blob's data to be used for swap.
846  *
847  * returns void.
848  */
849 void
850 ulp_blob_perform_64B_byte_swap(struct ulp_blob *blob)
851 {
852 	uint32_t i, j, num;
853 	uint8_t xchar;
854 	uint32_t offset = ULP_64B_IN_BYTES - 1;
855 
856 	/* validate the arguments */
857 	if (!blob) {
858 		BNXT_TF_DBG(ERR, "invalid argument\n");
859 		return; /* failure */
860 	}
861 	num = ULP_BITS_2_BYTE(blob->write_idx);
862 	for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
863 		for (j = 0; j < (ULP_64B_IN_BYTES / 2); j++) {
864 			xchar = blob->data[i + j];
865 			blob->data[i + j] = blob->data[i + offset - j];
866 			blob->data[i + offset - j] = xchar;
867 		}
868 	}
869 }
870 
871 static int32_t
872 ulp_blob_msb_block_merge(struct ulp_blob *dst, struct ulp_blob *src,
873 			 uint32_t block_size, uint32_t pad)
874 {
875 	uint32_t i, k, write_bytes, remaining;
876 	uint16_t num;
877 	uint8_t *src_buf = ulp_blob_data_get(src, &num);
878 	uint8_t bluff;
879 
880 	for (i = 0; i < num;) {
881 		if (((dst->write_idx % block_size)  + (num - i)) > block_size)
882 			write_bytes = block_size -
883 				(dst->write_idx % block_size);
884 		else
885 			write_bytes = num - i;
886 		for (k = 0; k < ULP_BITS_2_BYTE_NR(write_bytes); k++) {
887 			ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE,
888 				       *src_buf);
889 			dst->write_idx += ULP_BLOB_BYTE;
890 			src_buf++;
891 		}
892 		remaining = write_bytes % ULP_BLOB_BYTE;
893 		if (remaining) {
894 			bluff = (*src_buf) & ((uint8_t)-1 <<
895 					      (ULP_BLOB_BYTE - remaining));
896 			ulp_bs_put_msb(dst->data, dst->write_idx,
897 				       ULP_BLOB_BYTE, bluff);
898 			dst->write_idx += remaining;
899 		}
900 		if (write_bytes != (num - i)) {
901 			/* add the padding */
902 			ulp_blob_pad_push(dst, pad);
903 			if (remaining) {
904 				ulp_bs_put_msb(dst->data, dst->write_idx,
905 					       ULP_BLOB_BYTE - remaining,
906 					       *src_buf);
907 				dst->write_idx += ULP_BLOB_BYTE - remaining;
908 				src_buf++;
909 			}
910 		}
911 		i += write_bytes;
912 	}
913 	return 0;
914 }
915 
916 /*
917  * Perform the blob buffer merge.
918  * This api makes the src blob merged to the dst blob.
919  * The block size and pad size help in padding the dst blob
920  *
921  * dst [in] The destination blob, the blob to be merged.
922  * src [in] The src blob.
923  * block_size [in] The size of the block after which padding gets applied.
924  * pad [in] The size of the pad to be applied.
925  *
926  * returns 0 on success.
927  */
928 int32_t
929 ulp_blob_block_merge(struct ulp_blob *dst, struct ulp_blob *src,
930 		     uint32_t block_size, uint32_t pad)
931 {
932 	if (dst->byte_order == BNXT_ULP_BYTE_ORDER_BE &&
933 	    src->byte_order == BNXT_ULP_BYTE_ORDER_BE)
934 		return ulp_blob_msb_block_merge(dst, src, block_size, pad);
935 
936 	BNXT_TF_DBG(ERR, "block merge not implemented yet\n");
937 	return -EINVAL;
938 }
939 
940 int32_t
941 ulp_blob_append(struct ulp_blob *dst, struct ulp_blob *src,
942 		uint16_t src_offset, uint16_t src_len)
943 {
944 	uint32_t k, remaining;
945 	uint16_t num;
946 	uint8_t bluff;
947 	uint8_t *src_buf = ulp_blob_data_get(src, &num);
948 
949 	if ((src_offset + src_len) > num)
950 		return -EINVAL;
951 
952 	/* Only supporting BE for now */
953 	if (src->byte_order != BNXT_ULP_BYTE_ORDER_BE ||
954 	    dst->byte_order != BNXT_ULP_BYTE_ORDER_BE)
955 		return -EINVAL;
956 
957 	/* Handle if the source offset is not on a byte boundary */
958 	remaining = src_offset % ULP_BLOB_BYTE;
959 	if (remaining) {
960 		bluff = src_buf[src_offset / ULP_BLOB_BYTE] & ((uint8_t)-1 >>
961 				      (ULP_BLOB_BYTE - remaining));
962 		ulp_bs_put_msb(dst->data, dst->write_idx,
963 			       ULP_BLOB_BYTE, bluff);
964 		dst->write_idx += remaining;
965 		src_offset += remaining;
966 	}
967 
968 	src_buf += ULP_BITS_2_BYTE_NR(src_offset);
969 
970 	/* Push the byte aligned pieces */
971 	for (k = 0; k < ULP_BITS_2_BYTE_NR(src_len); k++) {
972 		ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE,
973 			       *src_buf);
974 		dst->write_idx += ULP_BLOB_BYTE;
975 		src_buf++;
976 	}
977 
978 	/* Handle the remaining if length is not a byte boundary */
979 	remaining = src_len % ULP_BLOB_BYTE;
980 	if (remaining) {
981 		bluff = (*src_buf) & ((uint8_t)-1 <<
982 				      (ULP_BLOB_BYTE - remaining));
983 		ulp_bs_put_msb(dst->data, dst->write_idx,
984 			       ULP_BLOB_BYTE, bluff);
985 		dst->write_idx += remaining;
986 	}
987 
988 	return 0;
989 }
990 
991 /*
992  * Perform the blob buffer copy.
993  * This api makes the src blob merged to the dst blob.
994  *
995  * dst [in] The destination blob, the blob to be merged.
996  * src [in] The src blob.
997  *
998  * returns 0 on success.
999  */
1000 int32_t
1001 ulp_blob_buffer_copy(struct ulp_blob *dst, struct ulp_blob *src)
1002 {
1003 	if ((dst->write_idx + src->write_idx) > dst->bitlen) {
1004 		BNXT_TF_DBG(ERR, "source buffer too large\n");
1005 		return -EINVAL;
1006 	}
1007 	if (ULP_BITS_IS_BYTE_NOT_ALIGNED(dst->write_idx) ||
1008 	    ULP_BITS_IS_BYTE_NOT_ALIGNED(src->write_idx)) {
1009 		BNXT_TF_DBG(ERR, "source buffer is not aligned\n");
1010 		return -EINVAL;
1011 	}
1012 	memcpy(&dst->data[ULP_BITS_2_BYTE_NR(dst->write_idx)],
1013 	       src->data, ULP_BITS_2_BYTE_NR(src->write_idx));
1014 	dst->write_idx += src->write_idx;
1015 	return 0;
1016 }
1017 
1018 /*
1019  * Read data from the operand
1020  *
1021  * operand [in] A pointer to a 16 Byte operand
1022  *
1023  * val [in/out] The variable to copy the operand to
1024  *
1025  * bytes [in] The number of bytes to read into val
1026  *
1027  * returns number of bits read, zero on error
1028  */
1029 uint16_t
1030 ulp_operand_read(uint8_t *operand,
1031 		 uint8_t *val,
1032 		 uint16_t bytes)
1033 {
1034 	/* validate the arguments */
1035 	if (!operand || !val) {
1036 		BNXT_TF_DBG(ERR, "invalid argument\n");
1037 		return 0; /* failure */
1038 	}
1039 	memcpy(val, operand, bytes);
1040 	return bytes;
1041 }
1042 
1043 /*
1044  * Check the buffer is empty
1045  *
1046  * buf [in] The buffer
1047  * size [in] The size of the buffer
1048  *
1049  */
1050 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
1051 {
1052 	return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
1053 }
1054 
1055 /* Function to check if bitmap is zero.Return 1 on success */
1056 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
1057 {
1058 	while (size-- > 0) {
1059 		if (*bitmap != 0)
1060 			return 0;
1061 		bitmap++;
1062 	}
1063 	return 1;
1064 }
1065 
1066 /* Function to check if bitmap is ones. Return 1 on success */
1067 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
1068 {
1069 	while (size-- > 0) {
1070 		if (*bitmap != 0xFF)
1071 			return 0;
1072 		bitmap++;
1073 	}
1074 	return 1;
1075 }
1076 
1077 /* Function to check if bitmap is not zero. Return 1 on success */
1078 uint32_t ulp_bitmap_notzero(const uint8_t *bitmap, int32_t size)
1079 {
1080 	while (size-- > 0) {
1081 		if (*bitmap != 0)
1082 			return 1;
1083 		bitmap++;
1084 	}
1085 	return 0;
1086 }
1087 
1088 /* returns 0 if input is power of 2 */
1089 int32_t ulp_util_is_power_of_2(uint64_t x)
1090 {
1091 	if (((x - 1) & x))
1092 		return -1;
1093 	return 0;
1094 }
1095