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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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