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, 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 : rc = npc_ipv6_field_hash_get(pst->npc, (const uint32_t *)hash_field, intf, i,
509 : : &hash);
510 [ # # ]: 0 : if (rc)
511 : 0 : return rc;
512 : :
513 : 0 : mask = GENMASK(31, 0);
514 : 0 : memcpy(pst->mcam_mask + xinfo->key_off, (uint8_t *)&mask, 4);
515 : 0 : memcpy(pst->mcam_data + xinfo->key_off, (uint8_t *)&hash, 4);
516 : : }
517 : :
518 : : return 0;
519 : : }
520 : :
521 : : int
522 [ # # ]: 0 : npc_process_ipv6_field_hash(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
523 : : const struct roc_npc_flow_item_ipv6 *ipv6_mask,
524 : : struct npc_parse_state *pst, uint8_t ltype)
525 : : {
526 [ # # ]: 0 : if (!roc_model_is_cn20k())
527 : 0 : return npc_process_ipv6_field_hash_legacy(ipv6_spec, ipv6_mask, pst, ltype);
528 : : else
529 : 0 : return npc_process_ipv6_field_hash_o20k(ipv6_spec, ipv6_mask, pst, ltype);
530 : : }
531 : :
532 : : static int
533 : 0 : npc_update_parse_state_legacy(struct npc_parse_state *pst, struct npc_parse_item_info *info,
534 : : int lid, int lt, uint8_t flags)
535 : : {
536 : : struct npc_lid_lt_xtract_info *xinfo;
537 : : struct roc_npc_flow_dump_data *dump;
538 : : struct npc_xtract_info *lfinfo;
539 : : int intf, lf_cfg;
540 : : int i, j, rc = 0;
541 : :
542 : 0 : pst->layer_mask |= lid;
543 : 0 : pst->lt[lid] = lt;
544 : 0 : pst->flags[lid] = flags;
545 : :
546 : 0 : intf = pst->nix_intf;
547 : 0 : xinfo = &pst->npc->prx_dxcfg[intf][lid][lt];
548 [ # # ]: 0 : if (xinfo->is_terminating)
549 : 0 : pst->terminate = 1;
550 : :
551 [ # # ]: 0 : if (info->spec == NULL)
552 : 0 : goto done;
553 : :
554 [ # # ]: 0 : for (i = 0; i < NPC_MAX_LD; i++) {
555 [ # # ]: 0 : if (xinfo->xtract[i].use_hash)
556 : 0 : continue;
557 : 0 : rc = npc_update_extraction_data(pst, info, &xinfo->xtract[i]);
558 [ # # ]: 0 : if (rc != 0)
559 : 0 : return rc;
560 : : }
561 : :
562 [ # # ]: 0 : for (i = 0; i < NPC_MAX_LD; i++) {
563 [ # # ]: 0 : if (xinfo->xtract[i].flags_enable == 0)
564 : 0 : continue;
565 [ # # ]: 0 : if (xinfo->xtract[i].use_hash)
566 : 0 : continue;
567 : :
568 : 0 : lf_cfg = pst->npc->prx_lfcfg[i].i;
569 [ # # ]: 0 : if (lf_cfg == lid) {
570 [ # # ]: 0 : for (j = 0; j < NPC_MAX_LFL; j++) {
571 : 0 : lfinfo = pst->npc->prx_fxcfg[intf][i][j].xtract;
572 : 0 : rc = npc_update_extraction_data(pst, info, &lfinfo[0]);
573 [ # # ]: 0 : if (rc != 0)
574 : 0 : return rc;
575 : :
576 [ # # ]: 0 : if (lfinfo[0].enable)
577 : 0 : pst->flags[lid] = j;
578 : : }
579 : : }
580 : : }
581 : :
582 : 0 : done:
583 : 0 : dump = &pst->flow->dump_data[pst->flow->num_patterns++];
584 : 0 : dump->lid = lid;
585 : 0 : dump->ltype = lt;
586 : 0 : pst->pattern++;
587 : 0 : return 0;
588 : : }
589 : :
590 : : static int
591 : 0 : npc_update_parse_state_o20(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
592 : : int lt, uint8_t flags)
593 : : {
594 : : struct npc_lid_lt_xtract_info_cn20k *xinfo;
595 : : union npc_kex_ldata_flags_cfg *lid_cfg;
596 : : struct roc_npc_flow_dump_data *dump;
597 : : int intf;
598 : : int i, rc = 0;
599 : :
600 : 0 : pst->layer_mask |= lid;
601 : 0 : pst->lt[lid] = lt;
602 : 0 : pst->flags[lid] = flags;
603 : :
604 : 0 : intf = pst->nix_intf;
605 [ # # ]: 0 : if (info->spec == NULL)
606 : 0 : goto done;
607 : :
608 [ # # ]: 0 : for (i = 0; i < NPC_MAX_EXTRACTTORS; i++) {
609 : 0 : lid_cfg = &pst->npc->lid_cfg[intf][i];
610 [ # # ]: 0 : if (lid_cfg->s.lid != lid)
611 : 0 : continue;
612 : : xinfo = &pst->npc->prx_dxcfg_cn20k[intf][i][lt];
613 [ # # ]: 0 : if (xinfo->is_terminating)
614 : 0 : pst->terminate = 1;
615 : :
616 [ # # ]: 0 : if (xinfo->xtract.use_hash)
617 : 0 : continue;
618 : 0 : rc = npc_update_extraction_data(pst, info, &xinfo->xtract);
619 [ # # ]: 0 : if (rc != 0)
620 : 0 : return rc;
621 : : }
622 : :
623 : 0 : done:
624 : 0 : dump = &pst->flow->dump_data[pst->flow->num_patterns++];
625 : 0 : dump->lid = lid;
626 : 0 : dump->ltype = lt;
627 : 0 : pst->pattern++;
628 : 0 : return 0;
629 : : }
630 : :
631 : : int
632 [ # # ]: 0 : npc_update_parse_state(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
633 : : int lt, uint8_t flags)
634 : : {
635 [ # # ]: 0 : if (roc_model_is_cn20k())
636 : 0 : return npc_update_parse_state_o20(pst, info, lid, lt, flags);
637 : : else
638 : 0 : return npc_update_parse_state_legacy(pst, info, lid, lt, flags);
639 : : }
640 : :
641 : : int
642 : 0 : npc_mcam_init(struct npc *npc, struct roc_npc_flow *flow, int mcam_id)
643 : : {
644 : : struct msg_rsp *rsp;
645 : 0 : struct mbox *mbox = mbox_get(npc->mbox);
646 : : int rc = 0, idx;
647 : :
648 [ # # ]: 0 : if (roc_model_is_cn20k()) {
649 : : struct npc_cn20k_mcam_write_entry_req *req;
650 : :
651 : 0 : req = mbox_alloc_msg_npc_cn20k_mcam_write_entry(mbox);
652 [ # # ]: 0 : if (req == NULL) {
653 : : rc = -ENOSPC;
654 : 0 : goto exit;
655 : : }
656 : 0 : req->cntr = 0;
657 : 0 : req->entry = mcam_id;
658 : :
659 : 0 : req->intf = (flow->nix_intf == NIX_INTF_RX) ? NPC_MCAM_RX : NPC_MCAM_TX;
660 : 0 : req->enable_entry = 1;
661 : 0 : req->entry_data.action = flow->npc_action;
662 : 0 : req->entry_data.vtag_action = flow->vtag_action;
663 : :
664 [ # # ]: 0 : for (idx = 0; idx < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; idx++) {
665 : 0 : req->entry_data.kw[idx] = 0x0;
666 : 0 : req->entry_data.kw_mask[idx] = 0x0;
667 : : }
668 : :
669 [ # # ]: 0 : if (flow->nix_intf == NIX_INTF_RX) {
670 : 0 : req->entry_data.kw[0] |= (uint64_t)npc->channel;
671 : 0 : req->entry_data.kw_mask[0] |= (BIT_ULL(12) - 1);
672 : : } else {
673 : 0 : uint16_t pf_func = (flow->npc_action >> 4) & 0xffff;
674 : :
675 [ # # ]: 0 : pf_func = plt_cpu_to_be_16(pf_func);
676 : 0 : req->entry_data.kw[0] |= ((uint64_t)pf_func << 32);
677 : 0 : req->entry_data.kw_mask[0] |= ((uint64_t)0xffff << 32);
678 : : }
679 : : } else {
680 : : struct npc_mcam_write_entry_req *req;
681 : :
682 : 0 : req = mbox_alloc_msg_npc_mcam_write_entry(mbox);
683 [ # # ]: 0 : if (req == NULL) {
684 : : rc = -ENOSPC;
685 : 0 : goto exit;
686 : : }
687 : 0 : req->set_cntr = 0;
688 : 0 : req->cntr = 0;
689 : 0 : req->entry = mcam_id;
690 : :
691 : 0 : req->intf = (flow->nix_intf == NIX_INTF_RX) ? NPC_MCAM_RX : NPC_MCAM_TX;
692 : 0 : req->enable_entry = 1;
693 : 0 : req->entry_data.action = flow->npc_action;
694 : 0 : req->entry_data.vtag_action = flow->vtag_action;
695 : :
696 [ # # ]: 0 : for (idx = 0; idx < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; idx++) {
697 : 0 : req->entry_data.kw[idx] = 0x0;
698 : 0 : req->entry_data.kw_mask[idx] = 0x0;
699 : : }
700 : :
701 [ # # ]: 0 : if (flow->nix_intf == NIX_INTF_RX) {
702 : 0 : req->entry_data.kw[0] |= (uint64_t)npc->channel;
703 : 0 : req->entry_data.kw_mask[0] |= (BIT_ULL(12) - 1);
704 : : } else {
705 : 0 : uint16_t pf_func = (flow->npc_action >> 4) & 0xffff;
706 : :
707 [ # # ]: 0 : pf_func = plt_cpu_to_be_16(pf_func);
708 : 0 : req->entry_data.kw[0] |= ((uint64_t)pf_func << 32);
709 : 0 : req->entry_data.kw_mask[0] |= ((uint64_t)0xffff << 32);
710 : : }
711 : : }
712 : :
713 : : rc = mbox_process_msg(mbox, (void *)&rsp);
714 [ # # ]: 0 : if (rc != 0) {
715 : 0 : plt_err("npc: mcam initialisation write failed");
716 : 0 : goto exit;
717 : : }
718 : : rc = 0;
719 : 0 : exit:
720 : : mbox_put(mbox);
721 : 0 : return rc;
722 : : }
723 : :
724 : : int
725 : 0 : npc_mcam_move(struct mbox *mbox, uint16_t old_ent, uint16_t new_ent)
726 : : {
727 : : struct npc_mcam_shift_entry_req *req;
728 : : struct npc_mcam_shift_entry_rsp *rsp;
729 : : int rc = -ENOSPC;
730 : :
731 : : /* Old entry is disabled & it's contents are moved to new_entry,
732 : : * new entry is enabled finally.
733 : : */
734 : 0 : req = mbox_alloc_msg_npc_mcam_shift_entry(mbox_get(mbox));
735 [ # # ]: 0 : if (req == NULL)
736 : 0 : goto exit;
737 : 0 : req->curr_entry[0] = old_ent;
738 : 0 : req->new_entry[0] = new_ent;
739 : 0 : req->shift_count = 1;
740 : :
741 : : rc = mbox_process_msg(mbox, (void *)&rsp);
742 [ # # ]: 0 : if (rc)
743 : 0 : goto exit;
744 : :
745 : : rc = 0;
746 : 0 : exit:
747 : : mbox_put(mbox);
748 : 0 : return rc;
749 : : }
750 : :
751 : : enum SHIFT_DIR {
752 : : SLIDE_ENTRIES_TO_LOWER_INDEX,
753 : : SLIDE_ENTRIES_TO_HIGHER_INDEX,
754 : : };
755 : :
756 : : static int
757 : 0 : npc_slide_mcam_entries(struct mbox *mbox, struct npc *npc, int prio,
758 : : uint16_t *free_mcam_id, int dir)
759 : : {
760 : : uint16_t to_mcam_id = 0, from_mcam_id = 0;
761 : : struct npc_prio_flow_list_head *list;
762 : : struct npc_prio_flow_entry *curr = 0;
763 : : int rc = 0;
764 : :
765 : 0 : list = &npc->prio_flow_list[prio];
766 : :
767 : 0 : to_mcam_id = *free_mcam_id;
768 [ # # ]: 0 : if (dir == SLIDE_ENTRIES_TO_HIGHER_INDEX)
769 : 0 : curr = TAILQ_LAST(list, npc_prio_flow_list_head);
770 [ # # ]: 0 : else if (dir == SLIDE_ENTRIES_TO_LOWER_INDEX)
771 : 0 : curr = TAILQ_FIRST(list);
772 : :
773 [ # # ]: 0 : while (curr) {
774 : 0 : from_mcam_id = curr->flow->mcam_id;
775 : 0 : if ((dir == SLIDE_ENTRIES_TO_HIGHER_INDEX &&
776 [ # # ]: 0 : from_mcam_id < to_mcam_id) ||
777 : 0 : (dir == SLIDE_ENTRIES_TO_LOWER_INDEX &&
778 [ # # ]: 0 : from_mcam_id > to_mcam_id)) {
779 : : /* Newly allocated entry and the source entry given to
780 : : * npc_mcam_shift_entry_req will be in disabled state.
781 : : * Initialise and enable before moving an entry into
782 : : * this mcam.
783 : : */
784 : 0 : rc = npc_mcam_init(npc, curr->flow, to_mcam_id);
785 [ # # ]: 0 : if (rc)
786 : 0 : return rc;
787 : 0 : rc = npc_mcam_move(mbox, from_mcam_id, to_mcam_id);
788 [ # # ]: 0 : if (rc)
789 : 0 : return rc;
790 : 0 : curr->flow->mcam_id = to_mcam_id;
791 : : to_mcam_id = from_mcam_id;
792 : : }
793 : :
794 [ # # ]: 0 : if (dir == SLIDE_ENTRIES_TO_HIGHER_INDEX)
795 : 0 : curr = TAILQ_PREV(curr, npc_prio_flow_list_head, next);
796 [ # # ]: 0 : else if (dir == SLIDE_ENTRIES_TO_LOWER_INDEX)
797 : 0 : curr = TAILQ_NEXT(curr, next);
798 : : }
799 : :
800 : 0 : *free_mcam_id = from_mcam_id;
801 : :
802 : 0 : return 0;
803 : : }
804 : :
805 : : /*
806 : : * The mcam_alloc request is first made with NPC_MCAM_LOWER_PRIO with the last
807 : : * entry in the requested priority level as the reference entry. If it fails,
808 : : * the alloc request is retried with NPC_MCAM_HIGHER_PRIO with the first entry
809 : : * in the next lower priority level as the reference entry. After obtaining
810 : : * the free MCAM from kernel, we check if it is at the right user requested
811 : : * priority level. If not, the flow rules are moved across MCAM entries till
812 : : * the user requested priority levels are met.
813 : : * The MCAM sorting algorithm works as below.
814 : : * For any given free MCAM obtained from the kernel, there are 3 possibilities.
815 : : * Case 1:
816 : : * There are entries belonging to higher user priority level (numerically
817 : : * lesser) in higher mcam indices. In this case, the entries with higher user
818 : : * priority are slided towards lower indices and a free entry is created in the
819 : : * higher indices.
820 : : * Example:
821 : : * Assume free entry = 1610, user requested priority = 2 and
822 : : * max user priority levels = 5 with below entries in respective priority
823 : : * levels.
824 : : * 0: 1630, 1635, 1641
825 : : * 1: 1646, 1650, 1651
826 : : * 2: 1652, 1655, 1660
827 : : * 3: 1661, 1662, 1663, 1664
828 : : * 4: 1665, 1667, 1670
829 : : *
830 : : * Entries (1630, 1635, 1641, 1646, 1650, 1651) have to be slided down towards
831 : : * lower indices.
832 : : * Shifting sequence will be as below:
833 : : * 1610 <- 1630 <- 1635 <- 1641 <- 1646 <- 1650 <- 1651
834 : : * Entry 1651 will be free-ed for writing the new flow. This entry will now
835 : : * become the head of priority level 2.
836 : : *
837 : : * Case 2:
838 : : * There are entries belonging to lower user priority level (numerically
839 : : * bigger) in lower mcam indices. In this case, the entries with lower user
840 : : * priority are slided towards higher indices and a free entry is created in the
841 : : * lower indices.
842 : : *
843 : : * Example:
844 : : * free entry = 1653, user requested priority = 0
845 : : * 0: 1630, 1635, 1641
846 : : * 1: 1646, 1650, 1651
847 : : * 2: 1652, 1655, 1660
848 : : * 3: 1661, 1662, 1663, 1664
849 : : * 4: 1665, 1667, 1670
850 : : *
851 : : * Entries (1646, 1650, 1651, 1652) have to be slided up towards higher
852 : : * indices.
853 : : * Shifting sequence will be as below:
854 : : * 1646 -> 1650 -> 1651 -> 1652 -> 1653
855 : : * Entry 1646 will be free-ed for writing the new flow. This entry will now
856 : : * become the last element in priority level 0.
857 : : *
858 : : * Case 3:
859 : : * Free mcam is at the right place, ie, all higher user priority level
860 : : * mcams lie in lower indices and all lower user priority level mcams lie in
861 : : * higher mcam indices.
862 : : *
863 : : * The priority level lists are scanned first for case (1) and if the
864 : : * condition is found true, case(2) is skipped because they are mutually
865 : : * exclusive. For example, consider below state.
866 : : * 0: 1630, 1635, 1641
867 : : * 1: 1646, 1650, 1651
868 : : * 2: 1652, 1655, 1660
869 : : * 3: 1661, 1662, 1663, 1664
870 : : * 4: 1665, 1667, 1670
871 : : * free entry = 1610, user requested priority = 2
872 : : *
873 : : * Case 1: Here the condition is;
874 : : * "if (requested_prio > prio_idx && free_mcam < tail->flow->mcam_id ){}"
875 : : * If this condition is true, it means at some higher priority level than
876 : : * requested priority level, there are entries at lower indices than the given
877 : : * free mcam. That is, we have found in levels 0,1 there is an mcam X which is
878 : : * greater than 1610.
879 : : * If, for any free entry and user req prio, the above condition is true, then
880 : : * the below case(2) condition will always be false since the lists are kept
881 : : * sorted. The case(2) condition is;
882 : : * "if (requested_prio < prio_idx && free_mcam > head->flow->mcam_id){}"
883 : : * There can't be entries at lower indices at priority level higher
884 : : * than the requested priority level. That is, here, at levels 3 & 4 there
885 : : * cannot be any entry greater than 1610. Because all entries in 3 & 4 must be
886 : : * greater than X which was found to be greater than 1610 earlier.
887 : : */
888 : :
889 : : static int
890 : 0 : npc_sort_mcams_by_user_prio_level(struct mbox *mbox,
891 : : struct npc_prio_flow_entry *flow_list_entry,
892 : : struct npc *npc,
893 : : struct npc_mcam_alloc_entry_rsp *rsp)
894 : : {
895 : 0 : int requested_prio = flow_list_entry->flow->priority;
896 : : struct npc_prio_flow_entry *head, *tail;
897 : : struct npc_prio_flow_list_head *list;
898 : 0 : uint16_t free_mcam = rsp->entry;
899 : : bool do_reverse_scan = true;
900 : : int prio_idx = 0, rc = 0;
901 : :
902 [ # # ]: 0 : while (prio_idx <= npc->flow_max_priority - 1) {
903 : 0 : list = &npc->prio_flow_list[prio_idx];
904 : 0 : tail = TAILQ_LAST(list, npc_prio_flow_list_head);
905 : :
906 : : /* requested priority is lower than current level
907 : : * ie, numerically req prio is higher
908 : : */
909 [ # # ]: 0 : if ((requested_prio > prio_idx) && tail) {
910 : : /* but there are some mcams in current level
911 : : * at higher indices, ie, at priority lower
912 : : * than free_mcam.
913 : : */
914 [ # # ]: 0 : if (free_mcam < tail->flow->mcam_id) {
915 : 0 : rc = npc_slide_mcam_entries(
916 : : mbox, npc, prio_idx, &free_mcam,
917 : : SLIDE_ENTRIES_TO_LOWER_INDEX);
918 [ # # ]: 0 : if (rc)
919 : 0 : return rc;
920 : : do_reverse_scan = false;
921 : : }
922 : : }
923 : 0 : prio_idx++;
924 : : }
925 : :
926 : 0 : prio_idx = npc->flow_max_priority - 1;
927 [ # # ]: 0 : while (prio_idx && do_reverse_scan) {
928 : 0 : list = &npc->prio_flow_list[prio_idx];
929 : 0 : head = TAILQ_FIRST(list);
930 : :
931 : : /* requested priority is higher than current level
932 : : * ie, numerically req prio is lower
933 : : */
934 [ # # ]: 0 : if (requested_prio < prio_idx && head) {
935 : : /* but free mcam is higher than lowest priority
936 : : * mcam in current level
937 : : */
938 [ # # ]: 0 : if (free_mcam > head->flow->mcam_id) {
939 : 0 : rc = npc_slide_mcam_entries(
940 : : mbox, npc, prio_idx, &free_mcam,
941 : : SLIDE_ENTRIES_TO_HIGHER_INDEX);
942 [ # # ]: 0 : if (rc)
943 : 0 : return rc;
944 : : }
945 : : }
946 : 0 : prio_idx--;
947 : : }
948 : 0 : rsp->entry = free_mcam;
949 : 0 : return rc;
950 : : }
951 : :
952 : : static void
953 : 0 : npc_insert_into_flow_list(struct npc *npc, struct npc_prio_flow_entry *entry)
954 : : {
955 : : struct npc_prio_flow_list_head *list;
956 : : struct npc_prio_flow_entry *curr;
957 : :
958 : 0 : list = &npc->prio_flow_list[entry->flow->priority];
959 : 0 : curr = TAILQ_FIRST(list);
960 : :
961 [ # # ]: 0 : if (curr) {
962 [ # # ]: 0 : while (curr) {
963 [ # # ]: 0 : if (entry->flow->mcam_id > curr->flow->mcam_id)
964 : 0 : curr = TAILQ_NEXT(curr, next);
965 : : else
966 : : break;
967 : : }
968 [ # # ]: 0 : if (curr)
969 : 0 : TAILQ_INSERT_BEFORE(curr, entry, next);
970 : : else
971 : 0 : TAILQ_INSERT_TAIL(list, entry, next);
972 : : } else {
973 : 0 : TAILQ_INSERT_HEAD(list, entry, next);
974 : : }
975 : 0 : }
976 : :
977 : : static int
978 : 0 : npc_allocate_mcam_entry(struct mbox *mbox, int prio, struct npc_mcam_alloc_entry_rsp *rsp_local,
979 : : int ref_entry, uint8_t kw_type)
980 : : {
981 : : struct npc_mcam_alloc_entry_rsp *rsp;
982 : : struct npc_mcam_alloc_entry_req *req;
983 : :
984 : : int rc = -ENOSPC;
985 : :
986 : 0 : req = mbox_alloc_msg_npc_mcam_alloc_entry(mbox_get(mbox));
987 [ # # ]: 0 : if (req == NULL)
988 : 0 : goto exit;
989 : 0 : req->contig = 1;
990 : 0 : req->count = 1;
991 : 0 : req->ref_priority = prio;
992 : 0 : req->ref_entry = ref_entry;
993 : 0 : req->kw_type = kw_type;
994 : :
995 : : rc = mbox_process_msg(mbox, (void *)&rsp);
996 [ # # ]: 0 : if (rc)
997 : 0 : goto exit;
998 : :
999 [ # # ]: 0 : if (!rsp->count) {
1000 : : rc = -ENOSPC;
1001 : 0 : goto exit;
1002 : : }
1003 : :
1004 : : mbox_memcpy(rsp_local, rsp, sizeof(*rsp));
1005 : : rc = 0;
1006 : 0 : exit:
1007 : : mbox_put(mbox);
1008 : 0 : return rc;
1009 : : }
1010 : :
1011 : : static void
1012 : 0 : npc_find_mcam_ref_entry(struct roc_npc_flow *flow, struct npc *npc, int *prio,
1013 : : int *ref_entry, int dir)
1014 : : {
1015 : : struct npc_prio_flow_entry *head, *tail;
1016 : : struct npc_prio_flow_list_head *list;
1017 : 0 : int prio_idx = flow->priority;
1018 : :
1019 [ # # ]: 0 : if (dir == NPC_MCAM_LOWER_PRIO) {
1020 [ # # ]: 0 : while (prio_idx >= 0) {
1021 : 0 : list = &npc->prio_flow_list[prio_idx];
1022 : 0 : head = TAILQ_FIRST(list);
1023 [ # # ]: 0 : if (head) {
1024 : 0 : *prio = NPC_MCAM_LOWER_PRIO;
1025 : 0 : *ref_entry = head->flow->mcam_id;
1026 : 0 : return;
1027 : : }
1028 : 0 : prio_idx--;
1029 : : }
1030 [ # # ]: 0 : } else if (dir == NPC_MCAM_HIGHER_PRIO) {
1031 : : prio_idx = flow->priority;
1032 [ # # ]: 0 : while (prio_idx <= npc->flow_max_priority - 1) {
1033 : 0 : list = &npc->prio_flow_list[prio_idx];
1034 : 0 : tail = TAILQ_LAST(list, npc_prio_flow_list_head);
1035 [ # # ]: 0 : if (tail) {
1036 : 0 : *prio = NPC_MCAM_HIGHER_PRIO;
1037 : 0 : *ref_entry = tail->flow->mcam_id;
1038 : 0 : return;
1039 : : }
1040 : 0 : prio_idx++;
1041 : : }
1042 : : }
1043 : 0 : *prio = NPC_MCAM_ANY_PRIO;
1044 : 0 : *ref_entry = 0;
1045 : : }
1046 : :
1047 : : static int
1048 : 0 : npc_alloc_mcam_by_ref_entry(struct mbox *mbox, struct roc_npc_flow *flow, struct npc *npc,
1049 : : struct npc_mcam_alloc_entry_rsp *rsp_local)
1050 : : {
1051 : 0 : int prio, ref_entry = 0, rc = 0, dir = NPC_MCAM_LOWER_PRIO;
1052 : : bool retry_done = false;
1053 : :
1054 : 0 : retry:
1055 : 0 : npc_find_mcam_ref_entry(flow, npc, &prio, &ref_entry, dir);
1056 : 0 : rc = npc_allocate_mcam_entry(mbox, prio, rsp_local, ref_entry, flow->key_type);
1057 [ # # ]: 0 : if (rc && !retry_done) {
1058 : 0 : plt_npc_dbg(
1059 : : "npc: Failed to allocate lower priority entry. Retrying for higher priority");
1060 : :
1061 : : dir = NPC_MCAM_HIGHER_PRIO;
1062 : : retry_done = true;
1063 : 0 : goto retry;
1064 [ # # ]: 0 : } else if (rc && retry_done) {
1065 : 0 : return rc;
1066 : : }
1067 : :
1068 : : return 0;
1069 : : }
1070 : :
1071 : : int
1072 : 0 : npc_get_free_mcam_entry(struct mbox *mbox, struct roc_npc_flow *flow, struct npc *npc)
1073 : : {
1074 : : struct npc_mcam_alloc_entry_rsp rsp_local;
1075 : : struct npc_prio_flow_entry *new_entry;
1076 : : int rc = 0;
1077 : :
1078 : 0 : new_entry = plt_zmalloc(sizeof(*new_entry), 0);
1079 [ # # ]: 0 : if (!new_entry)
1080 : : return -ENOSPC;
1081 : :
1082 [ # # ]: 0 : if (roc_model_is_cn20k()) {
1083 : 0 : rc = npc_allocate_mcam_entry(mbox, NPC_MCAM_ANY_PRIO, &rsp_local, 0,
1084 : 0 : flow->key_type);
1085 [ # # ]: 0 : if (rc) {
1086 : 0 : plt_npc_dbg("npc: failed to allocate MCAM entry.");
1087 : 0 : return rc;
1088 : : }
1089 : :
1090 : 0 : new_entry->flow = flow;
1091 : : } else {
1092 : 0 : rc = npc_alloc_mcam_by_ref_entry(mbox, flow, npc, &rsp_local);
1093 : :
1094 [ # # ]: 0 : if (rc)
1095 : : return rc;
1096 : :
1097 : 0 : new_entry->flow = flow;
1098 : :
1099 : 0 : plt_npc_dbg("kernel allocated MCAM entry %d", rsp_local.entry);
1100 : :
1101 : 0 : rc = npc_sort_mcams_by_user_prio_level(mbox, new_entry, npc, &rsp_local);
1102 [ # # ]: 0 : if (rc)
1103 : 0 : goto err;
1104 : :
1105 : 0 : plt_npc_dbg("allocated MCAM entry after sorting %d", rsp_local.entry);
1106 : : }
1107 : :
1108 : 0 : flow->mcam_id = rsp_local.entry;
1109 : 0 : npc_insert_into_flow_list(npc, new_entry);
1110 : :
1111 : 0 : return rsp_local.entry;
1112 : : err:
1113 : 0 : plt_free(new_entry);
1114 : 0 : return rc;
1115 : : }
1116 : :
1117 : : void
1118 : 0 : npc_delete_prio_list_entry(struct npc *npc, struct roc_npc_flow *flow)
1119 : : {
1120 : : struct npc_prio_flow_list_head *list;
1121 : : struct npc_prio_flow_entry *curr;
1122 : :
1123 : 0 : list = &npc->prio_flow_list[flow->priority];
1124 : 0 : curr = TAILQ_FIRST(list);
1125 : :
1126 [ # # ]: 0 : if (!curr)
1127 : : return;
1128 : :
1129 [ # # ]: 0 : while (curr) {
1130 [ # # ]: 0 : if (flow->mcam_id == curr->flow->mcam_id) {
1131 [ # # ]: 0 : TAILQ_REMOVE(list, curr, next);
1132 : 0 : plt_free(curr);
1133 : 0 : break;
1134 : : }
1135 : 0 : curr = TAILQ_NEXT(curr, next);
1136 : : }
1137 : : }
|