1f0a1913fSSubbaraya Sundeep // SPDX-License-Identifier: GPL-2.0
2cb0e3ec4SSunil Goutham /* Marvell RVU Ethernet driver
3f0a1913fSSubbaraya Sundeep  *
4f0a1913fSSubbaraya Sundeep  * Copyright (C) 2020 Marvell.
5cb0e3ec4SSunil Goutham  *
6f0a1913fSSubbaraya Sundeep  */
7f0a1913fSSubbaraya Sundeep 
8f0a1913fSSubbaraya Sundeep #include <net/ipv6.h>
9cc65fcabSSunil Goutham #include <linux/sort.h>
10f0a1913fSSubbaraya Sundeep 
11f0a1913fSSubbaraya Sundeep #include "otx2_common.h"
12f0a1913fSSubbaraya Sundeep 
13f0a1913fSSubbaraya Sundeep #define OTX2_DEFAULT_ACTION	0x1
14f0a1913fSSubbaraya Sundeep 
152da48943SSunil Goutham static int otx2_mcam_entry_init(struct otx2_nic *pfvf);
162da48943SSunil Goutham 
17f0a1913fSSubbaraya Sundeep struct otx2_flow {
18f0a1913fSSubbaraya Sundeep 	struct ethtool_rx_flow_spec flow_spec;
19f0a1913fSSubbaraya Sundeep 	struct list_head list;
20f0a1913fSSubbaraya Sundeep 	u32 location;
21*fa5e0ccbSRatheesh Kannoth 	u32 entry;
22f0a1913fSSubbaraya Sundeep 	bool is_vf;
2381a43620SGeetha sowjanya 	u8 rss_ctx_id;
248e675581SHariprasad Kelam #define DMAC_FILTER_RULE		BIT(0)
258e675581SHariprasad Kelam #define PFC_FLOWCTRL_RULE		BIT(1)
268e675581SHariprasad Kelam 	u16 rule_type;
27f0a1913fSSubbaraya Sundeep 	int vf;
2879d2be38SHariprasad Kelam };
2979d2be38SHariprasad Kelam 
3079d2be38SHariprasad Kelam enum dmac_req {
3179d2be38SHariprasad Kelam 	DMAC_ADDR_UPDATE,
3279d2be38SHariprasad Kelam 	DMAC_ADDR_DEL
33f0a1913fSSubbaraya Sundeep };
34f0a1913fSSubbaraya Sundeep 
359917060fSSunil Goutham static void otx2_clear_ntuple_flow_info(struct otx2_nic *pfvf, struct otx2_flow_config *flow_cfg)
369917060fSSunil Goutham {
379917060fSSunil Goutham 	devm_kfree(pfvf->dev, flow_cfg->flow_ent);
389917060fSSunil Goutham 	flow_cfg->flow_ent = NULL;
392e2a8126SSunil Goutham 	flow_cfg->max_flows = 0;
409917060fSSunil Goutham }
419917060fSSunil Goutham 
429917060fSSunil Goutham static int otx2_free_ntuple_mcam_entries(struct otx2_nic *pfvf)
439917060fSSunil Goutham {
449917060fSSunil Goutham 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
459917060fSSunil Goutham 	struct npc_mcam_free_entry_req *req;
469917060fSSunil Goutham 	int ent, err;
479917060fSSunil Goutham 
482e2a8126SSunil Goutham 	if (!flow_cfg->max_flows)
499917060fSSunil Goutham 		return 0;
509917060fSSunil Goutham 
519917060fSSunil Goutham 	mutex_lock(&pfvf->mbox.lock);
522e2a8126SSunil Goutham 	for (ent = 0; ent < flow_cfg->max_flows; ent++) {
539917060fSSunil Goutham 		req = otx2_mbox_alloc_msg_npc_mcam_free_entry(&pfvf->mbox);
549917060fSSunil Goutham 		if (!req)
559917060fSSunil Goutham 			break;
569917060fSSunil Goutham 
579917060fSSunil Goutham 		req->entry = flow_cfg->flow_ent[ent];
589917060fSSunil Goutham 
599917060fSSunil Goutham 		/* Send message to AF to free MCAM entries */
609917060fSSunil Goutham 		err = otx2_sync_mbox_msg(&pfvf->mbox);
619917060fSSunil Goutham 		if (err)
629917060fSSunil Goutham 			break;
639917060fSSunil Goutham 	}
649917060fSSunil Goutham 	mutex_unlock(&pfvf->mbox.lock);
659917060fSSunil Goutham 	otx2_clear_ntuple_flow_info(pfvf, flow_cfg);
669917060fSSunil Goutham 	return 0;
679917060fSSunil Goutham }
689917060fSSunil Goutham 
69cc65fcabSSunil Goutham static int mcam_entry_cmp(const void *a, const void *b)
70cc65fcabSSunil Goutham {
71cc65fcabSSunil Goutham 	return *(u16 *)a - *(u16 *)b;
72cc65fcabSSunil Goutham }
73cc65fcabSSunil Goutham 
742da48943SSunil Goutham int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
759917060fSSunil Goutham {
769917060fSSunil Goutham 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
779917060fSSunil Goutham 	struct npc_mcam_alloc_entry_req *req;
789917060fSSunil Goutham 	struct npc_mcam_alloc_entry_rsp *rsp;
799917060fSSunil Goutham 	int ent, allocated = 0;
809917060fSSunil Goutham 
819917060fSSunil Goutham 	/* Free current ones and allocate new ones with requested count */
829917060fSSunil Goutham 	otx2_free_ntuple_mcam_entries(pfvf);
839917060fSSunil Goutham 
849917060fSSunil Goutham 	if (!count)
859917060fSSunil Goutham 		return 0;
869917060fSSunil Goutham 
879917060fSSunil Goutham 	flow_cfg->flow_ent = devm_kmalloc_array(pfvf->dev, count,
889917060fSSunil Goutham 						sizeof(u16), GFP_KERNEL);
892da48943SSunil Goutham 	if (!flow_cfg->flow_ent) {
902da48943SSunil Goutham 		netdev_err(pfvf->netdev,
912da48943SSunil Goutham 			   "%s: Unable to allocate memory for flow entries\n",
922da48943SSunil Goutham 			    __func__);
939917060fSSunil Goutham 		return -ENOMEM;
942da48943SSunil Goutham 	}
959917060fSSunil Goutham 
969917060fSSunil Goutham 	mutex_lock(&pfvf->mbox.lock);
979917060fSSunil Goutham 
989917060fSSunil Goutham 	/* In a single request a max of NPC_MAX_NONCONTIG_ENTRIES MCAM entries
999917060fSSunil Goutham 	 * can only be allocated.
1009917060fSSunil Goutham 	 */
1019917060fSSunil Goutham 	while (allocated < count) {
1029917060fSSunil Goutham 		req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&pfvf->mbox);
1039917060fSSunil Goutham 		if (!req)
1049917060fSSunil Goutham 			goto exit;
1059917060fSSunil Goutham 
1069917060fSSunil Goutham 		req->contig = false;
1079917060fSSunil Goutham 		req->count = (count - allocated) > NPC_MAX_NONCONTIG_ENTRIES ?
1089917060fSSunil Goutham 				NPC_MAX_NONCONTIG_ENTRIES : count - allocated;
1093cffaed2SRakesh Babu 
1103cffaed2SRakesh Babu 		/* Allocate higher priority entries for PFs, so that VF's entries
1113cffaed2SRakesh Babu 		 * will be on top of PF.
1123cffaed2SRakesh Babu 		 */
1133cffaed2SRakesh Babu 		if (!is_otx2_vf(pfvf->pcifunc)) {
1149917060fSSunil Goutham 			req->priority = NPC_MCAM_HIGHER_PRIO;
1159917060fSSunil Goutham 			req->ref_entry = flow_cfg->def_ent[0];
1163cffaed2SRakesh Babu 		}
1179917060fSSunil Goutham 
1189917060fSSunil Goutham 		/* Send message to AF */
1199917060fSSunil Goutham 		if (otx2_sync_mbox_msg(&pfvf->mbox))
1209917060fSSunil Goutham 			goto exit;
1219917060fSSunil Goutham 
1229917060fSSunil Goutham 		rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp
1239917060fSSunil Goutham 			(&pfvf->mbox.mbox, 0, &req->hdr);
1249917060fSSunil Goutham 
1259917060fSSunil Goutham 		for (ent = 0; ent < rsp->count; ent++)
1269917060fSSunil Goutham 			flow_cfg->flow_ent[ent + allocated] = rsp->entry_list[ent];
1279917060fSSunil Goutham 
1289917060fSSunil Goutham 		allocated += rsp->count;
1299917060fSSunil Goutham 
1309917060fSSunil Goutham 		/* If this request is not fulfilled, no need to send
1319917060fSSunil Goutham 		 * further requests.
1329917060fSSunil Goutham 		 */
1339917060fSSunil Goutham 		if (rsp->count != req->count)
1349917060fSSunil Goutham 			break;
1359917060fSSunil Goutham 	}
1369917060fSSunil Goutham 
137cc65fcabSSunil Goutham 	/* Multiple MCAM entry alloc requests could result in non-sequential
138cc65fcabSSunil Goutham 	 * MCAM entries in the flow_ent[] array. Sort them in an ascending order,
139cc65fcabSSunil Goutham 	 * otherwise user installed ntuple filter index and MCAM entry index will
140cc65fcabSSunil Goutham 	 * not be in sync.
141cc65fcabSSunil Goutham 	 */
142cc65fcabSSunil Goutham 	if (allocated)
143cc65fcabSSunil Goutham 		sort(&flow_cfg->flow_ent[0], allocated,
144cc65fcabSSunil Goutham 		     sizeof(flow_cfg->flow_ent[0]), mcam_entry_cmp, NULL);
145cc65fcabSSunil Goutham 
1469917060fSSunil Goutham exit:
1479917060fSSunil Goutham 	mutex_unlock(&pfvf->mbox.lock);
1489917060fSSunil Goutham 
1492e2a8126SSunil Goutham 	flow_cfg->max_flows = allocated;
1509917060fSSunil Goutham 
1512da48943SSunil Goutham 	if (allocated) {
1523cffaed2SRakesh Babu 		pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
1533cffaed2SRakesh Babu 		pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
1542da48943SSunil Goutham 	}
1553cffaed2SRakesh Babu 
1569917060fSSunil Goutham 	if (allocated != count)
1579917060fSSunil Goutham 		netdev_info(pfvf->netdev,
1583cffaed2SRakesh Babu 			    "Unable to allocate %d MCAM entries, got only %d\n",
1599917060fSSunil Goutham 			    count, allocated);
1609917060fSSunil Goutham 	return allocated;
1619917060fSSunil Goutham }
1622da48943SSunil Goutham EXPORT_SYMBOL(otx2_alloc_mcam_entries);
1639917060fSSunil Goutham 
1642da48943SSunil Goutham static int otx2_mcam_entry_init(struct otx2_nic *pfvf)
165f0a1913fSSubbaraya Sundeep {
166f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
167f0a1913fSSubbaraya Sundeep 	struct npc_mcam_alloc_entry_req *req;
168f0a1913fSSubbaraya Sundeep 	struct npc_mcam_alloc_entry_rsp *rsp;
169f0c2982aSNaveen Mamindlapalli 	int vf_vlan_max_flows;
1709917060fSSunil Goutham 	int ent, count;
1719917060fSSunil Goutham 
1729917060fSSunil Goutham 	vf_vlan_max_flows = pfvf->total_vfs * OTX2_PER_VF_VLAN_FLOWS;
1739917060fSSunil Goutham 	count = OTX2_MAX_UNICAST_FLOWS +
1749917060fSSunil Goutham 			OTX2_MAX_VLAN_FLOWS + vf_vlan_max_flows;
1759917060fSSunil Goutham 
1769917060fSSunil Goutham 	flow_cfg->def_ent = devm_kmalloc_array(pfvf->dev, count,
1779917060fSSunil Goutham 					       sizeof(u16), GFP_KERNEL);
1789917060fSSunil Goutham 	if (!flow_cfg->def_ent)
1799917060fSSunil Goutham 		return -ENOMEM;
180f0a1913fSSubbaraya Sundeep 
181f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
182f0a1913fSSubbaraya Sundeep 
183f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&pfvf->mbox);
184f0a1913fSSubbaraya Sundeep 	if (!req) {
185f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
186f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
187f0a1913fSSubbaraya Sundeep 	}
188f0a1913fSSubbaraya Sundeep 
189f0a1913fSSubbaraya Sundeep 	req->contig = false;
1909917060fSSunil Goutham 	req->count = count;
191f0a1913fSSubbaraya Sundeep 
192f0a1913fSSubbaraya Sundeep 	/* Send message to AF */
193f0a1913fSSubbaraya Sundeep 	if (otx2_sync_mbox_msg(&pfvf->mbox)) {
194f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
195f0a1913fSSubbaraya Sundeep 		return -EINVAL;
196f0a1913fSSubbaraya Sundeep 	}
197f0a1913fSSubbaraya Sundeep 
198f0a1913fSSubbaraya Sundeep 	rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp
199f0a1913fSSubbaraya Sundeep 	       (&pfvf->mbox.mbox, 0, &req->hdr);
200f0a1913fSSubbaraya Sundeep 
20163ee5157SHariprasad Kelam 	if (rsp->count != req->count) {
202f0a1913fSSubbaraya Sundeep 		netdev_info(pfvf->netdev,
2039917060fSSunil Goutham 			    "Unable to allocate MCAM entries for ucast, vlan and vf_vlan\n");
2049917060fSSunil Goutham 		mutex_unlock(&pfvf->mbox.lock);
2059917060fSSunil Goutham 		devm_kfree(pfvf->dev, flow_cfg->def_ent);
2069917060fSSunil Goutham 		return 0;
2079917060fSSunil Goutham 	}
2089917060fSSunil Goutham 
2099917060fSSunil Goutham 	for (ent = 0; ent < rsp->count; ent++)
2109917060fSSunil Goutham 		flow_cfg->def_ent[ent] = rsp->entry_list[ent];
2119917060fSSunil Goutham 
212f0c2982aSNaveen Mamindlapalli 	flow_cfg->vf_vlan_offset = 0;
2139917060fSSunil Goutham 	flow_cfg->unicast_offset = vf_vlan_max_flows;
214fd9d7859SHariprasad Kelam 	flow_cfg->rx_vlan_offset = flow_cfg->unicast_offset +
215fd9d7859SHariprasad Kelam 					OTX2_MAX_UNICAST_FLOWS;
21663ee5157SHariprasad Kelam 	pfvf->flags |= OTX2_FLAG_UCAST_FLTR_SUPPORT;
217fd9d7859SHariprasad Kelam 	pfvf->flags |= OTX2_FLAG_RX_VLAN_SUPPORT;
218f0c2982aSNaveen Mamindlapalli 	pfvf->flags |= OTX2_FLAG_VF_VLAN_SUPPORT;
219f0a1913fSSubbaraya Sundeep 
220f0a1913fSSubbaraya Sundeep 	pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
221f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
222f0a1913fSSubbaraya Sundeep 
2239917060fSSunil Goutham 	/* Allocate entries for Ntuple filters */
2242da48943SSunil Goutham 	count = otx2_alloc_mcam_entries(pfvf, OTX2_DEFAULT_FLOWCOUNT);
2259917060fSSunil Goutham 	if (count <= 0) {
2269917060fSSunil Goutham 		otx2_clear_ntuple_flow_info(pfvf, flow_cfg);
2279917060fSSunil Goutham 		return 0;
2289917060fSSunil Goutham 	}
2299917060fSSunil Goutham 
2309917060fSSunil Goutham 	pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
2319917060fSSunil Goutham 
232f0a1913fSSubbaraya Sundeep 	return 0;
233f0a1913fSSubbaraya Sundeep }
234f0a1913fSSubbaraya Sundeep 
235*fa5e0ccbSRatheesh Kannoth /* TODO : revisit on size */
236*fa5e0ccbSRatheesh Kannoth #define OTX2_DMAC_FLTR_BITMAP_SZ (4 * 2048 + 32)
237*fa5e0ccbSRatheesh Kannoth 
2383cffaed2SRakesh Babu int otx2vf_mcam_flow_init(struct otx2_nic *pfvf)
2393cffaed2SRakesh Babu {
2403cffaed2SRakesh Babu 	struct otx2_flow_config *flow_cfg;
2413cffaed2SRakesh Babu 
2423cffaed2SRakesh Babu 	pfvf->flow_cfg = devm_kzalloc(pfvf->dev,
2433cffaed2SRakesh Babu 				      sizeof(struct otx2_flow_config),
2443cffaed2SRakesh Babu 				      GFP_KERNEL);
2453cffaed2SRakesh Babu 	if (!pfvf->flow_cfg)
2463cffaed2SRakesh Babu 		return -ENOMEM;
2473cffaed2SRakesh Babu 
248*fa5e0ccbSRatheesh Kannoth 	pfvf->flow_cfg->dmacflt_bmap = devm_kcalloc(pfvf->dev,
249*fa5e0ccbSRatheesh Kannoth 						    BITS_TO_LONGS(OTX2_DMAC_FLTR_BITMAP_SZ),
250*fa5e0ccbSRatheesh Kannoth 						    sizeof(long), GFP_KERNEL);
251*fa5e0ccbSRatheesh Kannoth 	if (!pfvf->flow_cfg->dmacflt_bmap)
252*fa5e0ccbSRatheesh Kannoth 		return -ENOMEM;
253*fa5e0ccbSRatheesh Kannoth 
2543cffaed2SRakesh Babu 	flow_cfg = pfvf->flow_cfg;
2553cffaed2SRakesh Babu 	INIT_LIST_HEAD(&flow_cfg->flow_list);
2562e2a8126SSunil Goutham 	flow_cfg->max_flows = 0;
2573cffaed2SRakesh Babu 
2583cffaed2SRakesh Babu 	return 0;
2593cffaed2SRakesh Babu }
2603cffaed2SRakesh Babu EXPORT_SYMBOL(otx2vf_mcam_flow_init);
2613cffaed2SRakesh Babu 
262f0a1913fSSubbaraya Sundeep int otx2_mcam_flow_init(struct otx2_nic *pf)
263f0a1913fSSubbaraya Sundeep {
264f0a1913fSSubbaraya Sundeep 	int err;
265f0a1913fSSubbaraya Sundeep 
266f0a1913fSSubbaraya Sundeep 	pf->flow_cfg = devm_kzalloc(pf->dev, sizeof(struct otx2_flow_config),
267f0a1913fSSubbaraya Sundeep 				    GFP_KERNEL);
268f0a1913fSSubbaraya Sundeep 	if (!pf->flow_cfg)
269f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
270f0a1913fSSubbaraya Sundeep 
271*fa5e0ccbSRatheesh Kannoth 	pf->flow_cfg->dmacflt_bmap = devm_kcalloc(pf->dev,
272*fa5e0ccbSRatheesh Kannoth 						  BITS_TO_LONGS(OTX2_DMAC_FLTR_BITMAP_SZ),
273*fa5e0ccbSRatheesh Kannoth 						  sizeof(long), GFP_KERNEL);
274*fa5e0ccbSRatheesh Kannoth 	if (!pf->flow_cfg->dmacflt_bmap)
275*fa5e0ccbSRatheesh Kannoth 		return -ENOMEM;
276*fa5e0ccbSRatheesh Kannoth 
277f0a1913fSSubbaraya Sundeep 	INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
278f0a1913fSSubbaraya Sundeep 
2792da48943SSunil Goutham 	/* Allocate bare minimum number of MCAM entries needed for
2802da48943SSunil Goutham 	 * unicast and ntuple filters.
2812da48943SSunil Goutham 	 */
2822da48943SSunil Goutham 	err = otx2_mcam_entry_init(pf);
283f0a1913fSSubbaraya Sundeep 	if (err)
284f0a1913fSSubbaraya Sundeep 		return err;
285f0a1913fSSubbaraya Sundeep 
2869917060fSSunil Goutham 	/* Check if MCAM entries are allocate or not */
2879917060fSSunil Goutham 	if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
2889917060fSSunil Goutham 		return 0;
2899917060fSSunil Goutham 
29063ee5157SHariprasad Kelam 	pf->mac_table = devm_kzalloc(pf->dev, sizeof(struct otx2_mac_table)
29163ee5157SHariprasad Kelam 					* OTX2_MAX_UNICAST_FLOWS, GFP_KERNEL);
29263ee5157SHariprasad Kelam 	if (!pf->mac_table)
29363ee5157SHariprasad Kelam 		return -ENOMEM;
29463ee5157SHariprasad Kelam 
29579d2be38SHariprasad Kelam 	otx2_dmacflt_get_max_cnt(pf);
29679d2be38SHariprasad Kelam 
29779d2be38SHariprasad Kelam 	/* DMAC filters are not allocated */
29879d2be38SHariprasad Kelam 	if (!pf->flow_cfg->dmacflt_max_flows)
29979d2be38SHariprasad Kelam 		return 0;
30079d2be38SHariprasad Kelam 
30179d2be38SHariprasad Kelam 	pf->flow_cfg->bmap_to_dmacindex =
302*fa5e0ccbSRatheesh Kannoth 			devm_kzalloc(pf->dev, sizeof(u32) *
30379d2be38SHariprasad Kelam 				     pf->flow_cfg->dmacflt_max_flows,
30479d2be38SHariprasad Kelam 				     GFP_KERNEL);
30579d2be38SHariprasad Kelam 
30679d2be38SHariprasad Kelam 	if (!pf->flow_cfg->bmap_to_dmacindex)
30779d2be38SHariprasad Kelam 		return -ENOMEM;
30879d2be38SHariprasad Kelam 
30979d2be38SHariprasad Kelam 	pf->flags |= OTX2_FLAG_DMACFLTR_SUPPORT;
31079d2be38SHariprasad Kelam 
311f0a1913fSSubbaraya Sundeep 	return 0;
312f0a1913fSSubbaraya Sundeep }
313f0a1913fSSubbaraya Sundeep 
314f0a1913fSSubbaraya Sundeep void otx2_mcam_flow_del(struct otx2_nic *pf)
315f0a1913fSSubbaraya Sundeep {
316f0a1913fSSubbaraya Sundeep 	otx2_destroy_mcam_flows(pf);
317f0a1913fSSubbaraya Sundeep }
3183cffaed2SRakesh Babu EXPORT_SYMBOL(otx2_mcam_flow_del);
319f0a1913fSSubbaraya Sundeep 
32063ee5157SHariprasad Kelam /*  On success adds mcam entry
32163ee5157SHariprasad Kelam  *  On failure enable promisous mode
32263ee5157SHariprasad Kelam  */
32363ee5157SHariprasad Kelam static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac)
32463ee5157SHariprasad Kelam {
32563ee5157SHariprasad Kelam 	struct otx2_flow_config *flow_cfg = pf->flow_cfg;
32663ee5157SHariprasad Kelam 	struct npc_install_flow_req *req;
32763ee5157SHariprasad Kelam 	int err, i;
32863ee5157SHariprasad Kelam 
32963ee5157SHariprasad Kelam 	if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
33063ee5157SHariprasad Kelam 		return -ENOMEM;
33163ee5157SHariprasad Kelam 
33263ee5157SHariprasad Kelam 	/* dont have free mcam entries or uc list is greater than alloted */
33363ee5157SHariprasad Kelam 	if (netdev_uc_count(pf->netdev) > OTX2_MAX_UNICAST_FLOWS)
33463ee5157SHariprasad Kelam 		return -ENOMEM;
33563ee5157SHariprasad Kelam 
33663ee5157SHariprasad Kelam 	mutex_lock(&pf->mbox.lock);
33763ee5157SHariprasad Kelam 	req = otx2_mbox_alloc_msg_npc_install_flow(&pf->mbox);
33863ee5157SHariprasad Kelam 	if (!req) {
33963ee5157SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
34063ee5157SHariprasad Kelam 		return -ENOMEM;
34163ee5157SHariprasad Kelam 	}
34263ee5157SHariprasad Kelam 
34363ee5157SHariprasad Kelam 	/* unicast offset starts with 32 0..31 for ntuple */
34463ee5157SHariprasad Kelam 	for (i = 0; i <  OTX2_MAX_UNICAST_FLOWS; i++) {
34563ee5157SHariprasad Kelam 		if (pf->mac_table[i].inuse)
34663ee5157SHariprasad Kelam 			continue;
34763ee5157SHariprasad Kelam 		ether_addr_copy(pf->mac_table[i].addr, mac);
34863ee5157SHariprasad Kelam 		pf->mac_table[i].inuse = true;
34963ee5157SHariprasad Kelam 		pf->mac_table[i].mcam_entry =
3509917060fSSunil Goutham 			flow_cfg->def_ent[i + flow_cfg->unicast_offset];
35163ee5157SHariprasad Kelam 		req->entry =  pf->mac_table[i].mcam_entry;
35263ee5157SHariprasad Kelam 		break;
35363ee5157SHariprasad Kelam 	}
35463ee5157SHariprasad Kelam 
35563ee5157SHariprasad Kelam 	ether_addr_copy(req->packet.dmac, mac);
35663ee5157SHariprasad Kelam 	eth_broadcast_addr((u8 *)&req->mask.dmac);
35763ee5157SHariprasad Kelam 	req->features = BIT_ULL(NPC_DMAC);
35863ee5157SHariprasad Kelam 	req->channel = pf->hw.rx_chan_base;
35963ee5157SHariprasad Kelam 	req->intf = NIX_INTF_RX;
36063ee5157SHariprasad Kelam 	req->op = NIX_RX_ACTION_DEFAULT;
36163ee5157SHariprasad Kelam 	req->set_cntr = 1;
36263ee5157SHariprasad Kelam 
36363ee5157SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pf->mbox);
36463ee5157SHariprasad Kelam 	mutex_unlock(&pf->mbox.lock);
36563ee5157SHariprasad Kelam 
36663ee5157SHariprasad Kelam 	return err;
36763ee5157SHariprasad Kelam }
36863ee5157SHariprasad Kelam 
36963ee5157SHariprasad Kelam int otx2_add_macfilter(struct net_device *netdev, const u8 *mac)
37063ee5157SHariprasad Kelam {
37163ee5157SHariprasad Kelam 	struct otx2_nic *pf = netdev_priv(netdev);
37263ee5157SHariprasad Kelam 
373*fa5e0ccbSRatheesh Kannoth 	if (!bitmap_empty(pf->flow_cfg->dmacflt_bmap,
37479d2be38SHariprasad Kelam 			  pf->flow_cfg->dmacflt_max_flows))
37579d2be38SHariprasad Kelam 		netdev_warn(netdev,
37679d2be38SHariprasad Kelam 			    "Add %pM to CGX/RPM DMAC filters list as well\n",
37779d2be38SHariprasad Kelam 			    mac);
37879d2be38SHariprasad Kelam 
37963ee5157SHariprasad Kelam 	return otx2_do_add_macfilter(pf, mac);
38063ee5157SHariprasad Kelam }
38163ee5157SHariprasad Kelam 
38263ee5157SHariprasad Kelam static bool otx2_get_mcamentry_for_mac(struct otx2_nic *pf, const u8 *mac,
38363ee5157SHariprasad Kelam 				       int *mcam_entry)
38463ee5157SHariprasad Kelam {
38563ee5157SHariprasad Kelam 	int i;
38663ee5157SHariprasad Kelam 
38763ee5157SHariprasad Kelam 	for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) {
38863ee5157SHariprasad Kelam 		if (!pf->mac_table[i].inuse)
38963ee5157SHariprasad Kelam 			continue;
39063ee5157SHariprasad Kelam 
39163ee5157SHariprasad Kelam 		if (ether_addr_equal(pf->mac_table[i].addr, mac)) {
39263ee5157SHariprasad Kelam 			*mcam_entry = pf->mac_table[i].mcam_entry;
39363ee5157SHariprasad Kelam 			pf->mac_table[i].inuse = false;
39463ee5157SHariprasad Kelam 			return true;
39563ee5157SHariprasad Kelam 		}
39663ee5157SHariprasad Kelam 	}
39763ee5157SHariprasad Kelam 	return false;
39863ee5157SHariprasad Kelam }
39963ee5157SHariprasad Kelam 
40063ee5157SHariprasad Kelam int otx2_del_macfilter(struct net_device *netdev, const u8 *mac)
40163ee5157SHariprasad Kelam {
40263ee5157SHariprasad Kelam 	struct otx2_nic *pf = netdev_priv(netdev);
40363ee5157SHariprasad Kelam 	struct npc_delete_flow_req *req;
40463ee5157SHariprasad Kelam 	int err, mcam_entry;
40563ee5157SHariprasad Kelam 
40663ee5157SHariprasad Kelam 	/* check does mcam entry exists for given mac */
40763ee5157SHariprasad Kelam 	if (!otx2_get_mcamentry_for_mac(pf, mac, &mcam_entry))
40863ee5157SHariprasad Kelam 		return 0;
40963ee5157SHariprasad Kelam 
41063ee5157SHariprasad Kelam 	mutex_lock(&pf->mbox.lock);
41163ee5157SHariprasad Kelam 	req = otx2_mbox_alloc_msg_npc_delete_flow(&pf->mbox);
41263ee5157SHariprasad Kelam 	if (!req) {
41363ee5157SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
41463ee5157SHariprasad Kelam 		return -ENOMEM;
41563ee5157SHariprasad Kelam 	}
41663ee5157SHariprasad Kelam 	req->entry = mcam_entry;
41763ee5157SHariprasad Kelam 	/* Send message to AF */
41863ee5157SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pf->mbox);
41963ee5157SHariprasad Kelam 	mutex_unlock(&pf->mbox.lock);
42063ee5157SHariprasad Kelam 
42163ee5157SHariprasad Kelam 	return err;
42263ee5157SHariprasad Kelam }
42363ee5157SHariprasad Kelam 
424f0a1913fSSubbaraya Sundeep static struct otx2_flow *otx2_find_flow(struct otx2_nic *pfvf, u32 location)
425f0a1913fSSubbaraya Sundeep {
426f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter;
427f0a1913fSSubbaraya Sundeep 
428f0a1913fSSubbaraya Sundeep 	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
429f0a1913fSSubbaraya Sundeep 		if (iter->location == location)
430f0a1913fSSubbaraya Sundeep 			return iter;
431f0a1913fSSubbaraya Sundeep 	}
432f0a1913fSSubbaraya Sundeep 
433f0a1913fSSubbaraya Sundeep 	return NULL;
434f0a1913fSSubbaraya Sundeep }
435f0a1913fSSubbaraya Sundeep 
436f0a1913fSSubbaraya Sundeep static void otx2_add_flow_to_list(struct otx2_nic *pfvf, struct otx2_flow *flow)
437f0a1913fSSubbaraya Sundeep {
438f0a1913fSSubbaraya Sundeep 	struct list_head *head = &pfvf->flow_cfg->flow_list;
439f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter;
440f0a1913fSSubbaraya Sundeep 
441f0a1913fSSubbaraya Sundeep 	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
442f0a1913fSSubbaraya Sundeep 		if (iter->location > flow->location)
443f0a1913fSSubbaraya Sundeep 			break;
444f0a1913fSSubbaraya Sundeep 		head = &iter->list;
445f0a1913fSSubbaraya Sundeep 	}
446f0a1913fSSubbaraya Sundeep 
447f0a1913fSSubbaraya Sundeep 	list_add(&flow->list, head);
448f0a1913fSSubbaraya Sundeep }
449f0a1913fSSubbaraya Sundeep 
4503cffaed2SRakesh Babu int otx2_get_maxflows(struct otx2_flow_config *flow_cfg)
45179d2be38SHariprasad Kelam {
4523cffaed2SRakesh Babu 	if (!flow_cfg)
4533cffaed2SRakesh Babu 		return 0;
4543cffaed2SRakesh Babu 
4552e2a8126SSunil Goutham 	if (flow_cfg->nr_flows == flow_cfg->max_flows ||
456*fa5e0ccbSRatheesh Kannoth 	    !bitmap_empty(flow_cfg->dmacflt_bmap,
45779d2be38SHariprasad Kelam 			  flow_cfg->dmacflt_max_flows))
4582e2a8126SSunil Goutham 		return flow_cfg->max_flows + flow_cfg->dmacflt_max_flows;
45979d2be38SHariprasad Kelam 	else
4602e2a8126SSunil Goutham 		return flow_cfg->max_flows;
46179d2be38SHariprasad Kelam }
4623cffaed2SRakesh Babu EXPORT_SYMBOL(otx2_get_maxflows);
46379d2be38SHariprasad Kelam 
464f0a1913fSSubbaraya Sundeep int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
465f0a1913fSSubbaraya Sundeep 		  u32 location)
466f0a1913fSSubbaraya Sundeep {
467f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter;
468f0a1913fSSubbaraya Sundeep 
46979d2be38SHariprasad Kelam 	if (location >= otx2_get_maxflows(pfvf->flow_cfg))
470f0a1913fSSubbaraya Sundeep 		return -EINVAL;
471f0a1913fSSubbaraya Sundeep 
472f0a1913fSSubbaraya Sundeep 	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
473f0a1913fSSubbaraya Sundeep 		if (iter->location == location) {
474f0a1913fSSubbaraya Sundeep 			nfc->fs = iter->flow_spec;
47581a43620SGeetha sowjanya 			nfc->rss_context = iter->rss_ctx_id;
476f0a1913fSSubbaraya Sundeep 			return 0;
477f0a1913fSSubbaraya Sundeep 		}
478f0a1913fSSubbaraya Sundeep 	}
479f0a1913fSSubbaraya Sundeep 
480f0a1913fSSubbaraya Sundeep 	return -ENOENT;
481f0a1913fSSubbaraya Sundeep }
482f0a1913fSSubbaraya Sundeep 
483f0a1913fSSubbaraya Sundeep int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
484f0a1913fSSubbaraya Sundeep 		       u32 *rule_locs)
485f0a1913fSSubbaraya Sundeep {
486f41b2d67SSubbaraya Sundeep 	u32 rule_cnt = nfc->rule_cnt;
487f0a1913fSSubbaraya Sundeep 	u32 location = 0;
488f0a1913fSSubbaraya Sundeep 	int idx = 0;
489f0a1913fSSubbaraya Sundeep 	int err = 0;
490f0a1913fSSubbaraya Sundeep 
49179d2be38SHariprasad Kelam 	nfc->data = otx2_get_maxflows(pfvf->flow_cfg);
492f41b2d67SSubbaraya Sundeep 	while ((!err || err == -ENOENT) && idx < rule_cnt) {
493f0a1913fSSubbaraya Sundeep 		err = otx2_get_flow(pfvf, nfc, location);
494f0a1913fSSubbaraya Sundeep 		if (!err)
495f0a1913fSSubbaraya Sundeep 			rule_locs[idx++] = location;
496f0a1913fSSubbaraya Sundeep 		location++;
497f0a1913fSSubbaraya Sundeep 	}
498f41b2d67SSubbaraya Sundeep 	nfc->rule_cnt = rule_cnt;
499f0a1913fSSubbaraya Sundeep 
500f0a1913fSSubbaraya Sundeep 	return err;
501f0a1913fSSubbaraya Sundeep }
502f0a1913fSSubbaraya Sundeep 
503b7cf9661SNaveen Mamindlapalli static int otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp,
504f0a1913fSSubbaraya Sundeep 				  struct npc_install_flow_req *req,
505f0a1913fSSubbaraya Sundeep 				  u32 flow_type)
506f0a1913fSSubbaraya Sundeep {
507f0a1913fSSubbaraya Sundeep 	struct ethtool_usrip4_spec *ipv4_usr_mask = &fsp->m_u.usr_ip4_spec;
508f0a1913fSSubbaraya Sundeep 	struct ethtool_usrip4_spec *ipv4_usr_hdr = &fsp->h_u.usr_ip4_spec;
509f0a1913fSSubbaraya Sundeep 	struct ethtool_tcpip4_spec *ipv4_l4_mask = &fsp->m_u.tcp_ip4_spec;
510f0a1913fSSubbaraya Sundeep 	struct ethtool_tcpip4_spec *ipv4_l4_hdr = &fsp->h_u.tcp_ip4_spec;
511b7cf9661SNaveen Mamindlapalli 	struct ethtool_ah_espip4_spec *ah_esp_hdr = &fsp->h_u.ah_ip4_spec;
512b7cf9661SNaveen Mamindlapalli 	struct ethtool_ah_espip4_spec *ah_esp_mask = &fsp->m_u.ah_ip4_spec;
513f0a1913fSSubbaraya Sundeep 	struct flow_msg *pmask = &req->mask;
514f0a1913fSSubbaraya Sundeep 	struct flow_msg *pkt = &req->packet;
515f0a1913fSSubbaraya Sundeep 
516f0a1913fSSubbaraya Sundeep 	switch (flow_type) {
517f0a1913fSSubbaraya Sundeep 	case IP_USER_FLOW:
518f0a1913fSSubbaraya Sundeep 		if (ipv4_usr_mask->ip4src) {
519f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip4src, &ipv4_usr_hdr->ip4src,
520f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip4src));
521f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip4src, &ipv4_usr_mask->ip4src,
522f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip4src));
523f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SIP_IPV4);
524f0a1913fSSubbaraya Sundeep 		}
525f0a1913fSSubbaraya Sundeep 		if (ipv4_usr_mask->ip4dst) {
526f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip4dst, &ipv4_usr_hdr->ip4dst,
527f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip4dst));
528f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip4dst, &ipv4_usr_mask->ip4dst,
529f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip4dst));
530f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DIP_IPV4);
531f0a1913fSSubbaraya Sundeep 		}
5322b9cef66SNaveen Mamindlapalli 		if (ipv4_usr_mask->tos) {
5332b9cef66SNaveen Mamindlapalli 			pkt->tos = ipv4_usr_hdr->tos;
5342b9cef66SNaveen Mamindlapalli 			pmask->tos = ipv4_usr_mask->tos;
5352b9cef66SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_TOS);
5362b9cef66SNaveen Mamindlapalli 		}
5372b9cef66SNaveen Mamindlapalli 		if (ipv4_usr_mask->proto) {
5382b9cef66SNaveen Mamindlapalli 			switch (ipv4_usr_hdr->proto) {
5392b9cef66SNaveen Mamindlapalli 			case IPPROTO_ICMP:
5402b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_ICMP);
5412b9cef66SNaveen Mamindlapalli 				break;
5422b9cef66SNaveen Mamindlapalli 			case IPPROTO_TCP:
5432b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_TCP);
5442b9cef66SNaveen Mamindlapalli 				break;
5452b9cef66SNaveen Mamindlapalli 			case IPPROTO_UDP:
5462b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_UDP);
5472b9cef66SNaveen Mamindlapalli 				break;
5482b9cef66SNaveen Mamindlapalli 			case IPPROTO_SCTP:
5492b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
5502b9cef66SNaveen Mamindlapalli 				break;
5512b9cef66SNaveen Mamindlapalli 			case IPPROTO_AH:
5522b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_AH);
5532b9cef66SNaveen Mamindlapalli 				break;
5542b9cef66SNaveen Mamindlapalli 			case IPPROTO_ESP:
5552b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_ESP);
5562b9cef66SNaveen Mamindlapalli 				break;
5572b9cef66SNaveen Mamindlapalli 			default:
5582b9cef66SNaveen Mamindlapalli 				return -EOPNOTSUPP;
5592b9cef66SNaveen Mamindlapalli 			}
5602b9cef66SNaveen Mamindlapalli 		}
561b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IP);
562b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
563b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
564f0a1913fSSubbaraya Sundeep 		break;
565f0a1913fSSubbaraya Sundeep 	case TCP_V4_FLOW:
566f0a1913fSSubbaraya Sundeep 	case UDP_V4_FLOW:
567f0a1913fSSubbaraya Sundeep 	case SCTP_V4_FLOW:
568b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IP);
569b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
570b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
571f0a1913fSSubbaraya Sundeep 		if (ipv4_l4_mask->ip4src) {
572f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip4src, &ipv4_l4_hdr->ip4src,
573f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip4src));
574f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip4src, &ipv4_l4_mask->ip4src,
575f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip4src));
576f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SIP_IPV4);
577f0a1913fSSubbaraya Sundeep 		}
578f0a1913fSSubbaraya Sundeep 		if (ipv4_l4_mask->ip4dst) {
579f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip4dst, &ipv4_l4_hdr->ip4dst,
580f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip4dst));
581f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip4dst, &ipv4_l4_mask->ip4dst,
582f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip4dst));
583f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DIP_IPV4);
584f0a1913fSSubbaraya Sundeep 		}
5852b9cef66SNaveen Mamindlapalli 		if (ipv4_l4_mask->tos) {
5862b9cef66SNaveen Mamindlapalli 			pkt->tos = ipv4_l4_hdr->tos;
5872b9cef66SNaveen Mamindlapalli 			pmask->tos = ipv4_l4_mask->tos;
5882b9cef66SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_TOS);
5892b9cef66SNaveen Mamindlapalli 		}
590f0a1913fSSubbaraya Sundeep 		if (ipv4_l4_mask->psrc) {
591f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->sport, &ipv4_l4_hdr->psrc,
592f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->sport));
593f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->sport, &ipv4_l4_mask->psrc,
594f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->sport));
595f0a1913fSSubbaraya Sundeep 			if (flow_type == UDP_V4_FLOW)
596f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_UDP);
597f0a1913fSSubbaraya Sundeep 			else if (flow_type == TCP_V4_FLOW)
598f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_TCP);
599f0a1913fSSubbaraya Sundeep 			else
600f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_SCTP);
601f0a1913fSSubbaraya Sundeep 		}
602f0a1913fSSubbaraya Sundeep 		if (ipv4_l4_mask->pdst) {
603f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->dport, &ipv4_l4_hdr->pdst,
604f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->dport));
605f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->dport, &ipv4_l4_mask->pdst,
606f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->dport));
607f0a1913fSSubbaraya Sundeep 			if (flow_type == UDP_V4_FLOW)
608f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_UDP);
609f0a1913fSSubbaraya Sundeep 			else if (flow_type == TCP_V4_FLOW)
610f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_TCP);
611f0a1913fSSubbaraya Sundeep 			else
612f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_SCTP);
613f0a1913fSSubbaraya Sundeep 		}
614b7cf9661SNaveen Mamindlapalli 		if (flow_type == UDP_V4_FLOW)
615b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_UDP);
616b7cf9661SNaveen Mamindlapalli 		else if (flow_type == TCP_V4_FLOW)
617b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_TCP);
618b7cf9661SNaveen Mamindlapalli 		else
619b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
620b7cf9661SNaveen Mamindlapalli 		break;
621b7cf9661SNaveen Mamindlapalli 	case AH_V4_FLOW:
622b7cf9661SNaveen Mamindlapalli 	case ESP_V4_FLOW:
623b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IP);
624b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
625b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
626b7cf9661SNaveen Mamindlapalli 		if (ah_esp_mask->ip4src) {
627b7cf9661SNaveen Mamindlapalli 			memcpy(&pkt->ip4src, &ah_esp_hdr->ip4src,
628b7cf9661SNaveen Mamindlapalli 			       sizeof(pkt->ip4src));
629b7cf9661SNaveen Mamindlapalli 			memcpy(&pmask->ip4src, &ah_esp_mask->ip4src,
630b7cf9661SNaveen Mamindlapalli 			       sizeof(pmask->ip4src));
631b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_SIP_IPV4);
632b7cf9661SNaveen Mamindlapalli 		}
633b7cf9661SNaveen Mamindlapalli 		if (ah_esp_mask->ip4dst) {
634b7cf9661SNaveen Mamindlapalli 			memcpy(&pkt->ip4dst, &ah_esp_hdr->ip4dst,
635b7cf9661SNaveen Mamindlapalli 			       sizeof(pkt->ip4dst));
636b7cf9661SNaveen Mamindlapalli 			memcpy(&pmask->ip4dst, &ah_esp_mask->ip4dst,
637b7cf9661SNaveen Mamindlapalli 			       sizeof(pmask->ip4dst));
638b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_DIP_IPV4);
639b7cf9661SNaveen Mamindlapalli 		}
6402b9cef66SNaveen Mamindlapalli 		if (ah_esp_mask->tos) {
6412b9cef66SNaveen Mamindlapalli 			pkt->tos = ah_esp_hdr->tos;
6422b9cef66SNaveen Mamindlapalli 			pmask->tos = ah_esp_mask->tos;
6432b9cef66SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_TOS);
6442b9cef66SNaveen Mamindlapalli 		}
645b7cf9661SNaveen Mamindlapalli 
646b7cf9661SNaveen Mamindlapalli 		/* NPC profile doesn't extract AH/ESP header fields */
6472b9cef66SNaveen Mamindlapalli 		if (ah_esp_mask->spi & ah_esp_hdr->spi)
648b7cf9661SNaveen Mamindlapalli 			return -EOPNOTSUPP;
649b7cf9661SNaveen Mamindlapalli 
650b7cf9661SNaveen Mamindlapalli 		if (flow_type == AH_V4_FLOW)
651b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_AH);
652b7cf9661SNaveen Mamindlapalli 		else
653b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_ESP);
654f0a1913fSSubbaraya Sundeep 		break;
655f0a1913fSSubbaraya Sundeep 	default:
656f0a1913fSSubbaraya Sundeep 		break;
657f0a1913fSSubbaraya Sundeep 	}
658b7cf9661SNaveen Mamindlapalli 
659b7cf9661SNaveen Mamindlapalli 	return 0;
660f0a1913fSSubbaraya Sundeep }
661f0a1913fSSubbaraya Sundeep 
662b7cf9661SNaveen Mamindlapalli static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
663f0a1913fSSubbaraya Sundeep 				  struct npc_install_flow_req *req,
664f0a1913fSSubbaraya Sundeep 				  u32 flow_type)
665f0a1913fSSubbaraya Sundeep {
666f0a1913fSSubbaraya Sundeep 	struct ethtool_usrip6_spec *ipv6_usr_mask = &fsp->m_u.usr_ip6_spec;
667f0a1913fSSubbaraya Sundeep 	struct ethtool_usrip6_spec *ipv6_usr_hdr = &fsp->h_u.usr_ip6_spec;
668f0a1913fSSubbaraya Sundeep 	struct ethtool_tcpip6_spec *ipv6_l4_mask = &fsp->m_u.tcp_ip6_spec;
669f0a1913fSSubbaraya Sundeep 	struct ethtool_tcpip6_spec *ipv6_l4_hdr = &fsp->h_u.tcp_ip6_spec;
670b7cf9661SNaveen Mamindlapalli 	struct ethtool_ah_espip6_spec *ah_esp_hdr = &fsp->h_u.ah_ip6_spec;
671b7cf9661SNaveen Mamindlapalli 	struct ethtool_ah_espip6_spec *ah_esp_mask = &fsp->m_u.ah_ip6_spec;
672f0a1913fSSubbaraya Sundeep 	struct flow_msg *pmask = &req->mask;
673f0a1913fSSubbaraya Sundeep 	struct flow_msg *pkt = &req->packet;
674f0a1913fSSubbaraya Sundeep 
675f0a1913fSSubbaraya Sundeep 	switch (flow_type) {
676f0a1913fSSubbaraya Sundeep 	case IPV6_USER_FLOW:
677f0a1913fSSubbaraya Sundeep 		if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6src)) {
678f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip6src, &ipv6_usr_hdr->ip6src,
679f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip6src));
680f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip6src, &ipv6_usr_mask->ip6src,
681f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip6src));
682f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SIP_IPV6);
683f0a1913fSSubbaraya Sundeep 		}
684f0a1913fSSubbaraya Sundeep 		if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6dst)) {
685f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip6dst, &ipv6_usr_hdr->ip6dst,
686f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip6dst));
687f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip6dst, &ipv6_usr_mask->ip6dst,
688f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip6dst));
689f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DIP_IPV6);
690f0a1913fSSubbaraya Sundeep 		}
691b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IPV6);
692b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
693b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
694f0a1913fSSubbaraya Sundeep 		break;
695f0a1913fSSubbaraya Sundeep 	case TCP_V6_FLOW:
696f0a1913fSSubbaraya Sundeep 	case UDP_V6_FLOW:
697f0a1913fSSubbaraya Sundeep 	case SCTP_V6_FLOW:
698b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IPV6);
699b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
700b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
701f0a1913fSSubbaraya Sundeep 		if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6src)) {
702f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip6src, &ipv6_l4_hdr->ip6src,
703f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip6src));
704f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip6src, &ipv6_l4_mask->ip6src,
705f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip6src));
706f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SIP_IPV6);
707f0a1913fSSubbaraya Sundeep 		}
708f0a1913fSSubbaraya Sundeep 		if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6dst)) {
709f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip6dst, &ipv6_l4_hdr->ip6dst,
710f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip6dst));
711f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip6dst, &ipv6_l4_mask->ip6dst,
712f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip6dst));
713f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DIP_IPV6);
714f0a1913fSSubbaraya Sundeep 		}
715f0a1913fSSubbaraya Sundeep 		if (ipv6_l4_mask->psrc) {
716f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->sport, &ipv6_l4_hdr->psrc,
717f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->sport));
718f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->sport, &ipv6_l4_mask->psrc,
719f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->sport));
720f0a1913fSSubbaraya Sundeep 			if (flow_type == UDP_V6_FLOW)
721f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_UDP);
722f0a1913fSSubbaraya Sundeep 			else if (flow_type == TCP_V6_FLOW)
723f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_TCP);
724f0a1913fSSubbaraya Sundeep 			else
725f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_SCTP);
726f0a1913fSSubbaraya Sundeep 		}
727f0a1913fSSubbaraya Sundeep 		if (ipv6_l4_mask->pdst) {
728f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->dport, &ipv6_l4_hdr->pdst,
729f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->dport));
730f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->dport, &ipv6_l4_mask->pdst,
731f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->dport));
732f0a1913fSSubbaraya Sundeep 			if (flow_type == UDP_V6_FLOW)
733f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_UDP);
734f0a1913fSSubbaraya Sundeep 			else if (flow_type == TCP_V6_FLOW)
735f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_TCP);
736f0a1913fSSubbaraya Sundeep 			else
737f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_SCTP);
738f0a1913fSSubbaraya Sundeep 		}
739b7cf9661SNaveen Mamindlapalli 		if (flow_type == UDP_V6_FLOW)
740b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_UDP);
741b7cf9661SNaveen Mamindlapalli 		else if (flow_type == TCP_V6_FLOW)
742b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_TCP);
743b7cf9661SNaveen Mamindlapalli 		else
744b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
745f0a1913fSSubbaraya Sundeep 		break;
746b7cf9661SNaveen Mamindlapalli 	case AH_V6_FLOW:
747b7cf9661SNaveen Mamindlapalli 	case ESP_V6_FLOW:
748b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IPV6);
749b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
750b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
751b7cf9661SNaveen Mamindlapalli 		if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6src)) {
752b7cf9661SNaveen Mamindlapalli 			memcpy(&pkt->ip6src, &ah_esp_hdr->ip6src,
753b7cf9661SNaveen Mamindlapalli 			       sizeof(pkt->ip6src));
754b7cf9661SNaveen Mamindlapalli 			memcpy(&pmask->ip6src, &ah_esp_mask->ip6src,
755b7cf9661SNaveen Mamindlapalli 			       sizeof(pmask->ip6src));
756b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_SIP_IPV6);
757b7cf9661SNaveen Mamindlapalli 		}
758b7cf9661SNaveen Mamindlapalli 		if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6dst)) {
759b7cf9661SNaveen Mamindlapalli 			memcpy(&pkt->ip6dst, &ah_esp_hdr->ip6dst,
760b7cf9661SNaveen Mamindlapalli 			       sizeof(pkt->ip6dst));
761b7cf9661SNaveen Mamindlapalli 			memcpy(&pmask->ip6dst, &ah_esp_mask->ip6dst,
762b7cf9661SNaveen Mamindlapalli 			       sizeof(pmask->ip6dst));
763b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_DIP_IPV6);
764b7cf9661SNaveen Mamindlapalli 		}
765b7cf9661SNaveen Mamindlapalli 
766b7cf9661SNaveen Mamindlapalli 		/* NPC profile doesn't extract AH/ESP header fields */
767b7cf9661SNaveen Mamindlapalli 		if ((ah_esp_mask->spi & ah_esp_hdr->spi) ||
768b7cf9661SNaveen Mamindlapalli 		    (ah_esp_mask->tclass & ah_esp_mask->tclass))
769b7cf9661SNaveen Mamindlapalli 			return -EOPNOTSUPP;
770b7cf9661SNaveen Mamindlapalli 
771b7cf9661SNaveen Mamindlapalli 		if (flow_type == AH_V6_FLOW)
772b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_AH);
773b7cf9661SNaveen Mamindlapalli 		else
774b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_ESP);
775320daffdSGustavo A. R. Silva 		break;
776f0a1913fSSubbaraya Sundeep 	default:
777f0a1913fSSubbaraya Sundeep 		break;
778f0a1913fSSubbaraya Sundeep 	}
779b7cf9661SNaveen Mamindlapalli 
780b7cf9661SNaveen Mamindlapalli 	return 0;
781f0a1913fSSubbaraya Sundeep }
782f0a1913fSSubbaraya Sundeep 
783dce677daSSubbaraya Sundeep static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
784f0a1913fSSubbaraya Sundeep 			      struct npc_install_flow_req *req)
785f0a1913fSSubbaraya Sundeep {
786f0a1913fSSubbaraya Sundeep 	struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
787f0a1913fSSubbaraya Sundeep 	struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
788f0a1913fSSubbaraya Sundeep 	struct flow_msg *pmask = &req->mask;
789f0a1913fSSubbaraya Sundeep 	struct flow_msg *pkt = &req->packet;
790f0a1913fSSubbaraya Sundeep 	u32 flow_type;
791b7cf9661SNaveen Mamindlapalli 	int ret;
792f0a1913fSSubbaraya Sundeep 
79381a43620SGeetha sowjanya 	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
794f0a1913fSSubbaraya Sundeep 	switch (flow_type) {
795f0a1913fSSubbaraya Sundeep 	/* bits not set in mask are don't care */
796f0a1913fSSubbaraya Sundeep 	case ETHER_FLOW:
797f0a1913fSSubbaraya Sundeep 		if (!is_zero_ether_addr(eth_mask->h_source)) {
798f0a1913fSSubbaraya Sundeep 			ether_addr_copy(pkt->smac, eth_hdr->h_source);
799f0a1913fSSubbaraya Sundeep 			ether_addr_copy(pmask->smac, eth_mask->h_source);
800f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SMAC);
801f0a1913fSSubbaraya Sundeep 		}
802f0a1913fSSubbaraya Sundeep 		if (!is_zero_ether_addr(eth_mask->h_dest)) {
803f0a1913fSSubbaraya Sundeep 			ether_addr_copy(pkt->dmac, eth_hdr->h_dest);
804f0a1913fSSubbaraya Sundeep 			ether_addr_copy(pmask->dmac, eth_mask->h_dest);
805f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DMAC);
806f0a1913fSSubbaraya Sundeep 		}
8073cffaed2SRakesh Babu 		if (eth_hdr->h_proto) {
808f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->etype, &eth_hdr->h_proto,
809f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->etype));
810f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->etype, &eth_mask->h_proto,
811f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->etype));
812f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_ETYPE);
813f0a1913fSSubbaraya Sundeep 		}
814f0a1913fSSubbaraya Sundeep 		break;
815f0a1913fSSubbaraya Sundeep 	case IP_USER_FLOW:
816f0a1913fSSubbaraya Sundeep 	case TCP_V4_FLOW:
817f0a1913fSSubbaraya Sundeep 	case UDP_V4_FLOW:
818f0a1913fSSubbaraya Sundeep 	case SCTP_V4_FLOW:
819b7cf9661SNaveen Mamindlapalli 	case AH_V4_FLOW:
820b7cf9661SNaveen Mamindlapalli 	case ESP_V4_FLOW:
821b7cf9661SNaveen Mamindlapalli 		ret = otx2_prepare_ipv4_flow(fsp, req, flow_type);
822b7cf9661SNaveen Mamindlapalli 		if (ret)
823b7cf9661SNaveen Mamindlapalli 			return ret;
824f0a1913fSSubbaraya Sundeep 		break;
825f0a1913fSSubbaraya Sundeep 	case IPV6_USER_FLOW:
826f0a1913fSSubbaraya Sundeep 	case TCP_V6_FLOW:
827f0a1913fSSubbaraya Sundeep 	case UDP_V6_FLOW:
828f0a1913fSSubbaraya Sundeep 	case SCTP_V6_FLOW:
829b7cf9661SNaveen Mamindlapalli 	case AH_V6_FLOW:
830b7cf9661SNaveen Mamindlapalli 	case ESP_V6_FLOW:
831b7cf9661SNaveen Mamindlapalli 		ret = otx2_prepare_ipv6_flow(fsp, req, flow_type);
832b7cf9661SNaveen Mamindlapalli 		if (ret)
833b7cf9661SNaveen Mamindlapalli 			return ret;
834f0a1913fSSubbaraya Sundeep 		break;
835f0a1913fSSubbaraya Sundeep 	default:
836f0a1913fSSubbaraya Sundeep 		return -EOPNOTSUPP;
837f0a1913fSSubbaraya Sundeep 	}
838f0a1913fSSubbaraya Sundeep 	if (fsp->flow_type & FLOW_EXT) {
839dce677daSSubbaraya Sundeep 		u16 vlan_etype;
840dce677daSSubbaraya Sundeep 
841dce677daSSubbaraya Sundeep 		if (fsp->m_ext.vlan_etype) {
842dce677daSSubbaraya Sundeep 			/* Partial masks not supported */
843dce677daSSubbaraya Sundeep 			if (be16_to_cpu(fsp->m_ext.vlan_etype) != 0xFFFF)
844f0a1913fSSubbaraya Sundeep 				return -EINVAL;
845dce677daSSubbaraya Sundeep 
846dce677daSSubbaraya Sundeep 			vlan_etype = be16_to_cpu(fsp->h_ext.vlan_etype);
847dce677daSSubbaraya Sundeep 			/* Only ETH_P_8021Q and ETH_P_802AD types supported */
848dce677daSSubbaraya Sundeep 			if (vlan_etype != ETH_P_8021Q &&
849dce677daSSubbaraya Sundeep 			    vlan_etype != ETH_P_8021AD)
850dce677daSSubbaraya Sundeep 				return -EINVAL;
851dce677daSSubbaraya Sundeep 
852dce677daSSubbaraya Sundeep 			memcpy(&pkt->vlan_etype, &fsp->h_ext.vlan_etype,
853dce677daSSubbaraya Sundeep 			       sizeof(pkt->vlan_etype));
854dce677daSSubbaraya Sundeep 			memcpy(&pmask->vlan_etype, &fsp->m_ext.vlan_etype,
855dce677daSSubbaraya Sundeep 			       sizeof(pmask->vlan_etype));
856dce677daSSubbaraya Sundeep 
857dce677daSSubbaraya Sundeep 			if (vlan_etype == ETH_P_8021Q)
858dce677daSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG);
859dce677daSSubbaraya Sundeep 			else
860dce677daSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_VLAN_ETYPE_STAG);
861dce677daSSubbaraya Sundeep 		}
862dce677daSSubbaraya Sundeep 
863f0a1913fSSubbaraya Sundeep 		if (fsp->m_ext.vlan_tci) {
864f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->vlan_tci, &fsp->h_ext.vlan_tci,
865f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->vlan_tci));
866f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->vlan_tci, &fsp->m_ext.vlan_tci,
867f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->vlan_tci));
868f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_OUTER_VID);
869f0a1913fSSubbaraya Sundeep 		}
870f0a1913fSSubbaraya Sundeep 
871f0a1913fSSubbaraya Sundeep 		/* Not Drop/Direct to queue but use action in default entry */
872f0a1913fSSubbaraya Sundeep 		if (fsp->m_ext.data[1] &&
873f0a1913fSSubbaraya Sundeep 		    fsp->h_ext.data[1] == cpu_to_be32(OTX2_DEFAULT_ACTION))
874f0a1913fSSubbaraya Sundeep 			req->op = NIX_RX_ACTION_DEFAULT;
875f0a1913fSSubbaraya Sundeep 	}
876f0a1913fSSubbaraya Sundeep 
877f0a1913fSSubbaraya Sundeep 	if (fsp->flow_type & FLOW_MAC_EXT &&
878f0a1913fSSubbaraya Sundeep 	    !is_zero_ether_addr(fsp->m_ext.h_dest)) {
879f0a1913fSSubbaraya Sundeep 		ether_addr_copy(pkt->dmac, fsp->h_ext.h_dest);
880f0a1913fSSubbaraya Sundeep 		ether_addr_copy(pmask->dmac, fsp->m_ext.h_dest);
881f0a1913fSSubbaraya Sundeep 		req->features |= BIT_ULL(NPC_DMAC);
882f0a1913fSSubbaraya Sundeep 	}
883f0a1913fSSubbaraya Sundeep 
884f0a1913fSSubbaraya Sundeep 	if (!req->features)
885f0a1913fSSubbaraya Sundeep 		return -EOPNOTSUPP;
886f0a1913fSSubbaraya Sundeep 
887f0a1913fSSubbaraya Sundeep 	return 0;
888f0a1913fSSubbaraya Sundeep }
889f0a1913fSSubbaraya Sundeep 
89079d2be38SHariprasad Kelam static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
89179d2be38SHariprasad Kelam 					struct ethtool_rx_flow_spec *fsp)
89279d2be38SHariprasad Kelam {
89379d2be38SHariprasad Kelam 	struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
89479d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
89579d2be38SHariprasad Kelam 	u64 ring_cookie = fsp->ring_cookie;
89679d2be38SHariprasad Kelam 	u32 flow_type;
89779d2be38SHariprasad Kelam 
89879d2be38SHariprasad Kelam 	if (!(pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT))
89979d2be38SHariprasad Kelam 		return false;
90079d2be38SHariprasad Kelam 
90179d2be38SHariprasad Kelam 	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
90279d2be38SHariprasad Kelam 
90379d2be38SHariprasad Kelam 	/* CGX/RPM block dmac filtering configured for white listing
90479d2be38SHariprasad Kelam 	 * check for action other than DROP
90579d2be38SHariprasad Kelam 	 */
90679d2be38SHariprasad Kelam 	if (flow_type == ETHER_FLOW && ring_cookie != RX_CLS_FLOW_DISC &&
90779d2be38SHariprasad Kelam 	    !ethtool_get_flow_spec_ring_vf(ring_cookie)) {
90879d2be38SHariprasad Kelam 		if (is_zero_ether_addr(eth_mask->h_dest) &&
90979d2be38SHariprasad Kelam 		    is_valid_ether_addr(eth_hdr->h_dest))
91079d2be38SHariprasad Kelam 			return true;
91179d2be38SHariprasad Kelam 	}
91279d2be38SHariprasad Kelam 
91379d2be38SHariprasad Kelam 	return false;
91479d2be38SHariprasad Kelam }
91579d2be38SHariprasad Kelam 
916f0a1913fSSubbaraya Sundeep static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
917f0a1913fSSubbaraya Sundeep {
918f0a1913fSSubbaraya Sundeep 	u64 ring_cookie = flow->flow_spec.ring_cookie;
9198e675581SHariprasad Kelam #ifdef CONFIG_DCB
9208e675581SHariprasad Kelam 	int vlan_prio, qidx, pfc_rule = 0;
9218e675581SHariprasad Kelam #endif
922f0a1913fSSubbaraya Sundeep 	struct npc_install_flow_req *req;
923f0a1913fSSubbaraya Sundeep 	int err, vf = 0;
924f0a1913fSSubbaraya Sundeep 
925f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
926f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
927f0a1913fSSubbaraya Sundeep 	if (!req) {
928f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
929f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
930f0a1913fSSubbaraya Sundeep 	}
931f0a1913fSSubbaraya Sundeep 
932f0a1913fSSubbaraya Sundeep 	err = otx2_prepare_flow_request(&flow->flow_spec, req);
933f0a1913fSSubbaraya Sundeep 	if (err) {
934f0a1913fSSubbaraya Sundeep 		/* free the allocated msg above */
935f0a1913fSSubbaraya Sundeep 		otx2_mbox_reset(&pfvf->mbox.mbox, 0);
936f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
937f0a1913fSSubbaraya Sundeep 		return err;
938f0a1913fSSubbaraya Sundeep 	}
939f0a1913fSSubbaraya Sundeep 
940f0a1913fSSubbaraya Sundeep 	req->entry = flow->entry;
941f0a1913fSSubbaraya Sundeep 	req->intf = NIX_INTF_RX;
942f0a1913fSSubbaraya Sundeep 	req->set_cntr = 1;
943f0a1913fSSubbaraya Sundeep 	req->channel = pfvf->hw.rx_chan_base;
944f0a1913fSSubbaraya Sundeep 	if (ring_cookie == RX_CLS_FLOW_DISC) {
945f0a1913fSSubbaraya Sundeep 		req->op = NIX_RX_ACTIONOP_DROP;
946f0a1913fSSubbaraya Sundeep 	} else {
947f0a1913fSSubbaraya Sundeep 		/* change to unicast only if action of default entry is not
948f0a1913fSSubbaraya Sundeep 		 * requested by user
949f0a1913fSSubbaraya Sundeep 		 */
95081a43620SGeetha sowjanya 		if (flow->flow_spec.flow_type & FLOW_RSS) {
95181a43620SGeetha sowjanya 			req->op = NIX_RX_ACTIONOP_RSS;
95281a43620SGeetha sowjanya 			req->index = flow->rss_ctx_id;
953e7938365SSunil Goutham 			req->flow_key_alg = pfvf->hw.flowkey_alg_idx;
95481a43620SGeetha sowjanya 		} else {
955f0a1913fSSubbaraya Sundeep 			req->op = NIX_RX_ACTIONOP_UCAST;
956f0a1913fSSubbaraya Sundeep 			req->index = ethtool_get_flow_spec_ring(ring_cookie);
95781a43620SGeetha sowjanya 		}
958f0a1913fSSubbaraya Sundeep 		vf = ethtool_get_flow_spec_ring_vf(ring_cookie);
959f0a1913fSSubbaraya Sundeep 		if (vf > pci_num_vf(pfvf->pdev)) {
960f0a1913fSSubbaraya Sundeep 			mutex_unlock(&pfvf->mbox.lock);
961f0a1913fSSubbaraya Sundeep 			return -EINVAL;
962f0a1913fSSubbaraya Sundeep 		}
9638e675581SHariprasad Kelam 
9648e675581SHariprasad Kelam #ifdef CONFIG_DCB
9658e675581SHariprasad Kelam 		/* Identify PFC rule if PFC enabled and ntuple rule is vlan */
9668e675581SHariprasad Kelam 		if (!vf && (req->features & BIT_ULL(NPC_OUTER_VID)) &&
9678e675581SHariprasad Kelam 		    pfvf->pfc_en && req->op != NIX_RX_ACTIONOP_RSS) {
9688e675581SHariprasad Kelam 			vlan_prio = ntohs(req->packet.vlan_tci) &
9698e675581SHariprasad Kelam 				    ntohs(req->mask.vlan_tci);
9708e675581SHariprasad Kelam 
9718e675581SHariprasad Kelam 			/* Get the priority */
9728e675581SHariprasad Kelam 			vlan_prio >>= 13;
9738e675581SHariprasad Kelam 			flow->rule_type |= PFC_FLOWCTRL_RULE;
9748e675581SHariprasad Kelam 			/* Check if PFC enabled for this priority */
9758e675581SHariprasad Kelam 			if (pfvf->pfc_en & BIT(vlan_prio)) {
9768e675581SHariprasad Kelam 				pfc_rule = true;
9778e675581SHariprasad Kelam 				qidx = req->index;
9788e675581SHariprasad Kelam 			}
9798e675581SHariprasad Kelam 		}
9808e675581SHariprasad Kelam #endif
981f0a1913fSSubbaraya Sundeep 	}
982f0a1913fSSubbaraya Sundeep 
983f0a1913fSSubbaraya Sundeep 	/* ethtool ring_cookie has (VF + 1) for VF */
984f0a1913fSSubbaraya Sundeep 	if (vf) {
985f0a1913fSSubbaraya Sundeep 		req->vf = vf;
986f0a1913fSSubbaraya Sundeep 		flow->is_vf = true;
987f0a1913fSSubbaraya Sundeep 		flow->vf = vf;
988f0a1913fSSubbaraya Sundeep 	}
989f0a1913fSSubbaraya Sundeep 
990f0a1913fSSubbaraya Sundeep 	/* Send message to AF */
991f0a1913fSSubbaraya Sundeep 	err = otx2_sync_mbox_msg(&pfvf->mbox);
9928e675581SHariprasad Kelam 
9938e675581SHariprasad Kelam #ifdef CONFIG_DCB
9948e675581SHariprasad Kelam 	if (!err && pfc_rule)
9958e675581SHariprasad Kelam 		otx2_update_bpid_in_rqctx(pfvf, vlan_prio, qidx, true);
9968e675581SHariprasad Kelam #endif
9978e675581SHariprasad Kelam 
998f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
999f0a1913fSSubbaraya Sundeep 	return err;
1000f0a1913fSSubbaraya Sundeep }
1001f0a1913fSSubbaraya Sundeep 
100279d2be38SHariprasad Kelam static int otx2_add_flow_with_pfmac(struct otx2_nic *pfvf,
100379d2be38SHariprasad Kelam 				    struct otx2_flow *flow)
100479d2be38SHariprasad Kelam {
100579d2be38SHariprasad Kelam 	struct otx2_flow *pf_mac;
100679d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr;
100779d2be38SHariprasad Kelam 
100879d2be38SHariprasad Kelam 	pf_mac = kzalloc(sizeof(*pf_mac), GFP_KERNEL);
100979d2be38SHariprasad Kelam 	if (!pf_mac)
101079d2be38SHariprasad Kelam 		return -ENOMEM;
101179d2be38SHariprasad Kelam 
101279d2be38SHariprasad Kelam 	pf_mac->entry = 0;
10138e675581SHariprasad Kelam 	pf_mac->rule_type |= DMAC_FILTER_RULE;
10142e2a8126SSunil Goutham 	pf_mac->location = pfvf->flow_cfg->max_flows;
101579d2be38SHariprasad Kelam 	memcpy(&pf_mac->flow_spec, &flow->flow_spec,
101679d2be38SHariprasad Kelam 	       sizeof(struct ethtool_rx_flow_spec));
101779d2be38SHariprasad Kelam 	pf_mac->flow_spec.location = pf_mac->location;
101879d2be38SHariprasad Kelam 
101979d2be38SHariprasad Kelam 	/* Copy PF mac address */
102079d2be38SHariprasad Kelam 	eth_hdr = &pf_mac->flow_spec.h_u.ether_spec;
102179d2be38SHariprasad Kelam 	ether_addr_copy(eth_hdr->h_dest, pfvf->netdev->dev_addr);
102279d2be38SHariprasad Kelam 
102379d2be38SHariprasad Kelam 	/* Install DMAC filter with PF mac address */
102479d2be38SHariprasad Kelam 	otx2_dmacflt_add(pfvf, eth_hdr->h_dest, 0);
102579d2be38SHariprasad Kelam 
102679d2be38SHariprasad Kelam 	otx2_add_flow_to_list(pfvf, pf_mac);
102779d2be38SHariprasad Kelam 	pfvf->flow_cfg->nr_flows++;
1028*fa5e0ccbSRatheesh Kannoth 	set_bit(0, pfvf->flow_cfg->dmacflt_bmap);
102979d2be38SHariprasad Kelam 
103079d2be38SHariprasad Kelam 	return 0;
103179d2be38SHariprasad Kelam }
103279d2be38SHariprasad Kelam 
103381a43620SGeetha sowjanya int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
1034f0a1913fSSubbaraya Sundeep {
1035f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
103681a43620SGeetha sowjanya 	struct ethtool_rx_flow_spec *fsp = &nfc->fs;
1037f0a1913fSSubbaraya Sundeep 	struct otx2_flow *flow;
103879d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr;
1039f0a1913fSSubbaraya Sundeep 	bool new = false;
104079d2be38SHariprasad Kelam 	int err = 0;
104181a43620SGeetha sowjanya 	u32 ring;
1042f0a1913fSSubbaraya Sundeep 
1043a515e5b5SSunil Goutham 	if (!flow_cfg->max_flows) {
1044a515e5b5SSunil Goutham 		netdev_err(pfvf->netdev,
1045a515e5b5SSunil Goutham 			   "Ntuple rule count is 0, allocate and retry\n");
1046a515e5b5SSunil Goutham 		return -EINVAL;
1047a515e5b5SSunil Goutham 	}
1048a515e5b5SSunil Goutham 
104981a43620SGeetha sowjanya 	ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
1050f0a1913fSSubbaraya Sundeep 	if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
1051f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
1052f0a1913fSSubbaraya Sundeep 
1053f0a1913fSSubbaraya Sundeep 	if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC)
1054f0a1913fSSubbaraya Sundeep 		return -EINVAL;
1055f0a1913fSSubbaraya Sundeep 
105679d2be38SHariprasad Kelam 	if (fsp->location >= otx2_get_maxflows(flow_cfg))
1057f0a1913fSSubbaraya Sundeep 		return -EINVAL;
1058f0a1913fSSubbaraya Sundeep 
1059f0a1913fSSubbaraya Sundeep 	flow = otx2_find_flow(pfvf, fsp->location);
1060f0a1913fSSubbaraya Sundeep 	if (!flow) {
106179d2be38SHariprasad Kelam 		flow = kzalloc(sizeof(*flow), GFP_KERNEL);
1062f0a1913fSSubbaraya Sundeep 		if (!flow)
1063f0a1913fSSubbaraya Sundeep 			return -ENOMEM;
1064f0a1913fSSubbaraya Sundeep 		flow->location = fsp->location;
1065dce677daSSubbaraya Sundeep 		flow->entry = flow_cfg->flow_ent[flow->location];
1066f0a1913fSSubbaraya Sundeep 		new = true;
1067f0a1913fSSubbaraya Sundeep 	}
1068f0a1913fSSubbaraya Sundeep 	/* struct copy */
1069f0a1913fSSubbaraya Sundeep 	flow->flow_spec = *fsp;
1070f0a1913fSSubbaraya Sundeep 
107181a43620SGeetha sowjanya 	if (fsp->flow_type & FLOW_RSS)
107281a43620SGeetha sowjanya 		flow->rss_ctx_id = nfc->rss_context;
107381a43620SGeetha sowjanya 
107479d2be38SHariprasad Kelam 	if (otx2_is_flow_rule_dmacfilter(pfvf, &flow->flow_spec)) {
107579d2be38SHariprasad Kelam 		eth_hdr = &flow->flow_spec.h_u.ether_spec;
107679d2be38SHariprasad Kelam 
107779d2be38SHariprasad Kelam 		/* Sync dmac filter table with updated fields */
10788e675581SHariprasad Kelam 		if (flow->rule_type & DMAC_FILTER_RULE)
107979d2be38SHariprasad Kelam 			return otx2_dmacflt_update(pfvf, eth_hdr->h_dest,
108079d2be38SHariprasad Kelam 						   flow->entry);
108179d2be38SHariprasad Kelam 
1082*fa5e0ccbSRatheesh Kannoth 		if (bitmap_full(flow_cfg->dmacflt_bmap,
108379d2be38SHariprasad Kelam 				flow_cfg->dmacflt_max_flows)) {
108479d2be38SHariprasad Kelam 			netdev_warn(pfvf->netdev,
108579d2be38SHariprasad Kelam 				    "Can't insert the rule %d as max allowed dmac filters are %d\n",
108679d2be38SHariprasad Kelam 				    flow->location +
108779d2be38SHariprasad Kelam 				    flow_cfg->dmacflt_max_flows,
108879d2be38SHariprasad Kelam 				    flow_cfg->dmacflt_max_flows);
108979d2be38SHariprasad Kelam 			err = -EINVAL;
109079d2be38SHariprasad Kelam 			if (new)
109179d2be38SHariprasad Kelam 				kfree(flow);
109279d2be38SHariprasad Kelam 			return err;
109379d2be38SHariprasad Kelam 		}
109479d2be38SHariprasad Kelam 
109579d2be38SHariprasad Kelam 		/* Install PF mac address to DMAC filter list */
1096*fa5e0ccbSRatheesh Kannoth 		if (!test_bit(0, flow_cfg->dmacflt_bmap))
109779d2be38SHariprasad Kelam 			otx2_add_flow_with_pfmac(pfvf, flow);
109879d2be38SHariprasad Kelam 
10998e675581SHariprasad Kelam 		flow->rule_type |= DMAC_FILTER_RULE;
1100*fa5e0ccbSRatheesh Kannoth 		flow->entry = find_first_zero_bit(flow_cfg->dmacflt_bmap,
110179d2be38SHariprasad Kelam 						  flow_cfg->dmacflt_max_flows);
11022e2a8126SSunil Goutham 		fsp->location = flow_cfg->max_flows + flow->entry;
110379d2be38SHariprasad Kelam 		flow->flow_spec.location = fsp->location;
110479d2be38SHariprasad Kelam 		flow->location = fsp->location;
110579d2be38SHariprasad Kelam 
1106*fa5e0ccbSRatheesh Kannoth 		set_bit(flow->entry, flow_cfg->dmacflt_bmap);
110779d2be38SHariprasad Kelam 		otx2_dmacflt_add(pfvf, eth_hdr->h_dest, flow->entry);
110879d2be38SHariprasad Kelam 
110979d2be38SHariprasad Kelam 	} else {
11102e2a8126SSunil Goutham 		if (flow->location >= pfvf->flow_cfg->max_flows) {
111179d2be38SHariprasad Kelam 			netdev_warn(pfvf->netdev,
111279d2be38SHariprasad Kelam 				    "Can't insert non dmac ntuple rule at %d, allowed range %d-0\n",
111379d2be38SHariprasad Kelam 				    flow->location,
11142e2a8126SSunil Goutham 				    flow_cfg->max_flows - 1);
111579d2be38SHariprasad Kelam 			err = -EINVAL;
111679d2be38SHariprasad Kelam 		} else {
1117f0a1913fSSubbaraya Sundeep 			err = otx2_add_flow_msg(pfvf, flow);
111879d2be38SHariprasad Kelam 		}
111979d2be38SHariprasad Kelam 	}
112079d2be38SHariprasad Kelam 
1121f0a1913fSSubbaraya Sundeep 	if (err) {
11223cffaed2SRakesh Babu 		if (err == MBOX_MSG_INVALID)
11233cffaed2SRakesh Babu 			err = -EINVAL;
1124f0a1913fSSubbaraya Sundeep 		if (new)
1125f0a1913fSSubbaraya Sundeep 			kfree(flow);
1126f0a1913fSSubbaraya Sundeep 		return err;
1127f0a1913fSSubbaraya Sundeep 	}
1128f0a1913fSSubbaraya Sundeep 
1129f0a1913fSSubbaraya Sundeep 	/* add the new flow installed to list */
1130f0a1913fSSubbaraya Sundeep 	if (new) {
1131f0a1913fSSubbaraya Sundeep 		otx2_add_flow_to_list(pfvf, flow);
1132f0a1913fSSubbaraya Sundeep 		flow_cfg->nr_flows++;
1133f0a1913fSSubbaraya Sundeep 	}
1134f0a1913fSSubbaraya Sundeep 
1135f0a1913fSSubbaraya Sundeep 	return 0;
1136f0a1913fSSubbaraya Sundeep }
1137f0a1913fSSubbaraya Sundeep 
1138f0a1913fSSubbaraya Sundeep static int otx2_remove_flow_msg(struct otx2_nic *pfvf, u16 entry, bool all)
1139f0a1913fSSubbaraya Sundeep {
1140f0a1913fSSubbaraya Sundeep 	struct npc_delete_flow_req *req;
1141f0a1913fSSubbaraya Sundeep 	int err;
1142f0a1913fSSubbaraya Sundeep 
1143f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
1144f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1145f0a1913fSSubbaraya Sundeep 	if (!req) {
1146f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
1147f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
1148f0a1913fSSubbaraya Sundeep 	}
1149f0a1913fSSubbaraya Sundeep 
1150f0a1913fSSubbaraya Sundeep 	req->entry = entry;
1151f0a1913fSSubbaraya Sundeep 	if (all)
1152f0a1913fSSubbaraya Sundeep 		req->all = 1;
1153f0a1913fSSubbaraya Sundeep 
1154f0a1913fSSubbaraya Sundeep 	/* Send message to AF */
1155f0a1913fSSubbaraya Sundeep 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1156f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
1157f0a1913fSSubbaraya Sundeep 	return err;
1158f0a1913fSSubbaraya Sundeep }
1159f0a1913fSSubbaraya Sundeep 
116079d2be38SHariprasad Kelam static void otx2_update_rem_pfmac(struct otx2_nic *pfvf, int req)
116179d2be38SHariprasad Kelam {
116279d2be38SHariprasad Kelam 	struct otx2_flow *iter;
116379d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr;
116479d2be38SHariprasad Kelam 	bool found = false;
116579d2be38SHariprasad Kelam 
116679d2be38SHariprasad Kelam 	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
11678e675581SHariprasad Kelam 		if ((iter->rule_type & DMAC_FILTER_RULE) && iter->entry == 0) {
116879d2be38SHariprasad Kelam 			eth_hdr = &iter->flow_spec.h_u.ether_spec;
116979d2be38SHariprasad Kelam 			if (req == DMAC_ADDR_DEL) {
117079d2be38SHariprasad Kelam 				otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
117179d2be38SHariprasad Kelam 						    0);
1172*fa5e0ccbSRatheesh Kannoth 				clear_bit(0, pfvf->flow_cfg->dmacflt_bmap);
117379d2be38SHariprasad Kelam 				found = true;
117479d2be38SHariprasad Kelam 			} else {
117579d2be38SHariprasad Kelam 				ether_addr_copy(eth_hdr->h_dest,
117679d2be38SHariprasad Kelam 						pfvf->netdev->dev_addr);
1177*fa5e0ccbSRatheesh Kannoth 
117879d2be38SHariprasad Kelam 				otx2_dmacflt_update(pfvf, eth_hdr->h_dest, 0);
117979d2be38SHariprasad Kelam 			}
118079d2be38SHariprasad Kelam 			break;
118179d2be38SHariprasad Kelam 		}
118279d2be38SHariprasad Kelam 	}
118379d2be38SHariprasad Kelam 
118479d2be38SHariprasad Kelam 	if (found) {
118579d2be38SHariprasad Kelam 		list_del(&iter->list);
118679d2be38SHariprasad Kelam 		kfree(iter);
118779d2be38SHariprasad Kelam 		pfvf->flow_cfg->nr_flows--;
118879d2be38SHariprasad Kelam 	}
118979d2be38SHariprasad Kelam }
119079d2be38SHariprasad Kelam 
1191f0a1913fSSubbaraya Sundeep int otx2_remove_flow(struct otx2_nic *pfvf, u32 location)
1192f0a1913fSSubbaraya Sundeep {
1193f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1194f0a1913fSSubbaraya Sundeep 	struct otx2_flow *flow;
1195f0a1913fSSubbaraya Sundeep 	int err;
1196f0a1913fSSubbaraya Sundeep 
119779d2be38SHariprasad Kelam 	if (location >= otx2_get_maxflows(flow_cfg))
1198f0a1913fSSubbaraya Sundeep 		return -EINVAL;
1199f0a1913fSSubbaraya Sundeep 
1200f0a1913fSSubbaraya Sundeep 	flow = otx2_find_flow(pfvf, location);
1201f0a1913fSSubbaraya Sundeep 	if (!flow)
1202f0a1913fSSubbaraya Sundeep 		return -ENOENT;
1203f0a1913fSSubbaraya Sundeep 
12048e675581SHariprasad Kelam 	if (flow->rule_type & DMAC_FILTER_RULE) {
120579d2be38SHariprasad Kelam 		struct ethhdr *eth_hdr = &flow->flow_spec.h_u.ether_spec;
120679d2be38SHariprasad Kelam 
120779d2be38SHariprasad Kelam 		/* user not allowed to remove dmac filter with interface mac */
120879d2be38SHariprasad Kelam 		if (ether_addr_equal(pfvf->netdev->dev_addr, eth_hdr->h_dest))
120979d2be38SHariprasad Kelam 			return -EPERM;
121079d2be38SHariprasad Kelam 
121179d2be38SHariprasad Kelam 		err = otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
121279d2be38SHariprasad Kelam 					  flow->entry);
1213*fa5e0ccbSRatheesh Kannoth 		clear_bit(flow->entry, flow_cfg->dmacflt_bmap);
121479d2be38SHariprasad Kelam 		/* If all dmac filters are removed delete macfilter with
121579d2be38SHariprasad Kelam 		 * interface mac address and configure CGX/RPM block in
121679d2be38SHariprasad Kelam 		 * promiscuous mode
121779d2be38SHariprasad Kelam 		 */
1218*fa5e0ccbSRatheesh Kannoth 		if (bitmap_weight(flow_cfg->dmacflt_bmap,
121979d2be38SHariprasad Kelam 				  flow_cfg->dmacflt_max_flows) == 1)
122079d2be38SHariprasad Kelam 			otx2_update_rem_pfmac(pfvf, DMAC_ADDR_DEL);
122179d2be38SHariprasad Kelam 	} else {
12228e675581SHariprasad Kelam #ifdef CONFIG_DCB
12238e675581SHariprasad Kelam 		if (flow->rule_type & PFC_FLOWCTRL_RULE)
12248e675581SHariprasad Kelam 			otx2_update_bpid_in_rqctx(pfvf, 0,
12258e675581SHariprasad Kelam 						  flow->flow_spec.ring_cookie,
12268e675581SHariprasad Kelam 						  false);
12278e675581SHariprasad Kelam #endif
12288e675581SHariprasad Kelam 
1229f0a1913fSSubbaraya Sundeep 		err = otx2_remove_flow_msg(pfvf, flow->entry, false);
123079d2be38SHariprasad Kelam 	}
123179d2be38SHariprasad Kelam 
1232f0a1913fSSubbaraya Sundeep 	if (err)
1233f0a1913fSSubbaraya Sundeep 		return err;
1234f0a1913fSSubbaraya Sundeep 
1235f0a1913fSSubbaraya Sundeep 	list_del(&flow->list);
1236f0a1913fSSubbaraya Sundeep 	kfree(flow);
1237f0a1913fSSubbaraya Sundeep 	flow_cfg->nr_flows--;
1238f0a1913fSSubbaraya Sundeep 
1239f0a1913fSSubbaraya Sundeep 	return 0;
1240f0a1913fSSubbaraya Sundeep }
1241f0a1913fSSubbaraya Sundeep 
124281a43620SGeetha sowjanya void otx2_rss_ctx_flow_del(struct otx2_nic *pfvf, int ctx_id)
124381a43620SGeetha sowjanya {
124481a43620SGeetha sowjanya 	struct otx2_flow *flow, *tmp;
124581a43620SGeetha sowjanya 	int err;
124681a43620SGeetha sowjanya 
124781a43620SGeetha sowjanya 	list_for_each_entry_safe(flow, tmp, &pfvf->flow_cfg->flow_list, list) {
124881a43620SGeetha sowjanya 		if (flow->rss_ctx_id != ctx_id)
124981a43620SGeetha sowjanya 			continue;
125081a43620SGeetha sowjanya 		err = otx2_remove_flow(pfvf, flow->location);
125181a43620SGeetha sowjanya 		if (err)
125281a43620SGeetha sowjanya 			netdev_warn(pfvf->netdev,
125381a43620SGeetha sowjanya 				    "Can't delete the rule %d associated with this rss group err:%d",
125481a43620SGeetha sowjanya 				    flow->location, err);
125581a43620SGeetha sowjanya 	}
125681a43620SGeetha sowjanya }
125781a43620SGeetha sowjanya 
1258f0a1913fSSubbaraya Sundeep int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf)
1259f0a1913fSSubbaraya Sundeep {
1260f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1261f0a1913fSSubbaraya Sundeep 	struct npc_delete_flow_req *req;
1262f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter, *tmp;
1263f0a1913fSSubbaraya Sundeep 	int err;
1264f0a1913fSSubbaraya Sundeep 
1265f0a1913fSSubbaraya Sundeep 	if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
1266f0a1913fSSubbaraya Sundeep 		return 0;
1267f0a1913fSSubbaraya Sundeep 
1268a515e5b5SSunil Goutham 	if (!flow_cfg->max_flows)
1269a515e5b5SSunil Goutham 		return 0;
1270a515e5b5SSunil Goutham 
1271f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
1272f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1273f0a1913fSSubbaraya Sundeep 	if (!req) {
1274f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
1275f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
1276f0a1913fSSubbaraya Sundeep 	}
1277f0a1913fSSubbaraya Sundeep 
12789917060fSSunil Goutham 	req->start = flow_cfg->flow_ent[0];
12792e2a8126SSunil Goutham 	req->end   = flow_cfg->flow_ent[flow_cfg->max_flows - 1];
1280f0a1913fSSubbaraya Sundeep 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1281f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
1282f0a1913fSSubbaraya Sundeep 
1283f0a1913fSSubbaraya Sundeep 	list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) {
1284f0a1913fSSubbaraya Sundeep 		list_del(&iter->list);
1285f0a1913fSSubbaraya Sundeep 		kfree(iter);
1286f0a1913fSSubbaraya Sundeep 		flow_cfg->nr_flows--;
1287f0a1913fSSubbaraya Sundeep 	}
1288f0a1913fSSubbaraya Sundeep 	return err;
1289f0a1913fSSubbaraya Sundeep }
1290f0a1913fSSubbaraya Sundeep 
1291f0a1913fSSubbaraya Sundeep int otx2_destroy_mcam_flows(struct otx2_nic *pfvf)
1292f0a1913fSSubbaraya Sundeep {
1293f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1294f0a1913fSSubbaraya Sundeep 	struct npc_mcam_free_entry_req *req;
1295f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter, *tmp;
1296f0a1913fSSubbaraya Sundeep 	int err;
1297f0a1913fSSubbaraya Sundeep 
1298f0a1913fSSubbaraya Sundeep 	if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
1299f0a1913fSSubbaraya Sundeep 		return 0;
1300f0a1913fSSubbaraya Sundeep 
1301f0a1913fSSubbaraya Sundeep 	/* remove all flows */
1302f0a1913fSSubbaraya Sundeep 	err = otx2_remove_flow_msg(pfvf, 0, true);
1303f0a1913fSSubbaraya Sundeep 	if (err)
1304f0a1913fSSubbaraya Sundeep 		return err;
1305f0a1913fSSubbaraya Sundeep 
1306f0a1913fSSubbaraya Sundeep 	list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) {
1307f0a1913fSSubbaraya Sundeep 		list_del(&iter->list);
1308f0a1913fSSubbaraya Sundeep 		kfree(iter);
1309f0a1913fSSubbaraya Sundeep 		flow_cfg->nr_flows--;
1310f0a1913fSSubbaraya Sundeep 	}
1311f0a1913fSSubbaraya Sundeep 
1312f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
1313f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_mcam_free_entry(&pfvf->mbox);
1314f0a1913fSSubbaraya Sundeep 	if (!req) {
1315f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
1316f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
1317f0a1913fSSubbaraya Sundeep 	}
1318f0a1913fSSubbaraya Sundeep 
1319f0a1913fSSubbaraya Sundeep 	req->all = 1;
1320f0a1913fSSubbaraya Sundeep 	/* Send message to AF to free MCAM entries */
1321f0a1913fSSubbaraya Sundeep 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1322f0a1913fSSubbaraya Sundeep 	if (err) {
1323f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
1324f0a1913fSSubbaraya Sundeep 		return err;
1325f0a1913fSSubbaraya Sundeep 	}
1326f0a1913fSSubbaraya Sundeep 
1327f0a1913fSSubbaraya Sundeep 	pfvf->flags &= ~OTX2_FLAG_MCAM_ENTRIES_ALLOC;
1328f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
1329f0a1913fSSubbaraya Sundeep 
1330f0a1913fSSubbaraya Sundeep 	return 0;
1331f0a1913fSSubbaraya Sundeep }
1332fd9d7859SHariprasad Kelam 
1333fd9d7859SHariprasad Kelam int otx2_install_rxvlan_offload_flow(struct otx2_nic *pfvf)
1334fd9d7859SHariprasad Kelam {
1335fd9d7859SHariprasad Kelam 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1336fd9d7859SHariprasad Kelam 	struct npc_install_flow_req *req;
1337fd9d7859SHariprasad Kelam 	int err;
1338fd9d7859SHariprasad Kelam 
1339fd9d7859SHariprasad Kelam 	mutex_lock(&pfvf->mbox.lock);
1340fd9d7859SHariprasad Kelam 	req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
1341fd9d7859SHariprasad Kelam 	if (!req) {
1342fd9d7859SHariprasad Kelam 		mutex_unlock(&pfvf->mbox.lock);
1343fd9d7859SHariprasad Kelam 		return -ENOMEM;
1344fd9d7859SHariprasad Kelam 	}
1345fd9d7859SHariprasad Kelam 
13469917060fSSunil Goutham 	req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
1347fd9d7859SHariprasad Kelam 	req->intf = NIX_INTF_RX;
1348fd9d7859SHariprasad Kelam 	ether_addr_copy(req->packet.dmac, pfvf->netdev->dev_addr);
1349fd9d7859SHariprasad Kelam 	eth_broadcast_addr((u8 *)&req->mask.dmac);
1350fd9d7859SHariprasad Kelam 	req->channel = pfvf->hw.rx_chan_base;
1351fd9d7859SHariprasad Kelam 	req->op = NIX_RX_ACTION_DEFAULT;
1352fd9d7859SHariprasad Kelam 	req->features = BIT_ULL(NPC_OUTER_VID) | BIT_ULL(NPC_DMAC);
1353fd9d7859SHariprasad Kelam 	req->vtag0_valid = true;
1354fd9d7859SHariprasad Kelam 	req->vtag0_type = NIX_AF_LFX_RX_VTAG_TYPE0;
1355fd9d7859SHariprasad Kelam 
1356fd9d7859SHariprasad Kelam 	/* Send message to AF */
1357fd9d7859SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1358fd9d7859SHariprasad Kelam 	mutex_unlock(&pfvf->mbox.lock);
1359fd9d7859SHariprasad Kelam 	return err;
1360fd9d7859SHariprasad Kelam }
1361fd9d7859SHariprasad Kelam 
1362fd9d7859SHariprasad Kelam static int otx2_delete_rxvlan_offload_flow(struct otx2_nic *pfvf)
1363fd9d7859SHariprasad Kelam {
1364fd9d7859SHariprasad Kelam 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1365fd9d7859SHariprasad Kelam 	struct npc_delete_flow_req *req;
1366fd9d7859SHariprasad Kelam 	int err;
1367fd9d7859SHariprasad Kelam 
1368fd9d7859SHariprasad Kelam 	mutex_lock(&pfvf->mbox.lock);
1369fd9d7859SHariprasad Kelam 	req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1370fd9d7859SHariprasad Kelam 	if (!req) {
1371fd9d7859SHariprasad Kelam 		mutex_unlock(&pfvf->mbox.lock);
1372fd9d7859SHariprasad Kelam 		return -ENOMEM;
1373fd9d7859SHariprasad Kelam 	}
1374fd9d7859SHariprasad Kelam 
13759917060fSSunil Goutham 	req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
1376fd9d7859SHariprasad Kelam 	/* Send message to AF */
1377fd9d7859SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1378fd9d7859SHariprasad Kelam 	mutex_unlock(&pfvf->mbox.lock);
1379fd9d7859SHariprasad Kelam 	return err;
1380fd9d7859SHariprasad Kelam }
1381fd9d7859SHariprasad Kelam 
1382fd9d7859SHariprasad Kelam int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable)
1383fd9d7859SHariprasad Kelam {
1384fd9d7859SHariprasad Kelam 	struct nix_vtag_config *req;
1385fd9d7859SHariprasad Kelam 	struct mbox_msghdr *rsp_hdr;
1386fd9d7859SHariprasad Kelam 	int err;
1387fd9d7859SHariprasad Kelam 
1388fd9d7859SHariprasad Kelam 	/* Dont have enough mcam entries */
1389fd9d7859SHariprasad Kelam 	if (!(pf->flags & OTX2_FLAG_RX_VLAN_SUPPORT))
1390fd9d7859SHariprasad Kelam 		return -ENOMEM;
1391fd9d7859SHariprasad Kelam 
1392fd9d7859SHariprasad Kelam 	if (enable) {
1393fd9d7859SHariprasad Kelam 		err = otx2_install_rxvlan_offload_flow(pf);
1394fd9d7859SHariprasad Kelam 		if (err)
1395fd9d7859SHariprasad Kelam 			return err;
1396fd9d7859SHariprasad Kelam 	} else {
1397fd9d7859SHariprasad Kelam 		err = otx2_delete_rxvlan_offload_flow(pf);
1398fd9d7859SHariprasad Kelam 		if (err)
1399fd9d7859SHariprasad Kelam 			return err;
1400fd9d7859SHariprasad Kelam 	}
1401fd9d7859SHariprasad Kelam 
1402fd9d7859SHariprasad Kelam 	mutex_lock(&pf->mbox.lock);
1403fd9d7859SHariprasad Kelam 	req = otx2_mbox_alloc_msg_nix_vtag_cfg(&pf->mbox);
1404fd9d7859SHariprasad Kelam 	if (!req) {
1405fd9d7859SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
1406fd9d7859SHariprasad Kelam 		return -ENOMEM;
1407fd9d7859SHariprasad Kelam 	}
1408fd9d7859SHariprasad Kelam 
1409fd9d7859SHariprasad Kelam 	/* config strip, capture and size */
1410fd9d7859SHariprasad Kelam 	req->vtag_size = VTAGSIZE_T4;
1411fd9d7859SHariprasad Kelam 	req->cfg_type = 1; /* rx vlan cfg */
1412fd9d7859SHariprasad Kelam 	req->rx.vtag_type = NIX_AF_LFX_RX_VTAG_TYPE0;
1413fd9d7859SHariprasad Kelam 	req->rx.strip_vtag = enable;
1414fd9d7859SHariprasad Kelam 	req->rx.capture_vtag = enable;
1415fd9d7859SHariprasad Kelam 
1416fd9d7859SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pf->mbox);
1417fd9d7859SHariprasad Kelam 	if (err) {
1418fd9d7859SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
1419fd9d7859SHariprasad Kelam 		return err;
1420fd9d7859SHariprasad Kelam 	}
1421fd9d7859SHariprasad Kelam 
1422fd9d7859SHariprasad Kelam 	rsp_hdr = otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr);
1423fd9d7859SHariprasad Kelam 	if (IS_ERR(rsp_hdr)) {
1424fd9d7859SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
1425fd9d7859SHariprasad Kelam 		return PTR_ERR(rsp_hdr);
1426fd9d7859SHariprasad Kelam 	}
1427fd9d7859SHariprasad Kelam 
1428fd9d7859SHariprasad Kelam 	mutex_unlock(&pf->mbox.lock);
1429fd9d7859SHariprasad Kelam 	return rsp_hdr->rc;
1430fd9d7859SHariprasad Kelam }
143179d2be38SHariprasad Kelam 
143279d2be38SHariprasad Kelam void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf)
143379d2be38SHariprasad Kelam {
143479d2be38SHariprasad Kelam 	struct otx2_flow *iter;
143579d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr;
143679d2be38SHariprasad Kelam 
143779d2be38SHariprasad Kelam 	list_for_each_entry(iter, &pf->flow_cfg->flow_list, list) {
14388e675581SHariprasad Kelam 		if (iter->rule_type & DMAC_FILTER_RULE) {
143979d2be38SHariprasad Kelam 			eth_hdr = &iter->flow_spec.h_u.ether_spec;
144079d2be38SHariprasad Kelam 			otx2_dmacflt_add(pf, eth_hdr->h_dest,
144179d2be38SHariprasad Kelam 					 iter->entry);
144279d2be38SHariprasad Kelam 		}
144379d2be38SHariprasad Kelam 	}
144479d2be38SHariprasad Kelam }
144579d2be38SHariprasad Kelam 
144679d2be38SHariprasad Kelam void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf)
144779d2be38SHariprasad Kelam {
144879d2be38SHariprasad Kelam 	otx2_update_rem_pfmac(pfvf, DMAC_ADDR_UPDATE);
144979d2be38SHariprasad Kelam }
1450