1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2014-2021 Broadcom
7 #include "bnxt_tf_common.h"
10 * Initialize the regfile structure for writing
12 * regfile [in] Ptr to a regfile instance
14 * returns 0 on error or 1 on success
17 ulp_regfile_init(struct ulp_regfile *regfile)
19 /* validate the arguments */
21 BNXT_TF_DBG(ERR, "invalid argument\n");
22 return 0; /* failure */
24 memset(regfile, 0, sizeof(struct ulp_regfile));
25 return 1; /* Success */
29 * Read a value from the regfile
31 * regfile [in] The regfile instance. Must be initialized prior to being used
33 * field [in] The field to be read within the regfile.
37 * returns size, zero on failure
40 ulp_regfile_read(struct ulp_regfile *regfile,
41 enum bnxt_ulp_regfile_index field,
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 */
50 *data = regfile->entry[field].data;
55 * Write a value to the regfile
57 * regfile [in] The regfile instance. Must be initialized prior to being used
59 * field [in] The field to be written within the regfile.
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.
64 * size [in] The size in bytes of the value beingritten into this
70 ulp_regfile_write(struct ulp_regfile *regfile,
71 enum bnxt_ulp_regfile_index field,
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 */
80 regfile->entry[field].data = data;
81 return sizeof(data); /* Success */
85 ulp_bs_put_msb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val)
87 uint8_t bitoffs = bitpos % 8;
88 uint16_t index = bitpos / 8;
94 mask = ((uint8_t)-1 >> (8 - bitlen));
95 shift = 8 - bitoffs - bitlen;
99 tmp &= ~(mask << shift);
103 tmp &= ~((uint8_t)-1 >> bitoffs);
104 tmp |= val >> -shift;
108 tmp &= ((uint8_t)-1 >> (bitlen - (8 - bitoffs)));
109 tmp |= val << (8 + shift);
115 ulp_bs_put_lsb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val)
117 uint8_t bitoffs = bitpos % 8;
118 uint16_t index = bitpos / 8;
127 if (bitoffs + bitlen <= 8) {
128 mask = ((1 << bitlen) - 1) << shift;
130 tmp |= ((val << shift) & mask);
133 partial = 8 - bitoffs;
134 mask = ((1 << partial) - 1) << shift;
136 tmp |= ((val << shift) & mask);
140 partial = bitlen - partial;
141 mask = ((1 << partial) - 1);
150 * Add data to the byte array in Little endian format.
152 * bs [in] The byte array where data is pushed
154 * pos [in] The offset where data is pushed
156 * len [in] The number of bits to be added to the data array.
158 * val [in] The data to be added to the data array.
160 * returns the number of bits pushed.
163 ulp_bs_push_lsb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
169 if (cnt > 0 && !(len % 8))
172 for (i = 0; i < cnt; i++) {
173 ulp_bs_put_lsb(bs, pos, 8, val[cnt - i]);
178 /* Handle the remainder bits */
180 ulp_bs_put_lsb(bs, pos, tlen, val[0]);
185 * Add data to the byte array in Big endian format.
187 * bs [in] The byte array where data is pushed
189 * pos [in] The offset where data is pushed
191 * len [in] The number of bits to be added to the data array.
193 * val [in] The data to be added to the data array.
195 * returns the number of bits pushed.
198 ulp_bs_push_msb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
201 int cnt = (len + 7) / 8;
204 /* Handle any remainder bits */
210 ulp_bs_put_msb(bs, pos, tmp, val[0]);
215 for (i = 1; i < cnt; i++) {
216 ulp_bs_put_msb(bs, pos, 8, val[i]);
225 * Initializes the blob structure for creating binary blob
227 * blob [in] The blob to be initialized
229 * bitlen [in] The bit length of the blob
231 * order [in] The byte order for the blob. Currently only supporting
232 * big endian. All fields are packed with this order.
234 * returns 0 on error or 1 on success
237 ulp_blob_init(struct ulp_blob *blob,
239 enum bnxt_ulp_byte_order order)
241 /* validate the arguments */
242 if (!blob || bitlen > (8 * sizeof(blob->data))) {
243 BNXT_TF_DBG(ERR, "invalid argument\n");
244 return 0; /* failure */
246 blob->bitlen = bitlen;
247 blob->byte_order = order;
249 memset(blob->data, 0, sizeof(blob->data));
250 return 1; /* Success */
254 * Add data to the binary blob at the current offset.
256 * blob [in] The blob that data is added to. The blob must
257 * be initialized prior to pushing data.
259 * data [in] A pointer to bytes to be added to the blob.
261 * datalen [in] The number of bits to be added to the blob.
263 * The offset of the data is updated after each push of data.
264 * NULL returned on error.
266 #define ULP_BLOB_BYTE 8
267 #define ULP_BLOB_BYTE_HEX 0xFF
268 #define BLOB_MASK_CAL(x) ((0xFF << (x)) & 0xFF)
270 ulp_blob_push(struct ulp_blob *blob,
276 /* validate the arguments */
277 if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
278 BNXT_TF_DBG(ERR, "invalid argument\n");
279 return 0; /* failure */
282 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
283 rc = ulp_bs_push_msb(blob->data,
288 rc = ulp_bs_push_lsb(blob->data,
293 BNXT_TF_DBG(ERR, "Failed ro write blob\n");
296 blob->write_idx += datalen;
301 * Insert data into the binary blob at the given offset.
303 * blob [in] The blob that data is added to. The blob must
304 * be initialized prior to pushing data.
306 * offset [in] The offset where the data needs to be inserted.
308 * data [in/out] A pointer to bytes to be added to the blob.
310 * datalen [in] The number of bits to be added to the blob.
312 * The offset of the data is updated after each push of data.
313 * NULL returned on error.
316 ulp_blob_insert(struct ulp_blob *blob, uint32_t offset,
317 uint8_t *data, uint32_t datalen)
320 uint8_t local_data[BNXT_ULP_FLMP_BLOB_SIZE];
323 /* validate the arguments */
324 if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx) ||
325 offset > blob->write_idx) {
326 BNXT_TF_DBG(ERR, "invalid argument\n");
327 return 0; /* failure */
330 mov_len = blob->write_idx - offset;
331 /* If offset and data len are not 8 bit aligned then return error */
332 if (ULP_BITS_IS_BYTE_NOT_ALIGNED(offset) ||
333 ULP_BITS_IS_BYTE_NOT_ALIGNED(datalen)) {
334 BNXT_TF_DBG(ERR, "invalid argument, not aligned\n");
335 return 0; /* failure */
338 /* copy the data so we can move the data */
339 memcpy(local_data, &blob->data[ULP_BITS_2_BYTE_NR(offset)],
340 ULP_BITS_2_BYTE(mov_len));
341 blob->write_idx = offset;
342 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
343 rc = ulp_bs_push_msb(blob->data,
348 rc = ulp_bs_push_lsb(blob->data,
353 BNXT_TF_DBG(ERR, "Failed ro write blob\n");
356 /* copy the previously stored data */
357 memcpy(&blob->data[ULP_BITS_2_BYTE_NR(offset + datalen)], local_data,
358 ULP_BITS_2_BYTE(mov_len));
359 blob->write_idx += (mov_len + datalen);
364 * Add data to the binary blob at the current offset.
366 * blob [in] The blob that data is added to. The blob must
367 * be initialized prior to pushing data.
369 * data [in] 64-bit value to be added to the blob.
371 * datalen [in] The number of bits to be added to the blob.
373 * The offset of the data is updated after each push of data.
374 * NULL returned on error, pointer pushed value otherwise.
377 ulp_blob_push_64(struct ulp_blob *blob,
381 uint8_t *val = (uint8_t *)data;
384 int size = (datalen + 7) / 8;
386 if (!blob || !data ||
387 datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
388 BNXT_TF_DBG(ERR, "invalid argument\n");
392 rc = ulp_blob_push(blob, &val[8 - size], datalen);
396 return &val[8 - size];
400 * Add data to the binary blob at the current offset.
402 * blob [in] The blob that data is added to. The blob must
403 * be initialized prior to pushing data.
405 * data [in] 32-bit value to be added to the blob.
407 * datalen [in] The number of bits to be added ot the blob.
409 * The offset of the data is updated after each push of data.
410 * NULL returned on error, pointer pushed value otherwise.
413 ulp_blob_push_32(struct ulp_blob *blob,
417 uint8_t *val = (uint8_t *)data;
419 uint32_t size = ULP_BITS_2_BYTE(datalen);
421 if (!data || size > sizeof(uint32_t)) {
422 BNXT_TF_DBG(ERR, "invalid argument\n");
426 rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen);
430 return &val[sizeof(uint32_t) - size];
434 * Add encap data to the binary blob at the current offset.
436 * blob [in] The blob that data is added to. The blob must
437 * be initialized prior to pushing data.
439 * data [in] value to be added to the blob.
441 * datalen [in] The number of bits to be added to the blob.
443 * The offset of the data is updated after each push of data.
444 * NULL returned on error, pointer pushed value otherwise.
447 ulp_blob_push_encap(struct ulp_blob *blob,
451 uint8_t *val = (uint8_t *)data;
452 uint32_t initial_size, write_size = datalen;
455 if (!blob || !data ||
456 datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
457 BNXT_TF_DBG(ERR, "invalid argument\n");
461 initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
462 (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
463 while (write_size > 0) {
464 if (initial_size && write_size > initial_size) {
467 } else if (initial_size && write_size <= initial_size) {
470 } else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) {
471 size = ULP_BYTE_2_BITS(sizeof(uint64_t));
475 if (!ulp_blob_push(blob, val, size)) {
476 BNXT_TF_DBG(ERR, "push field failed\n");
479 val += ULP_BITS_2_BYTE(size);
486 * Adds pad to an initialized blob at the current offset
488 * blob [in] The blob that data is added to. The blob must
489 * be initialized prior to pushing data.
491 * datalen [in] The number of bits of pad to add
493 * returns the number of pad bits added, -1 on failure
496 ulp_blob_pad_push(struct ulp_blob *blob,
499 if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
500 BNXT_TF_DBG(ERR, "Pad too large for blob\n");
504 blob->write_idx += datalen;
508 /* Get data from src and put into dst using little-endian format */
510 ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
512 uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
513 uint16_t index = ULP_BITS_2_BYTE_NR(bitpos);
514 uint8_t mask, partial, shift;
517 partial = ULP_BLOB_BYTE - bitoffs;
518 if (bitoffs + bitlen <= ULP_BLOB_BYTE) {
519 mask = ((1 << bitlen) - 1) << shift;
520 *dst = (src[index] & mask) >> shift;
522 mask = ((1 << partial) - 1) << shift;
523 *dst = (src[index] & mask) >> shift;
525 partial = bitlen - partial;
526 mask = ((1 << partial) - 1);
527 *dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs);
532 * Get data from the byte array in Little endian format.
534 * src [in] The byte array where data is extracted from
536 * dst [out] The byte array where data is pulled into
538 * size [in] The size of dst array in bytes
540 * offset [in] The offset where data is pulled
542 * len [in] The number of bits to be extracted from the data array
547 ulp_bs_pull_lsb(uint8_t *src, uint8_t *dst, uint32_t size,
548 uint32_t offset, uint32_t len)
551 uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
553 /* iterate bytewise to get data */
554 for (idx = 0; idx < cnt; idx++) {
555 ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE,
556 &dst[size - 1 - idx]);
557 offset += ULP_BLOB_BYTE;
558 len -= ULP_BLOB_BYTE;
561 /* Extract the last reminder data that is not 8 byte boundary */
563 ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]);
566 /* Get data from src and put into dst using big-endian format */
568 ulp_bs_get_msb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
570 uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
571 uint16_t index = ULP_BITS_2_BYTE_NR(bitpos);
575 shift = ULP_BLOB_BYTE - bitoffs - bitlen;
577 mask = 0xFF >> -bitlen;
578 *dst = (src[index] >> shift) & mask;
580 *dst = (src[index] & (0xFF >> bitoffs)) << -shift;
581 *dst |= src[index + 1] >> -shift;
586 * Get data from the byte array in Big endian format.
588 * src [in] The byte array where data is extracted from
590 * dst [out] The byte array where data is pulled into
592 * offset [in] The offset where data is pulled
594 * len [in] The number of bits to be extracted from the data array
599 ulp_bs_pull_msb(uint8_t *src, uint8_t *dst,
600 uint32_t offset, uint32_t len)
603 uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
605 /* iterate bytewise to get data */
606 for (idx = 0; idx < cnt; idx++) {
607 ulp_bs_get_msb(src, offset, ULP_BLOB_BYTE, &dst[idx]);
608 offset += ULP_BLOB_BYTE;
609 len -= ULP_BLOB_BYTE;
612 /* Extract the last reminder data that is not 8 byte boundary */
614 ulp_bs_get_msb(src, offset, len, &dst[idx]);
618 * Extract data from the binary blob using given offset.
620 * blob [in] The blob that data is extracted from. The blob must
621 * be initialized prior to pulling data.
623 * data [in] A pointer to put the data.
624 * data_size [in] size of the data buffer in bytes.
625 *offset [in] - Offset in the blob to extract the data in bits format.
626 * len [in] The number of bits to be pulled from the blob.
628 * Output: zero on success, -1 on failure
631 ulp_blob_pull(struct ulp_blob *blob, uint8_t *data, uint32_t data_size,
632 uint16_t offset, uint16_t len)
634 /* validate the arguments */
635 if (!blob || (offset + len) > blob->bitlen ||
636 ULP_BYTE_2_BITS(data_size) < len) {
637 BNXT_TF_DBG(ERR, "invalid argument\n");
638 return -1; /* failure */
641 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
642 ulp_bs_pull_msb(blob->data, data, offset, len);
644 ulp_bs_pull_lsb(blob->data, data, data_size, offset, len);
649 * Get the data portion of the binary blob.
651 * blob [in] The blob's data to be retrieved. The blob must be
652 * initialized prior to pushing data.
654 * datalen [out] The number of bits to that are filled.
656 * returns a byte array of the blob data. Returns NULL on error.
659 ulp_blob_data_get(struct ulp_blob *blob,
662 /* validate the arguments */
664 BNXT_TF_DBG(ERR, "invalid argument\n");
665 return NULL; /* failure */
667 *datalen = blob->write_idx;
672 * Set the encap swap start index of the binary blob.
674 * blob [in] The blob's data to be retrieved. The blob must be
675 * initialized prior to pushing data.
680 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
682 /* validate the arguments */
684 BNXT_TF_DBG(ERR, "invalid argument\n");
685 return; /* failure */
687 blob->encap_swap_idx = blob->write_idx;
691 * Perform the encap buffer swap to 64 bit reversal.
693 * blob [in] The blob's data to be used for swap.
698 ulp_blob_perform_encap_swap(struct ulp_blob *blob)
700 uint32_t i, idx = 0, end_idx = 0, roundoff;
701 uint8_t temp_val_1, temp_val_2;
703 /* validate the arguments */
705 BNXT_TF_DBG(ERR, "invalid argument\n");
706 return; /* failure */
708 idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx);
709 end_idx = ULP_BITS_2_BYTE(blob->write_idx);
710 roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx));
711 if (roundoff > end_idx) {
712 blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx);
715 while (idx <= end_idx) {
716 for (i = 0; i < 4; i = i + 2) {
717 temp_val_1 = blob->data[idx + i];
718 temp_val_2 = blob->data[idx + i + 1];
719 blob->data[idx + i] = blob->data[idx + 6 - i];
720 blob->data[idx + i + 1] = blob->data[idx + 7 - i];
721 blob->data[idx + 7 - i] = temp_val_2;
722 blob->data[idx + 6 - i] = temp_val_1;
729 * Perform the blob buffer reversal byte wise.
730 * This api makes the first byte the last and
733 * blob [in] The blob's data to be used for swap.
738 ulp_blob_perform_byte_reverse(struct ulp_blob *blob)
740 uint32_t idx = 0, num = 0;
743 /* validate the arguments */
745 BNXT_TF_DBG(ERR, "invalid argument\n");
746 return; /* failure */
749 num = ULP_BITS_2_BYTE_NR(blob->write_idx);
750 for (idx = 0; idx < (num / 2); idx++) {
751 xchar = blob->data[idx];
752 blob->data[idx] = blob->data[(num - 1) - idx];
753 blob->data[(num - 1) - idx] = xchar;
758 * Perform the blob buffer 64 bit word swap.
759 * This api makes the first 4 bytes the last in
760 * a given 64 bit value and vice-versa.
762 * blob [in] The blob's data to be used for swap.
767 ulp_blob_perform_64B_word_swap(struct ulp_blob *blob)
771 uint32_t word_size = ULP_64B_IN_BYTES / 2;
773 /* validate the arguments */
775 BNXT_TF_DBG(ERR, "invalid argument\n");
776 return; /* failure */
778 num = ULP_BITS_2_BYTE(blob->write_idx);
779 for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
780 for (j = 0; j < word_size; j++) {
781 xchar = blob->data[i + j];
782 blob->data[i + j] = blob->data[i + j + word_size];
783 blob->data[i + j + word_size] = xchar;
789 * Perform the blob buffer 64 bit byte swap.
790 * This api makes the first byte the last in
791 * a given 64 bit value and vice-versa.
793 * blob [in] The blob's data to be used for swap.
798 ulp_blob_perform_64B_byte_swap(struct ulp_blob *blob)
802 uint32_t offset = ULP_64B_IN_BYTES - 1;
804 /* validate the arguments */
806 BNXT_TF_DBG(ERR, "invalid argument\n");
807 return; /* failure */
809 num = ULP_BITS_2_BYTE(blob->write_idx);
810 for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
811 for (j = 0; j < (ULP_64B_IN_BYTES / 2); j++) {
812 xchar = blob->data[i + j];
813 blob->data[i + j] = blob->data[i + offset - j];
814 blob->data[i + offset - j] = xchar;
820 * Read data from the operand
822 * operand [in] A pointer to a 16 Byte operand
824 * val [in/out] The variable to copy the operand to
826 * bytes [in] The number of bytes to read into val
828 * returns number of bits read, zero on error
831 ulp_operand_read(uint8_t *operand,
835 /* validate the arguments */
836 if (!operand || !val) {
837 BNXT_TF_DBG(ERR, "invalid argument\n");
838 return 0; /* failure */
840 memcpy(val, operand, bytes);
845 * copy the buffer in the encap format which is 2 bytes.
846 * The MSB of the src is placed at the LSB of dst.
848 * dst [out] The destination buffer
849 * src [in] The source buffer dst
850 * size[in] size of the buffer.
851 * align[in] The alignment is either 8 or 16.
854 ulp_encap_buffer_copy(uint8_t *dst,
859 uint16_t idx, tmp_size = 0;
872 /* copy 2 bytes at a time. Write MSB to LSB */
873 while ((idx + sizeof(uint16_t)) <= tmp_size) {
875 &src[tmp_size - idx - sizeof(uint16_t)],
877 idx += sizeof(uint16_t);
883 * Check the buffer is empty
885 * buf [in] The buffer
886 * size [in] The size of the buffer
889 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
891 return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
894 /* Function to check if bitmap is zero.Return 1 on success */
895 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
905 /* Function to check if bitmap is ones. Return 1 on success */
906 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
916 /* Function to check if bitmap is not zero. Return 1 on success */
917 uint32_t ulp_bitmap_notzero(uint8_t *bitmap, int32_t size)