net/bnxt: use hashing for flow template match
[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 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 }