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);
124*c4eae7baSDipendra Khadka if (IS_ERR(rsp))
125*c4eae7baSDipendra Khadka goto exit;
1269917060fSSunil Goutham
1279917060fSSunil Goutham for (ent = 0; ent < rsp->count; ent++)
1289917060fSSunil Goutham flow_cfg->flow_ent[ent + allocated] = rsp->entry_list[ent];
1299917060fSSunil Goutham
1309917060fSSunil Goutham allocated += rsp->count;
1319917060fSSunil Goutham
1329917060fSSunil Goutham /* If this request is not fulfilled, no need to send
1339917060fSSunil Goutham * further requests.
1349917060fSSunil Goutham */
1359917060fSSunil Goutham if (rsp->count != req->count)
1369917060fSSunil Goutham break;
1379917060fSSunil Goutham }
1389917060fSSunil Goutham
139cc65fcabSSunil Goutham /* Multiple MCAM entry alloc requests could result in non-sequential
140cc65fcabSSunil Goutham * MCAM entries in the flow_ent[] array. Sort them in an ascending order,
141cc65fcabSSunil Goutham * otherwise user installed ntuple filter index and MCAM entry index will
142cc65fcabSSunil Goutham * not be in sync.
143cc65fcabSSunil Goutham */
144cc65fcabSSunil Goutham if (allocated)
145cc65fcabSSunil Goutham sort(&flow_cfg->flow_ent[0], allocated,
146cc65fcabSSunil Goutham sizeof(flow_cfg->flow_ent[0]), mcam_entry_cmp, NULL);
147cc65fcabSSunil Goutham
1489917060fSSunil Goutham exit:
1499917060fSSunil Goutham mutex_unlock(&pfvf->mbox.lock);
1509917060fSSunil Goutham
1512e2a8126SSunil Goutham flow_cfg->max_flows = allocated;
1529917060fSSunil Goutham
1532da48943SSunil Goutham if (allocated) {
1543cffaed2SRakesh Babu pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
1553cffaed2SRakesh Babu pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
1562da48943SSunil Goutham }
1573cffaed2SRakesh Babu
1589917060fSSunil Goutham if (allocated != count)
1599917060fSSunil Goutham netdev_info(pfvf->netdev,
1603cffaed2SRakesh Babu "Unable to allocate %d MCAM entries, got only %d\n",
1619917060fSSunil Goutham count, allocated);
1629917060fSSunil Goutham return allocated;
1639917060fSSunil Goutham }
1642da48943SSunil Goutham EXPORT_SYMBOL(otx2_alloc_mcam_entries);
1659917060fSSunil Goutham
otx2_mcam_entry_init(struct otx2_nic * pfvf)1662da48943SSunil Goutham static int otx2_mcam_entry_init(struct otx2_nic *pfvf)
167f0a1913fSSubbaraya Sundeep {
168f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
169674b3e16SSuman Ghosh struct npc_get_field_status_req *freq;
170674b3e16SSuman Ghosh struct npc_get_field_status_rsp *frsp;
171f0a1913fSSubbaraya Sundeep struct npc_mcam_alloc_entry_req *req;
172f0a1913fSSubbaraya Sundeep struct npc_mcam_alloc_entry_rsp *rsp;
173f0c2982aSNaveen Mamindlapalli int vf_vlan_max_flows;
1749917060fSSunil Goutham int ent, count;
1759917060fSSunil Goutham
1769917060fSSunil Goutham vf_vlan_max_flows = pfvf->total_vfs * OTX2_PER_VF_VLAN_FLOWS;
1779917060fSSunil Goutham count = OTX2_MAX_UNICAST_FLOWS +
1789917060fSSunil Goutham OTX2_MAX_VLAN_FLOWS + vf_vlan_max_flows;
1799917060fSSunil Goutham
1809917060fSSunil Goutham flow_cfg->def_ent = devm_kmalloc_array(pfvf->dev, count,
1819917060fSSunil Goutham sizeof(u16), GFP_KERNEL);
1829917060fSSunil Goutham if (!flow_cfg->def_ent)
1839917060fSSunil Goutham return -ENOMEM;
184f0a1913fSSubbaraya Sundeep
185f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
186f0a1913fSSubbaraya Sundeep
187f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&pfvf->mbox);
188f0a1913fSSubbaraya Sundeep if (!req) {
189f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
190f0a1913fSSubbaraya Sundeep return -ENOMEM;
191f0a1913fSSubbaraya Sundeep }
192f0a1913fSSubbaraya Sundeep
193f0a1913fSSubbaraya Sundeep req->contig = false;
1949917060fSSunil Goutham req->count = count;
195f0a1913fSSubbaraya Sundeep
196f0a1913fSSubbaraya Sundeep /* Send message to AF */
197f0a1913fSSubbaraya Sundeep if (otx2_sync_mbox_msg(&pfvf->mbox)) {
198f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
199f0a1913fSSubbaraya Sundeep return -EINVAL;
200f0a1913fSSubbaraya Sundeep }
201f0a1913fSSubbaraya Sundeep
202f0a1913fSSubbaraya Sundeep rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp
203f0a1913fSSubbaraya Sundeep (&pfvf->mbox.mbox, 0, &req->hdr);
204*c4eae7baSDipendra Khadka if (IS_ERR(rsp)) {
205*c4eae7baSDipendra Khadka mutex_unlock(&pfvf->mbox.lock);
206*c4eae7baSDipendra Khadka return PTR_ERR(rsp);
207*c4eae7baSDipendra Khadka }
208f0a1913fSSubbaraya Sundeep
20963ee5157SHariprasad Kelam if (rsp->count != req->count) {
210f0a1913fSSubbaraya Sundeep netdev_info(pfvf->netdev,
2119917060fSSunil Goutham "Unable to allocate MCAM entries for ucast, vlan and vf_vlan\n");
2129917060fSSunil Goutham mutex_unlock(&pfvf->mbox.lock);
2139917060fSSunil Goutham devm_kfree(pfvf->dev, flow_cfg->def_ent);
2149917060fSSunil Goutham return 0;
2159917060fSSunil Goutham }
2169917060fSSunil Goutham
2179917060fSSunil Goutham for (ent = 0; ent < rsp->count; ent++)
2189917060fSSunil Goutham flow_cfg->def_ent[ent] = rsp->entry_list[ent];
2199917060fSSunil Goutham
220f0c2982aSNaveen Mamindlapalli flow_cfg->vf_vlan_offset = 0;
2219917060fSSunil Goutham flow_cfg->unicast_offset = vf_vlan_max_flows;
222fd9d7859SHariprasad Kelam flow_cfg->rx_vlan_offset = flow_cfg->unicast_offset +
223fd9d7859SHariprasad Kelam OTX2_MAX_UNICAST_FLOWS;
22463ee5157SHariprasad Kelam pfvf->flags |= OTX2_FLAG_UCAST_FLTR_SUPPORT;
225674b3e16SSuman Ghosh
226674b3e16SSuman Ghosh /* Check if NPC_DMAC field is supported
227674b3e16SSuman Ghosh * by the mkex profile before setting VLAN support flag.
228674b3e16SSuman Ghosh */
229674b3e16SSuman Ghosh freq = otx2_mbox_alloc_msg_npc_get_field_status(&pfvf->mbox);
230674b3e16SSuman Ghosh if (!freq) {
231674b3e16SSuman Ghosh mutex_unlock(&pfvf->mbox.lock);
232674b3e16SSuman Ghosh return -ENOMEM;
233674b3e16SSuman Ghosh }
234674b3e16SSuman Ghosh
235674b3e16SSuman Ghosh freq->field = NPC_DMAC;
236674b3e16SSuman Ghosh if (otx2_sync_mbox_msg(&pfvf->mbox)) {
237674b3e16SSuman Ghosh mutex_unlock(&pfvf->mbox.lock);
238674b3e16SSuman Ghosh return -EINVAL;
239674b3e16SSuman Ghosh }
240674b3e16SSuman Ghosh
241674b3e16SSuman Ghosh frsp = (struct npc_get_field_status_rsp *)otx2_mbox_get_rsp
242674b3e16SSuman Ghosh (&pfvf->mbox.mbox, 0, &freq->hdr);
243*c4eae7baSDipendra Khadka if (IS_ERR(frsp)) {
244*c4eae7baSDipendra Khadka mutex_unlock(&pfvf->mbox.lock);
245*c4eae7baSDipendra Khadka return PTR_ERR(frsp);
246*c4eae7baSDipendra Khadka }
247674b3e16SSuman Ghosh
248674b3e16SSuman Ghosh if (frsp->enable) {
249fd9d7859SHariprasad Kelam pfvf->flags |= OTX2_FLAG_RX_VLAN_SUPPORT;
250f0c2982aSNaveen Mamindlapalli pfvf->flags |= OTX2_FLAG_VF_VLAN_SUPPORT;
251674b3e16SSuman Ghosh }
252f0a1913fSSubbaraya Sundeep
253f0a1913fSSubbaraya Sundeep pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
254f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
255f0a1913fSSubbaraya Sundeep
2569917060fSSunil Goutham /* Allocate entries for Ntuple filters */
2572da48943SSunil Goutham count = otx2_alloc_mcam_entries(pfvf, OTX2_DEFAULT_FLOWCOUNT);
2589917060fSSunil Goutham if (count <= 0) {
2599917060fSSunil Goutham otx2_clear_ntuple_flow_info(pfvf, flow_cfg);
2609917060fSSunil Goutham return 0;
2619917060fSSunil Goutham }
2629917060fSSunil Goutham
2639917060fSSunil Goutham pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
2649917060fSSunil Goutham
265f0a1913fSSubbaraya Sundeep return 0;
266f0a1913fSSubbaraya Sundeep }
267f0a1913fSSubbaraya Sundeep
268fa5e0ccbSRatheesh Kannoth /* TODO : revisit on size */
269fa5e0ccbSRatheesh Kannoth #define OTX2_DMAC_FLTR_BITMAP_SZ (4 * 2048 + 32)
270fa5e0ccbSRatheesh Kannoth
otx2vf_mcam_flow_init(struct otx2_nic * pfvf)2713cffaed2SRakesh Babu int otx2vf_mcam_flow_init(struct otx2_nic *pfvf)
2723cffaed2SRakesh Babu {
2733cffaed2SRakesh Babu struct otx2_flow_config *flow_cfg;
2743cffaed2SRakesh Babu
2753cffaed2SRakesh Babu pfvf->flow_cfg = devm_kzalloc(pfvf->dev,
2763cffaed2SRakesh Babu sizeof(struct otx2_flow_config),
2773cffaed2SRakesh Babu GFP_KERNEL);
2783cffaed2SRakesh Babu if (!pfvf->flow_cfg)
2793cffaed2SRakesh Babu return -ENOMEM;
2803cffaed2SRakesh Babu
281fa5e0ccbSRatheesh Kannoth pfvf->flow_cfg->dmacflt_bmap = devm_kcalloc(pfvf->dev,
282fa5e0ccbSRatheesh Kannoth BITS_TO_LONGS(OTX2_DMAC_FLTR_BITMAP_SZ),
283fa5e0ccbSRatheesh Kannoth sizeof(long), GFP_KERNEL);
284fa5e0ccbSRatheesh Kannoth if (!pfvf->flow_cfg->dmacflt_bmap)
285fa5e0ccbSRatheesh Kannoth return -ENOMEM;
286fa5e0ccbSRatheesh Kannoth
2873cffaed2SRakesh Babu flow_cfg = pfvf->flow_cfg;
2883cffaed2SRakesh Babu INIT_LIST_HEAD(&flow_cfg->flow_list);
289ec87f054SSuman Ghosh INIT_LIST_HEAD(&flow_cfg->flow_list_tc);
2902e2a8126SSunil Goutham flow_cfg->max_flows = 0;
2913cffaed2SRakesh Babu
2923cffaed2SRakesh Babu return 0;
2933cffaed2SRakesh Babu }
2943cffaed2SRakesh Babu EXPORT_SYMBOL(otx2vf_mcam_flow_init);
2953cffaed2SRakesh Babu
otx2_mcam_flow_init(struct otx2_nic * pf)296f0a1913fSSubbaraya Sundeep int otx2_mcam_flow_init(struct otx2_nic *pf)
297f0a1913fSSubbaraya Sundeep {
298f0a1913fSSubbaraya Sundeep int err;
299f0a1913fSSubbaraya Sundeep
300f0a1913fSSubbaraya Sundeep pf->flow_cfg = devm_kzalloc(pf->dev, sizeof(struct otx2_flow_config),
301f0a1913fSSubbaraya Sundeep GFP_KERNEL);
302f0a1913fSSubbaraya Sundeep if (!pf->flow_cfg)
303f0a1913fSSubbaraya Sundeep return -ENOMEM;
304f0a1913fSSubbaraya Sundeep
305fa5e0ccbSRatheesh Kannoth pf->flow_cfg->dmacflt_bmap = devm_kcalloc(pf->dev,
306fa5e0ccbSRatheesh Kannoth BITS_TO_LONGS(OTX2_DMAC_FLTR_BITMAP_SZ),
307fa5e0ccbSRatheesh Kannoth sizeof(long), GFP_KERNEL);
308fa5e0ccbSRatheesh Kannoth if (!pf->flow_cfg->dmacflt_bmap)
309fa5e0ccbSRatheesh Kannoth return -ENOMEM;
310fa5e0ccbSRatheesh Kannoth
311f0a1913fSSubbaraya Sundeep INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
312ec87f054SSuman Ghosh INIT_LIST_HEAD(&pf->flow_cfg->flow_list_tc);
313f0a1913fSSubbaraya Sundeep
3142da48943SSunil Goutham /* Allocate bare minimum number of MCAM entries needed for
3152da48943SSunil Goutham * unicast and ntuple filters.
3162da48943SSunil Goutham */
3172da48943SSunil Goutham err = otx2_mcam_entry_init(pf);
318f0a1913fSSubbaraya Sundeep if (err)
319f0a1913fSSubbaraya Sundeep return err;
320f0a1913fSSubbaraya Sundeep
3219917060fSSunil Goutham /* Check if MCAM entries are allocate or not */
3229917060fSSunil Goutham if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
3239917060fSSunil Goutham return 0;
3249917060fSSunil Goutham
32563ee5157SHariprasad Kelam pf->mac_table = devm_kzalloc(pf->dev, sizeof(struct otx2_mac_table)
32663ee5157SHariprasad Kelam * OTX2_MAX_UNICAST_FLOWS, GFP_KERNEL);
32763ee5157SHariprasad Kelam if (!pf->mac_table)
32863ee5157SHariprasad Kelam return -ENOMEM;
32963ee5157SHariprasad Kelam
33079d2be38SHariprasad Kelam otx2_dmacflt_get_max_cnt(pf);
33179d2be38SHariprasad Kelam
33279d2be38SHariprasad Kelam /* DMAC filters are not allocated */
33379d2be38SHariprasad Kelam if (!pf->flow_cfg->dmacflt_max_flows)
33479d2be38SHariprasad Kelam return 0;
33579d2be38SHariprasad Kelam
33679d2be38SHariprasad Kelam pf->flow_cfg->bmap_to_dmacindex =
337fa5e0ccbSRatheesh Kannoth devm_kzalloc(pf->dev, sizeof(u32) *
33879d2be38SHariprasad Kelam pf->flow_cfg->dmacflt_max_flows,
33979d2be38SHariprasad Kelam GFP_KERNEL);
34079d2be38SHariprasad Kelam
34179d2be38SHariprasad Kelam if (!pf->flow_cfg->bmap_to_dmacindex)
34279d2be38SHariprasad Kelam return -ENOMEM;
34379d2be38SHariprasad Kelam
34479d2be38SHariprasad Kelam pf->flags |= OTX2_FLAG_DMACFLTR_SUPPORT;
34579d2be38SHariprasad Kelam
346f0a1913fSSubbaraya Sundeep return 0;
347f0a1913fSSubbaraya Sundeep }
348f0a1913fSSubbaraya Sundeep
otx2_mcam_flow_del(struct otx2_nic * pf)349f0a1913fSSubbaraya Sundeep void otx2_mcam_flow_del(struct otx2_nic *pf)
350f0a1913fSSubbaraya Sundeep {
351f0a1913fSSubbaraya Sundeep otx2_destroy_mcam_flows(pf);
352f0a1913fSSubbaraya Sundeep }
3533cffaed2SRakesh Babu EXPORT_SYMBOL(otx2_mcam_flow_del);
354f0a1913fSSubbaraya Sundeep
35563ee5157SHariprasad Kelam /* On success adds mcam entry
35663ee5157SHariprasad Kelam * On failure enable promisous mode
35763ee5157SHariprasad Kelam */
otx2_do_add_macfilter(struct otx2_nic * pf,const u8 * mac)35863ee5157SHariprasad Kelam static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac)
35963ee5157SHariprasad Kelam {
36063ee5157SHariprasad Kelam struct otx2_flow_config *flow_cfg = pf->flow_cfg;
36163ee5157SHariprasad Kelam struct npc_install_flow_req *req;
36263ee5157SHariprasad Kelam int err, i;
36363ee5157SHariprasad Kelam
36463ee5157SHariprasad Kelam if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
36563ee5157SHariprasad Kelam return -ENOMEM;
36663ee5157SHariprasad Kelam
36763ee5157SHariprasad Kelam /* dont have free mcam entries or uc list is greater than alloted */
36863ee5157SHariprasad Kelam if (netdev_uc_count(pf->netdev) > OTX2_MAX_UNICAST_FLOWS)
36963ee5157SHariprasad Kelam return -ENOMEM;
37063ee5157SHariprasad Kelam
37163ee5157SHariprasad Kelam mutex_lock(&pf->mbox.lock);
37263ee5157SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_install_flow(&pf->mbox);
37363ee5157SHariprasad Kelam if (!req) {
37463ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
37563ee5157SHariprasad Kelam return -ENOMEM;
37663ee5157SHariprasad Kelam }
37763ee5157SHariprasad Kelam
37863ee5157SHariprasad Kelam /* unicast offset starts with 32 0..31 for ntuple */
37963ee5157SHariprasad Kelam for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) {
38063ee5157SHariprasad Kelam if (pf->mac_table[i].inuse)
38163ee5157SHariprasad Kelam continue;
38263ee5157SHariprasad Kelam ether_addr_copy(pf->mac_table[i].addr, mac);
38363ee5157SHariprasad Kelam pf->mac_table[i].inuse = true;
38463ee5157SHariprasad Kelam pf->mac_table[i].mcam_entry =
3859917060fSSunil Goutham flow_cfg->def_ent[i + flow_cfg->unicast_offset];
38663ee5157SHariprasad Kelam req->entry = pf->mac_table[i].mcam_entry;
38763ee5157SHariprasad Kelam break;
38863ee5157SHariprasad Kelam }
38963ee5157SHariprasad Kelam
39063ee5157SHariprasad Kelam ether_addr_copy(req->packet.dmac, mac);
39163ee5157SHariprasad Kelam eth_broadcast_addr((u8 *)&req->mask.dmac);
39263ee5157SHariprasad Kelam req->features = BIT_ULL(NPC_DMAC);
39363ee5157SHariprasad Kelam req->channel = pf->hw.rx_chan_base;
39463ee5157SHariprasad Kelam req->intf = NIX_INTF_RX;
39563ee5157SHariprasad Kelam req->op = NIX_RX_ACTION_DEFAULT;
39663ee5157SHariprasad Kelam req->set_cntr = 1;
39763ee5157SHariprasad Kelam
39863ee5157SHariprasad Kelam err = otx2_sync_mbox_msg(&pf->mbox);
39963ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
40063ee5157SHariprasad Kelam
40163ee5157SHariprasad Kelam return err;
40263ee5157SHariprasad Kelam }
40363ee5157SHariprasad Kelam
otx2_add_macfilter(struct net_device * netdev,const u8 * mac)40463ee5157SHariprasad Kelam int otx2_add_macfilter(struct net_device *netdev, const u8 *mac)
40563ee5157SHariprasad Kelam {
40663ee5157SHariprasad Kelam struct otx2_nic *pf = netdev_priv(netdev);
40763ee5157SHariprasad Kelam
408fa5e0ccbSRatheesh Kannoth if (!bitmap_empty(pf->flow_cfg->dmacflt_bmap,
40979d2be38SHariprasad Kelam pf->flow_cfg->dmacflt_max_flows))
41079d2be38SHariprasad Kelam netdev_warn(netdev,
41179d2be38SHariprasad Kelam "Add %pM to CGX/RPM DMAC filters list as well\n",
41279d2be38SHariprasad Kelam mac);
41379d2be38SHariprasad Kelam
41463ee5157SHariprasad Kelam return otx2_do_add_macfilter(pf, mac);
41563ee5157SHariprasad Kelam }
41663ee5157SHariprasad Kelam
otx2_get_mcamentry_for_mac(struct otx2_nic * pf,const u8 * mac,int * mcam_entry)41763ee5157SHariprasad Kelam static bool otx2_get_mcamentry_for_mac(struct otx2_nic *pf, const u8 *mac,
41863ee5157SHariprasad Kelam int *mcam_entry)
41963ee5157SHariprasad Kelam {
42063ee5157SHariprasad Kelam int i;
42163ee5157SHariprasad Kelam
42263ee5157SHariprasad Kelam for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) {
42363ee5157SHariprasad Kelam if (!pf->mac_table[i].inuse)
42463ee5157SHariprasad Kelam continue;
42563ee5157SHariprasad Kelam
42663ee5157SHariprasad Kelam if (ether_addr_equal(pf->mac_table[i].addr, mac)) {
42763ee5157SHariprasad Kelam *mcam_entry = pf->mac_table[i].mcam_entry;
42863ee5157SHariprasad Kelam pf->mac_table[i].inuse = false;
42963ee5157SHariprasad Kelam return true;
43063ee5157SHariprasad Kelam }
43163ee5157SHariprasad Kelam }
43263ee5157SHariprasad Kelam return false;
43363ee5157SHariprasad Kelam }
43463ee5157SHariprasad Kelam
otx2_del_macfilter(struct net_device * netdev,const u8 * mac)43563ee5157SHariprasad Kelam int otx2_del_macfilter(struct net_device *netdev, const u8 *mac)
43663ee5157SHariprasad Kelam {
43763ee5157SHariprasad Kelam struct otx2_nic *pf = netdev_priv(netdev);
43863ee5157SHariprasad Kelam struct npc_delete_flow_req *req;
43963ee5157SHariprasad Kelam int err, mcam_entry;
44063ee5157SHariprasad Kelam
44163ee5157SHariprasad Kelam /* check does mcam entry exists for given mac */
44263ee5157SHariprasad Kelam if (!otx2_get_mcamentry_for_mac(pf, mac, &mcam_entry))
44363ee5157SHariprasad Kelam return 0;
44463ee5157SHariprasad Kelam
44563ee5157SHariprasad Kelam mutex_lock(&pf->mbox.lock);
44663ee5157SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_delete_flow(&pf->mbox);
44763ee5157SHariprasad Kelam if (!req) {
44863ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
44963ee5157SHariprasad Kelam return -ENOMEM;
45063ee5157SHariprasad Kelam }
45163ee5157SHariprasad Kelam req->entry = mcam_entry;
45263ee5157SHariprasad Kelam /* Send message to AF */
45363ee5157SHariprasad Kelam err = otx2_sync_mbox_msg(&pf->mbox);
45463ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
45563ee5157SHariprasad Kelam
45663ee5157SHariprasad Kelam return err;
45763ee5157SHariprasad Kelam }
45863ee5157SHariprasad Kelam
otx2_find_flow(struct otx2_nic * pfvf,u32 location)459f0a1913fSSubbaraya Sundeep static struct otx2_flow *otx2_find_flow(struct otx2_nic *pfvf, u32 location)
460f0a1913fSSubbaraya Sundeep {
461f0a1913fSSubbaraya Sundeep struct otx2_flow *iter;
462f0a1913fSSubbaraya Sundeep
463f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
464f0a1913fSSubbaraya Sundeep if (iter->location == location)
465f0a1913fSSubbaraya Sundeep return iter;
466f0a1913fSSubbaraya Sundeep }
467f0a1913fSSubbaraya Sundeep
468f0a1913fSSubbaraya Sundeep return NULL;
469f0a1913fSSubbaraya Sundeep }
470f0a1913fSSubbaraya Sundeep
otx2_add_flow_to_list(struct otx2_nic * pfvf,struct otx2_flow * flow)471f0a1913fSSubbaraya Sundeep static void otx2_add_flow_to_list(struct otx2_nic *pfvf, struct otx2_flow *flow)
472f0a1913fSSubbaraya Sundeep {
473f0a1913fSSubbaraya Sundeep struct list_head *head = &pfvf->flow_cfg->flow_list;
474f0a1913fSSubbaraya Sundeep struct otx2_flow *iter;
475f0a1913fSSubbaraya Sundeep
476f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
477f0a1913fSSubbaraya Sundeep if (iter->location > flow->location)
478f0a1913fSSubbaraya Sundeep break;
479f0a1913fSSubbaraya Sundeep head = &iter->list;
480f0a1913fSSubbaraya Sundeep }
481f0a1913fSSubbaraya Sundeep
482f0a1913fSSubbaraya Sundeep list_add(&flow->list, head);
483f0a1913fSSubbaraya Sundeep }
484f0a1913fSSubbaraya Sundeep
otx2_get_maxflows(struct otx2_flow_config * flow_cfg)4853cffaed2SRakesh Babu int otx2_get_maxflows(struct otx2_flow_config *flow_cfg)
48679d2be38SHariprasad Kelam {
4873cffaed2SRakesh Babu if (!flow_cfg)
4883cffaed2SRakesh Babu return 0;
4893cffaed2SRakesh Babu
4902e2a8126SSunil Goutham if (flow_cfg->nr_flows == flow_cfg->max_flows ||
491fa5e0ccbSRatheesh Kannoth !bitmap_empty(flow_cfg->dmacflt_bmap,
49279d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows))
4932e2a8126SSunil Goutham return flow_cfg->max_flows + flow_cfg->dmacflt_max_flows;
49479d2be38SHariprasad Kelam else
4952e2a8126SSunil Goutham return flow_cfg->max_flows;
49679d2be38SHariprasad Kelam }
4973cffaed2SRakesh Babu EXPORT_SYMBOL(otx2_get_maxflows);
49879d2be38SHariprasad Kelam
otx2_get_flow(struct otx2_nic * pfvf,struct ethtool_rxnfc * nfc,u32 location)499f0a1913fSSubbaraya Sundeep int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
500f0a1913fSSubbaraya Sundeep u32 location)
501f0a1913fSSubbaraya Sundeep {
502f0a1913fSSubbaraya Sundeep struct otx2_flow *iter;
503f0a1913fSSubbaraya Sundeep
50479d2be38SHariprasad Kelam if (location >= otx2_get_maxflows(pfvf->flow_cfg))
505f0a1913fSSubbaraya Sundeep return -EINVAL;
506f0a1913fSSubbaraya Sundeep
507f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
508f0a1913fSSubbaraya Sundeep if (iter->location == location) {
509f0a1913fSSubbaraya Sundeep nfc->fs = iter->flow_spec;
51081a43620SGeetha sowjanya nfc->rss_context = iter->rss_ctx_id;
511f0a1913fSSubbaraya Sundeep return 0;
512f0a1913fSSubbaraya Sundeep }
513f0a1913fSSubbaraya Sundeep }
514f0a1913fSSubbaraya Sundeep
515f0a1913fSSubbaraya Sundeep return -ENOENT;
516f0a1913fSSubbaraya Sundeep }
517f0a1913fSSubbaraya Sundeep
otx2_get_all_flows(struct otx2_nic * pfvf,struct ethtool_rxnfc * nfc,u32 * rule_locs)518f0a1913fSSubbaraya Sundeep int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
519f0a1913fSSubbaraya Sundeep u32 *rule_locs)
520f0a1913fSSubbaraya Sundeep {
521f41b2d67SSubbaraya Sundeep u32 rule_cnt = nfc->rule_cnt;
522f0a1913fSSubbaraya Sundeep u32 location = 0;
523f0a1913fSSubbaraya Sundeep int idx = 0;
524f0a1913fSSubbaraya Sundeep int err = 0;
525f0a1913fSSubbaraya Sundeep
52679d2be38SHariprasad Kelam nfc->data = otx2_get_maxflows(pfvf->flow_cfg);
527f41b2d67SSubbaraya Sundeep while ((!err || err == -ENOENT) && idx < rule_cnt) {
528f0a1913fSSubbaraya Sundeep err = otx2_get_flow(pfvf, nfc, location);
529f0a1913fSSubbaraya Sundeep if (!err)
530f0a1913fSSubbaraya Sundeep rule_locs[idx++] = location;
531f0a1913fSSubbaraya Sundeep location++;
532f0a1913fSSubbaraya Sundeep }
533f41b2d67SSubbaraya Sundeep nfc->rule_cnt = rule_cnt;
534f0a1913fSSubbaraya Sundeep
535f0a1913fSSubbaraya Sundeep return err;
536f0a1913fSSubbaraya Sundeep }
537f0a1913fSSubbaraya Sundeep
otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec * fsp,struct npc_install_flow_req * req,u32 flow_type)538b7cf9661SNaveen Mamindlapalli static int otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp,
539f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req,
540f0a1913fSSubbaraya Sundeep u32 flow_type)
541f0a1913fSSubbaraya Sundeep {
542f0a1913fSSubbaraya Sundeep struct ethtool_usrip4_spec *ipv4_usr_mask = &fsp->m_u.usr_ip4_spec;
543f0a1913fSSubbaraya Sundeep struct ethtool_usrip4_spec *ipv4_usr_hdr = &fsp->h_u.usr_ip4_spec;
544f0a1913fSSubbaraya Sundeep struct ethtool_tcpip4_spec *ipv4_l4_mask = &fsp->m_u.tcp_ip4_spec;
545f0a1913fSSubbaraya Sundeep struct ethtool_tcpip4_spec *ipv4_l4_hdr = &fsp->h_u.tcp_ip4_spec;
546b7cf9661SNaveen Mamindlapalli struct ethtool_ah_espip4_spec *ah_esp_hdr = &fsp->h_u.ah_ip4_spec;
547b7cf9661SNaveen Mamindlapalli struct ethtool_ah_espip4_spec *ah_esp_mask = &fsp->m_u.ah_ip4_spec;
548f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask;
549f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet;
550f0a1913fSSubbaraya Sundeep
551f0a1913fSSubbaraya Sundeep switch (flow_type) {
552f0a1913fSSubbaraya Sundeep case IP_USER_FLOW:
553f0a1913fSSubbaraya Sundeep if (ipv4_usr_mask->ip4src) {
554f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4src, &ipv4_usr_hdr->ip4src,
555f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4src));
556f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4src, &ipv4_usr_mask->ip4src,
557f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4src));
558f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV4);
559f0a1913fSSubbaraya Sundeep }
560f0a1913fSSubbaraya Sundeep if (ipv4_usr_mask->ip4dst) {
561f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4dst, &ipv4_usr_hdr->ip4dst,
562f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4dst));
563f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4dst, &ipv4_usr_mask->ip4dst,
564f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4dst));
565f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV4);
566f0a1913fSSubbaraya Sundeep }
5672b9cef66SNaveen Mamindlapalli if (ipv4_usr_mask->tos) {
5682b9cef66SNaveen Mamindlapalli pkt->tos = ipv4_usr_hdr->tos;
5692b9cef66SNaveen Mamindlapalli pmask->tos = ipv4_usr_mask->tos;
5702b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_TOS);
5712b9cef66SNaveen Mamindlapalli }
5722b9cef66SNaveen Mamindlapalli if (ipv4_usr_mask->proto) {
5732b9cef66SNaveen Mamindlapalli switch (ipv4_usr_hdr->proto) {
5742b9cef66SNaveen Mamindlapalli case IPPROTO_ICMP:
5752b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_ICMP);
5762b9cef66SNaveen Mamindlapalli break;
5772b9cef66SNaveen Mamindlapalli case IPPROTO_TCP:
5782b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_TCP);
5792b9cef66SNaveen Mamindlapalli break;
5802b9cef66SNaveen Mamindlapalli case IPPROTO_UDP:
5812b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_UDP);
5822b9cef66SNaveen Mamindlapalli break;
5832b9cef66SNaveen Mamindlapalli case IPPROTO_SCTP:
5842b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
5852b9cef66SNaveen Mamindlapalli break;
5862b9cef66SNaveen Mamindlapalli case IPPROTO_AH:
5872b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_AH);
5882b9cef66SNaveen Mamindlapalli break;
5892b9cef66SNaveen Mamindlapalli case IPPROTO_ESP:
5902b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_ESP);
5912b9cef66SNaveen Mamindlapalli break;
5922b9cef66SNaveen Mamindlapalli default:
5932b9cef66SNaveen Mamindlapalli return -EOPNOTSUPP;
5942b9cef66SNaveen Mamindlapalli }
5952b9cef66SNaveen Mamindlapalli }
596b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IP);
597b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
598b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
599f0a1913fSSubbaraya Sundeep break;
600f0a1913fSSubbaraya Sundeep case TCP_V4_FLOW:
601f0a1913fSSubbaraya Sundeep case UDP_V4_FLOW:
602f0a1913fSSubbaraya Sundeep case SCTP_V4_FLOW:
603b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IP);
604b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
605b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
606f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->ip4src) {
607f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4src, &ipv4_l4_hdr->ip4src,
608f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4src));
609f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4src, &ipv4_l4_mask->ip4src,
610f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4src));
611f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV4);
612f0a1913fSSubbaraya Sundeep }
613f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->ip4dst) {
614f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4dst, &ipv4_l4_hdr->ip4dst,
615f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4dst));
616f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4dst, &ipv4_l4_mask->ip4dst,
617f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4dst));
618f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV4);
619f0a1913fSSubbaraya Sundeep }
6202b9cef66SNaveen Mamindlapalli if (ipv4_l4_mask->tos) {
6212b9cef66SNaveen Mamindlapalli pkt->tos = ipv4_l4_hdr->tos;
6222b9cef66SNaveen Mamindlapalli pmask->tos = ipv4_l4_mask->tos;
6232b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_TOS);
6242b9cef66SNaveen Mamindlapalli }
625f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->psrc) {
626f0a1913fSSubbaraya Sundeep memcpy(&pkt->sport, &ipv4_l4_hdr->psrc,
627f0a1913fSSubbaraya Sundeep sizeof(pkt->sport));
628f0a1913fSSubbaraya Sundeep memcpy(&pmask->sport, &ipv4_l4_mask->psrc,
629f0a1913fSSubbaraya Sundeep sizeof(pmask->sport));
630f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V4_FLOW)
631f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_UDP);
632f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V4_FLOW)
633f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_TCP);
634f0a1913fSSubbaraya Sundeep else
635f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_SCTP);
636f0a1913fSSubbaraya Sundeep }
637f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->pdst) {
638f0a1913fSSubbaraya Sundeep memcpy(&pkt->dport, &ipv4_l4_hdr->pdst,
639f0a1913fSSubbaraya Sundeep sizeof(pkt->dport));
640f0a1913fSSubbaraya Sundeep memcpy(&pmask->dport, &ipv4_l4_mask->pdst,
641f0a1913fSSubbaraya Sundeep sizeof(pmask->dport));
642f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V4_FLOW)
643f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_UDP);
644f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V4_FLOW)
645f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_TCP);
646f0a1913fSSubbaraya Sundeep else
647f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_SCTP);
648f0a1913fSSubbaraya Sundeep }
649b7cf9661SNaveen Mamindlapalli if (flow_type == UDP_V4_FLOW)
650b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_UDP);
651b7cf9661SNaveen Mamindlapalli else if (flow_type == TCP_V4_FLOW)
652b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_TCP);
653b7cf9661SNaveen Mamindlapalli else
654b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
655b7cf9661SNaveen Mamindlapalli break;
656b7cf9661SNaveen Mamindlapalli case AH_V4_FLOW:
657b7cf9661SNaveen Mamindlapalli case ESP_V4_FLOW:
658b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IP);
659b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
660b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
661b7cf9661SNaveen Mamindlapalli if (ah_esp_mask->ip4src) {
662b7cf9661SNaveen Mamindlapalli memcpy(&pkt->ip4src, &ah_esp_hdr->ip4src,
663b7cf9661SNaveen Mamindlapalli sizeof(pkt->ip4src));
664b7cf9661SNaveen Mamindlapalli memcpy(&pmask->ip4src, &ah_esp_mask->ip4src,
665b7cf9661SNaveen Mamindlapalli sizeof(pmask->ip4src));
666b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_SIP_IPV4);
667b7cf9661SNaveen Mamindlapalli }
668b7cf9661SNaveen Mamindlapalli if (ah_esp_mask->ip4dst) {
669b7cf9661SNaveen Mamindlapalli memcpy(&pkt->ip4dst, &ah_esp_hdr->ip4dst,
670b7cf9661SNaveen Mamindlapalli sizeof(pkt->ip4dst));
671b7cf9661SNaveen Mamindlapalli memcpy(&pmask->ip4dst, &ah_esp_mask->ip4dst,
672b7cf9661SNaveen Mamindlapalli sizeof(pmask->ip4dst));
673b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_DIP_IPV4);
674b7cf9661SNaveen Mamindlapalli }
6752b9cef66SNaveen Mamindlapalli if (ah_esp_mask->tos) {
6762b9cef66SNaveen Mamindlapalli pkt->tos = ah_esp_hdr->tos;
6772b9cef66SNaveen Mamindlapalli pmask->tos = ah_esp_mask->tos;
6782b9cef66SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_TOS);
6792b9cef66SNaveen Mamindlapalli }
680b7cf9661SNaveen Mamindlapalli
681b7cf9661SNaveen Mamindlapalli /* NPC profile doesn't extract AH/ESP header fields */
6822b9cef66SNaveen Mamindlapalli if (ah_esp_mask->spi & ah_esp_hdr->spi)
683b7cf9661SNaveen Mamindlapalli return -EOPNOTSUPP;
684b7cf9661SNaveen Mamindlapalli
685b7cf9661SNaveen Mamindlapalli if (flow_type == AH_V4_FLOW)
686b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_AH);
687b7cf9661SNaveen Mamindlapalli else
688b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_ESP);
689f0a1913fSSubbaraya Sundeep break;
690f0a1913fSSubbaraya Sundeep default:
691f0a1913fSSubbaraya Sundeep break;
692f0a1913fSSubbaraya Sundeep }
693b7cf9661SNaveen Mamindlapalli
694b7cf9661SNaveen Mamindlapalli return 0;
695f0a1913fSSubbaraya Sundeep }
696f0a1913fSSubbaraya Sundeep
otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec * fsp,struct npc_install_flow_req * req,u32 flow_type)697b7cf9661SNaveen Mamindlapalli static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
698f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req,
699f0a1913fSSubbaraya Sundeep u32 flow_type)
700f0a1913fSSubbaraya Sundeep {
701f0a1913fSSubbaraya Sundeep struct ethtool_usrip6_spec *ipv6_usr_mask = &fsp->m_u.usr_ip6_spec;
702f0a1913fSSubbaraya Sundeep struct ethtool_usrip6_spec *ipv6_usr_hdr = &fsp->h_u.usr_ip6_spec;
703f0a1913fSSubbaraya Sundeep struct ethtool_tcpip6_spec *ipv6_l4_mask = &fsp->m_u.tcp_ip6_spec;
704f0a1913fSSubbaraya Sundeep struct ethtool_tcpip6_spec *ipv6_l4_hdr = &fsp->h_u.tcp_ip6_spec;
705b7cf9661SNaveen Mamindlapalli struct ethtool_ah_espip6_spec *ah_esp_hdr = &fsp->h_u.ah_ip6_spec;
706b7cf9661SNaveen Mamindlapalli struct ethtool_ah_espip6_spec *ah_esp_mask = &fsp->m_u.ah_ip6_spec;
707f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask;
708f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet;
709f0a1913fSSubbaraya Sundeep
710f0a1913fSSubbaraya Sundeep switch (flow_type) {
711f0a1913fSSubbaraya Sundeep case IPV6_USER_FLOW:
712f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6src)) {
713f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6src, &ipv6_usr_hdr->ip6src,
714f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6src));
715f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6src, &ipv6_usr_mask->ip6src,
716f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6src));
717f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV6);
718f0a1913fSSubbaraya Sundeep }
719f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6dst)) {
720f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6dst, &ipv6_usr_hdr->ip6dst,
721f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6dst));
722f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6dst, &ipv6_usr_mask->ip6dst,
723f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6dst));
724f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV6);
725f0a1913fSSubbaraya Sundeep }
726c672e372SSuman Ghosh if (ipv6_usr_hdr->l4_proto == IPPROTO_FRAGMENT) {
727c672e372SSuman Ghosh pkt->next_header = ipv6_usr_hdr->l4_proto;
728c672e372SSuman Ghosh pmask->next_header = ipv6_usr_mask->l4_proto;
729c672e372SSuman Ghosh req->features |= BIT_ULL(NPC_IPFRAG_IPV6);
730c672e372SSuman Ghosh }
731b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IPV6);
732b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
733b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
734f0a1913fSSubbaraya Sundeep break;
735f0a1913fSSubbaraya Sundeep case TCP_V6_FLOW:
736f0a1913fSSubbaraya Sundeep case UDP_V6_FLOW:
737f0a1913fSSubbaraya Sundeep case SCTP_V6_FLOW:
738b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IPV6);
739b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
740b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
741f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6src)) {
742f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6src, &ipv6_l4_hdr->ip6src,
743f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6src));
744f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6src, &ipv6_l4_mask->ip6src,
745f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6src));
746f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV6);
747f0a1913fSSubbaraya Sundeep }
748f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6dst)) {
749f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6dst, &ipv6_l4_hdr->ip6dst,
750f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6dst));
751f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6dst, &ipv6_l4_mask->ip6dst,
752f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6dst));
753f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV6);
754f0a1913fSSubbaraya Sundeep }
755f0a1913fSSubbaraya Sundeep if (ipv6_l4_mask->psrc) {
756f0a1913fSSubbaraya Sundeep memcpy(&pkt->sport, &ipv6_l4_hdr->psrc,
757f0a1913fSSubbaraya Sundeep sizeof(pkt->sport));
758f0a1913fSSubbaraya Sundeep memcpy(&pmask->sport, &ipv6_l4_mask->psrc,
759f0a1913fSSubbaraya Sundeep sizeof(pmask->sport));
760f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V6_FLOW)
761f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_UDP);
762f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V6_FLOW)
763f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_TCP);
764f0a1913fSSubbaraya Sundeep else
765f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_SCTP);
766f0a1913fSSubbaraya Sundeep }
767f0a1913fSSubbaraya Sundeep if (ipv6_l4_mask->pdst) {
768f0a1913fSSubbaraya Sundeep memcpy(&pkt->dport, &ipv6_l4_hdr->pdst,
769f0a1913fSSubbaraya Sundeep sizeof(pkt->dport));
770f0a1913fSSubbaraya Sundeep memcpy(&pmask->dport, &ipv6_l4_mask->pdst,
771f0a1913fSSubbaraya Sundeep sizeof(pmask->dport));
772f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V6_FLOW)
773f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_UDP);
774f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V6_FLOW)
775f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_TCP);
776f0a1913fSSubbaraya Sundeep else
777f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_SCTP);
778f0a1913fSSubbaraya Sundeep }
779b7cf9661SNaveen Mamindlapalli if (flow_type == UDP_V6_FLOW)
780b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_UDP);
781b7cf9661SNaveen Mamindlapalli else if (flow_type == TCP_V6_FLOW)
782b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_TCP);
783b7cf9661SNaveen Mamindlapalli else
784b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
785f0a1913fSSubbaraya Sundeep break;
786b7cf9661SNaveen Mamindlapalli case AH_V6_FLOW:
787b7cf9661SNaveen Mamindlapalli case ESP_V6_FLOW:
788b7cf9661SNaveen Mamindlapalli pkt->etype = cpu_to_be16(ETH_P_IPV6);
789b7cf9661SNaveen Mamindlapalli pmask->etype = cpu_to_be16(0xFFFF);
790b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_ETYPE);
791b7cf9661SNaveen Mamindlapalli if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6src)) {
792b7cf9661SNaveen Mamindlapalli memcpy(&pkt->ip6src, &ah_esp_hdr->ip6src,
793b7cf9661SNaveen Mamindlapalli sizeof(pkt->ip6src));
794b7cf9661SNaveen Mamindlapalli memcpy(&pmask->ip6src, &ah_esp_mask->ip6src,
795b7cf9661SNaveen Mamindlapalli sizeof(pmask->ip6src));
796b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_SIP_IPV6);
797b7cf9661SNaveen Mamindlapalli }
798b7cf9661SNaveen Mamindlapalli if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6dst)) {
799b7cf9661SNaveen Mamindlapalli memcpy(&pkt->ip6dst, &ah_esp_hdr->ip6dst,
800b7cf9661SNaveen Mamindlapalli sizeof(pkt->ip6dst));
801b7cf9661SNaveen Mamindlapalli memcpy(&pmask->ip6dst, &ah_esp_mask->ip6dst,
802b7cf9661SNaveen Mamindlapalli sizeof(pmask->ip6dst));
803b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_DIP_IPV6);
804b7cf9661SNaveen Mamindlapalli }
805b7cf9661SNaveen Mamindlapalli
806b7cf9661SNaveen Mamindlapalli /* NPC profile doesn't extract AH/ESP header fields */
807b7cf9661SNaveen Mamindlapalli if ((ah_esp_mask->spi & ah_esp_hdr->spi) ||
8083acd9db9SDeepak R Varma (ah_esp_mask->tclass & ah_esp_hdr->tclass))
809b7cf9661SNaveen Mamindlapalli return -EOPNOTSUPP;
810b7cf9661SNaveen Mamindlapalli
811b7cf9661SNaveen Mamindlapalli if (flow_type == AH_V6_FLOW)
812b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_AH);
813b7cf9661SNaveen Mamindlapalli else
814b7cf9661SNaveen Mamindlapalli req->features |= BIT_ULL(NPC_IPPROTO_ESP);
815320daffdSGustavo A. R. Silva break;
816f0a1913fSSubbaraya Sundeep default:
817f0a1913fSSubbaraya Sundeep break;
818f0a1913fSSubbaraya Sundeep }
819b7cf9661SNaveen Mamindlapalli
820b7cf9661SNaveen Mamindlapalli return 0;
821f0a1913fSSubbaraya Sundeep }
822f0a1913fSSubbaraya Sundeep
otx2_prepare_flow_request(struct ethtool_rx_flow_spec * fsp,struct npc_install_flow_req * req)823dce677daSSubbaraya Sundeep static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
824f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req)
825f0a1913fSSubbaraya Sundeep {
826f0a1913fSSubbaraya Sundeep struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
827f0a1913fSSubbaraya Sundeep struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
828f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask;
829f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet;
830f0a1913fSSubbaraya Sundeep u32 flow_type;
831b7cf9661SNaveen Mamindlapalli int ret;
832f0a1913fSSubbaraya Sundeep
83381a43620SGeetha sowjanya flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
834f0a1913fSSubbaraya Sundeep switch (flow_type) {
835f0a1913fSSubbaraya Sundeep /* bits not set in mask are don't care */
836f0a1913fSSubbaraya Sundeep case ETHER_FLOW:
837f0a1913fSSubbaraya Sundeep if (!is_zero_ether_addr(eth_mask->h_source)) {
838f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->smac, eth_hdr->h_source);
839f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->smac, eth_mask->h_source);
840f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SMAC);
841f0a1913fSSubbaraya Sundeep }
842f0a1913fSSubbaraya Sundeep if (!is_zero_ether_addr(eth_mask->h_dest)) {
843f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->dmac, eth_hdr->h_dest);
844f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->dmac, eth_mask->h_dest);
845f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DMAC);
846f0a1913fSSubbaraya Sundeep }
8473cffaed2SRakesh Babu if (eth_hdr->h_proto) {
848f0a1913fSSubbaraya Sundeep memcpy(&pkt->etype, ð_hdr->h_proto,
849f0a1913fSSubbaraya Sundeep sizeof(pkt->etype));
850f0a1913fSSubbaraya Sundeep memcpy(&pmask->etype, ð_mask->h_proto,
851f0a1913fSSubbaraya Sundeep sizeof(pmask->etype));
852f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_ETYPE);
853f0a1913fSSubbaraya Sundeep }
854f0a1913fSSubbaraya Sundeep break;
855f0a1913fSSubbaraya Sundeep case IP_USER_FLOW:
856f0a1913fSSubbaraya Sundeep case TCP_V4_FLOW:
857f0a1913fSSubbaraya Sundeep case UDP_V4_FLOW:
858f0a1913fSSubbaraya Sundeep case SCTP_V4_FLOW:
859b7cf9661SNaveen Mamindlapalli case AH_V4_FLOW:
860b7cf9661SNaveen Mamindlapalli case ESP_V4_FLOW:
861b7cf9661SNaveen Mamindlapalli ret = otx2_prepare_ipv4_flow(fsp, req, flow_type);
862b7cf9661SNaveen Mamindlapalli if (ret)
863b7cf9661SNaveen Mamindlapalli return ret;
864f0a1913fSSubbaraya Sundeep break;
865f0a1913fSSubbaraya Sundeep case IPV6_USER_FLOW:
866f0a1913fSSubbaraya Sundeep case TCP_V6_FLOW:
867f0a1913fSSubbaraya Sundeep case UDP_V6_FLOW:
868f0a1913fSSubbaraya Sundeep case SCTP_V6_FLOW:
869b7cf9661SNaveen Mamindlapalli case AH_V6_FLOW:
870b7cf9661SNaveen Mamindlapalli case ESP_V6_FLOW:
871b7cf9661SNaveen Mamindlapalli ret = otx2_prepare_ipv6_flow(fsp, req, flow_type);
872b7cf9661SNaveen Mamindlapalli if (ret)
873b7cf9661SNaveen Mamindlapalli return ret;
874f0a1913fSSubbaraya Sundeep break;
875f0a1913fSSubbaraya Sundeep default:
876f0a1913fSSubbaraya Sundeep return -EOPNOTSUPP;
877f0a1913fSSubbaraya Sundeep }
878f0a1913fSSubbaraya Sundeep if (fsp->flow_type & FLOW_EXT) {
879dce677daSSubbaraya Sundeep u16 vlan_etype;
880dce677daSSubbaraya Sundeep
881dce677daSSubbaraya Sundeep if (fsp->m_ext.vlan_etype) {
882dce677daSSubbaraya Sundeep /* Partial masks not supported */
883dce677daSSubbaraya Sundeep if (be16_to_cpu(fsp->m_ext.vlan_etype) != 0xFFFF)
884f0a1913fSSubbaraya Sundeep return -EINVAL;
885dce677daSSubbaraya Sundeep
886dce677daSSubbaraya Sundeep vlan_etype = be16_to_cpu(fsp->h_ext.vlan_etype);
8878278ee2aSSuman Ghosh
8888278ee2aSSuman Ghosh /* Drop rule with vlan_etype == 802.1Q
8898278ee2aSSuman Ghosh * and vlan_id == 0 is not supported
8908278ee2aSSuman Ghosh */
8918278ee2aSSuman Ghosh if (vlan_etype == ETH_P_8021Q && !fsp->m_ext.vlan_tci &&
8928278ee2aSSuman Ghosh fsp->ring_cookie == RX_CLS_FLOW_DISC)
8938278ee2aSSuman Ghosh return -EINVAL;
8948278ee2aSSuman Ghosh
895dce677daSSubbaraya Sundeep /* Only ETH_P_8021Q and ETH_P_802AD types supported */
896dce677daSSubbaraya Sundeep if (vlan_etype != ETH_P_8021Q &&
897dce677daSSubbaraya Sundeep vlan_etype != ETH_P_8021AD)
898dce677daSSubbaraya Sundeep return -EINVAL;
899dce677daSSubbaraya Sundeep
900dce677daSSubbaraya Sundeep memcpy(&pkt->vlan_etype, &fsp->h_ext.vlan_etype,
901dce677daSSubbaraya Sundeep sizeof(pkt->vlan_etype));
902dce677daSSubbaraya Sundeep memcpy(&pmask->vlan_etype, &fsp->m_ext.vlan_etype,
903dce677daSSubbaraya Sundeep sizeof(pmask->vlan_etype));
904dce677daSSubbaraya Sundeep
905dce677daSSubbaraya Sundeep if (vlan_etype == ETH_P_8021Q)
906dce677daSSubbaraya Sundeep req->features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG);
907dce677daSSubbaraya Sundeep else
908dce677daSSubbaraya Sundeep req->features |= BIT_ULL(NPC_VLAN_ETYPE_STAG);
909dce677daSSubbaraya Sundeep }
910dce677daSSubbaraya Sundeep
911f0a1913fSSubbaraya Sundeep if (fsp->m_ext.vlan_tci) {
912f0a1913fSSubbaraya Sundeep memcpy(&pkt->vlan_tci, &fsp->h_ext.vlan_tci,
913f0a1913fSSubbaraya Sundeep sizeof(pkt->vlan_tci));
914f0a1913fSSubbaraya Sundeep memcpy(&pmask->vlan_tci, &fsp->m_ext.vlan_tci,
915f0a1913fSSubbaraya Sundeep sizeof(pmask->vlan_tci));
916f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_OUTER_VID);
917f0a1913fSSubbaraya Sundeep }
918f0a1913fSSubbaraya Sundeep
919c672e372SSuman Ghosh if (fsp->m_ext.data[1]) {
920c672e372SSuman Ghosh if (flow_type == IP_USER_FLOW) {
921c672e372SSuman Ghosh if (be32_to_cpu(fsp->h_ext.data[1]) != IPV4_FLAG_MORE)
922c672e372SSuman Ghosh return -EINVAL;
923c672e372SSuman Ghosh
924c672e372SSuman Ghosh pkt->ip_flag = be32_to_cpu(fsp->h_ext.data[1]);
925c672e372SSuman Ghosh pmask->ip_flag = be32_to_cpu(fsp->m_ext.data[1]);
926c672e372SSuman Ghosh req->features |= BIT_ULL(NPC_IPFRAG_IPV4);
927c672e372SSuman Ghosh } else if (fsp->h_ext.data[1] ==
928c672e372SSuman Ghosh cpu_to_be32(OTX2_DEFAULT_ACTION)) {
929c672e372SSuman Ghosh /* Not Drop/Direct to queue but use action
930c672e372SSuman Ghosh * in default entry
931c672e372SSuman Ghosh */
932f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTION_DEFAULT;
933f0a1913fSSubbaraya Sundeep }
934c672e372SSuman Ghosh }
935c672e372SSuman Ghosh }
936f0a1913fSSubbaraya Sundeep
937f0a1913fSSubbaraya Sundeep if (fsp->flow_type & FLOW_MAC_EXT &&
938f0a1913fSSubbaraya Sundeep !is_zero_ether_addr(fsp->m_ext.h_dest)) {
939f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->dmac, fsp->h_ext.h_dest);
940f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->dmac, fsp->m_ext.h_dest);
941f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DMAC);
942f0a1913fSSubbaraya Sundeep }
943f0a1913fSSubbaraya Sundeep
944f0a1913fSSubbaraya Sundeep if (!req->features)
945f0a1913fSSubbaraya Sundeep return -EOPNOTSUPP;
946f0a1913fSSubbaraya Sundeep
947f0a1913fSSubbaraya Sundeep return 0;
948f0a1913fSSubbaraya Sundeep }
949f0a1913fSSubbaraya Sundeep
otx2_is_flow_rule_dmacfilter(struct otx2_nic * pfvf,struct ethtool_rx_flow_spec * fsp)95079d2be38SHariprasad Kelam static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
95179d2be38SHariprasad Kelam struct ethtool_rx_flow_spec *fsp)
95279d2be38SHariprasad Kelam {
95379d2be38SHariprasad Kelam struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
95479d2be38SHariprasad Kelam struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
95579d2be38SHariprasad Kelam u64 ring_cookie = fsp->ring_cookie;
95679d2be38SHariprasad Kelam u32 flow_type;
95779d2be38SHariprasad Kelam
95879d2be38SHariprasad Kelam if (!(pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT))
95979d2be38SHariprasad Kelam return false;
96079d2be38SHariprasad Kelam
96179d2be38SHariprasad Kelam flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
96279d2be38SHariprasad Kelam
96379d2be38SHariprasad Kelam /* CGX/RPM block dmac filtering configured for white listing
96479d2be38SHariprasad Kelam * check for action other than DROP
96579d2be38SHariprasad Kelam */
96679d2be38SHariprasad Kelam if (flow_type == ETHER_FLOW && ring_cookie != RX_CLS_FLOW_DISC &&
96779d2be38SHariprasad Kelam !ethtool_get_flow_spec_ring_vf(ring_cookie)) {
96879d2be38SHariprasad Kelam if (is_zero_ether_addr(eth_mask->h_dest) &&
96979d2be38SHariprasad Kelam is_valid_ether_addr(eth_hdr->h_dest))
97079d2be38SHariprasad Kelam return true;
97179d2be38SHariprasad Kelam }
97279d2be38SHariprasad Kelam
97379d2be38SHariprasad Kelam return false;
97479d2be38SHariprasad Kelam }
97579d2be38SHariprasad Kelam
otx2_add_flow_msg(struct otx2_nic * pfvf,struct otx2_flow * flow)976f0a1913fSSubbaraya Sundeep static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
977f0a1913fSSubbaraya Sundeep {
978f0a1913fSSubbaraya Sundeep u64 ring_cookie = flow->flow_spec.ring_cookie;
9798e675581SHariprasad Kelam #ifdef CONFIG_DCB
9808e675581SHariprasad Kelam int vlan_prio, qidx, pfc_rule = 0;
9818e675581SHariprasad Kelam #endif
982f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req;
983f0a1913fSSubbaraya Sundeep int err, vf = 0;
984f0a1913fSSubbaraya Sundeep
985f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
986f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
987f0a1913fSSubbaraya Sundeep if (!req) {
988f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
989f0a1913fSSubbaraya Sundeep return -ENOMEM;
990f0a1913fSSubbaraya Sundeep }
991f0a1913fSSubbaraya Sundeep
992f0a1913fSSubbaraya Sundeep err = otx2_prepare_flow_request(&flow->flow_spec, req);
993f0a1913fSSubbaraya Sundeep if (err) {
994f0a1913fSSubbaraya Sundeep /* free the allocated msg above */
995f0a1913fSSubbaraya Sundeep otx2_mbox_reset(&pfvf->mbox.mbox, 0);
996f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
997f0a1913fSSubbaraya Sundeep return err;
998f0a1913fSSubbaraya Sundeep }
999f0a1913fSSubbaraya Sundeep
1000f0a1913fSSubbaraya Sundeep req->entry = flow->entry;
1001f0a1913fSSubbaraya Sundeep req->intf = NIX_INTF_RX;
1002f0a1913fSSubbaraya Sundeep req->set_cntr = 1;
1003f0a1913fSSubbaraya Sundeep req->channel = pfvf->hw.rx_chan_base;
1004f0a1913fSSubbaraya Sundeep if (ring_cookie == RX_CLS_FLOW_DISC) {
1005f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTIONOP_DROP;
1006f0a1913fSSubbaraya Sundeep } else {
1007f0a1913fSSubbaraya Sundeep /* change to unicast only if action of default entry is not
1008f0a1913fSSubbaraya Sundeep * requested by user
1009f0a1913fSSubbaraya Sundeep */
101081a43620SGeetha sowjanya if (flow->flow_spec.flow_type & FLOW_RSS) {
101181a43620SGeetha sowjanya req->op = NIX_RX_ACTIONOP_RSS;
101281a43620SGeetha sowjanya req->index = flow->rss_ctx_id;
1013e7938365SSunil Goutham req->flow_key_alg = pfvf->hw.flowkey_alg_idx;
101481a43620SGeetha sowjanya } else {
1015f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTIONOP_UCAST;
1016f0a1913fSSubbaraya Sundeep req->index = ethtool_get_flow_spec_ring(ring_cookie);
101781a43620SGeetha sowjanya }
1018f0a1913fSSubbaraya Sundeep vf = ethtool_get_flow_spec_ring_vf(ring_cookie);
1019f0a1913fSSubbaraya Sundeep if (vf > pci_num_vf(pfvf->pdev)) {
1020f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1021f0a1913fSSubbaraya Sundeep return -EINVAL;
1022f0a1913fSSubbaraya Sundeep }
10238e675581SHariprasad Kelam
10248e675581SHariprasad Kelam #ifdef CONFIG_DCB
10258e675581SHariprasad Kelam /* Identify PFC rule if PFC enabled and ntuple rule is vlan */
10268e675581SHariprasad Kelam if (!vf && (req->features & BIT_ULL(NPC_OUTER_VID)) &&
10278e675581SHariprasad Kelam pfvf->pfc_en && req->op != NIX_RX_ACTIONOP_RSS) {
10288e675581SHariprasad Kelam vlan_prio = ntohs(req->packet.vlan_tci) &
10298e675581SHariprasad Kelam ntohs(req->mask.vlan_tci);
10308e675581SHariprasad Kelam
10318e675581SHariprasad Kelam /* Get the priority */
10328e675581SHariprasad Kelam vlan_prio >>= 13;
10338e675581SHariprasad Kelam flow->rule_type |= PFC_FLOWCTRL_RULE;
10348e675581SHariprasad Kelam /* Check if PFC enabled for this priority */
10358e675581SHariprasad Kelam if (pfvf->pfc_en & BIT(vlan_prio)) {
10368e675581SHariprasad Kelam pfc_rule = true;
10378e675581SHariprasad Kelam qidx = req->index;
10388e675581SHariprasad Kelam }
10398e675581SHariprasad Kelam }
10408e675581SHariprasad Kelam #endif
1041f0a1913fSSubbaraya Sundeep }
1042f0a1913fSSubbaraya Sundeep
1043f0a1913fSSubbaraya Sundeep /* ethtool ring_cookie has (VF + 1) for VF */
1044f0a1913fSSubbaraya Sundeep if (vf) {
1045f0a1913fSSubbaraya Sundeep req->vf = vf;
1046f0a1913fSSubbaraya Sundeep flow->is_vf = true;
1047f0a1913fSSubbaraya Sundeep flow->vf = vf;
1048f0a1913fSSubbaraya Sundeep }
1049f0a1913fSSubbaraya Sundeep
1050f0a1913fSSubbaraya Sundeep /* Send message to AF */
1051f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox);
10528e675581SHariprasad Kelam
10538e675581SHariprasad Kelam #ifdef CONFIG_DCB
10548e675581SHariprasad Kelam if (!err && pfc_rule)
10558e675581SHariprasad Kelam otx2_update_bpid_in_rqctx(pfvf, vlan_prio, qidx, true);
10568e675581SHariprasad Kelam #endif
10578e675581SHariprasad Kelam
1058f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1059f0a1913fSSubbaraya Sundeep return err;
1060f0a1913fSSubbaraya Sundeep }
1061f0a1913fSSubbaraya Sundeep
otx2_add_flow_with_pfmac(struct otx2_nic * pfvf,struct otx2_flow * flow)106279d2be38SHariprasad Kelam static int otx2_add_flow_with_pfmac(struct otx2_nic *pfvf,
106379d2be38SHariprasad Kelam struct otx2_flow *flow)
106479d2be38SHariprasad Kelam {
106579d2be38SHariprasad Kelam struct otx2_flow *pf_mac;
106679d2be38SHariprasad Kelam struct ethhdr *eth_hdr;
106779d2be38SHariprasad Kelam
106879d2be38SHariprasad Kelam pf_mac = kzalloc(sizeof(*pf_mac), GFP_KERNEL);
106979d2be38SHariprasad Kelam if (!pf_mac)
107079d2be38SHariprasad Kelam return -ENOMEM;
107179d2be38SHariprasad Kelam
107279d2be38SHariprasad Kelam pf_mac->entry = 0;
10738e675581SHariprasad Kelam pf_mac->rule_type |= DMAC_FILTER_RULE;
10742e2a8126SSunil Goutham pf_mac->location = pfvf->flow_cfg->max_flows;
107579d2be38SHariprasad Kelam memcpy(&pf_mac->flow_spec, &flow->flow_spec,
107679d2be38SHariprasad Kelam sizeof(struct ethtool_rx_flow_spec));
107779d2be38SHariprasad Kelam pf_mac->flow_spec.location = pf_mac->location;
107879d2be38SHariprasad Kelam
107979d2be38SHariprasad Kelam /* Copy PF mac address */
108079d2be38SHariprasad Kelam eth_hdr = &pf_mac->flow_spec.h_u.ether_spec;
108179d2be38SHariprasad Kelam ether_addr_copy(eth_hdr->h_dest, pfvf->netdev->dev_addr);
108279d2be38SHariprasad Kelam
108379d2be38SHariprasad Kelam /* Install DMAC filter with PF mac address */
108479d2be38SHariprasad Kelam otx2_dmacflt_add(pfvf, eth_hdr->h_dest, 0);
108579d2be38SHariprasad Kelam
108679d2be38SHariprasad Kelam otx2_add_flow_to_list(pfvf, pf_mac);
108779d2be38SHariprasad Kelam pfvf->flow_cfg->nr_flows++;
1088fa5e0ccbSRatheesh Kannoth set_bit(0, pfvf->flow_cfg->dmacflt_bmap);
108979d2be38SHariprasad Kelam
109079d2be38SHariprasad Kelam return 0;
109179d2be38SHariprasad Kelam }
109279d2be38SHariprasad Kelam
otx2_add_flow(struct otx2_nic * pfvf,struct ethtool_rxnfc * nfc)109381a43620SGeetha sowjanya int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
1094f0a1913fSSubbaraya Sundeep {
1095f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
109681a43620SGeetha sowjanya struct ethtool_rx_flow_spec *fsp = &nfc->fs;
1097f0a1913fSSubbaraya Sundeep struct otx2_flow *flow;
109879d2be38SHariprasad Kelam struct ethhdr *eth_hdr;
1099f0a1913fSSubbaraya Sundeep bool new = false;
110079d2be38SHariprasad Kelam int err = 0;
1101f174a0daSSuman Ghosh u64 vf_num;
110281a43620SGeetha sowjanya u32 ring;
1103f0a1913fSSubbaraya Sundeep
1104a515e5b5SSunil Goutham if (!flow_cfg->max_flows) {
1105a515e5b5SSunil Goutham netdev_err(pfvf->netdev,
1106a515e5b5SSunil Goutham "Ntuple rule count is 0, allocate and retry\n");
1107a515e5b5SSunil Goutham return -EINVAL;
1108a515e5b5SSunil Goutham }
1109a515e5b5SSunil Goutham
111081a43620SGeetha sowjanya ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
1111f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
1112f0a1913fSSubbaraya Sundeep return -ENOMEM;
1113f0a1913fSSubbaraya Sundeep
1114f174a0daSSuman Ghosh /* Number of queues on a VF can be greater or less than
1115f174a0daSSuman Ghosh * the PF's queue. Hence no need to check for the
1116f174a0daSSuman Ghosh * queue count. Hence no need to check queue count if PF
1117f174a0daSSuman Ghosh * is installing for its VF. Below is the expected vf_num value
1118f174a0daSSuman Ghosh * based on the ethtool commands.
1119f174a0daSSuman Ghosh *
1120f174a0daSSuman Ghosh * e.g.
1121f174a0daSSuman Ghosh * 1. ethtool -U <netdev> ... action -1 ==> vf_num:255
1122f174a0daSSuman Ghosh * 2. ethtool -U <netdev> ... action <queue_num> ==> vf_num:0
1123f174a0daSSuman Ghosh * 3. ethtool -U <netdev> ... vf <vf_idx> queue <queue_num> ==>
1124f174a0daSSuman Ghosh * vf_num:vf_idx+1
1125f174a0daSSuman Ghosh */
1126f174a0daSSuman Ghosh vf_num = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
1127f174a0daSSuman Ghosh if (!is_otx2_vf(pfvf->pcifunc) && !vf_num &&
1128f174a0daSSuman Ghosh ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC)
1129f0a1913fSSubbaraya Sundeep return -EINVAL;
1130f0a1913fSSubbaraya Sundeep
113179d2be38SHariprasad Kelam if (fsp->location >= otx2_get_maxflows(flow_cfg))
1132f0a1913fSSubbaraya Sundeep return -EINVAL;
1133f0a1913fSSubbaraya Sundeep
1134f0a1913fSSubbaraya Sundeep flow = otx2_find_flow(pfvf, fsp->location);
1135f0a1913fSSubbaraya Sundeep if (!flow) {
113679d2be38SHariprasad Kelam flow = kzalloc(sizeof(*flow), GFP_KERNEL);
1137f0a1913fSSubbaraya Sundeep if (!flow)
1138f0a1913fSSubbaraya Sundeep return -ENOMEM;
1139f0a1913fSSubbaraya Sundeep flow->location = fsp->location;
1140dce677daSSubbaraya Sundeep flow->entry = flow_cfg->flow_ent[flow->location];
1141f0a1913fSSubbaraya Sundeep new = true;
1142f0a1913fSSubbaraya Sundeep }
1143f0a1913fSSubbaraya Sundeep /* struct copy */
1144f0a1913fSSubbaraya Sundeep flow->flow_spec = *fsp;
1145f0a1913fSSubbaraya Sundeep
114681a43620SGeetha sowjanya if (fsp->flow_type & FLOW_RSS)
114781a43620SGeetha sowjanya flow->rss_ctx_id = nfc->rss_context;
114881a43620SGeetha sowjanya
114979d2be38SHariprasad Kelam if (otx2_is_flow_rule_dmacfilter(pfvf, &flow->flow_spec)) {
115079d2be38SHariprasad Kelam eth_hdr = &flow->flow_spec.h_u.ether_spec;
115179d2be38SHariprasad Kelam
115279d2be38SHariprasad Kelam /* Sync dmac filter table with updated fields */
11538e675581SHariprasad Kelam if (flow->rule_type & DMAC_FILTER_RULE)
115479d2be38SHariprasad Kelam return otx2_dmacflt_update(pfvf, eth_hdr->h_dest,
115579d2be38SHariprasad Kelam flow->entry);
115679d2be38SHariprasad Kelam
1157fa5e0ccbSRatheesh Kannoth if (bitmap_full(flow_cfg->dmacflt_bmap,
115879d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows)) {
115979d2be38SHariprasad Kelam netdev_warn(pfvf->netdev,
116079d2be38SHariprasad Kelam "Can't insert the rule %d as max allowed dmac filters are %d\n",
116179d2be38SHariprasad Kelam flow->location +
116279d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows,
116379d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows);
116479d2be38SHariprasad Kelam err = -EINVAL;
116579d2be38SHariprasad Kelam if (new)
116679d2be38SHariprasad Kelam kfree(flow);
116779d2be38SHariprasad Kelam return err;
116879d2be38SHariprasad Kelam }
116979d2be38SHariprasad Kelam
117079d2be38SHariprasad Kelam /* Install PF mac address to DMAC filter list */
1171fa5e0ccbSRatheesh Kannoth if (!test_bit(0, flow_cfg->dmacflt_bmap))
117279d2be38SHariprasad Kelam otx2_add_flow_with_pfmac(pfvf, flow);
117379d2be38SHariprasad Kelam
11748e675581SHariprasad Kelam flow->rule_type |= DMAC_FILTER_RULE;
1175fa5e0ccbSRatheesh Kannoth flow->entry = find_first_zero_bit(flow_cfg->dmacflt_bmap,
117679d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows);
11772e2a8126SSunil Goutham fsp->location = flow_cfg->max_flows + flow->entry;
117879d2be38SHariprasad Kelam flow->flow_spec.location = fsp->location;
117979d2be38SHariprasad Kelam flow->location = fsp->location;
118079d2be38SHariprasad Kelam
1181fa5e0ccbSRatheesh Kannoth set_bit(flow->entry, flow_cfg->dmacflt_bmap);
118279d2be38SHariprasad Kelam otx2_dmacflt_add(pfvf, eth_hdr->h_dest, flow->entry);
118379d2be38SHariprasad Kelam
118479d2be38SHariprasad Kelam } else {
11852e2a8126SSunil Goutham if (flow->location >= pfvf->flow_cfg->max_flows) {
118679d2be38SHariprasad Kelam netdev_warn(pfvf->netdev,
118779d2be38SHariprasad Kelam "Can't insert non dmac ntuple rule at %d, allowed range %d-0\n",
118879d2be38SHariprasad Kelam flow->location,
11892e2a8126SSunil Goutham flow_cfg->max_flows - 1);
119079d2be38SHariprasad Kelam err = -EINVAL;
119179d2be38SHariprasad Kelam } else {
1192f0a1913fSSubbaraya Sundeep err = otx2_add_flow_msg(pfvf, flow);
119379d2be38SHariprasad Kelam }
119479d2be38SHariprasad Kelam }
119579d2be38SHariprasad Kelam
1196f0a1913fSSubbaraya Sundeep if (err) {
11973cffaed2SRakesh Babu if (err == MBOX_MSG_INVALID)
11983cffaed2SRakesh Babu err = -EINVAL;
1199f0a1913fSSubbaraya Sundeep if (new)
1200f0a1913fSSubbaraya Sundeep kfree(flow);
1201f0a1913fSSubbaraya Sundeep return err;
1202f0a1913fSSubbaraya Sundeep }
1203f0a1913fSSubbaraya Sundeep
1204f0a1913fSSubbaraya Sundeep /* add the new flow installed to list */
1205f0a1913fSSubbaraya Sundeep if (new) {
1206f0a1913fSSubbaraya Sundeep otx2_add_flow_to_list(pfvf, flow);
1207f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows++;
1208f0a1913fSSubbaraya Sundeep }
1209f0a1913fSSubbaraya Sundeep
1210f174a0daSSuman Ghosh if (flow->is_vf)
1211f174a0daSSuman Ghosh netdev_info(pfvf->netdev,
1212f174a0daSSuman Ghosh "Make sure that VF's queue number is within its queue limit\n");
1213f0a1913fSSubbaraya Sundeep return 0;
1214f0a1913fSSubbaraya Sundeep }
1215f0a1913fSSubbaraya Sundeep
otx2_remove_flow_msg(struct otx2_nic * pfvf,u16 entry,bool all)1216f0a1913fSSubbaraya Sundeep static int otx2_remove_flow_msg(struct otx2_nic *pfvf, u16 entry, bool all)
1217f0a1913fSSubbaraya Sundeep {
1218f0a1913fSSubbaraya Sundeep struct npc_delete_flow_req *req;
1219f0a1913fSSubbaraya Sundeep int err;
1220f0a1913fSSubbaraya Sundeep
1221f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
1222f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1223f0a1913fSSubbaraya Sundeep if (!req) {
1224f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1225f0a1913fSSubbaraya Sundeep return -ENOMEM;
1226f0a1913fSSubbaraya Sundeep }
1227f0a1913fSSubbaraya Sundeep
1228f0a1913fSSubbaraya Sundeep req->entry = entry;
1229f0a1913fSSubbaraya Sundeep if (all)
1230f0a1913fSSubbaraya Sundeep req->all = 1;
1231f0a1913fSSubbaraya Sundeep
1232f0a1913fSSubbaraya Sundeep /* Send message to AF */
1233f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox);
1234f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1235f0a1913fSSubbaraya Sundeep return err;
1236f0a1913fSSubbaraya Sundeep }
1237f0a1913fSSubbaraya Sundeep
otx2_update_rem_pfmac(struct otx2_nic * pfvf,int req)123879d2be38SHariprasad Kelam static void otx2_update_rem_pfmac(struct otx2_nic *pfvf, int req)
123979d2be38SHariprasad Kelam {
124079d2be38SHariprasad Kelam struct otx2_flow *iter;
124179d2be38SHariprasad Kelam struct ethhdr *eth_hdr;
124279d2be38SHariprasad Kelam bool found = false;
124379d2be38SHariprasad Kelam
124479d2be38SHariprasad Kelam list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
12458e675581SHariprasad Kelam if ((iter->rule_type & DMAC_FILTER_RULE) && iter->entry == 0) {
124679d2be38SHariprasad Kelam eth_hdr = &iter->flow_spec.h_u.ether_spec;
124779d2be38SHariprasad Kelam if (req == DMAC_ADDR_DEL) {
124879d2be38SHariprasad Kelam otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
124979d2be38SHariprasad Kelam 0);
1250fa5e0ccbSRatheesh Kannoth clear_bit(0, pfvf->flow_cfg->dmacflt_bmap);
125179d2be38SHariprasad Kelam found = true;
125279d2be38SHariprasad Kelam } else {
125379d2be38SHariprasad Kelam ether_addr_copy(eth_hdr->h_dest,
125479d2be38SHariprasad Kelam pfvf->netdev->dev_addr);
1255fa5e0ccbSRatheesh Kannoth
125679d2be38SHariprasad Kelam otx2_dmacflt_update(pfvf, eth_hdr->h_dest, 0);
125779d2be38SHariprasad Kelam }
125879d2be38SHariprasad Kelam break;
125979d2be38SHariprasad Kelam }
126079d2be38SHariprasad Kelam }
126179d2be38SHariprasad Kelam
126279d2be38SHariprasad Kelam if (found) {
126379d2be38SHariprasad Kelam list_del(&iter->list);
126479d2be38SHariprasad Kelam kfree(iter);
126579d2be38SHariprasad Kelam pfvf->flow_cfg->nr_flows--;
126679d2be38SHariprasad Kelam }
126779d2be38SHariprasad Kelam }
126879d2be38SHariprasad Kelam
otx2_remove_flow(struct otx2_nic * pfvf,u32 location)1269f0a1913fSSubbaraya Sundeep int otx2_remove_flow(struct otx2_nic *pfvf, u32 location)
1270f0a1913fSSubbaraya Sundeep {
1271f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1272f0a1913fSSubbaraya Sundeep struct otx2_flow *flow;
1273f0a1913fSSubbaraya Sundeep int err;
1274f0a1913fSSubbaraya Sundeep
127579d2be38SHariprasad Kelam if (location >= otx2_get_maxflows(flow_cfg))
1276f0a1913fSSubbaraya Sundeep return -EINVAL;
1277f0a1913fSSubbaraya Sundeep
1278f0a1913fSSubbaraya Sundeep flow = otx2_find_flow(pfvf, location);
1279f0a1913fSSubbaraya Sundeep if (!flow)
1280f0a1913fSSubbaraya Sundeep return -ENOENT;
1281f0a1913fSSubbaraya Sundeep
12828e675581SHariprasad Kelam if (flow->rule_type & DMAC_FILTER_RULE) {
128379d2be38SHariprasad Kelam struct ethhdr *eth_hdr = &flow->flow_spec.h_u.ether_spec;
128479d2be38SHariprasad Kelam
128579d2be38SHariprasad Kelam /* user not allowed to remove dmac filter with interface mac */
128679d2be38SHariprasad Kelam if (ether_addr_equal(pfvf->netdev->dev_addr, eth_hdr->h_dest))
128779d2be38SHariprasad Kelam return -EPERM;
128879d2be38SHariprasad Kelam
128979d2be38SHariprasad Kelam err = otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
129079d2be38SHariprasad Kelam flow->entry);
1291fa5e0ccbSRatheesh Kannoth clear_bit(flow->entry, flow_cfg->dmacflt_bmap);
129279d2be38SHariprasad Kelam /* If all dmac filters are removed delete macfilter with
129379d2be38SHariprasad Kelam * interface mac address and configure CGX/RPM block in
129479d2be38SHariprasad Kelam * promiscuous mode
129579d2be38SHariprasad Kelam */
1296fa5e0ccbSRatheesh Kannoth if (bitmap_weight(flow_cfg->dmacflt_bmap,
129779d2be38SHariprasad Kelam flow_cfg->dmacflt_max_flows) == 1)
129879d2be38SHariprasad Kelam otx2_update_rem_pfmac(pfvf, DMAC_ADDR_DEL);
129979d2be38SHariprasad Kelam } else {
13008e675581SHariprasad Kelam #ifdef CONFIG_DCB
13018e675581SHariprasad Kelam if (flow->rule_type & PFC_FLOWCTRL_RULE)
13028e675581SHariprasad Kelam otx2_update_bpid_in_rqctx(pfvf, 0,
13038e675581SHariprasad Kelam flow->flow_spec.ring_cookie,
13048e675581SHariprasad Kelam false);
13058e675581SHariprasad Kelam #endif
13068e675581SHariprasad Kelam
1307f0a1913fSSubbaraya Sundeep err = otx2_remove_flow_msg(pfvf, flow->entry, false);
130879d2be38SHariprasad Kelam }
130979d2be38SHariprasad Kelam
1310f0a1913fSSubbaraya Sundeep if (err)
1311f0a1913fSSubbaraya Sundeep return err;
1312f0a1913fSSubbaraya Sundeep
1313f0a1913fSSubbaraya Sundeep list_del(&flow->list);
1314f0a1913fSSubbaraya Sundeep kfree(flow);
1315f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--;
1316f0a1913fSSubbaraya Sundeep
1317f0a1913fSSubbaraya Sundeep return 0;
1318f0a1913fSSubbaraya Sundeep }
1319f0a1913fSSubbaraya Sundeep
otx2_rss_ctx_flow_del(struct otx2_nic * pfvf,int ctx_id)132081a43620SGeetha sowjanya void otx2_rss_ctx_flow_del(struct otx2_nic *pfvf, int ctx_id)
132181a43620SGeetha sowjanya {
132281a43620SGeetha sowjanya struct otx2_flow *flow, *tmp;
132381a43620SGeetha sowjanya int err;
132481a43620SGeetha sowjanya
132581a43620SGeetha sowjanya list_for_each_entry_safe(flow, tmp, &pfvf->flow_cfg->flow_list, list) {
132681a43620SGeetha sowjanya if (flow->rss_ctx_id != ctx_id)
132781a43620SGeetha sowjanya continue;
132881a43620SGeetha sowjanya err = otx2_remove_flow(pfvf, flow->location);
132981a43620SGeetha sowjanya if (err)
133081a43620SGeetha sowjanya netdev_warn(pfvf->netdev,
133181a43620SGeetha sowjanya "Can't delete the rule %d associated with this rss group err:%d",
133281a43620SGeetha sowjanya flow->location, err);
133381a43620SGeetha sowjanya }
133481a43620SGeetha sowjanya }
133581a43620SGeetha sowjanya
otx2_destroy_ntuple_flows(struct otx2_nic * pfvf)1336f0a1913fSSubbaraya Sundeep int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf)
1337f0a1913fSSubbaraya Sundeep {
1338f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1339f0a1913fSSubbaraya Sundeep struct npc_delete_flow_req *req;
1340f0a1913fSSubbaraya Sundeep struct otx2_flow *iter, *tmp;
1341f0a1913fSSubbaraya Sundeep int err;
1342f0a1913fSSubbaraya Sundeep
1343f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
1344f0a1913fSSubbaraya Sundeep return 0;
1345f0a1913fSSubbaraya Sundeep
1346a515e5b5SSunil Goutham if (!flow_cfg->max_flows)
1347a515e5b5SSunil Goutham return 0;
1348a515e5b5SSunil Goutham
1349f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
1350f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1351f0a1913fSSubbaraya Sundeep if (!req) {
1352f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1353f0a1913fSSubbaraya Sundeep return -ENOMEM;
1354f0a1913fSSubbaraya Sundeep }
1355f0a1913fSSubbaraya Sundeep
13569917060fSSunil Goutham req->start = flow_cfg->flow_ent[0];
13572e2a8126SSunil Goutham req->end = flow_cfg->flow_ent[flow_cfg->max_flows - 1];
1358f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox);
1359f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1360f0a1913fSSubbaraya Sundeep
1361f0a1913fSSubbaraya Sundeep list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) {
1362f0a1913fSSubbaraya Sundeep list_del(&iter->list);
1363f0a1913fSSubbaraya Sundeep kfree(iter);
1364f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--;
1365f0a1913fSSubbaraya Sundeep }
1366f0a1913fSSubbaraya Sundeep return err;
1367f0a1913fSSubbaraya Sundeep }
1368f0a1913fSSubbaraya Sundeep
otx2_destroy_mcam_flows(struct otx2_nic * pfvf)1369f0a1913fSSubbaraya Sundeep int otx2_destroy_mcam_flows(struct otx2_nic *pfvf)
1370f0a1913fSSubbaraya Sundeep {
1371f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1372f0a1913fSSubbaraya Sundeep struct npc_mcam_free_entry_req *req;
1373f0a1913fSSubbaraya Sundeep struct otx2_flow *iter, *tmp;
1374f0a1913fSSubbaraya Sundeep int err;
1375f0a1913fSSubbaraya Sundeep
1376f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
1377f0a1913fSSubbaraya Sundeep return 0;
1378f0a1913fSSubbaraya Sundeep
1379f0a1913fSSubbaraya Sundeep /* remove all flows */
1380f0a1913fSSubbaraya Sundeep err = otx2_remove_flow_msg(pfvf, 0, true);
1381f0a1913fSSubbaraya Sundeep if (err)
1382f0a1913fSSubbaraya Sundeep return err;
1383f0a1913fSSubbaraya Sundeep
1384f0a1913fSSubbaraya Sundeep list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) {
1385f0a1913fSSubbaraya Sundeep list_del(&iter->list);
1386f0a1913fSSubbaraya Sundeep kfree(iter);
1387f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--;
1388f0a1913fSSubbaraya Sundeep }
1389f0a1913fSSubbaraya Sundeep
1390f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock);
1391f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_mcam_free_entry(&pfvf->mbox);
1392f0a1913fSSubbaraya Sundeep if (!req) {
1393f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1394f0a1913fSSubbaraya Sundeep return -ENOMEM;
1395f0a1913fSSubbaraya Sundeep }
1396f0a1913fSSubbaraya Sundeep
1397f0a1913fSSubbaraya Sundeep req->all = 1;
1398f0a1913fSSubbaraya Sundeep /* Send message to AF to free MCAM entries */
1399f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox);
1400f0a1913fSSubbaraya Sundeep if (err) {
1401f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1402f0a1913fSSubbaraya Sundeep return err;
1403f0a1913fSSubbaraya Sundeep }
1404f0a1913fSSubbaraya Sundeep
1405f0a1913fSSubbaraya Sundeep pfvf->flags &= ~OTX2_FLAG_MCAM_ENTRIES_ALLOC;
1406f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock);
1407f0a1913fSSubbaraya Sundeep
1408f0a1913fSSubbaraya Sundeep return 0;
1409f0a1913fSSubbaraya Sundeep }
1410fd9d7859SHariprasad Kelam
otx2_install_rxvlan_offload_flow(struct otx2_nic * pfvf)1411fd9d7859SHariprasad Kelam int otx2_install_rxvlan_offload_flow(struct otx2_nic *pfvf)
1412fd9d7859SHariprasad Kelam {
1413fd9d7859SHariprasad Kelam struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1414fd9d7859SHariprasad Kelam struct npc_install_flow_req *req;
1415fd9d7859SHariprasad Kelam int err;
1416fd9d7859SHariprasad Kelam
1417fd9d7859SHariprasad Kelam mutex_lock(&pfvf->mbox.lock);
1418fd9d7859SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
1419fd9d7859SHariprasad Kelam if (!req) {
1420fd9d7859SHariprasad Kelam mutex_unlock(&pfvf->mbox.lock);
1421fd9d7859SHariprasad Kelam return -ENOMEM;
1422fd9d7859SHariprasad Kelam }
1423fd9d7859SHariprasad Kelam
14249917060fSSunil Goutham req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
1425fd9d7859SHariprasad Kelam req->intf = NIX_INTF_RX;
1426fd9d7859SHariprasad Kelam ether_addr_copy(req->packet.dmac, pfvf->netdev->dev_addr);
1427fd9d7859SHariprasad Kelam eth_broadcast_addr((u8 *)&req->mask.dmac);
1428fd9d7859SHariprasad Kelam req->channel = pfvf->hw.rx_chan_base;
1429fd9d7859SHariprasad Kelam req->op = NIX_RX_ACTION_DEFAULT;
1430fd9d7859SHariprasad Kelam req->features = BIT_ULL(NPC_OUTER_VID) | BIT_ULL(NPC_DMAC);
1431fd9d7859SHariprasad Kelam req->vtag0_valid = true;
1432fd9d7859SHariprasad Kelam req->vtag0_type = NIX_AF_LFX_RX_VTAG_TYPE0;
1433fd9d7859SHariprasad Kelam
1434fd9d7859SHariprasad Kelam /* Send message to AF */
1435fd9d7859SHariprasad Kelam err = otx2_sync_mbox_msg(&pfvf->mbox);
1436fd9d7859SHariprasad Kelam mutex_unlock(&pfvf->mbox.lock);
1437fd9d7859SHariprasad Kelam return err;
1438fd9d7859SHariprasad Kelam }
1439fd9d7859SHariprasad Kelam
otx2_delete_rxvlan_offload_flow(struct otx2_nic * pfvf)1440fd9d7859SHariprasad Kelam static int otx2_delete_rxvlan_offload_flow(struct otx2_nic *pfvf)
1441fd9d7859SHariprasad Kelam {
1442fd9d7859SHariprasad Kelam struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
1443fd9d7859SHariprasad Kelam struct npc_delete_flow_req *req;
1444fd9d7859SHariprasad Kelam int err;
1445fd9d7859SHariprasad Kelam
1446fd9d7859SHariprasad Kelam mutex_lock(&pfvf->mbox.lock);
1447fd9d7859SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox);
1448fd9d7859SHariprasad Kelam if (!req) {
1449fd9d7859SHariprasad Kelam mutex_unlock(&pfvf->mbox.lock);
1450fd9d7859SHariprasad Kelam return -ENOMEM;
1451fd9d7859SHariprasad Kelam }
1452fd9d7859SHariprasad Kelam
14539917060fSSunil Goutham req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
1454fd9d7859SHariprasad Kelam /* Send message to AF */
1455fd9d7859SHariprasad Kelam err = otx2_sync_mbox_msg(&pfvf->mbox);
1456fd9d7859SHariprasad Kelam mutex_unlock(&pfvf->mbox.lock);
1457fd9d7859SHariprasad Kelam return err;
1458fd9d7859SHariprasad Kelam }
1459fd9d7859SHariprasad Kelam
otx2_enable_rxvlan(struct otx2_nic * pf,bool enable)1460fd9d7859SHariprasad Kelam int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable)
1461fd9d7859SHariprasad Kelam {
1462fd9d7859SHariprasad Kelam struct nix_vtag_config *req;
1463fd9d7859SHariprasad Kelam struct mbox_msghdr *rsp_hdr;
1464fd9d7859SHariprasad Kelam int err;
1465fd9d7859SHariprasad Kelam
1466fd9d7859SHariprasad Kelam /* Dont have enough mcam entries */
1467fd9d7859SHariprasad Kelam if (!(pf->flags & OTX2_FLAG_RX_VLAN_SUPPORT))
1468fd9d7859SHariprasad Kelam return -ENOMEM;
1469fd9d7859SHariprasad Kelam
1470fd9d7859SHariprasad Kelam if (enable) {
1471fd9d7859SHariprasad Kelam err = otx2_install_rxvlan_offload_flow(pf);
1472fd9d7859SHariprasad Kelam if (err)
1473fd9d7859SHariprasad Kelam return err;
1474fd9d7859SHariprasad Kelam } else {
1475fd9d7859SHariprasad Kelam err = otx2_delete_rxvlan_offload_flow(pf);
1476fd9d7859SHariprasad Kelam if (err)
1477fd9d7859SHariprasad Kelam return err;
1478fd9d7859SHariprasad Kelam }
1479fd9d7859SHariprasad Kelam
1480fd9d7859SHariprasad Kelam mutex_lock(&pf->mbox.lock);
1481fd9d7859SHariprasad Kelam req = otx2_mbox_alloc_msg_nix_vtag_cfg(&pf->mbox);
1482fd9d7859SHariprasad Kelam if (!req) {
1483fd9d7859SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
1484fd9d7859SHariprasad Kelam return -ENOMEM;
1485fd9d7859SHariprasad Kelam }
1486fd9d7859SHariprasad Kelam
1487fd9d7859SHariprasad Kelam /* config strip, capture and size */
1488fd9d7859SHariprasad Kelam req->vtag_size = VTAGSIZE_T4;
1489fd9d7859SHariprasad Kelam req->cfg_type = 1; /* rx vlan cfg */
1490fd9d7859SHariprasad Kelam req->rx.vtag_type = NIX_AF_LFX_RX_VTAG_TYPE0;
1491fd9d7859SHariprasad Kelam req->rx.strip_vtag = enable;
1492fd9d7859SHariprasad Kelam req->rx.capture_vtag = enable;
1493fd9d7859SHariprasad Kelam
1494fd9d7859SHariprasad Kelam err = otx2_sync_mbox_msg(&pf->mbox);
1495fd9d7859SHariprasad Kelam if (err) {
1496fd9d7859SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
1497fd9d7859SHariprasad Kelam return err;
1498fd9d7859SHariprasad Kelam }
1499fd9d7859SHariprasad Kelam
1500fd9d7859SHariprasad Kelam rsp_hdr = otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr);
1501fd9d7859SHariprasad Kelam if (IS_ERR(rsp_hdr)) {
1502fd9d7859SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
1503fd9d7859SHariprasad Kelam return PTR_ERR(rsp_hdr);
1504fd9d7859SHariprasad Kelam }
1505fd9d7859SHariprasad Kelam
1506fd9d7859SHariprasad Kelam mutex_unlock(&pf->mbox.lock);
1507fd9d7859SHariprasad Kelam return rsp_hdr->rc;
1508fd9d7859SHariprasad Kelam }
150979d2be38SHariprasad Kelam
otx2_dmacflt_reinstall_flows(struct otx2_nic * pf)151079d2be38SHariprasad Kelam void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf)
151179d2be38SHariprasad Kelam {
151279d2be38SHariprasad Kelam struct otx2_flow *iter;
151379d2be38SHariprasad Kelam struct ethhdr *eth_hdr;
151479d2be38SHariprasad Kelam
151579d2be38SHariprasad Kelam list_for_each_entry(iter, &pf->flow_cfg->flow_list, list) {
15168e675581SHariprasad Kelam if (iter->rule_type & DMAC_FILTER_RULE) {
151779d2be38SHariprasad Kelam eth_hdr = &iter->flow_spec.h_u.ether_spec;
151879d2be38SHariprasad Kelam otx2_dmacflt_add(pf, eth_hdr->h_dest,
151979d2be38SHariprasad Kelam iter->entry);
152079d2be38SHariprasad Kelam }
152179d2be38SHariprasad Kelam }
152279d2be38SHariprasad Kelam }
152379d2be38SHariprasad Kelam
otx2_dmacflt_update_pfmac_flow(struct otx2_nic * pfvf)152479d2be38SHariprasad Kelam void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf)
152579d2be38SHariprasad Kelam {
152679d2be38SHariprasad Kelam otx2_update_rem_pfmac(pfvf, DMAC_ADDR_UPDATE);
152779d2be38SHariprasad Kelam }
1528