net/bnxt: refactor mapper opcodes
[dpdk.git] / drivers / net / bnxt / tf_ulp / ulp_utils.c
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 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] 32-bit value to be added to the blob.
319  *
320  * datalen [in] The number of bits to be added ot 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 uint8_t *
326 ulp_blob_push_32(struct ulp_blob *blob,
327                  uint32_t *data,
328                  uint32_t datalen)
329 {
330         uint8_t *val = (uint8_t *)data;
331         uint32_t rc;
332         uint32_t size = ULP_BITS_2_BYTE(datalen);
333
334         if (!data || size > sizeof(uint32_t)) {
335                 BNXT_TF_DBG(ERR, "invalid argument\n");
336                 return 0;
337         }
338
339         rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen);
340         if (!rc)
341                 return 0;
342
343         return &val[sizeof(uint32_t) - size];
344 }
345
346 /*
347  * Add encap data to the binary blob at the current offset.
348  *
349  * blob [in] The blob that data is added to.  The blob must
350  * be initialized prior to pushing data.
351  *
352  * data [in] value to be added to the blob.
353  *
354  * datalen [in] The number of bits to be added to the blob.
355  *
356  * The offset of the data is updated after each push of data.
357  * NULL returned on error, pointer pushed value otherwise.
358  */
359 uint32_t
360 ulp_blob_push_encap(struct ulp_blob *blob,
361                     uint8_t *data,
362                     uint32_t datalen)
363 {
364         uint8_t         *val = (uint8_t *)data;
365         uint32_t        initial_size, write_size = datalen;
366         uint32_t        size = 0;
367
368         if (!blob || !data ||
369             datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
370                 BNXT_TF_DBG(ERR, "invalid argument\n");
371                 return 0;
372         }
373
374         initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) -
375             (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t)));
376         while (write_size > 0) {
377                 if (initial_size && write_size > initial_size) {
378                         size = initial_size;
379                         initial_size = 0;
380                 } else if (initial_size && write_size <= initial_size) {
381                         size = write_size;
382                         initial_size = 0;
383                 } else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) {
384                         size = ULP_BYTE_2_BITS(sizeof(uint64_t));
385                 } else {
386                         size = write_size;
387                 }
388                 if (!ulp_blob_push(blob, val, size)) {
389                         BNXT_TF_DBG(ERR, "push field failed\n");
390                         return 0;
391                 }
392                 val += ULP_BITS_2_BYTE(size);
393                 write_size -= size;
394         }
395         return datalen;
396 }
397
398 /*
399  * Adds pad to an initialized blob at the current offset
400  *
401  * blob [in] The blob that data is added to.  The blob must
402  * be initialized prior to pushing data.
403  *
404  * datalen [in] The number of bits of pad to add
405  *
406  * returns the number of pad bits added, -1 on failure
407  */
408 int32_t
409 ulp_blob_pad_push(struct ulp_blob *blob,
410                   uint32_t datalen)
411 {
412         if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) {
413                 BNXT_TF_DBG(ERR, "Pad too large for blob\n");
414                 return 0;
415         }
416
417         blob->write_idx += datalen;
418         return datalen;
419 }
420
421 /*
422  * Get the data portion of the binary blob.
423  *
424  * blob [in] The blob's data to be retrieved. The blob must be
425  * initialized prior to pushing data.
426  *
427  * datalen [out] The number of bits to that are filled.
428  *
429  * returns a byte array of the blob data.  Returns NULL on error.
430  */
431 uint8_t *
432 ulp_blob_data_get(struct ulp_blob *blob,
433                   uint16_t *datalen)
434 {
435         /* validate the arguments */
436         if (!blob) {
437                 BNXT_TF_DBG(ERR, "invalid argument\n");
438                 return NULL; /* failure */
439         }
440         *datalen = blob->write_idx;
441         return blob->data;
442 }
443
444 /*
445  * Set the encap swap start index of the binary blob.
446  *
447  * blob [in] The blob's data to be retrieved. The blob must be
448  * initialized prior to pushing data.
449  *
450  * returns void.
451  */
452 void
453 ulp_blob_encap_swap_idx_set(struct ulp_blob *blob)
454 {
455         /* validate the arguments */
456         if (!blob) {
457                 BNXT_TF_DBG(ERR, "invalid argument\n");
458                 return; /* failure */
459         }
460         blob->encap_swap_idx = blob->write_idx;
461 }
462
463 /*
464  * Perform the encap buffer swap to 64 bit reversal.
465  *
466  * blob [in] The blob's data to be used for swap.
467  *
468  * returns void.
469  */
470 void
471 ulp_blob_perform_encap_swap(struct ulp_blob *blob)
472 {
473         uint32_t                i, idx = 0, end_idx = 0;
474         uint8_t         temp_val_1, temp_val_2;
475
476         /* validate the arguments */
477         if (!blob) {
478                 BNXT_TF_DBG(ERR, "invalid argument\n");
479                 return; /* failure */
480         }
481         idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx + 1);
482         end_idx = ULP_BITS_2_BYTE(blob->write_idx);
483
484         while (idx <= end_idx) {
485                 for (i = 0; i < 4; i = i + 2) {
486                         temp_val_1 = blob->data[idx + i];
487                         temp_val_2 = blob->data[idx + i + 1];
488                         blob->data[idx + i] = blob->data[idx + 6 - i];
489                         blob->data[idx + i + 1] = blob->data[idx + 7 - i];
490                         blob->data[idx + 7 - i] = temp_val_2;
491                         blob->data[idx + 6 - i] = temp_val_1;
492                 }
493                 idx += 8;
494         }
495 }
496
497 /*
498  * Perform the blob buffer reversal byte wise.
499  * This api makes the first byte the last and
500  * vice-versa.
501  *
502  * blob [in] The blob's data to be used for swap.
503  *
504  * returns void.
505  */
506 void
507 ulp_blob_perform_byte_reverse(struct ulp_blob *blob)
508 {
509         uint32_t idx = 0, num = 0;
510         uint8_t xchar;
511
512         /* validate the arguments */
513         if (!blob) {
514                 BNXT_TF_DBG(ERR, "invalid argument\n");
515                 return; /* failure */
516         }
517
518         num = ULP_BITS_2_BYTE_NR(blob->write_idx);
519         for (idx = 0; idx < (num / 2); idx++) {
520                 xchar = blob->data[idx];
521                 blob->data[idx] = blob->data[(num - 1) - idx];
522                 blob->data[(num - 1) - idx] = xchar;
523         }
524 }
525
526 /*
527  * Read data from the operand
528  *
529  * operand [in] A pointer to a 16 Byte operand
530  *
531  * val [in/out] The variable to copy the operand to
532  *
533  * bytes [in] The number of bytes to read into val
534  *
535  * returns number of bits read, zero on error
536  */
537 uint16_t
538 ulp_operand_read(uint8_t *operand,
539                  uint8_t *val,
540                  uint16_t bytes)
541 {
542         /* validate the arguments */
543         if (!operand || !val) {
544                 BNXT_TF_DBG(ERR, "invalid argument\n");
545                 return 0; /* failure */
546         }
547         memcpy(val, operand, bytes);
548         return bytes;
549 }
550
551 /*
552  * copy the buffer in the encap format which is 2 bytes.
553  * The MSB of the src is placed at the LSB of dst.
554  *
555  * dst [out] The destination buffer
556  * src [in] The source buffer dst
557  * size[in] size of the buffer.
558  */
559 void
560 ulp_encap_buffer_copy(uint8_t *dst,
561                       const uint8_t *src,
562                       uint16_t size)
563 {
564         uint16_t        idx = 0;
565
566         /* copy 2 bytes at a time. Write MSB to LSB */
567         while ((idx + sizeof(uint16_t)) <= size) {
568                 memcpy(&dst[idx], &src[size - idx - sizeof(uint16_t)],
569                        sizeof(uint16_t));
570                 idx += sizeof(uint16_t);
571         }
572 }
573
574 /*
575  * Check the buffer is empty
576  *
577  * buf [in] The buffer
578  * size [in] The size of the buffer
579  *
580  */
581 int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size)
582 {
583         return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
584 }
585
586 /* Function to check if bitmap is zero.Return 1 on success */
587 uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size)
588 {
589         while (size-- > 0) {
590                 if (*bitmap != 0)
591                         return 0;
592                 bitmap++;
593         }
594         return 1;
595 }
596
597 /* Function to check if bitmap is ones. Return 1 on success */
598 uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size)
599 {
600         while (size-- > 0) {
601                 if (*bitmap != 0xFF)
602                         return 0;
603                 bitmap++;
604         }
605         return 1;
606 }
607
608 /* Function to check if bitmap is not zero. Return 1 on success */
609 uint32_t ulp_bitmap_notzero(uint8_t *bitmap, int32_t size)
610 {
611         while (size-- > 0) {
612                 if (*bitmap != 0)
613                         return 1;
614                 bitmap++;
615         }
616         return 0;
617 }