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, &eth_hdr->h_proto,
440f0a1913fSSubbaraya Sundeep 			       sizeof(pkt->etype));
441f0a1913fSSubbaraya Sundeep 			memcpy(&pmask->etype, &eth_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