1f0a1913fSSubbaraya Sundeep // SPDX-License-Identifier: GPL-2.0 2f0a1913fSSubbaraya Sundeep /* Marvell OcteonTx2 RVU Physcial Function ethernet driver 3f0a1913fSSubbaraya Sundeep * 4f0a1913fSSubbaraya Sundeep * Copyright (C) 2020 Marvell. 5f0a1913fSSubbaraya Sundeep */ 6f0a1913fSSubbaraya Sundeep 7f0a1913fSSubbaraya Sundeep #include <net/ipv6.h> 8f0a1913fSSubbaraya Sundeep 9f0a1913fSSubbaraya Sundeep #include "otx2_common.h" 10f0a1913fSSubbaraya Sundeep 11f0a1913fSSubbaraya Sundeep #define OTX2_DEFAULT_ACTION 0x1 12f0a1913fSSubbaraya Sundeep 13f0a1913fSSubbaraya Sundeep struct otx2_flow { 14f0a1913fSSubbaraya Sundeep struct ethtool_rx_flow_spec flow_spec; 15f0a1913fSSubbaraya Sundeep struct list_head list; 16f0a1913fSSubbaraya Sundeep u32 location; 17f0a1913fSSubbaraya Sundeep u16 entry; 18f0a1913fSSubbaraya Sundeep bool is_vf; 19f0a1913fSSubbaraya Sundeep int vf; 20f0a1913fSSubbaraya Sundeep }; 21f0a1913fSSubbaraya Sundeep 22f0a1913fSSubbaraya Sundeep int otx2_alloc_mcam_entries(struct otx2_nic *pfvf) 23f0a1913fSSubbaraya Sundeep { 24f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; 25f0a1913fSSubbaraya Sundeep struct npc_mcam_alloc_entry_req *req; 26f0a1913fSSubbaraya Sundeep struct npc_mcam_alloc_entry_rsp *rsp; 27f0a1913fSSubbaraya Sundeep int i; 28f0a1913fSSubbaraya Sundeep 29f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock); 30f0a1913fSSubbaraya Sundeep 31f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&pfvf->mbox); 32f0a1913fSSubbaraya Sundeep if (!req) { 33f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 34f0a1913fSSubbaraya Sundeep return -ENOMEM; 35f0a1913fSSubbaraya Sundeep } 36f0a1913fSSubbaraya Sundeep 37f0a1913fSSubbaraya Sundeep req->contig = false; 38f0a1913fSSubbaraya Sundeep req->count = OTX2_MCAM_COUNT; 39f0a1913fSSubbaraya Sundeep 40f0a1913fSSubbaraya Sundeep /* Send message to AF */ 41f0a1913fSSubbaraya Sundeep if (otx2_sync_mbox_msg(&pfvf->mbox)) { 42f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 43f0a1913fSSubbaraya Sundeep return -EINVAL; 44f0a1913fSSubbaraya Sundeep } 45f0a1913fSSubbaraya Sundeep 46f0a1913fSSubbaraya Sundeep rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp 47f0a1913fSSubbaraya Sundeep (&pfvf->mbox.mbox, 0, &req->hdr); 48f0a1913fSSubbaraya Sundeep 49*63ee5157SHariprasad Kelam if (rsp->count != req->count) { 50f0a1913fSSubbaraya Sundeep netdev_info(pfvf->netdev, 51f0a1913fSSubbaraya Sundeep "Unable to allocate %d MCAM entries, got %d\n", 52f0a1913fSSubbaraya Sundeep req->count, rsp->count); 53*63ee5157SHariprasad Kelam /* support only ntuples here */ 54f0a1913fSSubbaraya Sundeep flow_cfg->ntuple_max_flows = rsp->count; 55f0a1913fSSubbaraya Sundeep flow_cfg->ntuple_offset = 0; 56f0a1913fSSubbaraya Sundeep pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT; 57*63ee5157SHariprasad Kelam } else { 58*63ee5157SHariprasad Kelam flow_cfg->ntuple_offset = 0; 59*63ee5157SHariprasad Kelam flow_cfg->unicast_offset = flow_cfg->ntuple_offset + 60*63ee5157SHariprasad Kelam OTX2_MAX_NTUPLE_FLOWS; 61*63ee5157SHariprasad Kelam pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT; 62*63ee5157SHariprasad Kelam pfvf->flags |= OTX2_FLAG_UCAST_FLTR_SUPPORT; 63*63ee5157SHariprasad Kelam } 64f0a1913fSSubbaraya Sundeep 65f0a1913fSSubbaraya Sundeep for (i = 0; i < rsp->count; i++) 66f0a1913fSSubbaraya Sundeep flow_cfg->entry[i] = rsp->entry_list[i]; 67f0a1913fSSubbaraya Sundeep 68f0a1913fSSubbaraya Sundeep pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC; 69f0a1913fSSubbaraya Sundeep 70f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 71f0a1913fSSubbaraya Sundeep 72f0a1913fSSubbaraya Sundeep return 0; 73f0a1913fSSubbaraya Sundeep } 74f0a1913fSSubbaraya Sundeep 75f0a1913fSSubbaraya Sundeep int otx2_mcam_flow_init(struct otx2_nic *pf) 76f0a1913fSSubbaraya Sundeep { 77f0a1913fSSubbaraya Sundeep int err; 78f0a1913fSSubbaraya Sundeep 79f0a1913fSSubbaraya Sundeep pf->flow_cfg = devm_kzalloc(pf->dev, sizeof(struct otx2_flow_config), 80f0a1913fSSubbaraya Sundeep GFP_KERNEL); 81f0a1913fSSubbaraya Sundeep if (!pf->flow_cfg) 82f0a1913fSSubbaraya Sundeep return -ENOMEM; 83f0a1913fSSubbaraya Sundeep 84f0a1913fSSubbaraya Sundeep INIT_LIST_HEAD(&pf->flow_cfg->flow_list); 85f0a1913fSSubbaraya Sundeep 86f0a1913fSSubbaraya Sundeep pf->flow_cfg->ntuple_max_flows = OTX2_MAX_NTUPLE_FLOWS; 87f0a1913fSSubbaraya Sundeep 88f0a1913fSSubbaraya Sundeep err = otx2_alloc_mcam_entries(pf); 89f0a1913fSSubbaraya Sundeep if (err) 90f0a1913fSSubbaraya Sundeep return err; 91f0a1913fSSubbaraya Sundeep 92*63ee5157SHariprasad Kelam pf->mac_table = devm_kzalloc(pf->dev, sizeof(struct otx2_mac_table) 93*63ee5157SHariprasad Kelam * OTX2_MAX_UNICAST_FLOWS, GFP_KERNEL); 94*63ee5157SHariprasad Kelam if (!pf->mac_table) 95*63ee5157SHariprasad Kelam return -ENOMEM; 96*63ee5157SHariprasad Kelam 97f0a1913fSSubbaraya Sundeep return 0; 98f0a1913fSSubbaraya Sundeep } 99f0a1913fSSubbaraya Sundeep 100f0a1913fSSubbaraya Sundeep void otx2_mcam_flow_del(struct otx2_nic *pf) 101f0a1913fSSubbaraya Sundeep { 102f0a1913fSSubbaraya Sundeep otx2_destroy_mcam_flows(pf); 103f0a1913fSSubbaraya Sundeep } 104f0a1913fSSubbaraya Sundeep 105*63ee5157SHariprasad Kelam /* On success adds mcam entry 106*63ee5157SHariprasad Kelam * On failure enable promisous mode 107*63ee5157SHariprasad Kelam */ 108*63ee5157SHariprasad Kelam static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac) 109*63ee5157SHariprasad Kelam { 110*63ee5157SHariprasad Kelam struct otx2_flow_config *flow_cfg = pf->flow_cfg; 111*63ee5157SHariprasad Kelam struct npc_install_flow_req *req; 112*63ee5157SHariprasad Kelam int err, i; 113*63ee5157SHariprasad Kelam 114*63ee5157SHariprasad Kelam if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT)) 115*63ee5157SHariprasad Kelam return -ENOMEM; 116*63ee5157SHariprasad Kelam 117*63ee5157SHariprasad Kelam /* dont have free mcam entries or uc list is greater than alloted */ 118*63ee5157SHariprasad Kelam if (netdev_uc_count(pf->netdev) > OTX2_MAX_UNICAST_FLOWS) 119*63ee5157SHariprasad Kelam return -ENOMEM; 120*63ee5157SHariprasad Kelam 121*63ee5157SHariprasad Kelam mutex_lock(&pf->mbox.lock); 122*63ee5157SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_install_flow(&pf->mbox); 123*63ee5157SHariprasad Kelam if (!req) { 124*63ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock); 125*63ee5157SHariprasad Kelam return -ENOMEM; 126*63ee5157SHariprasad Kelam } 127*63ee5157SHariprasad Kelam 128*63ee5157SHariprasad Kelam /* unicast offset starts with 32 0..31 for ntuple */ 129*63ee5157SHariprasad Kelam for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) { 130*63ee5157SHariprasad Kelam if (pf->mac_table[i].inuse) 131*63ee5157SHariprasad Kelam continue; 132*63ee5157SHariprasad Kelam ether_addr_copy(pf->mac_table[i].addr, mac); 133*63ee5157SHariprasad Kelam pf->mac_table[i].inuse = true; 134*63ee5157SHariprasad Kelam pf->mac_table[i].mcam_entry = 135*63ee5157SHariprasad Kelam flow_cfg->entry[i + flow_cfg->unicast_offset]; 136*63ee5157SHariprasad Kelam req->entry = pf->mac_table[i].mcam_entry; 137*63ee5157SHariprasad Kelam break; 138*63ee5157SHariprasad Kelam } 139*63ee5157SHariprasad Kelam 140*63ee5157SHariprasad Kelam ether_addr_copy(req->packet.dmac, mac); 141*63ee5157SHariprasad Kelam eth_broadcast_addr((u8 *)&req->mask.dmac); 142*63ee5157SHariprasad Kelam req->features = BIT_ULL(NPC_DMAC); 143*63ee5157SHariprasad Kelam req->channel = pf->hw.rx_chan_base; 144*63ee5157SHariprasad Kelam req->intf = NIX_INTF_RX; 145*63ee5157SHariprasad Kelam req->op = NIX_RX_ACTION_DEFAULT; 146*63ee5157SHariprasad Kelam req->set_cntr = 1; 147*63ee5157SHariprasad Kelam 148*63ee5157SHariprasad Kelam err = otx2_sync_mbox_msg(&pf->mbox); 149*63ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock); 150*63ee5157SHariprasad Kelam 151*63ee5157SHariprasad Kelam return err; 152*63ee5157SHariprasad Kelam } 153*63ee5157SHariprasad Kelam 154*63ee5157SHariprasad Kelam int otx2_add_macfilter(struct net_device *netdev, const u8 *mac) 155*63ee5157SHariprasad Kelam { 156*63ee5157SHariprasad Kelam struct otx2_nic *pf = netdev_priv(netdev); 157*63ee5157SHariprasad Kelam 158*63ee5157SHariprasad Kelam return otx2_do_add_macfilter(pf, mac); 159*63ee5157SHariprasad Kelam } 160*63ee5157SHariprasad Kelam 161*63ee5157SHariprasad Kelam static bool otx2_get_mcamentry_for_mac(struct otx2_nic *pf, const u8 *mac, 162*63ee5157SHariprasad Kelam int *mcam_entry) 163*63ee5157SHariprasad Kelam { 164*63ee5157SHariprasad Kelam int i; 165*63ee5157SHariprasad Kelam 166*63ee5157SHariprasad Kelam for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) { 167*63ee5157SHariprasad Kelam if (!pf->mac_table[i].inuse) 168*63ee5157SHariprasad Kelam continue; 169*63ee5157SHariprasad Kelam 170*63ee5157SHariprasad Kelam if (ether_addr_equal(pf->mac_table[i].addr, mac)) { 171*63ee5157SHariprasad Kelam *mcam_entry = pf->mac_table[i].mcam_entry; 172*63ee5157SHariprasad Kelam pf->mac_table[i].inuse = false; 173*63ee5157SHariprasad Kelam return true; 174*63ee5157SHariprasad Kelam } 175*63ee5157SHariprasad Kelam } 176*63ee5157SHariprasad Kelam return false; 177*63ee5157SHariprasad Kelam } 178*63ee5157SHariprasad Kelam 179*63ee5157SHariprasad Kelam int otx2_del_macfilter(struct net_device *netdev, const u8 *mac) 180*63ee5157SHariprasad Kelam { 181*63ee5157SHariprasad Kelam struct otx2_nic *pf = netdev_priv(netdev); 182*63ee5157SHariprasad Kelam struct npc_delete_flow_req *req; 183*63ee5157SHariprasad Kelam int err, mcam_entry; 184*63ee5157SHariprasad Kelam 185*63ee5157SHariprasad Kelam /* check does mcam entry exists for given mac */ 186*63ee5157SHariprasad Kelam if (!otx2_get_mcamentry_for_mac(pf, mac, &mcam_entry)) 187*63ee5157SHariprasad Kelam return 0; 188*63ee5157SHariprasad Kelam 189*63ee5157SHariprasad Kelam mutex_lock(&pf->mbox.lock); 190*63ee5157SHariprasad Kelam req = otx2_mbox_alloc_msg_npc_delete_flow(&pf->mbox); 191*63ee5157SHariprasad Kelam if (!req) { 192*63ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock); 193*63ee5157SHariprasad Kelam return -ENOMEM; 194*63ee5157SHariprasad Kelam } 195*63ee5157SHariprasad Kelam req->entry = mcam_entry; 196*63ee5157SHariprasad Kelam /* Send message to AF */ 197*63ee5157SHariprasad Kelam err = otx2_sync_mbox_msg(&pf->mbox); 198*63ee5157SHariprasad Kelam mutex_unlock(&pf->mbox.lock); 199*63ee5157SHariprasad Kelam 200*63ee5157SHariprasad Kelam return err; 201*63ee5157SHariprasad Kelam } 202*63ee5157SHariprasad Kelam 203f0a1913fSSubbaraya Sundeep static struct otx2_flow *otx2_find_flow(struct otx2_nic *pfvf, u32 location) 204f0a1913fSSubbaraya Sundeep { 205f0a1913fSSubbaraya Sundeep struct otx2_flow *iter; 206f0a1913fSSubbaraya Sundeep 207f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) { 208f0a1913fSSubbaraya Sundeep if (iter->location == location) 209f0a1913fSSubbaraya Sundeep return iter; 210f0a1913fSSubbaraya Sundeep } 211f0a1913fSSubbaraya Sundeep 212f0a1913fSSubbaraya Sundeep return NULL; 213f0a1913fSSubbaraya Sundeep } 214f0a1913fSSubbaraya Sundeep 215f0a1913fSSubbaraya Sundeep static void otx2_add_flow_to_list(struct otx2_nic *pfvf, struct otx2_flow *flow) 216f0a1913fSSubbaraya Sundeep { 217f0a1913fSSubbaraya Sundeep struct list_head *head = &pfvf->flow_cfg->flow_list; 218f0a1913fSSubbaraya Sundeep struct otx2_flow *iter; 219f0a1913fSSubbaraya Sundeep 220f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) { 221f0a1913fSSubbaraya Sundeep if (iter->location > flow->location) 222f0a1913fSSubbaraya Sundeep break; 223f0a1913fSSubbaraya Sundeep head = &iter->list; 224f0a1913fSSubbaraya Sundeep } 225f0a1913fSSubbaraya Sundeep 226f0a1913fSSubbaraya Sundeep list_add(&flow->list, head); 227f0a1913fSSubbaraya Sundeep } 228f0a1913fSSubbaraya Sundeep 229f0a1913fSSubbaraya Sundeep int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc, 230f0a1913fSSubbaraya Sundeep u32 location) 231f0a1913fSSubbaraya Sundeep { 232f0a1913fSSubbaraya Sundeep struct otx2_flow *iter; 233f0a1913fSSubbaraya Sundeep 234f0a1913fSSubbaraya Sundeep if (location >= pfvf->flow_cfg->ntuple_max_flows) 235f0a1913fSSubbaraya Sundeep return -EINVAL; 236f0a1913fSSubbaraya Sundeep 237f0a1913fSSubbaraya Sundeep list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) { 238f0a1913fSSubbaraya Sundeep if (iter->location == location) { 239f0a1913fSSubbaraya Sundeep nfc->fs = iter->flow_spec; 240f0a1913fSSubbaraya Sundeep return 0; 241f0a1913fSSubbaraya Sundeep } 242f0a1913fSSubbaraya Sundeep } 243f0a1913fSSubbaraya Sundeep 244f0a1913fSSubbaraya Sundeep return -ENOENT; 245f0a1913fSSubbaraya Sundeep } 246f0a1913fSSubbaraya Sundeep 247f0a1913fSSubbaraya Sundeep int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc, 248f0a1913fSSubbaraya Sundeep u32 *rule_locs) 249f0a1913fSSubbaraya Sundeep { 250f0a1913fSSubbaraya Sundeep u32 location = 0; 251f0a1913fSSubbaraya Sundeep int idx = 0; 252f0a1913fSSubbaraya Sundeep int err = 0; 253f0a1913fSSubbaraya Sundeep 254f0a1913fSSubbaraya Sundeep nfc->data = pfvf->flow_cfg->ntuple_max_flows; 255f0a1913fSSubbaraya Sundeep while ((!err || err == -ENOENT) && idx < nfc->rule_cnt) { 256f0a1913fSSubbaraya Sundeep err = otx2_get_flow(pfvf, nfc, location); 257f0a1913fSSubbaraya Sundeep if (!err) 258f0a1913fSSubbaraya Sundeep rule_locs[idx++] = location; 259f0a1913fSSubbaraya Sundeep location++; 260f0a1913fSSubbaraya Sundeep } 261f0a1913fSSubbaraya Sundeep 262f0a1913fSSubbaraya Sundeep return err; 263f0a1913fSSubbaraya Sundeep } 264f0a1913fSSubbaraya Sundeep 265f0a1913fSSubbaraya Sundeep static void otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp, 266f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req, 267f0a1913fSSubbaraya Sundeep u32 flow_type) 268f0a1913fSSubbaraya Sundeep { 269f0a1913fSSubbaraya Sundeep struct ethtool_usrip4_spec *ipv4_usr_mask = &fsp->m_u.usr_ip4_spec; 270f0a1913fSSubbaraya Sundeep struct ethtool_usrip4_spec *ipv4_usr_hdr = &fsp->h_u.usr_ip4_spec; 271f0a1913fSSubbaraya Sundeep struct ethtool_tcpip4_spec *ipv4_l4_mask = &fsp->m_u.tcp_ip4_spec; 272f0a1913fSSubbaraya Sundeep struct ethtool_tcpip4_spec *ipv4_l4_hdr = &fsp->h_u.tcp_ip4_spec; 273f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask; 274f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet; 275f0a1913fSSubbaraya Sundeep 276f0a1913fSSubbaraya Sundeep switch (flow_type) { 277f0a1913fSSubbaraya Sundeep case IP_USER_FLOW: 278f0a1913fSSubbaraya Sundeep if (ipv4_usr_mask->ip4src) { 279f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4src, &ipv4_usr_hdr->ip4src, 280f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4src)); 281f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4src, &ipv4_usr_mask->ip4src, 282f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4src)); 283f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV4); 284f0a1913fSSubbaraya Sundeep } 285f0a1913fSSubbaraya Sundeep if (ipv4_usr_mask->ip4dst) { 286f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4dst, &ipv4_usr_hdr->ip4dst, 287f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4dst)); 288f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4dst, &ipv4_usr_mask->ip4dst, 289f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4dst)); 290f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV4); 291f0a1913fSSubbaraya Sundeep } 292f0a1913fSSubbaraya Sundeep break; 293f0a1913fSSubbaraya Sundeep case TCP_V4_FLOW: 294f0a1913fSSubbaraya Sundeep case UDP_V4_FLOW: 295f0a1913fSSubbaraya Sundeep case SCTP_V4_FLOW: 296f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->ip4src) { 297f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4src, &ipv4_l4_hdr->ip4src, 298f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4src)); 299f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4src, &ipv4_l4_mask->ip4src, 300f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4src)); 301f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV4); 302f0a1913fSSubbaraya Sundeep } 303f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->ip4dst) { 304f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip4dst, &ipv4_l4_hdr->ip4dst, 305f0a1913fSSubbaraya Sundeep sizeof(pkt->ip4dst)); 306f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip4dst, &ipv4_l4_mask->ip4dst, 307f0a1913fSSubbaraya Sundeep sizeof(pmask->ip4dst)); 308f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV4); 309f0a1913fSSubbaraya Sundeep } 310f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->psrc) { 311f0a1913fSSubbaraya Sundeep memcpy(&pkt->sport, &ipv4_l4_hdr->psrc, 312f0a1913fSSubbaraya Sundeep sizeof(pkt->sport)); 313f0a1913fSSubbaraya Sundeep memcpy(&pmask->sport, &ipv4_l4_mask->psrc, 314f0a1913fSSubbaraya Sundeep sizeof(pmask->sport)); 315f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V4_FLOW) 316f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_UDP); 317f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V4_FLOW) 318f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_TCP); 319f0a1913fSSubbaraya Sundeep else 320f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_SCTP); 321f0a1913fSSubbaraya Sundeep } 322f0a1913fSSubbaraya Sundeep if (ipv4_l4_mask->pdst) { 323f0a1913fSSubbaraya Sundeep memcpy(&pkt->dport, &ipv4_l4_hdr->pdst, 324f0a1913fSSubbaraya Sundeep sizeof(pkt->dport)); 325f0a1913fSSubbaraya Sundeep memcpy(&pmask->dport, &ipv4_l4_mask->pdst, 326f0a1913fSSubbaraya Sundeep sizeof(pmask->dport)); 327f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V4_FLOW) 328f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_UDP); 329f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V4_FLOW) 330f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_TCP); 331f0a1913fSSubbaraya Sundeep else 332f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_SCTP); 333f0a1913fSSubbaraya Sundeep } 334f0a1913fSSubbaraya Sundeep break; 335f0a1913fSSubbaraya Sundeep default: 336f0a1913fSSubbaraya Sundeep break; 337f0a1913fSSubbaraya Sundeep } 338f0a1913fSSubbaraya Sundeep } 339f0a1913fSSubbaraya Sundeep 340f0a1913fSSubbaraya Sundeep static void otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp, 341f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req, 342f0a1913fSSubbaraya Sundeep u32 flow_type) 343f0a1913fSSubbaraya Sundeep { 344f0a1913fSSubbaraya Sundeep struct ethtool_usrip6_spec *ipv6_usr_mask = &fsp->m_u.usr_ip6_spec; 345f0a1913fSSubbaraya Sundeep struct ethtool_usrip6_spec *ipv6_usr_hdr = &fsp->h_u.usr_ip6_spec; 346f0a1913fSSubbaraya Sundeep struct ethtool_tcpip6_spec *ipv6_l4_mask = &fsp->m_u.tcp_ip6_spec; 347f0a1913fSSubbaraya Sundeep struct ethtool_tcpip6_spec *ipv6_l4_hdr = &fsp->h_u.tcp_ip6_spec; 348f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask; 349f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet; 350f0a1913fSSubbaraya Sundeep 351f0a1913fSSubbaraya Sundeep switch (flow_type) { 352f0a1913fSSubbaraya Sundeep case IPV6_USER_FLOW: 353f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6src)) { 354f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6src, &ipv6_usr_hdr->ip6src, 355f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6src)); 356f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6src, &ipv6_usr_mask->ip6src, 357f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6src)); 358f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV6); 359f0a1913fSSubbaraya Sundeep } 360f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_usr_mask->ip6dst)) { 361f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6dst, &ipv6_usr_hdr->ip6dst, 362f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6dst)); 363f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6dst, &ipv6_usr_mask->ip6dst, 364f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6dst)); 365f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV6); 366f0a1913fSSubbaraya Sundeep } 367f0a1913fSSubbaraya Sundeep break; 368f0a1913fSSubbaraya Sundeep case TCP_V6_FLOW: 369f0a1913fSSubbaraya Sundeep case UDP_V6_FLOW: 370f0a1913fSSubbaraya Sundeep case SCTP_V6_FLOW: 371f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6src)) { 372f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6src, &ipv6_l4_hdr->ip6src, 373f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6src)); 374f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6src, &ipv6_l4_mask->ip6src, 375f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6src)); 376f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SIP_IPV6); 377f0a1913fSSubbaraya Sundeep } 378f0a1913fSSubbaraya Sundeep if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6dst)) { 379f0a1913fSSubbaraya Sundeep memcpy(&pkt->ip6dst, &ipv6_l4_hdr->ip6dst, 380f0a1913fSSubbaraya Sundeep sizeof(pkt->ip6dst)); 381f0a1913fSSubbaraya Sundeep memcpy(&pmask->ip6dst, &ipv6_l4_mask->ip6dst, 382f0a1913fSSubbaraya Sundeep sizeof(pmask->ip6dst)); 383f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DIP_IPV6); 384f0a1913fSSubbaraya Sundeep } 385f0a1913fSSubbaraya Sundeep if (ipv6_l4_mask->psrc) { 386f0a1913fSSubbaraya Sundeep memcpy(&pkt->sport, &ipv6_l4_hdr->psrc, 387f0a1913fSSubbaraya Sundeep sizeof(pkt->sport)); 388f0a1913fSSubbaraya Sundeep memcpy(&pmask->sport, &ipv6_l4_mask->psrc, 389f0a1913fSSubbaraya Sundeep sizeof(pmask->sport)); 390f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V6_FLOW) 391f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_UDP); 392f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V6_FLOW) 393f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_TCP); 394f0a1913fSSubbaraya Sundeep else 395f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SPORT_SCTP); 396f0a1913fSSubbaraya Sundeep } 397f0a1913fSSubbaraya Sundeep if (ipv6_l4_mask->pdst) { 398f0a1913fSSubbaraya Sundeep memcpy(&pkt->dport, &ipv6_l4_hdr->pdst, 399f0a1913fSSubbaraya Sundeep sizeof(pkt->dport)); 400f0a1913fSSubbaraya Sundeep memcpy(&pmask->dport, &ipv6_l4_mask->pdst, 401f0a1913fSSubbaraya Sundeep sizeof(pmask->dport)); 402f0a1913fSSubbaraya Sundeep if (flow_type == UDP_V6_FLOW) 403f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_UDP); 404f0a1913fSSubbaraya Sundeep else if (flow_type == TCP_V6_FLOW) 405f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_TCP); 406f0a1913fSSubbaraya Sundeep else 407f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DPORT_SCTP); 408f0a1913fSSubbaraya Sundeep } 409f0a1913fSSubbaraya Sundeep break; 410f0a1913fSSubbaraya Sundeep default: 411f0a1913fSSubbaraya Sundeep break; 412f0a1913fSSubbaraya Sundeep } 413f0a1913fSSubbaraya Sundeep } 414f0a1913fSSubbaraya Sundeep 415f0a1913fSSubbaraya Sundeep int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp, 416f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req) 417f0a1913fSSubbaraya Sundeep { 418f0a1913fSSubbaraya Sundeep struct ethhdr *eth_mask = &fsp->m_u.ether_spec; 419f0a1913fSSubbaraya Sundeep struct ethhdr *eth_hdr = &fsp->h_u.ether_spec; 420f0a1913fSSubbaraya Sundeep struct flow_msg *pmask = &req->mask; 421f0a1913fSSubbaraya Sundeep struct flow_msg *pkt = &req->packet; 422f0a1913fSSubbaraya Sundeep u32 flow_type; 423f0a1913fSSubbaraya Sundeep 424f0a1913fSSubbaraya Sundeep flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT); 425f0a1913fSSubbaraya Sundeep switch (flow_type) { 426f0a1913fSSubbaraya Sundeep /* bits not set in mask are don't care */ 427f0a1913fSSubbaraya Sundeep case ETHER_FLOW: 428f0a1913fSSubbaraya Sundeep if (!is_zero_ether_addr(eth_mask->h_source)) { 429f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->smac, eth_hdr->h_source); 430f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->smac, eth_mask->h_source); 431f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_SMAC); 432f0a1913fSSubbaraya Sundeep } 433f0a1913fSSubbaraya Sundeep if (!is_zero_ether_addr(eth_mask->h_dest)) { 434f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->dmac, eth_hdr->h_dest); 435f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->dmac, eth_mask->h_dest); 436f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DMAC); 437f0a1913fSSubbaraya Sundeep } 438f0a1913fSSubbaraya Sundeep if (eth_mask->h_proto) { 439f0a1913fSSubbaraya Sundeep memcpy(&pkt->etype, ð_hdr->h_proto, 440f0a1913fSSubbaraya Sundeep sizeof(pkt->etype)); 441f0a1913fSSubbaraya Sundeep memcpy(&pmask->etype, ð_mask->h_proto, 442f0a1913fSSubbaraya Sundeep sizeof(pmask->etype)); 443f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_ETYPE); 444f0a1913fSSubbaraya Sundeep } 445f0a1913fSSubbaraya Sundeep break; 446f0a1913fSSubbaraya Sundeep case IP_USER_FLOW: 447f0a1913fSSubbaraya Sundeep case TCP_V4_FLOW: 448f0a1913fSSubbaraya Sundeep case UDP_V4_FLOW: 449f0a1913fSSubbaraya Sundeep case SCTP_V4_FLOW: 450f0a1913fSSubbaraya Sundeep otx2_prepare_ipv4_flow(fsp, req, flow_type); 451f0a1913fSSubbaraya Sundeep break; 452f0a1913fSSubbaraya Sundeep case IPV6_USER_FLOW: 453f0a1913fSSubbaraya Sundeep case TCP_V6_FLOW: 454f0a1913fSSubbaraya Sundeep case UDP_V6_FLOW: 455f0a1913fSSubbaraya Sundeep case SCTP_V6_FLOW: 456f0a1913fSSubbaraya Sundeep otx2_prepare_ipv6_flow(fsp, req, flow_type); 457f0a1913fSSubbaraya Sundeep break; 458f0a1913fSSubbaraya Sundeep default: 459f0a1913fSSubbaraya Sundeep return -EOPNOTSUPP; 460f0a1913fSSubbaraya Sundeep } 461f0a1913fSSubbaraya Sundeep if (fsp->flow_type & FLOW_EXT) { 462f0a1913fSSubbaraya Sundeep if (fsp->m_ext.vlan_etype) 463f0a1913fSSubbaraya Sundeep return -EINVAL; 464f0a1913fSSubbaraya Sundeep if (fsp->m_ext.vlan_tci) { 465f0a1913fSSubbaraya Sundeep if (fsp->m_ext.vlan_tci != cpu_to_be16(VLAN_VID_MASK)) 466f0a1913fSSubbaraya Sundeep return -EINVAL; 467f0a1913fSSubbaraya Sundeep if (be16_to_cpu(fsp->h_ext.vlan_tci) >= VLAN_N_VID) 468f0a1913fSSubbaraya Sundeep return -EINVAL; 469f0a1913fSSubbaraya Sundeep 470f0a1913fSSubbaraya Sundeep memcpy(&pkt->vlan_tci, &fsp->h_ext.vlan_tci, 471f0a1913fSSubbaraya Sundeep sizeof(pkt->vlan_tci)); 472f0a1913fSSubbaraya Sundeep memcpy(&pmask->vlan_tci, &fsp->m_ext.vlan_tci, 473f0a1913fSSubbaraya Sundeep sizeof(pmask->vlan_tci)); 474f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_OUTER_VID); 475f0a1913fSSubbaraya Sundeep } 476f0a1913fSSubbaraya Sundeep 477f0a1913fSSubbaraya Sundeep /* Not Drop/Direct to queue but use action in default entry */ 478f0a1913fSSubbaraya Sundeep if (fsp->m_ext.data[1] && 479f0a1913fSSubbaraya Sundeep fsp->h_ext.data[1] == cpu_to_be32(OTX2_DEFAULT_ACTION)) 480f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTION_DEFAULT; 481f0a1913fSSubbaraya Sundeep } 482f0a1913fSSubbaraya Sundeep 483f0a1913fSSubbaraya Sundeep if (fsp->flow_type & FLOW_MAC_EXT && 484f0a1913fSSubbaraya Sundeep !is_zero_ether_addr(fsp->m_ext.h_dest)) { 485f0a1913fSSubbaraya Sundeep ether_addr_copy(pkt->dmac, fsp->h_ext.h_dest); 486f0a1913fSSubbaraya Sundeep ether_addr_copy(pmask->dmac, fsp->m_ext.h_dest); 487f0a1913fSSubbaraya Sundeep req->features |= BIT_ULL(NPC_DMAC); 488f0a1913fSSubbaraya Sundeep } 489f0a1913fSSubbaraya Sundeep 490f0a1913fSSubbaraya Sundeep if (!req->features) 491f0a1913fSSubbaraya Sundeep return -EOPNOTSUPP; 492f0a1913fSSubbaraya Sundeep 493f0a1913fSSubbaraya Sundeep return 0; 494f0a1913fSSubbaraya Sundeep } 495f0a1913fSSubbaraya Sundeep 496f0a1913fSSubbaraya Sundeep static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow) 497f0a1913fSSubbaraya Sundeep { 498f0a1913fSSubbaraya Sundeep u64 ring_cookie = flow->flow_spec.ring_cookie; 499f0a1913fSSubbaraya Sundeep struct npc_install_flow_req *req; 500f0a1913fSSubbaraya Sundeep int err, vf = 0; 501f0a1913fSSubbaraya Sundeep 502f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock); 503f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox); 504f0a1913fSSubbaraya Sundeep if (!req) { 505f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 506f0a1913fSSubbaraya Sundeep return -ENOMEM; 507f0a1913fSSubbaraya Sundeep } 508f0a1913fSSubbaraya Sundeep 509f0a1913fSSubbaraya Sundeep err = otx2_prepare_flow_request(&flow->flow_spec, req); 510f0a1913fSSubbaraya Sundeep if (err) { 511f0a1913fSSubbaraya Sundeep /* free the allocated msg above */ 512f0a1913fSSubbaraya Sundeep otx2_mbox_reset(&pfvf->mbox.mbox, 0); 513f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 514f0a1913fSSubbaraya Sundeep return err; 515f0a1913fSSubbaraya Sundeep } 516f0a1913fSSubbaraya Sundeep 517f0a1913fSSubbaraya Sundeep req->entry = flow->entry; 518f0a1913fSSubbaraya Sundeep req->intf = NIX_INTF_RX; 519f0a1913fSSubbaraya Sundeep req->set_cntr = 1; 520f0a1913fSSubbaraya Sundeep req->channel = pfvf->hw.rx_chan_base; 521f0a1913fSSubbaraya Sundeep if (ring_cookie == RX_CLS_FLOW_DISC) { 522f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTIONOP_DROP; 523f0a1913fSSubbaraya Sundeep } else { 524f0a1913fSSubbaraya Sundeep /* change to unicast only if action of default entry is not 525f0a1913fSSubbaraya Sundeep * requested by user 526f0a1913fSSubbaraya Sundeep */ 527f0a1913fSSubbaraya Sundeep if (req->op != NIX_RX_ACTION_DEFAULT) 528f0a1913fSSubbaraya Sundeep req->op = NIX_RX_ACTIONOP_UCAST; 529f0a1913fSSubbaraya Sundeep req->index = ethtool_get_flow_spec_ring(ring_cookie); 530f0a1913fSSubbaraya Sundeep vf = ethtool_get_flow_spec_ring_vf(ring_cookie); 531f0a1913fSSubbaraya Sundeep if (vf > pci_num_vf(pfvf->pdev)) { 532f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 533f0a1913fSSubbaraya Sundeep return -EINVAL; 534f0a1913fSSubbaraya Sundeep } 535f0a1913fSSubbaraya Sundeep } 536f0a1913fSSubbaraya Sundeep 537f0a1913fSSubbaraya Sundeep /* ethtool ring_cookie has (VF + 1) for VF */ 538f0a1913fSSubbaraya Sundeep if (vf) { 539f0a1913fSSubbaraya Sundeep req->vf = vf; 540f0a1913fSSubbaraya Sundeep flow->is_vf = true; 541f0a1913fSSubbaraya Sundeep flow->vf = vf; 542f0a1913fSSubbaraya Sundeep } 543f0a1913fSSubbaraya Sundeep 544f0a1913fSSubbaraya Sundeep /* Send message to AF */ 545f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox); 546f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 547f0a1913fSSubbaraya Sundeep return err; 548f0a1913fSSubbaraya Sundeep } 549f0a1913fSSubbaraya Sundeep 550f0a1913fSSubbaraya Sundeep int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rx_flow_spec *fsp) 551f0a1913fSSubbaraya Sundeep { 552f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; 553f0a1913fSSubbaraya Sundeep u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie); 554f0a1913fSSubbaraya Sundeep struct otx2_flow *flow; 555f0a1913fSSubbaraya Sundeep bool new = false; 556f0a1913fSSubbaraya Sundeep int err; 557f0a1913fSSubbaraya Sundeep 558f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT)) 559f0a1913fSSubbaraya Sundeep return -ENOMEM; 560f0a1913fSSubbaraya Sundeep 561f0a1913fSSubbaraya Sundeep if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC) 562f0a1913fSSubbaraya Sundeep return -EINVAL; 563f0a1913fSSubbaraya Sundeep 564f0a1913fSSubbaraya Sundeep if (fsp->location >= flow_cfg->ntuple_max_flows) 565f0a1913fSSubbaraya Sundeep return -EINVAL; 566f0a1913fSSubbaraya Sundeep 567f0a1913fSSubbaraya Sundeep flow = otx2_find_flow(pfvf, fsp->location); 568f0a1913fSSubbaraya Sundeep if (!flow) { 569f0a1913fSSubbaraya Sundeep flow = kzalloc(sizeof(*flow), GFP_ATOMIC); 570f0a1913fSSubbaraya Sundeep if (!flow) 571f0a1913fSSubbaraya Sundeep return -ENOMEM; 572f0a1913fSSubbaraya Sundeep flow->location = fsp->location; 573f0a1913fSSubbaraya Sundeep flow->entry = flow_cfg->entry[flow_cfg->ntuple_offset + 574f0a1913fSSubbaraya Sundeep flow->location]; 575f0a1913fSSubbaraya Sundeep new = true; 576f0a1913fSSubbaraya Sundeep } 577f0a1913fSSubbaraya Sundeep /* struct copy */ 578f0a1913fSSubbaraya Sundeep flow->flow_spec = *fsp; 579f0a1913fSSubbaraya Sundeep 580f0a1913fSSubbaraya Sundeep err = otx2_add_flow_msg(pfvf, flow); 581f0a1913fSSubbaraya Sundeep if (err) { 582f0a1913fSSubbaraya Sundeep if (new) 583f0a1913fSSubbaraya Sundeep kfree(flow); 584f0a1913fSSubbaraya Sundeep return err; 585f0a1913fSSubbaraya Sundeep } 586f0a1913fSSubbaraya Sundeep 587f0a1913fSSubbaraya Sundeep /* add the new flow installed to list */ 588f0a1913fSSubbaraya Sundeep if (new) { 589f0a1913fSSubbaraya Sundeep otx2_add_flow_to_list(pfvf, flow); 590f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows++; 591f0a1913fSSubbaraya Sundeep } 592f0a1913fSSubbaraya Sundeep 593f0a1913fSSubbaraya Sundeep return 0; 594f0a1913fSSubbaraya Sundeep } 595f0a1913fSSubbaraya Sundeep 596f0a1913fSSubbaraya Sundeep static int otx2_remove_flow_msg(struct otx2_nic *pfvf, u16 entry, bool all) 597f0a1913fSSubbaraya Sundeep { 598f0a1913fSSubbaraya Sundeep struct npc_delete_flow_req *req; 599f0a1913fSSubbaraya Sundeep int err; 600f0a1913fSSubbaraya Sundeep 601f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock); 602f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox); 603f0a1913fSSubbaraya Sundeep if (!req) { 604f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 605f0a1913fSSubbaraya Sundeep return -ENOMEM; 606f0a1913fSSubbaraya Sundeep } 607f0a1913fSSubbaraya Sundeep 608f0a1913fSSubbaraya Sundeep req->entry = entry; 609f0a1913fSSubbaraya Sundeep if (all) 610f0a1913fSSubbaraya Sundeep req->all = 1; 611f0a1913fSSubbaraya Sundeep 612f0a1913fSSubbaraya Sundeep /* Send message to AF */ 613f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox); 614f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 615f0a1913fSSubbaraya Sundeep return err; 616f0a1913fSSubbaraya Sundeep } 617f0a1913fSSubbaraya Sundeep 618f0a1913fSSubbaraya Sundeep int otx2_remove_flow(struct otx2_nic *pfvf, u32 location) 619f0a1913fSSubbaraya Sundeep { 620f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; 621f0a1913fSSubbaraya Sundeep struct otx2_flow *flow; 622f0a1913fSSubbaraya Sundeep int err; 623f0a1913fSSubbaraya Sundeep 624f0a1913fSSubbaraya Sundeep if (location >= flow_cfg->ntuple_max_flows) 625f0a1913fSSubbaraya Sundeep return -EINVAL; 626f0a1913fSSubbaraya Sundeep 627f0a1913fSSubbaraya Sundeep flow = otx2_find_flow(pfvf, location); 628f0a1913fSSubbaraya Sundeep if (!flow) 629f0a1913fSSubbaraya Sundeep return -ENOENT; 630f0a1913fSSubbaraya Sundeep 631f0a1913fSSubbaraya Sundeep err = otx2_remove_flow_msg(pfvf, flow->entry, false); 632f0a1913fSSubbaraya Sundeep if (err) 633f0a1913fSSubbaraya Sundeep return err; 634f0a1913fSSubbaraya Sundeep 635f0a1913fSSubbaraya Sundeep list_del(&flow->list); 636f0a1913fSSubbaraya Sundeep kfree(flow); 637f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--; 638f0a1913fSSubbaraya Sundeep 639f0a1913fSSubbaraya Sundeep return 0; 640f0a1913fSSubbaraya Sundeep } 641f0a1913fSSubbaraya Sundeep 642f0a1913fSSubbaraya Sundeep int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf) 643f0a1913fSSubbaraya Sundeep { 644f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; 645f0a1913fSSubbaraya Sundeep struct npc_delete_flow_req *req; 646f0a1913fSSubbaraya Sundeep struct otx2_flow *iter, *tmp; 647f0a1913fSSubbaraya Sundeep int err; 648f0a1913fSSubbaraya Sundeep 649f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT)) 650f0a1913fSSubbaraya Sundeep return 0; 651f0a1913fSSubbaraya Sundeep 652f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock); 653f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_delete_flow(&pfvf->mbox); 654f0a1913fSSubbaraya Sundeep if (!req) { 655f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 656f0a1913fSSubbaraya Sundeep return -ENOMEM; 657f0a1913fSSubbaraya Sundeep } 658f0a1913fSSubbaraya Sundeep 659f0a1913fSSubbaraya Sundeep req->start = flow_cfg->entry[flow_cfg->ntuple_offset]; 660f0a1913fSSubbaraya Sundeep req->end = flow_cfg->entry[flow_cfg->ntuple_offset + 661f0a1913fSSubbaraya Sundeep flow_cfg->ntuple_max_flows - 1]; 662f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox); 663f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 664f0a1913fSSubbaraya Sundeep 665f0a1913fSSubbaraya Sundeep list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) { 666f0a1913fSSubbaraya Sundeep list_del(&iter->list); 667f0a1913fSSubbaraya Sundeep kfree(iter); 668f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--; 669f0a1913fSSubbaraya Sundeep } 670f0a1913fSSubbaraya Sundeep return err; 671f0a1913fSSubbaraya Sundeep } 672f0a1913fSSubbaraya Sundeep 673f0a1913fSSubbaraya Sundeep int otx2_destroy_mcam_flows(struct otx2_nic *pfvf) 674f0a1913fSSubbaraya Sundeep { 675f0a1913fSSubbaraya Sundeep struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; 676f0a1913fSSubbaraya Sundeep struct npc_mcam_free_entry_req *req; 677f0a1913fSSubbaraya Sundeep struct otx2_flow *iter, *tmp; 678f0a1913fSSubbaraya Sundeep int err; 679f0a1913fSSubbaraya Sundeep 680f0a1913fSSubbaraya Sundeep if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC)) 681f0a1913fSSubbaraya Sundeep return 0; 682f0a1913fSSubbaraya Sundeep 683f0a1913fSSubbaraya Sundeep /* remove all flows */ 684f0a1913fSSubbaraya Sundeep err = otx2_remove_flow_msg(pfvf, 0, true); 685f0a1913fSSubbaraya Sundeep if (err) 686f0a1913fSSubbaraya Sundeep return err; 687f0a1913fSSubbaraya Sundeep 688f0a1913fSSubbaraya Sundeep list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list, list) { 689f0a1913fSSubbaraya Sundeep list_del(&iter->list); 690f0a1913fSSubbaraya Sundeep kfree(iter); 691f0a1913fSSubbaraya Sundeep flow_cfg->nr_flows--; 692f0a1913fSSubbaraya Sundeep } 693f0a1913fSSubbaraya Sundeep 694f0a1913fSSubbaraya Sundeep mutex_lock(&pfvf->mbox.lock); 695f0a1913fSSubbaraya Sundeep req = otx2_mbox_alloc_msg_npc_mcam_free_entry(&pfvf->mbox); 696f0a1913fSSubbaraya Sundeep if (!req) { 697f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 698f0a1913fSSubbaraya Sundeep return -ENOMEM; 699f0a1913fSSubbaraya Sundeep } 700f0a1913fSSubbaraya Sundeep 701f0a1913fSSubbaraya Sundeep req->all = 1; 702f0a1913fSSubbaraya Sundeep /* Send message to AF to free MCAM entries */ 703f0a1913fSSubbaraya Sundeep err = otx2_sync_mbox_msg(&pfvf->mbox); 704f0a1913fSSubbaraya Sundeep if (err) { 705f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 706f0a1913fSSubbaraya Sundeep return err; 707f0a1913fSSubbaraya Sundeep } 708f0a1913fSSubbaraya Sundeep 709f0a1913fSSubbaraya Sundeep pfvf->flags &= ~OTX2_FLAG_MCAM_ENTRIES_ALLOC; 710f0a1913fSSubbaraya Sundeep mutex_unlock(&pfvf->mbox.lock); 711f0a1913fSSubbaraya Sundeep 712f0a1913fSSubbaraya Sundeep return 0; 713f0a1913fSSubbaraya Sundeep } 714