1665b6a74SKiran Kumar K /* SPDX-License-Identifier: BSD-3-Clause
2665b6a74SKiran Kumar K * Copyright(C) 2021 Marvell.
3665b6a74SKiran Kumar K */
4665b6a74SKiran Kumar K #include "roc_api.h"
5665b6a74SKiran Kumar K #include "roc_priv.h"
6665b6a74SKiran Kumar K
7665b6a74SKiran Kumar K static void
npc_prep_mcam_ldata(uint8_t * ptr,const uint8_t * data,int len)8665b6a74SKiran Kumar K npc_prep_mcam_ldata(uint8_t *ptr, const uint8_t *data, int len)
9665b6a74SKiran Kumar K {
10665b6a74SKiran Kumar K int idx;
11665b6a74SKiran Kumar K
12665b6a74SKiran Kumar K for (idx = 0; idx < len; idx++)
13665b6a74SKiran Kumar K ptr[idx] = data[len - 1 - idx];
14665b6a74SKiran Kumar K }
15665b6a74SKiran Kumar K
16665b6a74SKiran Kumar K static int
npc_check_copysz(size_t size,size_t len)17665b6a74SKiran Kumar K npc_check_copysz(size_t size, size_t len)
18665b6a74SKiran Kumar K {
19665b6a74SKiran Kumar K if (len <= size)
20665b6a74SKiran Kumar K return len;
21665b6a74SKiran Kumar K return NPC_ERR_PARAM;
22665b6a74SKiran Kumar K }
23665b6a74SKiran Kumar K
24665b6a74SKiran Kumar K static inline int
npc_mem_is_zero(const void * mem,int len)25665b6a74SKiran Kumar K npc_mem_is_zero(const void *mem, int len)
26665b6a74SKiran Kumar K {
27665b6a74SKiran Kumar K const char *m = mem;
28665b6a74SKiran Kumar K int i;
29665b6a74SKiran Kumar K
30665b6a74SKiran Kumar K for (i = 0; i < len; i++) {
31665b6a74SKiran Kumar K if (m[i] != 0)
32665b6a74SKiran Kumar K return 0;
33665b6a74SKiran Kumar K }
34665b6a74SKiran Kumar K return 1;
35665b6a74SKiran Kumar K }
36665b6a74SKiran Kumar K
37665b6a74SKiran Kumar K static void
npc_set_hw_mask(struct npc_parse_item_info * info,struct npc_xtract_info * xinfo,char * hw_mask)38665b6a74SKiran Kumar K npc_set_hw_mask(struct npc_parse_item_info *info, struct npc_xtract_info *xinfo,
39665b6a74SKiran Kumar K char *hw_mask)
40665b6a74SKiran Kumar K {
41665b6a74SKiran Kumar K int max_off, offset;
42665b6a74SKiran Kumar K int j;
43665b6a74SKiran Kumar K
44665b6a74SKiran Kumar K if (xinfo->enable == 0)
45665b6a74SKiran Kumar K return;
46665b6a74SKiran Kumar K
47665b6a74SKiran Kumar K if (xinfo->hdr_off < info->hw_hdr_len)
48665b6a74SKiran Kumar K return;
49665b6a74SKiran Kumar K
50665b6a74SKiran Kumar K max_off = xinfo->hdr_off + xinfo->len - info->hw_hdr_len;
51665b6a74SKiran Kumar K
52665b6a74SKiran Kumar K if (max_off > info->len)
53665b6a74SKiran Kumar K max_off = info->len;
54665b6a74SKiran Kumar K
55665b6a74SKiran Kumar K offset = xinfo->hdr_off - info->hw_hdr_len;
56665b6a74SKiran Kumar K for (j = offset; j < max_off; j++)
57665b6a74SKiran Kumar K hw_mask[j] = 0xff;
58665b6a74SKiran Kumar K }
59665b6a74SKiran Kumar K
60e3315630SSatheesh Paul static void
npc_ipv6_hash_mask_get(struct npc_xtract_info * xinfo,struct npc_parse_item_info * info)61e3315630SSatheesh Paul npc_ipv6_hash_mask_get(struct npc_xtract_info *xinfo, struct npc_parse_item_info *info)
62e3315630SSatheesh Paul {
63e3315630SSatheesh Paul int offset = 0;
64e3315630SSatheesh Paul uint8_t *hw_mask = info->hw_mask;
65e3315630SSatheesh Paul
66e3315630SSatheesh Paul offset = xinfo->hdr_off - info->hw_hdr_len;
67e3315630SSatheesh Paul memset(&hw_mask[offset], 0xFF, NPC_HASH_FIELD_LEN);
68e3315630SSatheesh Paul }
69e3315630SSatheesh Paul
70665b6a74SKiran Kumar K void
npc_get_hw_supp_mask(struct npc_parse_state * pst,struct npc_parse_item_info * info,int lid,int lt)71e3315630SSatheesh Paul npc_get_hw_supp_mask(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid, int lt)
72665b6a74SKiran Kumar K {
73665b6a74SKiran Kumar K struct npc_xtract_info *xinfo, *lfinfo;
74665b6a74SKiran Kumar K char *hw_mask = info->hw_mask;
75665b6a74SKiran Kumar K int lf_cfg = 0;
76665b6a74SKiran Kumar K int i, j;
77665b6a74SKiran Kumar K int intf;
78665b6a74SKiran Kumar K
79665b6a74SKiran Kumar K intf = pst->nix_intf;
80665b6a74SKiran Kumar K xinfo = pst->npc->prx_dxcfg[intf][lid][lt].xtract;
81665b6a74SKiran Kumar K memset(hw_mask, 0, info->len);
82665b6a74SKiran Kumar K
83e3315630SSatheesh Paul for (i = 0; i < NPC_MAX_LD; i++) {
84e3315630SSatheesh Paul if (pst->npc->hash_extract_cap && xinfo[i].use_hash)
85e3315630SSatheesh Paul npc_ipv6_hash_mask_get(&xinfo[i], info);
86e3315630SSatheesh Paul else
87665b6a74SKiran Kumar K npc_set_hw_mask(info, &xinfo[i], hw_mask);
88e3315630SSatheesh Paul }
89665b6a74SKiran Kumar K
90665b6a74SKiran Kumar K for (i = 0; i < NPC_MAX_LD; i++) {
91665b6a74SKiran Kumar K if (xinfo[i].flags_enable == 0)
92665b6a74SKiran Kumar K continue;
93665b6a74SKiran Kumar K
94665b6a74SKiran Kumar K lf_cfg = pst->npc->prx_lfcfg[i].i;
95665b6a74SKiran Kumar K if (lf_cfg == lid) {
96665b6a74SKiran Kumar K for (j = 0; j < NPC_MAX_LFL; j++) {
97665b6a74SKiran Kumar K lfinfo = pst->npc->prx_fxcfg[intf][i][j].xtract;
98665b6a74SKiran Kumar K npc_set_hw_mask(info, &lfinfo[0], hw_mask);
99665b6a74SKiran Kumar K }
100665b6a74SKiran Kumar K }
101665b6a74SKiran Kumar K }
102665b6a74SKiran Kumar K }
103665b6a74SKiran Kumar K
10447412486SSatheesh Paul inline int
npc_mask_is_supported(const char * mask,const char * hw_mask,int len)105665b6a74SKiran Kumar K npc_mask_is_supported(const char *mask, const char *hw_mask, int len)
106665b6a74SKiran Kumar K {
107665b6a74SKiran Kumar K /*
108665b6a74SKiran Kumar K * If no hw_mask, assume nothing is supported.
109665b6a74SKiran Kumar K * mask is never NULL
110665b6a74SKiran Kumar K */
111665b6a74SKiran Kumar K if (hw_mask == NULL)
112665b6a74SKiran Kumar K return npc_mem_is_zero(mask, len);
113665b6a74SKiran Kumar K
114665b6a74SKiran Kumar K while (len--) {
115665b6a74SKiran Kumar K if ((mask[len] | hw_mask[len]) != hw_mask[len])
116665b6a74SKiran Kumar K return 0; /* False */
117665b6a74SKiran Kumar K }
118665b6a74SKiran Kumar K return 1;
119665b6a74SKiran Kumar K }
120665b6a74SKiran Kumar K
121665b6a74SKiran Kumar K int
npc_parse_item_basic(const struct roc_npc_item_info * item,struct npc_parse_item_info * info)122665b6a74SKiran Kumar K npc_parse_item_basic(const struct roc_npc_item_info *item,
123665b6a74SKiran Kumar K struct npc_parse_item_info *info)
124665b6a74SKiran Kumar K {
125665b6a74SKiran Kumar K /* Item must not be NULL */
126665b6a74SKiran Kumar K if (item == NULL)
127665b6a74SKiran Kumar K return NPC_ERR_PARAM;
128665b6a74SKiran Kumar K
129665b6a74SKiran Kumar K /* Don't support ranges */
130665b6a74SKiran Kumar K if (item->last != NULL)
131665b6a74SKiran Kumar K return NPC_ERR_INVALID_RANGE;
132665b6a74SKiran Kumar K
133665b6a74SKiran Kumar K /* If spec is NULL, both mask and last must be NULL, this
134665b6a74SKiran Kumar K * makes it to match ANY value (eq to mask = 0).
135665b6a74SKiran Kumar K * Setting either mask or last without spec is an error
136665b6a74SKiran Kumar K */
137665b6a74SKiran Kumar K if (item->spec == NULL) {
138665b6a74SKiran Kumar K if (item->last == NULL && item->mask == NULL) {
139665b6a74SKiran Kumar K info->spec = NULL;
140665b6a74SKiran Kumar K return 0;
141665b6a74SKiran Kumar K }
142665b6a74SKiran Kumar K return NPC_ERR_INVALID_SPEC;
143665b6a74SKiran Kumar K }
144665b6a74SKiran Kumar K
145665b6a74SKiran Kumar K /* We have valid spec */
146612ce5cfSSatheesh Paul if (item->type != ROC_NPC_ITEM_TYPE_RAW)
147665b6a74SKiran Kumar K info->spec = item->spec;
148665b6a74SKiran Kumar K
149665b6a74SKiran Kumar K /* If mask is not set, use default mask, err if default mask is
150665b6a74SKiran Kumar K * also NULL.
151665b6a74SKiran Kumar K */
152665b6a74SKiran Kumar K if (item->mask == NULL) {
153665b6a74SKiran Kumar K if (info->def_mask == NULL)
154665b6a74SKiran Kumar K return NPC_ERR_PARAM;
155665b6a74SKiran Kumar K info->mask = info->def_mask;
156665b6a74SKiran Kumar K } else {
157612ce5cfSSatheesh Paul if (item->type != ROC_NPC_ITEM_TYPE_RAW)
158665b6a74SKiran Kumar K info->mask = item->mask;
159665b6a74SKiran Kumar K }
160665b6a74SKiran Kumar K
161ea0d681eSGowrishankar Muthukrishnan if (info->mask == NULL)
162ea0d681eSGowrishankar Muthukrishnan return NPC_ERR_INVALID_MASK;
163ea0d681eSGowrishankar Muthukrishnan
164665b6a74SKiran Kumar K /* mask specified must be subset of hw supported mask
165665b6a74SKiran Kumar K * mask | hw_mask == hw_mask
166665b6a74SKiran Kumar K */
167665b6a74SKiran Kumar K if (!npc_mask_is_supported(info->mask, info->hw_mask, info->len))
168665b6a74SKiran Kumar K return NPC_ERR_INVALID_MASK;
169665b6a74SKiran Kumar K
170665b6a74SKiran Kumar K return 0;
171665b6a74SKiran Kumar K }
172665b6a74SKiran Kumar K
173665b6a74SKiran Kumar K static int
npc_update_extraction_data(struct npc_parse_state * pst,struct npc_parse_item_info * info,struct npc_xtract_info * xinfo)174665b6a74SKiran Kumar K npc_update_extraction_data(struct npc_parse_state *pst,
175665b6a74SKiran Kumar K struct npc_parse_item_info *info,
176665b6a74SKiran Kumar K struct npc_xtract_info *xinfo)
177665b6a74SKiran Kumar K {
178665b6a74SKiran Kumar K uint8_t int_info_mask[NPC_MAX_EXTRACT_DATA_LEN];
179665b6a74SKiran Kumar K uint8_t int_info[NPC_MAX_EXTRACT_DATA_LEN];
180665b6a74SKiran Kumar K struct npc_xtract_info *x;
181665b6a74SKiran Kumar K int hdr_off;
182665b6a74SKiran Kumar K int len = 0;
183665b6a74SKiran Kumar K
184665b6a74SKiran Kumar K x = xinfo;
1858540d7dbSAnkur Dwivedi if (x->len > NPC_MAX_EXTRACT_DATA_LEN)
1868540d7dbSAnkur Dwivedi return NPC_ERR_INVALID_SIZE;
1878540d7dbSAnkur Dwivedi
188665b6a74SKiran Kumar K len = x->len;
189665b6a74SKiran Kumar K hdr_off = x->hdr_off;
190665b6a74SKiran Kumar K
191665b6a74SKiran Kumar K if (hdr_off < info->hw_hdr_len)
192665b6a74SKiran Kumar K return 0;
193665b6a74SKiran Kumar K
194665b6a74SKiran Kumar K if (x->enable == 0)
195665b6a74SKiran Kumar K return 0;
196665b6a74SKiran Kumar K
197665b6a74SKiran Kumar K hdr_off -= info->hw_hdr_len;
198665b6a74SKiran Kumar K
199665b6a74SKiran Kumar K if (hdr_off >= info->len)
200665b6a74SKiran Kumar K return 0;
201665b6a74SKiran Kumar K
202665b6a74SKiran Kumar K if (hdr_off + len > info->len)
203665b6a74SKiran Kumar K len = info->len - hdr_off;
204665b6a74SKiran Kumar K
205665b6a74SKiran Kumar K len = npc_check_copysz((ROC_NPC_MAX_MCAM_WIDTH_DWORDS * 8) - x->key_off,
206665b6a74SKiran Kumar K len);
207665b6a74SKiran Kumar K if (len < 0)
208665b6a74SKiran Kumar K return NPC_ERR_INVALID_SIZE;
209665b6a74SKiran Kumar K
210665b6a74SKiran Kumar K /* Need to reverse complete structure so that dest addr is at
211665b6a74SKiran Kumar K * MSB so as to program the MCAM using mcam_data & mcam_mask
212665b6a74SKiran Kumar K * arrays
213665b6a74SKiran Kumar K */
214665b6a74SKiran Kumar K npc_prep_mcam_ldata(int_info, (const uint8_t *)info->spec + hdr_off,
215665b6a74SKiran Kumar K x->len);
216665b6a74SKiran Kumar K npc_prep_mcam_ldata(int_info_mask,
217665b6a74SKiran Kumar K (const uint8_t *)info->mask + hdr_off, x->len);
218665b6a74SKiran Kumar K
219665b6a74SKiran Kumar K memcpy(pst->mcam_mask + x->key_off, int_info_mask, len);
220665b6a74SKiran Kumar K memcpy(pst->mcam_data + x->key_off, int_info, len);
221665b6a74SKiran Kumar K return 0;
222665b6a74SKiran Kumar K }
223665b6a74SKiran Kumar K
224e3315630SSatheesh Paul static int
npc_field_hash_secret_get(struct npc * npc,struct npc_hash_cfg * hash_cfg)225e3315630SSatheesh Paul npc_field_hash_secret_get(struct npc *npc, struct npc_hash_cfg *hash_cfg)
226e3315630SSatheesh Paul {
227e3315630SSatheesh Paul struct npc_get_field_hash_info_req *req;
228e3315630SSatheesh Paul struct npc_get_field_hash_info_rsp *rsp;
229e3315630SSatheesh Paul struct mbox *mbox = mbox_get(npc->mbox);
230e3315630SSatheesh Paul int rc = 0;
231e3315630SSatheesh Paul
232e3315630SSatheesh Paul req = mbox_alloc_msg_npc_get_field_hash_info(mbox);
233e3315630SSatheesh Paul if (req == NULL)
234e3315630SSatheesh Paul return -ENOSPC;
235e3315630SSatheesh Paul rc = mbox_process_msg(mbox, (void *)&rsp);
236e3315630SSatheesh Paul if (rc) {
237e3315630SSatheesh Paul plt_err("Failed to fetch field hash secret key");
238e3315630SSatheesh Paul goto done;
239e3315630SSatheesh Paul }
240e3315630SSatheesh Paul
241e3315630SSatheesh Paul mbox_memcpy(hash_cfg->secret_key, rsp->secret_key, sizeof(rsp->secret_key));
242e3315630SSatheesh Paul mbox_memcpy(hash_cfg->hash_mask, rsp->hash_mask, sizeof(rsp->hash_mask));
243e3315630SSatheesh Paul mbox_memcpy(hash_cfg->hash_ctrl, rsp->hash_ctrl, sizeof(rsp->hash_ctrl));
244e3315630SSatheesh Paul
245e3315630SSatheesh Paul done:
246e3315630SSatheesh Paul mbox_put(mbox);
247e3315630SSatheesh Paul return rc;
248e3315630SSatheesh Paul }
249e3315630SSatheesh Paul
250e3315630SSatheesh Paul static inline void
be32_to_cpu_array(uint32_t * dst,const uint32_t * src,size_t len)251e3315630SSatheesh Paul be32_to_cpu_array(uint32_t *dst, const uint32_t *src, size_t len)
252e3315630SSatheesh Paul {
253e3315630SSatheesh Paul size_t i;
254e3315630SSatheesh Paul
255e3315630SSatheesh Paul for (i = 0; i < len; i++)
256e3315630SSatheesh Paul dst[i] = plt_be_to_cpu_32(src[i]);
257e3315630SSatheesh Paul }
258e3315630SSatheesh Paul
259e3315630SSatheesh Paul static uint64_t
npc_wide_extract(const uint64_t input[],size_t start_bit,size_t width_bits)260e3315630SSatheesh Paul npc_wide_extract(const uint64_t input[], size_t start_bit, size_t width_bits)
261e3315630SSatheesh Paul {
262e3315630SSatheesh Paul const uint64_t mask = ~(uint64_t)((~(__uint128_t)0) << width_bits);
263e3315630SSatheesh Paul const size_t msb = start_bit + width_bits - 1;
264e3315630SSatheesh Paul const size_t lword = start_bit >> 6;
265e3315630SSatheesh Paul const size_t uword = msb >> 6;
266e3315630SSatheesh Paul size_t lbits;
267e3315630SSatheesh Paul uint64_t hi, lo;
268e3315630SSatheesh Paul
269e3315630SSatheesh Paul if (lword == uword)
270e3315630SSatheesh Paul return (input[lword] >> (start_bit & 63)) & mask;
271e3315630SSatheesh Paul
272e3315630SSatheesh Paul lbits = 64 - (start_bit & 63);
273e3315630SSatheesh Paul hi = input[uword];
274e3315630SSatheesh Paul lo = (input[lword] >> (start_bit & 63));
275e3315630SSatheesh Paul return ((hi << lbits) | lo) & mask;
276e3315630SSatheesh Paul }
277e3315630SSatheesh Paul
278e3315630SSatheesh Paul static void
npc_lshift_key(uint64_t * key,size_t key_bit_len)279e3315630SSatheesh Paul npc_lshift_key(uint64_t *key, size_t key_bit_len)
280e3315630SSatheesh Paul {
281e3315630SSatheesh Paul uint64_t prev_orig_word = 0;
282e3315630SSatheesh Paul uint64_t cur_orig_word = 0;
283e3315630SSatheesh Paul size_t extra = key_bit_len % 64;
284e3315630SSatheesh Paul size_t max_idx = key_bit_len / 64;
285e3315630SSatheesh Paul size_t i;
286e3315630SSatheesh Paul
287e3315630SSatheesh Paul if (extra)
288e3315630SSatheesh Paul max_idx++;
289e3315630SSatheesh Paul
290e3315630SSatheesh Paul for (i = 0; i < max_idx; i++) {
291e3315630SSatheesh Paul cur_orig_word = key[i];
292e3315630SSatheesh Paul key[i] = key[i] << 1;
293e3315630SSatheesh Paul key[i] |= ((prev_orig_word >> 63) & 0x1);
294e3315630SSatheesh Paul prev_orig_word = cur_orig_word;
295e3315630SSatheesh Paul }
296e3315630SSatheesh Paul }
297e3315630SSatheesh Paul
298e3315630SSatheesh Paul static uint32_t
npc_toeplitz_hash(const uint64_t * data,uint64_t * key,size_t data_bit_len,size_t key_bit_len)299e3315630SSatheesh Paul npc_toeplitz_hash(const uint64_t *data, uint64_t *key, size_t data_bit_len, size_t key_bit_len)
300e3315630SSatheesh Paul {
301e3315630SSatheesh Paul uint32_t hash_out = 0;
302e3315630SSatheesh Paul uint64_t temp_data = 0;
303e3315630SSatheesh Paul int i;
304e3315630SSatheesh Paul
305e3315630SSatheesh Paul for (i = data_bit_len - 1; i >= 0; i--) {
306e3315630SSatheesh Paul temp_data = (data[i / 64]);
307e3315630SSatheesh Paul temp_data = temp_data >> (i % 64);
308e3315630SSatheesh Paul temp_data &= 0x1;
309e3315630SSatheesh Paul if (temp_data)
310e3315630SSatheesh Paul hash_out ^= (uint32_t)(npc_wide_extract(key, key_bit_len - 32, 32));
311e3315630SSatheesh Paul
312e3315630SSatheesh Paul npc_lshift_key(key, key_bit_len);
313e3315630SSatheesh Paul }
314e3315630SSatheesh Paul
315e3315630SSatheesh Paul return hash_out;
316e3315630SSatheesh Paul }
317e3315630SSatheesh Paul
318e3315630SSatheesh Paul static uint32_t
npc_field_hash_calc(uint64_t * ldata,struct npc_hash_cfg * hash_cfg,uint8_t intf,uint8_t hash_idx)319e3315630SSatheesh Paul npc_field_hash_calc(uint64_t *ldata, struct npc_hash_cfg *hash_cfg, uint8_t intf, uint8_t hash_idx)
320e3315630SSatheesh Paul {
321e3315630SSatheesh Paul uint64_t hash_key[3];
322e3315630SSatheesh Paul uint64_t data_padded[2];
323e3315630SSatheesh Paul uint32_t field_hash;
324e3315630SSatheesh Paul
325e3315630SSatheesh Paul hash_key[0] = hash_cfg->secret_key[1] << 31;
326e3315630SSatheesh Paul hash_key[0] |= hash_cfg->secret_key[2];
327e3315630SSatheesh Paul hash_key[1] = hash_cfg->secret_key[1] >> 33;
328e3315630SSatheesh Paul hash_key[1] |= hash_cfg->secret_key[0] << 31;
329e3315630SSatheesh Paul hash_key[2] = hash_cfg->secret_key[0] >> 33;
330e3315630SSatheesh Paul
331e3315630SSatheesh Paul data_padded[0] = hash_cfg->hash_mask[intf][hash_idx][0] & ldata[0];
332e3315630SSatheesh Paul data_padded[1] = hash_cfg->hash_mask[intf][hash_idx][1] & ldata[1];
333e3315630SSatheesh Paul field_hash = npc_toeplitz_hash(data_padded, hash_key, 128, 159);
334e3315630SSatheesh Paul
335e3315630SSatheesh Paul field_hash &= hash_cfg->hash_ctrl[intf][hash_idx] >> 32;
336e3315630SSatheesh Paul field_hash |= hash_cfg->hash_ctrl[intf][hash_idx];
337e3315630SSatheesh Paul return field_hash;
338e3315630SSatheesh Paul }
339e3315630SSatheesh Paul
340e3315630SSatheesh Paul static int
npc_ipv6_field_hash_get(struct npc * npc,const uint32_t * ip6addr,uint8_t intf,int hash_idx,uint32_t * hash)341e3315630SSatheesh Paul npc_ipv6_field_hash_get(struct npc *npc, const uint32_t *ip6addr, uint8_t intf, int hash_idx,
342e3315630SSatheesh Paul uint32_t *hash)
343e3315630SSatheesh Paul {
344e3315630SSatheesh Paul #define IPV6_WORDS 4
345e3315630SSatheesh Paul uint32_t ipv6_addr[IPV6_WORDS];
346e3315630SSatheesh Paul struct npc_hash_cfg hash_cfg;
347e3315630SSatheesh Paul uint64_t ldata[2];
348e3315630SSatheesh Paul int rc = 0;
349e3315630SSatheesh Paul
350e3315630SSatheesh Paul rc = npc_field_hash_secret_get(npc, &hash_cfg);
351e3315630SSatheesh Paul if (rc)
352e3315630SSatheesh Paul return -1;
353e3315630SSatheesh Paul
354e3315630SSatheesh Paul be32_to_cpu_array(ipv6_addr, ip6addr, IPV6_WORDS);
355e3315630SSatheesh Paul ldata[0] = (uint64_t)ipv6_addr[2] << 32 | ipv6_addr[3];
356e3315630SSatheesh Paul ldata[1] = (uint64_t)ipv6_addr[0] << 32 | ipv6_addr[1];
357e3315630SSatheesh Paul *hash = npc_field_hash_calc(ldata, &hash_cfg, intf, hash_idx);
358e3315630SSatheesh Paul
359e3315630SSatheesh Paul return 0;
360e3315630SSatheesh Paul }
361e3315630SSatheesh Paul
362e3315630SSatheesh Paul static int
npc_hash_field_get(struct npc_xtract_info * xinfo,const struct roc_npc_flow_item_ipv6 * ipv6_spec,const struct roc_npc_flow_item_ipv6 * ipv6_mask,uint8_t * hash_field)363e3315630SSatheesh Paul npc_hash_field_get(struct npc_xtract_info *xinfo, const struct roc_npc_flow_item_ipv6 *ipv6_spec,
364e3315630SSatheesh Paul const struct roc_npc_flow_item_ipv6 *ipv6_mask, uint8_t *hash_field)
365e3315630SSatheesh Paul {
366e3315630SSatheesh Paul const uint8_t *ipv6_hdr_spec, *ipv6_hdr_mask;
367e3315630SSatheesh Paul struct roc_ipv6_hdr ipv6_buf;
368e3315630SSatheesh Paul int offset = xinfo->hdr_off;
369e3315630SSatheesh Paul
370e3315630SSatheesh Paul memset(&ipv6_buf, 0, sizeof(ipv6_buf));
371e3315630SSatheesh Paul
372e3315630SSatheesh Paul ipv6_hdr_spec = (const uint8_t *)&ipv6_spec->hdr;
373e3315630SSatheesh Paul ipv6_hdr_mask = (const uint8_t *)&ipv6_mask->hdr;
374e3315630SSatheesh Paul
375e3315630SSatheesh Paul /* Check if mask is set for the field to be hashed */
376e3315630SSatheesh Paul if (memcmp(ipv6_hdr_mask + offset, &ipv6_buf, ROC_IPV6_ADDR_LEN) == 0)
377e3315630SSatheesh Paul return 0;
378e3315630SSatheesh Paul
379e3315630SSatheesh Paul /* Extract the field to be hashed from item spec */
380e3315630SSatheesh Paul memcpy(hash_field, ipv6_hdr_spec + offset, ROC_IPV6_ADDR_LEN);
381e3315630SSatheesh Paul return 1;
382e3315630SSatheesh Paul }
383e3315630SSatheesh Paul
384665b6a74SKiran Kumar K int
npc_process_ipv6_field_hash(const struct roc_npc_flow_item_ipv6 * ipv6_spec,const struct roc_npc_flow_item_ipv6 * ipv6_mask,struct npc_parse_state * pst,uint8_t ltype)385e3315630SSatheesh Paul npc_process_ipv6_field_hash(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
386e3315630SSatheesh Paul const struct roc_npc_flow_item_ipv6 *ipv6_mask,
387*0a6a4437SSatheesh Paul struct npc_parse_state *pst, uint8_t ltype)
388e3315630SSatheesh Paul {
389e3315630SSatheesh Paul struct npc_lid_lt_xtract_info *lid_lt_xinfo;
390e3315630SSatheesh Paul uint8_t hash_field[ROC_IPV6_ADDR_LEN];
391e3315630SSatheesh Paul struct npc_xtract_info *xinfo;
392e3315630SSatheesh Paul struct roc_ipv6_hdr ipv6_buf;
393e3315630SSatheesh Paul uint32_t hash = 0, mask;
394e3315630SSatheesh Paul int intf, i, rc = 0;
395e3315630SSatheesh Paul
396e3315630SSatheesh Paul memset(&ipv6_buf, 0, sizeof(ipv6_buf));
397e3315630SSatheesh Paul memset(hash_field, 0, sizeof(hash_field));
398e3315630SSatheesh Paul
399e3315630SSatheesh Paul intf = pst->nix_intf;
400*0a6a4437SSatheesh Paul lid_lt_xinfo = &pst->npc->prx_dxcfg[intf][NPC_LID_LC][ltype];
401e3315630SSatheesh Paul
402e3315630SSatheesh Paul for (i = 0; i < NPC_MAX_LD; i++) {
403e3315630SSatheesh Paul xinfo = &lid_lt_xinfo->xtract[i];
404e3315630SSatheesh Paul if (!xinfo->use_hash)
405e3315630SSatheesh Paul continue;
406e3315630SSatheesh Paul
407e3315630SSatheesh Paul rc = npc_hash_field_get(xinfo, ipv6_spec, ipv6_mask, hash_field);
408e3315630SSatheesh Paul if (rc == 0)
409e3315630SSatheesh Paul continue;
410e3315630SSatheesh Paul
411e3315630SSatheesh Paul rc = npc_ipv6_field_hash_get(pst->npc, (const uint32_t *)hash_field, intf, i,
412e3315630SSatheesh Paul &hash);
413e3315630SSatheesh Paul if (rc)
414e3315630SSatheesh Paul return rc;
415e3315630SSatheesh Paul
416e3315630SSatheesh Paul mask = GENMASK(31, 0);
417e3315630SSatheesh Paul memcpy(pst->mcam_mask + xinfo->key_off, (uint8_t *)&mask, 4);
418e3315630SSatheesh Paul memcpy(pst->mcam_data + xinfo->key_off, (uint8_t *)&hash, 4);
419e3315630SSatheesh Paul }
420e3315630SSatheesh Paul
421e3315630SSatheesh Paul return 0;
422e3315630SSatheesh Paul }
423e3315630SSatheesh Paul
424e3315630SSatheesh Paul int
npc_update_parse_state(struct npc_parse_state * pst,struct npc_parse_item_info * info,int lid,int lt,uint8_t flags)425e3315630SSatheesh Paul npc_update_parse_state(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
426e3315630SSatheesh Paul int lt, uint8_t flags)
427665b6a74SKiran Kumar K {
428665b6a74SKiran Kumar K struct npc_lid_lt_xtract_info *xinfo;
4299869c399SSatheesh Paul struct roc_npc_flow_dump_data *dump;
430665b6a74SKiran Kumar K struct npc_xtract_info *lfinfo;
431665b6a74SKiran Kumar K int intf, lf_cfg;
432665b6a74SKiran Kumar K int i, j, rc = 0;
433665b6a74SKiran Kumar K
434665b6a74SKiran Kumar K pst->layer_mask |= lid;
435665b6a74SKiran Kumar K pst->lt[lid] = lt;
436665b6a74SKiran Kumar K pst->flags[lid] = flags;
437665b6a74SKiran Kumar K
438665b6a74SKiran Kumar K intf = pst->nix_intf;
439665b6a74SKiran Kumar K xinfo = &pst->npc->prx_dxcfg[intf][lid][lt];
440665b6a74SKiran Kumar K if (xinfo->is_terminating)
441665b6a74SKiran Kumar K pst->terminate = 1;
442665b6a74SKiran Kumar K
443665b6a74SKiran Kumar K if (info->spec == NULL)
444665b6a74SKiran Kumar K goto done;
445665b6a74SKiran Kumar K
446665b6a74SKiran Kumar K for (i = 0; i < NPC_MAX_LD; i++) {
447e3315630SSatheesh Paul if (xinfo->xtract[i].use_hash)
448e3315630SSatheesh Paul continue;
449665b6a74SKiran Kumar K rc = npc_update_extraction_data(pst, info, &xinfo->xtract[i]);
450665b6a74SKiran Kumar K if (rc != 0)
451665b6a74SKiran Kumar K return rc;
452665b6a74SKiran Kumar K }
453665b6a74SKiran Kumar K
454665b6a74SKiran Kumar K for (i = 0; i < NPC_MAX_LD; i++) {
455665b6a74SKiran Kumar K if (xinfo->xtract[i].flags_enable == 0)
456665b6a74SKiran Kumar K continue;
457e3315630SSatheesh Paul if (xinfo->xtract[i].use_hash)
458e3315630SSatheesh Paul continue;
459665b6a74SKiran Kumar K
460665b6a74SKiran Kumar K lf_cfg = pst->npc->prx_lfcfg[i].i;
461665b6a74SKiran Kumar K if (lf_cfg == lid) {
462665b6a74SKiran Kumar K for (j = 0; j < NPC_MAX_LFL; j++) {
463665b6a74SKiran Kumar K lfinfo = pst->npc->prx_fxcfg[intf][i][j].xtract;
464665b6a74SKiran Kumar K rc = npc_update_extraction_data(pst, info,
465665b6a74SKiran Kumar K &lfinfo[0]);
466665b6a74SKiran Kumar K if (rc != 0)
467665b6a74SKiran Kumar K return rc;
468665b6a74SKiran Kumar K
469665b6a74SKiran Kumar K if (lfinfo[0].enable)
470665b6a74SKiran Kumar K pst->flags[lid] = j;
471665b6a74SKiran Kumar K }
472665b6a74SKiran Kumar K }
473665b6a74SKiran Kumar K }
474665b6a74SKiran Kumar K
475665b6a74SKiran Kumar K done:
4769869c399SSatheesh Paul dump = &pst->flow->dump_data[pst->flow->num_patterns++];
4779869c399SSatheesh Paul dump->lid = lid;
4789869c399SSatheesh Paul dump->ltype = lt;
479665b6a74SKiran Kumar K pst->pattern++;
480665b6a74SKiran Kumar K return 0;
481665b6a74SKiran Kumar K }
482665b6a74SKiran Kumar K
48322d9d348SSatheesh Paul int
npc_mcam_init(struct npc * npc,struct roc_npc_flow * flow,int mcam_id)48422d9d348SSatheesh Paul npc_mcam_init(struct npc *npc, struct roc_npc_flow *flow, int mcam_id)
485665b6a74SKiran Kumar K {
4861f669198SSatheesh Paul struct npc_mcam_write_entry_req *req;
4871f669198SSatheesh Paul struct npc_mcam_write_entry_rsq *rsp;
48844a9307cSRakesh Kudurumalla struct mbox *mbox = mbox_get(npc->mbox);
4891f669198SSatheesh Paul int rc = 0, idx;
490665b6a74SKiran Kumar K
49144a9307cSRakesh Kudurumalla req = mbox_alloc_msg_npc_mcam_write_entry(mbox);
49244a9307cSRakesh Kudurumalla if (req == NULL) {
49344a9307cSRakesh Kudurumalla rc = -ENOSPC;
49444a9307cSRakesh Kudurumalla goto exit;
49544a9307cSRakesh Kudurumalla }
4961f669198SSatheesh Paul req->set_cntr = 0;
4971f669198SSatheesh Paul req->cntr = 0;
4981f669198SSatheesh Paul req->entry = mcam_id;
499665b6a74SKiran Kumar K
5001f669198SSatheesh Paul req->intf = (flow->nix_intf == NIX_INTF_RX) ? NPC_MCAM_RX : NPC_MCAM_TX;
5011f669198SSatheesh Paul req->enable_entry = 1;
5021f669198SSatheesh Paul req->entry_data.action = flow->npc_action;
5031f669198SSatheesh Paul req->entry_data.vtag_action = flow->vtag_action;
5041f669198SSatheesh Paul
5051f669198SSatheesh Paul for (idx = 0; idx < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; idx++) {
5061f669198SSatheesh Paul req->entry_data.kw[idx] = 0x0;
5071f669198SSatheesh Paul req->entry_data.kw_mask[idx] = 0x0;
5081f669198SSatheesh Paul }
5091f669198SSatheesh Paul
5101f669198SSatheesh Paul if (flow->nix_intf == NIX_INTF_RX) {
5111f669198SSatheesh Paul req->entry_data.kw[0] |= (uint64_t)npc->channel;
5121f669198SSatheesh Paul req->entry_data.kw_mask[0] |= (BIT_ULL(12) - 1);
5131f669198SSatheesh Paul } else {
5141f669198SSatheesh Paul uint16_t pf_func = (flow->npc_action >> 4) & 0xffff;
5151f669198SSatheesh Paul
5161f669198SSatheesh Paul pf_func = plt_cpu_to_be_16(pf_func);
5171f669198SSatheesh Paul req->entry_data.kw[0] |= ((uint64_t)pf_func << 32);
5181f669198SSatheesh Paul req->entry_data.kw_mask[0] |= ((uint64_t)0xffff << 32);
5191f669198SSatheesh Paul }
5201f669198SSatheesh Paul
52144a9307cSRakesh Kudurumalla rc = mbox_process_msg(mbox, (void *)&rsp);
5221f669198SSatheesh Paul if (rc != 0) {
5231f669198SSatheesh Paul plt_err("npc: mcam initialisation write failed");
52444a9307cSRakesh Kudurumalla goto exit;
5251f669198SSatheesh Paul }
52644a9307cSRakesh Kudurumalla rc = 0;
52744a9307cSRakesh Kudurumalla exit:
52844a9307cSRakesh Kudurumalla mbox_put(mbox);
52944a9307cSRakesh Kudurumalla return rc;
530665b6a74SKiran Kumar K }
531665b6a74SKiran Kumar K
53222d9d348SSatheesh Paul int
npc_mcam_move(struct mbox * mbox,uint16_t old_ent,uint16_t new_ent)53322d9d348SSatheesh Paul npc_mcam_move(struct mbox *mbox, uint16_t old_ent, uint16_t new_ent)
534665b6a74SKiran Kumar K {
535665b6a74SKiran Kumar K struct npc_mcam_shift_entry_req *req;
536665b6a74SKiran Kumar K struct npc_mcam_shift_entry_rsp *rsp;
537665b6a74SKiran Kumar K int rc = -ENOSPC;
538665b6a74SKiran Kumar K
539665b6a74SKiran Kumar K /* Old entry is disabled & it's contents are moved to new_entry,
540665b6a74SKiran Kumar K * new entry is enabled finally.
541665b6a74SKiran Kumar K */
54244a9307cSRakesh Kudurumalla req = mbox_alloc_msg_npc_mcam_shift_entry(mbox_get(mbox));
543665b6a74SKiran Kumar K if (req == NULL)
54444a9307cSRakesh Kudurumalla goto exit;
545665b6a74SKiran Kumar K req->curr_entry[0] = old_ent;
546665b6a74SKiran Kumar K req->new_entry[0] = new_ent;
547665b6a74SKiran Kumar K req->shift_count = 1;
548665b6a74SKiran Kumar K
549665b6a74SKiran Kumar K rc = mbox_process_msg(mbox, (void *)&rsp);
550665b6a74SKiran Kumar K if (rc)
55144a9307cSRakesh Kudurumalla goto exit;
552665b6a74SKiran Kumar K
55344a9307cSRakesh Kudurumalla rc = 0;
55444a9307cSRakesh Kudurumalla exit:
55544a9307cSRakesh Kudurumalla mbox_put(mbox);
55644a9307cSRakesh Kudurumalla return rc;
557665b6a74SKiran Kumar K }
558665b6a74SKiran Kumar K
5591f669198SSatheesh Paul enum SHIFT_DIR {
5601f669198SSatheesh Paul SLIDE_ENTRIES_TO_LOWER_INDEX,
5611f669198SSatheesh Paul SLIDE_ENTRIES_TO_HIGHER_INDEX,
5621f669198SSatheesh Paul };
5631f669198SSatheesh Paul
564665b6a74SKiran Kumar K static int
npc_slide_mcam_entries(struct mbox * mbox,struct npc * npc,int prio,uint16_t * free_mcam_id,int dir)5651f669198SSatheesh Paul npc_slide_mcam_entries(struct mbox *mbox, struct npc *npc, int prio,
5661f669198SSatheesh Paul uint16_t *free_mcam_id, int dir)
567665b6a74SKiran Kumar K {
5681f669198SSatheesh Paul uint16_t to_mcam_id = 0, from_mcam_id = 0;
5691f669198SSatheesh Paul struct npc_prio_flow_list_head *list;
5701f669198SSatheesh Paul struct npc_prio_flow_entry *curr = 0;
5711f669198SSatheesh Paul int rc = 0;
5721f669198SSatheesh Paul
5731f669198SSatheesh Paul list = &npc->prio_flow_list[prio];
5741f669198SSatheesh Paul
5751f669198SSatheesh Paul to_mcam_id = *free_mcam_id;
5761f669198SSatheesh Paul if (dir == SLIDE_ENTRIES_TO_HIGHER_INDEX)
5771f669198SSatheesh Paul curr = TAILQ_LAST(list, npc_prio_flow_list_head);
5781f669198SSatheesh Paul else if (dir == SLIDE_ENTRIES_TO_LOWER_INDEX)
5791f669198SSatheesh Paul curr = TAILQ_FIRST(list);
5801f669198SSatheesh Paul
5811f669198SSatheesh Paul while (curr) {
5821f669198SSatheesh Paul from_mcam_id = curr->flow->mcam_id;
5831f669198SSatheesh Paul if ((dir == SLIDE_ENTRIES_TO_HIGHER_INDEX &&
5841f669198SSatheesh Paul from_mcam_id < to_mcam_id) ||
5851f669198SSatheesh Paul (dir == SLIDE_ENTRIES_TO_LOWER_INDEX &&
5861f669198SSatheesh Paul from_mcam_id > to_mcam_id)) {
5871f669198SSatheesh Paul /* Newly allocated entry and the source entry given to
5881f669198SSatheesh Paul * npc_mcam_shift_entry_req will be in disabled state.
5891f669198SSatheesh Paul * Initialise and enable before moving an entry into
5901f669198SSatheesh Paul * this mcam.
5911f669198SSatheesh Paul */
59222d9d348SSatheesh Paul rc = npc_mcam_init(npc, curr->flow, to_mcam_id);
5931f669198SSatheesh Paul if (rc)
5941f669198SSatheesh Paul return rc;
59522d9d348SSatheesh Paul rc = npc_mcam_move(mbox, from_mcam_id, to_mcam_id);
5961f669198SSatheesh Paul if (rc)
5971f669198SSatheesh Paul return rc;
5981f669198SSatheesh Paul curr->flow->mcam_id = to_mcam_id;
5991f669198SSatheesh Paul to_mcam_id = from_mcam_id;
6001f669198SSatheesh Paul }
6011f669198SSatheesh Paul
6021f669198SSatheesh Paul if (dir == SLIDE_ENTRIES_TO_HIGHER_INDEX)
6031f669198SSatheesh Paul curr = TAILQ_PREV(curr, npc_prio_flow_list_head, next);
6041f669198SSatheesh Paul else if (dir == SLIDE_ENTRIES_TO_LOWER_INDEX)
6051f669198SSatheesh Paul curr = TAILQ_NEXT(curr, next);
6061f669198SSatheesh Paul }
6071f669198SSatheesh Paul
6081f669198SSatheesh Paul *free_mcam_id = from_mcam_id;
6091f669198SSatheesh Paul
6101f669198SSatheesh Paul return 0;
6111f669198SSatheesh Paul }
6121f669198SSatheesh Paul
6131f669198SSatheesh Paul /*
6141f669198SSatheesh Paul * The mcam_alloc request is first made with NPC_MCAM_LOWER_PRIO with the last
6151f669198SSatheesh Paul * entry in the requested priority level as the reference entry. If it fails,
6161f669198SSatheesh Paul * the alloc request is retried with NPC_MCAM_HIGHER_PRIO with the first entry
6171f669198SSatheesh Paul * in the next lower priority level as the reference entry. After obtaining
6181f669198SSatheesh Paul * the free MCAM from kernel, we check if it is at the right user requested
6191f669198SSatheesh Paul * priority level. If not, the flow rules are moved across MCAM entries till
6201f669198SSatheesh Paul * the user requested priority levels are met.
6211f669198SSatheesh Paul * The MCAM sorting algorithm works as below.
6221f669198SSatheesh Paul * For any given free MCAM obtained from the kernel, there are 3 possibilities.
6231f669198SSatheesh Paul * Case 1:
6241f669198SSatheesh Paul * There are entries belonging to higher user priority level (numerically
6251f669198SSatheesh Paul * lesser) in higher mcam indices. In this case, the entries with higher user
6261f669198SSatheesh Paul * priority are slided towards lower indices and a free entry is created in the
6271f669198SSatheesh Paul * higher indices.
6281f669198SSatheesh Paul * Example:
6291f669198SSatheesh Paul * Assume free entry = 1610, user requested priority = 2 and
6301f669198SSatheesh Paul * max user priority levels = 5 with below entries in respective priority
6311f669198SSatheesh Paul * levels.
6321f669198SSatheesh Paul * 0: 1630, 1635, 1641
6331f669198SSatheesh Paul * 1: 1646, 1650, 1651
6341f669198SSatheesh Paul * 2: 1652, 1655, 1660
6351f669198SSatheesh Paul * 3: 1661, 1662, 1663, 1664
6361f669198SSatheesh Paul * 4: 1665, 1667, 1670
6371f669198SSatheesh Paul *
6381f669198SSatheesh Paul * Entries (1630, 1635, 1641, 1646, 1650, 1651) have to be slided down towards
6391f669198SSatheesh Paul * lower indices.
6401f669198SSatheesh Paul * Shifting sequence will be as below:
6411f669198SSatheesh Paul * 1610 <- 1630 <- 1635 <- 1641 <- 1646 <- 1650 <- 1651
6421f669198SSatheesh Paul * Entry 1651 will be free-ed for writing the new flow. This entry will now
6431f669198SSatheesh Paul * become the head of priority level 2.
6441f669198SSatheesh Paul *
6451f669198SSatheesh Paul * Case 2:
6461f669198SSatheesh Paul * There are entries belonging to lower user priority level (numerically
6471f669198SSatheesh Paul * bigger) in lower mcam indices. In this case, the entries with lower user
6481f669198SSatheesh Paul * priority are slided towards higher indices and a free entry is created in the
6491f669198SSatheesh Paul * lower indices.
6501f669198SSatheesh Paul *
6511f669198SSatheesh Paul * Example:
6521f669198SSatheesh Paul * free entry = 1653, user requested priority = 0
6531f669198SSatheesh Paul * 0: 1630, 1635, 1641
6541f669198SSatheesh Paul * 1: 1646, 1650, 1651
6551f669198SSatheesh Paul * 2: 1652, 1655, 1660
6561f669198SSatheesh Paul * 3: 1661, 1662, 1663, 1664
6571f669198SSatheesh Paul * 4: 1665, 1667, 1670
6581f669198SSatheesh Paul *
6591f669198SSatheesh Paul * Entries (1646, 1650, 1651, 1652) have to be slided up towards higher
6601f669198SSatheesh Paul * indices.
6611f669198SSatheesh Paul * Shifting sequence will be as below:
6621f669198SSatheesh Paul * 1646 -> 1650 -> 1651 -> 1652 -> 1653
6631f669198SSatheesh Paul * Entry 1646 will be free-ed for writing the new flow. This entry will now
6641f669198SSatheesh Paul * become the last element in priority level 0.
6651f669198SSatheesh Paul *
6661f669198SSatheesh Paul * Case 3:
6671f669198SSatheesh Paul * Free mcam is at the right place, ie, all higher user priority level
6681f669198SSatheesh Paul * mcams lie in lower indices and all lower user priority level mcams lie in
6691f669198SSatheesh Paul * higher mcam indices.
6701f669198SSatheesh Paul *
6711f669198SSatheesh Paul * The priority level lists are scanned first for case (1) and if the
6721f669198SSatheesh Paul * condition is found true, case(2) is skipped because they are mutually
6731f669198SSatheesh Paul * exclusive. For example, consider below state.
6741f669198SSatheesh Paul * 0: 1630, 1635, 1641
6751f669198SSatheesh Paul * 1: 1646, 1650, 1651
6761f669198SSatheesh Paul * 2: 1652, 1655, 1660
6771f669198SSatheesh Paul * 3: 1661, 1662, 1663, 1664
6781f669198SSatheesh Paul * 4: 1665, 1667, 1670
6791f669198SSatheesh Paul * free entry = 1610, user requested priority = 2
6801f669198SSatheesh Paul *
6811f669198SSatheesh Paul * Case 1: Here the condition is;
6821f669198SSatheesh Paul * "if (requested_prio > prio_idx && free_mcam < tail->flow->mcam_id ){}"
6831f669198SSatheesh Paul * If this condition is true, it means at some higher priority level than
6841f669198SSatheesh Paul * requested priority level, there are entries at lower indices than the given
6851f669198SSatheesh Paul * free mcam. That is, we have found in levels 0,1 there is an mcam X which is
6861f669198SSatheesh Paul * greater than 1610.
6871f669198SSatheesh Paul * If, for any free entry and user req prio, the above condition is true, then
6881f669198SSatheesh Paul * the below case(2) condition will always be false since the lists are kept
6891f669198SSatheesh Paul * sorted. The case(2) condition is;
6901f669198SSatheesh Paul * "if (requested_prio < prio_idx && free_mcam > head->flow->mcam_id){}"
6911f669198SSatheesh Paul * There can't be entries at lower indices at priority level higher
6921f669198SSatheesh Paul * than the requested priority level. That is, here, at levels 3 & 4 there
6931f669198SSatheesh Paul * cannot be any entry greater than 1610. Because all entries in 3 & 4 must be
6941f669198SSatheesh Paul * greater than X which was found to be greater than 1610 earlier.
6951f669198SSatheesh Paul */
6961f669198SSatheesh Paul
6971f669198SSatheesh Paul static int
npc_sort_mcams_by_user_prio_level(struct mbox * mbox,struct npc_prio_flow_entry * flow_list_entry,struct npc * npc,struct npc_mcam_alloc_entry_rsp * rsp)6981f669198SSatheesh Paul npc_sort_mcams_by_user_prio_level(struct mbox *mbox,
6991f669198SSatheesh Paul struct npc_prio_flow_entry *flow_list_entry,
7001f669198SSatheesh Paul struct npc *npc,
7011f669198SSatheesh Paul struct npc_mcam_alloc_entry_rsp *rsp)
7021f669198SSatheesh Paul {
7031f669198SSatheesh Paul int requested_prio = flow_list_entry->flow->priority;
7041f669198SSatheesh Paul struct npc_prio_flow_entry *head, *tail;
7051f669198SSatheesh Paul struct npc_prio_flow_list_head *list;
7061f669198SSatheesh Paul uint16_t free_mcam = rsp->entry;
7071f669198SSatheesh Paul bool do_reverse_scan = true;
7081f669198SSatheesh Paul int prio_idx = 0, rc = 0;
7091f669198SSatheesh Paul
7101f669198SSatheesh Paul while (prio_idx <= npc->flow_max_priority - 1) {
7111f669198SSatheesh Paul list = &npc->prio_flow_list[prio_idx];
7121f669198SSatheesh Paul tail = TAILQ_LAST(list, npc_prio_flow_list_head);
7131f669198SSatheesh Paul
7141f669198SSatheesh Paul /* requested priority is lower than current level
7151f669198SSatheesh Paul * ie, numerically req prio is higher
7161f669198SSatheesh Paul */
7171f669198SSatheesh Paul if ((requested_prio > prio_idx) && tail) {
7181f669198SSatheesh Paul /* but there are some mcams in current level
7191f669198SSatheesh Paul * at higher indices, ie, at priority lower
7201f669198SSatheesh Paul * than free_mcam.
7211f669198SSatheesh Paul */
7221f669198SSatheesh Paul if (free_mcam < tail->flow->mcam_id) {
7231f669198SSatheesh Paul rc = npc_slide_mcam_entries(
7241f669198SSatheesh Paul mbox, npc, prio_idx, &free_mcam,
7251f669198SSatheesh Paul SLIDE_ENTRIES_TO_LOWER_INDEX);
7261f669198SSatheesh Paul if (rc)
7271f669198SSatheesh Paul return rc;
7281f669198SSatheesh Paul do_reverse_scan = false;
7291f669198SSatheesh Paul }
7301f669198SSatheesh Paul }
7311f669198SSatheesh Paul prio_idx++;
7321f669198SSatheesh Paul }
7331f669198SSatheesh Paul
7341f669198SSatheesh Paul prio_idx = npc->flow_max_priority - 1;
7351f669198SSatheesh Paul while (prio_idx && do_reverse_scan) {
7361f669198SSatheesh Paul list = &npc->prio_flow_list[prio_idx];
7371f669198SSatheesh Paul head = TAILQ_FIRST(list);
7381f669198SSatheesh Paul
7391f669198SSatheesh Paul /* requested priority is higher than current level
7401f669198SSatheesh Paul * ie, numerically req prio is lower
7411f669198SSatheesh Paul */
7421f669198SSatheesh Paul if (requested_prio < prio_idx && head) {
7431f669198SSatheesh Paul /* but free mcam is higher than lowest priority
7441f669198SSatheesh Paul * mcam in current level
7451f669198SSatheesh Paul */
7461f669198SSatheesh Paul if (free_mcam > head->flow->mcam_id) {
7471f669198SSatheesh Paul rc = npc_slide_mcam_entries(
7481f669198SSatheesh Paul mbox, npc, prio_idx, &free_mcam,
7491f669198SSatheesh Paul SLIDE_ENTRIES_TO_HIGHER_INDEX);
7501f669198SSatheesh Paul if (rc)
7511f669198SSatheesh Paul return rc;
7521f669198SSatheesh Paul }
7531f669198SSatheesh Paul }
7541f669198SSatheesh Paul prio_idx--;
7551f669198SSatheesh Paul }
7561f669198SSatheesh Paul rsp->entry = free_mcam;
7571f669198SSatheesh Paul return rc;
7581f669198SSatheesh Paul }
7591f669198SSatheesh Paul
7601f669198SSatheesh Paul static void
npc_insert_into_flow_list(struct npc * npc,struct npc_prio_flow_entry * entry)7611f669198SSatheesh Paul npc_insert_into_flow_list(struct npc *npc, struct npc_prio_flow_entry *entry)
7621f669198SSatheesh Paul {
7631f669198SSatheesh Paul struct npc_prio_flow_list_head *list;
7641f669198SSatheesh Paul struct npc_prio_flow_entry *curr;
7651f669198SSatheesh Paul
7661f669198SSatheesh Paul list = &npc->prio_flow_list[entry->flow->priority];
7671f669198SSatheesh Paul curr = TAILQ_FIRST(list);
7681f669198SSatheesh Paul
7691f669198SSatheesh Paul if (curr) {
7701f669198SSatheesh Paul while (curr) {
7711f669198SSatheesh Paul if (entry->flow->mcam_id > curr->flow->mcam_id)
7721f669198SSatheesh Paul curr = TAILQ_NEXT(curr, next);
7731f669198SSatheesh Paul else
7741f669198SSatheesh Paul break;
7751f669198SSatheesh Paul }
7761f669198SSatheesh Paul if (curr)
7771f669198SSatheesh Paul TAILQ_INSERT_BEFORE(curr, entry, next);
7781f669198SSatheesh Paul else
7791f669198SSatheesh Paul TAILQ_INSERT_TAIL(list, entry, next);
7801f669198SSatheesh Paul } else {
7811f669198SSatheesh Paul TAILQ_INSERT_HEAD(list, entry, next);
7821f669198SSatheesh Paul }
7831f669198SSatheesh Paul }
7841f669198SSatheesh Paul
7851f669198SSatheesh Paul static int
npc_allocate_mcam_entry(struct mbox * mbox,int prio,struct npc_mcam_alloc_entry_rsp * rsp_local,int ref_entry)7861f669198SSatheesh Paul npc_allocate_mcam_entry(struct mbox *mbox, int prio,
7871f669198SSatheesh Paul struct npc_mcam_alloc_entry_rsp *rsp_local,
7881f669198SSatheesh Paul int ref_entry)
7891f669198SSatheesh Paul {
790665b6a74SKiran Kumar K struct npc_mcam_alloc_entry_rsp *rsp_cmd;
791665b6a74SKiran Kumar K struct npc_mcam_alloc_entry_req *req;
792665b6a74SKiran Kumar K struct npc_mcam_alloc_entry_rsp *rsp;
7931f669198SSatheesh Paul int rc = -ENOSPC;
794665b6a74SKiran Kumar K
79544a9307cSRakesh Kudurumalla req = mbox_alloc_msg_npc_mcam_alloc_entry(mbox_get(mbox));
796665b6a74SKiran Kumar K if (req == NULL)
79744a9307cSRakesh Kudurumalla goto exit;
798665b6a74SKiran Kumar K req->contig = 1;
7991f669198SSatheesh Paul req->count = 1;
800665b6a74SKiran Kumar K req->priority = prio;
8011f669198SSatheesh Paul req->ref_entry = ref_entry;
802665b6a74SKiran Kumar K
803665b6a74SKiran Kumar K rc = mbox_process_msg(mbox, (void *)&rsp_cmd);
804665b6a74SKiran Kumar K if (rc)
80544a9307cSRakesh Kudurumalla goto exit;
806665b6a74SKiran Kumar K
80744a9307cSRakesh Kudurumalla if (!rsp_cmd->count) {
80844a9307cSRakesh Kudurumalla rc = -ENOSPC;
80944a9307cSRakesh Kudurumalla goto exit;
81044a9307cSRakesh Kudurumalla }
811665b6a74SKiran Kumar K
8126a65e22aSSatheesh Paul mbox_memcpy(rsp_local, rsp_cmd, sizeof(*rsp));
8131f669198SSatheesh Paul
81444a9307cSRakesh Kudurumalla rc = 0;
81544a9307cSRakesh Kudurumalla exit:
81644a9307cSRakesh Kudurumalla mbox_put(mbox);
81744a9307cSRakesh Kudurumalla return rc;
818665b6a74SKiran Kumar K }
819665b6a74SKiran Kumar K
8201f669198SSatheesh Paul static void
npc_find_mcam_ref_entry(struct roc_npc_flow * flow,struct npc * npc,int * prio,int * ref_entry,int dir)8211f669198SSatheesh Paul npc_find_mcam_ref_entry(struct roc_npc_flow *flow, struct npc *npc, int *prio,
8221f669198SSatheesh Paul int *ref_entry, int dir)
8231f669198SSatheesh Paul {
8241f669198SSatheesh Paul struct npc_prio_flow_entry *head, *tail;
8251f669198SSatheesh Paul struct npc_prio_flow_list_head *list;
8261f669198SSatheesh Paul int prio_idx = flow->priority;
827665b6a74SKiran Kumar K
8281f669198SSatheesh Paul if (dir == NPC_MCAM_LOWER_PRIO) {
8291f669198SSatheesh Paul while (prio_idx >= 0) {
8301f669198SSatheesh Paul list = &npc->prio_flow_list[prio_idx];
8311f669198SSatheesh Paul head = TAILQ_FIRST(list);
8321f669198SSatheesh Paul if (head) {
8331f669198SSatheesh Paul *prio = NPC_MCAM_LOWER_PRIO;
8341f669198SSatheesh Paul *ref_entry = head->flow->mcam_id;
8351f669198SSatheesh Paul return;
836665b6a74SKiran Kumar K }
8371f669198SSatheesh Paul prio_idx--;
8381f669198SSatheesh Paul }
8391f669198SSatheesh Paul } else if (dir == NPC_MCAM_HIGHER_PRIO) {
8401f669198SSatheesh Paul prio_idx = flow->priority;
8411f669198SSatheesh Paul while (prio_idx <= npc->flow_max_priority - 1) {
8421f669198SSatheesh Paul list = &npc->prio_flow_list[prio_idx];
8431f669198SSatheesh Paul tail = TAILQ_LAST(list, npc_prio_flow_list_head);
8441f669198SSatheesh Paul if (tail) {
8451f669198SSatheesh Paul *prio = NPC_MCAM_HIGHER_PRIO;
8461f669198SSatheesh Paul *ref_entry = tail->flow->mcam_id;
8471f669198SSatheesh Paul return;
8481f669198SSatheesh Paul }
8491f669198SSatheesh Paul prio_idx++;
850665b6a74SKiran Kumar K }
851665b6a74SKiran Kumar K }
8521f669198SSatheesh Paul *prio = NPC_MCAM_ANY_PRIO;
8531f669198SSatheesh Paul *ref_entry = 0;
854665b6a74SKiran Kumar K }
855665b6a74SKiran Kumar K
8561f669198SSatheesh Paul static int
npc_alloc_mcam_by_ref_entry(struct mbox * mbox,struct roc_npc_flow * flow,struct npc * npc,struct npc_mcam_alloc_entry_rsp * rsp_local)8571f669198SSatheesh Paul npc_alloc_mcam_by_ref_entry(struct mbox *mbox, struct roc_npc_flow *flow,
8581f669198SSatheesh Paul struct npc *npc,
8591f669198SSatheesh Paul struct npc_mcam_alloc_entry_rsp *rsp_local)
8601f669198SSatheesh Paul {
8611f669198SSatheesh Paul int prio, ref_entry = 0, rc = 0, dir = NPC_MCAM_LOWER_PRIO;
8621f669198SSatheesh Paul bool retry_done = false;
8631f669198SSatheesh Paul
8641f669198SSatheesh Paul retry:
8651f669198SSatheesh Paul npc_find_mcam_ref_entry(flow, npc, &prio, &ref_entry, dir);
8661f669198SSatheesh Paul rc = npc_allocate_mcam_entry(mbox, prio, rsp_local, ref_entry);
8671f669198SSatheesh Paul if (rc && !retry_done) {
8680c585f88SSatheesh Paul plt_npc_dbg(
8691f669198SSatheesh Paul "npc: Failed to allocate lower priority entry. Retrying for higher priority");
8701f669198SSatheesh Paul
8711f669198SSatheesh Paul dir = NPC_MCAM_HIGHER_PRIO;
8721f669198SSatheesh Paul retry_done = true;
8731f669198SSatheesh Paul goto retry;
8741f669198SSatheesh Paul } else if (rc && retry_done) {
8751f669198SSatheesh Paul return rc;
8761f669198SSatheesh Paul }
877665b6a74SKiran Kumar K
878665b6a74SKiran Kumar K return 0;
879665b6a74SKiran Kumar K }
880665b6a74SKiran Kumar K
881665b6a74SKiran Kumar K int
npc_get_free_mcam_entry(struct mbox * mbox,struct roc_npc_flow * flow,struct npc * npc)8821f669198SSatheesh Paul npc_get_free_mcam_entry(struct mbox *mbox, struct roc_npc_flow *flow,
883665b6a74SKiran Kumar K struct npc *npc)
884665b6a74SKiran Kumar K {
8851f669198SSatheesh Paul struct npc_mcam_alloc_entry_rsp rsp_local;
8861f669198SSatheesh Paul struct npc_prio_flow_entry *new_entry;
8871f669198SSatheesh Paul int rc = 0;
888665b6a74SKiran Kumar K
8891f669198SSatheesh Paul rc = npc_alloc_mcam_by_ref_entry(mbox, flow, npc, &rsp_local);
890665b6a74SKiran Kumar K
891665b6a74SKiran Kumar K if (rc)
892665b6a74SKiran Kumar K return rc;
893665b6a74SKiran Kumar K
8941f669198SSatheesh Paul new_entry = plt_zmalloc(sizeof(*new_entry), 0);
8951f669198SSatheesh Paul if (!new_entry)
8961f669198SSatheesh Paul return -ENOSPC;
8971f669198SSatheesh Paul
8981f669198SSatheesh Paul new_entry->flow = flow;
8991f669198SSatheesh Paul
900542e27e9SSatheesh Paul plt_npc_dbg("kernel allocated MCAM entry %d", rsp_local.entry);
9011f669198SSatheesh Paul
9021f669198SSatheesh Paul rc = npc_sort_mcams_by_user_prio_level(mbox, new_entry, npc,
9031f669198SSatheesh Paul &rsp_local);
9041f669198SSatheesh Paul if (rc)
9051f669198SSatheesh Paul goto err;
9061f669198SSatheesh Paul
907542e27e9SSatheesh Paul plt_npc_dbg("allocated MCAM entry after sorting %d", rsp_local.entry);
9081f669198SSatheesh Paul flow->mcam_id = rsp_local.entry;
9091f669198SSatheesh Paul npc_insert_into_flow_list(npc, new_entry);
9101f669198SSatheesh Paul
9111f669198SSatheesh Paul return rsp_local.entry;
9121f669198SSatheesh Paul err:
9131f669198SSatheesh Paul plt_free(new_entry);
9141f669198SSatheesh Paul return rc;
9151f669198SSatheesh Paul }
9161f669198SSatheesh Paul
9171f669198SSatheesh Paul void
npc_delete_prio_list_entry(struct npc * npc,struct roc_npc_flow * flow)9181f669198SSatheesh Paul npc_delete_prio_list_entry(struct npc *npc, struct roc_npc_flow *flow)
9191f669198SSatheesh Paul {
9201f669198SSatheesh Paul struct npc_prio_flow_list_head *list;
9211f669198SSatheesh Paul struct npc_prio_flow_entry *curr;
9221f669198SSatheesh Paul
9231f669198SSatheesh Paul list = &npc->prio_flow_list[flow->priority];
9241f669198SSatheesh Paul curr = TAILQ_FIRST(list);
9251f669198SSatheesh Paul
9261f669198SSatheesh Paul if (!curr)
9271f669198SSatheesh Paul return;
9281f669198SSatheesh Paul
9291f669198SSatheesh Paul while (curr) {
9301f669198SSatheesh Paul if (flow->mcam_id == curr->flow->mcam_id) {
9311f669198SSatheesh Paul TAILQ_REMOVE(list, curr, next);
9321f669198SSatheesh Paul plt_free(curr);
9331f669198SSatheesh Paul break;
9341f669198SSatheesh Paul }
9351f669198SSatheesh Paul curr = TAILQ_NEXT(curr, next);
9361f669198SSatheesh Paul }
937665b6a74SKiran Kumar K }
938