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