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