xref: /openbmc/linux/drivers/infiniband/hw/usnic/usnic_fwd.c (revision 2183b990b67b761f81c68a18f60df028e080cf05)
1e3cf00d0SUpinder Malhi /*
2e3cf00d0SUpinder Malhi  * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3e3cf00d0SUpinder Malhi  *
4e3cf00d0SUpinder Malhi  * This program is free software; you may redistribute it and/or modify
5e3cf00d0SUpinder Malhi  * it under the terms of the GNU General Public License as published by
6e3cf00d0SUpinder Malhi  * the Free Software Foundation; version 2 of the License.
7e3cf00d0SUpinder Malhi  *
8e3cf00d0SUpinder Malhi  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9e3cf00d0SUpinder Malhi  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10e3cf00d0SUpinder Malhi  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11e3cf00d0SUpinder Malhi  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12e3cf00d0SUpinder Malhi  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13e3cf00d0SUpinder Malhi  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14e3cf00d0SUpinder Malhi  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15e3cf00d0SUpinder Malhi  * SOFTWARE.
16e3cf00d0SUpinder Malhi  *
17e3cf00d0SUpinder Malhi  */
18e3cf00d0SUpinder Malhi #include <linux/netdevice.h>
19e3cf00d0SUpinder Malhi #include <linux/pci.h>
20e3cf00d0SUpinder Malhi 
21e3cf00d0SUpinder Malhi #include "enic_api.h"
22e3cf00d0SUpinder Malhi #include "usnic_common_pkt_hdr.h"
23e3cf00d0SUpinder Malhi #include "usnic_fwd.h"
24e3cf00d0SUpinder Malhi #include "usnic_log.h"
25e3cf00d0SUpinder Malhi 
26*2183b990SUpinder Malhi static int usnic_fwd_devcmd_locked(struct usnic_fwd_dev *ufdev, int vnic_idx,
27*2183b990SUpinder Malhi 					enum vnic_devcmd_cmd cmd, u64 *a0,
28*2183b990SUpinder Malhi 					u64 *a1)
29*2183b990SUpinder Malhi {
30*2183b990SUpinder Malhi 	int status;
31*2183b990SUpinder Malhi 	struct net_device *netdev = ufdev->netdev;
32*2183b990SUpinder Malhi 
33*2183b990SUpinder Malhi 	lockdep_assert_held(&ufdev->lock);
34*2183b990SUpinder Malhi 
35*2183b990SUpinder Malhi 	status = enic_api_devcmd_proxy_by_index(netdev,
36*2183b990SUpinder Malhi 			vnic_idx,
37*2183b990SUpinder Malhi 			cmd,
38*2183b990SUpinder Malhi 			a0, a1,
39*2183b990SUpinder Malhi 			1000);
40*2183b990SUpinder Malhi 	if (status) {
41*2183b990SUpinder Malhi 		if (status == ERR_EINVAL && cmd == CMD_DEL_FILTER) {
42*2183b990SUpinder Malhi 			usnic_dbg("Dev %s vnic idx %u cmd %u already deleted",
43*2183b990SUpinder Malhi 					ufdev->name, vnic_idx, cmd);
44*2183b990SUpinder Malhi 		} else {
45*2183b990SUpinder Malhi 			usnic_err("Dev %s vnic idx %u cmd %u failed with status %d\n",
46*2183b990SUpinder Malhi 					ufdev->name, vnic_idx, cmd,
47*2183b990SUpinder Malhi 					status);
48*2183b990SUpinder Malhi 		}
49*2183b990SUpinder Malhi 	} else {
50*2183b990SUpinder Malhi 		usnic_dbg("Dev %s vnic idx %u cmd %u success",
51*2183b990SUpinder Malhi 				ufdev->name, vnic_idx, cmd);
52*2183b990SUpinder Malhi 	}
53*2183b990SUpinder Malhi 
54*2183b990SUpinder Malhi 	return status;
55*2183b990SUpinder Malhi }
56*2183b990SUpinder Malhi 
57*2183b990SUpinder Malhi static int usnic_fwd_devcmd(struct usnic_fwd_dev *ufdev, int vnic_idx,
58*2183b990SUpinder Malhi 				enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1)
59*2183b990SUpinder Malhi {
60*2183b990SUpinder Malhi 	int status;
61*2183b990SUpinder Malhi 
62*2183b990SUpinder Malhi 	spin_lock(&ufdev->lock);
63*2183b990SUpinder Malhi 	status = usnic_fwd_devcmd_locked(ufdev, vnic_idx, cmd, a0, a1);
64*2183b990SUpinder Malhi 	spin_unlock(&ufdev->lock);
65*2183b990SUpinder Malhi 
66*2183b990SUpinder Malhi 	return status;
67*2183b990SUpinder Malhi }
68*2183b990SUpinder Malhi 
69e3cf00d0SUpinder Malhi struct usnic_fwd_dev *usnic_fwd_dev_alloc(struct pci_dev *pdev)
70e3cf00d0SUpinder Malhi {
71e3cf00d0SUpinder Malhi 	struct usnic_fwd_dev *ufdev;
72e3cf00d0SUpinder Malhi 
73e3cf00d0SUpinder Malhi 	ufdev = kzalloc(sizeof(*ufdev), GFP_KERNEL);
74e3cf00d0SUpinder Malhi 	if (!ufdev)
75e3cf00d0SUpinder Malhi 		return NULL;
76e3cf00d0SUpinder Malhi 
77e3cf00d0SUpinder Malhi 	ufdev->pdev = pdev;
78e3cf00d0SUpinder Malhi 	ufdev->netdev = pci_get_drvdata(pdev);
79e3cf00d0SUpinder Malhi 	spin_lock_init(&ufdev->lock);
80*2183b990SUpinder Malhi 	strncpy(ufdev->name, netdev_name(ufdev->netdev),
81*2183b990SUpinder Malhi 			sizeof(ufdev->name) - 1);
82e3cf00d0SUpinder Malhi 
83e3cf00d0SUpinder Malhi 	return ufdev;
84e3cf00d0SUpinder Malhi }
85e3cf00d0SUpinder Malhi 
86e3cf00d0SUpinder Malhi void usnic_fwd_dev_free(struct usnic_fwd_dev *ufdev)
87e3cf00d0SUpinder Malhi {
88e3cf00d0SUpinder Malhi 	kfree(ufdev);
89e3cf00d0SUpinder Malhi }
90e3cf00d0SUpinder Malhi 
91*2183b990SUpinder Malhi void usnic_fwd_set_mac(struct usnic_fwd_dev *ufdev, char mac[ETH_ALEN])
92e3cf00d0SUpinder Malhi {
93e3cf00d0SUpinder Malhi 	spin_lock(&ufdev->lock);
94*2183b990SUpinder Malhi 	memcpy(&ufdev->mac, mac, sizeof(ufdev->mac));
95e3cf00d0SUpinder Malhi 	spin_unlock(&ufdev->lock);
96e3cf00d0SUpinder Malhi }
97e3cf00d0SUpinder Malhi 
98*2183b990SUpinder Malhi void usnic_fwd_carrier_up(struct usnic_fwd_dev *ufdev)
99e3cf00d0SUpinder Malhi {
100*2183b990SUpinder Malhi 	spin_lock(&ufdev->lock);
101*2183b990SUpinder Malhi 	ufdev->link_up = 1;
102*2183b990SUpinder Malhi 	spin_unlock(&ufdev->lock);
103e3cf00d0SUpinder Malhi }
104e3cf00d0SUpinder Malhi 
105*2183b990SUpinder Malhi void usnic_fwd_carrier_down(struct usnic_fwd_dev *ufdev)
106*2183b990SUpinder Malhi {
107*2183b990SUpinder Malhi 	spin_lock(&ufdev->lock);
108*2183b990SUpinder Malhi 	ufdev->link_up = 0;
109*2183b990SUpinder Malhi 	spin_unlock(&ufdev->lock);
110e3cf00d0SUpinder Malhi }
111e3cf00d0SUpinder Malhi 
112*2183b990SUpinder Malhi void usnic_fwd_set_mtu(struct usnic_fwd_dev *ufdev, unsigned int mtu)
113*2183b990SUpinder Malhi {
114*2183b990SUpinder Malhi 	spin_lock(&ufdev->lock);
115*2183b990SUpinder Malhi 	ufdev->mtu = mtu;
116*2183b990SUpinder Malhi 	spin_unlock(&ufdev->lock);
117*2183b990SUpinder Malhi }
118*2183b990SUpinder Malhi 
119*2183b990SUpinder Malhi static int usnic_fwd_dev_ready_locked(struct usnic_fwd_dev *ufdev)
120*2183b990SUpinder Malhi {
121*2183b990SUpinder Malhi 	lockdep_assert_held(&ufdev->lock);
122*2183b990SUpinder Malhi 
123*2183b990SUpinder Malhi 	if (!ufdev->link_up)
124*2183b990SUpinder Malhi 		return -EPERM;
125*2183b990SUpinder Malhi 
126*2183b990SUpinder Malhi 	return 0;
127*2183b990SUpinder Malhi }
128*2183b990SUpinder Malhi 
129*2183b990SUpinder Malhi static void fill_tlv(struct filter_tlv *tlv, struct filter *filter,
130*2183b990SUpinder Malhi 		struct filter_action *action)
131*2183b990SUpinder Malhi {
132e3cf00d0SUpinder Malhi 	tlv->type = CLSF_TLV_FILTER;
133e3cf00d0SUpinder Malhi 	tlv->length = sizeof(struct filter);
134*2183b990SUpinder Malhi 	*((struct filter *)&tlv->val) = *filter;
135*2183b990SUpinder Malhi 
136e3cf00d0SUpinder Malhi 	tlv = (struct filter_tlv *)((char *)tlv + sizeof(struct filter_tlv) +
137e3cf00d0SUpinder Malhi 			sizeof(struct filter));
138e3cf00d0SUpinder Malhi 	tlv->type = CLSF_TLV_ACTION;
139e3cf00d0SUpinder Malhi 	tlv->length = sizeof(struct filter_action);
140*2183b990SUpinder Malhi 	*((struct filter_action *)&tlv->val) = *action;
141*2183b990SUpinder Malhi }
142e3cf00d0SUpinder Malhi 
143*2183b990SUpinder Malhi struct usnic_fwd_flow*
144*2183b990SUpinder Malhi usnic_fwd_alloc_flow(struct usnic_fwd_dev *ufdev, struct filter *filter,
145*2183b990SUpinder Malhi 				struct usnic_filter_action *uaction)
146*2183b990SUpinder Malhi {
147*2183b990SUpinder Malhi 	struct filter_tlv *tlv;
148*2183b990SUpinder Malhi 	struct pci_dev *pdev;
149*2183b990SUpinder Malhi 	struct usnic_fwd_flow *flow;
150*2183b990SUpinder Malhi 	uint64_t a0, a1;
151*2183b990SUpinder Malhi 	uint64_t tlv_size;
152*2183b990SUpinder Malhi 	dma_addr_t tlv_pa;
153*2183b990SUpinder Malhi 	int status;
154*2183b990SUpinder Malhi 
155*2183b990SUpinder Malhi 	pdev = ufdev->pdev;
156*2183b990SUpinder Malhi 	tlv_size = (2*sizeof(struct filter_tlv) + sizeof(struct filter) +
157*2183b990SUpinder Malhi 			sizeof(struct filter_action));
158*2183b990SUpinder Malhi 
159*2183b990SUpinder Malhi 	flow = kzalloc(sizeof(*flow), GFP_ATOMIC);
160*2183b990SUpinder Malhi 	if (!flow)
161*2183b990SUpinder Malhi 		return ERR_PTR(-ENOMEM);
162*2183b990SUpinder Malhi 
163*2183b990SUpinder Malhi 	tlv = pci_alloc_consistent(pdev, tlv_size, &tlv_pa);
164*2183b990SUpinder Malhi 	if (!tlv) {
165*2183b990SUpinder Malhi 		usnic_err("Failed to allocate memory\n");
166*2183b990SUpinder Malhi 		status = -ENOMEM;
167*2183b990SUpinder Malhi 		goto out_free_flow;
168*2183b990SUpinder Malhi 	}
169*2183b990SUpinder Malhi 
170*2183b990SUpinder Malhi 	fill_tlv(tlv, filter, &uaction->action);
171*2183b990SUpinder Malhi 
172*2183b990SUpinder Malhi 	spin_lock(&ufdev->lock);
173*2183b990SUpinder Malhi 	status = usnic_fwd_dev_ready_locked(ufdev);
174*2183b990SUpinder Malhi 	if (status) {
175*2183b990SUpinder Malhi 		usnic_err("Forwarding dev %s not ready with status %d\n",
176*2183b990SUpinder Malhi 				ufdev->name, status);
177*2183b990SUpinder Malhi 		goto out_free_tlv;
178*2183b990SUpinder Malhi 	}
179*2183b990SUpinder Malhi 
180*2183b990SUpinder Malhi 	/* Issue Devcmd */
181*2183b990SUpinder Malhi 	a0 = tlv_pa;
182*2183b990SUpinder Malhi 	a1 = tlv_size;
183*2183b990SUpinder Malhi 	status = usnic_fwd_devcmd_locked(ufdev, uaction->vnic_idx,
184*2183b990SUpinder Malhi 						CMD_ADD_FILTER, &a0, &a1);
185e3cf00d0SUpinder Malhi 	if (status) {
186e3cf00d0SUpinder Malhi 		usnic_err("VF %s Filter add failed with status:%d",
187*2183b990SUpinder Malhi 				ufdev->name, status);
188*2183b990SUpinder Malhi 		status = -EFAULT;
189*2183b990SUpinder Malhi 		goto out_free_tlv;
190e3cf00d0SUpinder Malhi 	} else {
191*2183b990SUpinder Malhi 		usnic_dbg("VF %s FILTER ID:%llu", ufdev->name, a0);
192e3cf00d0SUpinder Malhi 	}
193e3cf00d0SUpinder Malhi 
194*2183b990SUpinder Malhi 	flow->flow_id = (uint32_t) a0;
195*2183b990SUpinder Malhi 	flow->vnic_idx = uaction->vnic_idx;
196*2183b990SUpinder Malhi 	flow->ufdev = ufdev;
197e3cf00d0SUpinder Malhi 
198*2183b990SUpinder Malhi out_free_tlv:
199*2183b990SUpinder Malhi 	spin_unlock(&ufdev->lock);
200*2183b990SUpinder Malhi 	pci_free_consistent(pdev, tlv_size, tlv, tlv_pa);
201*2183b990SUpinder Malhi 	if (!status)
202*2183b990SUpinder Malhi 		return flow;
203*2183b990SUpinder Malhi out_free_flow:
204*2183b990SUpinder Malhi 	kfree(flow);
205*2183b990SUpinder Malhi 	return ERR_PTR(status);
206e3cf00d0SUpinder Malhi }
207e3cf00d0SUpinder Malhi 
208*2183b990SUpinder Malhi int usnic_fwd_dealloc_flow(struct usnic_fwd_flow *flow)
209e3cf00d0SUpinder Malhi {
210e3cf00d0SUpinder Malhi 	int status;
211e3cf00d0SUpinder Malhi 	u64 a0, a1;
212e3cf00d0SUpinder Malhi 
213*2183b990SUpinder Malhi 	a0 = flow->flow_id;
214e3cf00d0SUpinder Malhi 
215*2183b990SUpinder Malhi 	status = usnic_fwd_devcmd(flow->ufdev, flow->vnic_idx,
216e3cf00d0SUpinder Malhi 					CMD_DEL_FILTER, &a0, &a1);
217e3cf00d0SUpinder Malhi 	if (status) {
218e3cf00d0SUpinder Malhi 		if (status == ERR_EINVAL) {
219e3cf00d0SUpinder Malhi 			usnic_dbg("Filter %u already deleted for VF Idx %u pf: %s status: %d",
220*2183b990SUpinder Malhi 					flow->flow_id, flow->vnic_idx,
221*2183b990SUpinder Malhi 					flow->ufdev->name, status);
222e3cf00d0SUpinder Malhi 		} else {
223e3cf00d0SUpinder Malhi 			usnic_err("PF %s VF Idx %u Filter: %u FILTER DELETE failed with status %d",
224*2183b990SUpinder Malhi 					flow->ufdev->name, flow->vnic_idx,
225*2183b990SUpinder Malhi 					flow->flow_id, status);
226e3cf00d0SUpinder Malhi 		}
227*2183b990SUpinder Malhi 		status = 0;
228*2183b990SUpinder Malhi 		/*
229*2183b990SUpinder Malhi 		 * Log the error and fake success to the caller because if
230*2183b990SUpinder Malhi 		 * a flow fails to be deleted in the firmware, it is an
231*2183b990SUpinder Malhi 		 * unrecoverable error.
232*2183b990SUpinder Malhi 		 */
233e3cf00d0SUpinder Malhi 	} else {
234e3cf00d0SUpinder Malhi 		usnic_dbg("PF %s VF Idx %u Filter: %u FILTER DELETED",
235*2183b990SUpinder Malhi 				flow->ufdev->name, flow->vnic_idx,
236*2183b990SUpinder Malhi 				flow->flow_id);
237e3cf00d0SUpinder Malhi 	}
238e3cf00d0SUpinder Malhi 
239*2183b990SUpinder Malhi 	kfree(flow);
240e3cf00d0SUpinder Malhi 	return status;
241e3cf00d0SUpinder Malhi }
242e3cf00d0SUpinder Malhi 
243*2183b990SUpinder Malhi int usnic_fwd_enable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx)
244e3cf00d0SUpinder Malhi {
245e3cf00d0SUpinder Malhi 	int status;
246e3cf00d0SUpinder Malhi 	struct net_device *pf_netdev;
247e3cf00d0SUpinder Malhi 	u64 a0, a1;
248e3cf00d0SUpinder Malhi 
249e3cf00d0SUpinder Malhi 	pf_netdev = ufdev->netdev;
250*2183b990SUpinder Malhi 	a0 = qp_idx;
251e3cf00d0SUpinder Malhi 	a1 = CMD_QP_RQWQ;
252e3cf00d0SUpinder Malhi 
253*2183b990SUpinder Malhi 	status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_ENABLE,
254*2183b990SUpinder Malhi 						&a0, &a1);
255e3cf00d0SUpinder Malhi 	if (status) {
256e3cf00d0SUpinder Malhi 		usnic_err("PF %s VNIC Index %u RQ Index: %u ENABLE Failed with status %d",
257e3cf00d0SUpinder Malhi 				netdev_name(pf_netdev),
258e3cf00d0SUpinder Malhi 				vnic_idx,
259*2183b990SUpinder Malhi 				qp_idx,
260e3cf00d0SUpinder Malhi 				status);
261e3cf00d0SUpinder Malhi 	} else {
262e3cf00d0SUpinder Malhi 		usnic_dbg("PF %s VNIC Index %u RQ Index: %u ENABLED",
263e3cf00d0SUpinder Malhi 				netdev_name(pf_netdev),
264*2183b990SUpinder Malhi 				vnic_idx, qp_idx);
265e3cf00d0SUpinder Malhi 	}
266e3cf00d0SUpinder Malhi 
267e3cf00d0SUpinder Malhi 	return status;
268e3cf00d0SUpinder Malhi }
269e3cf00d0SUpinder Malhi 
270*2183b990SUpinder Malhi int usnic_fwd_disable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx)
271e3cf00d0SUpinder Malhi {
272e3cf00d0SUpinder Malhi 	int status;
273e3cf00d0SUpinder Malhi 	u64 a0, a1;
274e3cf00d0SUpinder Malhi 	struct net_device *pf_netdev;
275e3cf00d0SUpinder Malhi 
276e3cf00d0SUpinder Malhi 	pf_netdev = ufdev->netdev;
277*2183b990SUpinder Malhi 	a0 = qp_idx;
278e3cf00d0SUpinder Malhi 	a1 = CMD_QP_RQWQ;
279e3cf00d0SUpinder Malhi 
280*2183b990SUpinder Malhi 	status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_DISABLE,
281*2183b990SUpinder Malhi 			&a0, &a1);
282e3cf00d0SUpinder Malhi 	if (status) {
283e3cf00d0SUpinder Malhi 		usnic_err("PF %s VNIC Index %u RQ Index: %u DISABLE Failed with status %d",
284e3cf00d0SUpinder Malhi 				netdev_name(pf_netdev),
285e3cf00d0SUpinder Malhi 				vnic_idx,
286*2183b990SUpinder Malhi 				qp_idx,
287e3cf00d0SUpinder Malhi 				status);
288e3cf00d0SUpinder Malhi 	} else {
289e3cf00d0SUpinder Malhi 		usnic_dbg("PF %s VNIC Index %u RQ Index: %u DISABLED",
290e3cf00d0SUpinder Malhi 				netdev_name(pf_netdev),
291e3cf00d0SUpinder Malhi 				vnic_idx,
292*2183b990SUpinder Malhi 				qp_idx);
293e3cf00d0SUpinder Malhi 	}
294e3cf00d0SUpinder Malhi 
295e3cf00d0SUpinder Malhi 	return status;
296e3cf00d0SUpinder Malhi }
297