xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_utils.c (revision c569279aded4bb8fdf83b09e0726fa07028dcef8)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2023 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 zero on success
16  */
17 int32_t
18 ulp_regfile_init(struct ulp_regfile *regfile)
19 {
20 	/* validate the arguments */
21 	if (!regfile) {
22 		BNXT_DRV_DBG(ERR, "invalid argument\n");
23 		return -EINVAL;
24 	}
25 	memset(regfile, 0, sizeof(struct ulp_regfile));
26 	return 0; /* 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 zero on success
39  */
40 int32_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_DRV_DBG(ERR, "invalid argument\n");
48 		return -EINVAL;
49 	}
50 
51 	*data = regfile->entry[field].data;
52 	return 0;
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_DRV_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 zero on success
233  * Notes - If bitlen is zero then set it to max.
234  */
235 int32_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_DRV_DBG(ERR, "invalid argument\n");
243 		return -EINVAL;
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 0; /* 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  *
267  * returns zero on success
268  */
269 #define ULP_BLOB_BYTE		8
270 #define ULP_BLOB_BYTE_HEX	0xFF
271 #define BLOB_MASK_CAL(x)	((0xFF << (x)) & 0xFF)
272 int32_t
273 ulp_blob_push(struct ulp_blob *blob,
274 	      uint8_t *data,
275 	      uint32_t datalen)
276 {
277 	uint32_t rc;
278 
279 	/* validate the arguments */
280 	if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
281 		BNXT_DRV_DBG(ERR, "invalid argument\n");
282 		return -EINVAL;
283 	}
284 
285 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
286 		rc = ulp_bs_push_msb(blob->data,
287 				     blob->write_idx,
288 				     datalen,
289 				     data);
290 	else
291 		rc = ulp_bs_push_lsb(blob->data,
292 				     blob->write_idx,
293 				     datalen,
294 				     data);
295 	if (!rc) {
296 		BNXT_DRV_DBG(ERR, "Failed to write blob\n");
297 		return -EINVAL;
298 	}
299 	blob->write_idx += datalen;
300 	return 0;
301 }
302 
303 /*
304  * Insert data into the binary blob at the given offset.
305  *
306  * blob [in] The blob that data is added to.  The blob must
307  * be initialized prior to pushing data.
308  *
309  * offset [in] The offset where the data needs to be inserted.
310  *
311  * data [in/out] A pointer to bytes to be added to the blob.
312  *
313  * datalen [in] The number of bits to be added to the blob.
314  *
315  * The offset of the data is updated after each push of data.
316  *
317  * returns zero on success
318  */
319 int32_t
320 ulp_blob_insert(struct ulp_blob *blob, uint32_t offset,
321 		uint8_t *data, uint32_t datalen)
322 {
323 	uint32_t rc;
324 	uint8_t local_data[BNXT_ULP_FLMP_BLOB_SIZE];
325 	uint16_t mov_len;
326 
327 	/* validate the arguments */
328 	if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx) ||
329 	    offset > blob->write_idx) {
330 		BNXT_DRV_DBG(ERR, "invalid argument\n");
331 		return -EINVAL;
332 	}
333 
334 	mov_len = blob->write_idx - offset;
335 	/* If offset and data len are not 8 bit aligned then return error */
336 	if (ULP_BITS_IS_BYTE_NOT_ALIGNED(offset) ||
337 	    ULP_BITS_IS_BYTE_NOT_ALIGNED(datalen)) {
338 		BNXT_DRV_DBG(ERR, "invalid argument, not aligned\n");
339 		return -EINVAL;
340 	}
341 
342 	/* copy the data so we can move the data */
343 	memcpy(local_data, &blob->data[ULP_BITS_2_BYTE_NR(offset)],
344 	       ULP_BITS_2_BYTE(mov_len));
345 	blob->write_idx = offset;
346 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
347 		rc = ulp_bs_push_msb(blob->data,
348 				     blob->write_idx,
349 				     datalen,
350 				     data);
351 	else
352 		rc = ulp_bs_push_lsb(blob->data,
353 				     blob->write_idx,
354 				     datalen,
355 				     data);
356 	if (!rc) {
357 		BNXT_DRV_DBG(ERR, "Failed to write blob\n");
358 		return -EINVAL;
359 	}
360 	/* copy the previously stored data */
361 	memcpy(&blob->data[ULP_BITS_2_BYTE_NR(offset + datalen)], local_data,
362 	       ULP_BITS_2_BYTE(mov_len));
363 	blob->write_idx += (mov_len + datalen);
364 	return 0;
365 }
366 
367 /*
368  * Add data to the binary blob at the current offset.
369  *
370  * blob [in] The blob that data is added to.  The blob must
371  * be initialized prior to pushing data.
372  *
373  * data [in] 64-bit value to be added to the blob.
374  *
375  * datalen [in] The number of bits to be added to the blob.
376  *
377  * The offset of the data is updated after each push of data.
378  * NULL returned on error, pointer pushed value otherwise.
379  */
380 uint8_t *
381 ulp_blob_push_64(struct ulp_blob *blob,
382 		 uint64_t *data,
383 		 uint32_t datalen)
384 {
385 	uint8_t *val = (uint8_t *)data;
386 	int rc;
387 
388 	int size = (datalen + 7) / 8;
389 
390 	if (!blob || !data ||
391 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
392 		BNXT_DRV_DBG(ERR, "invalid argument\n");
393 		return NULL;
394 	}
395 
396 	rc = ulp_blob_push(blob, &val[8 - size], datalen);
397 	if (rc)
398 		return NULL;
399 
400 	return &val[8 - size];
401 }
402 
403 /*
404  * Add data to the binary blob at the current offset.
405  *
406  * blob [in] The blob that data is added to.  The blob must
407  * be initialized prior to pushing data.
408  *
409  * data [in] 32-bit value to be added to the blob.
410  *
411  * datalen [in] The number of bits to be added to the blob.
412  *
413  * The offset of the data is updated after each push of data.
414  * NULL returned on error, pointer pushed value otherwise.
415  */
416 uint8_t *
417 ulp_blob_push_32(struct ulp_blob *blob,
418 		 uint32_t *data,
419 		 uint32_t datalen)
420 {
421 	uint8_t *val = (uint8_t *)data;
422 	uint32_t rc;
423 	uint32_t size = ULP_BITS_2_BYTE(datalen);
424 
425 	if (!data || size > sizeof(uint32_t)) {
426 		BNXT_DRV_DBG(ERR, "invalid argument\n");
427 		return NULL;
428 	}
429 
430 	rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen);
431 	if (rc)
432 		return NULL;
433 
434 	return &val[sizeof(uint32_t) - size];
435 }
436 
437 /*
438  * Add encap data to the binary blob at the current offset.
439  *
440  * blob [in] The blob that data is added to.  The blob must
441  * be initialized prior to pushing data.
442  *
443  * data [in] value to be added to the blob.
444  *
445  * datalen [in] The number of bits to be added to the blob.
446  *
447  * The offset of the data is updated after each push of data.
448  * NULL returned on error, pointer pushed value otherwise.
449  */
450 int32_t
451 ulp_blob_push_encap(struct ulp_blob *blob,
452 		    uint8_t *data,
453 		    uint32_t datalen)
454 {
455 	uint8_t		*val = (uint8_t *)data;
456 	uint32_t	initial_size, write_size = datalen;
457 	uint32_t	size = 0;
458 
459 	if (!blob || !data ||
460 	    datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
461 		BNXT_DRV_DBG(ERR, "invalid argument\n");
462 		return -1;
463 	}
464 
465 	initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
466 	    (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
467 	while (write_size > 0) {
468 		if (initial_size && write_size > initial_size) {
469 			size = initial_size;
470 			initial_size = 0;
471 		} else if (initial_size && write_size <= initial_size) {
472 			size = write_size;
473 			initial_size = 0;
474 		} else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) {
475 			size = ULP_BYTE_2_BITS(sizeof(uint64_t));
476 		} else {
477 			size = write_size;
478 		}
479 		if (ulp_blob_push(blob, val, size)) {
480 			BNXT_DRV_DBG(ERR, "push field failed\n");
481 			return -1;
482 		}
483 		val += ULP_BITS_2_BYTE(size);
484 		write_size -= size;
485 	}
486 	return datalen;
487 }
488 
489 /*
490  * Adds pad to an initialized blob at the current offset
491  *
492  * blob [in] The blob that data is added to.  The blob must
493  * be initialized prior to pushing data.
494  *
495  * datalen [in] The number of bits of pad to add
496  *
497  * returns the number of pad bits added, -1 on failure
498  */
499 int32_t
500 ulp_blob_pad_push(struct ulp_blob *blob,
501 		  uint32_t datalen)
502 {
503 	if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
504 		BNXT_DRV_DBG(ERR, "Pad too large for blob\n");
505 		return -1;
506 	}
507 
508 	blob->write_idx += datalen;
509 	return datalen;
510 }
511 
512 /*
513  * Adds pad to an initialized blob at the current offset based on
514  * the alignment.
515  *
516  * blob [in] The blob that needs to be aligned
517  *
518  * align [in] Alignment in bits.
519  *
520  * returns the number of pad bits added, -1 on failure
521  */
522 int32_t
523 ulp_blob_pad_align(struct ulp_blob *blob,
524 		   uint32_t align)
525 {
526 	int32_t pad = 0;
527 
528 	pad = RTE_ALIGN(blob->write_idx, align) - blob->write_idx;
529 	if (pad > (int32_t)(blob->bitlen - blob->write_idx)) {
530 		BNXT_DRV_DBG(ERR, "Pad too large for blob\n");
531 		return -1;
532 	}
533 	blob->write_idx += pad;
534 	return pad;
535 }
536 
537 /* Get data from src and put into dst using little-endian format */
538 static void
539 ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
540 {
541 	uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
542 	uint16_t index  = ULP_BITS_2_BYTE_NR(bitpos);
543 	uint8_t mask, partial, shift;
544 
545 	shift = bitoffs;
546 	partial = ULP_BLOB_BYTE - bitoffs;
547 	if (bitoffs + bitlen <= ULP_BLOB_BYTE) {
548 		mask = ((1 << bitlen) - 1) << shift;
549 		*dst = (src[index] & mask) >> shift;
550 	} else {
551 		mask = ((1 << partial) - 1) << shift;
552 		*dst = (src[index] & mask) >> shift;
553 		index++;
554 		partial = bitlen - partial;
555 		mask = ((1 << partial) - 1);
556 		*dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs);
557 	}
558 }
559 
560 /*
561  * Get data from the byte array in Little endian format.
562  *
563  * src [in] The byte array where data is extracted from
564  *
565  * dst [out] The byte array where data is pulled into
566  *
567  * size [in] The size of dst array in bytes
568  *
569  * offset [in] The offset where data is pulled
570  *
571  * len [in] The number of bits to be extracted from the data array
572  *
573  * returns None.
574  */
575 void
576 ulp_bs_pull_lsb(uint8_t *src, uint8_t *dst, uint32_t size,
577 		uint32_t offset, uint32_t len)
578 {
579 	uint32_t idx;
580 	uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
581 
582 	/* iterate bytewise to get data */
583 	for (idx = 0; idx < cnt; idx++) {
584 		ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE,
585 			       &dst[size - 1 - idx]);
586 		offset += ULP_BLOB_BYTE;
587 		len -= ULP_BLOB_BYTE;
588 	}
589 
590 	/* Extract the last reminder data that is not 8 byte boundary */
591 	if (len)
592 		ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]);
593 }
594 
595 /* Get data from src and put into dst using big-endian format */
596 static void
597 ulp_bs_get_msb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
598 {
599 	uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
600 	uint16_t index  = ULP_BITS_2_BYTE_NR(bitpos);
601 	uint8_t mask;
602 	int32_t shift;
603 
604 	shift = ULP_BLOB_BYTE - bitoffs - bitlen;
605 	if (shift >= 0) {
606 		mask = 0xFF >> -bitlen;
607 		*dst = (src[index] >> shift) & mask;
608 	} else {
609 		*dst = (src[index] & (0xFF >> bitoffs)) << -shift;
610 		*dst |= src[index + 1] >> -shift;
611 	}
612 }
613 
614 /*
615  * Get data from the byte array in Big endian format.
616  *
617  * src [in] The byte array where data is extracted from
618  *
619  * dst [out] The byte array where data is pulled into
620  *
621  * offset [in] The offset where data is pulled
622  *
623  * len [in] The number of bits to be extracted from the data array
624  *
625  * returns None.
626  */
627 void
628 ulp_bs_pull_msb(uint8_t *src, uint8_t *dst,
629 		uint32_t offset, uint32_t len)
630 {
631 	uint32_t idx;
632 	uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
633 
634 	/* iterate bytewise to get data */
635 	for (idx = 0; idx < cnt; idx++) {
636 		ulp_bs_get_msb(src, offset, ULP_BLOB_BYTE, &dst[idx]);
637 		offset += ULP_BLOB_BYTE;
638 		len -= ULP_BLOB_BYTE;
639 	}
640 
641 	/* Extract the last reminder data that is not 8 byte boundary */
642 	if (len)
643 		ulp_bs_get_msb(src, offset, len, &dst[idx]);
644 }
645 
646 /*
647  * Extract data from the binary blob using given offset.
648  *
649  * blob [in] The blob that data is extracted from. The blob must
650  * be initialized prior to pulling data.
651  *
652  * data [in] A pointer to put the data.
653  * data_size [in] size of the data buffer in bytes.
654  *offset [in] - Offset in the blob to extract the data in bits format.
655  * len [in] The number of bits to be pulled from the blob.
656  *
657  * Output: zero on success, -1 on failure
658  */
659 int32_t
660 ulp_blob_pull(struct ulp_blob *blob, uint8_t *data, uint32_t data_size,
661 	      uint16_t offset, uint16_t len)
662 {
663 	/* validate the arguments */
664 	if (!blob || (offset + len) > blob->bitlen ||
665 	    ULP_BYTE_2_BITS(data_size) < len) {
666 		BNXT_DRV_DBG(ERR, "invalid argument\n");
667 		return -1; /* failure */
668 	}
669 
670 	if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
671 		ulp_bs_pull_msb(blob->data, data, offset, len);
672 	else
673 		ulp_bs_pull_lsb(blob->data, data, data_size, offset, len);
674 	return 0;
675 }
676 
677 /*
678  * Get the data portion of the binary blob.
679  *
680  * blob [in] The blob's data to be retrieved. The blob must be
681  * initialized prior to pushing data.
682  *
683  * datalen [out] The number of bits that are filled.
684  *
685  * Returns a byte array of the blob data or NULL on error.
686  */
687 uint8_t *
688 ulp_blob_data_get(struct ulp_blob *blob,
689 		  uint16_t *datalen)
690 {
691 	/* validate the arguments */
692 	if (!blob) {
693 		BNXT_DRV_DBG(ERR, "invalid argument\n");
694 		return NULL; /* failure */
695 	}
696 	*datalen = blob->write_idx;
697 	return blob->data;
698 }
699 
700 /*
701  * Get the data length of the binary blob.
702  *
703  * blob [in] The blob's data len to be retrieved.
704  *
705  * returns length of the binary blob
706  */
707 uint16_t
708 ulp_blob_data_len_get(struct ulp_blob *blob)
709 {
710 	/* validate the arguments */
711 	if (!blob) {
712 		BNXT_DRV_DBG(ERR, "invalid argument\n");
713 		return 0; /* failure */
714 	}
715 	return blob->write_idx;
716 }
717 
718 /*
719  * Set the encap swap start index of the binary blob.
720  *
721  * blob [in] The blob's data to be retrieved. The blob must be
722  * initialized prior to pushing data.
723  *
724  * returns void.
725  */
726 void
727 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
728 {
729 	/* validate the arguments */
730 	if (!blob) {
731 		BNXT_DRV_DBG(ERR, "invalid argument\n");
732 		return; /* failure */
733 	}
734 	blob->encap_swap_idx = blob->write_idx;
735 }
736 
737 /*
738  * Perform the encap buffer swap to 64 bit reversal.
739  *
740  * blob [in] The blob's data to be used for swap.
741  *
742  * returns void.
743  */
744 void
745 ulp_blob_perform_encap_swap(struct ulp_blob *blob)
746 {
747 	uint32_t i, idx = 0, end_idx = 0, roundoff;
748 	uint8_t temp_val_1, temp_val_2;
749 
750 	/* validate the arguments */
751 	if (!blob) {
752 		BNXT_DRV_DBG(ERR, "invalid argument\n");
753 		return; /* failure */
754 	}
755 	idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx);
756 	end_idx = ULP_BITS_2_BYTE(blob->write_idx);
757 	roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx));
758 	if (roundoff > end_idx) {
759 		blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx);
760 		end_idx = roundoff;
761 	}
762 	while (idx <= end_idx) {
763 		for (i = 0; i < 4; i = i + 2) {
764 			temp_val_1 = blob->data[idx + i];
765 			temp_val_2 = blob->data[idx + i + 1];
766 			blob->data[idx + i] = blob->data[idx + 6 - i];
767 			blob->data[idx + i + 1] = blob->data[idx + 7 - i];
768 			blob->data[idx + 7 - i] = temp_val_2;
769 			blob->data[idx + 6 - i] = temp_val_1;
770 		}
771 		idx += 8;
772 	}
773 }
774 
775 /*
776  * Perform the blob buffer reversal byte wise.
777  * This api makes the first byte the last and
778  * vice-versa.
779  *
780  * blob [in] The blob's data to be used for swap.
781  * chunk_size[in] the swap is done within the chunk in bytes
782  *
783  * returns void.
784  */
785 void
786 ulp_blob_perform_byte_reverse(struct ulp_blob *blob,
787 			      uint32_t chunk_size)
788 {
789 	uint32_t idx = 0, jdx = 0, num = 0;
790 	uint8_t xchar;
791 	uint8_t *buff;
792 
793 	/* validate the arguments */
794 	if (!blob) {
795 		BNXT_DRV_DBG(ERR, "invalid argument\n");
796 		return; /* failure */
797 	}
798 
799 	buff = blob->data;
800 	num = ULP_BITS_2_BYTE(blob->write_idx) / chunk_size;
801 	for (idx = 0; idx < num; idx++) {
802 		for (jdx = 0; jdx < chunk_size / 2; jdx++) {
803 			xchar = buff[jdx];
804 			buff[jdx] = buff[(chunk_size - 1) - jdx];
805 			buff[(chunk_size - 1) - jdx] = xchar;
806 		}
807 		buff += chunk_size;
808 	}
809 }
810 
811 /*
812  * Perform the blob buffer 64 bit word swap.
813  * This api makes the first 4 bytes the last in
814  * a given 64 bit value and vice-versa.
815  *
816  * blob [in] The blob's data to be used for swap.
817  *
818  * returns void.
819  */
820 void
821 ulp_blob_perform_64B_word_swap(struct ulp_blob *blob)
822 {
823 	uint32_t i, j, num;
824 	uint8_t xchar;
825 	uint32_t word_size = ULP_64B_IN_BYTES / 2;
826 
827 	/* validate the arguments */
828 	if (!blob) {
829 		BNXT_DRV_DBG(ERR, "invalid argument\n");
830 		return; /* failure */
831 	}
832 	num = ULP_BITS_2_BYTE(blob->write_idx);
833 	for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
834 		for (j = 0; j < word_size; j++) {
835 			xchar = blob->data[i + j];
836 			blob->data[i + j] = blob->data[i + j + word_size];
837 			blob->data[i + j + word_size] = xchar;
838 		}
839 	}
840 }
841 
842 /*
843  * Perform the blob buffer 64 bit byte swap.
844  * This api makes the first byte the last in
845  * a given 64 bit value and vice-versa.
846  *
847  * blob [in] The blob's data to be used for swap.
848  *
849  * returns void.
850  */
851 void
852 ulp_blob_perform_64B_byte_swap(struct ulp_blob *blob)
853 {
854 	uint32_t i, j, num;
855 	uint8_t xchar;
856 	uint32_t offset = ULP_64B_IN_BYTES - 1;
857 
858 	/* validate the arguments */
859 	if (!blob) {
860 		BNXT_DRV_DBG(ERR, "invalid argument\n");
861 		return; /* failure */
862 	}
863 	num = ULP_BITS_2_BYTE(blob->write_idx);
864 	for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
865 		for (j = 0; j < (ULP_64B_IN_BYTES / 2); j++) {
866 			xchar = blob->data[i + j];
867 			blob->data[i + j] = blob->data[i + offset - j];
868 			blob->data[i + offset - j] = xchar;
869 		}
870 	}
871 }
872 
873 static int32_t
874 ulp_blob_msb_block_merge(struct ulp_blob *dst, struct ulp_blob *src,
875 			 uint32_t block_size, uint32_t pad)
876 {
877 	uint32_t i, k, write_bytes, remaining;
878 	uint16_t num;
879 	uint8_t *src_buf = ulp_blob_data_get(src, &num);
880 	uint8_t bluff;
881 
882 	for (i = 0; i < num;) {
883 		if (((dst->write_idx % block_size) + (num - i)) > block_size)
884 			write_bytes = block_size -
885 				(dst->write_idx % block_size);
886 		else
887 			write_bytes = num - i;
888 		for (k = 0; k < ULP_BITS_2_BYTE_NR(write_bytes); k++) {
889 			ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE,
890 				       *src_buf);
891 			dst->write_idx += ULP_BLOB_BYTE;
892 			src_buf++;
893 		}
894 		remaining = write_bytes % ULP_BLOB_BYTE;
895 		if (remaining) {
896 			bluff = (*src_buf) & ((uint8_t)-1 <<
897 					      (ULP_BLOB_BYTE - remaining));
898 			ulp_bs_put_msb(dst->data, dst->write_idx,
899 				       ULP_BLOB_BYTE, bluff);
900 			dst->write_idx += remaining;
901 		}
902 		if (write_bytes != (num - i)) {
903 			/* add the padding */
904 			ulp_blob_pad_push(dst, pad);
905 			if (remaining) {
906 				ulp_bs_put_msb(dst->data, dst->write_idx,
907 					       ULP_BLOB_BYTE - remaining,
908 					       *src_buf);
909 				dst->write_idx += ULP_BLOB_BYTE - remaining;
910 				src_buf++;
911 			}
912 		}
913 		i += write_bytes;
914 	}
915 	return 0;
916 }
917 
918 /*
919  * Perform the blob buffer merge.
920  * This api makes the src blob merged to the dst blob.
921  * The block size and pad size help in padding the dst blob
922  *
923  * dst [in] The destination blob, the blob to be merged.
924  * src [in] The src blob.
925  * block_size [in] The size of the block in bytes after which padding gets
926  *                 applied.
927  * pad [in] The size of the pad to be applied.
928  *
929  * returns 0 on success.
930  */
931 int32_t
932 ulp_blob_block_merge(struct ulp_blob *dst, struct ulp_blob *src,
933 		     uint32_t block_size, uint32_t pad)
934 {
935 	if (dst->byte_order == BNXT_ULP_BYTE_ORDER_BE &&
936 	    src->byte_order == BNXT_ULP_BYTE_ORDER_BE)
937 		return ulp_blob_msb_block_merge(dst, src, block_size, pad);
938 
939 	BNXT_DRV_DBG(ERR, "block merge not implemented yet\n");
940 	return -EINVAL;
941 }
942 
943 int32_t
944 ulp_blob_append(struct ulp_blob *dst, struct ulp_blob *src,
945 		uint16_t src_offset, uint16_t src_len)
946 {
947 	uint32_t k, remaining = 0;
948 	uint16_t num;
949 	uint8_t bluff;
950 	uint8_t *src_buf = ulp_blob_data_get(src, &num);
951 
952 	if ((src_offset + src_len) > num)
953 		return -EINVAL;
954 
955 	/* Only supporting BE for now */
956 	if (src->byte_order != BNXT_ULP_BYTE_ORDER_BE ||
957 	    dst->byte_order != BNXT_ULP_BYTE_ORDER_BE)
958 		return -EINVAL;
959 
960 	/* Handle if the source offset is not on a byte boundary */
961 	remaining = src_offset % ULP_BLOB_BYTE;
962 	if (remaining) {
963 		bluff = src_buf[src_offset / ULP_BLOB_BYTE] & ((uint8_t)-1 >>
964 				      (ULP_BLOB_BYTE - remaining));
965 		ulp_bs_put_msb(dst->data, dst->write_idx,
966 			       ULP_BLOB_BYTE, bluff);
967 		dst->write_idx += remaining;
968 		src_offset += remaining;
969 	}
970 
971 	src_buf += ULP_BITS_2_BYTE_NR(src_offset);
972 
973 	/* Push the byte aligned pieces */
974 	for (k = 0; k < ULP_BITS_2_BYTE_NR(src_len); k++) {
975 		ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE,
976 			       *src_buf);
977 		dst->write_idx += ULP_BLOB_BYTE;
978 		src_buf++;
979 	}
980 
981 	/* Handle the remaining if length is not a byte boundary */
982 	if (src_len > remaining)
983 		remaining = (src_len - remaining) % ULP_BLOB_BYTE;
984 	else
985 		remaining = 0;
986 	if (remaining) {
987 		bluff = (*src_buf) & ((uint8_t)-1 <<
988 				      (ULP_BLOB_BYTE - remaining));
989 		ulp_bs_put_msb(dst->data, dst->write_idx,
990 			       ULP_BLOB_BYTE, bluff);
991 		dst->write_idx += remaining;
992 	}
993 
994 	return 0;
995 }
996 
997 /*
998  * Perform the blob buffer copy.
999  * This api makes the src blob merged to the dst blob.
1000  *
1001  * dst [in] The destination blob, the blob to be merged.
1002  * src [in] The src blob.
1003  *
1004  * returns 0 on success.
1005  */
1006 int32_t
1007 ulp_blob_buffer_copy(struct ulp_blob *dst, struct ulp_blob *src)
1008 {
1009 	if ((dst->write_idx + src->write_idx) > dst->bitlen) {
1010 		BNXT_DRV_DBG(ERR, "source buffer too large\n");
1011 		return -EINVAL;
1012 	}
1013 	if (ULP_BITS_IS_BYTE_NOT_ALIGNED(dst->write_idx) ||
1014 	    ULP_BITS_IS_BYTE_NOT_ALIGNED(src->write_idx)) {
1015 		BNXT_DRV_DBG(ERR, "source buffer is not aligned\n");
1016 		return -EINVAL;
1017 	}
1018 	memcpy(&dst->data[ULP_BITS_2_BYTE_NR(dst->write_idx)],
1019 	       src->data, ULP_BITS_2_BYTE_NR(src->write_idx));
1020 	dst->write_idx += src->write_idx;
1021 	return 0;
1022 }
1023 
1024 /*
1025  * Read data from the operand
1026  *
1027  * operand [in] A pointer to a 16 Byte operand
1028  *
1029  * val [in/out] The variable to copy the operand to
1030  *
1031  * bytes [in] The number of bytes to read into val
1032  *
1033  * returns zero on success.
1034  */
1035 int32_t
1036 ulp_operand_read(uint8_t *operand,
1037 		 uint8_t *val,
1038 		 uint16_t bytes)
1039 {
1040 	/* validate the arguments */
1041 	if (!operand || !val) {
1042 		BNXT_DRV_DBG(ERR, "invalid argument\n");
1043 		return -EINVAL;
1044 	}
1045 	memcpy(val, operand, bytes);
1046 	return 0;
1047 }
1048 
1049 /*
1050  * Check the buffer is empty
1051  *
1052  * buf [in] The buffer
1053  * size [in] The size of the buffer
1054  *
1055  */
1056 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
1057 {
1058 	return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
1059 }
1060 
1061 /* Function to check if bitmap is zero.Return 1 on success */
1062 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
1063 {
1064 	while (size-- > 0) {
1065 		if (*bitmap != 0)
1066 			return 0;
1067 		bitmap++;
1068 	}
1069 	return 1;
1070 }
1071 
1072 /* Function to check if bitmap is ones. Return 1 on success */
1073 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
1074 {
1075 	while (size-- > 0) {
1076 		if (*bitmap != 0xFF)
1077 			return 0;
1078 		bitmap++;
1079 	}
1080 	return 1;
1081 }
1082 
1083 /* Function to check if bitmap is not zero. Return 1 on success */
1084 uint32_t ulp_bitmap_notzero(const uint8_t *bitmap, int32_t size)
1085 {
1086 	while (size-- > 0) {
1087 		if (*bitmap != 0)
1088 			return 1;
1089 		bitmap++;
1090 	}
1091 	return 0;
1092 }
1093 
1094 /* returns 0 if input is power of 2 */
1095 int32_t ulp_util_is_power_of_2(uint64_t x)
1096 {
1097 	if (((x - 1) & x))
1098 		return -1;
1099 	return 0;
1100 }
1101