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