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