1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2023 Broadcom 3 * All rights reserved. 4 */ 5 6 #ifndef _ULP_UTILS_H_ 7 #define _ULP_UTILS_H_ 8 9 #include "bnxt.h" 10 #include "ulp_template_db_enum.h" 11 12 #define ULP_BUFFER_ALIGN_8_BITS 8 13 #define ULP_BUFFER_ALIGN_8_BYTE 8 14 #define ULP_BUFFER_ALIGN_16_BYTE 16 15 #define ULP_BUFFER_ALIGN_64_BYTE 64 16 #define ULP_64B_IN_BYTES 8 17 #define ULP_64B_IN_BITS 64 18 19 /* 20 * Macros for bitmap sets and gets 21 * These macros can be used if the val are power of 2. 22 */ 23 #define ULP_BITMAP_SET(bitmap, val) ((bitmap) |= (val)) 24 #define ULP_BITMAP_RESET(bitmap, val) ((bitmap) &= ~(val)) 25 #define ULP_BITMAP_ISSET(bitmap, val) ((bitmap) & (val)) 26 #define ULP_BITMAP_CMP(b1, b2) memcmp(&(b1)->bits, \ 27 &(b2)->bits, sizeof((b1)->bits)) 28 /* 29 * Macros for bitmap sets and gets 30 * These macros can be used if the val are not power of 2 and 31 * are simple index values. 32 */ 33 #define ULP_INDEX_BITMAP_SIZE (sizeof(uint64_t) * 8) 34 #define ULP_INDEX_BITMAP_CSET(i) (1UL << \ 35 ((ULP_INDEX_BITMAP_SIZE - 1) - \ 36 ((i) % ULP_INDEX_BITMAP_SIZE))) 37 38 #define ULP_INDEX_BITMAP_SET(b, i) ((b) |= \ 39 (1UL << ((ULP_INDEX_BITMAP_SIZE - 1) - \ 40 ((i) % ULP_INDEX_BITMAP_SIZE)))) 41 42 #define ULP_INDEX_BITMAP_RESET(b, i) ((b) &= \ 43 (~(1UL << ((ULP_INDEX_BITMAP_SIZE - 1) - \ 44 ((i) % ULP_INDEX_BITMAP_SIZE))))) 45 46 #define ULP_INDEX_BITMAP_GET(b, i) (((b) >> \ 47 ((ULP_INDEX_BITMAP_SIZE - 1) - \ 48 ((i) % ULP_INDEX_BITMAP_SIZE))) & 1) 49 50 #define ULP_DEVICE_PARAMS_INDEX(tid, dev_id) \ 51 (((tid) << BNXT_ULP_LOG2_MAX_NUM_DEV) | (dev_id)) 52 53 /* Macro to convert bytes to bits */ 54 #define ULP_BYTE_2_BITS(byte_x) ((byte_x) * 8) 55 /* Macro to convert bits to bytes */ 56 #define ULP_BITS_2_BYTE(bits_x) (((bits_x) + 7) / 8) 57 /* Macro to convert bits to bytes with no round off*/ 58 #define ULP_BITS_2_BYTE_NR(bits_x) ((bits_x) / 8) 59 60 /* Macro to round off to next multiple of 8*/ 61 #define ULP_BYTE_ROUND_OFF_8(x) (((x) + 7) & ~7) 62 63 /* Macro to check bits are byte aligned */ 64 #define ULP_BITS_IS_BYTE_NOT_ALIGNED(x) ((x) % 8) 65 66 /* Macro for word conversion */ 67 #define ULP_BITS_TO_4_BYTE_WORD(x) (((x) + 31) / 32) 68 #define ULP_BITS_TO_32_BYTE_WORD(x) (((x) + 255) / 256) 69 #define ULP_BITS_TO_4_BYTE_QWORDS(x) (((x) + 127) / 128) 70 #define ULP_BITS_TO_128B_ALIGNED_BYTES(x) ((((x) + 127) / 128) * 16) 71 72 /* Macros to read the computed fields */ 73 #define ULP_COMP_FLD_IDX_RD(params, idx) \ 74 rte_be_to_cpu_64((params)->comp_fld[(idx)]) 75 76 #define ULP_COMP_FLD_IDX_WR(params, idx, val) \ 77 ((params)->comp_fld[(idx)] = rte_cpu_to_be_64((uint64_t)(val))) 78 /* 79 * Making the blob statically sized to 128 bytes for now. 80 * The blob must be initialized with ulp_blob_init prior to using. 81 */ 82 #define BNXT_ULP_FLMP_BLOB_SIZE (128) 83 #define BNXT_ULP_FLMP_BLOB_SIZE_IN_BITS ULP_BYTE_2_BITS(BNXT_ULP_FLMP_BLOB_SIZE) 84 struct ulp_blob { 85 enum bnxt_ulp_byte_order byte_order; 86 uint16_t write_idx; 87 uint16_t bitlen; 88 uint8_t data[BNXT_ULP_FLMP_BLOB_SIZE]; 89 uint16_t encap_swap_idx; 90 }; 91 92 /* 93 * The data can likely be only 32 bits for now. Just size check 94 * the data when being written. 95 */ 96 #define ULP_REGFILE_ENTRY_SIZE (sizeof(uint32_t)) 97 struct ulp_regfile_entry { 98 uint64_t data; 99 uint32_t size; 100 }; 101 102 struct ulp_regfile { 103 struct ulp_regfile_entry entry[BNXT_ULP_RF_IDX_LAST]; 104 }; 105 106 /* 107 * Initialize the regfile structure for writing 108 * 109 * regfile [in] Ptr to a regfile instance 110 * 111 * returns zero on success 112 */ 113 static inline int32_t 114 ulp_regfile_init(struct ulp_regfile *regfile) 115 { 116 /* validate the arguments */ 117 if (!regfile) { 118 BNXT_DRV_DBG(ERR, "invalid argument\n"); 119 return -EINVAL; 120 } 121 memset(regfile, 0, sizeof(struct ulp_regfile)); 122 return 0; /* Success */ 123 } 124 125 /* 126 * Read a value from the regfile 127 * 128 * regfile [in] The regfile instance. Must be initialized prior to being used 129 * 130 * field [in] The field to be read within the regfile. 131 * 132 * data [in/out] 133 * 134 * returns zero on success 135 */ 136 static inline int32_t 137 ulp_regfile_read(struct ulp_regfile *regfile, 138 enum bnxt_ulp_rf_idx field, 139 uint64_t *data) 140 { 141 /* validate the arguments */ 142 if (unlikely(!regfile || field >= BNXT_ULP_RF_IDX_LAST)) { 143 BNXT_DRV_DBG(ERR, "invalid argument\n"); 144 return -EINVAL; 145 } 146 147 *data = regfile->entry[field].data; 148 return 0; 149 } 150 151 /* 152 * Write a value to the regfile 153 * 154 * regfile [in] The regfile instance. Must be initialized prior to being used 155 * 156 * field [in] The field to be written within the regfile. 157 * 158 * data [in] The value is written into this variable. It is going to be in the 159 * same byte order as it was written. 160 * 161 * size [in] The size in bytes of the value being written into this 162 * variable. 163 * 164 * returns 0 on success 165 */ 166 static inline int32_t 167 ulp_regfile_write(struct ulp_regfile *regfile, 168 enum bnxt_ulp_rf_idx field, 169 uint64_t data) 170 { 171 /* validate the arguments */ 172 if (unlikely(!regfile || field >= BNXT_ULP_RF_IDX_LAST)) { 173 BNXT_DRV_DBG(ERR, "invalid argument\n"); 174 return -EINVAL; /* failure */ 175 } 176 177 regfile->entry[field].data = data; 178 return 0; /* Success */ 179 } 180 181 182 /* 183 * Add data to the byte array in Big endian format. 184 * 185 * bs [in] The byte array where data is pushed 186 * 187 * bitpos [in] The offset where data is pushed 188 * 189 * bitlen [in] The number of bits to be added to the data array. 190 * 191 * val [in] The data to be added to the data array. 192 * 193 */ 194 static inline void 195 ulp_bs_put_msb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val) 196 { 197 uint8_t bitoffs = bitpos % 8; 198 uint16_t index = bitpos / 8; 199 uint8_t mask; 200 uint8_t tmp; 201 int8_t shift; 202 203 tmp = bs[index]; 204 mask = ((uint8_t)-1 >> (8 - bitlen)); 205 shift = 8 - bitoffs - bitlen; 206 val &= mask; 207 208 if (shift >= 0) { 209 tmp &= ~(mask << shift); 210 tmp |= val << shift; 211 bs[index] = tmp; 212 } else { 213 tmp &= ~((uint8_t)-1 >> bitoffs); 214 tmp |= val >> -shift; 215 bs[index++] = tmp; 216 217 tmp = bs[index]; 218 tmp &= ((uint8_t)-1 >> (bitlen - (8 - bitoffs))); 219 tmp |= val << (8 + shift); 220 bs[index] = tmp; 221 } 222 } 223 224 /* 225 * Add data to the byte array in Little endian format. 226 * 227 * bs [in] The byte array where data is pushed 228 * 229 * bitpos [in] The offset where data is pushed 230 * 231 * bitlen [in] The number of bits to be added to the data array. 232 * 233 * val [in] The data to be added to the data array. 234 * 235 */ 236 static inline void 237 ulp_bs_put_lsb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val) 238 { 239 uint8_t bitoffs = bitpos % 8; 240 uint16_t index = bitpos / 8; 241 uint8_t mask; 242 uint8_t tmp; 243 uint8_t shift; 244 uint8_t partial; 245 246 tmp = bs[index]; 247 shift = bitoffs; 248 249 if (bitoffs + bitlen <= 8) { 250 mask = ((1 << bitlen) - 1) << shift; 251 tmp &= ~mask; 252 tmp |= ((val << shift) & mask); 253 bs[index] = tmp; 254 } else { 255 partial = 8 - bitoffs; 256 mask = ((1 << partial) - 1) << shift; 257 tmp &= ~mask; 258 tmp |= ((val << shift) & mask); 259 bs[index++] = tmp; 260 261 val >>= partial; 262 partial = bitlen - partial; 263 mask = ((1 << partial) - 1); 264 tmp = bs[index]; 265 tmp &= ~mask; 266 tmp |= (val & mask); 267 bs[index] = tmp; 268 } 269 } 270 271 /* 272 * Add data to the byte array in Little endian format. 273 * 274 * bs [in] The byte array where data is pushed 275 * 276 * pos [in] The offset where data is pushed 277 * 278 * len [in] The number of bits to be added to the data array. 279 * 280 * val [in] The data to be added to the data array. 281 * 282 * returns the number of bits pushed. 283 */ 284 static inline uint32_t 285 ulp_bs_push_lsb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val) 286 { 287 int i; 288 int cnt = (len) / 8; 289 int tlen = len; 290 291 if (cnt > 0 && !(len % 8)) 292 cnt -= 1; 293 294 for (i = 0; i < cnt; i++) { 295 ulp_bs_put_lsb(bs, pos, 8, val[cnt - i]); 296 pos += 8; 297 tlen -= 8; 298 } 299 300 /* Handle the remainder bits */ 301 if (tlen) 302 ulp_bs_put_lsb(bs, pos, tlen, val[0]); 303 return len; 304 } 305 306 /* 307 * Add data to the byte array in Big endian format. 308 * 309 * bs [in] The byte array where data is pushed 310 * 311 * pos [in] The offset where data is pushed 312 * 313 * len [in] The number of bits to be added to the data array. 314 * 315 * val [in] The data to be added to the data array. 316 * 317 * returns the number of bits pushed. 318 */ 319 static inline uint32_t 320 ulp_bs_push_msb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val) 321 { 322 int i; 323 int cnt = (len + 7) / 8; 324 325 /* Handle any remainder bits */ 326 int tmp = len % 8; 327 328 if (!tmp) 329 tmp = 8; 330 331 ulp_bs_put_msb(bs, pos, tmp, val[0]); 332 333 pos += tmp; 334 335 for (i = 1; i < cnt; i++) { 336 ulp_bs_put_msb(bs, pos, 8, val[i]); 337 pos += 8; 338 } 339 340 return len; 341 } 342 343 /* 344 * Initializes the blob structure for creating binary blob 345 * 346 * blob [in] The blob to be initialized 347 * 348 * bitlen [in] The bit length of the blob 349 * 350 * order [in] The byte order for the blob. Currently only supporting 351 * big endian. All fields are packed with this order. 352 * 353 * returns zero on success 354 * Notes - If bitlen is zero then set it to max. 355 */ 356 static inline int32_t 357 ulp_blob_init(struct ulp_blob *blob, 358 uint16_t bitlen, 359 enum bnxt_ulp_byte_order order) 360 { 361 /* validate the arguments */ 362 if (unlikely(!blob || bitlen > (8 * sizeof(blob->data)))) { 363 BNXT_DRV_DBG(ERR, "invalid argument\n"); 364 return -EINVAL; 365 } 366 if (bitlen) 367 blob->bitlen = bitlen; 368 else 369 blob->bitlen = BNXT_ULP_FLMP_BLOB_SIZE_IN_BITS; 370 blob->byte_order = order; 371 blob->write_idx = 0; 372 memset(blob->data, 0, sizeof(blob->data)); 373 return 0; /* Success */ 374 } 375 376 /* 377 * Add data to the binary blob at the current offset. 378 * 379 * blob [in] The blob that data is added to. The blob must 380 * be initialized prior to pushing data. 381 * 382 * data [in] A pointer to bytes to be added to the blob. 383 * 384 * datalen [in] The number of bits to be added to the blob. 385 * 386 * The offset of the data is updated after each push of data. 387 * 388 * returns zero on success 389 */ 390 #define ULP_BLOB_BYTE 8 391 #define ULP_BLOB_BYTE_HEX 0xFF 392 #define BLOB_MASK_CAL(x) ((0xFF << (x)) & 0xFF) 393 static inline int32_t 394 ulp_blob_push(struct ulp_blob *blob, 395 uint8_t *data, 396 uint32_t datalen) 397 { 398 uint32_t rc; 399 400 /* validate the arguments */ 401 if (unlikely(!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx))) { 402 BNXT_DRV_DBG(ERR, "invalid argument\n"); 403 return -EINVAL; 404 } 405 406 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) 407 rc = ulp_bs_push_msb(blob->data, 408 blob->write_idx, 409 datalen, 410 data); 411 else 412 rc = ulp_bs_push_lsb(blob->data, 413 blob->write_idx, 414 datalen, 415 data); 416 if (unlikely(!rc)) { 417 BNXT_DRV_DBG(ERR, "Failed to write blob\n"); 418 return -EINVAL; 419 } 420 blob->write_idx += datalen; 421 return 0; 422 } 423 424 /* 425 * Insert data into the binary blob at the given offset. 426 * 427 * blob [in] The blob that data is added to. The blob must 428 * be initialized prior to pushing data. 429 * 430 * offset [in] The offset where the data needs to be inserted. 431 * 432 * data [in/out] A pointer to bytes to be added to the blob. 433 * 434 * datalen [in] The number of bits to be added to the blob. 435 * 436 * The offset of the data is updated after each push of data. 437 * 438 * returns zero on success 439 */ 440 static inline int32_t 441 ulp_blob_insert(struct ulp_blob *blob, uint32_t offset, 442 uint8_t *data, uint32_t datalen) 443 { 444 uint32_t rc; 445 uint8_t local_data[BNXT_ULP_FLMP_BLOB_SIZE]; 446 uint16_t mov_len; 447 448 /* validate the arguments */ 449 if (unlikely(!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx) || 450 offset > blob->write_idx)) { 451 BNXT_DRV_DBG(ERR, "invalid argument\n"); 452 return -EINVAL; 453 } 454 455 mov_len = blob->write_idx - offset; 456 /* If offset and data len are not 8 bit aligned then return error */ 457 if (unlikely(ULP_BITS_IS_BYTE_NOT_ALIGNED(offset) || 458 ULP_BITS_IS_BYTE_NOT_ALIGNED(datalen))) { 459 BNXT_DRV_DBG(ERR, "invalid argument, not aligned\n"); 460 return -EINVAL; 461 } 462 463 /* copy the data so we can move the data */ 464 memcpy(local_data, &blob->data[ULP_BITS_2_BYTE_NR(offset)], 465 ULP_BITS_2_BYTE(mov_len)); 466 blob->write_idx = offset; 467 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) 468 rc = ulp_bs_push_msb(blob->data, 469 blob->write_idx, 470 datalen, 471 data); 472 else 473 rc = ulp_bs_push_lsb(blob->data, 474 blob->write_idx, 475 datalen, 476 data); 477 if (unlikely(!rc)) { 478 BNXT_DRV_DBG(ERR, "Failed to write blob\n"); 479 return -EINVAL; 480 } 481 /* copy the previously stored data */ 482 memcpy(&blob->data[ULP_BITS_2_BYTE_NR(offset + datalen)], local_data, 483 ULP_BITS_2_BYTE(mov_len)); 484 blob->write_idx += (mov_len + datalen); 485 return 0; 486 } 487 488 /* 489 * Add data to the binary blob at the current offset. 490 * 491 * blob [in] The blob that data is added to. The blob must 492 * be initialized prior to pushing data. 493 * 494 * data [in] 64-bit value to be added to the blob. 495 * 496 * datalen [in] The number of bits to be added to the blob. 497 * 498 * The offset of the data is updated after each push of data. 499 * NULL returned on error, pointer pushed value otherwise. 500 */ 501 static inline uint8_t * 502 ulp_blob_push_64(struct ulp_blob *blob, 503 uint64_t *data, 504 uint32_t datalen) 505 { 506 uint8_t *val = (uint8_t *)data; 507 int rc; 508 509 int size = (datalen + 7) / 8; 510 511 if (unlikely(!blob || !data || 512 datalen > (uint32_t)(blob->bitlen - blob->write_idx))) { 513 BNXT_DRV_DBG(ERR, "invalid argument\n"); 514 return NULL; 515 } 516 517 rc = ulp_blob_push(blob, &val[8 - size], datalen); 518 if (unlikely(rc)) 519 return NULL; 520 521 return &val[8 - size]; 522 } 523 524 /* 525 * Add data to the binary blob at the current offset. 526 * 527 * blob [in] The blob that data is added to. The blob must 528 * be initialized prior to pushing data. 529 * 530 * data [in] 32-bit value to be added to the blob. 531 * 532 * datalen [in] The number of bits to be added to the blob. 533 * 534 * The offset of the data is updated after each push of data. 535 * NULL returned on error, pointer pushed value otherwise. 536 */ 537 static inline uint8_t * 538 ulp_blob_push_32(struct ulp_blob *blob, 539 uint32_t *data, 540 uint32_t datalen) 541 { 542 uint8_t *val = (uint8_t *)data; 543 uint32_t rc; 544 uint32_t size = ULP_BITS_2_BYTE(datalen); 545 546 if (unlikely(!data || size > sizeof(uint32_t))) { 547 BNXT_DRV_DBG(ERR, "invalid argument\n"); 548 return NULL; 549 } 550 551 rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen); 552 if (unlikely(rc)) 553 return NULL; 554 555 return &val[sizeof(uint32_t) - size]; 556 } 557 558 /* 559 * Add encap data to the binary blob at the current offset. 560 * 561 * blob [in] The blob that data is added to. The blob must 562 * be initialized prior to pushing data. 563 * 564 * data [in] value to be added to the blob. 565 * 566 * datalen [in] The number of bits to be added to the blob. 567 * 568 * The offset of the data is updated after each push of data. 569 * NULL returned on error, pointer pushed value otherwise. 570 */ 571 static inline int32_t 572 ulp_blob_push_encap(struct ulp_blob *blob, 573 uint8_t *data, 574 uint32_t datalen) 575 { 576 uint8_t *val = (uint8_t *)data; 577 uint32_t initial_size, write_size = datalen; 578 uint32_t size = 0; 579 580 if (unlikely(!blob || !data || 581 datalen > (uint32_t)(blob->bitlen - blob->write_idx))) { 582 BNXT_DRV_DBG(ERR, "invalid argument\n"); 583 return -1; 584 } 585 586 initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) - 587 (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t))); 588 while (write_size > 0) { 589 if (initial_size && write_size > initial_size) { 590 size = initial_size; 591 initial_size = 0; 592 } else if (initial_size && write_size <= initial_size) { 593 size = write_size; 594 initial_size = 0; 595 } else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) { 596 size = ULP_BYTE_2_BITS(sizeof(uint64_t)); 597 } else { 598 size = write_size; 599 } 600 if (unlikely(ulp_blob_push(blob, val, size))) { 601 BNXT_DRV_DBG(ERR, "push field failed\n"); 602 return -1; 603 } 604 val += ULP_BITS_2_BYTE(size); 605 write_size -= size; 606 } 607 return datalen; 608 } 609 610 /* 611 * Adds pad to an initialized blob at the current offset 612 * 613 * blob [in] The blob that data is added to. The blob must 614 * be initialized prior to pushing data. 615 * 616 * datalen [in] The number of bits of pad to add 617 * 618 * returns the number of pad bits added, -1 on failure 619 */ 620 static inline int32_t 621 ulp_blob_pad_push(struct ulp_blob *blob, 622 uint32_t datalen) 623 { 624 if (unlikely(datalen > (uint32_t)(blob->bitlen - blob->write_idx))) { 625 BNXT_DRV_DBG(ERR, "Pad too large for blob\n"); 626 return -1; 627 } 628 629 blob->write_idx += datalen; 630 return datalen; 631 } 632 633 /* 634 * Adds pad to an initialized blob at the current offset based on 635 * the alignment. 636 * 637 * blob [in] The blob that needs to be aligned 638 * 639 * align [in] Alignment in bits. 640 * 641 * returns the number of pad bits added, -1 on failure 642 */ 643 static inline int32_t 644 ulp_blob_pad_align(struct ulp_blob *blob, 645 uint32_t align) 646 { 647 int32_t pad = 0; 648 649 pad = RTE_ALIGN(blob->write_idx, align) - blob->write_idx; 650 if (unlikely(pad > (int32_t)(blob->bitlen - blob->write_idx))) { 651 BNXT_DRV_DBG(ERR, "Pad too large for blob\n"); 652 return -1; 653 } 654 blob->write_idx += pad; 655 return pad; 656 } 657 658 /* Get data from src and put into dst using little-endian format */ 659 static inline void 660 ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst) 661 { 662 uint8_t bitoffs = bitpos % ULP_BLOB_BYTE; 663 uint16_t index = ULP_BITS_2_BYTE_NR(bitpos); 664 uint8_t mask, partial, shift; 665 666 shift = bitoffs; 667 partial = ULP_BLOB_BYTE - bitoffs; 668 if (bitoffs + bitlen <= ULP_BLOB_BYTE) { 669 mask = ((1 << bitlen) - 1) << shift; 670 *dst = (src[index] & mask) >> shift; 671 } else { 672 mask = ((1 << partial) - 1) << shift; 673 *dst = (src[index] & mask) >> shift; 674 index++; 675 partial = bitlen - partial; 676 mask = ((1 << partial) - 1); 677 *dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs); 678 } 679 } 680 681 /* 682 * Get data from the byte array in Little endian format. 683 * 684 * src [in] The byte array where data is extracted from 685 * 686 * dst [out] The byte array where data is pulled into 687 * 688 * size [in] The size of dst array in bytes 689 * 690 * offset [in] The offset where data is pulled 691 * 692 * len [in] The number of bits to be extracted from the data array 693 * 694 * returns None. 695 */ 696 static inline void 697 ulp_bs_pull_lsb(uint8_t *src, uint8_t *dst, uint32_t size, 698 uint32_t offset, uint32_t len) 699 { 700 uint32_t idx; 701 uint32_t cnt = ULP_BITS_2_BYTE_NR(len); 702 703 /* iterate bytewise to get data */ 704 for (idx = 0; idx < cnt; idx++) { 705 ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE, 706 &dst[size - 1 - idx]); 707 offset += ULP_BLOB_BYTE; 708 len -= ULP_BLOB_BYTE; 709 } 710 711 /* Extract the last reminder data that is not 8 byte boundary */ 712 if (len) 713 ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]); 714 } 715 716 /* 717 * Get data from the byte array in Big endian format. 718 * 719 * src [in] The byte array where data is extracted from 720 * 721 * bitpos [in] The offset where data is pulled 722 * 723 * bitlen [in] The number of bits to be extracted from the data array 724 * 725 * dst [out] The byte array where data is pulled into 726 * 727 * returns None. 728 */ 729 /* Get data from src and put into dst using big-endian format */ 730 static inline void 731 ulp_bs_get_msb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst) 732 { 733 uint8_t bitoffs = bitpos % ULP_BLOB_BYTE; 734 uint16_t index = ULP_BITS_2_BYTE_NR(bitpos); 735 uint8_t mask; 736 int32_t shift; 737 738 shift = ULP_BLOB_BYTE - bitoffs - bitlen; 739 if (shift >= 0) { 740 mask = 0xFF >> -bitlen; 741 *dst = (src[index] >> shift) & mask; 742 } else { 743 *dst = (src[index] & (0xFF >> bitoffs)) << -shift; 744 *dst |= src[index + 1] >> -shift; 745 } 746 } 747 748 /* 749 * Get data from the byte array in Big endian format. 750 * 751 * src [in] The byte array where data is extracted from 752 * 753 * dst [out] The byte array where data is pulled into 754 * 755 * offset [in] The offset where data is pulled 756 * 757 * len [in] The number of bits to be extracted from the data array 758 * 759 * returns None. 760 */ 761 static inline void 762 ulp_bs_pull_msb(uint8_t *src, uint8_t *dst, 763 uint32_t offset, uint32_t len) 764 { 765 uint32_t idx; 766 uint32_t cnt = ULP_BITS_2_BYTE_NR(len); 767 768 /* iterate bytewise to get data */ 769 for (idx = 0; idx < cnt; idx++) { 770 ulp_bs_get_msb(src, offset, ULP_BLOB_BYTE, &dst[idx]); 771 offset += ULP_BLOB_BYTE; 772 len -= ULP_BLOB_BYTE; 773 } 774 775 /* Extract the last reminder data that is not 8 byte boundary */ 776 if (len) 777 ulp_bs_get_msb(src, offset, len, &dst[idx]); 778 } 779 780 /* 781 * Extract data from the binary blob using given offset. 782 * 783 * blob [in] The blob that data is extracted from. The blob must 784 * be initialized prior to pulling data. 785 * 786 * data [in] A pointer to put the data. 787 * data_size [in] size of the data buffer in bytes. 788 *offset [in] - Offset in the blob to extract the data in bits format. 789 * len [in] The number of bits to be pulled from the blob. 790 * 791 * Output: zero on success, -1 on failure 792 */ 793 static inline int32_t 794 ulp_blob_pull(struct ulp_blob *blob, uint8_t *data, uint32_t data_size, 795 uint16_t offset, uint16_t len) 796 { 797 /* validate the arguments */ 798 if (unlikely(!blob || (offset + len) > blob->bitlen || 799 ULP_BYTE_2_BITS(data_size) < len)) { 800 BNXT_DRV_DBG(ERR, "invalid argument\n"); 801 return -1; /* failure */ 802 } 803 804 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) 805 ulp_bs_pull_msb(blob->data, data, offset, len); 806 else 807 ulp_bs_pull_lsb(blob->data, data, data_size, offset, len); 808 return 0; 809 } 810 811 /* 812 * Get the data portion of the binary blob. 813 * 814 * blob [in] The blob's data to be retrieved. The blob must be 815 * initialized prior to pushing data. 816 * 817 * datalen [out] The number of bits that are filled. 818 * 819 * Returns a byte array of the blob data or NULL on error. 820 */ 821 static inline uint8_t * 822 ulp_blob_data_get(struct ulp_blob *blob, 823 uint16_t *datalen) 824 { 825 /* validate the arguments */ 826 if (unlikely(!blob)) { 827 BNXT_DRV_DBG(ERR, "invalid argument\n"); 828 return NULL; /* failure */ 829 } 830 *datalen = blob->write_idx; 831 return blob->data; 832 } 833 834 /* 835 * Get the data length of the binary blob. 836 * 837 * blob [in] The blob's data len to be retrieved. 838 * 839 * returns length of the binary blob 840 */ 841 static inline uint16_t 842 ulp_blob_data_len_get(struct ulp_blob *blob) 843 { 844 /* validate the arguments */ 845 if (unlikely(!blob)) { 846 BNXT_DRV_DBG(ERR, "invalid argument\n"); 847 return 0; /* failure */ 848 } 849 return blob->write_idx; 850 } 851 852 /* 853 * Set the encap swap start index of the binary blob. 854 * 855 * blob [in] The blob's data to be retrieved. The blob must be 856 * initialized prior to pushing data. 857 * 858 * returns void. 859 */ 860 static inline void 861 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob) 862 { 863 /* validate the arguments */ 864 if (unlikely(!blob)) { 865 BNXT_DRV_DBG(ERR, "invalid argument\n"); 866 return; /* failure */ 867 } 868 blob->encap_swap_idx = blob->write_idx; 869 } 870 871 /* 872 * Perform the encap buffer swap to 64 bit reversal. 873 * 874 * blob [in] The blob's data to be used for swap. 875 * 876 * returns void. 877 */ 878 static inline void 879 ulp_blob_perform_encap_swap(struct ulp_blob *blob) 880 { 881 uint32_t i, idx = 0, end_idx = 0, roundoff; 882 uint8_t temp_val_1, temp_val_2; 883 884 /* validate the arguments */ 885 if (unlikely(!blob)) { 886 BNXT_DRV_DBG(ERR, "invalid argument\n"); 887 return; /* failure */ 888 } 889 idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx); 890 end_idx = ULP_BITS_2_BYTE(blob->write_idx); 891 roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx)); 892 if (roundoff > end_idx) { 893 blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx); 894 end_idx = roundoff; 895 } 896 while (idx <= end_idx) { 897 for (i = 0; i < 4; i = i + 2) { 898 temp_val_1 = blob->data[idx + i]; 899 temp_val_2 = blob->data[idx + i + 1]; 900 blob->data[idx + i] = blob->data[idx + 6 - i]; 901 blob->data[idx + i + 1] = blob->data[idx + 7 - i]; 902 blob->data[idx + 7 - i] = temp_val_2; 903 blob->data[idx + 6 - i] = temp_val_1; 904 } 905 idx += 8; 906 } 907 } 908 909 /* 910 * Perform the blob buffer reversal byte wise. 911 * This api makes the first byte the last and 912 * vice-versa. 913 * 914 * blob [in] The blob's data to be used for swap. 915 * chunk_size[in] the swap is done within the chunk in bytes 916 * 917 * returns void. 918 */ 919 static inline void 920 ulp_blob_perform_byte_reverse(struct ulp_blob *blob, 921 uint32_t chunk_size) 922 { 923 uint32_t idx = 0, jdx = 0, num = 0; 924 uint8_t xchar; 925 uint8_t *buff; 926 927 /* validate the arguments */ 928 if (unlikely(!blob)) { 929 BNXT_DRV_DBG(ERR, "invalid argument\n"); 930 return; /* failure */ 931 } 932 933 buff = blob->data; 934 num = ULP_BITS_2_BYTE(blob->write_idx) / chunk_size; 935 for (idx = 0; idx < num; idx++) { 936 for (jdx = 0; jdx < chunk_size / 2; jdx++) { 937 xchar = buff[jdx]; 938 buff[jdx] = buff[(chunk_size - 1) - jdx]; 939 buff[(chunk_size - 1) - jdx] = xchar; 940 } 941 buff += chunk_size; 942 } 943 } 944 945 /* 946 * Perform the blob buffer 64 bit word swap. 947 * This api makes the first 4 bytes the last in 948 * a given 64 bit value and vice-versa. 949 * 950 * blob [in] The blob's data to be used for swap. 951 * 952 * returns void. 953 */ 954 static inline void 955 ulp_blob_perform_64B_word_swap(struct ulp_blob *blob) 956 { 957 uint32_t i, j, num; 958 uint8_t xchar; 959 uint32_t word_size = ULP_64B_IN_BYTES / 2; 960 961 /* validate the arguments */ 962 if (unlikely(!blob)) { 963 BNXT_DRV_DBG(ERR, "invalid argument\n"); 964 return; /* failure */ 965 } 966 num = ULP_BITS_2_BYTE(blob->write_idx); 967 for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) { 968 for (j = 0; j < word_size; j++) { 969 xchar = blob->data[i + j]; 970 blob->data[i + j] = blob->data[i + j + word_size]; 971 blob->data[i + j + word_size] = xchar; 972 } 973 } 974 } 975 976 /* 977 * Perform the blob buffer 64 bit byte swap. 978 * This api makes the first byte the last in 979 * a given 64 bit value and vice-versa. 980 * 981 * blob [in] The blob's data to be used for swap. 982 * 983 * returns void. 984 */ 985 static inline void 986 ulp_blob_perform_64B_byte_swap(struct ulp_blob *blob) 987 { 988 uint32_t i, j, num; 989 uint8_t xchar; 990 uint32_t offset = ULP_64B_IN_BYTES - 1; 991 992 /* validate the arguments */ 993 if (unlikely(!blob)) { 994 BNXT_DRV_DBG(ERR, "invalid argument\n"); 995 return; /* failure */ 996 } 997 num = ULP_BITS_2_BYTE(blob->write_idx); 998 for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) { 999 for (j = 0; j < (ULP_64B_IN_BYTES / 2); j++) { 1000 xchar = blob->data[i + j]; 1001 blob->data[i + j] = blob->data[i + offset - j]; 1002 blob->data[i + offset - j] = xchar; 1003 } 1004 } 1005 } 1006 1007 /* 1008 * Perform the blob buffer merge. 1009 * This api makes the src blob merged to the dst blob. 1010 * The block size and pad size help in padding the dst blob 1011 * 1012 * dst [in] The destination blob, the blob to be merged. 1013 * src [in] The src blob. 1014 * block_size [in] The size of the block in bytes after which padding gets 1015 * applied. 1016 * pad [in] The size of the pad to be applied. 1017 * 1018 * returns 0 on success. 1019 */ 1020 static inline int32_t 1021 ulp_blob_msb_block_merge(struct ulp_blob *dst, struct ulp_blob *src, 1022 uint32_t block_size, uint32_t pad) 1023 { 1024 uint32_t i, k, write_bytes, remaining; 1025 uint16_t num; 1026 uint8_t *src_buf = ulp_blob_data_get(src, &num); 1027 uint8_t bluff; 1028 1029 for (i = 0; i < num;) { 1030 if (((dst->write_idx % block_size) + (num - i)) > block_size) 1031 write_bytes = block_size - 1032 (dst->write_idx % block_size); 1033 else 1034 write_bytes = num - i; 1035 for (k = 0; k < ULP_BITS_2_BYTE_NR(write_bytes); k++) { 1036 ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE, 1037 *src_buf); 1038 dst->write_idx += ULP_BLOB_BYTE; 1039 src_buf++; 1040 } 1041 remaining = write_bytes % ULP_BLOB_BYTE; 1042 if (remaining) { 1043 bluff = (*src_buf) & ((uint8_t)-1 << 1044 (ULP_BLOB_BYTE - remaining)); 1045 ulp_bs_put_msb(dst->data, dst->write_idx, 1046 ULP_BLOB_BYTE, bluff); 1047 dst->write_idx += remaining; 1048 } 1049 if (write_bytes != (num - i)) { 1050 /* add the padding */ 1051 ulp_blob_pad_push(dst, pad); 1052 if (remaining) { 1053 ulp_bs_put_msb(dst->data, dst->write_idx, 1054 ULP_BLOB_BYTE - remaining, 1055 *src_buf); 1056 dst->write_idx += ULP_BLOB_BYTE - remaining; 1057 src_buf++; 1058 } 1059 } 1060 i += write_bytes; 1061 } 1062 return 0; 1063 } 1064 1065 /* 1066 * Perform the blob buffer merge. 1067 * This api makes the src blob merged to the dst blob. 1068 * The block size and pad size help in padding the dst blob 1069 * 1070 * dst [in] The destination blob, the blob to be merged. 1071 * src [in] The src blob. 1072 * block_size [in] The size of the block in bytes after which padding gets 1073 * applied. 1074 * pad [in] The size of the pad to be applied. 1075 * 1076 * returns 0 on success. 1077 */ 1078 static inline int32_t 1079 ulp_blob_block_merge(struct ulp_blob *dst, struct ulp_blob *src, 1080 uint32_t block_size, uint32_t pad) 1081 { 1082 if (dst->byte_order == BNXT_ULP_BYTE_ORDER_BE && 1083 src->byte_order == BNXT_ULP_BYTE_ORDER_BE) 1084 return ulp_blob_msb_block_merge(dst, src, block_size, pad); 1085 1086 BNXT_DRV_DBG(ERR, "block merge not implemented yet\n"); 1087 return -EINVAL; 1088 } 1089 1090 /* 1091 * Perform the blob buffer append. 1092 * 1093 * dst [in] The destination blob, the blob to be merged. 1094 * src [in] The src blob. 1095 * src_offset [in] Offset of src data. 1096 * src_len [in] The size of the src data. 1097 * 1098 * returns 0 on success. 1099 */ 1100 static inline int32_t 1101 ulp_blob_append(struct ulp_blob *dst, struct ulp_blob *src, 1102 uint16_t src_offset, uint16_t src_len) 1103 { 1104 uint32_t k, remaining = 0; 1105 uint16_t num; 1106 uint8_t bluff; 1107 uint8_t *src_buf = ulp_blob_data_get(src, &num); 1108 1109 if (unlikely((src_offset + src_len) > num)) 1110 return -EINVAL; 1111 1112 /* Only supporting BE for now */ 1113 if (unlikely(src->byte_order != BNXT_ULP_BYTE_ORDER_BE || 1114 dst->byte_order != BNXT_ULP_BYTE_ORDER_BE)) 1115 return -EINVAL; 1116 1117 /* Handle if the source offset is not on a byte boundary */ 1118 remaining = src_offset % ULP_BLOB_BYTE; 1119 if (remaining) { 1120 bluff = src_buf[src_offset / ULP_BLOB_BYTE] & ((uint8_t)-1 >> 1121 (ULP_BLOB_BYTE - remaining)); 1122 ulp_bs_put_msb(dst->data, dst->write_idx, remaining, bluff); 1123 dst->write_idx += remaining; 1124 src_offset += remaining; 1125 } 1126 1127 src_buf += ULP_BITS_2_BYTE_NR(src_offset); 1128 1129 /* Push the byte aligned pieces */ 1130 for (k = 0; k < ULP_BITS_2_BYTE_NR(src_len); k++) { 1131 ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE, 1132 *src_buf); 1133 dst->write_idx += ULP_BLOB_BYTE; 1134 src_buf++; 1135 } 1136 1137 /* Handle the remaining if length is not a byte boundary */ 1138 if (src_len > remaining) 1139 remaining = (src_len - remaining) % ULP_BLOB_BYTE; 1140 else 1141 remaining = 0; 1142 if (remaining) { 1143 bluff = (*src_buf) & ((uint8_t)-1 << 1144 (ULP_BLOB_BYTE - remaining)); 1145 ulp_bs_put_msb(dst->data, dst->write_idx, 1146 ULP_BLOB_BYTE, bluff); 1147 dst->write_idx += remaining; 1148 } 1149 1150 return 0; 1151 } 1152 1153 /* 1154 * Perform the blob buffer copy. 1155 * This api makes the src blob merged to the dst blob. 1156 * 1157 * dst [in] The destination blob, the blob to be merged. 1158 * src [in] The src blob. 1159 * 1160 * returns 0 on success. 1161 */ 1162 static inline int32_t 1163 ulp_blob_buffer_copy(struct ulp_blob *dst, struct ulp_blob *src) 1164 { 1165 if (unlikely((dst->write_idx + src->write_idx) > dst->bitlen)) { 1166 BNXT_DRV_DBG(ERR, "source buffer too large\n"); 1167 return -EINVAL; 1168 } 1169 if (unlikely(ULP_BITS_IS_BYTE_NOT_ALIGNED(dst->write_idx) || 1170 ULP_BITS_IS_BYTE_NOT_ALIGNED(src->write_idx))) { 1171 BNXT_DRV_DBG(ERR, "source buffer is not aligned\n"); 1172 return -EINVAL; 1173 } 1174 memcpy(&dst->data[ULP_BITS_2_BYTE_NR(dst->write_idx)], 1175 src->data, ULP_BITS_2_BYTE_NR(src->write_idx)); 1176 dst->write_idx += src->write_idx; 1177 return 0; 1178 } 1179 1180 /* 1181 * Read data from the operand 1182 * 1183 * operand [in] A pointer to a 16 Byte operand 1184 * 1185 * val [in/out] The variable to copy the operand to 1186 * 1187 * bytes [in] The number of bytes to read into val 1188 * 1189 * returns zero on success. 1190 */ 1191 static inline int32_t 1192 ulp_operand_read(uint8_t *operand, 1193 uint8_t *val, 1194 uint16_t bytes) 1195 { 1196 /* validate the arguments */ 1197 if (unlikely(!operand || !val)) { 1198 BNXT_DRV_DBG(ERR, "invalid argument\n"); 1199 return -EINVAL; 1200 } 1201 memcpy(val, operand, bytes); 1202 return 0; 1203 } 1204 1205 /* Function to check if bitmap is ones. Return 1 on success */ 1206 static inline uint32_t 1207 ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size) 1208 { 1209 while (size-- > 0) { 1210 if (*bitmap != 0xFF) 1211 return 0; 1212 bitmap++; 1213 } 1214 return 1; 1215 } 1216 1217 /* Function to check if bitmap is not zero. Return 1 on success */ 1218 static inline uint32_t 1219 ulp_bitmap_notzero(const uint8_t *bitmap, int32_t size) 1220 { 1221 while (size-- > 0) { 1222 if (*bitmap != 0) 1223 return 1; 1224 bitmap++; 1225 } 1226 return 0; 1227 } 1228 1229 /* returns 0 if input is power of 2 */ 1230 static inline int32_t 1231 ulp_util_is_power_of_2(uint64_t x) 1232 { 1233 if (((x - 1) & x)) 1234 return -1; 1235 return 0; 1236 } 1237 #endif /* _ULP_UTILS_H_ */ 1238