net/mlx5: fix E-Switch egress mirror flow validation
[dpdk.git] / drivers / net / bnxt / tf_ulp / ulp_utils.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2021 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 }