1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2019 Broadcom 3 * All rights reserved. 4 */ 5 6 #include "ulp_utils.h" 7 #include "bnxt_tf_common.h" 8 9 /* 10 * Initialize the regfile structure for writing 11 * 12 * regfile [in] Ptr to a regfile instance 13 * 14 * returns 0 on error or 1 on success 15 */ 16 uint32_t 17 ulp_regfile_init(struct ulp_regfile *regfile) 18 { 19 /* validate the arguments */ 20 if (!regfile) { 21 BNXT_TF_DBG(ERR, "invalid argument\n"); 22 return 0; /* failure */ 23 } 24 memset(regfile, 0, sizeof(struct ulp_regfile)); 25 return 1; /* Success */ 26 } 27 28 /* 29 * Read a value from the regfile 30 * 31 * regfile [in] The regfile instance. Must be initialized prior to being used 32 * 33 * field [in] The field to be read within the regfile. 34 * 35 * data [in/out] 36 * 37 * returns size, zero on failure 38 */ 39 uint32_t 40 ulp_regfile_read(struct ulp_regfile *regfile, 41 enum bnxt_ulp_regfile_index field, 42 uint64_t *data) 43 { 44 /* validate the arguments */ 45 if (!regfile || field >= BNXT_ULP_REGFILE_INDEX_LAST) { 46 BNXT_TF_DBG(ERR, "invalid argument\n"); 47 return 0; /* failure */ 48 } 49 50 *data = regfile->entry[field].data; 51 return sizeof(*data); 52 } 53 54 /* 55 * Write a value to the regfile 56 * 57 * regfile [in] The regfile instance. Must be initialized prior to being used 58 * 59 * field [in] The field to be written within the regfile. 60 * 61 * data [in] The value is written into this variable. It is going to be in the 62 * same byte order as it was written. 63 * 64 * size [in] The size in bytes of the value beingritten into this 65 * variable. 66 * 67 * returns 0 on fail 68 */ 69 uint32_t 70 ulp_regfile_write(struct ulp_regfile *regfile, 71 enum bnxt_ulp_regfile_index field, 72 uint64_t data) 73 { 74 /* validate the arguments */ 75 if (!regfile || field >= BNXT_ULP_REGFILE_INDEX_LAST) { 76 BNXT_TF_DBG(ERR, "invalid argument\n"); 77 return 0; /* failure */ 78 } 79 80 regfile->entry[field].data = data; 81 return sizeof(data); /* Success */ 82 } 83 84 static void 85 ulp_bs_put_msb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val) 86 { 87 uint8_t bitoffs = bitpos % 8; 88 uint16_t index = bitpos / 8; 89 uint8_t mask; 90 uint8_t tmp; 91 int8_t shift; 92 93 tmp = bs[index]; 94 mask = ((uint8_t)-1 >> (8 - bitlen)); 95 shift = 8 - bitoffs - bitlen; 96 val &= mask; 97 98 if (shift >= 0) { 99 tmp &= ~(mask << shift); 100 tmp |= val << shift; 101 bs[index] = tmp; 102 } else { 103 tmp &= ~((uint8_t)-1 >> bitoffs); 104 tmp |= val >> -shift; 105 bs[index++] = tmp; 106 107 tmp = bs[index]; 108 tmp &= ((uint8_t)-1 >> (bitlen - (8 - bitoffs))); 109 tmp |= val << (8 + shift); 110 bs[index] = tmp; 111 } 112 } 113 114 static void 115 ulp_bs_put_lsb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val) 116 { 117 uint8_t bitoffs = bitpos % 8; 118 uint16_t index = bitpos / 8; 119 uint8_t mask; 120 uint8_t tmp; 121 uint8_t shift; 122 uint8_t partial; 123 124 tmp = bs[index]; 125 shift = bitoffs; 126 127 if (bitoffs + bitlen <= 8) { 128 mask = ((1 << bitlen) - 1) << shift; 129 tmp &= ~mask; 130 tmp |= ((val << shift) & mask); 131 bs[index] = tmp; 132 } else { 133 partial = 8 - bitoffs; 134 mask = ((1 << partial) - 1) << shift; 135 tmp &= ~mask; 136 tmp |= ((val << shift) & mask); 137 bs[index++] = tmp; 138 139 val >>= partial; 140 partial = bitlen - partial; 141 mask = ((1 << partial) - 1); 142 tmp = bs[index]; 143 tmp &= ~mask; 144 tmp |= (val & mask); 145 bs[index] = tmp; 146 } 147 } 148 149 /* Assuming that val is in Big-Endian Format */ 150 static uint32_t 151 ulp_bs_push_lsb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val) 152 { 153 int i; 154 int cnt = (len) / 8; 155 int tlen = len; 156 157 if (cnt > 0 && !(len % 8)) 158 cnt -= 1; 159 160 for (i = 0; i < cnt; i++) { 161 ulp_bs_put_lsb(bs, pos, 8, val[cnt - i]); 162 pos += 8; 163 tlen -= 8; 164 } 165 166 /* Handle the remainder bits */ 167 if (tlen) 168 ulp_bs_put_lsb(bs, pos, tlen, val[0]); 169 return len; 170 } 171 172 /* Assuming that val is in Big-Endian Format */ 173 static uint32_t 174 ulp_bs_push_msb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val) 175 { 176 int i; 177 int cnt = (len + 7) / 8; 178 int tlen = len; 179 180 /* Handle any remainder bits */ 181 int tmp = len % 8; 182 183 if (!tmp) 184 tmp = 8; 185 186 ulp_bs_put_msb(bs, pos, tmp, val[0]); 187 188 pos += tmp; 189 tlen -= tmp; 190 191 for (i = 1; i < cnt; i++) { 192 ulp_bs_put_msb(bs, pos, 8, val[i]); 193 pos += 8; 194 tlen -= 8; 195 } 196 197 return len; 198 } 199 200 /* 201 * Initializes the blob structure for creating binary blob 202 * 203 * blob [in] The blob to be initialized 204 * 205 * bitlen [in] The bit length of the blob 206 * 207 * order [in] The byte order for the blob. Currently only supporting 208 * big endian. All fields are packed with this order. 209 * 210 * returns 0 on error or 1 on success 211 */ 212 uint32_t 213 ulp_blob_init(struct ulp_blob *blob, 214 uint16_t bitlen, 215 enum bnxt_ulp_byte_order order) 216 { 217 /* validate the arguments */ 218 if (!blob || bitlen > (8 * sizeof(blob->data))) { 219 BNXT_TF_DBG(ERR, "invalid argument\n"); 220 return 0; /* failure */ 221 } 222 blob->bitlen = bitlen; 223 blob->byte_order = order; 224 blob->write_idx = 0; 225 memset(blob->data, 0, sizeof(blob->data)); 226 return 1; /* Success */ 227 } 228 229 /* 230 * Add data to the binary blob at the current offset. 231 * 232 * blob [in] The blob that data is added to. The blob must 233 * be initialized prior to pushing data. 234 * 235 * data [in] A pointer to bytes to be added to the blob. 236 * 237 * datalen [in] The number of bits to be added to the blob. 238 * 239 * The offset of the data is updated after each push of data. 240 * NULL returned on error. 241 */ 242 #define ULP_BLOB_BYTE 8 243 #define ULP_BLOB_BYTE_HEX 0xFF 244 #define BLOB_MASK_CAL(x) ((0xFF << (x)) & 0xFF) 245 uint32_t 246 ulp_blob_push(struct ulp_blob *blob, 247 uint8_t *data, 248 uint32_t datalen) 249 { 250 uint32_t rc; 251 252 /* validate the arguments */ 253 if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx)) { 254 BNXT_TF_DBG(ERR, "invalid argument\n"); 255 return 0; /* failure */ 256 } 257 258 if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) 259 rc = ulp_bs_push_msb(blob->data, 260 blob->write_idx, 261 datalen, 262 data); 263 else 264 rc = ulp_bs_push_lsb(blob->data, 265 blob->write_idx, 266 datalen, 267 data); 268 if (!rc) { 269 BNXT_TF_DBG(ERR, "Failed ro write blob\n"); 270 return 0; 271 } 272 blob->write_idx += datalen; 273 return datalen; 274 } 275 276 /* 277 * Add data to the binary blob at the current offset. 278 * 279 * blob [in] The blob that data is added to. The blob must 280 * be initialized prior to pushing data. 281 * 282 * data [in] 64-bit value to be added to the blob. 283 * 284 * datalen [in] The number of bits to be added to the blob. 285 * 286 * The offset of the data is updated after each push of data. 287 * NULL returned on error, pointer pushed value otherwise. 288 */ 289 uint8_t * 290 ulp_blob_push_64(struct ulp_blob *blob, 291 uint64_t *data, 292 uint32_t datalen) 293 { 294 uint8_t *val = (uint8_t *)data; 295 int rc; 296 297 int size = (datalen + 7) / 8; 298 299 if (!blob || !data || 300 datalen > (uint32_t)(blob->bitlen - blob->write_idx)) { 301 BNXT_TF_DBG(ERR, "invalid argument\n"); 302 return 0; 303 } 304 305 rc = ulp_blob_push(blob, &val[8 - size], datalen); 306 if (!rc) 307 return 0; 308 309 return &val[8 - size]; 310 } 311 312 /* 313 * Add encap data to the binary blob at the current offset. 314 * 315 * blob [in] The blob that data is added to. The blob must 316 * be initialized prior to pushing data. 317 * 318 * data [in] value to be added to the blob. 319 * 320 * datalen [in] The number of bits to be added to the blob. 321 * 322 * The offset of the data is updated after each push of data. 323 * NULL returned on error, pointer pushed value otherwise. 324 */ 325 uint32_t 326 ulp_blob_push_encap(struct ulp_blob *blob, 327 uint8_t *data, 328 uint32_t datalen) 329 { 330 uint8_t *val = (uint8_t *)data; 331 uint32_t initial_size, write_size = datalen; 332 uint32_t size = 0; 333 334 if (!blob || !data || 335 datalen > (uint32_t)(blob->bitlen - blob->write_idx)) { 336 BNXT_TF_DBG(ERR, "invalid argument\n"); 337 return 0; 338 } 339 340 initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) - 341 (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t))); 342 while (write_size > 0) { 343 if (initial_size && write_size > initial_size) { 344 size = initial_size; 345 initial_size = 0; 346 } else if (initial_size && write_size <= initial_size) { 347 size = write_size; 348 initial_size = 0; 349 } else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) { 350 size = ULP_BYTE_2_BITS(sizeof(uint64_t)); 351 } else { 352 size = write_size; 353 } 354 if (!ulp_blob_push(blob, val, size)) { 355 BNXT_TF_DBG(ERR, "push field failed\n"); 356 return 0; 357 } 358 val += ULP_BITS_2_BYTE(size); 359 write_size -= size; 360 } 361 return datalen; 362 } 363 364 /* 365 * Adds pad to an initialized blob at the current offset 366 * 367 * blob [in] The blob that data is added to. The blob must 368 * be initialized prior to pushing data. 369 * 370 * datalen [in] The number of bits of pad to add 371 * 372 * returns the number of pad bits added, zero on failure 373 */ 374 uint32_t 375 ulp_blob_pad_push(struct ulp_blob *blob, 376 uint32_t datalen) 377 { 378 if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) { 379 BNXT_TF_DBG(ERR, "Pad too large for blob\n"); 380 return 0; 381 } 382 383 blob->write_idx += datalen; 384 return datalen; 385 } 386 387 /* 388 * Get the data portion of the binary blob. 389 * 390 * blob [in] The blob's data to be retrieved. The blob must be 391 * initialized prior to pushing data. 392 * 393 * datalen [out] The number of bits to that are filled. 394 * 395 * returns a byte array of the blob data. Returns NULL on error. 396 */ 397 uint8_t * 398 ulp_blob_data_get(struct ulp_blob *blob, 399 uint16_t *datalen) 400 { 401 /* validate the arguments */ 402 if (!blob) { 403 BNXT_TF_DBG(ERR, "invalid argument\n"); 404 return NULL; /* failure */ 405 } 406 *datalen = blob->write_idx; 407 return blob->data; 408 } 409 410 /* 411 * Set the encap swap start index of the binary blob. 412 * 413 * blob [in] The blob's data to be retrieved. The blob must be 414 * initialized prior to pushing data. 415 * 416 * returns void. 417 */ 418 void 419 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob) 420 { 421 /* validate the arguments */ 422 if (!blob) { 423 BNXT_TF_DBG(ERR, "invalid argument\n"); 424 return; /* failure */ 425 } 426 blob->encap_swap_idx = blob->write_idx; 427 } 428 429 /* 430 * Perform the encap buffer swap to 64 bit reversal. 431 * 432 * blob [in] The blob's data to be used for swap. 433 * 434 * returns void. 435 */ 436 void 437 ulp_blob_perform_encap_swap(struct ulp_blob *blob) 438 { 439 uint32_t i, idx = 0, end_idx = 0; 440 uint8_t temp_val_1, temp_val_2; 441 442 /* validate the arguments */ 443 if (!blob) { 444 BNXT_TF_DBG(ERR, "invalid argument\n"); 445 return; /* failure */ 446 } 447 idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx + 1); 448 end_idx = ULP_BITS_2_BYTE(blob->write_idx); 449 450 while (idx <= end_idx) { 451 for (i = 0; i < 4; i = i + 2) { 452 temp_val_1 = blob->data[idx + i]; 453 temp_val_2 = blob->data[idx + i + 1]; 454 blob->data[idx + i] = blob->data[idx + 6 - i]; 455 blob->data[idx + i + 1] = blob->data[idx + 7 - i]; 456 blob->data[idx + 7 - i] = temp_val_2; 457 blob->data[idx + 6 - i] = temp_val_1; 458 } 459 idx += 8; 460 } 461 } 462 463 /* 464 * Read data from the operand 465 * 466 * operand [in] A pointer to a 16 Byte operand 467 * 468 * val [in/out] The variable to copy the operand to 469 * 470 * bytes [in] The number of bytes to read into val 471 * 472 * returns number of bits read, zero on error 473 */ 474 uint16_t 475 ulp_operand_read(uint8_t *operand, 476 uint8_t *val, 477 uint16_t bytes) 478 { 479 /* validate the arguments */ 480 if (!operand || !val) { 481 BNXT_TF_DBG(ERR, "invalid argument\n"); 482 return 0; /* failure */ 483 } 484 memcpy(val, operand, bytes); 485 return bytes; 486 } 487 488 /* 489 * copy the buffer in the encap format which is 2 bytes. 490 * The MSB of the src is placed at the LSB of dst. 491 * 492 * dst [out] The destination buffer 493 * src [in] The source buffer dst 494 * size[in] size of the buffer. 495 */ 496 void 497 ulp_encap_buffer_copy(uint8_t *dst, 498 const uint8_t *src, 499 uint16_t size) 500 { 501 uint16_t idx = 0; 502 503 /* copy 2 bytes at a time. Write MSB to LSB */ 504 while ((idx + sizeof(uint16_t)) <= size) { 505 memcpy(&dst[idx], &src[size - idx - sizeof(uint16_t)], 506 sizeof(uint16_t)); 507 idx += sizeof(uint16_t); 508 } 509 } 510 511 /* 512 * Check the buffer is empty 513 * 514 * buf [in] The buffer 515 * size [in] The size of the buffer 516 * 517 */ 518 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size) 519 { 520 return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1); 521 } 522 523 /* Function to check if bitmap is zero.Return 1 on success */ 524 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size) 525 { 526 while (size-- > 0) { 527 if (*bitmap != 0) 528 return 0; 529 bitmap++; 530 } 531 return 1; 532 } 533 534 /* Function to check if bitmap is ones. Return 1 on success */ 535 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size) 536 { 537 while (size-- > 0) { 538 if (*bitmap != 0xFF) 539 return 0; 540 bitmap++; 541 } 542 return 1; 543 } 544 545 /* Function to check if bitmap is not zero. Return 1 on success */ 546 uint32_t ulp_bitmap_notzero(uint8_t *bitmap, int32_t size) 547 { 548 while (size-- > 0) { 549 if (*bitmap != 0) 550 return 1; 551 bitmap++; 552 } 553 return 0; 554 } 555