xref: /dpdk/drivers/common/cnxk/roc_npc_utils.c (revision 0a6a4437631de7b41352326123b366f31cf7d0f7)
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