Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2021 Marvell.
3 : : */
4 : : #include "roc_api.h"
5 : : #include "roc_priv.h"
6 : :
7 : : uint8_t
8 : 0 : npc_get_key_type(struct npc *npc, struct roc_npc_flow *flow)
9 : : {
10 : : int i;
11 : :
12 : : /* KEX is configured just for X2 */
13 [ # # ]: 0 : if (npc->keyw[ROC_NPC_INTF_RX] == 1)
14 : : return NPC_CN20K_MCAM_KEY_X2;
15 : :
16 : : /* KEX is configured just for X4 */
17 [ # # ]: 0 : if (npc->keyw[ROC_NPC_INTF_RX] == 2)
18 : : return NPC_CN20K_MCAM_KEY_X4;
19 : :
20 : : /* KEX is configured for both X2 and X4 */
21 : : /* Check mask for upper 256 bits. if mask is set, then it is X4 entry */
22 [ # # ]: 0 : for (i = 4; i < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; i++) {
23 [ # # ]: 0 : if (flow->mcam_mask[i] != 0)
24 : : return NPC_CN20K_MCAM_KEY_X4;
25 : : }
26 : : return NPC_CN20K_MCAM_KEY_X2;
27 : : }
28 : :
29 : : static void
30 : : npc_prep_mcam_ldata(uint8_t *ptr, const uint8_t *data, int len)
31 : : {
32 : : int idx;
33 : :
34 [ # # # # ]: 0 : for (idx = 0; idx < len; idx++)
35 : 0 : ptr[idx] = data[len - 1 - idx];
36 : : }
37 : :
38 : : static int
39 : : npc_check_copysz(size_t size, size_t len)
40 : : {
41 : 0 : if (len <= size)
42 : : return len;
43 : : return NPC_ERR_PARAM;
44 : : }
45 : :
46 : : static inline int
47 : : npc_mem_is_zero(const void *mem, int len)
48 : : {
49 : : const char *m = mem;
50 : : int i;
51 : :
52 [ # # # # ]: 0 : for (i = 0; i < len; i++) {
53 [ # # # # ]: 0 : if (m[i] != 0)
54 : : return 0;
55 : : }
56 : : return 1;
57 : : }
58 : :
59 : : static void
60 : : npc_set_hw_mask(struct npc_parse_item_info *info, struct npc_xtract_info *xinfo,
61 : : char *hw_mask)
62 : : {
63 : : int max_off, offset;
64 : : int j;
65 : :
66 [ # # ]: 0 : if (xinfo->enable == 0)
67 : : return;
68 : :
69 [ # # # # : 0 : if (xinfo->hdr_off < info->hw_hdr_len)
# # ]
70 : : return;
71 : :
72 : 0 : max_off = xinfo->hdr_off + xinfo->len - info->hw_hdr_len;
73 : :
74 : 0 : if (max_off > info->len)
75 : : max_off = info->len;
76 : :
77 : 0 : offset = xinfo->hdr_off - info->hw_hdr_len;
78 [ # # # # : 0 : for (j = offset; j < max_off; j++)
# # ]
79 : 0 : hw_mask[j] = 0xff;
80 : : }
81 : :
82 : : static void
83 : : npc_ipv6_hash_mask_get(struct npc_xtract_info *xinfo, struct npc_parse_item_info *info)
84 : : {
85 : : int offset = 0;
86 : 0 : uint8_t *hw_mask = info->hw_mask;
87 : :
88 : 0 : offset = xinfo->hdr_off - info->hw_hdr_len;
89 : 0 : memset(&hw_mask[offset], 0xFF, NPC_HASH_FIELD_LEN);
90 : 0 : }
91 : :
92 : : static void
93 : 0 : npc_get_hw_supp_mask_legacy(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
94 : : int lt)
95 : : {
96 : : struct npc_xtract_info *xinfo, *lfinfo;
97 : 0 : char *hw_mask = info->hw_mask;
98 : : int lf_cfg = 0;
99 : : int i, j;
100 : : int intf;
101 : :
102 : 0 : intf = pst->nix_intf;
103 : 0 : xinfo = pst->npc->prx_dxcfg[intf][lid][lt].xtract;
104 : 0 : memset(hw_mask, 0, info->len);
105 : :
106 [ # # ]: 0 : for (i = 0; i < NPC_MAX_LD; i++) {
107 [ # # # # ]: 0 : if (pst->npc->hash_extract_cap && xinfo[i].use_hash)
108 : : npc_ipv6_hash_mask_get(&xinfo[i], info);
109 : : else
110 [ # # ]: 0 : npc_set_hw_mask(info, &xinfo[i], hw_mask);
111 : : }
112 : :
113 [ # # ]: 0 : for (i = 0; i < NPC_MAX_LD; i++) {
114 [ # # ]: 0 : if (xinfo[i].flags_enable == 0)
115 : 0 : continue;
116 : :
117 : 0 : lf_cfg = pst->npc->prx_lfcfg[i].i;
118 [ # # ]: 0 : if (lf_cfg == lid) {
119 [ # # ]: 0 : for (j = 0; j < NPC_MAX_LFL; j++) {
120 [ # # ]: 0 : lfinfo = pst->npc->prx_fxcfg[intf][i][j].xtract;
121 : : npc_set_hw_mask(info, &lfinfo[0], hw_mask);
122 : : }
123 : : }
124 : : }
125 : 0 : }
126 : :
127 : : static void
128 : 0 : npc_get_hw_supp_mask_o20k(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
129 : : int lt)
130 : : {
131 : : struct npc_xtract_info *xinfo;
132 : : union npc_kex_ldata_flags_cfg *lid_info;
133 : 0 : char *hw_mask = info->hw_mask;
134 : : int ex;
135 : : int intf;
136 : :
137 : 0 : intf = pst->nix_intf;
138 : 0 : memset(hw_mask, 0, info->len);
139 [ # # ]: 0 : for (ex = 0; ex < NPC_MAX_EXTRACTTORS; ex++) {
140 : 0 : lid_info = &pst->npc->lid_cfg[intf][ex];
141 [ # # ]: 0 : if (lid_info->s.lid != lid)
142 : 0 : continue;
143 : : xinfo = &pst->npc->prx_dxcfg_cn20k[intf][ex][lt].xtract;
144 : :
145 [ # # # # ]: 0 : if (pst->npc->hash_extract_cap && xinfo->use_hash)
146 : : npc_ipv6_hash_mask_get(xinfo, info);
147 : : else
148 : : npc_set_hw_mask(info, xinfo, hw_mask);
149 : : }
150 : 0 : }
151 : :
152 : : void
153 [ # # ]: 0 : npc_get_hw_supp_mask(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid, int lt)
154 : : {
155 [ # # ]: 0 : if (!roc_model_is_cn20k())
156 : 0 : return npc_get_hw_supp_mask_legacy(pst, info, lid, lt);
157 : : else
158 : 0 : return npc_get_hw_supp_mask_o20k(pst, info, lid, lt);
159 : : }
160 : :
161 : : inline int
162 : 0 : npc_mask_is_supported(const char *mask, const char *hw_mask, int len)
163 : : {
164 : : /*
165 : : * If no hw_mask, assume nothing is supported.
166 : : * mask is never NULL
167 : : */
168 [ # # ]: 0 : if (hw_mask == NULL)
169 : 0 : return npc_mem_is_zero(mask, len);
170 : :
171 [ # # # # ]: 0 : while (len--) {
172 [ # # # # ]: 0 : if ((mask[len] | hw_mask[len]) != hw_mask[len])
173 : : return 0; /* False */
174 : : }
175 : : return 1;
176 : : }
177 : :
178 : : int
179 : 0 : npc_parse_item_basic(const struct roc_npc_item_info *item,
180 : : struct npc_parse_item_info *info)
181 : : {
182 : : /* Item must not be NULL */
183 [ # # ]: 0 : if (item == NULL)
184 : : return NPC_ERR_PARAM;
185 : :
186 : : /* Don't support ranges */
187 [ # # ]: 0 : if (item->last != NULL)
188 : : return NPC_ERR_INVALID_RANGE;
189 : :
190 : : /* If spec is NULL, both mask and last must be NULL, this
191 : : * makes it to match ANY value (eq to mask = 0).
192 : : * Setting either mask or last without spec is an error
193 : : */
194 [ # # ]: 0 : if (item->spec == NULL) {
195 [ # # ]: 0 : if (item->last == NULL && item->mask == NULL) {
196 : 0 : info->spec = NULL;
197 : 0 : return 0;
198 : : }
199 : : return NPC_ERR_INVALID_SPEC;
200 : : }
201 : :
202 : : /* We have valid spec */
203 [ # # ]: 0 : if (item->type != ROC_NPC_ITEM_TYPE_RAW)
204 : 0 : info->spec = item->spec;
205 : :
206 : : /* If mask is not set, use default mask, err if default mask is
207 : : * also NULL.
208 : : */
209 [ # # ]: 0 : if (item->mask == NULL) {
210 [ # # ]: 0 : if (info->def_mask == NULL)
211 : : return NPC_ERR_PARAM;
212 : 0 : info->mask = info->def_mask;
213 : : } else {
214 [ # # ]: 0 : if (item->type != ROC_NPC_ITEM_TYPE_RAW)
215 : 0 : info->mask = item->mask;
216 : : }
217 : :
218 [ # # ]: 0 : if (info->mask == NULL)
219 : : return NPC_ERR_INVALID_MASK;
220 : :
221 : : /* mask specified must be subset of hw supported mask
222 : : * mask | hw_mask == hw_mask
223 : : */
224 [ # # # # ]: 0 : if (!npc_mask_is_supported(info->mask, info->hw_mask, info->len))
225 : 0 : return NPC_ERR_INVALID_MASK;
226 : :
227 : : return 0;
228 : : }
229 : :
230 : : static int
231 : 0 : npc_update_extraction_data(struct npc_parse_state *pst,
232 : : struct npc_parse_item_info *info,
233 : : struct npc_xtract_info *xinfo)
234 : : {
235 : : uint8_t int_info_mask[NPC_MAX_EXTRACT_DATA_LEN];
236 : : uint8_t int_info[NPC_MAX_EXTRACT_DATA_LEN];
237 : : struct npc_xtract_info *x;
238 : : int hdr_off;
239 : : int len = 0;
240 : :
241 : : x = xinfo;
242 [ # # ]: 0 : if (x->len > NPC_MAX_EXTRACT_DATA_LEN)
243 : : return NPC_ERR_INVALID_SIZE;
244 : :
245 : 0 : len = x->len;
246 : 0 : hdr_off = x->hdr_off;
247 : :
248 [ # # ]: 0 : if (hdr_off < info->hw_hdr_len)
249 : : return 0;
250 : :
251 [ # # ]: 0 : if (x->enable == 0)
252 : : return 0;
253 : :
254 : 0 : hdr_off -= info->hw_hdr_len;
255 : :
256 [ # # ]: 0 : if (hdr_off >= info->len)
257 : : return 0;
258 : :
259 [ # # ]: 0 : if (hdr_off + len > info->len)
260 : 0 : len = info->len - hdr_off;
261 : :
262 [ # # ]: 0 : len = npc_check_copysz((ROC_NPC_MAX_MCAM_WIDTH_DWORDS * 8) - x->key_off,
263 : : len);
264 [ # # ]: 0 : if (len < 0)
265 : : return NPC_ERR_INVALID_SIZE;
266 : :
267 : : /* Need to reverse complete structure so that dest addr is at
268 : : * MSB so as to program the MCAM using mcam_data & mcam_mask
269 : : * arrays
270 : : */
271 : 0 : npc_prep_mcam_ldata(int_info, (const uint8_t *)info->spec + hdr_off,
272 : : x->len);
273 : : npc_prep_mcam_ldata(int_info_mask,
274 : 0 : (const uint8_t *)info->mask + hdr_off, x->len);
275 : :
276 : 0 : memcpy(pst->mcam_mask + x->key_off, int_info_mask, len);
277 : 0 : memcpy(pst->mcam_data + x->key_off, int_info, len);
278 : 0 : return 0;
279 : : }
280 : :
281 : : static int
282 : 0 : npc_field_hash_secret_get(struct npc *npc, struct npc_hash_cfg *hash_cfg)
283 : : {
284 : : struct npc_get_field_hash_info_req *req;
285 : : struct npc_get_field_hash_info_rsp *rsp;
286 : 0 : struct mbox *mbox = mbox_get(npc->mbox);
287 : : int rc = 0;
288 : :
289 : 0 : req = mbox_alloc_msg_npc_get_field_hash_info(mbox);
290 [ # # ]: 0 : if (req == NULL)
291 : : return -ENOSPC;
292 : : rc = mbox_process_msg(mbox, (void *)&rsp);
293 [ # # ]: 0 : if (rc) {
294 : 0 : plt_err("Failed to fetch field hash secret key");
295 : 0 : goto done;
296 : : }
297 : :
298 [ # # ]: 0 : mbox_memcpy(hash_cfg->secret_key, rsp->secret_key, sizeof(rsp->secret_key));
299 : 0 : mbox_memcpy(hash_cfg->hash_mask, rsp->hash_mask, sizeof(rsp->hash_mask));
300 : 0 : mbox_memcpy(hash_cfg->hash_ctrl, rsp->hash_ctrl, sizeof(rsp->hash_ctrl));
301 : :
302 : 0 : done:
303 : : mbox_put(mbox);
304 : 0 : return rc;
305 : : }
306 : :
307 : : static inline void
308 : : be32_to_cpu_array(uint32_t *dst, const uint32_t *src, size_t len)
309 : : {
310 : : size_t i;
311 : :
312 [ # # ]: 0 : for (i = 0; i < len; i++)
313 [ # # ]: 0 : dst[i] = plt_be_to_cpu_32(src[i]);
314 : : }
315 : :
316 : : static uint64_t
317 : 0 : npc_wide_extract(const uint64_t input[], size_t start_bit, size_t width_bits)
318 : : {
319 : 0 : const uint64_t mask = ~(uint64_t)((~(__uint128_t)0) << width_bits);
320 : 0 : const size_t msb = start_bit + width_bits - 1;
321 : 0 : const size_t lword = start_bit >> 6;
322 : 0 : const size_t uword = msb >> 6;
323 : : size_t lbits;
324 : : uint64_t hi, lo;
325 : :
326 [ # # ]: 0 : if (lword == uword)
327 : 0 : return (input[lword] >> (start_bit & 63)) & mask;
328 : :
329 : 0 : lbits = 64 - (start_bit & 63);
330 : 0 : hi = input[uword];
331 : 0 : lo = (input[lword] >> (start_bit & 63));
332 : 0 : return ((hi << lbits) | lo) & mask;
333 : : }
334 : :
335 : : static void
336 : : npc_lshift_key(uint64_t *key, size_t key_bit_len)
337 : : {
338 : : uint64_t prev_orig_word = 0;
339 : : uint64_t cur_orig_word = 0;
340 : 0 : size_t extra = key_bit_len % 64;
341 : 0 : size_t max_idx = key_bit_len / 64;
342 : : size_t i;
343 : :
344 [ # # ]: 0 : if (extra)
345 : 0 : max_idx++;
346 : :
347 [ # # ]: 0 : for (i = 0; i < max_idx; i++) {
348 : 0 : cur_orig_word = key[i];
349 : 0 : key[i] = key[i] << 1;
350 : 0 : key[i] |= ((prev_orig_word >> 63) & 0x1);
351 : : prev_orig_word = cur_orig_word;
352 : : }
353 : : }
354 : :
355 : : static uint32_t
356 : 0 : npc_toeplitz_hash(const uint64_t *data, uint64_t *key, size_t data_bit_len, size_t key_bit_len)
357 : : {
358 : : uint32_t hash_out = 0;
359 : : uint64_t temp_data = 0;
360 : : int i;
361 : :
362 [ # # ]: 0 : for (i = data_bit_len - 1; i >= 0; i--) {
363 : 0 : temp_data = (data[i / 64]);
364 : 0 : temp_data = temp_data >> (i % 64);
365 : 0 : temp_data &= 0x1;
366 [ # # ]: 0 : if (temp_data)
367 : 0 : hash_out ^= (uint32_t)(npc_wide_extract(key, key_bit_len - 32, 32));
368 : :
369 : : npc_lshift_key(key, key_bit_len);
370 : : }
371 : :
372 : 0 : return hash_out;
373 : : }
374 : :
375 : : static uint32_t
376 : 0 : npc_field_hash_calc(uint64_t *ldata, struct npc_hash_cfg *hash_cfg, uint8_t intf, uint8_t hash_idx)
377 : : {
378 : : uint64_t hash_key[3];
379 : : uint64_t data_padded[2];
380 : : uint32_t field_hash;
381 : :
382 : 0 : hash_key[0] = hash_cfg->secret_key[1] << 31;
383 : 0 : hash_key[0] |= hash_cfg->secret_key[2];
384 : 0 : hash_key[1] = hash_cfg->secret_key[1] >> 33;
385 : 0 : hash_key[1] |= hash_cfg->secret_key[0] << 31;
386 : 0 : hash_key[2] = hash_cfg->secret_key[0] >> 33;
387 : :
388 : 0 : data_padded[0] = hash_cfg->hash_mask[intf][hash_idx][0] & ldata[0];
389 : 0 : data_padded[1] = hash_cfg->hash_mask[intf][hash_idx][1] & ldata[1];
390 : 0 : field_hash = npc_toeplitz_hash(data_padded, hash_key, 128, 159);
391 : :
392 : 0 : field_hash &= hash_cfg->hash_ctrl[intf][hash_idx] >> 32;
393 : 0 : field_hash |= hash_cfg->hash_ctrl[intf][hash_idx];
394 : 0 : return field_hash;
395 : : }
396 : :
397 : : static int
398 : 0 : npc_ipv6_field_hash_get(struct npc *npc, const uint32_t *ip6addr, uint8_t intf, int hash_idx,
399 : : uint32_t *hash)
400 : : {
401 : : #define IPV6_WORDS 4
402 : : uint32_t ipv6_addr[IPV6_WORDS];
403 : : struct npc_hash_cfg hash_cfg;
404 : : uint64_t ldata[2];
405 : : int rc = 0;
406 : :
407 : 0 : rc = npc_field_hash_secret_get(npc, &hash_cfg);
408 [ # # ]: 0 : if (rc)
409 : : return -1;
410 : :
411 : : be32_to_cpu_array(ipv6_addr, ip6addr, IPV6_WORDS);
412 : 0 : ldata[0] = (uint64_t)ipv6_addr[2] << 32 | ipv6_addr[3];
413 : 0 : ldata[1] = (uint64_t)ipv6_addr[0] << 32 | ipv6_addr[1];
414 : 0 : *hash = npc_field_hash_calc(ldata, &hash_cfg, intf, hash_idx);
415 : :
416 : 0 : return 0;
417 : : }
418 : :
419 : : static int
420 : 0 : npc_hash_field_get(struct npc_xtract_info *xinfo, const struct roc_npc_flow_item_ipv6 *ipv6_spec,
421 : : const struct roc_npc_flow_item_ipv6 *ipv6_mask, uint8_t *hash_field)
422 : : {
423 : : const uint8_t *ipv6_hdr_spec, *ipv6_hdr_mask;
424 : : struct roc_ipv6_hdr ipv6_buf;
425 [ # # ]: 0 : int offset = xinfo->hdr_off;
426 : :
427 : : memset(&ipv6_buf, 0, sizeof(ipv6_buf));
428 : :
429 : 0 : ipv6_hdr_spec = (const uint8_t *)&ipv6_spec->hdr;
430 : 0 : ipv6_hdr_mask = (const uint8_t *)&ipv6_mask->hdr;
431 : :
432 : : /* Check if mask is set for the field to be hashed */
433 [ # # ]: 0 : if (memcmp(ipv6_hdr_mask + offset, &ipv6_buf, ROC_IPV6_ADDR_LEN) == 0)
434 : : return 0;
435 : :
436 : : /* Extract the field to be hashed from item spec */
437 : 0 : memcpy(hash_field, ipv6_hdr_spec + offset, ROC_IPV6_ADDR_LEN);
438 : 0 : return 1;
439 : : }
440 : :
441 : : static int
442 : 0 : npc_process_ipv6_field_hash_legacy(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
443 : : const struct roc_npc_flow_item_ipv6 *ipv6_mask,
444 : : struct npc_parse_state *pst, uint8_t ltype)
445 : : {
446 : : struct npc_lid_lt_xtract_info *lid_lt_xinfo;
447 : : uint8_t hash_field[ROC_IPV6_ADDR_LEN];
448 : : struct npc_xtract_info *xinfo;
449 : 0 : uint32_t hash = 0, mask;
450 : : int intf, i, rc = 0;
451 : :
452 : : memset(hash_field, 0, sizeof(hash_field));
453 : :
454 : 0 : intf = pst->nix_intf;
455 : 0 : lid_lt_xinfo = &pst->npc->prx_dxcfg[intf][NPC_LID_LC][ltype];
456 : :
457 [ # # ]: 0 : for (i = 0; i < NPC_MAX_LD; i++) {
458 : 0 : xinfo = &lid_lt_xinfo->xtract[i];
459 [ # # ]: 0 : if (!xinfo->use_hash)
460 : 0 : continue;
461 : :
462 : 0 : rc = npc_hash_field_get(xinfo, ipv6_spec, ipv6_mask, hash_field);
463 [ # # ]: 0 : if (rc == 0)
464 : 0 : continue;
465 : :
466 : 0 : rc = npc_ipv6_field_hash_get(pst->npc, (const uint32_t *)hash_field, intf, i,
467 : : &hash);
468 [ # # ]: 0 : if (rc)
469 : 0 : return rc;
470 : :
471 : 0 : mask = GENMASK(31, 0);
472 : 0 : memcpy(pst->mcam_mask + xinfo->key_off, (uint8_t *)&mask, 4);
473 : 0 : memcpy(pst->mcam_data + xinfo->key_off, (uint8_t *)&hash, 4);
474 : : }
475 : :
476 : : return 0;
477 : : }
478 : :
479 : : static int
480 : 0 : npc_process_ipv6_field_hash_o20k(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
481 : : const struct roc_npc_flow_item_ipv6 *ipv6_mask,
482 : : struct npc_parse_state *pst, uint8_t ltype)
483 : : {
484 : : struct npc_lid_lt_xtract_info_cn20k *lid_lt_xinfo;
485 : : union npc_kex_ldata_flags_cfg *lid_cfg;
486 : : uint8_t hash_field[ROC_IPV6_ADDR_LEN];
487 : : struct npc_xtract_info *xinfo;
488 : 0 : uint32_t hash = 0, mask;
489 : : int intf, i, hash_idx = 0, rc = 0;
490 : :
491 : : memset(hash_field, 0, sizeof(hash_field));
492 : :
493 : 0 : intf = pst->nix_intf;
494 [ # # ]: 0 : for (i = 0; i < NPC_MAX_EXTRACTTORS; i++) {
495 : 0 : lid_cfg = &pst->npc->lid_cfg[intf][i];
496 [ # # ]: 0 : if (lid_cfg->s.lid != NPC_LID_LC)
497 : 0 : continue;
498 : 0 : lid_lt_xinfo = &pst->npc->prx_dxcfg_cn20k[intf][NPC_LID_LC][ltype];
499 : :
500 : 0 : xinfo = &lid_lt_xinfo->xtract;
501 [ # # ]: 0 : if (!xinfo->use_hash)
502 : 0 : continue;
503 : :
504 : 0 : rc = npc_hash_field_get(xinfo, ipv6_spec, ipv6_mask, hash_field);
505 [ # # ]: 0 : if (rc == 0)
506 : 0 : continue;
507 : :
508 [ # # ]: 0 : if (hash_idx >= NPC_MAX_HASH)
509 : : break;
510 : :
511 : 0 : rc = npc_ipv6_field_hash_get(pst->npc, (const uint32_t *)hash_field, intf,
512 : : hash_idx, &hash);
513 [ # # ]: 0 : if (rc)
514 : 0 : return rc;
515 : :
516 : 0 : mask = GENMASK(31, 0);
517 : 0 : memcpy(pst->mcam_mask + xinfo->key_off, (uint8_t *)&mask, 4);
518 : 0 : memcpy(pst->mcam_data + xinfo->key_off, (uint8_t *)&hash, 4);
519 : 0 : hash_idx++;
520 : : }
521 : :
522 : : return 0;
523 : : }
524 : :
525 : : int
526 [ # # ]: 0 : npc_process_ipv6_field_hash(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
527 : : const struct roc_npc_flow_item_ipv6 *ipv6_mask,
528 : : struct npc_parse_state *pst, uint8_t ltype)
529 : : {
530 [ # # ]: 0 : if (!roc_model_is_cn20k())
531 : 0 : return npc_process_ipv6_field_hash_legacy(ipv6_spec, ipv6_mask, pst, ltype);
532 : : else
533 : 0 : return npc_process_ipv6_field_hash_o20k(ipv6_spec, ipv6_mask, pst, ltype);
534 : : }
535 : :
536 : : static int
537 : 0 : npc_update_parse_state_legacy(struct npc_parse_state *pst, struct npc_parse_item_info *info,
538 : : int lid, int lt, uint8_t flags)
539 : : {
540 : : struct npc_lid_lt_xtract_info *xinfo;
541 : : struct roc_npc_flow_dump_data *dump;
542 : : struct npc_xtract_info *lfinfo;
543 : : int intf, lf_cfg;
544 : : int i, j, rc = 0;
545 : :
546 : 0 : pst->layer_mask |= lid;
547 : 0 : pst->lt[lid] = lt;
548 : 0 : pst->flags[lid] = flags;
549 : :
550 : 0 : intf = pst->nix_intf;
551 : 0 : xinfo = &pst->npc->prx_dxcfg[intf][lid][lt];
552 [ # # ]: 0 : if (xinfo->is_terminating)
553 : 0 : pst->terminate = 1;
554 : :
555 [ # # ]: 0 : if (info->spec == NULL)
556 : 0 : goto done;
557 : :
558 [ # # ]: 0 : for (i = 0; i < NPC_MAX_LD; i++) {
559 [ # # ]: 0 : if (xinfo->xtract[i].use_hash)
560 : 0 : continue;
561 : 0 : rc = npc_update_extraction_data(pst, info, &xinfo->xtract[i]);
562 [ # # ]: 0 : if (rc != 0)
563 : 0 : return rc;
564 : : }
565 : :
566 [ # # ]: 0 : for (i = 0; i < NPC_MAX_LD; i++) {
567 [ # # ]: 0 : if (xinfo->xtract[i].flags_enable == 0)
568 : 0 : continue;
569 [ # # ]: 0 : if (xinfo->xtract[i].use_hash)
570 : 0 : continue;
571 : :
572 : 0 : lf_cfg = pst->npc->prx_lfcfg[i].i;
573 [ # # ]: 0 : if (lf_cfg == lid) {
574 [ # # ]: 0 : for (j = 0; j < NPC_MAX_LFL; j++) {
575 : 0 : lfinfo = pst->npc->prx_fxcfg[intf][i][j].xtract;
576 : 0 : rc = npc_update_extraction_data(pst, info, &lfinfo[0]);
577 [ # # ]: 0 : if (rc != 0)
578 : 0 : return rc;
579 : :
580 [ # # ]: 0 : if (lfinfo[0].enable)
581 : 0 : pst->flags[lid] = j;
582 : : }
583 : : }
584 : : }
585 : :
586 : 0 : done:
587 : 0 : dump = &pst->flow->dump_data[pst->flow->num_patterns++];
588 : 0 : dump->lid = lid;
589 : 0 : dump->ltype = lt;
590 : 0 : pst->pattern++;
591 : 0 : return 0;
592 : : }
593 : :
594 : : static int
595 : 0 : npc_update_parse_state_o20(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
596 : : int lt, uint8_t flags)
597 : : {
598 : : struct npc_lid_lt_xtract_info_cn20k *xinfo;
599 : : union npc_kex_ldata_flags_cfg *lid_cfg;
600 : : struct roc_npc_flow_dump_data *dump;
601 : : int intf;
602 : : int i, rc = 0;
603 : :
604 : 0 : pst->layer_mask |= lid;
605 : 0 : pst->lt[lid] = lt;
606 : 0 : pst->flags[lid] = flags;
607 : :
608 : 0 : intf = pst->nix_intf;
609 [ # # ]: 0 : if (info->spec == NULL)
610 : 0 : goto done;
611 : :
612 [ # # ]: 0 : for (i = 0; i < NPC_MAX_EXTRACTTORS; i++) {
613 : 0 : lid_cfg = &pst->npc->lid_cfg[intf][i];
614 [ # # ]: 0 : if (lid_cfg->s.lid != lid)
615 : 0 : continue;
616 : : xinfo = &pst->npc->prx_dxcfg_cn20k[intf][i][lt];
617 [ # # ]: 0 : if (xinfo->is_terminating)
618 : 0 : pst->terminate = 1;
619 : :
620 [ # # ]: 0 : if (xinfo->xtract.use_hash)
621 : 0 : continue;
622 : 0 : rc = npc_update_extraction_data(pst, info, &xinfo->xtract);
623 [ # # ]: 0 : if (rc != 0)
624 : 0 : return rc;
625 : : }
626 : :
627 : 0 : done:
628 : 0 : dump = &pst->flow->dump_data[pst->flow->num_patterns++];
629 : 0 : dump->lid = lid;
630 : 0 : dump->ltype = lt;
631 : 0 : pst->pattern++;
632 : 0 : return 0;
633 : : }
634 : :
635 : : int
636 [ # # ]: 0 : npc_update_parse_state(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
637 : : int lt, uint8_t flags)
638 : : {
639 [ # # ]: 0 : if (roc_model_is_cn20k())
640 : 0 : return npc_update_parse_state_o20(pst, info, lid, lt, flags);
641 : : else
642 : 0 : return npc_update_parse_state_legacy(pst, info, lid, lt, flags);
643 : : }
644 : :
645 : : int
646 : 0 : npc_mcam_init(struct npc *npc, struct roc_npc_flow *flow, int mcam_id)
647 : : {
648 : : struct msg_rsp *rsp;
649 : 0 : struct mbox *mbox = mbox_get(npc->mbox);
650 : : int rc = 0, idx;
651 : :
652 [ # # ]: 0 : if (roc_model_is_cn20k()) {
653 : : struct npc_cn20k_mcam_write_entry_req *req;
654 : :
655 : 0 : req = mbox_alloc_msg_npc_cn20k_mcam_write_entry(mbox);
656 [ # # ]: 0 : if (req == NULL) {
657 : : rc = -ENOSPC;
658 : 0 : goto exit;
659 : : }
660 : 0 : req->cntr = 0;
661 : 0 : req->entry = mcam_id;
662 : :
663 : 0 : req->intf = (flow->nix_intf == NIX_INTF_RX) ? NPC_MCAM_RX : NPC_MCAM_TX;
664 : 0 : req->enable_entry = 1;
665 : 0 : req->entry_data.action = flow->npc_action;
666 : 0 : req->entry_data.vtag_action = flow->vtag_action;
667 : :
668 [ # # ]: 0 : for (idx = 0; idx < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; idx++) {
669 : 0 : req->entry_data.kw[idx] = 0x0;
670 : 0 : req->entry_data.kw_mask[idx] = 0x0;
671 : : }
672 : :
673 [ # # ]: 0 : if (flow->nix_intf == NIX_INTF_RX) {
674 : 0 : req->entry_data.kw[0] |= (uint64_t)npc->channel;
675 : 0 : req->entry_data.kw_mask[0] |= (BIT_ULL(12) - 1);
676 : : } else {
677 : 0 : uint16_t pf_func = (flow->npc_action >> 4) & 0xffff;
678 : :
679 [ # # ]: 0 : pf_func = plt_cpu_to_be_16(pf_func);
680 : 0 : req->entry_data.kw[0] |= ((uint64_t)pf_func << 32);
681 : 0 : req->entry_data.kw_mask[0] |= ((uint64_t)0xffff << 32);
682 : : }
683 : : } else {
684 : : struct npc_mcam_write_entry_req *req;
685 : :
686 : 0 : req = mbox_alloc_msg_npc_mcam_write_entry(mbox);
687 [ # # ]: 0 : if (req == NULL) {
688 : : rc = -ENOSPC;
689 : 0 : goto exit;
690 : : }
691 : 0 : req->set_cntr = 0;
692 : 0 : req->cntr = 0;
693 : 0 : req->entry = mcam_id;
694 : :
695 : 0 : req->intf = (flow->nix_intf == NIX_INTF_RX) ? NPC_MCAM_RX : NPC_MCAM_TX;
696 : 0 : req->enable_entry = 1;
697 : 0 : req->entry_data.action = flow->npc_action;
698 : 0 : req->entry_data.vtag_action = flow->vtag_action;
699 : :
700 [ # # ]: 0 : for (idx = 0; idx < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; idx++) {
701 : 0 : req->entry_data.kw[idx] = 0x0;
702 : 0 : req->entry_data.kw_mask[idx] = 0x0;
703 : : }
704 : :
705 [ # # ]: 0 : if (flow->nix_intf == NIX_INTF_RX) {
706 : 0 : req->entry_data.kw[0] |= (uint64_t)npc->channel;
707 : 0 : req->entry_data.kw_mask[0] |= (BIT_ULL(12) - 1);
708 : : } else {
709 : 0 : uint16_t pf_func = (flow->npc_action >> 4) & 0xffff;
710 : :
711 [ # # ]: 0 : pf_func = plt_cpu_to_be_16(pf_func);
712 : 0 : req->entry_data.kw[0] |= ((uint64_t)pf_func << 32);
713 : 0 : req->entry_data.kw_mask[0] |= ((uint64_t)0xffff << 32);
714 : : }
715 : : }
716 : :
717 : : rc = mbox_process_msg(mbox, (void *)&rsp);
718 [ # # ]: 0 : if (rc != 0) {
719 : 0 : plt_err("npc: mcam initialisation write failed");
720 : 0 : goto exit;
721 : : }
722 : : rc = 0;
723 : 0 : exit:
724 : : mbox_put(mbox);
725 : 0 : return rc;
726 : : }
727 : :
728 : : int
729 : 0 : npc_mcam_move(struct mbox *mbox, uint16_t old_ent, uint16_t new_ent)
730 : : {
731 : : struct npc_mcam_shift_entry_req *req;
732 : : struct npc_mcam_shift_entry_rsp *rsp;
733 : : int rc = -ENOSPC;
734 : :
735 : : /* Old entry is disabled & it's contents are moved to new_entry,
736 : : * new entry is enabled finally.
737 : : */
738 : 0 : req = mbox_alloc_msg_npc_mcam_shift_entry(mbox_get(mbox));
739 [ # # ]: 0 : if (req == NULL)
740 : 0 : goto exit;
741 : 0 : req->curr_entry[0] = old_ent;
742 : 0 : req->new_entry[0] = new_ent;
743 : 0 : req->shift_count = 1;
744 : :
745 : : rc = mbox_process_msg(mbox, (void *)&rsp);
746 [ # # ]: 0 : if (rc)
747 : 0 : goto exit;
748 : :
749 : : rc = 0;
750 : 0 : exit:
751 : : mbox_put(mbox);
752 : 0 : return rc;
753 : : }
754 : :
755 : : enum SHIFT_DIR {
756 : : SLIDE_ENTRIES_TO_LOWER_INDEX,
757 : : SLIDE_ENTRIES_TO_HIGHER_INDEX,
758 : : };
759 : :
760 : : static int
761 : 0 : npc_slide_mcam_entries(struct mbox *mbox, struct npc *npc, int prio,
762 : : uint16_t *free_mcam_id, int dir)
763 : : {
764 : : uint16_t to_mcam_id = 0, from_mcam_id = 0;
765 : : struct npc_prio_flow_list_head *list;
766 : : struct npc_prio_flow_entry *curr = 0;
767 : : int rc = 0;
768 : :
769 : 0 : list = &npc->prio_flow_list[prio];
770 : :
771 : 0 : to_mcam_id = *free_mcam_id;
772 [ # # ]: 0 : if (dir == SLIDE_ENTRIES_TO_HIGHER_INDEX)
773 : 0 : curr = TAILQ_LAST(list, npc_prio_flow_list_head);
774 [ # # ]: 0 : else if (dir == SLIDE_ENTRIES_TO_LOWER_INDEX)
775 : 0 : curr = TAILQ_FIRST(list);
776 : :
777 [ # # ]: 0 : while (curr) {
778 : 0 : from_mcam_id = curr->flow->mcam_id;
779 : 0 : if ((dir == SLIDE_ENTRIES_TO_HIGHER_INDEX &&
780 [ # # ]: 0 : from_mcam_id < to_mcam_id) ||
781 : 0 : (dir == SLIDE_ENTRIES_TO_LOWER_INDEX &&
782 [ # # ]: 0 : from_mcam_id > to_mcam_id)) {
783 : : /* Newly allocated entry and the source entry given to
784 : : * npc_mcam_shift_entry_req will be in disabled state.
785 : : * Initialise and enable before moving an entry into
786 : : * this mcam.
787 : : */
788 : 0 : rc = npc_mcam_init(npc, curr->flow, to_mcam_id);
789 [ # # ]: 0 : if (rc)
790 : 0 : return rc;
791 : 0 : rc = npc_mcam_move(mbox, from_mcam_id, to_mcam_id);
792 [ # # ]: 0 : if (rc)
793 : 0 : return rc;
794 : 0 : curr->flow->mcam_id = to_mcam_id;
795 : : to_mcam_id = from_mcam_id;
796 : : }
797 : :
798 [ # # ]: 0 : if (dir == SLIDE_ENTRIES_TO_HIGHER_INDEX)
799 : 0 : curr = TAILQ_PREV(curr, npc_prio_flow_list_head, next);
800 [ # # ]: 0 : else if (dir == SLIDE_ENTRIES_TO_LOWER_INDEX)
801 : 0 : curr = TAILQ_NEXT(curr, next);
802 : : }
803 : :
804 : 0 : *free_mcam_id = from_mcam_id;
805 : :
806 : 0 : return 0;
807 : : }
808 : :
809 : : /*
810 : : * The mcam_alloc request is first made with NPC_MCAM_LOWER_PRIO with the last
811 : : * entry in the requested priority level as the reference entry. If it fails,
812 : : * the alloc request is retried with NPC_MCAM_HIGHER_PRIO with the first entry
813 : : * in the next lower priority level as the reference entry. After obtaining
814 : : * the free MCAM from kernel, we check if it is at the right user requested
815 : : * priority level. If not, the flow rules are moved across MCAM entries till
816 : : * the user requested priority levels are met.
817 : : * The MCAM sorting algorithm works as below.
818 : : * For any given free MCAM obtained from the kernel, there are 3 possibilities.
819 : : * Case 1:
820 : : * There are entries belonging to higher user priority level (numerically
821 : : * lesser) in higher mcam indices. In this case, the entries with higher user
822 : : * priority are slided towards lower indices and a free entry is created in the
823 : : * higher indices.
824 : : * Example:
825 : : * Assume free entry = 1610, user requested priority = 2 and
826 : : * max user priority levels = 5 with below entries in respective priority
827 : : * levels.
828 : : * 0: 1630, 1635, 1641
829 : : * 1: 1646, 1650, 1651
830 : : * 2: 1652, 1655, 1660
831 : : * 3: 1661, 1662, 1663, 1664
832 : : * 4: 1665, 1667, 1670
833 : : *
834 : : * Entries (1630, 1635, 1641, 1646, 1650, 1651) have to be slided down towards
835 : : * lower indices.
836 : : * Shifting sequence will be as below:
837 : : * 1610 <- 1630 <- 1635 <- 1641 <- 1646 <- 1650 <- 1651
838 : : * Entry 1651 will be free-ed for writing the new flow. This entry will now
839 : : * become the head of priority level 2.
840 : : *
841 : : * Case 2:
842 : : * There are entries belonging to lower user priority level (numerically
843 : : * bigger) in lower mcam indices. In this case, the entries with lower user
844 : : * priority are slided towards higher indices and a free entry is created in the
845 : : * lower indices.
846 : : *
847 : : * Example:
848 : : * free entry = 1653, user requested priority = 0
849 : : * 0: 1630, 1635, 1641
850 : : * 1: 1646, 1650, 1651
851 : : * 2: 1652, 1655, 1660
852 : : * 3: 1661, 1662, 1663, 1664
853 : : * 4: 1665, 1667, 1670
854 : : *
855 : : * Entries (1646, 1650, 1651, 1652) have to be slided up towards higher
856 : : * indices.
857 : : * Shifting sequence will be as below:
858 : : * 1646 -> 1650 -> 1651 -> 1652 -> 1653
859 : : * Entry 1646 will be free-ed for writing the new flow. This entry will now
860 : : * become the last element in priority level 0.
861 : : *
862 : : * Case 3:
863 : : * Free mcam is at the right place, ie, all higher user priority level
864 : : * mcams lie in lower indices and all lower user priority level mcams lie in
865 : : * higher mcam indices.
866 : : *
867 : : * The priority level lists are scanned first for case (1) and if the
868 : : * condition is found true, case(2) is skipped because they are mutually
869 : : * exclusive. For example, consider below state.
870 : : * 0: 1630, 1635, 1641
871 : : * 1: 1646, 1650, 1651
872 : : * 2: 1652, 1655, 1660
873 : : * 3: 1661, 1662, 1663, 1664
874 : : * 4: 1665, 1667, 1670
875 : : * free entry = 1610, user requested priority = 2
876 : : *
877 : : * Case 1: Here the condition is;
878 : : * "if (requested_prio > prio_idx && free_mcam < tail->flow->mcam_id ){}"
879 : : * If this condition is true, it means at some higher priority level than
880 : : * requested priority level, there are entries at lower indices than the given
881 : : * free mcam. That is, we have found in levels 0,1 there is an mcam X which is
882 : : * greater than 1610.
883 : : * If, for any free entry and user req prio, the above condition is true, then
884 : : * the below case(2) condition will always be false since the lists are kept
885 : : * sorted. The case(2) condition is;
886 : : * "if (requested_prio < prio_idx && free_mcam > head->flow->mcam_id){}"
887 : : * There can't be entries at lower indices at priority level higher
888 : : * than the requested priority level. That is, here, at levels 3 & 4 there
889 : : * cannot be any entry greater than 1610. Because all entries in 3 & 4 must be
890 : : * greater than X which was found to be greater than 1610 earlier.
891 : : */
892 : :
893 : : static int
894 : 0 : npc_sort_mcams_by_user_prio_level(struct mbox *mbox,
895 : : struct npc_prio_flow_entry *flow_list_entry,
896 : : struct npc *npc,
897 : : struct npc_mcam_alloc_entry_rsp *rsp)
898 : : {
899 : 0 : int requested_prio = flow_list_entry->flow->priority;
900 : : struct npc_prio_flow_entry *head, *tail;
901 : : struct npc_prio_flow_list_head *list;
902 : 0 : uint16_t free_mcam = rsp->entry;
903 : : bool do_reverse_scan = true;
904 : : int prio_idx = 0, rc = 0;
905 : :
906 [ # # ]: 0 : while (prio_idx <= npc->flow_max_priority - 1) {
907 : 0 : list = &npc->prio_flow_list[prio_idx];
908 : 0 : tail = TAILQ_LAST(list, npc_prio_flow_list_head);
909 : :
910 : : /* requested priority is lower than current level
911 : : * ie, numerically req prio is higher
912 : : */
913 [ # # ]: 0 : if ((requested_prio > prio_idx) && tail) {
914 : : /* but there are some mcams in current level
915 : : * at higher indices, ie, at priority lower
916 : : * than free_mcam.
917 : : */
918 [ # # ]: 0 : if (free_mcam < tail->flow->mcam_id) {
919 : 0 : rc = npc_slide_mcam_entries(
920 : : mbox, npc, prio_idx, &free_mcam,
921 : : SLIDE_ENTRIES_TO_LOWER_INDEX);
922 [ # # ]: 0 : if (rc)
923 : 0 : return rc;
924 : : do_reverse_scan = false;
925 : : }
926 : : }
927 : 0 : prio_idx++;
928 : : }
929 : :
930 : 0 : prio_idx = npc->flow_max_priority - 1;
931 [ # # ]: 0 : while (prio_idx && do_reverse_scan) {
932 : 0 : list = &npc->prio_flow_list[prio_idx];
933 : 0 : head = TAILQ_FIRST(list);
934 : :
935 : : /* requested priority is higher than current level
936 : : * ie, numerically req prio is lower
937 : : */
938 [ # # ]: 0 : if (requested_prio < prio_idx && head) {
939 : : /* but free mcam is higher than lowest priority
940 : : * mcam in current level
941 : : */
942 [ # # ]: 0 : if (free_mcam > head->flow->mcam_id) {
943 : 0 : rc = npc_slide_mcam_entries(
944 : : mbox, npc, prio_idx, &free_mcam,
945 : : SLIDE_ENTRIES_TO_HIGHER_INDEX);
946 [ # # ]: 0 : if (rc)
947 : 0 : return rc;
948 : : }
949 : : }
950 : 0 : prio_idx--;
951 : : }
952 : 0 : rsp->entry = free_mcam;
953 : 0 : return rc;
954 : : }
955 : :
956 : : static void
957 : 0 : npc_insert_into_flow_list(struct npc *npc, struct npc_prio_flow_entry *entry)
958 : : {
959 : : struct npc_prio_flow_list_head *list;
960 : : struct npc_prio_flow_entry *curr;
961 : :
962 : 0 : list = &npc->prio_flow_list[entry->flow->priority];
963 : 0 : curr = TAILQ_FIRST(list);
964 : :
965 [ # # ]: 0 : if (curr) {
966 [ # # ]: 0 : while (curr) {
967 [ # # ]: 0 : if (entry->flow->mcam_id > curr->flow->mcam_id)
968 : 0 : curr = TAILQ_NEXT(curr, next);
969 : : else
970 : : break;
971 : : }
972 [ # # ]: 0 : if (curr)
973 : 0 : TAILQ_INSERT_BEFORE(curr, entry, next);
974 : : else
975 : 0 : TAILQ_INSERT_TAIL(list, entry, next);
976 : : } else {
977 : 0 : TAILQ_INSERT_HEAD(list, entry, next);
978 : : }
979 : 0 : }
980 : :
981 : : static int
982 : 0 : npc_allocate_mcam_entry(struct mbox *mbox, int prio, struct npc_mcam_alloc_entry_rsp *rsp_local,
983 : : int ref_entry, uint8_t kw_type)
984 : : {
985 : : struct npc_mcam_alloc_entry_rsp *rsp;
986 : : struct npc_mcam_alloc_entry_req *req;
987 : :
988 : : int rc = -ENOSPC;
989 : :
990 : 0 : req = mbox_alloc_msg_npc_mcam_alloc_entry(mbox_get(mbox));
991 [ # # ]: 0 : if (req == NULL)
992 : 0 : goto exit;
993 : 0 : req->contig = 1;
994 : 0 : req->count = 1;
995 : 0 : req->ref_priority = prio;
996 : 0 : req->ref_entry = ref_entry;
997 : 0 : req->kw_type = kw_type;
998 : :
999 : : rc = mbox_process_msg(mbox, (void *)&rsp);
1000 [ # # ]: 0 : if (rc)
1001 : 0 : goto exit;
1002 : :
1003 [ # # ]: 0 : if (!rsp->count) {
1004 : : rc = -ENOSPC;
1005 : 0 : goto exit;
1006 : : }
1007 : :
1008 : : mbox_memcpy(rsp_local, rsp, sizeof(*rsp));
1009 : : rc = 0;
1010 : 0 : exit:
1011 : : mbox_put(mbox);
1012 : 0 : return rc;
1013 : : }
1014 : :
1015 : : static void
1016 : 0 : npc_find_mcam_ref_entry(struct roc_npc_flow *flow, struct npc *npc, int *prio,
1017 : : int *ref_entry, int dir)
1018 : : {
1019 : : struct npc_prio_flow_entry *head, *tail;
1020 : : struct npc_prio_flow_list_head *list;
1021 : 0 : int prio_idx = flow->priority;
1022 : :
1023 [ # # ]: 0 : if (dir == NPC_MCAM_LOWER_PRIO) {
1024 [ # # ]: 0 : while (prio_idx >= 0) {
1025 : 0 : list = &npc->prio_flow_list[prio_idx];
1026 : 0 : head = TAILQ_FIRST(list);
1027 [ # # ]: 0 : if (head) {
1028 : 0 : *prio = NPC_MCAM_LOWER_PRIO;
1029 : 0 : *ref_entry = head->flow->mcam_id;
1030 : 0 : return;
1031 : : }
1032 : 0 : prio_idx--;
1033 : : }
1034 [ # # ]: 0 : } else if (dir == NPC_MCAM_HIGHER_PRIO) {
1035 : : prio_idx = flow->priority;
1036 [ # # ]: 0 : while (prio_idx <= npc->flow_max_priority - 1) {
1037 : 0 : list = &npc->prio_flow_list[prio_idx];
1038 : 0 : tail = TAILQ_LAST(list, npc_prio_flow_list_head);
1039 [ # # ]: 0 : if (tail) {
1040 : 0 : *prio = NPC_MCAM_HIGHER_PRIO;
1041 : 0 : *ref_entry = tail->flow->mcam_id;
1042 : 0 : return;
1043 : : }
1044 : 0 : prio_idx++;
1045 : : }
1046 : : }
1047 : 0 : *prio = NPC_MCAM_ANY_PRIO;
1048 : 0 : *ref_entry = 0;
1049 : : }
1050 : :
1051 : : static int
1052 : 0 : npc_alloc_mcam_by_ref_entry(struct mbox *mbox, struct roc_npc_flow *flow, struct npc *npc,
1053 : : struct npc_mcam_alloc_entry_rsp *rsp_local)
1054 : : {
1055 : 0 : int prio, ref_entry = 0, rc = 0, dir = NPC_MCAM_LOWER_PRIO;
1056 : : bool retry_done = false;
1057 : :
1058 : 0 : retry:
1059 : 0 : npc_find_mcam_ref_entry(flow, npc, &prio, &ref_entry, dir);
1060 : 0 : rc = npc_allocate_mcam_entry(mbox, prio, rsp_local, ref_entry, flow->key_type);
1061 [ # # ]: 0 : if (rc && !retry_done) {
1062 : 0 : plt_npc_dbg(
1063 : : "npc: Failed to allocate lower priority entry. Retrying for higher priority");
1064 : :
1065 : : dir = NPC_MCAM_HIGHER_PRIO;
1066 : : retry_done = true;
1067 : 0 : goto retry;
1068 [ # # ]: 0 : } else if (rc && retry_done) {
1069 : 0 : return rc;
1070 : : }
1071 : :
1072 : : return 0;
1073 : : }
1074 : :
1075 : : int
1076 : 0 : npc_get_free_mcam_entry(struct mbox *mbox, struct roc_npc_flow *flow, struct npc *npc)
1077 : : {
1078 : : struct npc_mcam_alloc_entry_rsp rsp_local;
1079 : : struct npc_prio_flow_entry *new_entry;
1080 : : int rc = 0;
1081 : :
1082 : 0 : new_entry = plt_zmalloc(sizeof(*new_entry), 0);
1083 [ # # ]: 0 : if (!new_entry)
1084 : : return -ENOSPC;
1085 : :
1086 [ # # ]: 0 : if (roc_model_is_cn20k()) {
1087 : 0 : rc = npc_allocate_mcam_entry(mbox, NPC_MCAM_ANY_PRIO, &rsp_local, 0,
1088 : 0 : flow->key_type);
1089 [ # # ]: 0 : if (rc) {
1090 : 0 : plt_npc_dbg("npc: failed to allocate MCAM entry.");
1091 : 0 : return rc;
1092 : : }
1093 : :
1094 : 0 : new_entry->flow = flow;
1095 : : } else {
1096 : 0 : rc = npc_alloc_mcam_by_ref_entry(mbox, flow, npc, &rsp_local);
1097 : :
1098 [ # # ]: 0 : if (rc)
1099 : : return rc;
1100 : :
1101 : 0 : new_entry->flow = flow;
1102 : :
1103 : 0 : plt_npc_dbg("kernel allocated MCAM entry %d", rsp_local.entry);
1104 : :
1105 : 0 : rc = npc_sort_mcams_by_user_prio_level(mbox, new_entry, npc, &rsp_local);
1106 [ # # ]: 0 : if (rc)
1107 : 0 : goto err;
1108 : :
1109 : 0 : plt_npc_dbg("allocated MCAM entry after sorting %d", rsp_local.entry);
1110 : : }
1111 : :
1112 : 0 : flow->mcam_id = rsp_local.entry;
1113 : 0 : npc_insert_into_flow_list(npc, new_entry);
1114 : :
1115 : 0 : return rsp_local.entry;
1116 : : err:
1117 : 0 : plt_free(new_entry);
1118 : 0 : return rc;
1119 : : }
1120 : :
1121 : : void
1122 : 0 : npc_delete_prio_list_entry(struct npc *npc, struct roc_npc_flow *flow)
1123 : : {
1124 : : struct npc_prio_flow_list_head *list;
1125 : : struct npc_prio_flow_entry *curr;
1126 : :
1127 : 0 : list = &npc->prio_flow_list[flow->priority];
1128 : 0 : curr = TAILQ_FIRST(list);
1129 : :
1130 [ # # ]: 0 : if (!curr)
1131 : : return;
1132 : :
1133 [ # # ]: 0 : while (curr) {
1134 [ # # ]: 0 : if (flow->mcam_id == curr->flow->mcam_id) {
1135 [ # # ]: 0 : TAILQ_REMOVE(list, curr, next);
1136 : 0 : plt_free(curr);
1137 : 0 : break;
1138 : : }
1139 : 0 : curr = TAILQ_NEXT(curr, next);
1140 : : }
1141 : : }
|