xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_utils.c (revision bc8e32473cc3978d763a1387eaa8244bcf75e77d)
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  * Insert data into the binary blob at the given offset.
278  *
279  * blob [in] The blob that data is added to.  The blob must
280  * be initialized prior to pushing data.
281  *
282  * offset [in] The offset where the data needs to be inserted.
283  *
284  * data [in/out] A pointer to bytes to be added to the blob.
285  *
286  * datalen [in] The number of bits to be added to the blob.
287  *
288  * The offset of the data is updated after each push of data.
289  * NULL returned on error.
290  */
291 uint32_t
292 ulp_blob_insert(struct ulp_blob *blob, uint32_t offset,
293 		uint8_t *data, uint32_t datalen)
294 {
295 	uint32_t rc;
296 	uint8_t local_data[BNXT_ULP_FLMP_BLOB_SIZE];
297 	uint16_t mov_len;
298 
299 	/* validate the arguments */
300 	if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx) ||
301 	    offset > blob->write_idx) {
302 		BNXT_TF_DBG(ERR, "invalid argument\n");
303 		return 0; /* failure */
304 	}
305 
306 	mov_len = blob->write_idx - offset;
307 	/* If offset and data len are not 8 bit aligned then return error */
308 	if (ULP_BITS_IS_BYTE_NOT_ALIGNED(offset) ||
309 	    ULP_BITS_IS_BYTE_NOT_ALIGNED(datalen)) {
310 		BNXT_TF_DBG(ERR, "invalid argument, not aligned\n");
311 		return 0; /* failure */
312 	}
313 
314 	/* copy the data so we can move the data */
315 	memcpy(local_data, &blob->data[ULP_BITS_2_BYTE_NR(offset)],
316 	       ULP_BITS_2_BYTE(mov_len));
317 	blob->write_idx = offset;
318 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
319 		rc = ulp_bs_push_msb(blob->data,
320 				     blob->write_idx,
321 				     datalen,
322 				     data);
323 	else
324 		rc = ulp_bs_push_lsb(blob->data,
325 				     blob->write_idx,
326 				     datalen,
327 				     data);
328 	if (!rc) {
329 		BNXT_TF_DBG(ERR, "Failed ro write blob\n");
330 		return 0;
331 	}
332 	/* copy the previously stored data */
333 	memcpy(&blob->data[ULP_BITS_2_BYTE_NR(offset + datalen)], local_data,
334 	       ULP_BITS_2_BYTE(mov_len));
335 	blob->write_idx += (mov_len + datalen);
336 	return datalen;
337 }
338 
339 /*
340  * Add data to the binary blob at the current offset.
341  *
342  * blob [in] The blob that data is added to.  The blob must
343  * be initialized prior to pushing data.
344  *
345  * data [in] 64-bit value to be added to the blob.
346  *
347  * datalen [in] The number of bits to be added to the blob.
348  *
349  * The offset of the data is updated after each push of data.
350  * NULL returned on error, pointer pushed value otherwise.
351  */
352 uint8_t *
353 ulp_blob_push_64(struct ulp_blob *blob,
354 		 uint64_t *data,
355 		 uint32_t datalen)
356 {
357 	uint8_t *val = (uint8_t *)data;
358 	int rc;
359 
360 	int size = (datalen + 7) / 8;
361 
362 	if (!blob || !data ||
363 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
364 		BNXT_TF_DBG(ERR, "invalid argument\n");
365 		return 0;
366 	}
367 
368 	rc = ulp_blob_push(blob, &val[8 - size], datalen);
369 	if (!rc)
370 		return 0;
371 
372 	return &val[8 - size];
373 }
374 
375 /*
376  * Add data to the binary blob at the current offset.
377  *
378  * blob [in] The blob that data is added to.  The blob must
379  * be initialized prior to pushing data.
380  *
381  * data [in] 32-bit value to be added to the blob.
382  *
383  * datalen [in] The number of bits to be added ot the blob.
384  *
385  * The offset of the data is updated after each push of data.
386  * NULL returned on error, pointer pushed value otherwise.
387  */
388 uint8_t *
389 ulp_blob_push_32(struct ulp_blob *blob,
390 		 uint32_t *data,
391 		 uint32_t datalen)
392 {
393 	uint8_t *val = (uint8_t *)data;
394 	uint32_t rc;
395 	uint32_t size = ULP_BITS_2_BYTE(datalen);
396 
397 	if (!data || size > sizeof(uint32_t)) {
398 		BNXT_TF_DBG(ERR, "invalid argument\n");
399 		return 0;
400 	}
401 
402 	rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen);
403 	if (!rc)
404 		return 0;
405 
406 	return &val[sizeof(uint32_t) - size];
407 }
408 
409 /*
410  * Add encap data to the binary blob at the current offset.
411  *
412  * blob [in] The blob that data is added to.  The blob must
413  * be initialized prior to pushing data.
414  *
415  * data [in] value to be added to the blob.
416  *
417  * datalen [in] The number of bits to be added to the blob.
418  *
419  * The offset of the data is updated after each push of data.
420  * NULL returned on error, pointer pushed value otherwise.
421  */
422 uint32_t
423 ulp_blob_push_encap(struct ulp_blob *blob,
424 		    uint8_t *data,
425 		    uint32_t datalen)
426 {
427 	uint8_t		*val = (uint8_t *)data;
428 	uint32_t	initial_size, write_size = datalen;
429 	uint32_t	size = 0;
430 
431 	if (!blob || !data ||
432 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
433 		BNXT_TF_DBG(ERR, "invalid argument\n");
434 		return 0;
435 	}
436 
437 	initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
438 	    (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
439 	while (write_size > 0) {
440 		if (initial_size && write_size > initial_size) {
441 			size = initial_size;
442 			initial_size = 0;
443 		} else if (initial_size && write_size <= initial_size) {
444 			size = write_size;
445 			initial_size = 0;
446 		} else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) {
447 			size = ULP_BYTE_2_BITS(sizeof(uint64_t));
448 		} else {
449 			size = write_size;
450 		}
451 		if (!ulp_blob_push(blob, val, size)) {
452 			BNXT_TF_DBG(ERR, "push field failed\n");
453 			return 0;
454 		}
455 		val += ULP_BITS_2_BYTE(size);
456 		write_size -= size;
457 	}
458 	return datalen;
459 }
460 
461 /*
462  * Adds pad to an initialized blob at the current offset
463  *
464  * blob [in] The blob that data is added to.  The blob must
465  * be initialized prior to pushing data.
466  *
467  * datalen [in] The number of bits of pad to add
468  *
469  * returns the number of pad bits added, -1 on failure
470  */
471 int32_t
472 ulp_blob_pad_push(struct ulp_blob *blob,
473 		  uint32_t datalen)
474 {
475 	if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
476 		BNXT_TF_DBG(ERR, "Pad too large for blob\n");
477 		return 0;
478 	}
479 
480 	blob->write_idx += datalen;
481 	return datalen;
482 }
483 
484 /* Get data from src and put into dst using little-endian format */
485 static void
486 ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
487 {
488 	uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
489 	uint16_t index  = ULP_BITS_2_BYTE_NR(bitpos);
490 	uint8_t mask, partial, shift;
491 
492 	shift = bitoffs;
493 	partial = ULP_BLOB_BYTE - bitoffs;
494 	if (bitoffs + bitlen <= ULP_BLOB_BYTE) {
495 		mask = ((1 << bitlen) - 1) << shift;
496 		*dst = (src[index] & mask) >> shift;
497 	} else {
498 		mask = ((1 << partial) - 1) << shift;
499 		*dst = (src[index] & mask) >> shift;
500 		index++;
501 		partial = bitlen - partial;
502 		mask = ((1 << partial) - 1);
503 		*dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs);
504 	}
505 }
506 
507 /* Assuming that src is in little-Endian Format */
508 static void
509 ulp_bs_pull_lsb(uint8_t *src, uint8_t *dst, uint32_t size,
510 		uint32_t offset, uint32_t len)
511 {
512 	uint32_t idx;
513 	uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
514 
515 	/* iterate bytewise to get data */
516 	for (idx = 0; idx < cnt; idx++) {
517 		ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE,
518 			       &dst[size - 1 - idx]);
519 		offset += ULP_BLOB_BYTE;
520 		len -= ULP_BLOB_BYTE;
521 	}
522 
523 	/* Extract the last reminder data that is not 8 byte boundary */
524 	if (len)
525 		ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]);
526 }
527 
528 /*
529  * Extract data from the binary blob using given offset.
530  *
531  * blob [in] The blob that data is extracted from. The blob must
532  * be initialized prior to pulling data.
533  *
534  * data [in] A pointer to put the data.
535  * data_size [in] size of the data buffer in bytes.
536  *offset [in] - Offset in the blob to extract the data in bits format.
537  * len [in] The number of bits to be pulled from the blob.
538  *
539  * Output: zero on success, -1 on failure
540  */
541 int32_t
542 ulp_blob_pull(struct ulp_blob *blob, uint8_t *data, uint32_t data_size,
543 	      uint16_t offset, uint16_t len)
544 {
545 	/* validate the arguments */
546 	if (!blob || (offset + len) > blob->bitlen ||
547 	    ULP_BYTE_2_BITS(data_size) < len) {
548 		BNXT_TF_DBG(ERR, "invalid argument\n");
549 		return -1; /* failure */
550 	}
551 
552 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) {
553 		BNXT_TF_DBG(ERR, "Big endian pull not implemented\n");
554 		return -1; /* failure */
555 	}
556 	ulp_bs_pull_lsb(blob->data, data, data_size, offset, len);
557 	return 0;
558 }
559 
560 /*
561  * Get the data portion of the binary blob.
562  *
563  * blob [in] The blob's data to be retrieved. The blob must be
564  * initialized prior to pushing data.
565  *
566  * datalen [out] The number of bits to that are filled.
567  *
568  * returns a byte array of the blob data.  Returns NULL on error.
569  */
570 uint8_t *
571 ulp_blob_data_get(struct ulp_blob *blob,
572 		  uint16_t *datalen)
573 {
574 	/* validate the arguments */
575 	if (!blob) {
576 		BNXT_TF_DBG(ERR, "invalid argument\n");
577 		return NULL; /* failure */
578 	}
579 	*datalen = blob->write_idx;
580 	return blob->data;
581 }
582 
583 /*
584  * Set the encap swap start index of the binary blob.
585  *
586  * blob [in] The blob's data to be retrieved. The blob must be
587  * initialized prior to pushing data.
588  *
589  * returns void.
590  */
591 void
592 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
593 {
594 	/* validate the arguments */
595 	if (!blob) {
596 		BNXT_TF_DBG(ERR, "invalid argument\n");
597 		return; /* failure */
598 	}
599 	blob->encap_swap_idx = blob->write_idx;
600 }
601 
602 /*
603  * Perform the encap buffer swap to 64 bit reversal.
604  *
605  * blob [in] The blob's data to be used for swap.
606  *
607  * returns void.
608  */
609 void
610 ulp_blob_perform_encap_swap(struct ulp_blob *blob)
611 {
612 	uint32_t i, idx = 0, end_idx = 0, roundoff;
613 	uint8_t temp_val_1, temp_val_2;
614 
615 	/* validate the arguments */
616 	if (!blob) {
617 		BNXT_TF_DBG(ERR, "invalid argument\n");
618 		return; /* failure */
619 	}
620 	idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx);
621 	end_idx = ULP_BITS_2_BYTE(blob->write_idx);
622 	roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx));
623 	if (roundoff > end_idx) {
624 		blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx);
625 		end_idx = roundoff;
626 	}
627 	while (idx <= end_idx) {
628 		for (i = 0; i < 4; i = i + 2) {
629 			temp_val_1 = blob->data[idx + i];
630 			temp_val_2 = blob->data[idx + i + 1];
631 			blob->data[idx + i] = blob->data[idx + 6 - i];
632 			blob->data[idx + i + 1] = blob->data[idx + 7 - i];
633 			blob->data[idx + 7 - i] = temp_val_2;
634 			blob->data[idx + 6 - i] = temp_val_1;
635 		}
636 		idx += 8;
637 	}
638 }
639 
640 /*
641  * Perform the blob buffer reversal byte wise.
642  * This api makes the first byte the last and
643  * vice-versa.
644  *
645  * blob [in] The blob's data to be used for swap.
646  *
647  * returns void.
648  */
649 void
650 ulp_blob_perform_byte_reverse(struct ulp_blob *blob)
651 {
652 	uint32_t idx = 0, num = 0;
653 	uint8_t xchar;
654 
655 	/* validate the arguments */
656 	if (!blob) {
657 		BNXT_TF_DBG(ERR, "invalid argument\n");
658 		return; /* failure */
659 	}
660 
661 	num = ULP_BITS_2_BYTE_NR(blob->write_idx);
662 	for (idx = 0; idx < (num / 2); idx++) {
663 		xchar = blob->data[idx];
664 		blob->data[idx] = blob->data[(num - 1) - idx];
665 		blob->data[(num - 1) - idx] = xchar;
666 	}
667 }
668 
669 /*
670  * Perform the blob buffer 64 bit word swap.
671  * This api makes the first 4 bytes the last in
672  * a given 64 bit value and vice-versa.
673  *
674  * blob [in] The blob's data to be used for swap.
675  *
676  * returns void.
677  */
678 void
679 ulp_blob_perform_64B_word_swap(struct ulp_blob *blob)
680 {
681 	uint32_t i, j, num;
682 	uint8_t xchar;
683 	uint32_t word_size = ULP_64B_IN_BYTES / 2;
684 
685 	/* validate the arguments */
686 	if (!blob) {
687 		BNXT_TF_DBG(ERR, "invalid argument\n");
688 		return; /* failure */
689 	}
690 	num = ULP_BITS_2_BYTE(blob->write_idx);
691 	for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
692 		for (j = 0; j < word_size; j++) {
693 			xchar = blob->data[i + j];
694 			blob->data[i + j] = blob->data[i + j + word_size];
695 			blob->data[i + j + word_size] = xchar;
696 		}
697 	}
698 }
699 
700 /*
701  * Perform the blob buffer 64 bit byte swap.
702  * This api makes the first byte the last in
703  * a given 64 bit value and vice-versa.
704  *
705  * blob [in] The blob's data to be used for swap.
706  *
707  * returns void.
708  */
709 void
710 ulp_blob_perform_64B_byte_swap(struct ulp_blob *blob)
711 {
712 	uint32_t i, j, num;
713 	uint8_t xchar;
714 	uint32_t offset = ULP_64B_IN_BYTES - 1;
715 
716 	/* validate the arguments */
717 	if (!blob) {
718 		BNXT_TF_DBG(ERR, "invalid argument\n");
719 		return; /* failure */
720 	}
721 	num = ULP_BITS_2_BYTE(blob->write_idx);
722 	for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
723 		for (j = 0; j < (ULP_64B_IN_BYTES / 2); j++) {
724 			xchar = blob->data[i + j];
725 			blob->data[i + j] = blob->data[i + offset - j];
726 			blob->data[i + offset - j] = xchar;
727 		}
728 	}
729 }
730 
731 /*
732  * Read data from the operand
733  *
734  * operand [in] A pointer to a 16 Byte operand
735  *
736  * val [in/out] The variable to copy the operand to
737  *
738  * bytes [in] The number of bytes to read into val
739  *
740  * returns number of bits read, zero on error
741  */
742 uint16_t
743 ulp_operand_read(uint8_t *operand,
744 		 uint8_t *val,
745 		 uint16_t bytes)
746 {
747 	/* validate the arguments */
748 	if (!operand || !val) {
749 		BNXT_TF_DBG(ERR, "invalid argument\n");
750 		return 0; /* failure */
751 	}
752 	memcpy(val, operand, bytes);
753 	return bytes;
754 }
755 
756 /*
757  * copy the buffer in the encap format which is 2 bytes.
758  * The MSB of the src is placed at the LSB of dst.
759  *
760  * dst [out] The destination buffer
761  * src [in] The source buffer dst
762  * size[in] size of the buffer.
763  * align[in] The alignment is either 8 or 16.
764  */
765 void
766 ulp_encap_buffer_copy(uint8_t *dst,
767 		      const uint8_t *src,
768 		      uint16_t size,
769 		      uint16_t align)
770 {
771 	uint16_t	idx, tmp_size = 0;
772 
773 	do {
774 		dst += tmp_size;
775 		src += tmp_size;
776 		idx = 0;
777 		if (size > align) {
778 			tmp_size = align;
779 			size -= align;
780 		} else {
781 			tmp_size = size;
782 			size = 0;
783 		}
784 		/* copy 2 bytes at a time. Write MSB to LSB */
785 		while ((idx + sizeof(uint16_t)) <= tmp_size) {
786 			memcpy(&dst[idx],
787 			       &src[tmp_size - idx - sizeof(uint16_t)],
788 			       sizeof(uint16_t));
789 			idx += sizeof(uint16_t);
790 		}
791 	} while (size);
792 }
793 
794 /*
795  * Check the buffer is empty
796  *
797  * buf [in] The buffer
798  * size [in] The size of the buffer
799  *
800  */
801 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
802 {
803 	return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
804 }
805 
806 /* Function to check if bitmap is zero.Return 1 on success */
807 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
808 {
809 	while (size-- > 0) {
810 		if (*bitmap != 0)
811 			return 0;
812 		bitmap++;
813 	}
814 	return 1;
815 }
816 
817 /* Function to check if bitmap is ones. Return 1 on success */
818 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
819 {
820 	while (size-- > 0) {
821 		if (*bitmap != 0xFF)
822 			return 0;
823 		bitmap++;
824 	}
825 	return 1;
826 }
827 
828 /* Function to check if bitmap is not zero. Return 1 on success */
829 uint32_t ulp_bitmap_notzero(uint8_t *bitmap, int32_t size)
830 {
831 	while (size-- > 0) {
832 		if (*bitmap != 0)
833 			return 1;
834 		bitmap++;
835 	}
836 	return 0;
837 }
838