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