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