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