Branch data Line data Source code
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 0 on error or 1 on success
16 : : */
17 : : uint32_t
18 : 0 : ulp_regfile_init(struct ulp_regfile *regfile)
19 : : {
20 : : /* validate the arguments */
21 [ # # ]: 0 : if (!regfile) {
22 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
23 : 0 : return 0; /* failure */
24 : : }
25 : : memset(regfile, 0, sizeof(struct ulp_regfile));
26 : 0 : 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 : 0 : ulp_regfile_read(struct ulp_regfile *regfile,
42 : : enum bnxt_ulp_rf_idx field,
43 : : uint64_t *data)
44 : : {
45 : : /* validate the arguments */
46 [ # # ]: 0 : if (!regfile || field >= BNXT_ULP_RF_IDX_LAST) {
47 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
48 : 0 : return 0; /* failure */
49 : : }
50 : :
51 : 0 : *data = regfile->entry[field].data;
52 : 0 : 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 : 0 : ulp_regfile_write(struct ulp_regfile *regfile,
72 : : enum bnxt_ulp_rf_idx field,
73 : : uint64_t data)
74 : : {
75 : : /* validate the arguments */
76 [ # # ]: 0 : if (!regfile || field >= BNXT_ULP_RF_IDX_LAST) {
77 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
78 : 0 : return -EINVAL; /* failure */
79 : : }
80 : :
81 : 0 : regfile->entry[field].data = data;
82 : 0 : return 0; /* Success */
83 : : }
84 : :
85 : : static void
86 : 0 : ulp_bs_put_msb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val)
87 : : {
88 : 0 : uint8_t bitoffs = bitpos % 8;
89 : 0 : uint16_t index = bitpos / 8;
90 : : uint8_t mask;
91 : : uint8_t tmp;
92 : : int8_t shift;
93 : :
94 : 0 : tmp = bs[index];
95 : 0 : mask = ((uint8_t)-1 >> (8 - bitlen));
96 : 0 : shift = 8 - bitoffs - bitlen;
97 : 0 : val &= mask;
98 : :
99 [ # # ]: 0 : if (shift >= 0) {
100 : 0 : tmp &= ~(mask << shift);
101 : 0 : tmp |= val << shift;
102 : 0 : bs[index] = tmp;
103 : : } else {
104 : 0 : tmp &= ~((uint8_t)-1 >> bitoffs);
105 : 0 : tmp |= val >> -shift;
106 : 0 : bs[index++] = tmp;
107 : :
108 : 0 : tmp = bs[index];
109 : 0 : tmp &= ((uint8_t)-1 >> (bitlen - (8 - bitoffs)));
110 : 0 : tmp |= val << (8 + shift);
111 : 0 : bs[index] = tmp;
112 : : }
113 : 0 : }
114 : :
115 : : static void
116 : 0 : ulp_bs_put_lsb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val)
117 : : {
118 : 0 : uint8_t bitoffs = bitpos % 8;
119 : 0 : uint16_t index = bitpos / 8;
120 : : uint8_t mask;
121 : : uint8_t tmp;
122 : : uint8_t shift;
123 : : uint8_t partial;
124 : :
125 : 0 : tmp = bs[index];
126 : : shift = bitoffs;
127 : :
128 [ # # ]: 0 : if (bitoffs + bitlen <= 8) {
129 : 0 : mask = ((1 << bitlen) - 1) << shift;
130 : 0 : tmp &= ~mask;
131 : 0 : tmp |= ((val << shift) & mask);
132 : 0 : bs[index] = tmp;
133 : : } else {
134 : 0 : partial = 8 - bitoffs;
135 : 0 : mask = ((1 << partial) - 1) << shift;
136 : 0 : tmp &= ~mask;
137 : 0 : tmp |= ((val << shift) & mask);
138 : 0 : bs[index++] = tmp;
139 : :
140 : 0 : val >>= partial;
141 : 0 : partial = bitlen - partial;
142 : 0 : mask = ((1 << partial) - 1);
143 : 0 : tmp = bs[index];
144 : : tmp &= ~mask;
145 : 0 : tmp |= (val & mask);
146 : 0 : bs[index] = tmp;
147 : : }
148 : 0 : }
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 : 0 : ulp_bs_push_lsb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
165 : : {
166 : : int i;
167 : 0 : int cnt = (len) / 8;
168 : 0 : int tlen = len;
169 : :
170 [ # # # # ]: 0 : if (cnt > 0 && !(len % 8))
171 : 0 : cnt -= 1;
172 : :
173 [ # # ]: 0 : for (i = 0; i < cnt; i++) {
174 : 0 : ulp_bs_put_lsb(bs, pos, 8, val[cnt - i]);
175 : 0 : pos += 8;
176 : 0 : tlen -= 8;
177 : : }
178 : :
179 : : /* Handle the remainder bits */
180 [ # # ]: 0 : if (tlen)
181 : 0 : ulp_bs_put_lsb(bs, pos, tlen, val[0]);
182 : 0 : 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 : 0 : ulp_bs_push_msb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val)
200 : : {
201 : : int i;
202 : 0 : int cnt = (len + 7) / 8;
203 : :
204 : : /* Handle any remainder bits */
205 : 0 : int tmp = len % 8;
206 : :
207 [ # # ]: 0 : if (!tmp)
208 : : tmp = 8;
209 : :
210 : 0 : ulp_bs_put_msb(bs, pos, tmp, val[0]);
211 : :
212 : 0 : pos += tmp;
213 : :
214 [ # # ]: 0 : for (i = 1; i < cnt; i++) {
215 : 0 : ulp_bs_put_msb(bs, pos, 8, val[i]);
216 : 0 : pos += 8;
217 : : }
218 : :
219 : 0 : 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 : 0 : ulp_blob_init(struct ulp_blob *blob,
237 : : uint16_t bitlen,
238 : : enum bnxt_ulp_byte_order order)
239 : : {
240 : : /* validate the arguments */
241 [ # # ]: 0 : if (!blob || bitlen > (8 * sizeof(blob->data))) {
242 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
243 : 0 : return 0; /* failure */
244 : : }
245 [ # # ]: 0 : if (bitlen)
246 : 0 : blob->bitlen = bitlen;
247 : : else
248 : 0 : blob->bitlen = BNXT_ULP_FLMP_BLOB_SIZE_IN_BITS;
249 : 0 : blob->byte_order = order;
250 : 0 : blob->write_idx = 0;
251 : 0 : memset(blob->data, 0, sizeof(blob->data));
252 : 0 : 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 : 0 : 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 [ # # # # ]: 0 : if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
280 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
281 : 0 : return 0; /* failure */
282 : : }
283 : :
284 [ # # ]: 0 : if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
285 : 0 : rc = ulp_bs_push_msb(blob->data,
286 : : blob->write_idx,
287 : : datalen,
288 : : data);
289 : : else
290 : 0 : rc = ulp_bs_push_lsb(blob->data,
291 : : blob->write_idx,
292 : : datalen,
293 : : data);
294 [ # # ]: 0 : if (!rc) {
295 : 0 : BNXT_TF_DBG(ERR, "Failed to write blob\n");
296 : 0 : return 0;
297 : : }
298 : 0 : blob->write_idx += datalen;
299 : 0 : 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 : 0 : 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 [ # # # # ]: 0 : if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx) ||
327 [ # # ]: 0 : offset > blob->write_idx) {
328 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
329 : 0 : return 0; /* failure */
330 : : }
331 : :
332 : 0 : mov_len = blob->write_idx - offset;
333 : : /* If offset and data len are not 8 bit aligned then return error */
334 [ # # ]: 0 : if (ULP_BITS_IS_BYTE_NOT_ALIGNED(offset) ||
335 [ # # ]: 0 : ULP_BITS_IS_BYTE_NOT_ALIGNED(datalen)) {
336 : 0 : BNXT_TF_DBG(ERR, "invalid argument, not aligned\n");
337 : 0 : return 0; /* failure */
338 : : }
339 : :
340 : : /* copy the data so we can move the data */
341 : 0 : memcpy(local_data, &blob->data[ULP_BITS_2_BYTE_NR(offset)],
342 [ # # ]: 0 : ULP_BITS_2_BYTE(mov_len));
343 : 0 : blob->write_idx = offset;
344 [ # # ]: 0 : if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
345 : 0 : rc = ulp_bs_push_msb(blob->data,
346 : : blob->write_idx,
347 : : datalen,
348 : : data);
349 : : else
350 : 0 : rc = ulp_bs_push_lsb(blob->data,
351 : : blob->write_idx,
352 : : datalen,
353 : : data);
354 [ # # ]: 0 : if (!rc) {
355 : 0 : BNXT_TF_DBG(ERR, "Failed to write blob\n");
356 : 0 : return 0;
357 : : }
358 : : /* copy the previously stored data */
359 : 0 : memcpy(&blob->data[ULP_BITS_2_BYTE_NR(offset + datalen)], local_data,
360 : : ULP_BITS_2_BYTE(mov_len));
361 : 0 : blob->write_idx += (mov_len + datalen);
362 : 0 : 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 : 0 : 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 : 0 : int size = (datalen + 7) / 8;
387 : :
388 [ # # ]: 0 : if (!blob || !data ||
389 [ # # ]: 0 : datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
390 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
391 : 0 : return 0;
392 : : }
393 : :
394 : 0 : rc = ulp_blob_push(blob, &val[8 - size], datalen);
395 [ # # ]: 0 : if (!rc)
396 : 0 : 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 : 0 : 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 : 0 : uint32_t size = ULP_BITS_2_BYTE(datalen);
422 : :
423 [ # # ]: 0 : if (!data || size > sizeof(uint32_t)) {
424 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
425 : 0 : return 0;
426 : : }
427 : :
428 : 0 : rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen);
429 [ # # ]: 0 : if (!rc)
430 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (!blob || !data ||
458 [ # # ]: 0 : datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
459 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
460 : 0 : return -1;
461 : : }
462 : :
463 : 0 : initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
464 : 0 : (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
465 [ # # ]: 0 : while (write_size > 0) {
466 [ # # ]: 0 : if (initial_size && write_size > initial_size) {
467 : : size = initial_size;
468 : : initial_size = 0;
469 [ # # ]: 0 : } 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 [ # # ]: 0 : if (!ulp_blob_push(blob, val, size)) {
478 : 0 : BNXT_TF_DBG(ERR, "push field failed\n");
479 : 0 : return -1;
480 : : }
481 : 0 : val += ULP_BITS_2_BYTE(size);
482 : 0 : write_size -= size;
483 : : }
484 : 0 : 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 : 0 : ulp_blob_pad_push(struct ulp_blob *blob,
499 : : uint32_t datalen)
500 : : {
501 [ # # ]: 0 : if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
502 : 0 : BNXT_TF_DBG(ERR, "Pad too large for blob\n");
503 : 0 : return -1;
504 : : }
505 : :
506 : 0 : blob->write_idx += datalen;
507 : 0 : 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 : 0 : ulp_blob_pad_align(struct ulp_blob *blob,
522 : : uint32_t align)
523 : : {
524 : : int32_t pad = 0;
525 : :
526 : 0 : pad = RTE_ALIGN(blob->write_idx, align) - blob->write_idx;
527 [ # # ]: 0 : if (pad > (int32_t)(blob->bitlen - blob->write_idx)) {
528 : 0 : BNXT_TF_DBG(ERR, "Pad too large for blob\n");
529 : 0 : return -1;
530 : : }
531 : 0 : blob->write_idx += pad;
532 : 0 : return pad;
533 : : }
534 : :
535 : : /* Get data from src and put into dst using little-endian format */
536 : : static void
537 : 0 : ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
538 : : {
539 : 0 : uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
540 : 0 : uint16_t index = ULP_BITS_2_BYTE_NR(bitpos);
541 : : uint8_t mask, partial, shift;
542 : :
543 : : shift = bitoffs;
544 : 0 : partial = ULP_BLOB_BYTE - bitoffs;
545 [ # # ]: 0 : if (bitoffs + bitlen <= ULP_BLOB_BYTE) {
546 : 0 : mask = ((1 << bitlen) - 1) << shift;
547 : 0 : *dst = (src[index] & mask) >> shift;
548 : : } else {
549 : 0 : mask = ((1 << partial) - 1) << shift;
550 : 0 : *dst = (src[index] & mask) >> shift;
551 : 0 : index++;
552 : 0 : partial = bitlen - partial;
553 : 0 : mask = ((1 << partial) - 1);
554 : 0 : *dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs);
555 : : }
556 : 0 : }
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 : 0 : 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 : 0 : uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
579 : :
580 : : /* iterate bytewise to get data */
581 [ # # ]: 0 : for (idx = 0; idx < cnt; idx++) {
582 : 0 : ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE,
583 : 0 : &dst[size - 1 - idx]);
584 : 0 : offset += ULP_BLOB_BYTE;
585 : 0 : len -= ULP_BLOB_BYTE;
586 : : }
587 : :
588 : : /* Extract the last reminder data that is not 8 byte boundary */
589 [ # # ]: 0 : if (len)
590 : 0 : ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]);
591 : 0 : }
592 : :
593 : : /* Get data from src and put into dst using big-endian format */
594 : : static void
595 : 0 : ulp_bs_get_msb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst)
596 : : {
597 : 0 : uint8_t bitoffs = bitpos % ULP_BLOB_BYTE;
598 : 0 : uint16_t index = ULP_BITS_2_BYTE_NR(bitpos);
599 : : uint8_t mask;
600 : : int32_t shift;
601 : :
602 : 0 : shift = ULP_BLOB_BYTE - bitoffs - bitlen;
603 [ # # ]: 0 : if (shift >= 0) {
604 : : mask = 0xFF >> -bitlen;
605 : 0 : *dst = (src[index] >> shift) & mask;
606 : : } else {
607 : 0 : *dst = (src[index] & (0xFF >> bitoffs)) << -shift;
608 : 0 : *dst |= src[index + 1] >> -shift;
609 : : }
610 : 0 : }
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 : 0 : ulp_bs_pull_msb(uint8_t *src, uint8_t *dst,
627 : : uint32_t offset, uint32_t len)
628 : : {
629 : : uint32_t idx;
630 : 0 : uint32_t cnt = ULP_BITS_2_BYTE_NR(len);
631 : :
632 : : /* iterate bytewise to get data */
633 [ # # ]: 0 : for (idx = 0; idx < cnt; idx++) {
634 : 0 : ulp_bs_get_msb(src, offset, ULP_BLOB_BYTE, &dst[idx]);
635 : 0 : offset += ULP_BLOB_BYTE;
636 : 0 : len -= ULP_BLOB_BYTE;
637 : : }
638 : :
639 : : /* Extract the last reminder data that is not 8 byte boundary */
640 [ # # ]: 0 : if (len)
641 : 0 : ulp_bs_get_msb(src, offset, len, &dst[idx]);
642 : 0 : }
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 : 0 : 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 [ # # # # ]: 0 : if (!blob || (offset + len) > blob->bitlen ||
663 [ # # ]: 0 : ULP_BYTE_2_BITS(data_size) < len) {
664 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
665 : 0 : return -1; /* failure */
666 : : }
667 : :
668 [ # # ]: 0 : if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE)
669 : 0 : ulp_bs_pull_msb(blob->data, data, offset, len);
670 : : else
671 : 0 : 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 : 0 : ulp_blob_data_get(struct ulp_blob *blob,
687 : : uint16_t *datalen)
688 : : {
689 : : /* validate the arguments */
690 [ # # ]: 0 : if (!blob) {
691 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
692 : 0 : return NULL; /* failure */
693 : : }
694 : 0 : *datalen = blob->write_idx;
695 : 0 : 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 : 0 : ulp_blob_data_len_get(struct ulp_blob *blob)
707 : : {
708 : : /* validate the arguments */
709 [ # # ]: 0 : if (!blob) {
710 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
711 : 0 : return 0; /* failure */
712 : : }
713 : 0 : 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 : 0 : ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
726 : : {
727 : : /* validate the arguments */
728 [ # # ]: 0 : if (!blob) {
729 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
730 : 0 : return; /* failure */
731 : : }
732 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (!blob) {
750 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
751 : 0 : return; /* failure */
752 : : }
753 : 0 : idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx);
754 : 0 : end_idx = ULP_BITS_2_BYTE(blob->write_idx);
755 : 0 : roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx));
756 [ # # ]: 0 : if (roundoff > end_idx) {
757 : 0 : blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx);
758 : : end_idx = roundoff;
759 : : }
760 [ # # ]: 0 : while (idx <= end_idx) {
761 [ # # ]: 0 : for (i = 0; i < 4; i = i + 2) {
762 : 0 : temp_val_1 = blob->data[idx + i];
763 : 0 : temp_val_2 = blob->data[idx + i + 1];
764 : 0 : blob->data[idx + i] = blob->data[idx + 6 - i];
765 : 0 : blob->data[idx + i + 1] = blob->data[idx + 7 - i];
766 : 0 : blob->data[idx + 7 - i] = temp_val_2;
767 : 0 : blob->data[idx + 6 - i] = temp_val_1;
768 : : }
769 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (!blob) {
793 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
794 : 0 : return; /* failure */
795 : : }
796 : :
797 : 0 : buff = blob->data;
798 : 0 : num = ULP_BITS_2_BYTE(blob->write_idx) / chunk_size;
799 [ # # ]: 0 : for (idx = 0; idx < num; idx++) {
800 [ # # ]: 0 : for (jdx = 0; jdx < chunk_size / 2; jdx++) {
801 : 0 : xchar = buff[jdx];
802 : 0 : buff[jdx] = buff[(chunk_size - 1) - jdx];
803 : 0 : buff[(chunk_size - 1) - jdx] = xchar;
804 : : }
805 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (!blob) {
827 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
828 : 0 : return; /* failure */
829 : : }
830 : 0 : num = ULP_BITS_2_BYTE(blob->write_idx);
831 [ # # ]: 0 : for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
832 [ # # ]: 0 : for (j = 0; j < word_size; j++) {
833 : 0 : xchar = blob->data[i + j];
834 : 0 : blob->data[i + j] = blob->data[i + j + word_size];
835 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (!blob) {
858 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
859 : 0 : return; /* failure */
860 : : }
861 : 0 : num = ULP_BITS_2_BYTE(blob->write_idx);
862 [ # # ]: 0 : for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) {
863 [ # # ]: 0 : for (j = 0; j < (ULP_64B_IN_BYTES / 2); j++) {
864 : 0 : xchar = blob->data[i + j];
865 : 0 : blob->data[i + j] = blob->data[i + offset - j];
866 : 0 : blob->data[i + offset - j] = xchar;
867 : : }
868 : : }
869 : : }
870 : :
871 : : static int32_t
872 : 0 : 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 : 0 : uint8_t *src_buf = ulp_blob_data_get(src, &num);
878 : : uint8_t bluff;
879 : :
880 [ # # ]: 0 : for (i = 0; i < num;) {
881 [ # # ]: 0 : if (((dst->write_idx % block_size) + (num - i)) > block_size)
882 : 0 : write_bytes = block_size -
883 : : (dst->write_idx % block_size);
884 : : else
885 : : write_bytes = num - i;
886 [ # # ]: 0 : for (k = 0; k < ULP_BITS_2_BYTE_NR(write_bytes); k++) {
887 : 0 : ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE,
888 : 0 : *src_buf);
889 : 0 : dst->write_idx += ULP_BLOB_BYTE;
890 : 0 : src_buf++;
891 : : }
892 : 0 : remaining = write_bytes % ULP_BLOB_BYTE;
893 [ # # ]: 0 : if (remaining) {
894 : 0 : bluff = (*src_buf) & ((uint8_t)-1 <<
895 : 0 : (ULP_BLOB_BYTE - remaining));
896 : 0 : ulp_bs_put_msb(dst->data, dst->write_idx,
897 : : ULP_BLOB_BYTE, bluff);
898 : 0 : dst->write_idx += remaining;
899 : : }
900 [ # # ]: 0 : if (write_bytes != (num - i)) {
901 : : /* add the padding */
902 : 0 : ulp_blob_pad_push(dst, pad);
903 [ # # ]: 0 : if (remaining) {
904 : 0 : ulp_bs_put_msb(dst->data, dst->write_idx,
905 : 0 : ULP_BLOB_BYTE - remaining,
906 : 0 : *src_buf);
907 : 0 : dst->write_idx += ULP_BLOB_BYTE - remaining;
908 : 0 : src_buf++;
909 : : }
910 : : }
911 : 0 : i += write_bytes;
912 : : }
913 : 0 : 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 : 0 : ulp_blob_block_merge(struct ulp_blob *dst, struct ulp_blob *src,
930 : : uint32_t block_size, uint32_t pad)
931 : : {
932 [ # # ]: 0 : if (dst->byte_order == BNXT_ULP_BYTE_ORDER_BE &&
933 [ # # ]: 0 : src->byte_order == BNXT_ULP_BYTE_ORDER_BE)
934 : 0 : return ulp_blob_msb_block_merge(dst, src, block_size, pad);
935 : :
936 : 0 : BNXT_TF_DBG(ERR, "block merge not implemented yet\n");
937 : 0 : return -EINVAL;
938 : : }
939 : :
940 : : int32_t
941 : 0 : 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 : 0 : uint8_t *src_buf = ulp_blob_data_get(src, &num);
948 : :
949 [ # # ]: 0 : if ((src_offset + src_len) > num)
950 : : return -EINVAL;
951 : :
952 : : /* Only supporting BE for now */
953 [ # # ]: 0 : if (src->byte_order != BNXT_ULP_BYTE_ORDER_BE ||
954 [ # # ]: 0 : 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 : 0 : remaining = src_offset % ULP_BLOB_BYTE;
959 [ # # ]: 0 : if (remaining) {
960 : 0 : bluff = src_buf[src_offset / ULP_BLOB_BYTE] & ((uint8_t)-1 >>
961 : 0 : (ULP_BLOB_BYTE - remaining));
962 : 0 : ulp_bs_put_msb(dst->data, dst->write_idx,
963 : : ULP_BLOB_BYTE, bluff);
964 : 0 : dst->write_idx += remaining;
965 : 0 : src_offset += remaining;
966 : : }
967 : :
968 : 0 : src_buf += ULP_BITS_2_BYTE_NR(src_offset);
969 : :
970 : : /* Push the byte aligned pieces */
971 [ # # ]: 0 : for (k = 0; k < ULP_BITS_2_BYTE_NR(src_len); k++) {
972 : 0 : ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE,
973 : 0 : *src_buf);
974 : 0 : dst->write_idx += ULP_BLOB_BYTE;
975 : 0 : src_buf++;
976 : : }
977 : :
978 : : /* Handle the remaining if length is not a byte boundary */
979 : 0 : remaining = src_len % ULP_BLOB_BYTE;
980 [ # # ]: 0 : if (remaining) {
981 : 0 : bluff = (*src_buf) & ((uint8_t)-1 <<
982 : 0 : (ULP_BLOB_BYTE - remaining));
983 : 0 : ulp_bs_put_msb(dst->data, dst->write_idx,
984 : : ULP_BLOB_BYTE, bluff);
985 : 0 : 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 : 0 : ulp_blob_buffer_copy(struct ulp_blob *dst, struct ulp_blob *src)
1002 : : {
1003 [ # # ]: 0 : if ((dst->write_idx + src->write_idx) > dst->bitlen) {
1004 : 0 : BNXT_TF_DBG(ERR, "source buffer too large\n");
1005 : 0 : return -EINVAL;
1006 : : }
1007 [ # # # # ]: 0 : if (ULP_BITS_IS_BYTE_NOT_ALIGNED(dst->write_idx) ||
1008 : : ULP_BITS_IS_BYTE_NOT_ALIGNED(src->write_idx)) {
1009 : 0 : BNXT_TF_DBG(ERR, "source buffer is not aligned\n");
1010 : 0 : return -EINVAL;
1011 : : }
1012 : 0 : memcpy(&dst->data[ULP_BITS_2_BYTE_NR(dst->write_idx)],
1013 : 0 : src->data, ULP_BITS_2_BYTE_NR(src->write_idx));
1014 : 0 : dst->write_idx += src->write_idx;
1015 : 0 : 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 : 0 : ulp_operand_read(uint8_t *operand,
1031 : : uint8_t *val,
1032 : : uint16_t bytes)
1033 : : {
1034 : : /* validate the arguments */
1035 [ # # ]: 0 : if (!operand || !val) {
1036 : 0 : BNXT_TF_DBG(ERR, "invalid argument\n");
1037 : 0 : return 0; /* failure */
1038 : : }
1039 : 0 : memcpy(val, operand, bytes);
1040 : 0 : 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 : 0 : int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
1051 : : {
1052 [ # # # # ]: 0 : 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 : 0 : uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
1057 : : {
1058 [ # # ]: 0 : while (size-- > 0) {
1059 [ # # ]: 0 : if (*bitmap != 0)
1060 : : return 0;
1061 : 0 : bitmap++;
1062 : : }
1063 : : return 1;
1064 : : }
1065 : :
1066 : : /* Function to check if bitmap is ones. Return 1 on success */
1067 : 0 : uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
1068 : : {
1069 [ # # ]: 0 : while (size-- > 0) {
1070 [ # # ]: 0 : if (*bitmap != 0xFF)
1071 : : return 0;
1072 : 0 : bitmap++;
1073 : : }
1074 : : return 1;
1075 : : }
1076 : :
1077 : : /* Function to check if bitmap is not zero. Return 1 on success */
1078 : 0 : uint32_t ulp_bitmap_notzero(const uint8_t *bitmap, int32_t size)
1079 : : {
1080 [ # # ]: 0 : while (size-- > 0) {
1081 [ # # ]: 0 : if (*bitmap != 0)
1082 : : return 1;
1083 : 0 : bitmap++;
1084 : : }
1085 : : return 0;
1086 : : }
1087 : :
1088 : : /* returns 0 if input is power of 2 */
1089 : 0 : int32_t ulp_util_is_power_of_2(uint64_t x)
1090 : : {
1091 [ # # ]: 0 : if (((x - 1) & x))
1092 : 0 : return -1;
1093 : : return 0;
1094 : : }
|