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;
21f0a1913fSSubbaraya Sundeep 	u16 entry;
22f0a1913fSSubbaraya Sundeep 	bool is_vf;
2381a43620SGeetha sowjanya 	u8 rss_ctx_id;
24*8e675581SHariprasad Kelam #define DMAC_FILTER_RULE		BIT(0)
25*8e675581SHariprasad Kelam #define PFC_FLOWCTRL_RULE		BIT(1)
26*8e675581SHariprasad 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 
2353cffaed2SRakesh Babu int otx2vf_mcam_flow_init(struct otx2_nic *pfvf)
2363cffaed2SRakesh Babu {
2373cffaed2SRakesh Babu 	struct otx2_flow_config *flow_cfg;
2383cffaed2SRakesh Babu 
2393cffaed2SRakesh Babu 	pfvf->flow_cfg = devm_kzalloc(pfvf->dev,
2403cffaed2SRakesh Babu 				      sizeof(struct otx2_flow_config),
2413cffaed2SRakesh Babu 				      GFP_KERNEL);
2423cffaed2SRakesh Babu 	if (!pfvf->flow_cfg)
2433cffaed2SRakesh Babu 		return -ENOMEM;
2443cffaed2SRakesh Babu 
2453cffaed2SRakesh Babu 	flow_cfg = pfvf->flow_cfg;
2463cffaed2SRakesh Babu 	INIT_LIST_HEAD(&flow_cfg->flow_list);
2472e2a8126SSunil Goutham 	flow_cfg->max_flows = 0;
2483cffaed2SRakesh Babu 
2493cffaed2SRakesh Babu 	return 0;
2503cffaed2SRakesh Babu }
2513cffaed2SRakesh Babu EXPORT_SYMBOL(otx2vf_mcam_flow_init);
2523cffaed2SRakesh Babu 
253f0a1913fSSubbaraya Sundeep int otx2_mcam_flow_init(struct otx2_nic *pf)
254f0a1913fSSubbaraya Sundeep {
255f0a1913fSSubbaraya Sundeep 	int err;
256f0a1913fSSubbaraya Sundeep 
257f0a1913fSSubbaraya Sundeep 	pf->flow_cfg = devm_kzalloc(pf->dev, sizeof(struct otx2_flow_config),
258f0a1913fSSubbaraya Sundeep 				    GFP_KERNEL);
259f0a1913fSSubbaraya Sundeep 	if (!pf->flow_cfg)
260f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
261f0a1913fSSubbaraya Sundeep 
262f0a1913fSSubbaraya Sundeep 	INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
263f0a1913fSSubbaraya Sundeep 
2642da48943SSunil Goutham 	/* Allocate bare minimum number of MCAM entries needed for
2652da48943SSunil Goutham 	 * unicast and ntuple filters.
2662da48943SSunil Goutham 	 */
2672da48943SSunil Goutham 	err = otx2_mcam_entry_init(pf);
268f0a1913fSSubbaraya Sundeep 	if (err)
269f0a1913fSSubbaraya Sundeep 		return err;
270f0a1913fSSubbaraya Sundeep 
2719917060fSSunil Goutham 	/* Check if MCAM entries are allocate or not */
2729917060fSSunil Goutham 	if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
2739917060fSSunil Goutham 		return 0;
2749917060fSSunil Goutham 
27563ee5157SHariprasad Kelam 	pf->mac_table = devm_kzalloc(pf->dev, sizeof(struct otx2_mac_table)
27663ee5157SHariprasad Kelam 					* OTX2_MAX_UNICAST_FLOWS, GFP_KERNEL);
27763ee5157SHariprasad Kelam 	if (!pf->mac_table)
27863ee5157SHariprasad Kelam 		return -ENOMEM;
27963ee5157SHariprasad Kelam 
28079d2be38SHariprasad Kelam 	otx2_dmacflt_get_max_cnt(pf);
28179d2be38SHariprasad Kelam 
28279d2be38SHariprasad Kelam 	/* DMAC filters are not allocated */
28379d2be38SHariprasad Kelam 	if (!pf->flow_cfg->dmacflt_max_flows)
28479d2be38SHariprasad Kelam 		return 0;
28579d2be38SHariprasad Kelam 
28679d2be38SHariprasad Kelam 	pf->flow_cfg->bmap_to_dmacindex =
28779d2be38SHariprasad Kelam 			devm_kzalloc(pf->dev, sizeof(u8) *
28879d2be38SHariprasad Kelam 				     pf->flow_cfg->dmacflt_max_flows,
28979d2be38SHariprasad Kelam 				     GFP_KERNEL);
29079d2be38SHariprasad Kelam 
29179d2be38SHariprasad Kelam 	if (!pf->flow_cfg->bmap_to_dmacindex)
29279d2be38SHariprasad Kelam 		return -ENOMEM;
29379d2be38SHariprasad Kelam 
29479d2be38SHariprasad Kelam 	pf->flags |= OTX2_FLAG_DMACFLTR_SUPPORT;
29579d2be38SHariprasad Kelam 
296f0a1913fSSubbaraya Sundeep 	return 0;
297f0a1913fSSubbaraya Sundeep }
298f0a1913fSSubbaraya Sundeep 
299f0a1913fSSubbaraya Sundeep void otx2_mcam_flow_del(struct otx2_nic *pf)
300f0a1913fSSubbaraya Sundeep {
301f0a1913fSSubbaraya Sundeep 	otx2_destroy_mcam_flows(pf);
302f0a1913fSSubbaraya Sundeep }
3033cffaed2SRakesh Babu EXPORT_SYMBOL(otx2_mcam_flow_del);
304f0a1913fSSubbaraya Sundeep 
30563ee5157SHariprasad Kelam /*  On success adds mcam entry
30663ee5157SHariprasad Kelam  *  On failure enable promisous mode
30763ee5157SHariprasad Kelam  */
30863ee5157SHariprasad Kelam static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac)
30963ee5157SHariprasad Kelam {
31063ee5157SHariprasad Kelam 	struct otx2_flow_config *flow_cfg = pf->flow_cfg;
31163ee5157SHariprasad Kelam 	struct npc_install_flow_req *req;
31263ee5157SHariprasad Kelam 	int err, i;
31363ee5157SHariprasad Kelam 
31463ee5157SHariprasad Kelam 	if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
31563ee5157SHariprasad Kelam 		return -ENOMEM;
31663ee5157SHariprasad Kelam 
31763ee5157SHariprasad Kelam 	/* dont have free mcam entries or uc list is greater than alloted */
31863ee5157SHariprasad Kelam 	if (netdev_uc_count(pf->netdev) > OTX2_MAX_UNICAST_FLOWS)
31963ee5157SHariprasad Kelam 		return -ENOMEM;
32063ee5157SHariprasad Kelam 
32163ee5157SHariprasad Kelam 	mutex_lock(&pf->mbox.lock);
32263ee5157SHariprasad Kelam 	req = otx2_mbox_alloc_msg_npc_install_flow(&pf->mbox);
32363ee5157SHariprasad Kelam 	if (!req) {
32463ee5157SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
32563ee5157SHariprasad Kelam 		return -ENOMEM;
32663ee5157SHariprasad Kelam 	}
32763ee5157SHariprasad Kelam 
32863ee5157SHariprasad Kelam 	/* unicast offset starts with 32 0..31 for ntuple */
32963ee5157SHariprasad Kelam 	for (i = 0; i <  OTX2_MAX_UNICAST_FLOWS; i++) {
33063ee5157SHariprasad Kelam 		if (pf->mac_table[i].inuse)
33163ee5157SHariprasad Kelam 			continue;
33263ee5157SHariprasad Kelam 		ether_addr_copy(pf->mac_table[i].addr, mac);
33363ee5157SHariprasad Kelam 		pf->mac_table[i].inuse = true;
33463ee5157SHariprasad Kelam 		pf->mac_table[i].mcam_entry =
3359917060fSSunil Goutham 			flow_cfg->def_ent[i + flow_cfg->unicast_offset];
33663ee5157SHariprasad Kelam 		req->entry =  pf->mac_table[i].mcam_entry;
33763ee5157SHariprasad Kelam 		break;
33863ee5157SHariprasad Kelam 	}
33963ee5157SHariprasad Kelam 
34063ee5157SHariprasad Kelam 	ether_addr_copy(req->packet.dmac, mac);
34163ee5157SHariprasad Kelam 	eth_broadcast_addr((u8 *)&req->mask.dmac);
34263ee5157SHariprasad Kelam 	req->features = BIT_ULL(NPC_DMAC);
34363ee5157SHariprasad Kelam 	req->channel = pf->hw.rx_chan_base;
34463ee5157SHariprasad Kelam 	req->intf = NIX_INTF_RX;
34563ee5157SHariprasad Kelam 	req->op = NIX_RX_ACTION_DEFAULT;
34663ee5157SHariprasad Kelam 	req->set_cntr = 1;
34763ee5157SHariprasad Kelam 
34863ee5157SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pf->mbox);
34963ee5157SHariprasad Kelam 	mutex_unlock(&pf->mbox.lock);
35063ee5157SHariprasad Kelam 
35163ee5157SHariprasad Kelam 	return err;
35263ee5157SHariprasad Kelam }
35363ee5157SHariprasad Kelam 
35463ee5157SHariprasad Kelam int otx2_add_macfilter(struct net_device *netdev, const u8 *mac)
35563ee5157SHariprasad Kelam {
35663ee5157SHariprasad Kelam 	struct otx2_nic *pf = netdev_priv(netdev);
35763ee5157SHariprasad Kelam 
35879d2be38SHariprasad Kelam 	if (bitmap_weight(&pf->flow_cfg->dmacflt_bmap,
35979d2be38SHariprasad Kelam 			  pf->flow_cfg->dmacflt_max_flows))
36079d2be38SHariprasad Kelam 		netdev_warn(netdev,
36179d2be38SHariprasad Kelam 			    "Add %pM to CGX/RPM DMAC filters list as well\n",
36279d2be38SHariprasad Kelam 			    mac);
36379d2be38SHariprasad Kelam 
36463ee5157SHariprasad Kelam 	return otx2_do_add_macfilter(pf, mac);
36563ee5157SHariprasad Kelam }
36663ee5157SHariprasad Kelam 
36763ee5157SHariprasad Kelam static bool otx2_get_mcamentry_for_mac(struct otx2_nic *pf, const u8 *mac,
36863ee5157SHariprasad Kelam 				       int *mcam_entry)
36963ee5157SHariprasad Kelam {
37063ee5157SHariprasad Kelam 	int i;
37163ee5157SHariprasad Kelam 
37263ee5157SHariprasad Kelam 	for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) {
37363ee5157SHariprasad Kelam 		if (!pf->mac_table[i].inuse)
37463ee5157SHariprasad Kelam 			continue;
37563ee5157SHariprasad Kelam 
37663ee5157SHariprasad Kelam 		if (ether_addr_equal(pf->mac_table[i].addr, mac)) {
37763ee5157SHariprasad Kelam 			*mcam_entry = pf->mac_table[i].mcam_entry;
37863ee5157SHariprasad Kelam 			pf->mac_table[i].inuse = false;
37963ee5157SHariprasad Kelam 			return true;
38063ee5157SHariprasad Kelam 		}
38163ee5157SHariprasad Kelam 	}
38263ee5157SHariprasad Kelam 	return false;
38363ee5157SHariprasad Kelam }
38463ee5157SHariprasad Kelam 
38563ee5157SHariprasad Kelam int otx2_del_macfilter(struct net_device *netdev, const u8 *mac)
38663ee5157SHariprasad Kelam {
38763ee5157SHariprasad Kelam 	struct otx2_nic *pf = netdev_priv(netdev);
38863ee5157SHariprasad Kelam 	struct npc_delete_flow_req *req;
38963ee5157SHariprasad Kelam 	int err, mcam_entry;
39063ee5157SHariprasad Kelam 
39163ee5157SHariprasad Kelam 	/* check does mcam entry exists for given mac */
39263ee5157SHariprasad Kelam 	if (!otx2_get_mcamentry_for_mac(pf, mac, &mcam_entry))
39363ee5157SHariprasad Kelam 		return 0;
39463ee5157SHariprasad Kelam 
39563ee5157SHariprasad Kelam 	mutex_lock(&pf->mbox.lock);
39663ee5157SHariprasad Kelam 	req = otx2_mbox_alloc_msg_npc_delete_flow(&pf->mbox);
39763ee5157SHariprasad Kelam 	if (!req) {
39863ee5157SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
39963ee5157SHariprasad Kelam 		return -ENOMEM;
40063ee5157SHariprasad Kelam 	}
40163ee5157SHariprasad Kelam 	req->entry = mcam_entry;
40263ee5157SHariprasad Kelam 	/* Send message to AF */
40363ee5157SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pf->mbox);
40463ee5157SHariprasad Kelam 	mutex_unlock(&pf->mbox.lock);
40563ee5157SHariprasad Kelam 
40663ee5157SHariprasad Kelam 	return err;
40763ee5157SHariprasad Kelam }
40863ee5157SHariprasad Kelam 
409f0a1913fSSubbaraya Sundeep static struct otx2_flow *otx2_find_flow(struct otx2_nic *pfvf, u32 location)
410f0a1913fSSubbaraya Sundeep {
411f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter;
412f0a1913fSSubbaraya Sundeep 
413f0a1913fSSubbaraya Sundeep 	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
414f0a1913fSSubbaraya Sundeep 		if (iter->location == location)
415f0a1913fSSubbaraya Sundeep 			return iter;
416f0a1913fSSubbaraya Sundeep 	}
417f0a1913fSSubbaraya Sundeep 
418f0a1913fSSubbaraya Sundeep 	return NULL;
419f0a1913fSSubbaraya Sundeep }
420f0a1913fSSubbaraya Sundeep 
421f0a1913fSSubbaraya Sundeep static void otx2_add_flow_to_list(struct otx2_nic *pfvf, struct otx2_flow *flow)
422f0a1913fSSubbaraya Sundeep {
423f0a1913fSSubbaraya Sundeep 	struct list_head *head = &pfvf->flow_cfg->flow_list;
424f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter;
425f0a1913fSSubbaraya Sundeep 
426f0a1913fSSubbaraya Sundeep 	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
427f0a1913fSSubbaraya Sundeep 		if (iter->location > flow->location)
428f0a1913fSSubbaraya Sundeep 			break;
429f0a1913fSSubbaraya Sundeep 		head = &iter->list;
430f0a1913fSSubbaraya Sundeep 	}
431f0a1913fSSubbaraya Sundeep 
432f0a1913fSSubbaraya Sundeep 	list_add(&flow->list, head);
433f0a1913fSSubbaraya Sundeep }
434f0a1913fSSubbaraya Sundeep 
4353cffaed2SRakesh Babu int otx2_get_maxflows(struct otx2_flow_config *flow_cfg)
43679d2be38SHariprasad Kelam {
4373cffaed2SRakesh Babu 	if (!flow_cfg)
4383cffaed2SRakesh Babu 		return 0;
4393cffaed2SRakesh Babu 
4402e2a8126SSunil Goutham 	if (flow_cfg->nr_flows == flow_cfg->max_flows ||
44179d2be38SHariprasad Kelam 	    bitmap_weight(&flow_cfg->dmacflt_bmap,
44279d2be38SHariprasad Kelam 			  flow_cfg->dmacflt_max_flows))
4432e2a8126SSunil Goutham 		return flow_cfg->max_flows + flow_cfg->dmacflt_max_flows;
44479d2be38SHariprasad Kelam 	else
4452e2a8126SSunil Goutham 		return flow_cfg->max_flows;
44679d2be38SHariprasad Kelam }
4473cffaed2SRakesh Babu EXPORT_SYMBOL(otx2_get_maxflows);
44879d2be38SHariprasad Kelam 
449f0a1913fSSubbaraya Sundeep int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
450f0a1913fSSubbaraya Sundeep 		  u32 location)
451f0a1913fSSubbaraya Sundeep {
452f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter;
453f0a1913fSSubbaraya Sundeep 
45479d2be38SHariprasad Kelam 	if (location >= otx2_get_maxflows(pfvf->flow_cfg))
455f0a1913fSSubbaraya Sundeep 		return -EINVAL;
456f0a1913fSSubbaraya Sundeep 
457f0a1913fSSubbaraya Sundeep 	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
458f0a1913fSSubbaraya Sundeep 		if (iter->location == location) {
459f0a1913fSSubbaraya Sundeep 			nfc->fs = iter->flow_spec;
46081a43620SGeetha sowjanya 			nfc->rss_context = iter->rss_ctx_id;
461f0a1913fSSubbaraya Sundeep 			return 0;
462f0a1913fSSubbaraya Sundeep 		}
463f0a1913fSSubbaraya Sundeep 	}
464f0a1913fSSubbaraya Sundeep 
465f0a1913fSSubbaraya Sundeep 	return -ENOENT;
466f0a1913fSSubbaraya Sundeep }
467f0a1913fSSubbaraya Sundeep 
468f0a1913fSSubbaraya Sundeep int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
469f0a1913fSSubbaraya Sundeep 		       u32 *rule_locs)
470f0a1913fSSubbaraya Sundeep {
471f41b2d67SSubbaraya Sundeep 	u32 rule_cnt = nfc->rule_cnt;
472f0a1913fSSubbaraya Sundeep 	u32 location = 0;
473f0a1913fSSubbaraya Sundeep 	int idx = 0;
474f0a1913fSSubbaraya Sundeep 	int err = 0;
475f0a1913fSSubbaraya Sundeep 
47679d2be38SHariprasad Kelam 	nfc->data = otx2_get_maxflows(pfvf->flow_cfg);
477f41b2d67SSubbaraya Sundeep 	while ((!err || err == -ENOENT) && idx < rule_cnt) {
478f0a1913fSSubbaraya Sundeep 		err = otx2_get_flow(pfvf, nfc, location);
479f0a1913fSSubbaraya Sundeep 		if (!err)
480f0a1913fSSubbaraya Sundeep 			rule_locs[idx++] = location;
481f0a1913fSSubbaraya Sundeep 		location++;
482f0a1913fSSubbaraya Sundeep 	}
483f41b2d67SSubbaraya Sundeep 	nfc->rule_cnt = rule_cnt;
484f0a1913fSSubbaraya Sundeep 
485f0a1913fSSubbaraya Sundeep 	return err;
486f0a1913fSSubbaraya Sundeep }
487f0a1913fSSubbaraya Sundeep 
488b7cf9661SNaveen Mamindlapalli static int otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp,
489f0a1913fSSubbaraya Sundeep 				  struct npc_install_flow_req *req,
490f0a1913fSSubbaraya Sundeep 				  u32 flow_type)
491f0a1913fSSubbaraya Sundeep {
492f0a1913fSSubbaraya Sundeep 	struct ethtool_usrip4_spec *ipv4_usr_mask = &fsp->m_u.usr_ip4_spec;
493f0a1913fSSubbaraya Sundeep 	struct ethtool_usrip4_spec *ipv4_usr_hdr = &fsp->h_u.usr_ip4_spec;
494f0a1913fSSubbaraya Sundeep 	struct ethtool_tcpip4_spec *ipv4_l4_mask = &fsp->m_u.tcp_ip4_spec;
495f0a1913fSSubbaraya Sundeep 	struct ethtool_tcpip4_spec *ipv4_l4_hdr = &fsp->h_u.tcp_ip4_spec;
496b7cf9661SNaveen Mamindlapalli 	struct ethtool_ah_espip4_spec *ah_esp_hdr = &fsp->h_u.ah_ip4_spec;
497b7cf9661SNaveen Mamindlapalli 	struct ethtool_ah_espip4_spec *ah_esp_mask = &fsp->m_u.ah_ip4_spec;
498f0a1913fSSubbaraya Sundeep 	struct flow_msg *pmask = &req->mask;
499f0a1913fSSubbaraya Sundeep 	struct flow_msg *pkt = &req->packet;
500f0a1913fSSubbaraya Sundeep 
501f0a1913fSSubbaraya Sundeep 	switch (flow_type) {
502f0a1913fSSubbaraya Sundeep 	case IP_USER_FLOW:
503f0a1913fSSubbaraya Sundeep 		if (ipv4_usr_mask->ip4src) {
504f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip4src, &ipv4_usr_hdr->ip4src,
505f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip4src));
506f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip4src, &ipv4_usr_mask->ip4src,
507f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip4src));
508f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SIP_IPV4);
509f0a1913fSSubbaraya Sundeep 		}
510f0a1913fSSubbaraya Sundeep 		if (ipv4_usr_mask->ip4dst) {
511f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip4dst, &ipv4_usr_hdr->ip4dst,
512f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip4dst));
513f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip4dst, &ipv4_usr_mask->ip4dst,
514f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip4dst));
515f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DIP_IPV4);
516f0a1913fSSubbaraya Sundeep 		}
5172b9cef66SNaveen Mamindlapalli 		if (ipv4_usr_mask->tos) {
5182b9cef66SNaveen Mamindlapalli 			pkt->tos = ipv4_usr_hdr->tos;
5192b9cef66SNaveen Mamindlapalli 			pmask->tos = ipv4_usr_mask->tos;
5202b9cef66SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_TOS);
5212b9cef66SNaveen Mamindlapalli 		}
5222b9cef66SNaveen Mamindlapalli 		if (ipv4_usr_mask->proto) {
5232b9cef66SNaveen Mamindlapalli 			switch (ipv4_usr_hdr->proto) {
5242b9cef66SNaveen Mamindlapalli 			case IPPROTO_ICMP:
5252b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_ICMP);
5262b9cef66SNaveen Mamindlapalli 				break;
5272b9cef66SNaveen Mamindlapalli 			case IPPROTO_TCP:
5282b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_TCP);
5292b9cef66SNaveen Mamindlapalli 				break;
5302b9cef66SNaveen Mamindlapalli 			case IPPROTO_UDP:
5312b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_UDP);
5322b9cef66SNaveen Mamindlapalli 				break;
5332b9cef66SNaveen Mamindlapalli 			case IPPROTO_SCTP:
5342b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
5352b9cef66SNaveen Mamindlapalli 				break;
5362b9cef66SNaveen Mamindlapalli 			case IPPROTO_AH:
5372b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_AH);
5382b9cef66SNaveen Mamindlapalli 				break;
5392b9cef66SNaveen Mamindlapalli 			case IPPROTO_ESP:
5402b9cef66SNaveen Mamindlapalli 				req->features |= BIT_ULL(NPC_IPPROTO_ESP);
5412b9cef66SNaveen Mamindlapalli 				break;
5422b9cef66SNaveen Mamindlapalli 			default:
5432b9cef66SNaveen Mamindlapalli 				return -EOPNOTSUPP;
5442b9cef66SNaveen Mamindlapalli 			}
5452b9cef66SNaveen Mamindlapalli 		}
546b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IP);
547b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
548b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
549f0a1913fSSubbaraya Sundeep 		break;
550f0a1913fSSubbaraya Sundeep 	case TCP_V4_FLOW:
551f0a1913fSSubbaraya Sundeep 	case UDP_V4_FLOW:
552f0a1913fSSubbaraya Sundeep 	case SCTP_V4_FLOW:
553b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IP);
554b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
555b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
556f0a1913fSSubbaraya Sundeep 		if (ipv4_l4_mask->ip4src) {
557f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip4src, &ipv4_l4_hdr->ip4src,
558f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip4src));
559f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip4src, &ipv4_l4_mask->ip4src,
560f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip4src));
561f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SIP_IPV4);
562f0a1913fSSubbaraya Sundeep 		}
563f0a1913fSSubbaraya Sundeep 		if (ipv4_l4_mask->ip4dst) {
564f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip4dst, &ipv4_l4_hdr->ip4dst,
565f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip4dst));
566f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip4dst, &ipv4_l4_mask->ip4dst,
567f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip4dst));
568f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DIP_IPV4);
569f0a1913fSSubbaraya Sundeep 		}
5702b9cef66SNaveen Mamindlapalli 		if (ipv4_l4_mask->tos) {
5712b9cef66SNaveen Mamindlapalli 			pkt->tos = ipv4_l4_hdr->tos;
5722b9cef66SNaveen Mamindlapalli 			pmask->tos = ipv4_l4_mask->tos;
5732b9cef66SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_TOS);
5742b9cef66SNaveen Mamindlapalli 		}
575f0a1913fSSubbaraya Sundeep 		if (ipv4_l4_mask->psrc) {
576f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->sport, &ipv4_l4_hdr->psrc,
577f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->sport));
578f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->sport, &ipv4_l4_mask->psrc,
579f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->sport));
580f0a1913fSSubbaraya Sundeep 			if (flow_type == UDP_V4_FLOW)
581f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_UDP);
582f0a1913fSSubbaraya Sundeep 			else if (flow_type == TCP_V4_FLOW)
583f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_TCP);
584f0a1913fSSubbaraya Sundeep 			else
585f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_SCTP);
586f0a1913fSSubbaraya Sundeep 		}
587f0a1913fSSubbaraya Sundeep 		if (ipv4_l4_mask->pdst) {
588f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->dport, &ipv4_l4_hdr->pdst,
589f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->dport));
590f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->dport, &ipv4_l4_mask->pdst,
591f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->dport));
592f0a1913fSSubbaraya Sundeep 			if (flow_type == UDP_V4_FLOW)
593f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_UDP);
594f0a1913fSSubbaraya Sundeep 			else if (flow_type == TCP_V4_FLOW)
595f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_TCP);
596f0a1913fSSubbaraya Sundeep 			else
597f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_SCTP);
598f0a1913fSSubbaraya Sundeep 		}
599b7cf9661SNaveen Mamindlapalli 		if (flow_type == UDP_V4_FLOW)
600b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_UDP);
601b7cf9661SNaveen Mamindlapalli 		else if (flow_type == TCP_V4_FLOW)
602b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_TCP);
603b7cf9661SNaveen Mamindlapalli 		else
604b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
605b7cf9661SNaveen Mamindlapalli 		break;
606b7cf9661SNaveen Mamindlapalli 	case AH_V4_FLOW:
607b7cf9661SNaveen Mamindlapalli 	case ESP_V4_FLOW:
608b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IP);
609b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
610b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
611b7cf9661SNaveen Mamindlapalli 		if (ah_esp_mask->ip4src) {
612b7cf9661SNaveen Mamindlapalli 			memcpy(&pkt->ip4src, &ah_esp_hdr->ip4src,
613b7cf9661SNaveen Mamindlapalli 			       sizeof(pkt->ip4src));
614b7cf9661SNaveen Mamindlapalli 			memcpy(&pmask->ip4src, &ah_esp_mask->ip4src,
615b7cf9661SNaveen Mamindlapalli 			       sizeof(pmask->ip4src));
616b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_SIP_IPV4);
617b7cf9661SNaveen Mamindlapalli 		}
618b7cf9661SNaveen Mamindlapalli 		if (ah_esp_mask->ip4dst) {
619b7cf9661SNaveen Mamindlapalli 			memcpy(&pkt->ip4dst, &ah_esp_hdr->ip4dst,
620b7cf9661SNaveen Mamindlapalli 			       sizeof(pkt->ip4dst));
621b7cf9661SNaveen Mamindlapalli 			memcpy(&pmask->ip4dst, &ah_esp_mask->ip4dst,
622b7cf9661SNaveen Mamindlapalli 			       sizeof(pmask->ip4dst));
623b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_DIP_IPV4);
624b7cf9661SNaveen Mamindlapalli 		}
6252b9cef66SNaveen Mamindlapalli 		if (ah_esp_mask->tos) {
6262b9cef66SNaveen Mamindlapalli 			pkt->tos = ah_esp_hdr->tos;
6272b9cef66SNaveen Mamindlapalli 			pmask->tos = ah_esp_mask->tos;
6282b9cef66SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_TOS);
6292b9cef66SNaveen Mamindlapalli 		}
630b7cf9661SNaveen Mamindlapalli 
631b7cf9661SNaveen Mamindlapalli 		/* NPC profile doesn't extract AH/ESP header fields */
6322b9cef66SNaveen Mamindlapalli 		if (ah_esp_mask->spi & ah_esp_hdr->spi)
633b7cf9661SNaveen Mamindlapalli 			return -EOPNOTSUPP;
634b7cf9661SNaveen Mamindlapalli 
635b7cf9661SNaveen Mamindlapalli 		if (flow_type == AH_V4_FLOW)
636b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_AH);
637b7cf9661SNaveen Mamindlapalli 		else
638b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_ESP);
639f0a1913fSSubbaraya Sundeep 		break;
640f0a1913fSSubbaraya Sundeep 	default:
641f0a1913fSSubbaraya Sundeep 		break;
642f0a1913fSSubbaraya Sundeep 	}
643b7cf9661SNaveen Mamindlapalli 
644b7cf9661SNaveen Mamindlapalli 	return 0;
645f0a1913fSSubbaraya Sundeep }
646f0a1913fSSubbaraya Sundeep 
647b7cf9661SNaveen Mamindlapalli static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
648f0a1913fSSubbaraya Sundeep 				  struct npc_install_flow_req *req,
649f0a1913fSSubbaraya Sundeep 				  u32 flow_type)
650f0a1913fSSubbaraya Sundeep {
651f0a1913fSSubbaraya Sundeep 	struct ethtool_usrip6_spec *ipv6_usr_mask = &fsp->m_u.usr_ip6_spec;
652f0a1913fSSubbaraya Sundeep 	struct ethtool_usrip6_spec *ipv6_usr_hdr = &fsp->h_u.usr_ip6_spec;
653f0a1913fSSubbaraya Sundeep 	struct ethtool_tcpip6_spec *ipv6_l4_mask = &fsp->m_u.tcp_ip6_spec;
654f0a1913fSSubbaraya Sundeep 	struct ethtool_tcpip6_spec *ipv6_l4_hdr = &fsp->h_u.tcp_ip6_spec;
655b7cf9661SNaveen Mamindlapalli 	struct ethtool_ah_espip6_spec *ah_esp_hdr = &fsp->h_u.ah_ip6_spec;
656b7cf9661SNaveen Mamindlapalli 	struct ethtool_ah_espip6_spec *ah_esp_mask = &fsp->m_u.ah_ip6_spec;
657f0a1913fSSubbaraya Sundeep 	struct flow_msg *pmask = &req->mask;
658f0a1913fSSubbaraya Sundeep 	struct flow_msg *pkt = &req->packet;
659f0a1913fSSubbaraya Sundeep 
660f0a1913fSSubbaraya Sundeep 	switch (flow_type) {
661f0a1913fSSubbaraya Sundeep 	case IPV6_USER_FLOW:
662f0a1913fSSubbaraya Sundeep 		if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6src)) {
663f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip6src, &ipv6_usr_hdr->ip6src,
664f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip6src));
665f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip6src, &ipv6_usr_mask->ip6src,
666f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip6src));
667f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SIP_IPV6);
668f0a1913fSSubbaraya Sundeep 		}
669f0a1913fSSubbaraya Sundeep 		if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6dst)) {
670f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip6dst, &ipv6_usr_hdr->ip6dst,
671f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip6dst));
672f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip6dst, &ipv6_usr_mask->ip6dst,
673f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip6dst));
674f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DIP_IPV6);
675f0a1913fSSubbaraya Sundeep 		}
676b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IPV6);
677b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
678b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
679f0a1913fSSubbaraya Sundeep 		break;
680f0a1913fSSubbaraya Sundeep 	case TCP_V6_FLOW:
681f0a1913fSSubbaraya Sundeep 	case UDP_V6_FLOW:
682f0a1913fSSubbaraya Sundeep 	case SCTP_V6_FLOW:
683b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IPV6);
684b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
685b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
686f0a1913fSSubbaraya Sundeep 		if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6src)) {
687f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip6src, &ipv6_l4_hdr->ip6src,
688f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip6src));
689f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip6src, &ipv6_l4_mask->ip6src,
690f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip6src));
691f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SIP_IPV6);
692f0a1913fSSubbaraya Sundeep 		}
693f0a1913fSSubbaraya Sundeep 		if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6dst)) {
694f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->ip6dst, &ipv6_l4_hdr->ip6dst,
695f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->ip6dst));
696f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->ip6dst, &ipv6_l4_mask->ip6dst,
697f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->ip6dst));
698f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DIP_IPV6);
699f0a1913fSSubbaraya Sundeep 		}
700f0a1913fSSubbaraya Sundeep 		if (ipv6_l4_mask->psrc) {
701f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->sport, &ipv6_l4_hdr->psrc,
702f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->sport));
703f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->sport, &ipv6_l4_mask->psrc,
704f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->sport));
705f0a1913fSSubbaraya Sundeep 			if (flow_type == UDP_V6_FLOW)
706f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_UDP);
707f0a1913fSSubbaraya Sundeep 			else if (flow_type == TCP_V6_FLOW)
708f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_TCP);
709f0a1913fSSubbaraya Sundeep 			else
710f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_SPORT_SCTP);
711f0a1913fSSubbaraya Sundeep 		}
712f0a1913fSSubbaraya Sundeep 		if (ipv6_l4_mask->pdst) {
713f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->dport, &ipv6_l4_hdr->pdst,
714f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->dport));
715f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->dport, &ipv6_l4_mask->pdst,
716f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->dport));
717f0a1913fSSubbaraya Sundeep 			if (flow_type == UDP_V6_FLOW)
718f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_UDP);
719f0a1913fSSubbaraya Sundeep 			else if (flow_type == TCP_V6_FLOW)
720f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_TCP);
721f0a1913fSSubbaraya Sundeep 			else
722f0a1913fSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_DPORT_SCTP);
723f0a1913fSSubbaraya Sundeep 		}
724b7cf9661SNaveen Mamindlapalli 		if (flow_type == UDP_V6_FLOW)
725b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_UDP);
726b7cf9661SNaveen Mamindlapalli 		else if (flow_type == TCP_V6_FLOW)
727b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_TCP);
728b7cf9661SNaveen Mamindlapalli 		else
729b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
730f0a1913fSSubbaraya Sundeep 		break;
731b7cf9661SNaveen Mamindlapalli 	case AH_V6_FLOW:
732b7cf9661SNaveen Mamindlapalli 	case ESP_V6_FLOW:
733b7cf9661SNaveen Mamindlapalli 		pkt->etype = cpu_to_be16(ETH_P_IPV6);
734b7cf9661SNaveen Mamindlapalli 		pmask->etype = cpu_to_be16(0xFFFF);
735b7cf9661SNaveen Mamindlapalli 		req->features |= BIT_ULL(NPC_ETYPE);
736b7cf9661SNaveen Mamindlapalli 		if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6src)) {
737b7cf9661SNaveen Mamindlapalli 			memcpy(&pkt->ip6src, &ah_esp_hdr->ip6src,
738b7cf9661SNaveen Mamindlapalli 			       sizeof(pkt->ip6src));
739b7cf9661SNaveen Mamindlapalli 			memcpy(&pmask->ip6src, &ah_esp_mask->ip6src,
740b7cf9661SNaveen Mamindlapalli 			       sizeof(pmask->ip6src));
741b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_SIP_IPV6);
742b7cf9661SNaveen Mamindlapalli 		}
743b7cf9661SNaveen Mamindlapalli 		if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6dst)) {
744b7cf9661SNaveen Mamindlapalli 			memcpy(&pkt->ip6dst, &ah_esp_hdr->ip6dst,
745b7cf9661SNaveen Mamindlapalli 			       sizeof(pkt->ip6dst));
746b7cf9661SNaveen Mamindlapalli 			memcpy(&pmask->ip6dst, &ah_esp_mask->ip6dst,
747b7cf9661SNaveen Mamindlapalli 			       sizeof(pmask->ip6dst));
748b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_DIP_IPV6);
749b7cf9661SNaveen Mamindlapalli 		}
750b7cf9661SNaveen Mamindlapalli 
751b7cf9661SNaveen Mamindlapalli 		/* NPC profile doesn't extract AH/ESP header fields */
752b7cf9661SNaveen Mamindlapalli 		if ((ah_esp_mask->spi & ah_esp_hdr->spi) ||
753b7cf9661SNaveen Mamindlapalli 		    (ah_esp_mask->tclass & ah_esp_mask->tclass))
754b7cf9661SNaveen Mamindlapalli 			return -EOPNOTSUPP;
755b7cf9661SNaveen Mamindlapalli 
756b7cf9661SNaveen Mamindlapalli 		if (flow_type == AH_V6_FLOW)
757b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_AH);
758b7cf9661SNaveen Mamindlapalli 		else
759b7cf9661SNaveen Mamindlapalli 			req->features |= BIT_ULL(NPC_IPPROTO_ESP);
760320daffdSGustavo A. R. Silva 		break;
761f0a1913fSSubbaraya Sundeep 	default:
762f0a1913fSSubbaraya Sundeep 		break;
763f0a1913fSSubbaraya Sundeep 	}
764b7cf9661SNaveen Mamindlapalli 
765b7cf9661SNaveen Mamindlapalli 	return 0;
766f0a1913fSSubbaraya Sundeep }
767f0a1913fSSubbaraya Sundeep 
768dce677daSSubbaraya Sundeep static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
769f0a1913fSSubbaraya Sundeep 			      struct npc_install_flow_req *req)
770f0a1913fSSubbaraya Sundeep {
771f0a1913fSSubbaraya Sundeep 	struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
772f0a1913fSSubbaraya Sundeep 	struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
773f0a1913fSSubbaraya Sundeep 	struct flow_msg *pmask = &req->mask;
774f0a1913fSSubbaraya Sundeep 	struct flow_msg *pkt = &req->packet;
775f0a1913fSSubbaraya Sundeep 	u32 flow_type;
776b7cf9661SNaveen Mamindlapalli 	int ret;
777f0a1913fSSubbaraya Sundeep 
77881a43620SGeetha sowjanya 	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
779f0a1913fSSubbaraya Sundeep 	switch (flow_type) {
780f0a1913fSSubbaraya Sundeep 	/* bits not set in mask are don't care */
781f0a1913fSSubbaraya Sundeep 	case ETHER_FLOW:
782f0a1913fSSubbaraya Sundeep 		if (!is_zero_ether_addr(eth_mask->h_source)) {
783f0a1913fSSubbaraya Sundeep 			ether_addr_copy(pkt->smac, eth_hdr->h_source);
784f0a1913fSSubbaraya Sundeep 			ether_addr_copy(pmask->smac, eth_mask->h_source);
785f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_SMAC);
786f0a1913fSSubbaraya Sundeep 		}
787f0a1913fSSubbaraya Sundeep 		if (!is_zero_ether_addr(eth_mask->h_dest)) {
788f0a1913fSSubbaraya Sundeep 			ether_addr_copy(pkt->dmac, eth_hdr->h_dest);
789f0a1913fSSubbaraya Sundeep 			ether_addr_copy(pmask->dmac, eth_mask->h_dest);
790f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_DMAC);
791f0a1913fSSubbaraya Sundeep 		}
7923cffaed2SRakesh Babu 		if (eth_hdr->h_proto) {
793f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->etype, &eth_hdr->h_proto,
794f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->etype));
795f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->etype, &eth_mask->h_proto,
796f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->etype));
797f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_ETYPE);
798f0a1913fSSubbaraya Sundeep 		}
799f0a1913fSSubbaraya Sundeep 		break;
800f0a1913fSSubbaraya Sundeep 	case IP_USER_FLOW:
801f0a1913fSSubbaraya Sundeep 	case TCP_V4_FLOW:
802f0a1913fSSubbaraya Sundeep 	case UDP_V4_FLOW:
803f0a1913fSSubbaraya Sundeep 	case SCTP_V4_FLOW:
804b7cf9661SNaveen Mamindlapalli 	case AH_V4_FLOW:
805b7cf9661SNaveen Mamindlapalli 	case ESP_V4_FLOW:
806b7cf9661SNaveen Mamindlapalli 		ret = otx2_prepare_ipv4_flow(fsp, req, flow_type);
807b7cf9661SNaveen Mamindlapalli 		if (ret)
808b7cf9661SNaveen Mamindlapalli 			return ret;
809f0a1913fSSubbaraya Sundeep 		break;
810f0a1913fSSubbaraya Sundeep 	case IPV6_USER_FLOW:
811f0a1913fSSubbaraya Sundeep 	case TCP_V6_FLOW:
812f0a1913fSSubbaraya Sundeep 	case UDP_V6_FLOW:
813f0a1913fSSubbaraya Sundeep 	case SCTP_V6_FLOW:
814b7cf9661SNaveen Mamindlapalli 	case AH_V6_FLOW:
815b7cf9661SNaveen Mamindlapalli 	case ESP_V6_FLOW:
816b7cf9661SNaveen Mamindlapalli 		ret = otx2_prepare_ipv6_flow(fsp, req, flow_type);
817b7cf9661SNaveen Mamindlapalli 		if (ret)
818b7cf9661SNaveen Mamindlapalli 			return ret;
819f0a1913fSSubbaraya Sundeep 		break;
820f0a1913fSSubbaraya Sundeep 	default:
821f0a1913fSSubbaraya Sundeep 		return -EOPNOTSUPP;
822f0a1913fSSubbaraya Sundeep 	}
823f0a1913fSSubbaraya Sundeep 	if (fsp->flow_type & FLOW_EXT) {
824dce677daSSubbaraya Sundeep 		u16 vlan_etype;
825dce677daSSubbaraya Sundeep 
826dce677daSSubbaraya Sundeep 		if (fsp->m_ext.vlan_etype) {
827dce677daSSubbaraya Sundeep 			/* Partial masks not supported */
828dce677daSSubbaraya Sundeep 			if (be16_to_cpu(fsp->m_ext.vlan_etype) != 0xFFFF)
829f0a1913fSSubbaraya Sundeep 				return -EINVAL;
830dce677daSSubbaraya Sundeep 
831dce677daSSubbaraya Sundeep 			vlan_etype = be16_to_cpu(fsp->h_ext.vlan_etype);
832dce677daSSubbaraya Sundeep 			/* Only ETH_P_8021Q and ETH_P_802AD types supported */
833dce677daSSubbaraya Sundeep 			if (vlan_etype != ETH_P_8021Q &&
834dce677daSSubbaraya Sundeep 			    vlan_etype != ETH_P_8021AD)
835dce677daSSubbaraya Sundeep 				return -EINVAL;
836dce677daSSubbaraya Sundeep 
837dce677daSSubbaraya Sundeep 			memcpy(&pkt->vlan_etype, &fsp->h_ext.vlan_etype,
838dce677daSSubbaraya Sundeep 			       sizeof(pkt->vlan_etype));
839dce677daSSubbaraya Sundeep 			memcpy(&pmask->vlan_etype, &fsp->m_ext.vlan_etype,
840dce677daSSubbaraya Sundeep 			       sizeof(pmask->vlan_etype));
841dce677daSSubbaraya Sundeep 
842dce677daSSubbaraya Sundeep 			if (vlan_etype == ETH_P_8021Q)
843dce677daSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG);
844dce677daSSubbaraya Sundeep 			else
845dce677daSSubbaraya Sundeep 				req->features |= BIT_ULL(NPC_VLAN_ETYPE_STAG);
846dce677daSSubbaraya Sundeep 		}
847dce677daSSubbaraya Sundeep 
848f0a1913fSSubbaraya Sundeep 		if (fsp->m_ext.vlan_tci) {
849f0a1913fSSubbaraya Sundeep 			memcpy(&pkt->vlan_tci, &fsp->h_ext.vlan_tci,
850f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->vlan_tci));
851f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->vlan_tci, &fsp->m_ext.vlan_tci,
852f0a1913fSSubbaraya Sundeep 			       sizeof(pmask->vlan_tci));
853f0a1913fSSubbaraya Sundeep 			req->features |= BIT_ULL(NPC_OUTER_VID);
854f0a1913fSSubbaraya Sundeep 		}
855f0a1913fSSubbaraya Sundeep 
856f0a1913fSSubbaraya Sundeep 		/* Not Drop/Direct to queue but use action in default entry */
857f0a1913fSSubbaraya Sundeep 		if (fsp->m_ext.data[1] &&
858f0a1913fSSubbaraya Sundeep 		    fsp->h_ext.data[1] == cpu_to_be32(OTX2_DEFAULT_ACTION))
859f0a1913fSSubbaraya Sundeep 			req->op = NIX_RX_ACTION_DEFAULT;
860f0a1913fSSubbaraya Sundeep 	}
861f0a1913fSSubbaraya Sundeep 
862f0a1913fSSubbaraya Sundeep 	if (fsp->flow_type & FLOW_MAC_EXT &&
863f0a1913fSSubbaraya Sundeep 	    !is_zero_ether_addr(fsp->m_ext.h_dest)) {
864f0a1913fSSubbaraya Sundeep 		ether_addr_copy(pkt->dmac, fsp->h_ext.h_dest);
865f0a1913fSSubbaraya Sundeep 		ether_addr_copy(pmask->dmac, fsp->m_ext.h_dest);
866f0a1913fSSubbaraya Sundeep 		req->features |= BIT_ULL(NPC_DMAC);
867f0a1913fSSubbaraya Sundeep 	}
868f0a1913fSSubbaraya Sundeep 
869f0a1913fSSubbaraya Sundeep 	if (!req->features)
870f0a1913fSSubbaraya Sundeep 		return -EOPNOTSUPP;
871f0a1913fSSubbaraya Sundeep 
872f0a1913fSSubbaraya Sundeep 	return 0;
873f0a1913fSSubbaraya Sundeep }
874f0a1913fSSubbaraya Sundeep 
87579d2be38SHariprasad Kelam static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
87679d2be38SHariprasad Kelam 					struct ethtool_rx_flow_spec *fsp)
87779d2be38SHariprasad Kelam {
87879d2be38SHariprasad Kelam 	struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
87979d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
88079d2be38SHariprasad Kelam 	u64 ring_cookie = fsp->ring_cookie;
88179d2be38SHariprasad Kelam 	u32 flow_type;
88279d2be38SHariprasad Kelam 
88379d2be38SHariprasad Kelam 	if (!(pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT))
88479d2be38SHariprasad Kelam 		return false;
88579d2be38SHariprasad Kelam 
88679d2be38SHariprasad Kelam 	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
88779d2be38SHariprasad Kelam 
88879d2be38SHariprasad Kelam 	/* CGX/RPM block dmac filtering configured for white listing
88979d2be38SHariprasad Kelam 	 * check for action other than DROP
89079d2be38SHariprasad Kelam 	 */
89179d2be38SHariprasad Kelam 	if (flow_type == ETHER_FLOW && ring_cookie != RX_CLS_FLOW_DISC &&
89279d2be38SHariprasad Kelam 	    !ethtool_get_flow_spec_ring_vf(ring_cookie)) {
89379d2be38SHariprasad Kelam 		if (is_zero_ether_addr(eth_mask->h_dest) &&
89479d2be38SHariprasad Kelam 		    is_valid_ether_addr(eth_hdr->h_dest))
89579d2be38SHariprasad Kelam 			return true;
89679d2be38SHariprasad Kelam 	}
89779d2be38SHariprasad Kelam 
89879d2be38SHariprasad Kelam 	return false;
89979d2be38SHariprasad Kelam }
90079d2be38SHariprasad Kelam 
901f0a1913fSSubbaraya Sundeep static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
902f0a1913fSSubbaraya Sundeep {
903f0a1913fSSubbaraya Sundeep 	u64 ring_cookie = flow->flow_spec.ring_cookie;
904*8e675581SHariprasad Kelam #ifdef CONFIG_DCB
905*8e675581SHariprasad Kelam 	int vlan_prio, qidx, pfc_rule = 0;
906*8e675581SHariprasad Kelam #endif
907f0a1913fSSubbaraya Sundeep 	struct npc_install_flow_req *req;
908f0a1913fSSubbaraya Sundeep 	int err, vf = 0;
909f0a1913fSSubbaraya Sundeep 
910f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
911f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
912f0a1913fSSubbaraya Sundeep 	if (!req) {
913f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
914f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
915f0a1913fSSubbaraya Sundeep 	}
916f0a1913fSSubbaraya Sundeep 
917f0a1913fSSubbaraya Sundeep 	err = otx2_prepare_flow_request(&flow->flow_spec, req);
918f0a1913fSSubbaraya Sundeep 	if (err) {
919f0a1913fSSubbaraya Sundeep 		/* free the allocated msg above */
920f0a1913fSSubbaraya Sundeep 		otx2_mbox_reset(&pfvf->mbox.mbox, 0);
921f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
922f0a1913fSSubbaraya Sundeep 		return err;
923f0a1913fSSubbaraya Sundeep 	}
924f0a1913fSSubbaraya Sundeep 
925f0a1913fSSubbaraya Sundeep 	req->entry = flow->entry;
926f0a1913fSSubbaraya Sundeep 	req->intf = NIX_INTF_RX;
927f0a1913fSSubbaraya Sundeep 	req->set_cntr = 1;
928f0a1913fSSubbaraya Sundeep 	req->channel = pfvf->hw.rx_chan_base;
929f0a1913fSSubbaraya Sundeep 	if (ring_cookie == RX_CLS_FLOW_DISC) {
930f0a1913fSSubbaraya Sundeep 		req->op = NIX_RX_ACTIONOP_DROP;
931f0a1913fSSubbaraya Sundeep 	} else {
932f0a1913fSSubbaraya Sundeep 		/* change to unicast only if action of default entry is not
933f0a1913fSSubbaraya Sundeep 		 * requested by user
934f0a1913fSSubbaraya Sundeep 		 */
93581a43620SGeetha sowjanya 		if (flow->flow_spec.flow_type & FLOW_RSS) {
93681a43620SGeetha sowjanya 			req->op = NIX_RX_ACTIONOP_RSS;
93781a43620SGeetha sowjanya 			req->index = flow->rss_ctx_id;
938e7938365SSunil Goutham 			req->flow_key_alg = pfvf->hw.flowkey_alg_idx;
93981a43620SGeetha sowjanya 		} else {
940f0a1913fSSubbaraya Sundeep 			req->op = NIX_RX_ACTIONOP_UCAST;
941f0a1913fSSubbaraya Sundeep 			req->index = ethtool_get_flow_spec_ring(ring_cookie);
94281a43620SGeetha sowjanya 		}
943f0a1913fSSubbaraya Sundeep 		vf = ethtool_get_flow_spec_ring_vf(ring_cookie);
944f0a1913fSSubbaraya Sundeep 		if (vf > pci_num_vf(pfvf->pdev)) {
945f0a1913fSSubbaraya Sundeep 			mutex_unlock(&pfvf->mbox.lock);
946f0a1913fSSubbaraya Sundeep 			return -EINVAL;
947f0a1913fSSubbaraya Sundeep 		}
948*8e675581SHariprasad Kelam 
949*8e675581SHariprasad Kelam #ifdef CONFIG_DCB
950*8e675581SHariprasad Kelam 		/* Identify PFC rule if PFC enabled and ntuple rule is vlan */
951*8e675581SHariprasad Kelam 		if (!vf && (req->features & BIT_ULL(NPC_OUTER_VID)) &&
952*8e675581SHariprasad Kelam 		    pfvf->pfc_en && req->op != NIX_RX_ACTIONOP_RSS) {
953*8e675581SHariprasad Kelam 			vlan_prio = ntohs(req->packet.vlan_tci) &
954*8e675581SHariprasad Kelam 				    ntohs(req->mask.vlan_tci);
955*8e675581SHariprasad Kelam 
956*8e675581SHariprasad Kelam 			/* Get the priority */
957*8e675581SHariprasad Kelam 			vlan_prio >>= 13;
958*8e675581SHariprasad Kelam 			flow->rule_type |= PFC_FLOWCTRL_RULE;
959*8e675581SHariprasad Kelam 			/* Check if PFC enabled for this priority */
960*8e675581SHariprasad Kelam 			if (pfvf->pfc_en & BIT(vlan_prio)) {
961*8e675581SHariprasad Kelam 				pfc_rule = true;
962*8e675581SHariprasad Kelam 				qidx = req->index;
963*8e675581SHariprasad Kelam 			}
964*8e675581SHariprasad Kelam 		}
965*8e675581SHariprasad Kelam #endif
966f0a1913fSSubbaraya Sundeep 	}
967f0a1913fSSubbaraya Sundeep 
968f0a1913fSSubbaraya Sundeep 	/* ethtool ring_cookie has (VF + 1) for VF */
969f0a1913fSSubbaraya Sundeep 	if (vf) {
970f0a1913fSSubbaraya Sundeep 		req->vf = vf;
971f0a1913fSSubbaraya Sundeep 		flow->is_vf = true;
972f0a1913fSSubbaraya Sundeep 		flow->vf = vf;
973f0a1913fSSubbaraya Sundeep 	}
974f0a1913fSSubbaraya Sundeep 
975f0a1913fSSubbaraya Sundeep 	/* Send message to AF */
976f0a1913fSSubbaraya Sundeep 	err = otx2_sync_mbox_msg(&pfvf->mbox);
977*8e675581SHariprasad Kelam 
978*8e675581SHariprasad Kelam #ifdef CONFIG_DCB
979*8e675581SHariprasad Kelam 	if (!err && pfc_rule)
980*8e675581SHariprasad Kelam 		otx2_update_bpid_in_rqctx(pfvf, vlan_prio, qidx, true);
981*8e675581SHariprasad Kelam #endif
982*8e675581SHariprasad Kelam 
983f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
984f0a1913fSSubbaraya Sundeep 	return err;
985f0a1913fSSubbaraya Sundeep }
986f0a1913fSSubbaraya Sundeep 
98779d2be38SHariprasad Kelam static int otx2_add_flow_with_pfmac(struct otx2_nic *pfvf,
98879d2be38SHariprasad Kelam 				    struct otx2_flow *flow)
98979d2be38SHariprasad Kelam {
99079d2be38SHariprasad Kelam 	struct otx2_flow *pf_mac;
99179d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr;
99279d2be38SHariprasad Kelam 
99379d2be38SHariprasad Kelam 	pf_mac = kzalloc(sizeof(*pf_mac), GFP_KERNEL);
99479d2be38SHariprasad Kelam 	if (!pf_mac)
99579d2be38SHariprasad Kelam 		return -ENOMEM;
99679d2be38SHariprasad Kelam 
99779d2be38SHariprasad Kelam 	pf_mac->entry = 0;
998*8e675581SHariprasad Kelam 	pf_mac->rule_type |= DMAC_FILTER_RULE;
9992e2a8126SSunil Goutham 	pf_mac->location = pfvf->flow_cfg->max_flows;
100079d2be38SHariprasad Kelam 	memcpy(&pf_mac->flow_spec, &flow->flow_spec,
100179d2be38SHariprasad Kelam 	       sizeof(struct ethtool_rx_flow_spec));
100279d2be38SHariprasad Kelam 	pf_mac->flow_spec.location = pf_mac->location;
100379d2be38SHariprasad Kelam 
100479d2be38SHariprasad Kelam 	/* Copy PF mac address */
100579d2be38SHariprasad Kelam 	eth_hdr = &pf_mac->flow_spec.h_u.ether_spec;
100679d2be38SHariprasad Kelam 	ether_addr_copy(eth_hdr->h_dest, pfvf->netdev->dev_addr);
100779d2be38SHariprasad Kelam 
100879d2be38SHariprasad Kelam 	/* Install DMAC filter with PF mac address */
100979d2be38SHariprasad Kelam 	otx2_dmacflt_add(pfvf, eth_hdr->h_dest, 0);
101079d2be38SHariprasad Kelam 
101179d2be38SHariprasad Kelam 	otx2_add_flow_to_list(pfvf, pf_mac);
101279d2be38SHariprasad Kelam 	pfvf->flow_cfg->nr_flows++;
101379d2be38SHariprasad Kelam 	set_bit(0, &pfvf->flow_cfg->dmacflt_bmap);
101479d2be38SHariprasad Kelam 
101579d2be38SHariprasad Kelam 	return 0;
101679d2be38SHariprasad Kelam }
101779d2be38SHariprasad Kelam 
101881a43620SGeetha sowjanya int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
1019f0a1913fSSubbaraya Sundeep {
1020f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
102181a43620SGeetha sowjanya 	struct ethtool_rx_flow_spec *fsp = &nfc->fs;
1022f0a1913fSSubbaraya Sundeep 	struct otx2_flow *flow;
102379d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr;
1024f0a1913fSSubbaraya Sundeep 	bool new = false;
102579d2be38SHariprasad Kelam 	int err = 0;
102681a43620SGeetha sowjanya 	u32 ring;
1027f0a1913fSSubbaraya Sundeep 
1028a515e5b5SSunil Goutham 	if (!flow_cfg->max_flows) {
1029a515e5b5SSunil Goutham 		netdev_err(pfvf->netdev,
1030a515e5b5SSunil Goutham 			   "Ntuple rule count is 0, allocate and retry\n");
1031a515e5b5SSunil Goutham 		return -EINVAL;
1032a515e5b5SSunil Goutham 	}
1033a515e5b5SSunil Goutham 
103481a43620SGeetha sowjanya 	ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
1035f0a1913fSSubbaraya Sundeep 	if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
1036f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
1037f0a1913fSSubbaraya Sundeep 
1038f0a1913fSSubbaraya Sundeep 	if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC)
1039f0a1913fSSubbaraya Sundeep 		return -EINVAL;
1040f0a1913fSSubbaraya Sundeep 
104179d2be38SHariprasad Kelam 	if (fsp->location >= otx2_get_maxflows(flow_cfg))
1042f0a1913fSSubbaraya Sundeep 		return -EINVAL;
1043f0a1913fSSubbaraya Sundeep 
1044f0a1913fSSubbaraya Sundeep 	flow = otx2_find_flow(pfvf, fsp->location);
1045f0a1913fSSubbaraya Sundeep 	if (!flow) {
104679d2be38SHariprasad Kelam 		flow = kzalloc(sizeof(*flow), GFP_KERNEL);
1047f0a1913fSSubbaraya Sundeep 		if (!flow)
1048f0a1913fSSubbaraya Sundeep 			return -ENOMEM;
1049f0a1913fSSubbaraya Sundeep 		flow->location = fsp->location;
1050dce677daSSubbaraya Sundeep 		flow->entry = flow_cfg->flow_ent[flow->location];
1051f0a1913fSSubbaraya Sundeep 		new = true;
1052f0a1913fSSubbaraya Sundeep 	}
1053f0a1913fSSubbaraya Sundeep 	/* struct copy */
1054f0a1913fSSubbaraya Sundeep 	flow->flow_spec = *fsp;
1055f0a1913fSSubbaraya Sundeep 
105681a43620SGeetha sowjanya 	if (fsp->flow_type & FLOW_RSS)
105781a43620SGeetha sowjanya 		flow->rss_ctx_id = nfc->rss_context;
105881a43620SGeetha sowjanya 
105979d2be38SHariprasad Kelam 	if (otx2_is_flow_rule_dmacfilter(pfvf, &flow->flow_spec)) {
106079d2be38SHariprasad Kelam 		eth_hdr = &flow->flow_spec.h_u.ether_spec;
106179d2be38SHariprasad Kelam 
106279d2be38SHariprasad Kelam 		/* Sync dmac filter table with updated fields */
1063*8e675581SHariprasad Kelam 		if (flow->rule_type & DMAC_FILTER_RULE)
106479d2be38SHariprasad Kelam 			return otx2_dmacflt_update(pfvf, eth_hdr->h_dest,
106579d2be38SHariprasad Kelam 						   flow->entry);
106679d2be38SHariprasad Kelam 
106779d2be38SHariprasad Kelam 		if (bitmap_full(&flow_cfg->dmacflt_bmap,
106879d2be38SHariprasad Kelam 				flow_cfg->dmacflt_max_flows)) {
106979d2be38SHariprasad Kelam 			netdev_warn(pfvf->netdev,
107079d2be38SHariprasad Kelam 				    "Can't insert the rule %d as max allowed dmac filters are %d\n",
107179d2be38SHariprasad Kelam 				    flow->location +
107279d2be38SHariprasad Kelam 				    flow_cfg->dmacflt_max_flows,
107379d2be38SHariprasad Kelam 				    flow_cfg->dmacflt_max_flows);
107479d2be38SHariprasad Kelam 			err = -EINVAL;
107579d2be38SHariprasad Kelam 			if (new)
107679d2be38SHariprasad Kelam 				kfree(flow);
107779d2be38SHariprasad Kelam 			return err;
107879d2be38SHariprasad Kelam 		}
107979d2be38SHariprasad Kelam 
108079d2be38SHariprasad Kelam 		/* Install PF mac address to DMAC filter list */
108179d2be38SHariprasad Kelam 		if (!test_bit(0, &flow_cfg->dmacflt_bmap))
108279d2be38SHariprasad Kelam 			otx2_add_flow_with_pfmac(pfvf, flow);
108379d2be38SHariprasad Kelam 
1084*8e675581SHariprasad Kelam 		flow->rule_type |= DMAC_FILTER_RULE;
108579d2be38SHariprasad Kelam 		flow->entry = find_first_zero_bit(&flow_cfg->dmacflt_bmap,
108679d2be38SHariprasad Kelam 						  flow_cfg->dmacflt_max_flows);
10872e2a8126SSunil Goutham 		fsp->location = flow_cfg->max_flows + flow->entry;
108879d2be38SHariprasad Kelam 		flow->flow_spec.location = fsp->location;
108979d2be38SHariprasad Kelam 		flow->location = fsp->location;
109079d2be38SHariprasad Kelam 
109179d2be38SHariprasad Kelam 		set_bit(flow->entry, &flow_cfg->dmacflt_bmap);
109279d2be38SHariprasad Kelam 		otx2_dmacflt_add(pfvf, eth_hdr->h_dest, flow->entry);
109379d2be38SHariprasad Kelam 
109479d2be38SHariprasad Kelam 	} else {
10952e2a8126SSunil Goutham 		if (flow->location >= pfvf->flow_cfg->max_flows) {
109679d2be38SHariprasad Kelam 			netdev_warn(pfvf->netdev,
109779d2be38SHariprasad Kelam 				    "Can't insert non dmac ntuple rule at %d, allowed range %d-0\n",
109879d2be38SHariprasad Kelam 				    flow->location,
10992e2a8126SSunil Goutham 				    flow_cfg->max_flows - 1);
110079d2be38SHariprasad Kelam 			err = -EINVAL;
110179d2be38SHariprasad Kelam 		} else {
1102f0a1913fSSubbaraya Sundeep 			err = otx2_add_flow_msg(pfvf, flow);
110379d2be38SHariprasad Kelam 		}
110479d2be38SHariprasad Kelam 	}
110579d2be38SHariprasad Kelam 
1106f0a1913fSSubbaraya Sundeep 	if (err) {
11073cffaed2SRakesh Babu 		if (err == MBOX_MSG_INVALID)
11083cffaed2SRakesh Babu 			err = -EINVAL;
1109f0a1913fSSubbaraya Sundeep 		if (new)
1110f0a1913fSSubbaraya Sundeep 			kfree(flow);
1111f0a1913fSSubbaraya Sundeep 		return err;
1112f0a1913fSSubbaraya Sundeep 	}
1113f0a1913fSSubbaraya Sundeep 
1114f0a1913fSSubbaraya Sundeep 	/* add the new flow installed to list */
1115f0a1913fSSubbaraya Sundeep 	if (new) {
1116f0a1913fSSubbaraya Sundeep 		otx2_add_flow_to_list(pfvf, flow);
1117f0a1913fSSubbaraya Sundeep 		flow_cfg->nr_flows++;
1118f0a1913fSSubbaraya Sundeep 	}
1119f0a1913fSSubbaraya Sundeep 
1120f0a1913fSSubbaraya Sundeep 	return 0;
1121f0a1913fSSubbaraya Sundeep }
1122f0a1913fSSubbaraya Sundeep 
1123f0a1913fSSubbaraya Sundeep static int otx2_remove_flow_msg(struct otx2_nic *pfvf, u16 entry, bool all)
1124f0a1913fSSubbaraya Sundeep {
1125f0a1913fSSubbaraya Sundeep 	struct npc_delete_flow_req *req;
1126f0a1913fSSubbaraya Sundeep 	int err;
1127f0a1913fSSubbaraya Sundeep 
1128f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
1129f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1130f0a1913fSSubbaraya Sundeep 	if (!req) {
1131f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
1132f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
1133f0a1913fSSubbaraya Sundeep 	}
1134f0a1913fSSubbaraya Sundeep 
1135f0a1913fSSubbaraya Sundeep 	req->entry = entry;
1136f0a1913fSSubbaraya Sundeep 	if (all)
1137f0a1913fSSubbaraya Sundeep 		req->all = 1;
1138f0a1913fSSubbaraya Sundeep 
1139f0a1913fSSubbaraya Sundeep 	/* Send message to AF */
1140f0a1913fSSubbaraya Sundeep 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1141f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
1142f0a1913fSSubbaraya Sundeep 	return err;
1143f0a1913fSSubbaraya Sundeep }
1144f0a1913fSSubbaraya Sundeep 
114579d2be38SHariprasad Kelam static void otx2_update_rem_pfmac(struct otx2_nic *pfvf, int req)
114679d2be38SHariprasad Kelam {
114779d2be38SHariprasad Kelam 	struct otx2_flow *iter;
114879d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr;
114979d2be38SHariprasad Kelam 	bool found = false;
115079d2be38SHariprasad Kelam 
115179d2be38SHariprasad Kelam 	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
1152*8e675581SHariprasad Kelam 		if ((iter->rule_type & DMAC_FILTER_RULE) && iter->entry == 0) {
115379d2be38SHariprasad Kelam 			eth_hdr = &iter->flow_spec.h_u.ether_spec;
115479d2be38SHariprasad Kelam 			if (req == DMAC_ADDR_DEL) {
115579d2be38SHariprasad Kelam 				otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
115679d2be38SHariprasad Kelam 						    0);
115779d2be38SHariprasad Kelam 				clear_bit(0, &pfvf->flow_cfg->dmacflt_bmap);
115879d2be38SHariprasad Kelam 				found = true;
115979d2be38SHariprasad Kelam 			} else {
116079d2be38SHariprasad Kelam 				ether_addr_copy(eth_hdr->h_dest,
116179d2be38SHariprasad Kelam 						pfvf->netdev->dev_addr);
116279d2be38SHariprasad Kelam 				otx2_dmacflt_update(pfvf, eth_hdr->h_dest, 0);
116379d2be38SHariprasad Kelam 			}
116479d2be38SHariprasad Kelam 			break;
116579d2be38SHariprasad Kelam 		}
116679d2be38SHariprasad Kelam 	}
116779d2be38SHariprasad Kelam 
116879d2be38SHariprasad Kelam 	if (found) {
116979d2be38SHariprasad Kelam 		list_del(&iter->list);
117079d2be38SHariprasad Kelam 		kfree(iter);
117179d2be38SHariprasad Kelam 		pfvf->flow_cfg->nr_flows--;
117279d2be38SHariprasad Kelam 	}
117379d2be38SHariprasad Kelam }
117479d2be38SHariprasad Kelam 
1175f0a1913fSSubbaraya Sundeep int otx2_remove_flow(struct otx2_nic *pfvf, u32 location)
1176f0a1913fSSubbaraya Sundeep {
1177f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1178f0a1913fSSubbaraya Sundeep 	struct otx2_flow *flow;
1179f0a1913fSSubbaraya Sundeep 	int err;
1180f0a1913fSSubbaraya Sundeep 
118179d2be38SHariprasad Kelam 	if (location >= otx2_get_maxflows(flow_cfg))
1182f0a1913fSSubbaraya Sundeep 		return -EINVAL;
1183f0a1913fSSubbaraya Sundeep 
1184f0a1913fSSubbaraya Sundeep 	flow = otx2_find_flow(pfvf, location);
1185f0a1913fSSubbaraya Sundeep 	if (!flow)
1186f0a1913fSSubbaraya Sundeep 		return -ENOENT;
1187f0a1913fSSubbaraya Sundeep 
1188*8e675581SHariprasad Kelam 	if (flow->rule_type & DMAC_FILTER_RULE) {
118979d2be38SHariprasad Kelam 		struct ethhdr *eth_hdr = &flow->flow_spec.h_u.ether_spec;
119079d2be38SHariprasad Kelam 
119179d2be38SHariprasad Kelam 		/* user not allowed to remove dmac filter with interface mac */
119279d2be38SHariprasad Kelam 		if (ether_addr_equal(pfvf->netdev->dev_addr, eth_hdr->h_dest))
119379d2be38SHariprasad Kelam 			return -EPERM;
119479d2be38SHariprasad Kelam 
119579d2be38SHariprasad Kelam 		err = otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
119679d2be38SHariprasad Kelam 					  flow->entry);
119779d2be38SHariprasad Kelam 		clear_bit(flow->entry, &flow_cfg->dmacflt_bmap);
119879d2be38SHariprasad Kelam 		/* If all dmac filters are removed delete macfilter with
119979d2be38SHariprasad Kelam 		 * interface mac address and configure CGX/RPM block in
120079d2be38SHariprasad Kelam 		 * promiscuous mode
120179d2be38SHariprasad Kelam 		 */
120279d2be38SHariprasad Kelam 		if (bitmap_weight(&flow_cfg->dmacflt_bmap,
120379d2be38SHariprasad Kelam 				  flow_cfg->dmacflt_max_flows) == 1)
120479d2be38SHariprasad Kelam 			otx2_update_rem_pfmac(pfvf, DMAC_ADDR_DEL);
120579d2be38SHariprasad Kelam 	} else {
1206*8e675581SHariprasad Kelam #ifdef CONFIG_DCB
1207*8e675581SHariprasad Kelam 		if (flow->rule_type & PFC_FLOWCTRL_RULE)
1208*8e675581SHariprasad Kelam 			otx2_update_bpid_in_rqctx(pfvf, 0,
1209*8e675581SHariprasad Kelam 						  flow->flow_spec.ring_cookie,
1210*8e675581SHariprasad Kelam 						  false);
1211*8e675581SHariprasad Kelam #endif
1212*8e675581SHariprasad Kelam 
1213f0a1913fSSubbaraya Sundeep 		err = otx2_remove_flow_msg(pfvf, flow->entry, false);
121479d2be38SHariprasad Kelam 	}
121579d2be38SHariprasad Kelam 
1216f0a1913fSSubbaraya Sundeep 	if (err)
1217f0a1913fSSubbaraya Sundeep 		return err;
1218f0a1913fSSubbaraya Sundeep 
1219f0a1913fSSubbaraya Sundeep 	list_del(&flow->list);
1220f0a1913fSSubbaraya Sundeep 	kfree(flow);
1221f0a1913fSSubbaraya Sundeep 	flow_cfg->nr_flows--;
1222f0a1913fSSubbaraya Sundeep 
1223f0a1913fSSubbaraya Sundeep 	return 0;
1224f0a1913fSSubbaraya Sundeep }
1225f0a1913fSSubbaraya Sundeep 
122681a43620SGeetha sowjanya void otx2_rss_ctx_flow_del(struct otx2_nic *pfvf, int ctx_id)
122781a43620SGeetha sowjanya {
122881a43620SGeetha sowjanya 	struct otx2_flow *flow, *tmp;
122981a43620SGeetha sowjanya 	int err;
123081a43620SGeetha sowjanya 
123181a43620SGeetha sowjanya 	list_for_each_entry_safe(flow, tmp, &pfvf->flow_cfg->flow_list, list) {
123281a43620SGeetha sowjanya 		if (flow->rss_ctx_id != ctx_id)
123381a43620SGeetha sowjanya 			continue;
123481a43620SGeetha sowjanya 		err = otx2_remove_flow(pfvf, flow->location);
123581a43620SGeetha sowjanya 		if (err)
123681a43620SGeetha sowjanya 			netdev_warn(pfvf->netdev,
123781a43620SGeetha sowjanya 				    "Can't delete the rule %d associated with this rss group err:%d",
123881a43620SGeetha sowjanya 				    flow->location, err);
123981a43620SGeetha sowjanya 	}
124081a43620SGeetha sowjanya }
124181a43620SGeetha sowjanya 
1242f0a1913fSSubbaraya Sundeep int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf)
1243f0a1913fSSubbaraya Sundeep {
1244f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1245f0a1913fSSubbaraya Sundeep 	struct npc_delete_flow_req *req;
1246f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter, *tmp;
1247f0a1913fSSubbaraya Sundeep 	int err;
1248f0a1913fSSubbaraya Sundeep 
1249f0a1913fSSubbaraya Sundeep 	if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
1250f0a1913fSSubbaraya Sundeep 		return 0;
1251f0a1913fSSubbaraya Sundeep 
1252a515e5b5SSunil Goutham 	if (!flow_cfg->max_flows)
1253a515e5b5SSunil Goutham 		return 0;
1254a515e5b5SSunil Goutham 
1255f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
1256f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1257f0a1913fSSubbaraya Sundeep 	if (!req) {
1258f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
1259f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
1260f0a1913fSSubbaraya Sundeep 	}
1261f0a1913fSSubbaraya Sundeep 
12629917060fSSunil Goutham 	req->start = flow_cfg->flow_ent[0];
12632e2a8126SSunil Goutham 	req->end   = flow_cfg->flow_ent[flow_cfg->max_flows - 1];
1264f0a1913fSSubbaraya Sundeep 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1265f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
1266f0a1913fSSubbaraya Sundeep 
1267f0a1913fSSubbaraya Sundeep 	list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) {
1268f0a1913fSSubbaraya Sundeep 		list_del(&iter->list);
1269f0a1913fSSubbaraya Sundeep 		kfree(iter);
1270f0a1913fSSubbaraya Sundeep 		flow_cfg->nr_flows--;
1271f0a1913fSSubbaraya Sundeep 	}
1272f0a1913fSSubbaraya Sundeep 	return err;
1273f0a1913fSSubbaraya Sundeep }
1274f0a1913fSSubbaraya Sundeep 
1275f0a1913fSSubbaraya Sundeep int otx2_destroy_mcam_flows(struct otx2_nic *pfvf)
1276f0a1913fSSubbaraya Sundeep {
1277f0a1913fSSubbaraya Sundeep 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1278f0a1913fSSubbaraya Sundeep 	struct npc_mcam_free_entry_req *req;
1279f0a1913fSSubbaraya Sundeep 	struct otx2_flow *iter, *tmp;
1280f0a1913fSSubbaraya Sundeep 	int err;
1281f0a1913fSSubbaraya Sundeep 
1282f0a1913fSSubbaraya Sundeep 	if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
1283f0a1913fSSubbaraya Sundeep 		return 0;
1284f0a1913fSSubbaraya Sundeep 
1285f0a1913fSSubbaraya Sundeep 	/* remove all flows */
1286f0a1913fSSubbaraya Sundeep 	err = otx2_remove_flow_msg(pfvf, 0, true);
1287f0a1913fSSubbaraya Sundeep 	if (err)
1288f0a1913fSSubbaraya Sundeep 		return err;
1289f0a1913fSSubbaraya Sundeep 
1290f0a1913fSSubbaraya Sundeep 	list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) {
1291f0a1913fSSubbaraya Sundeep 		list_del(&iter->list);
1292f0a1913fSSubbaraya Sundeep 		kfree(iter);
1293f0a1913fSSubbaraya Sundeep 		flow_cfg->nr_flows--;
1294f0a1913fSSubbaraya Sundeep 	}
1295f0a1913fSSubbaraya Sundeep 
1296f0a1913fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
1297f0a1913fSSubbaraya Sundeep 	req = otx2_mbox_alloc_msg_npc_mcam_free_entry(&pfvf->mbox);
1298f0a1913fSSubbaraya Sundeep 	if (!req) {
1299f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
1300f0a1913fSSubbaraya Sundeep 		return -ENOMEM;
1301f0a1913fSSubbaraya Sundeep 	}
1302f0a1913fSSubbaraya Sundeep 
1303f0a1913fSSubbaraya Sundeep 	req->all = 1;
1304f0a1913fSSubbaraya Sundeep 	/* Send message to AF to free MCAM entries */
1305f0a1913fSSubbaraya Sundeep 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1306f0a1913fSSubbaraya Sundeep 	if (err) {
1307f0a1913fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
1308f0a1913fSSubbaraya Sundeep 		return err;
1309f0a1913fSSubbaraya Sundeep 	}
1310f0a1913fSSubbaraya Sundeep 
1311f0a1913fSSubbaraya Sundeep 	pfvf->flags &= ~OTX2_FLAG_MCAM_ENTRIES_ALLOC;
1312f0a1913fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
1313f0a1913fSSubbaraya Sundeep 
1314f0a1913fSSubbaraya Sundeep 	return 0;
1315f0a1913fSSubbaraya Sundeep }
1316fd9d7859SHariprasad Kelam 
1317fd9d7859SHariprasad Kelam int otx2_install_rxvlan_offload_flow(struct otx2_nic *pfvf)
1318fd9d7859SHariprasad Kelam {
1319fd9d7859SHariprasad Kelam 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1320fd9d7859SHariprasad Kelam 	struct npc_install_flow_req *req;
1321fd9d7859SHariprasad Kelam 	int err;
1322fd9d7859SHariprasad Kelam 
1323fd9d7859SHariprasad Kelam 	mutex_lock(&pfvf->mbox.lock);
1324fd9d7859SHariprasad Kelam 	req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
1325fd9d7859SHariprasad Kelam 	if (!req) {
1326fd9d7859SHariprasad Kelam 		mutex_unlock(&pfvf->mbox.lock);
1327fd9d7859SHariprasad Kelam 		return -ENOMEM;
1328fd9d7859SHariprasad Kelam 	}
1329fd9d7859SHariprasad Kelam 
13309917060fSSunil Goutham 	req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
1331fd9d7859SHariprasad Kelam 	req->intf = NIX_INTF_RX;
1332fd9d7859SHariprasad Kelam 	ether_addr_copy(req->packet.dmac, pfvf->netdev->dev_addr);
1333fd9d7859SHariprasad Kelam 	eth_broadcast_addr((u8 *)&req->mask.dmac);
1334fd9d7859SHariprasad Kelam 	req->channel = pfvf->hw.rx_chan_base;
1335fd9d7859SHariprasad Kelam 	req->op = NIX_RX_ACTION_DEFAULT;
1336fd9d7859SHariprasad Kelam 	req->features = BIT_ULL(NPC_OUTER_VID) | BIT_ULL(NPC_DMAC);
1337fd9d7859SHariprasad Kelam 	req->vtag0_valid = true;
1338fd9d7859SHariprasad Kelam 	req->vtag0_type = NIX_AF_LFX_RX_VTAG_TYPE0;
1339fd9d7859SHariprasad Kelam 
1340fd9d7859SHariprasad Kelam 	/* Send message to AF */
1341fd9d7859SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1342fd9d7859SHariprasad Kelam 	mutex_unlock(&pfvf->mbox.lock);
1343fd9d7859SHariprasad Kelam 	return err;
1344fd9d7859SHariprasad Kelam }
1345fd9d7859SHariprasad Kelam 
1346fd9d7859SHariprasad Kelam static int otx2_delete_rxvlan_offload_flow(struct otx2_nic *pfvf)
1347fd9d7859SHariprasad Kelam {
1348fd9d7859SHariprasad Kelam 	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1349fd9d7859SHariprasad Kelam 	struct npc_delete_flow_req *req;
1350fd9d7859SHariprasad Kelam 	int err;
1351fd9d7859SHariprasad Kelam 
1352fd9d7859SHariprasad Kelam 	mutex_lock(&pfvf->mbox.lock);
1353fd9d7859SHariprasad Kelam 	req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1354fd9d7859SHariprasad Kelam 	if (!req) {
1355fd9d7859SHariprasad Kelam 		mutex_unlock(&pfvf->mbox.lock);
1356fd9d7859SHariprasad Kelam 		return -ENOMEM;
1357fd9d7859SHariprasad Kelam 	}
1358fd9d7859SHariprasad Kelam 
13599917060fSSunil Goutham 	req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
1360fd9d7859SHariprasad Kelam 	/* Send message to AF */
1361fd9d7859SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1362fd9d7859SHariprasad Kelam 	mutex_unlock(&pfvf->mbox.lock);
1363fd9d7859SHariprasad Kelam 	return err;
1364fd9d7859SHariprasad Kelam }
1365fd9d7859SHariprasad Kelam 
1366fd9d7859SHariprasad Kelam int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable)
1367fd9d7859SHariprasad Kelam {
1368fd9d7859SHariprasad Kelam 	struct nix_vtag_config *req;
1369fd9d7859SHariprasad Kelam 	struct mbox_msghdr *rsp_hdr;
1370fd9d7859SHariprasad Kelam 	int err;
1371fd9d7859SHariprasad Kelam 
1372fd9d7859SHariprasad Kelam 	/* Dont have enough mcam entries */
1373fd9d7859SHariprasad Kelam 	if (!(pf->flags & OTX2_FLAG_RX_VLAN_SUPPORT))
1374fd9d7859SHariprasad Kelam 		return -ENOMEM;
1375fd9d7859SHariprasad Kelam 
1376fd9d7859SHariprasad Kelam 	if (enable) {
1377fd9d7859SHariprasad Kelam 		err = otx2_install_rxvlan_offload_flow(pf);
1378fd9d7859SHariprasad Kelam 		if (err)
1379fd9d7859SHariprasad Kelam 			return err;
1380fd9d7859SHariprasad Kelam 	} else {
1381fd9d7859SHariprasad Kelam 		err = otx2_delete_rxvlan_offload_flow(pf);
1382fd9d7859SHariprasad Kelam 		if (err)
1383fd9d7859SHariprasad Kelam 			return err;
1384fd9d7859SHariprasad Kelam 	}
1385fd9d7859SHariprasad Kelam 
1386fd9d7859SHariprasad Kelam 	mutex_lock(&pf->mbox.lock);
1387fd9d7859SHariprasad Kelam 	req = otx2_mbox_alloc_msg_nix_vtag_cfg(&pf->mbox);
1388fd9d7859SHariprasad Kelam 	if (!req) {
1389fd9d7859SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
1390fd9d7859SHariprasad Kelam 		return -ENOMEM;
1391fd9d7859SHariprasad Kelam 	}
1392fd9d7859SHariprasad Kelam 
1393fd9d7859SHariprasad Kelam 	/* config strip, capture and size */
1394fd9d7859SHariprasad Kelam 	req->vtag_size = VTAGSIZE_T4;
1395fd9d7859SHariprasad Kelam 	req->cfg_type = 1; /* rx vlan cfg */
1396fd9d7859SHariprasad Kelam 	req->rx.vtag_type = NIX_AF_LFX_RX_VTAG_TYPE0;
1397fd9d7859SHariprasad Kelam 	req->rx.strip_vtag = enable;
1398fd9d7859SHariprasad Kelam 	req->rx.capture_vtag = enable;
1399fd9d7859SHariprasad Kelam 
1400fd9d7859SHariprasad Kelam 	err = otx2_sync_mbox_msg(&pf->mbox);
1401fd9d7859SHariprasad Kelam 	if (err) {
1402fd9d7859SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
1403fd9d7859SHariprasad Kelam 		return err;
1404fd9d7859SHariprasad Kelam 	}
1405fd9d7859SHariprasad Kelam 
1406fd9d7859SHariprasad Kelam 	rsp_hdr = otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr);
1407fd9d7859SHariprasad Kelam 	if (IS_ERR(rsp_hdr)) {
1408fd9d7859SHariprasad Kelam 		mutex_unlock(&pf->mbox.lock);
1409fd9d7859SHariprasad Kelam 		return PTR_ERR(rsp_hdr);
1410fd9d7859SHariprasad Kelam 	}
1411fd9d7859SHariprasad Kelam 
1412fd9d7859SHariprasad Kelam 	mutex_unlock(&pf->mbox.lock);
1413fd9d7859SHariprasad Kelam 	return rsp_hdr->rc;
1414fd9d7859SHariprasad Kelam }
141579d2be38SHariprasad Kelam 
141679d2be38SHariprasad Kelam void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf)
141779d2be38SHariprasad Kelam {
141879d2be38SHariprasad Kelam 	struct otx2_flow *iter;
141979d2be38SHariprasad Kelam 	struct ethhdr *eth_hdr;
142079d2be38SHariprasad Kelam 
142179d2be38SHariprasad Kelam 	list_for_each_entry(iter, &pf->flow_cfg->flow_list, list) {
1422*8e675581SHariprasad Kelam 		if (iter->rule_type & DMAC_FILTER_RULE) {
142379d2be38SHariprasad Kelam 			eth_hdr = &iter->flow_spec.h_u.ether_spec;
142479d2be38SHariprasad Kelam 			otx2_dmacflt_add(pf, eth_hdr->h_dest,
142579d2be38SHariprasad Kelam 					 iter->entry);
142679d2be38SHariprasad Kelam 		}
142779d2be38SHariprasad Kelam 	}
142879d2be38SHariprasad Kelam }
142979d2be38SHariprasad Kelam 
143079d2be38SHariprasad Kelam void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf)
143179d2be38SHariprasad Kelam {
143279d2be38SHariprasad Kelam 	otx2_update_rem_pfmac(pfvf, DMAC_ADDR_UPDATE);
143379d2be38SHariprasad Kelam }
1434