9e8b81e4c2e24fbd442597a2a7915d656dda22f1
[dpdk.git] / drivers / net / bnxt / tf_ulp / ulp_mark_mgr.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <rte_common.h>
7 #include <rte_malloc.h>
8 #include <rte_log.h>
9 #include "bnxt.h"
10 #include "bnxt_ulp.h"
11 #include "tf_ext_flow_handle.h"
12 #include "ulp_mark_mgr.h"
13 #include "bnxt_tf_common.h"
14 #include "ulp_template_db.h"
15 #include "ulp_template_struct.h"
16
17 #define ULP_MARK_DB_ENTRY_SET_VALID(mark_info) ((mark_info)->flags |=\
18                                                 BNXT_ULP_MARK_VALID)
19 #define ULP_MARK_DB_ENTRY_IS_INVALID(mark_info) (!((mark_info)->flags &\
20                                                    BNXT_ULP_MARK_VALID))
21 #define ULP_MARK_DB_ENTRY_IS_GLOBAL_HW_FID(mark_info) ((mark_info)->flags &\
22                                                 BNXT_ULP_MARK_GLOBAL_HW_FID)
23
24 static inline uint32_t
25 ulp_mark_db_idx_get(bool is_gfid, uint32_t fid, struct bnxt_ulp_mark_tbl *mtbl)
26 {
27         uint32_t idx = 0, hashtype = 0;
28
29         if (is_gfid) {
30                 TF_GET_HASH_TYPE_FROM_GFID(fid, hashtype);
31                 TF_GET_HASH_INDEX_FROM_GFID(fid, idx);
32
33                 /* Need to truncate anything beyond supported flows */
34                 idx &= mtbl->gfid_mask;
35                 if (hashtype)
36                         idx |= mtbl->gfid_type_bit;
37         } else {
38                 idx = fid;
39         }
40         return idx;
41 }
42
43 /*
44  * Allocate and Initialize all Mark Manager resources for this ulp context.
45  *
46  * ctxt [in] The ulp context for the mark manager.
47  *
48  */
49 int32_t
50 ulp_mark_db_init(struct bnxt_ulp_context *ctxt)
51 {
52         struct bnxt_ulp_device_params *dparms;
53         struct bnxt_ulp_mark_tbl *mark_tbl = NULL;
54         uint32_t dev_id;
55
56         if (!ctxt) {
57                 BNXT_TF_DBG(DEBUG, "Invalid ULP CTXT\n");
58                 return -EINVAL;
59         }
60
61         if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) {
62                 BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
63                 return -EINVAL;
64         }
65
66         dparms = bnxt_ulp_device_params_get(dev_id);
67         if (!dparms) {
68                 BNXT_TF_DBG(DEBUG, "Failed to device parms\n");
69                 return -EINVAL;
70         }
71
72         mark_tbl = rte_zmalloc("ulp_rx_mark_tbl_ptr",
73                                sizeof(struct bnxt_ulp_mark_tbl), 0);
74         if (!mark_tbl)
75                 goto mem_error;
76
77         /* Need to allocate 2 * Num flows to account for hash type bit.*/
78         mark_tbl->lfid_num_entries = dparms->lfid_entries;
79         mark_tbl->lfid_tbl = rte_zmalloc("ulp_rx_em_flow_mark_table",
80                                          mark_tbl->lfid_num_entries *
81                                          sizeof(struct bnxt_lfid_mark_info),
82                                          0);
83         if (!mark_tbl->lfid_tbl)
84                 goto mem_error;
85
86         /* Need to allocate 2 * Num flows to account for hash type bit */
87         mark_tbl->gfid_num_entries = dparms->gfid_entries;
88         mark_tbl->gfid_tbl = rte_zmalloc("ulp_rx_eem_flow_mark_table",
89                                          mark_tbl->gfid_num_entries *
90                                          sizeof(struct bnxt_gfid_mark_info),
91                                          0);
92         if (!mark_tbl->gfid_tbl)
93                 goto mem_error;
94
95         /*
96          * These values are used to compress the FID to the allowable index
97          * space.  The FID from hw may be the full hash which may be a big
98          * value to allocate and so allocate only needed hash values.
99          * gfid mask is the number of flow entries for the each left/right
100          * hash  The gfid type bit is used to get to the higher or lower hash
101          * entries.
102          */
103         mark_tbl->gfid_mask     = (mark_tbl->gfid_num_entries / 2) - 1;
104         mark_tbl->gfid_type_bit = (mark_tbl->gfid_num_entries / 2);
105
106         BNXT_TF_DBG(DEBUG, "GFID Max = 0x%08x\nGFID MASK = 0x%08x\n",
107                     mark_tbl->gfid_num_entries - 1,
108                     mark_tbl->gfid_mask);
109
110         /* Add the mark tbl to the ulp context. */
111         bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, mark_tbl);
112         return 0;
113
114 mem_error:
115         rte_free(mark_tbl->gfid_tbl);
116         rte_free(mark_tbl->lfid_tbl);
117         rte_free(mark_tbl);
118         BNXT_TF_DBG(DEBUG, "Failed to allocate memory for mark mgr\n");
119         return -ENOMEM;
120 }
121
122 /*
123  * Release all resources in the Mark Manager for this ulp context
124  *
125  * ctxt [in] The ulp context for the mark manager
126  *
127  */
128 int32_t
129 ulp_mark_db_deinit(struct bnxt_ulp_context *ctxt)
130 {
131         struct bnxt_ulp_mark_tbl *mtbl;
132
133         mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt);
134
135         if (mtbl) {
136                 rte_free(mtbl->gfid_tbl);
137                 rte_free(mtbl->lfid_tbl);
138                 rte_free(mtbl);
139
140                 /* Safe to ignore on deinit */
141                 (void)bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, NULL);
142         }
143
144         return 0;
145 }
146
147 /*
148  * Get a Mark from the Mark Manager
149  *
150  * ctxt [in] The ulp context for the mark manager
151  *
152  * is_gfid [in] The type of fid (GFID or LFID)
153  *
154  * fid [in] The flow id that is returned by HW in BD
155  *
156  * mark [out] The mark that is associated with the FID
157  *
158  */
159 int32_t
160 ulp_mark_db_mark_get(struct bnxt_ulp_context *ctxt,
161                      bool is_gfid,
162                      uint32_t fid,
163                      uint32_t *mark)
164 {
165         struct bnxt_ulp_mark_tbl *mtbl;
166         uint32_t idx = 0;
167
168         if (!ctxt || !mark)
169                 return -EINVAL;
170
171         mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt);
172         if (!mtbl) {
173                 BNXT_TF_DBG(ERR, "Unable to get Mark Table\n");
174                 return -EINVAL;
175         }
176
177         idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl);
178
179         if (is_gfid) {
180                 if (idx >= mtbl->gfid_num_entries ||
181                     ULP_MARK_DB_ENTRY_IS_INVALID(&mtbl->gfid_tbl[idx]))
182                         return -EINVAL;
183
184                 BNXT_TF_DBG(DEBUG, "Get GFID[0x%0x] = 0x%0x\n",
185                             idx, mtbl->gfid_tbl[idx].mark_id);
186
187                 *mark = mtbl->gfid_tbl[idx].mark_id;
188         } else {
189                 if (idx >= mtbl->lfid_num_entries ||
190                     ULP_MARK_DB_ENTRY_IS_INVALID(&mtbl->lfid_tbl[idx]))
191                         return -EINVAL;
192
193                 BNXT_TF_DBG(DEBUG, "Get LFID[0x%0x] = 0x%0x\n",
194                             idx, mtbl->lfid_tbl[idx].mark_id);
195
196                 *mark = mtbl->lfid_tbl[idx].mark_id;
197         }
198
199         return 0;
200 }
201
202 /*
203  * Adds a Mark to the Mark Manager
204  *
205  * ctxt [in] The ulp context for the mark manager
206  *
207  * mark_flag [in] mark flags.
208  *
209  * fid [in] The flow id that is returned by HW in BD
210  *
211  * mark [in] The mark to be associated with the FID
212  *
213  */
214 int32_t
215 ulp_mark_db_mark_add(struct bnxt_ulp_context *ctxt,
216                      uint32_t mark_flag,
217                      uint32_t fid,
218                      uint32_t mark)
219 {
220         struct bnxt_ulp_mark_tbl *mtbl;
221         uint32_t idx = 0;
222         bool is_gfid;
223
224         if (!ctxt) {
225                 BNXT_TF_DBG(ERR, "Invalid ulp context\n");
226                 return -EINVAL;
227         }
228
229         mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt);
230         if (!mtbl) {
231                 BNXT_TF_DBG(ERR, "Unable to get Mark DB\n");
232                 return -EINVAL;
233         }
234
235         is_gfid = (mark_flag & BNXT_ULP_MARK_GLOBAL_HW_FID);
236         if (is_gfid) {
237                 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl);
238                 if (idx >= mtbl->gfid_num_entries) {
239                         BNXT_TF_DBG(ERR, "Mark index greater than allocated\n");
240                         return -EINVAL;
241                 }
242                 BNXT_TF_DBG(DEBUG, "Set GFID[0x%0x] = 0x%0x\n", idx, mark);
243                 mtbl->gfid_tbl[idx].mark_id = mark;
244                 ULP_MARK_DB_ENTRY_SET_VALID(&mtbl->gfid_tbl[idx]);
245
246         } else {
247                 /* For the LFID, the FID is used as the index */
248                 if (fid >= mtbl->lfid_num_entries) {
249                         BNXT_TF_DBG(ERR, "Mark index greater than allocated\n");
250                         return -EINVAL;
251                 }
252                 mtbl->lfid_tbl[fid].mark_id = mark;
253                 ULP_MARK_DB_ENTRY_SET_VALID(&mtbl->lfid_tbl[fid]);
254         }
255
256         return 0;
257 }
258
259 /*
260  * Removes a Mark from the Mark Manager
261  *
262  * ctxt [in] The ulp context for the mark manager
263  *
264  * mark_flag [in] mark flags.
265  *
266  * fid [in] The flow id that is returned by HW in BD
267  *
268  */
269 int32_t
270 ulp_mark_db_mark_del(struct bnxt_ulp_context *ctxt,
271                      uint32_t mark_flag,
272                      uint32_t fid)
273 {
274         struct bnxt_ulp_mark_tbl *mtbl;
275         uint32_t idx = 0;
276         bool is_gfid;
277
278         if (!ctxt) {
279                 BNXT_TF_DBG(ERR, "Invalid ulp context\n");
280                 return -EINVAL;
281         }
282
283         mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt);
284         if (!mtbl) {
285                 BNXT_TF_DBG(ERR, "Unable to get Mark DB\n");
286                 return -EINVAL;
287         }
288
289         is_gfid = (mark_flag & BNXT_ULP_MARK_GLOBAL_HW_FID);
290         if (is_gfid) {
291                 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl);
292                 if (idx >= mtbl->gfid_num_entries) {
293                         BNXT_TF_DBG(ERR, "Mark index greater than allocated\n");
294                         return -EINVAL;
295                 }
296                 BNXT_TF_DBG(DEBUG, "Reset GFID[0x%0x]\n", idx);
297                 memset(&mtbl->gfid_tbl[idx], 0,
298                        sizeof(struct bnxt_gfid_mark_info));
299
300         } else {
301                 /* For the LFID, the FID is used as the index */
302                 if (fid >= mtbl->lfid_num_entries) {
303                         BNXT_TF_DBG(ERR, "Mark index greater than allocated\n");
304                         return -EINVAL;
305                 }
306                 memset(&mtbl->lfid_tbl[fid], 0,
307                        sizeof(struct bnxt_lfid_mark_info));
308         }
309
310         return 0;
311 }