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;
21fa5e0ccbSRatheesh 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
otx2_clear_ntuple_flow_info(struct otx2_nic * pfvf,struct otx2_flow_config * flow_cfg)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
otx2_free_ntuple_mcam_entries(struct otx2_nic * pfvf)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
mcam_entry_cmp(const void * a,const void * b)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
otx2_alloc_mcam_entries(struct otx2_nic * pfvf,u16 count)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
otx2_mcam_entry_init(struct otx2_nic * pfvf)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;
167674b3e16SSuman Ghosh struct npc_get_field_status_req *freq;
168674b3e16SSuman Ghosh struct npc_get_field_status_rsp *frsp;
169f0a1913fSSubbaraya Sundeep struct npc_mcam_alloc_entry_req *req;
170f0a1913fSSubbaraya Sundeep struct npc_mcam_alloc_entry_rsp *rsp;
171f0c2982aSNaveen Mamindlapalli int vf_vlan_max_flows;
1729917060fSSunil Goutham int ent, count;
1739917060fSSunil Goutham
1749917060fSSunil Goutham vf_vlan_max_flows = pfvf->total_vfs * OTX2_PER_VF_VLAN_FLOWS;
1759917060fSSunil Goutham count = OTX2_MAX_UNICAST_FLOWS +
1769917060fSSunil Goutham OTX2_MAX_VLAN_FLOWS + vf_vlan_max_flows;
1779917060fSSunil Goutham
1789917060fSSunil Goutham flow_cfg->def_ent = devm_kmalloc_array(pfvf->dev, count,
1799917060fSSunil Goutham sizeof(u16), GFP_KERNEL);
1809917060fSSunil Goutham if (!flow_cfg->def_ent)
1819917060fSSunil Goutham return -ENOMEM;
182f0a1913fSSubbaraya Sundeep
183f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
184f0a1913fSSubbaraya Sundeep
185f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&pfvf->mbox);
186f0a1913fSSubbaraya Sundeep if (!req) {
187f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
188f0a1913fSSubbaraya Sundeep return -ENOMEM;
189f0a1913fSSubbaraya Sundeep }
190f0a1913fSSubbaraya Sundeep
191f0a1913fSSubbaraya Sundeep req->contig = false;
1929917060fSSunil Goutham req->count = count;
193f0a1913fSSubbaraya Sundeep
194f0a1913fSSubbaraya Sundeep /* Send message to AF */
195f0a1913fSSubbaraya Sundeep if (otx2_sync_mbox_msg(&pfvf->mbox)) {
196f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
197f0a1913fSSubbaraya Sundeep return -EINVAL;
198f0a1913fSSubbaraya Sundeep }
199f0a1913fSSubbaraya Sundeep
200f0a1913fSSubbaraya Sundeep rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp
201f0a1913fSSubbaraya Sundeep (&pfvf->mbox.mbox, 0, &req->hdr);
202f0a1913fSSubbaraya Sundeep
20363ee5157SHariprasad Kelam if (rsp->count != req->count) {
204f0a1913fSSubbaraya Sundeep netdev_info(pfvf->netdev,
2059917060fSSunil Goutham "Unable to allocate MCAM entries for ucast, vlan and vf_vlan\n");
2069917060fSSunil Goutham mutex_unlock(&pfvf->mbox.lock);
2079917060fSSunil Goutham devm_kfree(pfvf->dev, flow_cfg->def_ent);
2089917060fSSunil Goutham return 0;
2099917060fSSunil Goutham }
2109917060fSSunil Goutham
2119917060fSSunil Goutham for (ent = 0; ent < rsp->count; ent++)
2129917060fSSunil Goutham flow_cfg->def_ent[ent] = rsp->entry_list[ent];
2139917060fSSunil Goutham
214f0c2982aSNaveen Mamindlapalli flow_cfg->vf_vlan_offset = 0;
2159917060fSSunil Goutham flow_cfg->unicast_offset = vf_vlan_max_flows;
216fd9d7859SHariprasad Kelam flow_cfg->rx_vlan_offset = flow_cfg->unicast_offset +
217fd9d7859SHariprasad Kelam OTX2_MAX_UNICAST_FLOWS;
21863ee5157SHariprasad Kelam pfvf->flags |= OTX2_FLAG_UCAST_FLTR_SUPPORT;
219674b3e16SSuman Ghosh
220674b3e16SSuman Ghosh /* Check if NPC_DMAC field is supported
221674b3e16SSuman Ghosh * by the mkex profile before setting VLAN support flag.
222674b3e16SSuman Ghosh */
223674b3e16SSuman Ghosh freq = otx2_mbox_alloc_msg_npc_get_field_status(&pfvf->mbox);
224674b3e16SSuman Ghosh if (!freq) {
225674b3e16SSuman Ghosh mutex_unlock(&pfvf->mbox.lock);
226674b3e16SSuman Ghosh return -ENOMEM;
227674b3e16SSuman Ghosh }
228674b3e16SSuman Ghosh
229674b3e16SSuman Ghosh freq->field = NPC_DMAC;
230674b3e16SSuman Ghosh if (otx2_sync_mbox_msg(&pfvf->mbox)) {
231674b3e16SSuman Ghosh mutex_unlock(&pfvf->mbox.lock);
232674b3e16SSuman Ghosh return -EINVAL;
233674b3e16SSuman Ghosh }
234674b3e16SSuman Ghosh
235674b3e16SSuman Ghosh frsp = (struct npc_get_field_status_rsp *)otx2_mbox_get_rsp
236674b3e16SSuman Ghosh (&pfvf->mbox.mbox, 0, &freq->hdr);
237674b3e16SSuman Ghosh
238674b3e16SSuman Ghosh if (frsp->enable) {
239fd9d7859SHariprasad Kelam pfvf->flags |= OTX2_FLAG_RX_VLAN_SUPPORT;
240f0c2982aSNaveen Mamindlapalli pfvf->flags |= OTX2_FLAG_VF_VLAN_SUPPORT;
241674b3e16SSuman Ghosh }
242f0a1913fSSubbaraya Sundeep
243f0a1913fSSubbaraya Sundeep pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
244f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
245f0a1913fSSubbaraya Sundeep
2469917060fSSunil Goutham /* Allocate entries for Ntuple filters */
2472da48943SSunil Goutham count = otx2_alloc_mcam_entries(pfvf, OTX2_DEFAULT_FLOWCOUNT);
2489917060fSSunil Goutham if (count <= 0) {
2499917060fSSunil Goutham otx2_clear_ntuple_flow_info(pfvf, flow_cfg);
2509917060fSSunil Goutham return 0;
2519917060fSSunil Goutham }
2529917060fSSunil Goutham
2539917060fSSunil Goutham pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
2549917060fSSunil Goutham
255f0a1913fSSubbaraya Sundeep return 0;
256f0a1913fSSubbaraya Sundeep }
257f0a1913fSSubbaraya Sundeep
258fa5e0ccbSRatheesh Kannoth /* TODO : revisit on size */
259fa5e0ccbSRatheesh Kannoth #define OTX2_DMAC_FLTR_BITMAP_SZ (4 * 2048 + 32)
260fa5e0ccbSRatheesh Kannoth
otx2vf_mcam_flow_init(struct otx2_nic * pfvf)2613cffaed2SRakesh Babu int otx2vf_mcam_flow_init(struct otx2_nic *pfvf)
2623cffaed2SRakesh Babu {
2633cffaed2SRakesh Babu struct otx2_flow_config *flow_cfg;
2643cffaed2SRakesh Babu
2653cffaed2SRakesh Babu pfvf->flow_cfg = devm_kzalloc(pfvf->dev,
2663cffaed2SRakesh Babu sizeof(struct otx2_flow_config),
2673cffaed2SRakesh Babu GFP_KERNEL);
2683cffaed2SRakesh Babu if (!pfvf->flow_cfg)
2693cffaed2SRakesh Babu return -ENOMEM;
2703cffaed2SRakesh Babu
271fa5e0ccbSRatheesh Kannoth pfvf->flow_cfg->dmacflt_bmap = devm_kcalloc(pfvf->dev,
272fa5e0ccbSRatheesh Kannoth BITS_TO_LONGS(OTX2_DMAC_FLTR_BITMAP_SZ),
273fa5e0ccbSRatheesh Kannoth sizeof(long), GFP_KERNEL);
274fa5e0ccbSRatheesh Kannoth if (!pfvf->flow_cfg->dmacflt_bmap)
275fa5e0ccbSRatheesh Kannoth return -ENOMEM;
276fa5e0ccbSRatheesh Kannoth
2773cffaed2SRakesh Babu flow_cfg = pfvf->flow_cfg;
2783cffaed2SRakesh Babu INIT_LIST_HEAD(&flow_cfg->flow_list);
279ec87f054SSuman Ghosh INIT_LIST_HEAD(&flow_cfg->flow_list_tc);
2802e2a8126SSunil Goutham flow_cfg->max_flows = 0;
2813cffaed2SRakesh Babu
2823cffaed2SRakesh Babu return 0;
2833cffaed2SRakesh Babu }
2843cffaed2SRakesh Babu EXPORT_SYMBOL(otx2vf_mcam_flow_init);
2853cffaed2SRakesh Babu
otx2_mcam_flow_init(struct otx2_nic * pf)286f0a1913fSSubbaraya Sundeep int otx2_mcam_flow_init(struct otx2_nic *pf)
287f0a1913fSSubbaraya Sundeep {
288f0a1913fSSubbaraya Sundeep int err;
289f0a1913fSSubbaraya Sundeep
290f0a1913fSSubbaraya Sundeep pf->flow_cfg = devm_kzalloc(pf->dev, sizeof(struct otx2_flow_config),
291f0a1913fSSubbaraya Sundeep GFP_KERNEL);
292f0a1913fSSubbaraya Sundeep if (!pf->flow_cfg)
293f0a1913fSSubbaraya Sundeep return -ENOMEM;
294f0a1913fSSubbaraya Sundeep
295fa5e0ccbSRatheesh Kannoth pf->flow_cfg->dmacflt_bmap = devm_kcalloc(pf->dev,
296fa5e0ccbSRatheesh Kannoth BITS_TO_LONGS(OTX2_DMAC_FLTR_BITMAP_SZ),
297fa5e0ccbSRatheesh Kannoth sizeof(long), GFP_KERNEL);
298fa5e0ccbSRatheesh Kannoth if (!pf->flow_cfg->dmacflt_bmap)
299fa5e0ccbSRatheesh Kannoth return -ENOMEM;
300fa5e0ccbSRatheesh Kannoth
301f0a1913fSSubbaraya Sundeep INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
302ec87f054SSuman Ghosh INIT_LIST_HEAD(&pf->flow_cfg->flow_list_tc);
303f0a1913fSSubbaraya Sundeep
3042da48943SSunil Goutham /* Allocate bare minimum number of MCAM entries needed for
3052da48943SSunil Goutham * unicast and ntuple filters.
3062da48943SSunil Goutham */
3072da48943SSunil Goutham err = otx2_mcam_entry_init(pf);
308f0a1913fSSubbaraya Sundeep if (err)
309f0a1913fSSubbaraya Sundeep return err;
310f0a1913fSSubbaraya Sundeep
3119917060fSSunil Goutham /* Check if MCAM entries are allocate or not */
3129917060fSSunil Goutham if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
3139917060fSSunil Goutham return 0;
3149917060fSSunil Goutham
31563ee5157SHariprasad Kelam pf->mac_table = devm_kzalloc(pf->dev, sizeof(struct otx2_mac_table)
31663ee5157SHariprasad Kelam * OTX2_MAX_UNICAST_FLOWS, GFP_KERNEL);
31763ee5157SHariprasad Kelam if (!pf->mac_table)
31863ee5157SHariprasad Kelam return -ENOMEM;
31963ee5157SHariprasad Kelam
32079d2be38SHariprasad Kelam otx2_dmacflt_get_max_cnt(pf);
32179d2be38SHariprasad Kelam
32279d2be38SHariprasad Kelam /* DMAC filters are not allocated */
32379d2be38SHariprasad Kelam if (!pf->flow_cfg->dmacflt_max_flows)
32479d2be38SHariprasad Kelam return 0;
32579d2be38SHariprasad Kelam
32679d2be38SHariprasad Kelam pf->flow_cfg->bmap_to_dmacindex =
327fa5e0ccbSRatheesh Kannoth devm_kzalloc(pf->dev, sizeof(u32) *
32879d2be38SHariprasad Kelam pf->flow_cfg->dmacflt_max_flows,
32979d2be38SHariprasad Kelam GFP_KERNEL);
33079d2be38SHariprasad Kelam
33179d2be38SHariprasad Kelam if (!pf->flow_cfg->bmap_to_dmacindex)
33279d2be38SHariprasad Kelam return -ENOMEM;
33379d2be38SHariprasad Kelam
33479d2be38SHariprasad Kelam pf->flags |= OTX2_FLAG_DMACFLTR_SUPPORT;
33579d2be38SHariprasad Kelam
336f0a1913fSSubbaraya Sundeep return 0;
337f0a1913fSSubbaraya Sundeep }
338f0a1913fSSubbaraya Sundeep
otx2_mcam_flow_del(struct otx2_nic * pf)339f0a1913fSSubbaraya Sundeep void otx2_mcam_flow_del(struct otx2_nic *pf)
340f0a1913fSSubbaraya Sundeep {
341f0a1913fSSubbaraya Sundeep otx2_destroy_mcam_flows(pf);
342f0a1913fSSubbaraya Sundeep }
3433cffaed2SRakesh Babu EXPORT_SYMBOL(otx2_mcam_flow_del);
344f0a1913fSSubbaraya Sundeep
34563ee5157SHariprasad Kelam /* On success adds mcam entry
34663ee5157SHariprasad Kelam * On failure enable promisous mode
34763ee5157SHariprasad Kelam */
otx2_do_add_macfilter(struct otx2_nic * pf,const u8 * mac)34863ee5157SHariprasad Kelam static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac)
34963ee5157SHariprasad Kelam {
35063ee5157SHariprasad Kelam struct otx2_flow_config *flow_cfg = pf->flow_cfg;
35163ee5157SHariprasad Kelam struct npc_install_flow_req *req;
35263ee5157SHariprasad Kelam int err, i;
35363ee5157SHariprasad Kelam
35463ee5157SHariprasad Kelam if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
35563ee5157SHariprasad Kelam return -ENOMEM;
35663ee5157SHariprasad Kelam
35763ee5157SHariprasad Kelam /* dont have free mcam entries or uc list is greater than alloted */
35863ee5157SHariprasad Kelam if (netdev_uc_count(pf->netdev) > OTX2_MAX_UNICAST_FLOWS)
35963ee5157SHariprasad Kelam return -ENOMEM;
36063ee5157SHariprasad Kelam
36163ee5157SHariprasad Kelam mutex_lock(&pf->mbox.lock);
36263ee5157SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_install_flow(&pf->mbox);
36363ee5157SHariprasad Kelam if (!req) {
36463ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
36563ee5157SHariprasad Kelam return -ENOMEM;
36663ee5157SHariprasad Kelam }
36763ee5157SHariprasad Kelam
36863ee5157SHariprasad Kelam /* unicast offset starts with 32 0..31 for ntuple */
36963ee5157SHariprasad Kelam for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) {
37063ee5157SHariprasad Kelam if (pf->mac_table[i].inuse)
37163ee5157SHariprasad Kelam continue;
37263ee5157SHariprasad Kelam ether_addr_copy(pf->mac_table[i].addr, mac);
37363ee5157SHariprasad Kelam pf->mac_table[i].inuse = true;
37463ee5157SHariprasad Kelam pf->mac_table[i].mcam_entry =
3759917060fSSunil Goutham flow_cfg->def_ent[i + flow_cfg->unicast_offset];
37663ee5157SHariprasad Kelam req->entry = pf->mac_table[i].mcam_entry;
37763ee5157SHariprasad Kelam break;
37863ee5157SHariprasad Kelam }
37963ee5157SHariprasad Kelam
38063ee5157SHariprasad Kelam ether_addr_copy(req->packet.dmac, mac);
38163ee5157SHariprasad Kelam eth_broadcast_addr((u8 *)&req->mask.dmac);
38263ee5157SHariprasad Kelam req->features = BIT_ULL(NPC_DMAC);
38363ee5157SHariprasad Kelam req->channel = pf->hw.rx_chan_base;
38463ee5157SHariprasad Kelam req->intf = NIX_INTF_RX;
38563ee5157SHariprasad Kelam req->op = NIX_RX_ACTION_DEFAULT;
38663ee5157SHariprasad Kelam req->set_cntr = 1;
38763ee5157SHariprasad Kelam
38863ee5157SHariprasad Kelam err = otx2_sync_mbox_msg(&pf->mbox);
38963ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
39063ee5157SHariprasad Kelam
39163ee5157SHariprasad Kelam return err;
39263ee5157SHariprasad Kelam }
39363ee5157SHariprasad Kelam
otx2_add_macfilter(struct net_device * netdev,const u8 * mac)39463ee5157SHariprasad Kelam int otx2_add_macfilter(struct net_device *netdev, const u8 *mac)
39563ee5157SHariprasad Kelam {
39663ee5157SHariprasad Kelam struct otx2_nic *pf = netdev_priv(netdev);
39763ee5157SHariprasad Kelam
398fa5e0ccbSRatheesh Kannoth if (!bitmap_empty(pf->flow_cfg->dmacflt_bmap,
39979d2be38SHariprasad Kelam pf->flow_cfg->dmacflt_max_flows))
40079d2be38SHariprasad Kelam netdev_warn(netdev,
40179d2be38SHariprasad Kelam "Add %pM to CGX/RPM DMAC filters list as well\n",
40279d2be38SHariprasad Kelam mac);
40379d2be38SHariprasad Kelam
40463ee5157SHariprasad Kelam return otx2_do_add_macfilter(pf, mac);
40563ee5157SHariprasad Kelam }
40663ee5157SHariprasad Kelam
otx2_get_mcamentry_for_mac(struct otx2_nic * pf,const u8 * mac,int * mcam_entry)40763ee5157SHariprasad Kelam static bool otx2_get_mcamentry_for_mac(struct otx2_nic *pf, const u8 *mac,
40863ee5157SHariprasad Kelam int *mcam_entry)
40963ee5157SHariprasad Kelam {
41063ee5157SHariprasad Kelam int i;
41163ee5157SHariprasad Kelam
41263ee5157SHariprasad Kelam for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) {
41363ee5157SHariprasad Kelam if (!pf->mac_table[i].inuse)
41463ee5157SHariprasad Kelam continue;
41563ee5157SHariprasad Kelam
41663ee5157SHariprasad Kelam if (ether_addr_equal(pf->mac_table[i].addr, mac)) {
41763ee5157SHariprasad Kelam *mcam_entry = pf->mac_table[i].mcam_entry;
41863ee5157SHariprasad Kelam pf->mac_table[i].inuse = false;
41963ee5157SHariprasad Kelam return true;
42063ee5157SHariprasad Kelam }
42163ee5157SHariprasad Kelam }
42263ee5157SHariprasad Kelam return false;
42363ee5157SHariprasad Kelam }
42463ee5157SHariprasad Kelam
otx2_del_macfilter(struct net_device * netdev,const u8 * mac)42563ee5157SHariprasad Kelam int otx2_del_macfilter(struct net_device *netdev, const u8 *mac)
42663ee5157SHariprasad Kelam {
42763ee5157SHariprasad Kelam struct otx2_nic *pf = netdev_priv(netdev);
42863ee5157SHariprasad Kelam struct npc_delete_flow_req *req;
42963ee5157SHariprasad Kelam int err, mcam_entry;
43063ee5157SHariprasad Kelam
43163ee5157SHariprasad Kelam /* check does mcam entry exists for given mac */
43263ee5157SHariprasad Kelam if (!otx2_get_mcamentry_for_mac(pf, mac, &mcam_entry))
43363ee5157SHariprasad Kelam return 0;
43463ee5157SHariprasad Kelam
43563ee5157SHariprasad Kelam mutex_lock(&pf->mbox.lock);
43663ee5157SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_delete_flow(&pf->mbox);
43763ee5157SHariprasad Kelam if (!req) {
43863ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
43963ee5157SHariprasad Kelam return -ENOMEM;
44063ee5157SHariprasad Kelam }
44163ee5157SHariprasad Kelam req->entry = mcam_entry;
44263ee5157SHariprasad Kelam /* Send message to AF */
44363ee5157SHariprasad Kelam err = otx2_sync_mbox_msg(&pf->mbox);
44463ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
44563ee5157SHariprasad Kelam
44663ee5157SHariprasad Kelam return err;
44763ee5157SHariprasad Kelam }
44863ee5157SHariprasad Kelam
otx2_find_flow(struct otx2_nic * pfvf,u32 location)449f0a1913fSSubbaraya Sundeep static struct otx2_flow *otx2_find_flow(struct otx2_nic *pfvf, u32 location)
450f0a1913fSSubbaraya Sundeep {
451f0a1913fSSubbaraya Sundeep struct otx2_flow *iter;
452f0a1913fSSubbaraya Sundeep
453f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
454f0a1913fSSubbaraya Sundeep if (iter->location == location)
455f0a1913fSSubbaraya Sundeep return iter;
456f0a1913fSSubbaraya Sundeep }
457f0a1913fSSubbaraya Sundeep
458f0a1913fSSubbaraya Sundeep return NULL;
459f0a1913fSSubbaraya Sundeep }
460f0a1913fSSubbaraya Sundeep
otx2_add_flow_to_list(struct otx2_nic * pfvf,struct otx2_flow * flow)461f0a1913fSSubbaraya Sundeep static void otx2_add_flow_to_list(struct otx2_nic *pfvf, struct otx2_flow *flow)
462f0a1913fSSubbaraya Sundeep {
463f0a1913fSSubbaraya Sundeep struct list_head *head = &pfvf->flow_cfg->flow_list;
464f0a1913fSSubbaraya Sundeep struct otx2_flow *iter;
465f0a1913fSSubbaraya Sundeep
466f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
467f0a1913fSSubbaraya Sundeep if (iter->location > flow->location)
468f0a1913fSSubbaraya Sundeep break;
469f0a1913fSSubbaraya Sundeep head = &iter->list;
470f0a1913fSSubbaraya Sundeep }
471f0a1913fSSubbaraya Sundeep
472f0a1913fSSubbaraya Sundeep list_add(&flow->list, head);
473f0a1913fSSubbaraya Sundeep }
474f0a1913fSSubbaraya Sundeep
otx2_get_maxflows(struct otx2_flow_config * flow_cfg)4753cffaed2SRakesh Babu int otx2_get_maxflows(struct otx2_flow_config *flow_cfg)
47679d2be38SHariprasad Kelam {
4773cffaed2SRakesh Babu if (!flow_cfg)
4783cffaed2SRakesh Babu return 0;
4793cffaed2SRakesh Babu
4802e2a8126SSunil Goutham if (flow_cfg->nr_flows == flow_cfg->max_flows ||
481fa5e0ccbSRatheesh Kannoth !bitmap_empty(flow_cfg->dmacflt_bmap,
48279d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows))
4832e2a8126SSunil Goutham return flow_cfg->max_flows + flow_cfg->dmacflt_max_flows;
48479d2be38SHariprasad Kelam else
4852e2a8126SSunil Goutham return flow_cfg->max_flows;
48679d2be38SHariprasad Kelam }
4873cffaed2SRakesh Babu EXPORT_SYMBOL(otx2_get_maxflows);
48879d2be38SHariprasad Kelam
otx2_get_flow(struct otx2_nic * pfvf,struct ethtool_rxnfc * nfc,u32 location)489f0a1913fSSubbaraya Sundeep int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
490f0a1913fSSubbaraya Sundeep u32 location)
491f0a1913fSSubbaraya Sundeep {
492f0a1913fSSubbaraya Sundeep struct otx2_flow *iter;
493f0a1913fSSubbaraya Sundeep
49479d2be38SHariprasad Kelam if (location >= otx2_get_maxflows(pfvf->flow_cfg))
495f0a1913fSSubbaraya Sundeep return -EINVAL;
496f0a1913fSSubbaraya Sundeep
497f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
498f0a1913fSSubbaraya Sundeep if (iter->location == location) {
499f0a1913fSSubbaraya Sundeep nfc->fs = iter->flow_spec;
50081a43620SGeetha sowjanya nfc->rss_context = iter->rss_ctx_id;
501f0a1913fSSubbaraya Sundeep return 0;
502f0a1913fSSubbaraya Sundeep }
503f0a1913fSSubbaraya Sundeep }
504f0a1913fSSubbaraya Sundeep
505f0a1913fSSubbaraya Sundeep return -ENOENT;
506f0a1913fSSubbaraya Sundeep }
507f0a1913fSSubbaraya Sundeep
otx2_get_all_flows(struct otx2_nic * pfvf,struct ethtool_rxnfc * nfc,u32 * rule_locs)508f0a1913fSSubbaraya Sundeep int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
509f0a1913fSSubbaraya Sundeep u32 *rule_locs)
510f0a1913fSSubbaraya Sundeep {
511f41b2d67SSubbaraya Sundeep u32 rule_cnt = nfc->rule_cnt;
512f0a1913fSSubbaraya Sundeep u32 location = 0;
513f0a1913fSSubbaraya Sundeep int idx = 0;
514f0a1913fSSubbaraya Sundeep int err = 0;
515f0a1913fSSubbaraya Sundeep
51679d2be38SHariprasad Kelam nfc->data = otx2_get_maxflows(pfvf->flow_cfg);
517f41b2d67SSubbaraya Sundeep while ((!err || err == -ENOENT) && idx < rule_cnt) {
518f0a1913fSSubbaraya Sundeep err = otx2_get_flow(pfvf, nfc, location);
519f0a1913fSSubbaraya Sundeep if (!err)
520f0a1913fSSubbaraya Sundeep rule_locs[idx++] = location;
521f0a1913fSSubbaraya Sundeep location++;
522f0a1913fSSubbaraya Sundeep }
523f41b2d67SSubbaraya Sundeep nfc->rule_cnt = rule_cnt;
524f0a1913fSSubbaraya Sundeep
525f0a1913fSSubbaraya Sundeep return err;
526f0a1913fSSubbaraya Sundeep }
527f0a1913fSSubbaraya Sundeep
otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec * fsp,struct npc_install_flow_req * req,u32 flow_type)528b7cf9661SNaveen Mamindlapalli static int otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp,
529f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req,
530f0a1913fSSubbaraya Sundeep u32 flow_type)
531f0a1913fSSubbaraya Sundeep {
532f0a1913fSSubbaraya Sundeep struct ethtool_usrip4_spec *ipv4_usr_mask = &fsp->m_u.usr_ip4_spec;
533f0a1913fSSubbaraya Sundeep struct ethtool_usrip4_spec *ipv4_usr_hdr = &fsp->h_u.usr_ip4_spec;
534f0a1913fSSubbaraya Sundeep struct ethtool_tcpip4_spec *ipv4_l4_mask = &fsp->m_u.tcp_ip4_spec;
535f0a1913fSSubbaraya Sundeep struct ethtool_tcpip4_spec *ipv4_l4_hdr = &fsp->h_u.tcp_ip4_spec;
536b7cf9661SNaveen Mamindlapalli struct ethtool_ah_espip4_spec *ah_esp_hdr = &fsp->h_u.ah_ip4_spec;
537b7cf9661SNaveen Mamindlapalli struct ethtool_ah_espip4_spec *ah_esp_mask = &fsp->m_u.ah_ip4_spec;
538f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask;
539f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet;
540f0a1913fSSubbaraya Sundeep
541f0a1913fSSubbaraya Sundeep switch (flow_type) {
542f0a1913fSSubbaraya Sundeep case IP_USER_FLOW:
543f0a1913fSSubbaraya Sundeep if (ipv4_usr_mask->ip4src) {
544f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4src, &ipv4_usr_hdr->ip4src,
545f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4src));
546f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4src, &ipv4_usr_mask->ip4src,
547f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4src));
548f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV4);
549f0a1913fSSubbaraya Sundeep }
550f0a1913fSSubbaraya Sundeep if (ipv4_usr_mask->ip4dst) {
551f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4dst, &ipv4_usr_hdr->ip4dst,
552f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4dst));
553f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4dst, &ipv4_usr_mask->ip4dst,
554f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4dst));
555f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV4);
556f0a1913fSSubbaraya Sundeep }
5572b9cef66SNaveen Mamindlapalli if (ipv4_usr_mask->tos) {
5582b9cef66SNaveen Mamindlapalli pkt->tos = ipv4_usr_hdr->tos;
5592b9cef66SNaveen Mamindlapalli pmask->tos = ipv4_usr_mask->tos;
5602b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_TOS);
5612b9cef66SNaveen Mamindlapalli }
5622b9cef66SNaveen Mamindlapalli if (ipv4_usr_mask->proto) {
5632b9cef66SNaveen Mamindlapalli switch (ipv4_usr_hdr->proto) {
5642b9cef66SNaveen Mamindlapalli case IPPROTO_ICMP:
5652b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_ICMP);
5662b9cef66SNaveen Mamindlapalli break;
5672b9cef66SNaveen Mamindlapalli case IPPROTO_TCP:
5682b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_TCP);
5692b9cef66SNaveen Mamindlapalli break;
5702b9cef66SNaveen Mamindlapalli case IPPROTO_UDP:
5712b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_UDP);
5722b9cef66SNaveen Mamindlapalli break;
5732b9cef66SNaveen Mamindlapalli case IPPROTO_SCTP:
5742b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
5752b9cef66SNaveen Mamindlapalli break;
5762b9cef66SNaveen Mamindlapalli case IPPROTO_AH:
5772b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_AH);
5782b9cef66SNaveen Mamindlapalli break;
5792b9cef66SNaveen Mamindlapalli case IPPROTO_ESP:
5802b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_ESP);
5812b9cef66SNaveen Mamindlapalli break;
5822b9cef66SNaveen Mamindlapalli default:
5832b9cef66SNaveen Mamindlapalli return -EOPNOTSUPP;
5842b9cef66SNaveen Mamindlapalli }
5852b9cef66SNaveen Mamindlapalli }
586b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IP);
587b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
588b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
589f0a1913fSSubbaraya Sundeep break;
590f0a1913fSSubbaraya Sundeep case TCP_V4_FLOW:
591f0a1913fSSubbaraya Sundeep case UDP_V4_FLOW:
592f0a1913fSSubbaraya Sundeep case SCTP_V4_FLOW:
593b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IP);
594b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
595b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
596f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->ip4src) {
597f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4src, &ipv4_l4_hdr->ip4src,
598f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4src));
599f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4src, &ipv4_l4_mask->ip4src,
600f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4src));
601f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV4);
602f0a1913fSSubbaraya Sundeep }
603f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->ip4dst) {
604f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4dst, &ipv4_l4_hdr->ip4dst,
605f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4dst));
606f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4dst, &ipv4_l4_mask->ip4dst,
607f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4dst));
608f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV4);
609f0a1913fSSubbaraya Sundeep }
6102b9cef66SNaveen Mamindlapalli if (ipv4_l4_mask->tos) {
6112b9cef66SNaveen Mamindlapalli pkt->tos = ipv4_l4_hdr->tos;
6122b9cef66SNaveen Mamindlapalli pmask->tos = ipv4_l4_mask->tos;
6132b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_TOS);
6142b9cef66SNaveen Mamindlapalli }
615f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->psrc) {
616f0a1913fSSubbaraya Sundeep memcpy(&pkt->sport, &ipv4_l4_hdr->psrc,
617f0a1913fSSubbaraya Sundeep sizeof(pkt->sport));
618f0a1913fSSubbaraya Sundeep memcpy(&pmask->sport, &ipv4_l4_mask->psrc,
619f0a1913fSSubbaraya Sundeep sizeof(pmask->sport));
620f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V4_FLOW)
621f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_UDP);
622f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V4_FLOW)
623f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_TCP);
624f0a1913fSSubbaraya Sundeep else
625f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_SCTP);
626f0a1913fSSubbaraya Sundeep }
627f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->pdst) {
628f0a1913fSSubbaraya Sundeep memcpy(&pkt->dport, &ipv4_l4_hdr->pdst,
629f0a1913fSSubbaraya Sundeep sizeof(pkt->dport));
630f0a1913fSSubbaraya Sundeep memcpy(&pmask->dport, &ipv4_l4_mask->pdst,
631f0a1913fSSubbaraya Sundeep sizeof(pmask->dport));
632f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V4_FLOW)
633f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_UDP);
634f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V4_FLOW)
635f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_TCP);
636f0a1913fSSubbaraya Sundeep else
637f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_SCTP);
638f0a1913fSSubbaraya Sundeep }
639b7cf9661SNaveen Mamindlapalli if (flow_type == UDP_V4_FLOW)
640b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_UDP);
641b7cf9661SNaveen Mamindlapalli else if (flow_type == TCP_V4_FLOW)
642b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_TCP);
643b7cf9661SNaveen Mamindlapalli else
644b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
645b7cf9661SNaveen Mamindlapalli break;
646b7cf9661SNaveen Mamindlapalli case AH_V4_FLOW:
647b7cf9661SNaveen Mamindlapalli case ESP_V4_FLOW:
648b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IP);
649b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
650b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
651b7cf9661SNaveen Mamindlapalli if (ah_esp_mask->ip4src) {
652b7cf9661SNaveen Mamindlapalli memcpy(&pkt->ip4src, &ah_esp_hdr->ip4src,
653b7cf9661SNaveen Mamindlapalli sizeof(pkt->ip4src));
654b7cf9661SNaveen Mamindlapalli memcpy(&pmask->ip4src, &ah_esp_mask->ip4src,
655b7cf9661SNaveen Mamindlapalli sizeof(pmask->ip4src));
656b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_SIP_IPV4);
657b7cf9661SNaveen Mamindlapalli }
658b7cf9661SNaveen Mamindlapalli if (ah_esp_mask->ip4dst) {
659b7cf9661SNaveen Mamindlapalli memcpy(&pkt->ip4dst, &ah_esp_hdr->ip4dst,
660b7cf9661SNaveen Mamindlapalli sizeof(pkt->ip4dst));
661b7cf9661SNaveen Mamindlapalli memcpy(&pmask->ip4dst, &ah_esp_mask->ip4dst,
662b7cf9661SNaveen Mamindlapalli sizeof(pmask->ip4dst));
663b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_DIP_IPV4);
664b7cf9661SNaveen Mamindlapalli }
6652b9cef66SNaveen Mamindlapalli if (ah_esp_mask->tos) {
6662b9cef66SNaveen Mamindlapalli pkt->tos = ah_esp_hdr->tos;
6672b9cef66SNaveen Mamindlapalli pmask->tos = ah_esp_mask->tos;
6682b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_TOS);
6692b9cef66SNaveen Mamindlapalli }
670b7cf9661SNaveen Mamindlapalli
671b7cf9661SNaveen Mamindlapalli /* NPC profile doesn't extract AH/ESP header fields */
6722b9cef66SNaveen Mamindlapalli if (ah_esp_mask->spi & ah_esp_hdr->spi)
673b7cf9661SNaveen Mamindlapalli return -EOPNOTSUPP;
674b7cf9661SNaveen Mamindlapalli
675b7cf9661SNaveen Mamindlapalli if (flow_type == AH_V4_FLOW)
676b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_AH);
677b7cf9661SNaveen Mamindlapalli else
678b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_ESP);
679f0a1913fSSubbaraya Sundeep break;
680f0a1913fSSubbaraya Sundeep default:
681f0a1913fSSubbaraya Sundeep break;
682f0a1913fSSubbaraya Sundeep }
683b7cf9661SNaveen Mamindlapalli
684b7cf9661SNaveen Mamindlapalli return 0;
685f0a1913fSSubbaraya Sundeep }
686f0a1913fSSubbaraya Sundeep
otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec * fsp,struct npc_install_flow_req * req,u32 flow_type)687b7cf9661SNaveen Mamindlapalli static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
688f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req,
689f0a1913fSSubbaraya Sundeep u32 flow_type)
690f0a1913fSSubbaraya Sundeep {
691f0a1913fSSubbaraya Sundeep struct ethtool_usrip6_spec *ipv6_usr_mask = &fsp->m_u.usr_ip6_spec;
692f0a1913fSSubbaraya Sundeep struct ethtool_usrip6_spec *ipv6_usr_hdr = &fsp->h_u.usr_ip6_spec;
693f0a1913fSSubbaraya Sundeep struct ethtool_tcpip6_spec *ipv6_l4_mask = &fsp->m_u.tcp_ip6_spec;
694f0a1913fSSubbaraya Sundeep struct ethtool_tcpip6_spec *ipv6_l4_hdr = &fsp->h_u.tcp_ip6_spec;
695b7cf9661SNaveen Mamindlapalli struct ethtool_ah_espip6_spec *ah_esp_hdr = &fsp->h_u.ah_ip6_spec;
696b7cf9661SNaveen Mamindlapalli struct ethtool_ah_espip6_spec *ah_esp_mask = &fsp->m_u.ah_ip6_spec;
697f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask;
698f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet;
699f0a1913fSSubbaraya Sundeep
700f0a1913fSSubbaraya Sundeep switch (flow_type) {
701f0a1913fSSubbaraya Sundeep case IPV6_USER_FLOW:
702f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6src)) {
703f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6src, &ipv6_usr_hdr->ip6src,
704f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6src));
705f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6src, &ipv6_usr_mask->ip6src,
706f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6src));
707f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV6);
708f0a1913fSSubbaraya Sundeep }
709f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6dst)) {
710f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6dst, &ipv6_usr_hdr->ip6dst,
711f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6dst));
712f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6dst, &ipv6_usr_mask->ip6dst,
713f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6dst));
714f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV6);
715f0a1913fSSubbaraya Sundeep }
716c672e372SSuman Ghosh if (ipv6_usr_hdr->l4_proto == IPPROTO_FRAGMENT) {
717c672e372SSuman Ghosh pkt->next_header = ipv6_usr_hdr->l4_proto;
718c672e372SSuman Ghosh pmask->next_header = ipv6_usr_mask->l4_proto;
719c672e372SSuman Ghosh req->features |= BIT_ULL(NPC_IPFRAG_IPV6);
720c672e372SSuman Ghosh }
721b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IPV6);
722b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
723b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
724f0a1913fSSubbaraya Sundeep break;
725f0a1913fSSubbaraya Sundeep case TCP_V6_FLOW:
726f0a1913fSSubbaraya Sundeep case UDP_V6_FLOW:
727f0a1913fSSubbaraya Sundeep case SCTP_V6_FLOW:
728b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IPV6);
729b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
730b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
731f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6src)) {
732f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6src, &ipv6_l4_hdr->ip6src,
733f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6src));
734f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6src, &ipv6_l4_mask->ip6src,
735f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6src));
736f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV6);
737f0a1913fSSubbaraya Sundeep }
738f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6dst)) {
739f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6dst, &ipv6_l4_hdr->ip6dst,
740f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6dst));
741f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6dst, &ipv6_l4_mask->ip6dst,
742f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6dst));
743f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV6);
744f0a1913fSSubbaraya Sundeep }
745f0a1913fSSubbaraya Sundeep if (ipv6_l4_mask->psrc) {
746f0a1913fSSubbaraya Sundeep memcpy(&pkt->sport, &ipv6_l4_hdr->psrc,
747f0a1913fSSubbaraya Sundeep sizeof(pkt->sport));
748f0a1913fSSubbaraya Sundeep memcpy(&pmask->sport, &ipv6_l4_mask->psrc,
749f0a1913fSSubbaraya Sundeep sizeof(pmask->sport));
750f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V6_FLOW)
751f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_UDP);
752f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V6_FLOW)
753f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_TCP);
754f0a1913fSSubbaraya Sundeep else
755f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_SCTP);
756f0a1913fSSubbaraya Sundeep }
757f0a1913fSSubbaraya Sundeep if (ipv6_l4_mask->pdst) {
758f0a1913fSSubbaraya Sundeep memcpy(&pkt->dport, &ipv6_l4_hdr->pdst,
759f0a1913fSSubbaraya Sundeep sizeof(pkt->dport));
760f0a1913fSSubbaraya Sundeep memcpy(&pmask->dport, &ipv6_l4_mask->pdst,
761f0a1913fSSubbaraya Sundeep sizeof(pmask->dport));
762f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V6_FLOW)
763f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_UDP);
764f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V6_FLOW)
765f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_TCP);
766f0a1913fSSubbaraya Sundeep else
767f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_SCTP);
768f0a1913fSSubbaraya Sundeep }
769b7cf9661SNaveen Mamindlapalli if (flow_type == UDP_V6_FLOW)
770b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_UDP);
771b7cf9661SNaveen Mamindlapalli else if (flow_type == TCP_V6_FLOW)
772b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_TCP);
773b7cf9661SNaveen Mamindlapalli else
774b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
775f0a1913fSSubbaraya Sundeep break;
776b7cf9661SNaveen Mamindlapalli case AH_V6_FLOW:
777b7cf9661SNaveen Mamindlapalli case ESP_V6_FLOW:
778b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IPV6);
779b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
780b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
781b7cf9661SNaveen Mamindlapalli if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6src)) {
782b7cf9661SNaveen Mamindlapalli memcpy(&pkt->ip6src, &ah_esp_hdr->ip6src,
783b7cf9661SNaveen Mamindlapalli sizeof(pkt->ip6src));
784b7cf9661SNaveen Mamindlapalli memcpy(&pmask->ip6src, &ah_esp_mask->ip6src,
785b7cf9661SNaveen Mamindlapalli sizeof(pmask->ip6src));
786b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_SIP_IPV6);
787b7cf9661SNaveen Mamindlapalli }
788b7cf9661SNaveen Mamindlapalli if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6dst)) {
789b7cf9661SNaveen Mamindlapalli memcpy(&pkt->ip6dst, &ah_esp_hdr->ip6dst,
790b7cf9661SNaveen Mamindlapalli sizeof(pkt->ip6dst));
791b7cf9661SNaveen Mamindlapalli memcpy(&pmask->ip6dst, &ah_esp_mask->ip6dst,
792b7cf9661SNaveen Mamindlapalli sizeof(pmask->ip6dst));
793b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_DIP_IPV6);
794b7cf9661SNaveen Mamindlapalli }
795b7cf9661SNaveen Mamindlapalli
796b7cf9661SNaveen Mamindlapalli /* NPC profile doesn't extract AH/ESP header fields */
797b7cf9661SNaveen Mamindlapalli if ((ah_esp_mask->spi & ah_esp_hdr->spi) ||
7983acd9db9SDeepak R Varma (ah_esp_mask->tclass & ah_esp_hdr->tclass))
799b7cf9661SNaveen Mamindlapalli return -EOPNOTSUPP;
800b7cf9661SNaveen Mamindlapalli
801b7cf9661SNaveen Mamindlapalli if (flow_type == AH_V6_FLOW)
802b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_AH);
803b7cf9661SNaveen Mamindlapalli else
804b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_ESP);
805320daffdSGustavo A. R. Silva break;
806f0a1913fSSubbaraya Sundeep default:
807f0a1913fSSubbaraya Sundeep break;
808f0a1913fSSubbaraya Sundeep }
809b7cf9661SNaveen Mamindlapalli
810b7cf9661SNaveen Mamindlapalli return 0;
811f0a1913fSSubbaraya Sundeep }
812f0a1913fSSubbaraya Sundeep
otx2_prepare_flow_request(struct ethtool_rx_flow_spec * fsp,struct npc_install_flow_req * req)813dce677daSSubbaraya Sundeep static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
814f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req)
815f0a1913fSSubbaraya Sundeep {
816f0a1913fSSubbaraya Sundeep struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
817f0a1913fSSubbaraya Sundeep struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
818f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask;
819f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet;
820f0a1913fSSubbaraya Sundeep u32 flow_type;
821b7cf9661SNaveen Mamindlapalli int ret;
822f0a1913fSSubbaraya Sundeep
82381a43620SGeetha sowjanya flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
824f0a1913fSSubbaraya Sundeep switch (flow_type) {
825f0a1913fSSubbaraya Sundeep /* bits not set in mask are don't care */
826f0a1913fSSubbaraya Sundeep case ETHER_FLOW:
827f0a1913fSSubbaraya Sundeep if (!is_zero_ether_addr(eth_mask->h_source)) {
828f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->smac, eth_hdr->h_source);
829f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->smac, eth_mask->h_source);
830f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SMAC);
831f0a1913fSSubbaraya Sundeep }
832f0a1913fSSubbaraya Sundeep if (!is_zero_ether_addr(eth_mask->h_dest)) {
833f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->dmac, eth_hdr->h_dest);
834f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->dmac, eth_mask->h_dest);
835f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DMAC);
836f0a1913fSSubbaraya Sundeep }
8373cffaed2SRakesh Babu if (eth_hdr->h_proto) {
838f0a1913fSSubbaraya Sundeep memcpy(&pkt->etype, ð_hdr->h_proto,
839f0a1913fSSubbaraya Sundeep sizeof(pkt->etype));
840f0a1913fSSubbaraya Sundeep memcpy(&pmask->etype, ð_mask->h_proto,
841f0a1913fSSubbaraya Sundeep sizeof(pmask->etype));
842f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_ETYPE);
843f0a1913fSSubbaraya Sundeep }
844f0a1913fSSubbaraya Sundeep break;
845f0a1913fSSubbaraya Sundeep case IP_USER_FLOW:
846f0a1913fSSubbaraya Sundeep case TCP_V4_FLOW:
847f0a1913fSSubbaraya Sundeep case UDP_V4_FLOW:
848f0a1913fSSubbaraya Sundeep case SCTP_V4_FLOW:
849b7cf9661SNaveen Mamindlapalli case AH_V4_FLOW:
850b7cf9661SNaveen Mamindlapalli case ESP_V4_FLOW:
851b7cf9661SNaveen Mamindlapalli ret = otx2_prepare_ipv4_flow(fsp, req, flow_type);
852b7cf9661SNaveen Mamindlapalli if (ret)
853b7cf9661SNaveen Mamindlapalli return ret;
854f0a1913fSSubbaraya Sundeep break;
855f0a1913fSSubbaraya Sundeep case IPV6_USER_FLOW:
856f0a1913fSSubbaraya Sundeep case TCP_V6_FLOW:
857f0a1913fSSubbaraya Sundeep case UDP_V6_FLOW:
858f0a1913fSSubbaraya Sundeep case SCTP_V6_FLOW:
859b7cf9661SNaveen Mamindlapalli case AH_V6_FLOW:
860b7cf9661SNaveen Mamindlapalli case ESP_V6_FLOW:
861b7cf9661SNaveen Mamindlapalli ret = otx2_prepare_ipv6_flow(fsp, req, flow_type);
862b7cf9661SNaveen Mamindlapalli if (ret)
863b7cf9661SNaveen Mamindlapalli return ret;
864f0a1913fSSubbaraya Sundeep break;
865f0a1913fSSubbaraya Sundeep default:
866f0a1913fSSubbaraya Sundeep return -EOPNOTSUPP;
867f0a1913fSSubbaraya Sundeep }
868f0a1913fSSubbaraya Sundeep if (fsp->flow_type & FLOW_EXT) {
869dce677daSSubbaraya Sundeep u16 vlan_etype;
870dce677daSSubbaraya Sundeep
871dce677daSSubbaraya Sundeep if (fsp->m_ext.vlan_etype) {
872dce677daSSubbaraya Sundeep /* Partial masks not supported */
873dce677daSSubbaraya Sundeep if (be16_to_cpu(fsp->m_ext.vlan_etype) != 0xFFFF)
874f0a1913fSSubbaraya Sundeep return -EINVAL;
875dce677daSSubbaraya Sundeep
876dce677daSSubbaraya Sundeep vlan_etype = be16_to_cpu(fsp->h_ext.vlan_etype);
8778278ee2aSSuman Ghosh
8788278ee2aSSuman Ghosh /* Drop rule with vlan_etype == 802.1Q
8798278ee2aSSuman Ghosh * and vlan_id == 0 is not supported
8808278ee2aSSuman Ghosh */
8818278ee2aSSuman Ghosh if (vlan_etype == ETH_P_8021Q && !fsp->m_ext.vlan_tci &&
8828278ee2aSSuman Ghosh fsp->ring_cookie == RX_CLS_FLOW_DISC)
8838278ee2aSSuman Ghosh return -EINVAL;
8848278ee2aSSuman Ghosh
885dce677daSSubbaraya Sundeep /* Only ETH_P_8021Q and ETH_P_802AD types supported */
886dce677daSSubbaraya Sundeep if (vlan_etype != ETH_P_8021Q &&
887dce677daSSubbaraya Sundeep vlan_etype != ETH_P_8021AD)
888dce677daSSubbaraya Sundeep return -EINVAL;
889dce677daSSubbaraya Sundeep
890dce677daSSubbaraya Sundeep memcpy(&pkt->vlan_etype, &fsp->h_ext.vlan_etype,
891dce677daSSubbaraya Sundeep sizeof(pkt->vlan_etype));
892dce677daSSubbaraya Sundeep memcpy(&pmask->vlan_etype, &fsp->m_ext.vlan_etype,
893dce677daSSubbaraya Sundeep sizeof(pmask->vlan_etype));
894dce677daSSubbaraya Sundeep
895dce677daSSubbaraya Sundeep if (vlan_etype == ETH_P_8021Q)
896dce677daSSubbaraya Sundeep req->features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG);
897dce677daSSubbaraya Sundeep else
898dce677daSSubbaraya Sundeep req->features |= BIT_ULL(NPC_VLAN_ETYPE_STAG);
899dce677daSSubbaraya Sundeep }
900dce677daSSubbaraya Sundeep
901f0a1913fSSubbaraya Sundeep if (fsp->m_ext.vlan_tci) {
902f0a1913fSSubbaraya Sundeep memcpy(&pkt->vlan_tci, &fsp->h_ext.vlan_tci,
903f0a1913fSSubbaraya Sundeep sizeof(pkt->vlan_tci));
904f0a1913fSSubbaraya Sundeep memcpy(&pmask->vlan_tci, &fsp->m_ext.vlan_tci,
905f0a1913fSSubbaraya Sundeep sizeof(pmask->vlan_tci));
906f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_OUTER_VID);
907f0a1913fSSubbaraya Sundeep }
908f0a1913fSSubbaraya Sundeep
909c672e372SSuman Ghosh if (fsp->m_ext.data[1]) {
910c672e372SSuman Ghosh if (flow_type == IP_USER_FLOW) {
911c672e372SSuman Ghosh if (be32_to_cpu(fsp->h_ext.data[1]) != IPV4_FLAG_MORE)
912c672e372SSuman Ghosh return -EINVAL;
913c672e372SSuman Ghosh
914c672e372SSuman Ghosh pkt->ip_flag = be32_to_cpu(fsp->h_ext.data[1]);
915c672e372SSuman Ghosh pmask->ip_flag = be32_to_cpu(fsp->m_ext.data[1]);
916c672e372SSuman Ghosh req->features |= BIT_ULL(NPC_IPFRAG_IPV4);
917c672e372SSuman Ghosh } else if (fsp->h_ext.data[1] ==
918c672e372SSuman Ghosh cpu_to_be32(OTX2_DEFAULT_ACTION)) {
919c672e372SSuman Ghosh /* Not Drop/Direct to queue but use action
920c672e372SSuman Ghosh * in default entry
921c672e372SSuman Ghosh */
922f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTION_DEFAULT;
923f0a1913fSSubbaraya Sundeep }
924c672e372SSuman Ghosh }
925c672e372SSuman Ghosh }
926f0a1913fSSubbaraya Sundeep
927f0a1913fSSubbaraya Sundeep if (fsp->flow_type & FLOW_MAC_EXT &&
928f0a1913fSSubbaraya Sundeep !is_zero_ether_addr(fsp->m_ext.h_dest)) {
929f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->dmac, fsp->h_ext.h_dest);
930f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->dmac, fsp->m_ext.h_dest);
931f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DMAC);
932f0a1913fSSubbaraya Sundeep }
933f0a1913fSSubbaraya Sundeep
934f0a1913fSSubbaraya Sundeep if (!req->features)
935f0a1913fSSubbaraya Sundeep return -EOPNOTSUPP;
936f0a1913fSSubbaraya Sundeep
937f0a1913fSSubbaraya Sundeep return 0;
938f0a1913fSSubbaraya Sundeep }
939f0a1913fSSubbaraya Sundeep
otx2_is_flow_rule_dmacfilter(struct otx2_nic * pfvf,struct ethtool_rx_flow_spec * fsp)94079d2be38SHariprasad Kelam static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
94179d2be38SHariprasad Kelam struct ethtool_rx_flow_spec *fsp)
94279d2be38SHariprasad Kelam {
94379d2be38SHariprasad Kelam struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
94479d2be38SHariprasad Kelam struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
94579d2be38SHariprasad Kelam u64 ring_cookie = fsp->ring_cookie;
94679d2be38SHariprasad Kelam u32 flow_type;
94779d2be38SHariprasad Kelam
94879d2be38SHariprasad Kelam if (!(pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT))
94979d2be38SHariprasad Kelam return false;
95079d2be38SHariprasad Kelam
95179d2be38SHariprasad Kelam flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
95279d2be38SHariprasad Kelam
95379d2be38SHariprasad Kelam /* CGX/RPM block dmac filtering configured for white listing
95479d2be38SHariprasad Kelam * check for action other than DROP
95579d2be38SHariprasad Kelam */
95679d2be38SHariprasad Kelam if (flow_type == ETHER_FLOW && ring_cookie != RX_CLS_FLOW_DISC &&
95779d2be38SHariprasad Kelam !ethtool_get_flow_spec_ring_vf(ring_cookie)) {
95879d2be38SHariprasad Kelam if (is_zero_ether_addr(eth_mask->h_dest) &&
95979d2be38SHariprasad Kelam is_valid_ether_addr(eth_hdr->h_dest))
96079d2be38SHariprasad Kelam return true;
96179d2be38SHariprasad Kelam }
96279d2be38SHariprasad Kelam
96379d2be38SHariprasad Kelam return false;
96479d2be38SHariprasad Kelam }
96579d2be38SHariprasad Kelam
otx2_add_flow_msg(struct otx2_nic * pfvf,struct otx2_flow * flow)966f0a1913fSSubbaraya Sundeep static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
967f0a1913fSSubbaraya Sundeep {
968f0a1913fSSubbaraya Sundeep u64 ring_cookie = flow->flow_spec.ring_cookie;
9698e675581SHariprasad Kelam #ifdef CONFIG_DCB
9708e675581SHariprasad Kelam int vlan_prio, qidx, pfc_rule = 0;
9718e675581SHariprasad Kelam #endif
972f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req;
973f0a1913fSSubbaraya Sundeep int err, vf = 0;
974f0a1913fSSubbaraya Sundeep
975f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
976f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
977f0a1913fSSubbaraya Sundeep if (!req) {
978f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
979f0a1913fSSubbaraya Sundeep return -ENOMEM;
980f0a1913fSSubbaraya Sundeep }
981f0a1913fSSubbaraya Sundeep
982f0a1913fSSubbaraya Sundeep err = otx2_prepare_flow_request(&flow->flow_spec, req);
983f0a1913fSSubbaraya Sundeep if (err) {
984f0a1913fSSubbaraya Sundeep /* free the allocated msg above */
985f0a1913fSSubbaraya Sundeep otx2_mbox_reset(&pfvf->mbox.mbox, 0);
986f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
987f0a1913fSSubbaraya Sundeep return err;
988f0a1913fSSubbaraya Sundeep }
989f0a1913fSSubbaraya Sundeep
990f0a1913fSSubbaraya Sundeep req->entry = flow->entry;
991f0a1913fSSubbaraya Sundeep req->intf = NIX_INTF_RX;
992f0a1913fSSubbaraya Sundeep req->set_cntr = 1;
993f0a1913fSSubbaraya Sundeep req->channel = pfvf->hw.rx_chan_base;
994f0a1913fSSubbaraya Sundeep if (ring_cookie == RX_CLS_FLOW_DISC) {
995f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTIONOP_DROP;
996f0a1913fSSubbaraya Sundeep } else {
997f0a1913fSSubbaraya Sundeep /* change to unicast only if action of default entry is not
998f0a1913fSSubbaraya Sundeep * requested by user
999f0a1913fSSubbaraya Sundeep */
100081a43620SGeetha sowjanya if (flow->flow_spec.flow_type & FLOW_RSS) {
100181a43620SGeetha sowjanya req->op = NIX_RX_ACTIONOP_RSS;
100281a43620SGeetha sowjanya req->index = flow->rss_ctx_id;
1003e7938365SSunil Goutham req->flow_key_alg = pfvf->hw.flowkey_alg_idx;
100481a43620SGeetha sowjanya } else {
1005f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTIONOP_UCAST;
1006f0a1913fSSubbaraya Sundeep req->index = ethtool_get_flow_spec_ring(ring_cookie);
100781a43620SGeetha sowjanya }
1008f0a1913fSSubbaraya Sundeep vf = ethtool_get_flow_spec_ring_vf(ring_cookie);
1009f0a1913fSSubbaraya Sundeep if (vf > pci_num_vf(pfvf->pdev)) {
1010f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1011f0a1913fSSubbaraya Sundeep return -EINVAL;
1012f0a1913fSSubbaraya Sundeep }
10138e675581SHariprasad Kelam
10148e675581SHariprasad Kelam #ifdef CONFIG_DCB
10158e675581SHariprasad Kelam /* Identify PFC rule if PFC enabled and ntuple rule is vlan */
10168e675581SHariprasad Kelam if (!vf && (req->features & BIT_ULL(NPC_OUTER_VID)) &&
10178e675581SHariprasad Kelam pfvf->pfc_en && req->op != NIX_RX_ACTIONOP_RSS) {
10188e675581SHariprasad Kelam vlan_prio = ntohs(req->packet.vlan_tci) &
10198e675581SHariprasad Kelam ntohs(req->mask.vlan_tci);
10208e675581SHariprasad Kelam
10218e675581SHariprasad Kelam /* Get the priority */
10228e675581SHariprasad Kelam vlan_prio >>= 13;
10238e675581SHariprasad Kelam flow->rule_type |= PFC_FLOWCTRL_RULE;
10248e675581SHariprasad Kelam /* Check if PFC enabled for this priority */
10258e675581SHariprasad Kelam if (pfvf->pfc_en & BIT(vlan_prio)) {
10268e675581SHariprasad Kelam pfc_rule = true;
10278e675581SHariprasad Kelam qidx = req->index;
10288e675581SHariprasad Kelam }
10298e675581SHariprasad Kelam }
10308e675581SHariprasad Kelam #endif
1031f0a1913fSSubbaraya Sundeep }
1032f0a1913fSSubbaraya Sundeep
1033f0a1913fSSubbaraya Sundeep /* ethtool ring_cookie has (VF + 1) for VF */
1034f0a1913fSSubbaraya Sundeep if (vf) {
1035f0a1913fSSubbaraya Sundeep req->vf = vf;
1036f0a1913fSSubbaraya Sundeep flow->is_vf = true;
1037f0a1913fSSubbaraya Sundeep flow->vf = vf;
1038f0a1913fSSubbaraya Sundeep }
1039f0a1913fSSubbaraya Sundeep
1040f0a1913fSSubbaraya Sundeep /* Send message to AF */
1041f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox);
10428e675581SHariprasad Kelam
10438e675581SHariprasad Kelam #ifdef CONFIG_DCB
10448e675581SHariprasad Kelam if (!err && pfc_rule)
10458e675581SHariprasad Kelam otx2_update_bpid_in_rqctx(pfvf, vlan_prio, qidx, true);
10468e675581SHariprasad Kelam #endif
10478e675581SHariprasad Kelam
1048f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1049f0a1913fSSubbaraya Sundeep return err;
1050f0a1913fSSubbaraya Sundeep }
1051f0a1913fSSubbaraya Sundeep
otx2_add_flow_with_pfmac(struct otx2_nic * pfvf,struct otx2_flow * flow)105279d2be38SHariprasad Kelam static int otx2_add_flow_with_pfmac(struct otx2_nic *pfvf,
105379d2be38SHariprasad Kelam struct otx2_flow *flow)
105479d2be38SHariprasad Kelam {
105579d2be38SHariprasad Kelam struct otx2_flow *pf_mac;
105679d2be38SHariprasad Kelam struct ethhdr *eth_hdr;
105779d2be38SHariprasad Kelam
105879d2be38SHariprasad Kelam pf_mac = kzalloc(sizeof(*pf_mac), GFP_KERNEL);
105979d2be38SHariprasad Kelam if (!pf_mac)
106079d2be38SHariprasad Kelam return -ENOMEM;
106179d2be38SHariprasad Kelam
106279d2be38SHariprasad Kelam pf_mac->entry = 0;
10638e675581SHariprasad Kelam pf_mac->rule_type |= DMAC_FILTER_RULE;
10642e2a8126SSunil Goutham pf_mac->location = pfvf->flow_cfg->max_flows;
106579d2be38SHariprasad Kelam memcpy(&pf_mac->flow_spec, &flow->flow_spec,
106679d2be38SHariprasad Kelam sizeof(struct ethtool_rx_flow_spec));
106779d2be38SHariprasad Kelam pf_mac->flow_spec.location = pf_mac->location;
106879d2be38SHariprasad Kelam
106979d2be38SHariprasad Kelam /* Copy PF mac address */
107079d2be38SHariprasad Kelam eth_hdr = &pf_mac->flow_spec.h_u.ether_spec;
107179d2be38SHariprasad Kelam ether_addr_copy(eth_hdr->h_dest, pfvf->netdev->dev_addr);
107279d2be38SHariprasad Kelam
107379d2be38SHariprasad Kelam /* Install DMAC filter with PF mac address */
107479d2be38SHariprasad Kelam otx2_dmacflt_add(pfvf, eth_hdr->h_dest, 0);
107579d2be38SHariprasad Kelam
107679d2be38SHariprasad Kelam otx2_add_flow_to_list(pfvf, pf_mac);
107779d2be38SHariprasad Kelam pfvf->flow_cfg->nr_flows++;
1078fa5e0ccbSRatheesh Kannoth set_bit(0, pfvf->flow_cfg->dmacflt_bmap);
107979d2be38SHariprasad Kelam
108079d2be38SHariprasad Kelam return 0;
108179d2be38SHariprasad Kelam }
108279d2be38SHariprasad Kelam
otx2_add_flow(struct otx2_nic * pfvf,struct ethtool_rxnfc * nfc)108381a43620SGeetha sowjanya int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
1084f0a1913fSSubbaraya Sundeep {
1085f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
108681a43620SGeetha sowjanya struct ethtool_rx_flow_spec *fsp = &nfc->fs;
1087f0a1913fSSubbaraya Sundeep struct otx2_flow *flow;
108879d2be38SHariprasad Kelam struct ethhdr *eth_hdr;
1089f0a1913fSSubbaraya Sundeep bool new = false;
109079d2be38SHariprasad Kelam int err = 0;
1091*f174a0daSSuman Ghosh u64 vf_num;
109281a43620SGeetha sowjanya u32 ring;
1093f0a1913fSSubbaraya Sundeep
1094a515e5b5SSunil Goutham if (!flow_cfg->max_flows) {
1095a515e5b5SSunil Goutham netdev_err(pfvf->netdev,
1096a515e5b5SSunil Goutham "Ntuple rule count is 0, allocate and retry\n");
1097a515e5b5SSunil Goutham return -EINVAL;
1098a515e5b5SSunil Goutham }
1099a515e5b5SSunil Goutham
110081a43620SGeetha sowjanya ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
1101f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
1102f0a1913fSSubbaraya Sundeep return -ENOMEM;
1103f0a1913fSSubbaraya Sundeep
1104*f174a0daSSuman Ghosh /* Number of queues on a VF can be greater or less than
1105*f174a0daSSuman Ghosh * the PF's queue. Hence no need to check for the
1106*f174a0daSSuman Ghosh * queue count. Hence no need to check queue count if PF
1107*f174a0daSSuman Ghosh * is installing for its VF. Below is the expected vf_num value
1108*f174a0daSSuman Ghosh * based on the ethtool commands.
1109*f174a0daSSuman Ghosh *
1110*f174a0daSSuman Ghosh * e.g.
1111*f174a0daSSuman Ghosh * 1. ethtool -U <netdev> ... action -1 ==> vf_num:255
1112*f174a0daSSuman Ghosh * 2. ethtool -U <netdev> ... action <queue_num> ==> vf_num:0
1113*f174a0daSSuman Ghosh * 3. ethtool -U <netdev> ... vf <vf_idx> queue <queue_num> ==>
1114*f174a0daSSuman Ghosh * vf_num:vf_idx+1
1115*f174a0daSSuman Ghosh */
1116*f174a0daSSuman Ghosh vf_num = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
1117*f174a0daSSuman Ghosh if (!is_otx2_vf(pfvf->pcifunc) && !vf_num &&
1118*f174a0daSSuman Ghosh ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC)
1119f0a1913fSSubbaraya Sundeep return -EINVAL;
1120f0a1913fSSubbaraya Sundeep
112179d2be38SHariprasad Kelam if (fsp->location >= otx2_get_maxflows(flow_cfg))
1122f0a1913fSSubbaraya Sundeep return -EINVAL;
1123f0a1913fSSubbaraya Sundeep
1124f0a1913fSSubbaraya Sundeep flow = otx2_find_flow(pfvf, fsp->location);
1125f0a1913fSSubbaraya Sundeep if (!flow) {
112679d2be38SHariprasad Kelam flow = kzalloc(sizeof(*flow), GFP_KERNEL);
1127f0a1913fSSubbaraya Sundeep if (!flow)
1128f0a1913fSSubbaraya Sundeep return -ENOMEM;
1129f0a1913fSSubbaraya Sundeep flow->location = fsp->location;
1130dce677daSSubbaraya Sundeep flow->entry = flow_cfg->flow_ent[flow->location];
1131f0a1913fSSubbaraya Sundeep new = true;
1132f0a1913fSSubbaraya Sundeep }
1133f0a1913fSSubbaraya Sundeep /* struct copy */
1134f0a1913fSSubbaraya Sundeep flow->flow_spec = *fsp;
1135f0a1913fSSubbaraya Sundeep
113681a43620SGeetha sowjanya if (fsp->flow_type & FLOW_RSS)
113781a43620SGeetha sowjanya flow->rss_ctx_id = nfc->rss_context;
113881a43620SGeetha sowjanya
113979d2be38SHariprasad Kelam if (otx2_is_flow_rule_dmacfilter(pfvf, &flow->flow_spec)) {
114079d2be38SHariprasad Kelam eth_hdr = &flow->flow_spec.h_u.ether_spec;
114179d2be38SHariprasad Kelam
114279d2be38SHariprasad Kelam /* Sync dmac filter table with updated fields */
11438e675581SHariprasad Kelam if (flow->rule_type & DMAC_FILTER_RULE)
114479d2be38SHariprasad Kelam return otx2_dmacflt_update(pfvf, eth_hdr->h_dest,
114579d2be38SHariprasad Kelam flow->entry);
114679d2be38SHariprasad Kelam
1147fa5e0ccbSRatheesh Kannoth if (bitmap_full(flow_cfg->dmacflt_bmap,
114879d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows)) {
114979d2be38SHariprasad Kelam netdev_warn(pfvf->netdev,
115079d2be38SHariprasad Kelam "Can't insert the rule %d as max allowed dmac filters are %d\n",
115179d2be38SHariprasad Kelam flow->location +
115279d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows,
115379d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows);
115479d2be38SHariprasad Kelam err = -EINVAL;
115579d2be38SHariprasad Kelam if (new)
115679d2be38SHariprasad Kelam kfree(flow);
115779d2be38SHariprasad Kelam return err;
115879d2be38SHariprasad Kelam }
115979d2be38SHariprasad Kelam
116079d2be38SHariprasad Kelam /* Install PF mac address to DMAC filter list */
1161fa5e0ccbSRatheesh Kannoth if (!test_bit(0, flow_cfg->dmacflt_bmap))
116279d2be38SHariprasad Kelam otx2_add_flow_with_pfmac(pfvf, flow);
116379d2be38SHariprasad Kelam
11648e675581SHariprasad Kelam flow->rule_type |= DMAC_FILTER_RULE;
1165fa5e0ccbSRatheesh Kannoth flow->entry = find_first_zero_bit(flow_cfg->dmacflt_bmap,
116679d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows);
11672e2a8126SSunil Goutham fsp->location = flow_cfg->max_flows + flow->entry;
116879d2be38SHariprasad Kelam flow->flow_spec.location = fsp->location;
116979d2be38SHariprasad Kelam flow->location = fsp->location;
117079d2be38SHariprasad Kelam
1171fa5e0ccbSRatheesh Kannoth set_bit(flow->entry, flow_cfg->dmacflt_bmap);
117279d2be38SHariprasad Kelam otx2_dmacflt_add(pfvf, eth_hdr->h_dest, flow->entry);
117379d2be38SHariprasad Kelam
117479d2be38SHariprasad Kelam } else {
11752e2a8126SSunil Goutham if (flow->location >= pfvf->flow_cfg->max_flows) {
117679d2be38SHariprasad Kelam netdev_warn(pfvf->netdev,
117779d2be38SHariprasad Kelam "Can't insert non dmac ntuple rule at %d, allowed range %d-0\n",
117879d2be38SHariprasad Kelam flow->location,
11792e2a8126SSunil Goutham flow_cfg->max_flows - 1);
118079d2be38SHariprasad Kelam err = -EINVAL;
118179d2be38SHariprasad Kelam } else {
1182f0a1913fSSubbaraya Sundeep err = otx2_add_flow_msg(pfvf, flow);
118379d2be38SHariprasad Kelam }
118479d2be38SHariprasad Kelam }
118579d2be38SHariprasad Kelam
1186f0a1913fSSubbaraya Sundeep if (err) {
11873cffaed2SRakesh Babu if (err == MBOX_MSG_INVALID)
11883cffaed2SRakesh Babu err = -EINVAL;
1189f0a1913fSSubbaraya Sundeep if (new)
1190f0a1913fSSubbaraya Sundeep kfree(flow);
1191f0a1913fSSubbaraya Sundeep return err;
1192f0a1913fSSubbaraya Sundeep }
1193f0a1913fSSubbaraya Sundeep
1194f0a1913fSSubbaraya Sundeep /* add the new flow installed to list */
1195f0a1913fSSubbaraya Sundeep if (new) {
1196f0a1913fSSubbaraya Sundeep otx2_add_flow_to_list(pfvf, flow);
1197f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows++;
1198f0a1913fSSubbaraya Sundeep }
1199f0a1913fSSubbaraya Sundeep
1200*f174a0daSSuman Ghosh if (flow->is_vf)
1201*f174a0daSSuman Ghosh netdev_info(pfvf->netdev,
1202*f174a0daSSuman Ghosh "Make sure that VF's queue number is within its queue limit\n");
1203f0a1913fSSubbaraya Sundeep return 0;
1204f0a1913fSSubbaraya Sundeep }
1205f0a1913fSSubbaraya Sundeep
otx2_remove_flow_msg(struct otx2_nic * pfvf,u16 entry,bool all)1206f0a1913fSSubbaraya Sundeep static int otx2_remove_flow_msg(struct otx2_nic *pfvf, u16 entry, bool all)
1207f0a1913fSSubbaraya Sundeep {
1208f0a1913fSSubbaraya Sundeep struct npc_delete_flow_req *req;
1209f0a1913fSSubbaraya Sundeep int err;
1210f0a1913fSSubbaraya Sundeep
1211f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
1212f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1213f0a1913fSSubbaraya Sundeep if (!req) {
1214f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1215f0a1913fSSubbaraya Sundeep return -ENOMEM;
1216f0a1913fSSubbaraya Sundeep }
1217f0a1913fSSubbaraya Sundeep
1218f0a1913fSSubbaraya Sundeep req->entry = entry;
1219f0a1913fSSubbaraya Sundeep if (all)
1220f0a1913fSSubbaraya Sundeep req->all = 1;
1221f0a1913fSSubbaraya Sundeep
1222f0a1913fSSubbaraya Sundeep /* Send message to AF */
1223f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox);
1224f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1225f0a1913fSSubbaraya Sundeep return err;
1226f0a1913fSSubbaraya Sundeep }
1227f0a1913fSSubbaraya Sundeep
otx2_update_rem_pfmac(struct otx2_nic * pfvf,int req)122879d2be38SHariprasad Kelam static void otx2_update_rem_pfmac(struct otx2_nic *pfvf, int req)
122979d2be38SHariprasad Kelam {
123079d2be38SHariprasad Kelam struct otx2_flow *iter;
123179d2be38SHariprasad Kelam struct ethhdr *eth_hdr;
123279d2be38SHariprasad Kelam bool found = false;
123379d2be38SHariprasad Kelam
123479d2be38SHariprasad Kelam list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
12358e675581SHariprasad Kelam if ((iter->rule_type & DMAC_FILTER_RULE) && iter->entry == 0) {
123679d2be38SHariprasad Kelam eth_hdr = &iter->flow_spec.h_u.ether_spec;
123779d2be38SHariprasad Kelam if (req == DMAC_ADDR_DEL) {
123879d2be38SHariprasad Kelam otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
123979d2be38SHariprasad Kelam 0);
1240fa5e0ccbSRatheesh Kannoth clear_bit(0, pfvf->flow_cfg->dmacflt_bmap);
124179d2be38SHariprasad Kelam found = true;
124279d2be38SHariprasad Kelam } else {
124379d2be38SHariprasad Kelam ether_addr_copy(eth_hdr->h_dest,
124479d2be38SHariprasad Kelam pfvf->netdev->dev_addr);
1245fa5e0ccbSRatheesh Kannoth
124679d2be38SHariprasad Kelam otx2_dmacflt_update(pfvf, eth_hdr->h_dest, 0);
124779d2be38SHariprasad Kelam }
124879d2be38SHariprasad Kelam break;
124979d2be38SHariprasad Kelam }
125079d2be38SHariprasad Kelam }
125179d2be38SHariprasad Kelam
125279d2be38SHariprasad Kelam if (found) {
125379d2be38SHariprasad Kelam list_del(&iter->list);
125479d2be38SHariprasad Kelam kfree(iter);
125579d2be38SHariprasad Kelam pfvf->flow_cfg->nr_flows--;
125679d2be38SHariprasad Kelam }
125779d2be38SHariprasad Kelam }
125879d2be38SHariprasad Kelam
otx2_remove_flow(struct otx2_nic * pfvf,u32 location)1259f0a1913fSSubbaraya Sundeep int otx2_remove_flow(struct otx2_nic *pfvf, u32 location)
1260f0a1913fSSubbaraya Sundeep {
1261f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1262f0a1913fSSubbaraya Sundeep struct otx2_flow *flow;
1263f0a1913fSSubbaraya Sundeep int err;
1264f0a1913fSSubbaraya Sundeep
126579d2be38SHariprasad Kelam if (location >= otx2_get_maxflows(flow_cfg))
1266f0a1913fSSubbaraya Sundeep return -EINVAL;
1267f0a1913fSSubbaraya Sundeep
1268f0a1913fSSubbaraya Sundeep flow = otx2_find_flow(pfvf, location);
1269f0a1913fSSubbaraya Sundeep if (!flow)
1270f0a1913fSSubbaraya Sundeep return -ENOENT;
1271f0a1913fSSubbaraya Sundeep
12728e675581SHariprasad Kelam if (flow->rule_type & DMAC_FILTER_RULE) {
127379d2be38SHariprasad Kelam struct ethhdr *eth_hdr = &flow->flow_spec.h_u.ether_spec;
127479d2be38SHariprasad Kelam
127579d2be38SHariprasad Kelam /* user not allowed to remove dmac filter with interface mac */
127679d2be38SHariprasad Kelam if (ether_addr_equal(pfvf->netdev->dev_addr, eth_hdr->h_dest))
127779d2be38SHariprasad Kelam return -EPERM;
127879d2be38SHariprasad Kelam
127979d2be38SHariprasad Kelam err = otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
128079d2be38SHariprasad Kelam flow->entry);
1281fa5e0ccbSRatheesh Kannoth clear_bit(flow->entry, flow_cfg->dmacflt_bmap);
128279d2be38SHariprasad Kelam /* If all dmac filters are removed delete macfilter with
128379d2be38SHariprasad Kelam * interface mac address and configure CGX/RPM block in
128479d2be38SHariprasad Kelam * promiscuous mode
128579d2be38SHariprasad Kelam */
1286fa5e0ccbSRatheesh Kannoth if (bitmap_weight(flow_cfg->dmacflt_bmap,
128779d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows) == 1)
128879d2be38SHariprasad Kelam otx2_update_rem_pfmac(pfvf, DMAC_ADDR_DEL);
128979d2be38SHariprasad Kelam } else {
12908e675581SHariprasad Kelam #ifdef CONFIG_DCB
12918e675581SHariprasad Kelam if (flow->rule_type & PFC_FLOWCTRL_RULE)
12928e675581SHariprasad Kelam otx2_update_bpid_in_rqctx(pfvf, 0,
12938e675581SHariprasad Kelam flow->flow_spec.ring_cookie,
12948e675581SHariprasad Kelam false);
12958e675581SHariprasad Kelam #endif
12968e675581SHariprasad Kelam
1297f0a1913fSSubbaraya Sundeep err = otx2_remove_flow_msg(pfvf, flow->entry, false);
129879d2be38SHariprasad Kelam }
129979d2be38SHariprasad Kelam
1300f0a1913fSSubbaraya Sundeep if (err)
1301f0a1913fSSubbaraya Sundeep return err;
1302f0a1913fSSubbaraya Sundeep
1303f0a1913fSSubbaraya Sundeep list_del(&flow->list);
1304f0a1913fSSubbaraya Sundeep kfree(flow);
1305f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--;
1306f0a1913fSSubbaraya Sundeep
1307f0a1913fSSubbaraya Sundeep return 0;
1308f0a1913fSSubbaraya Sundeep }
1309f0a1913fSSubbaraya Sundeep
otx2_rss_ctx_flow_del(struct otx2_nic * pfvf,int ctx_id)131081a43620SGeetha sowjanya void otx2_rss_ctx_flow_del(struct otx2_nic *pfvf, int ctx_id)
131181a43620SGeetha sowjanya {
131281a43620SGeetha sowjanya struct otx2_flow *flow, *tmp;
131381a43620SGeetha sowjanya int err;
131481a43620SGeetha sowjanya
131581a43620SGeetha sowjanya list_for_each_entry_safe(flow, tmp, &pfvf->flow_cfg->flow_list, list) {
131681a43620SGeetha sowjanya if (flow->rss_ctx_id != ctx_id)
131781a43620SGeetha sowjanya continue;
131881a43620SGeetha sowjanya err = otx2_remove_flow(pfvf, flow->location);
131981a43620SGeetha sowjanya if (err)
132081a43620SGeetha sowjanya netdev_warn(pfvf->netdev,
132181a43620SGeetha sowjanya "Can't delete the rule %d associated with this rss group err:%d",
132281a43620SGeetha sowjanya flow->location, err);
132381a43620SGeetha sowjanya }
132481a43620SGeetha sowjanya }
132581a43620SGeetha sowjanya
otx2_destroy_ntuple_flows(struct otx2_nic * pfvf)1326f0a1913fSSubbaraya Sundeep int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf)
1327f0a1913fSSubbaraya Sundeep {
1328f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1329f0a1913fSSubbaraya Sundeep struct npc_delete_flow_req *req;
1330f0a1913fSSubbaraya Sundeep struct otx2_flow *iter, *tmp;
1331f0a1913fSSubbaraya Sundeep int err;
1332f0a1913fSSubbaraya Sundeep
1333f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
1334f0a1913fSSubbaraya Sundeep return 0;
1335f0a1913fSSubbaraya Sundeep
1336a515e5b5SSunil Goutham if (!flow_cfg->max_flows)
1337a515e5b5SSunil Goutham return 0;
1338a515e5b5SSunil Goutham
1339f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
1340f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1341f0a1913fSSubbaraya Sundeep if (!req) {
1342f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1343f0a1913fSSubbaraya Sundeep return -ENOMEM;
1344f0a1913fSSubbaraya Sundeep }
1345f0a1913fSSubbaraya Sundeep
13469917060fSSunil Goutham req->start = flow_cfg->flow_ent[0];
13472e2a8126SSunil Goutham req->end = flow_cfg->flow_ent[flow_cfg->max_flows - 1];
1348f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox);
1349f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1350f0a1913fSSubbaraya Sundeep
1351f0a1913fSSubbaraya Sundeep list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) {
1352f0a1913fSSubbaraya Sundeep list_del(&iter->list);
1353f0a1913fSSubbaraya Sundeep kfree(iter);
1354f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--;
1355f0a1913fSSubbaraya Sundeep }
1356f0a1913fSSubbaraya Sundeep return err;
1357f0a1913fSSubbaraya Sundeep }
1358f0a1913fSSubbaraya Sundeep
otx2_destroy_mcam_flows(struct otx2_nic * pfvf)1359f0a1913fSSubbaraya Sundeep int otx2_destroy_mcam_flows(struct otx2_nic *pfvf)
1360f0a1913fSSubbaraya Sundeep {
1361f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1362f0a1913fSSubbaraya Sundeep struct npc_mcam_free_entry_req *req;
1363f0a1913fSSubbaraya Sundeep struct otx2_flow *iter, *tmp;
1364f0a1913fSSubbaraya Sundeep int err;
1365f0a1913fSSubbaraya Sundeep
1366f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
1367f0a1913fSSubbaraya Sundeep return 0;
1368f0a1913fSSubbaraya Sundeep
1369f0a1913fSSubbaraya Sundeep /* remove all flows */
1370f0a1913fSSubbaraya Sundeep err = otx2_remove_flow_msg(pfvf, 0, true);
1371f0a1913fSSubbaraya Sundeep if (err)
1372f0a1913fSSubbaraya Sundeep return err;
1373f0a1913fSSubbaraya Sundeep
1374f0a1913fSSubbaraya Sundeep list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) {
1375f0a1913fSSubbaraya Sundeep list_del(&iter->list);
1376f0a1913fSSubbaraya Sundeep kfree(iter);
1377f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--;
1378f0a1913fSSubbaraya Sundeep }
1379f0a1913fSSubbaraya Sundeep
1380f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
1381f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_mcam_free_entry(&pfvf->mbox);
1382f0a1913fSSubbaraya Sundeep if (!req) {
1383f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1384f0a1913fSSubbaraya Sundeep return -ENOMEM;
1385f0a1913fSSubbaraya Sundeep }
1386f0a1913fSSubbaraya Sundeep
1387f0a1913fSSubbaraya Sundeep req->all = 1;
1388f0a1913fSSubbaraya Sundeep /* Send message to AF to free MCAM entries */
1389f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox);
1390f0a1913fSSubbaraya Sundeep if (err) {
1391f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1392f0a1913fSSubbaraya Sundeep return err;
1393f0a1913fSSubbaraya Sundeep }
1394f0a1913fSSubbaraya Sundeep
1395f0a1913fSSubbaraya Sundeep pfvf->flags &= ~OTX2_FLAG_MCAM_ENTRIES_ALLOC;
1396f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1397f0a1913fSSubbaraya Sundeep
1398f0a1913fSSubbaraya Sundeep return 0;
1399f0a1913fSSubbaraya Sundeep }
1400fd9d7859SHariprasad Kelam
otx2_install_rxvlan_offload_flow(struct otx2_nic * pfvf)1401fd9d7859SHariprasad Kelam int otx2_install_rxvlan_offload_flow(struct otx2_nic *pfvf)
1402fd9d7859SHariprasad Kelam {
1403fd9d7859SHariprasad Kelam struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1404fd9d7859SHariprasad Kelam struct npc_install_flow_req *req;
1405fd9d7859SHariprasad Kelam int err;
1406fd9d7859SHariprasad Kelam
1407fd9d7859SHariprasad Kelam mutex_lock(&pfvf->mbox.lock);
1408fd9d7859SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
1409fd9d7859SHariprasad Kelam if (!req) {
1410fd9d7859SHariprasad Kelam mutex_unlock(&pfvf->mbox.lock);
1411fd9d7859SHariprasad Kelam return -ENOMEM;
1412fd9d7859SHariprasad Kelam }
1413fd9d7859SHariprasad Kelam
14149917060fSSunil Goutham req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
1415fd9d7859SHariprasad Kelam req->intf = NIX_INTF_RX;
1416fd9d7859SHariprasad Kelam ether_addr_copy(req->packet.dmac, pfvf->netdev->dev_addr);
1417fd9d7859SHariprasad Kelam eth_broadcast_addr((u8 *)&req->mask.dmac);
1418fd9d7859SHariprasad Kelam req->channel = pfvf->hw.rx_chan_base;
1419fd9d7859SHariprasad Kelam req->op = NIX_RX_ACTION_DEFAULT;
1420fd9d7859SHariprasad Kelam req->features = BIT_ULL(NPC_OUTER_VID) | BIT_ULL(NPC_DMAC);
1421fd9d7859SHariprasad Kelam req->vtag0_valid = true;
1422fd9d7859SHariprasad Kelam req->vtag0_type = NIX_AF_LFX_RX_VTAG_TYPE0;
1423fd9d7859SHariprasad Kelam
1424fd9d7859SHariprasad Kelam /* Send message to AF */
1425fd9d7859SHariprasad Kelam err = otx2_sync_mbox_msg(&pfvf->mbox);
1426fd9d7859SHariprasad Kelam mutex_unlock(&pfvf->mbox.lock);
1427fd9d7859SHariprasad Kelam return err;
1428fd9d7859SHariprasad Kelam }
1429fd9d7859SHariprasad Kelam
otx2_delete_rxvlan_offload_flow(struct otx2_nic * pfvf)1430fd9d7859SHariprasad Kelam static int otx2_delete_rxvlan_offload_flow(struct otx2_nic *pfvf)
1431fd9d7859SHariprasad Kelam {
1432fd9d7859SHariprasad Kelam struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1433fd9d7859SHariprasad Kelam struct npc_delete_flow_req *req;
1434fd9d7859SHariprasad Kelam int err;
1435fd9d7859SHariprasad Kelam
1436fd9d7859SHariprasad Kelam mutex_lock(&pfvf->mbox.lock);
1437fd9d7859SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1438fd9d7859SHariprasad Kelam if (!req) {
1439fd9d7859SHariprasad Kelam mutex_unlock(&pfvf->mbox.lock);
1440fd9d7859SHariprasad Kelam return -ENOMEM;
1441fd9d7859SHariprasad Kelam }
1442fd9d7859SHariprasad Kelam
14439917060fSSunil Goutham req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
1444fd9d7859SHariprasad Kelam /* Send message to AF */
1445fd9d7859SHariprasad Kelam err = otx2_sync_mbox_msg(&pfvf->mbox);
1446fd9d7859SHariprasad Kelam mutex_unlock(&pfvf->mbox.lock);
1447fd9d7859SHariprasad Kelam return err;
1448fd9d7859SHariprasad Kelam }
1449fd9d7859SHariprasad Kelam
otx2_enable_rxvlan(struct otx2_nic * pf,bool enable)1450fd9d7859SHariprasad Kelam int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable)
1451fd9d7859SHariprasad Kelam {
1452fd9d7859SHariprasad Kelam struct nix_vtag_config *req;
1453fd9d7859SHariprasad Kelam struct mbox_msghdr *rsp_hdr;
1454fd9d7859SHariprasad Kelam int err;
1455fd9d7859SHariprasad Kelam
1456fd9d7859SHariprasad Kelam /* Dont have enough mcam entries */
1457fd9d7859SHariprasad Kelam if (!(pf->flags & OTX2_FLAG_RX_VLAN_SUPPORT))
1458fd9d7859SHariprasad Kelam return -ENOMEM;
1459fd9d7859SHariprasad Kelam
1460fd9d7859SHariprasad Kelam if (enable) {
1461fd9d7859SHariprasad Kelam err = otx2_install_rxvlan_offload_flow(pf);
1462fd9d7859SHariprasad Kelam if (err)
1463fd9d7859SHariprasad Kelam return err;
1464fd9d7859SHariprasad Kelam } else {
1465fd9d7859SHariprasad Kelam err = otx2_delete_rxvlan_offload_flow(pf);
1466fd9d7859SHariprasad Kelam if (err)
1467fd9d7859SHariprasad Kelam return err;
1468fd9d7859SHariprasad Kelam }
1469fd9d7859SHariprasad Kelam
1470fd9d7859SHariprasad Kelam mutex_lock(&pf->mbox.lock);
1471fd9d7859SHariprasad Kelam req = otx2_mbox_alloc_msg_nix_vtag_cfg(&pf->mbox);
1472fd9d7859SHariprasad Kelam if (!req) {
1473fd9d7859SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
1474fd9d7859SHariprasad Kelam return -ENOMEM;
1475fd9d7859SHariprasad Kelam }
1476fd9d7859SHariprasad Kelam
1477fd9d7859SHariprasad Kelam /* config strip, capture and size */
1478fd9d7859SHariprasad Kelam req->vtag_size = VTAGSIZE_T4;
1479fd9d7859SHariprasad Kelam req->cfg_type = 1; /* rx vlan cfg */
1480fd9d7859SHariprasad Kelam req->rx.vtag_type = NIX_AF_LFX_RX_VTAG_TYPE0;
1481fd9d7859SHariprasad Kelam req->rx.strip_vtag = enable;
1482fd9d7859SHariprasad Kelam req->rx.capture_vtag = enable;
1483fd9d7859SHariprasad Kelam
1484fd9d7859SHariprasad Kelam err = otx2_sync_mbox_msg(&pf->mbox);
1485fd9d7859SHariprasad Kelam if (err) {
1486fd9d7859SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
1487fd9d7859SHariprasad Kelam return err;
1488fd9d7859SHariprasad Kelam }
1489fd9d7859SHariprasad Kelam
1490fd9d7859SHariprasad Kelam rsp_hdr = otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr);
1491fd9d7859SHariprasad Kelam if (IS_ERR(rsp_hdr)) {
1492fd9d7859SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
1493fd9d7859SHariprasad Kelam return PTR_ERR(rsp_hdr);
1494fd9d7859SHariprasad Kelam }
1495fd9d7859SHariprasad Kelam
1496fd9d7859SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
1497fd9d7859SHariprasad Kelam return rsp_hdr->rc;
1498fd9d7859SHariprasad Kelam }
149979d2be38SHariprasad Kelam
otx2_dmacflt_reinstall_flows(struct otx2_nic * pf)150079d2be38SHariprasad Kelam void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf)
150179d2be38SHariprasad Kelam {
150279d2be38SHariprasad Kelam struct otx2_flow *iter;
150379d2be38SHariprasad Kelam struct ethhdr *eth_hdr;
150479d2be38SHariprasad Kelam
150579d2be38SHariprasad Kelam list_for_each_entry(iter, &pf->flow_cfg->flow_list, list) {
15068e675581SHariprasad Kelam if (iter->rule_type & DMAC_FILTER_RULE) {
150779d2be38SHariprasad Kelam eth_hdr = &iter->flow_spec.h_u.ether_spec;
150879d2be38SHariprasad Kelam otx2_dmacflt_add(pf, eth_hdr->h_dest,
150979d2be38SHariprasad Kelam iter->entry);
151079d2be38SHariprasad Kelam }
151179d2be38SHariprasad Kelam }
151279d2be38SHariprasad Kelam }
151379d2be38SHariprasad Kelam
otx2_dmacflt_update_pfmac_flow(struct otx2_nic * pfvf)151479d2be38SHariprasad Kelam void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf)
151579d2be38SHariprasad Kelam {
151679d2be38SHariprasad Kelam otx2_update_rem_pfmac(pfvf, DMAC_ADDR_UPDATE);
151779d2be38SHariprasad Kelam }
1518