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 being written 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 to 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 to 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 to 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 - 886 (dst->write_idx % block_size); 887 else 888 write_bytes = num - i; 889 for (k = 0; k < ULP_BITS_2_BYTE_NR(write_bytes); k++) { 890 ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE, 891 *src_buf); 892 dst->write_idx += ULP_BLOB_BYTE; 893 src_buf++; 894 } 895 remaining = write_bytes % ULP_BLOB_BYTE; 896 if (remaining) { 897 bluff = (*src_buf) & ((uint8_t)-1 << 898 (ULP_BLOB_BYTE - remaining)); 899 ulp_bs_put_msb(dst->data, dst->write_idx, 900 ULP_BLOB_BYTE, bluff); 901 dst->write_idx += remaining; 902 } 903 if (write_bytes != (num - i)) { 904 /* add the padding */ 905 ulp_blob_pad_push(dst, pad); 906 if (remaining) { 907 ulp_bs_put_msb(dst->data, dst->write_idx, 908 ULP_BLOB_BYTE - remaining, 909 *src_buf); 910 dst->write_idx += ULP_BLOB_BYTE - remaining; 911 src_buf++; 912 } 913 } 914 i += write_bytes; 915 } 916 return 0; 917 } 918 919 /* 920 * Perform the blob buffer merge. 921 * This api makes the src blob merged to the dst blob. 922 * The block size and pad size help in padding the dst blob 923 * 924 * dst [in] The destination blob, the blob to be merged. 925 * src [in] The src blob. 926 * block_size [in] The size of the block after which padding gets applied. 927 * pad [in] The size of the pad to be applied. 928 * 929 * returns 0 on success. 930 */ 931 int32_t 932 ulp_blob_block_merge(struct ulp_blob *dst, struct ulp_blob *src, 933 uint32_t block_size, uint32_t pad) 934 { 935 if (dst->byte_order == BNXT_ULP_BYTE_ORDER_BE && 936 src->byte_order == BNXT_ULP_BYTE_ORDER_BE) 937 return ulp_blob_msb_block_merge(dst, src, block_size, pad); 938 939 BNXT_TF_DBG(ERR, "block merge not implemented yet\n"); 940 return -EINVAL; 941 } 942 943 int32_t 944 ulp_blob_append(struct ulp_blob *dst, struct ulp_blob *src, 945 uint16_t src_offset, uint16_t src_len) 946 { 947 uint32_t k, remaining; 948 uint16_t num; 949 uint8_t bluff; 950 uint8_t *src_buf = ulp_blob_data_get(src, &num); 951 952 if ((src_offset + src_len) > num) 953 return -EINVAL; 954 955 /* Only supporting BE for now */ 956 if (src->byte_order != BNXT_ULP_BYTE_ORDER_BE || 957 dst->byte_order != BNXT_ULP_BYTE_ORDER_BE) 958 return -EINVAL; 959 960 /* Handle if the source offset is not on a byte boundary */ 961 remaining = src_offset % ULP_BLOB_BYTE; 962 if (remaining) { 963 bluff = src_buf[src_offset / ULP_BLOB_BYTE] & ((uint8_t)-1 >> 964 (ULP_BLOB_BYTE - remaining)); 965 ulp_bs_put_msb(dst->data, dst->write_idx, 966 ULP_BLOB_BYTE, bluff); 967 dst->write_idx += remaining; 968 src_offset += remaining; 969 } 970 971 src_buf += ULP_BITS_2_BYTE_NR(src_offset); 972 973 /* Push the byte aligned pieces */ 974 for (k = 0; k < ULP_BITS_2_BYTE_NR(src_len); k++) { 975 ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE, 976 *src_buf); 977 dst->write_idx += ULP_BLOB_BYTE; 978 src_buf++; 979 } 980 981 /* Handle the remaining if length is not a byte boundary */ 982 remaining = src_len % ULP_BLOB_BYTE; 983 if (remaining) { 984 bluff = (*src_buf) & ((uint8_t)-1 << 985 (ULP_BLOB_BYTE - remaining)); 986 ulp_bs_put_msb(dst->data, dst->write_idx, 987 ULP_BLOB_BYTE, bluff); 988 dst->write_idx += remaining; 989 } 990 991 return 0; 992 } 993 994 /* 995 * Perform the blob buffer copy. 996 * This api makes the src blob merged to the dst blob. 997 * 998 * dst [in] The destination blob, the blob to be merged. 999 * src [in] The src blob. 1000 * 1001 * returns 0 on success. 1002 */ 1003 int32_t 1004 ulp_blob_buffer_copy(struct ulp_blob *dst, struct ulp_blob *src) 1005 { 1006 if ((dst->write_idx + src->write_idx) > dst->bitlen) { 1007 BNXT_TF_DBG(ERR, "source buffer too large\n"); 1008 return -EINVAL; 1009 } 1010 if (ULP_BITS_IS_BYTE_NOT_ALIGNED(dst->write_idx) || 1011 ULP_BITS_IS_BYTE_NOT_ALIGNED(src->write_idx)) { 1012 BNXT_TF_DBG(ERR, "source buffer is not aligned\n"); 1013 return -EINVAL; 1014 } 1015 memcpy(&dst->data[ULP_BITS_2_BYTE_NR(dst->write_idx)], 1016 src->data, ULP_BITS_2_BYTE_NR(src->write_idx)); 1017 dst->write_idx += src->write_idx; 1018 return 0; 1019 } 1020 1021 /* 1022 * Read data from the operand 1023 * 1024 * operand [in] A pointer to a 16 Byte operand 1025 * 1026 * val [in/out] The variable to copy the operand to 1027 * 1028 * bytes [in] The number of bytes to read into val 1029 * 1030 * returns number of bits read, zero on error 1031 */ 1032 uint16_t 1033 ulp_operand_read(uint8_t *operand, 1034 uint8_t *val, 1035 uint16_t bytes) 1036 { 1037 /* validate the arguments */ 1038 if (!operand || !val) { 1039 BNXT_TF_DBG(ERR, "invalid argument\n"); 1040 return 0; /* failure */ 1041 } 1042 memcpy(val, operand, bytes); 1043 return bytes; 1044 } 1045 1046 /* 1047 * Check the buffer is empty 1048 * 1049 * buf [in] The buffer 1050 * size [in] The size of the buffer 1051 * 1052 */ 1053 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size) 1054 { 1055 return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1); 1056 } 1057 1058 /* Function to check if bitmap is zero.Return 1 on success */ 1059 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size) 1060 { 1061 while (size-- > 0) { 1062 if (*bitmap != 0) 1063 return 0; 1064 bitmap++; 1065 } 1066 return 1; 1067 } 1068 1069 /* Function to check if bitmap is ones. Return 1 on success */ 1070 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size) 1071 { 1072 while (size-- > 0) { 1073 if (*bitmap != 0xFF) 1074 return 0; 1075 bitmap++; 1076 } 1077 return 1; 1078 } 1079 1080 /* Function to check if bitmap is not zero. Return 1 on success */ 1081 uint32_t ulp_bitmap_notzero(const uint8_t *bitmap, int32_t size) 1082 { 1083 while (size-- > 0) { 1084 if (*bitmap != 0) 1085 return 1; 1086 bitmap++; 1087 } 1088 return 0; 1089 } 1090 1091 /* returns 0 if input is power of 2 */ 1092 int32_t ulp_util_is_power_of_2(uint64_t x) 1093 { 1094 if (((x - 1) & x)) 1095 return -1; 1096 return 0; 1097 } 1098