1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2014-2019 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);
149 /* Assuming that val is in Big-Endian Format */
151 ulp_bs_push_lsb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
157 if (cnt > 0 && !(len % 8))
160 for (i = 0; i < cnt; i++) {
161 ulp_bs_put_lsb(bs, pos, 8, val[cnt - i]);
166 /* Handle the remainder bits */
168 ulp_bs_put_lsb(bs, pos, tlen, val[0]);
172 /* Assuming that val is in Big-Endian Format */
174 ulp_bs_push_msb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
177 int cnt = (len + 7) / 8;
180 /* Handle any remainder bits */
186 ulp_bs_put_msb(bs, pos, tmp, val[0]);
191 for (i = 1; i < cnt; i++) {
192 ulp_bs_put_msb(bs, pos, 8, val[i]);
201 * Initializes the blob structure for creating binary blob
203 * blob [in] The blob to be initialized
205 * bitlen [in] The bit length of the blob
207 * order [in] The byte order for the blob. Currently only supporting
208 * big endian. All fields are packed with this order.
210 * returns 0 on error or 1 on success
213 ulp_blob_init(struct ulp_blob *blob,
215 enum bnxt_ulp_byte_order order)
217 /* validate the arguments */
218 if (!blob || bitlen > (8 * sizeof(blob->data))) {
219 BNXT_TF_DBG(ERR, "invalid argument\n");
220 return 0; /* failure */
222 blob->bitlen = bitlen;
223 blob->byte_order = order;
225 memset(blob->data, 0, sizeof(blob->data));
226 return 1; /* Success */
230 * Add data to the binary blob at the current offset.
232 * blob [in] The blob that data is added to. The blob must
233 * be initialized prior to pushing data.
235 * data [in] A pointer to bytes to be added to the blob.
237 * datalen [in] The number of bits to be added to the blob.
239 * The offset of the data is updated after each push of data.
240 * NULL returned on error.
242 #define ULP_BLOB_BYTE 8
243 #define ULP_BLOB_BYTE_HEX 0xFF
244 #define BLOB_MASK_CAL(x) ((0xFF << (x)) & 0xFF)
246 ulp_blob_push(struct ulp_blob *blob,
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 */
258 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
259 rc = ulp_bs_push_msb(blob->data,
264 rc = ulp_bs_push_lsb(blob->data,
269 BNXT_TF_DBG(ERR, "Failed ro write blob\n");
272 blob->write_idx += datalen;
277 * Add data to the binary blob at the current offset.
279 * blob [in] The blob that data is added to. The blob must
280 * be initialized prior to pushing data.
282 * data [in] 64-bit value to be added to the blob.
284 * datalen [in] The number of bits to be added to the blob.
286 * The offset of the data is updated after each push of data.
287 * NULL returned on error, pointer pushed value otherwise.
290 ulp_blob_push_64(struct ulp_blob *blob,
294 uint8_t *val = (uint8_t *)data;
297 int size = (datalen + 7) / 8;
299 if (!blob || !data ||
300 datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
301 BNXT_TF_DBG(ERR, "invalid argument\n");
305 rc = ulp_blob_push(blob, &val[8 - size], datalen);
309 return &val[8 - size];
313 * Add data to the binary blob at the current offset.
315 * blob [in] The blob that data is added to. The blob must
316 * be initialized prior to pushing data.
318 * data [in] 32-bit value to be added to the blob.
320 * datalen [in] The number of bits to be added ot the blob.
322 * The offset of the data is updated after each push of data.
323 * NULL returned on error, pointer pushed value otherwise.
326 ulp_blob_push_32(struct ulp_blob *blob,
330 uint8_t *val = (uint8_t *)data;
332 uint32_t size = ULP_BITS_2_BYTE(datalen);
334 if (!data || size > sizeof(uint32_t)) {
335 BNXT_TF_DBG(ERR, "invalid argument\n");
339 rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen);
343 return &val[sizeof(uint32_t) - size];
347 * Add encap data to the binary blob at the current offset.
349 * blob [in] The blob that data is added to. The blob must
350 * be initialized prior to pushing data.
352 * data [in] value to be added to the blob.
354 * datalen [in] The number of bits to be added to the blob.
356 * The offset of the data is updated after each push of data.
357 * NULL returned on error, pointer pushed value otherwise.
360 ulp_blob_push_encap(struct ulp_blob *blob,
364 uint8_t *val = (uint8_t *)data;
365 uint32_t initial_size, write_size = datalen;
368 if (!blob || !data ||
369 datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
370 BNXT_TF_DBG(ERR, "invalid argument\n");
374 initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
375 (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
376 while (write_size > 0) {
377 if (initial_size && write_size > initial_size) {
380 } else if (initial_size && write_size <= initial_size) {
383 } else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) {
384 size = ULP_BYTE_2_BITS(sizeof(uint64_t));
388 if (!ulp_blob_push(blob, val, size)) {
389 BNXT_TF_DBG(ERR, "push field failed\n");
392 val += ULP_BITS_2_BYTE(size);
399 * Adds pad to an initialized blob at the current offset
401 * blob [in] The blob that data is added to. The blob must
402 * be initialized prior to pushing data.
404 * datalen [in] The number of bits of pad to add
406 * returns the number of pad bits added, -1 on failure
409 ulp_blob_pad_push(struct ulp_blob *blob,
412 if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
413 BNXT_TF_DBG(ERR, "Pad too large for blob\n");
417 blob->write_idx += datalen;
421 /* Get data from src and put into dst using little-endian format */
423 ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
425 uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
426 uint16_t index = ULP_BITS_2_BYTE_NR(bitpos);
427 uint8_t mask, partial, shift;
430 partial = ULP_BLOB_BYTE - bitoffs;
431 if (bitoffs + bitlen <= ULP_BLOB_BYTE) {
432 mask = ((1 << bitlen) - 1) << shift;
433 *dst = (src[index] & mask) >> shift;
435 mask = ((1 << partial) - 1) << shift;
436 *dst = (src[index] & mask) >> shift;
438 partial = bitlen - partial;
439 mask = ((1 << partial) - 1);
440 *dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs);
444 /* Assuming that src is in little-Endian Format */
446 ulp_bs_pull_lsb(uint8_t *src, uint8_t *dst, uint32_t size,
447 uint32_t offset, uint32_t len)
450 uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
452 /* iterate bytewise to get data */
453 for (idx = 0; idx < cnt; idx++) {
454 ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE,
455 &dst[size - 1 - idx]);
456 offset += ULP_BLOB_BYTE;
457 len -= ULP_BLOB_BYTE;
460 /* Extract the last reminder data that is not 8 byte boundary */
462 ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]);
466 * Extract data from the binary blob using given offset.
468 * blob [in] The blob that data is extracted from. The blob must
469 * be initialized prior to pulling data.
471 * data [in] A pointer to put the data.
472 * data_size [in] size of the data buffer in bytes.
473 *offset [in] - Offset in the blob to extract the data in bits format.
474 * len [in] The number of bits to be pulled from the blob.
476 * Output: zero on success, -1 on failure
479 ulp_blob_pull(struct ulp_blob *blob, uint8_t *data, uint32_t data_size,
480 uint16_t offset, uint16_t len)
482 /* validate the arguments */
483 if (!blob || (offset + len) > blob->bitlen ||
484 ULP_BYTE_2_BITS(data_size) < len) {
485 BNXT_TF_DBG(ERR, "invalid argument\n");
486 return -1; /* failure */
489 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) {
490 BNXT_TF_DBG(ERR, "Big endian pull not implemented\n");
491 return -1; /* failure */
493 ulp_bs_pull_lsb(blob->data, data, data_size, offset, len);
498 * Get the data portion of the binary blob.
500 * blob [in] The blob's data to be retrieved. The blob must be
501 * initialized prior to pushing data.
503 * datalen [out] The number of bits to that are filled.
505 * returns a byte array of the blob data. Returns NULL on error.
508 ulp_blob_data_get(struct ulp_blob *blob,
511 /* validate the arguments */
513 BNXT_TF_DBG(ERR, "invalid argument\n");
514 return NULL; /* failure */
516 *datalen = blob->write_idx;
521 * Set the encap swap start index of the binary blob.
523 * blob [in] The blob's data to be retrieved. The blob must be
524 * initialized prior to pushing data.
529 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
531 /* validate the arguments */
533 BNXT_TF_DBG(ERR, "invalid argument\n");
534 return; /* failure */
536 blob->encap_swap_idx = blob->write_idx;
540 * Perform the encap buffer swap to 64 bit reversal.
542 * blob [in] The blob's data to be used for swap.
547 ulp_blob_perform_encap_swap(struct ulp_blob *blob)
549 uint32_t i, idx = 0, end_idx = 0, roundoff;
550 uint8_t temp_val_1, temp_val_2;
552 /* validate the arguments */
554 BNXT_TF_DBG(ERR, "invalid argument\n");
555 return; /* failure */
557 idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx);
558 end_idx = ULP_BITS_2_BYTE(blob->write_idx);
559 roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx));
560 if (roundoff > end_idx) {
561 blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx);
564 while (idx <= end_idx) {
565 for (i = 0; i < 4; i = i + 2) {
566 temp_val_1 = blob->data[idx + i];
567 temp_val_2 = blob->data[idx + i + 1];
568 blob->data[idx + i] = blob->data[idx + 6 - i];
569 blob->data[idx + i + 1] = blob->data[idx + 7 - i];
570 blob->data[idx + 7 - i] = temp_val_2;
571 blob->data[idx + 6 - i] = temp_val_1;
578 * Perform the blob buffer reversal byte wise.
579 * This api makes the first byte the last and
582 * blob [in] The blob's data to be used for swap.
587 ulp_blob_perform_byte_reverse(struct ulp_blob *blob)
589 uint32_t idx = 0, num = 0;
592 /* validate the arguments */
594 BNXT_TF_DBG(ERR, "invalid argument\n");
595 return; /* failure */
598 num = ULP_BITS_2_BYTE_NR(blob->write_idx);
599 for (idx = 0; idx < (num / 2); idx++) {
600 xchar = blob->data[idx];
601 blob->data[idx] = blob->data[(num - 1) - idx];
602 blob->data[(num - 1) - idx] = xchar;
607 * Read data from the operand
609 * operand [in] A pointer to a 16 Byte operand
611 * val [in/out] The variable to copy the operand to
613 * bytes [in] The number of bytes to read into val
615 * returns number of bits read, zero on error
618 ulp_operand_read(uint8_t *operand,
622 /* validate the arguments */
623 if (!operand || !val) {
624 BNXT_TF_DBG(ERR, "invalid argument\n");
625 return 0; /* failure */
627 memcpy(val, operand, bytes);
632 * copy the buffer in the encap format which is 2 bytes.
633 * The MSB of the src is placed at the LSB of dst.
635 * dst [out] The destination buffer
636 * src [in] The source buffer dst
637 * size[in] size of the buffer.
638 * align[in] The alignment is either 8 or 16.
641 ulp_encap_buffer_copy(uint8_t *dst,
646 uint16_t idx, tmp_size = 0;
659 /* copy 2 bytes at a time. Write MSB to LSB */
660 while ((idx + sizeof(uint16_t)) <= tmp_size) {
662 &src[tmp_size - idx - sizeof(uint16_t)],
664 idx += sizeof(uint16_t);
670 * Check the buffer is empty
672 * buf [in] The buffer
673 * size [in] The size of the buffer
676 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
678 return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
681 /* Function to check if bitmap is zero.Return 1 on success */
682 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
692 /* Function to check if bitmap is ones. Return 1 on success */
693 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
703 /* Function to check if bitmap is not zero. Return 1 on success */
704 uint32_t ulp_bitmap_notzero(uint8_t *bitmap, int32_t size)