xref: /openbmc/linux/drivers/infiniband/hw/mlx5/gsi.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1d16e91daSHaggai Eran /*
2d16e91daSHaggai Eran  * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
3d16e91daSHaggai Eran  *
4d16e91daSHaggai Eran  * This software is available to you under a choice of one of two
5d16e91daSHaggai Eran  * licenses.  You may choose to be licensed under the terms of the GNU
6d16e91daSHaggai Eran  * General Public License (GPL) Version 2, available from the file
7d16e91daSHaggai Eran  * COPYING in the main directory of this source tree, or the
8d16e91daSHaggai Eran  * OpenIB.org BSD license below:
9d16e91daSHaggai Eran  *
10d16e91daSHaggai Eran  *     Redistribution and use in source and binary forms, with or
11d16e91daSHaggai Eran  *     without modification, are permitted provided that the following
12d16e91daSHaggai Eran  *     conditions are met:
13d16e91daSHaggai Eran  *
14d16e91daSHaggai Eran  *      - Redistributions of source code must retain the above
15d16e91daSHaggai Eran  *        copyright notice, this list of conditions and the following
16d16e91daSHaggai Eran  *        disclaimer.
17d16e91daSHaggai Eran  *
18d16e91daSHaggai Eran  *      - Redistributions in binary form must reproduce the above
19d16e91daSHaggai Eran  *        copyright notice, this list of conditions and the following
20d16e91daSHaggai Eran  *        disclaimer in the documentation and/or other materials
21d16e91daSHaggai Eran  *        provided with the distribution.
22d16e91daSHaggai Eran  *
23d16e91daSHaggai Eran  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24d16e91daSHaggai Eran  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25d16e91daSHaggai Eran  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26d16e91daSHaggai Eran  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27d16e91daSHaggai Eran  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28d16e91daSHaggai Eran  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29d16e91daSHaggai Eran  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30d16e91daSHaggai Eran  * SOFTWARE.
31d16e91daSHaggai Eran  */
32d16e91daSHaggai Eran 
33d16e91daSHaggai Eran #include "mlx5_ib.h"
34d16e91daSHaggai Eran 
35ea6dc203SHaggai Eran struct mlx5_ib_gsi_wr {
36ea6dc203SHaggai Eran 	struct ib_cqe cqe;
37ea6dc203SHaggai Eran 	struct ib_wc wc;
38ea6dc203SHaggai Eran 	bool completed:1;
39ea6dc203SHaggai Eran };
40ea6dc203SHaggai Eran 
mlx5_ib_deth_sqpn_cap(struct mlx5_ib_dev * dev)41ebab41cfSHaggai Eran static bool mlx5_ib_deth_sqpn_cap(struct mlx5_ib_dev *dev)
42ebab41cfSHaggai Eran {
43ebab41cfSHaggai Eran 	return MLX5_CAP_GEN(dev->mdev, set_deth_sqpn);
44ebab41cfSHaggai Eran }
45ebab41cfSHaggai Eran 
46ea6dc203SHaggai Eran /* Call with gsi->lock locked */
generate_completions(struct mlx5_ib_qp * mqp)47f8225e34SLeon Romanovsky static void generate_completions(struct mlx5_ib_qp *mqp)
48ea6dc203SHaggai Eran {
49f8225e34SLeon Romanovsky 	struct mlx5_ib_gsi_qp *gsi = &mqp->gsi;
50f8225e34SLeon Romanovsky 	struct ib_cq *gsi_cq = mqp->ibqp.send_cq;
51ea6dc203SHaggai Eran 	struct mlx5_ib_gsi_wr *wr;
52ea6dc203SHaggai Eran 	u32 index;
53ea6dc203SHaggai Eran 
54b0ffeb53SSlava Shwartsman 	for (index = gsi->outstanding_ci; index != gsi->outstanding_pi;
55b0ffeb53SSlava Shwartsman 	     index++) {
56b0ffeb53SSlava Shwartsman 		wr = &gsi->outstanding_wrs[index % gsi->cap.max_send_wr];
57ea6dc203SHaggai Eran 
58ea6dc203SHaggai Eran 		if (!wr->completed)
59ea6dc203SHaggai Eran 			break;
60ea6dc203SHaggai Eran 
61ea6dc203SHaggai Eran 		WARN_ON_ONCE(mlx5_ib_generate_wc(gsi_cq, &wr->wc));
62ea6dc203SHaggai Eran 		wr->completed = false;
63ea6dc203SHaggai Eran 	}
64ea6dc203SHaggai Eran 
65ea6dc203SHaggai Eran 	gsi->outstanding_ci = index;
66ea6dc203SHaggai Eran }
67ea6dc203SHaggai Eran 
handle_single_completion(struct ib_cq * cq,struct ib_wc * wc)68ea6dc203SHaggai Eran static void handle_single_completion(struct ib_cq *cq, struct ib_wc *wc)
69ea6dc203SHaggai Eran {
70ea6dc203SHaggai Eran 	struct mlx5_ib_gsi_qp *gsi = cq->cq_context;
71ea6dc203SHaggai Eran 	struct mlx5_ib_gsi_wr *wr =
72ea6dc203SHaggai Eran 		container_of(wc->wr_cqe, struct mlx5_ib_gsi_wr, cqe);
73f8225e34SLeon Romanovsky 	struct mlx5_ib_qp *mqp = container_of(gsi, struct mlx5_ib_qp, gsi);
74ea6dc203SHaggai Eran 	u64 wr_id;
75ea6dc203SHaggai Eran 	unsigned long flags;
76ea6dc203SHaggai Eran 
77ea6dc203SHaggai Eran 	spin_lock_irqsave(&gsi->lock, flags);
78ea6dc203SHaggai Eran 	wr->completed = true;
79ea6dc203SHaggai Eran 	wr_id = wr->wc.wr_id;
80ea6dc203SHaggai Eran 	wr->wc = *wc;
81ea6dc203SHaggai Eran 	wr->wc.wr_id = wr_id;
82f8225e34SLeon Romanovsky 	wr->wc.qp = &mqp->ibqp;
83ea6dc203SHaggai Eran 
84f8225e34SLeon Romanovsky 	generate_completions(mqp);
85ea6dc203SHaggai Eran 	spin_unlock_irqrestore(&gsi->lock, flags);
86ea6dc203SHaggai Eran }
87ea6dc203SHaggai Eran 
mlx5_ib_create_gsi(struct ib_pd * pd,struct mlx5_ib_qp * mqp,struct ib_qp_init_attr * attr)882dc4d672SLeon Romanovsky int mlx5_ib_create_gsi(struct ib_pd *pd, struct mlx5_ib_qp *mqp,
892dc4d672SLeon Romanovsky 		       struct ib_qp_init_attr *attr)
90d16e91daSHaggai Eran {
91d16e91daSHaggai Eran 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
92d16e91daSHaggai Eran 	struct mlx5_ib_gsi_qp *gsi;
932dc4d672SLeon Romanovsky 	struct ib_qp_init_attr hw_init_attr = *attr;
942dc4d672SLeon Romanovsky 	const u8 port_num = attr->port_num;
95cfc1a89eSMaor Gottlieb 	int num_qps = 0;
96d16e91daSHaggai Eran 	int ret;
97d16e91daSHaggai Eran 
98cfc1a89eSMaor Gottlieb 	if (mlx5_ib_deth_sqpn_cap(dev)) {
99cfc1a89eSMaor Gottlieb 		if (MLX5_CAP_GEN(dev->mdev,
100cfc1a89eSMaor Gottlieb 				 port_type) == MLX5_CAP_PORT_TYPE_IB)
101cfc1a89eSMaor Gottlieb 			num_qps = pd->device->attrs.max_pkeys;
102cfc1a89eSMaor Gottlieb 		else if (dev->lag_active)
103*34a30d76SMark Bloch 			num_qps = dev->lag_ports;
104cfc1a89eSMaor Gottlieb 	}
105cfc1a89eSMaor Gottlieb 
1060d9aef86SLeon Romanovsky 	gsi = &mqp->gsi;
107ebab41cfSHaggai Eran 	gsi->tx_qps = kcalloc(num_qps, sizeof(*gsi->tx_qps), GFP_KERNEL);
1082dc4d672SLeon Romanovsky 	if (!gsi->tx_qps)
1092dc4d672SLeon Romanovsky 		return -ENOMEM;
110ebab41cfSHaggai Eran 
1112dc4d672SLeon Romanovsky 	gsi->outstanding_wrs =
1122dc4d672SLeon Romanovsky 		kcalloc(attr->cap.max_send_wr, sizeof(*gsi->outstanding_wrs),
113ea6dc203SHaggai Eran 			GFP_KERNEL);
114ea6dc203SHaggai Eran 	if (!gsi->outstanding_wrs) {
115ea6dc203SHaggai Eran 		ret = -ENOMEM;
116ea6dc203SHaggai Eran 		goto err_free_tx;
117ea6dc203SHaggai Eran 	}
118ea6dc203SHaggai Eran 
119d16e91daSHaggai Eran 	if (dev->devr.ports[port_num - 1].gsi) {
120d16e91daSHaggai Eran 		mlx5_ib_warn(dev, "GSI QP already exists on port %d\n",
121d16e91daSHaggai Eran 			     port_num);
122d16e91daSHaggai Eran 		ret = -EBUSY;
123ea6dc203SHaggai Eran 		goto err_free_wrs;
124d16e91daSHaggai Eran 	}
125ebab41cfSHaggai Eran 	gsi->num_qps = num_qps;
126ebab41cfSHaggai Eran 	spin_lock_init(&gsi->lock);
127d16e91daSHaggai Eran 
1282dc4d672SLeon Romanovsky 	gsi->cap = attr->cap;
129d16e91daSHaggai Eran 	gsi->port_num = port_num;
130d16e91daSHaggai Eran 
1312dc4d672SLeon Romanovsky 	gsi->cq = ib_alloc_cq(pd->device, gsi, attr->cap.max_send_wr, 0,
132ea6dc203SHaggai Eran 			      IB_POLL_SOFTIRQ);
133ea6dc203SHaggai Eran 	if (IS_ERR(gsi->cq)) {
134ea6dc203SHaggai Eran 		mlx5_ib_warn(dev, "unable to create send CQ for GSI QP. error %ld\n",
135ea6dc203SHaggai Eran 			     PTR_ERR(gsi->cq));
136ea6dc203SHaggai Eran 		ret = PTR_ERR(gsi->cq);
137ea6dc203SHaggai Eran 		goto err_free_wrs;
138ea6dc203SHaggai Eran 	}
139ea6dc203SHaggai Eran 
140d16e91daSHaggai Eran 	hw_init_attr.qp_type = MLX5_IB_QPT_HW_GSI;
141ea6dc203SHaggai Eran 	hw_init_attr.send_cq = gsi->cq;
142ebe6ccc5SHaggai Eran 	if (num_qps) {
143ebe6ccc5SHaggai Eran 		hw_init_attr.cap.max_send_wr = 0;
144ebe6ccc5SHaggai Eran 		hw_init_attr.cap.max_send_sge = 0;
145ebe6ccc5SHaggai Eran 		hw_init_attr.cap.max_inline_data = 0;
146ebe6ccc5SHaggai Eran 	}
147d7ecab1eSLeon Romanovsky 
1480dc0da15SLeon Romanovsky 	gsi->rx_qp = ib_create_qp(pd, &hw_init_attr);
149d16e91daSHaggai Eran 	if (IS_ERR(gsi->rx_qp)) {
150d16e91daSHaggai Eran 		mlx5_ib_warn(dev, "unable to create hardware GSI QP. error %ld\n",
151d16e91daSHaggai Eran 			     PTR_ERR(gsi->rx_qp));
152d16e91daSHaggai Eran 		ret = PTR_ERR(gsi->rx_qp);
153ea6dc203SHaggai Eran 		goto err_destroy_cq;
154d16e91daSHaggai Eran 	}
155d16e91daSHaggai Eran 
1562dc4d672SLeon Romanovsky 	dev->devr.ports[attr->port_num - 1].gsi = gsi;
1572dc4d672SLeon Romanovsky 	return 0;
158d16e91daSHaggai Eran 
159ea6dc203SHaggai Eran err_destroy_cq:
160ea6dc203SHaggai Eran 	ib_free_cq(gsi->cq);
161ea6dc203SHaggai Eran err_free_wrs:
162ea6dc203SHaggai Eran 	kfree(gsi->outstanding_wrs);
163ea6dc203SHaggai Eran err_free_tx:
164ebab41cfSHaggai Eran 	kfree(gsi->tx_qps);
1652dc4d672SLeon Romanovsky 	return ret;
166d16e91daSHaggai Eran }
167d16e91daSHaggai Eran 
mlx5_ib_destroy_gsi(struct mlx5_ib_qp * mqp)1680d9aef86SLeon Romanovsky int mlx5_ib_destroy_gsi(struct mlx5_ib_qp *mqp)
169d16e91daSHaggai Eran {
1700d9aef86SLeon Romanovsky 	struct mlx5_ib_dev *dev = to_mdev(mqp->ibqp.device);
1710d9aef86SLeon Romanovsky 	struct mlx5_ib_gsi_qp *gsi = &mqp->gsi;
172d16e91daSHaggai Eran 	const int port_num = gsi->port_num;
173ebab41cfSHaggai Eran 	int qp_index;
174d16e91daSHaggai Eran 	int ret;
175d16e91daSHaggai Eran 
1760dc0da15SLeon Romanovsky 	ret = ib_destroy_qp(gsi->rx_qp);
177d16e91daSHaggai Eran 	if (ret) {
178d16e91daSHaggai Eran 		mlx5_ib_warn(dev, "unable to destroy hardware GSI QP. error %d\n",
179d16e91daSHaggai Eran 			     ret);
180d16e91daSHaggai Eran 		return ret;
181d16e91daSHaggai Eran 	}
182d16e91daSHaggai Eran 	dev->devr.ports[port_num - 1].gsi = NULL;
183ebab41cfSHaggai Eran 	gsi->rx_qp = NULL;
184d16e91daSHaggai Eran 
185ebab41cfSHaggai Eran 	for (qp_index = 0; qp_index < gsi->num_qps; ++qp_index) {
186ebab41cfSHaggai Eran 		if (!gsi->tx_qps[qp_index])
187ebab41cfSHaggai Eran 			continue;
188ebab41cfSHaggai Eran 		WARN_ON_ONCE(ib_destroy_qp(gsi->tx_qps[qp_index]));
189ebab41cfSHaggai Eran 		gsi->tx_qps[qp_index] = NULL;
190ebab41cfSHaggai Eran 	}
191ebab41cfSHaggai Eran 
192ea6dc203SHaggai Eran 	ib_free_cq(gsi->cq);
193ea6dc203SHaggai Eran 
194ea6dc203SHaggai Eran 	kfree(gsi->outstanding_wrs);
195ebab41cfSHaggai Eran 	kfree(gsi->tx_qps);
196d16e91daSHaggai Eran 	return 0;
197d16e91daSHaggai Eran }
198d16e91daSHaggai Eran 
create_gsi_ud_qp(struct mlx5_ib_gsi_qp * gsi)199ebab41cfSHaggai Eran static struct ib_qp *create_gsi_ud_qp(struct mlx5_ib_gsi_qp *gsi)
200ebab41cfSHaggai Eran {
201ebab41cfSHaggai Eran 	struct ib_pd *pd = gsi->rx_qp->pd;
202ebab41cfSHaggai Eran 	struct ib_qp_init_attr init_attr = {
203ebab41cfSHaggai Eran 		.event_handler = gsi->rx_qp->event_handler,
204ebab41cfSHaggai Eran 		.qp_context = gsi->rx_qp->qp_context,
205ea6dc203SHaggai Eran 		.send_cq = gsi->cq,
206ebab41cfSHaggai Eran 		.recv_cq = gsi->rx_qp->recv_cq,
207ebab41cfSHaggai Eran 		.cap = {
208ebab41cfSHaggai Eran 			.max_send_wr = gsi->cap.max_send_wr,
209ebab41cfSHaggai Eran 			.max_send_sge = gsi->cap.max_send_sge,
210ebab41cfSHaggai Eran 			.max_inline_data = gsi->cap.max_inline_data,
211ebab41cfSHaggai Eran 		},
212ebab41cfSHaggai Eran 		.qp_type = IB_QPT_UD,
2133f89b01fSMichael Guralnik 		.create_flags = MLX5_IB_QP_CREATE_SQPN_QP1,
214ebab41cfSHaggai Eran 	};
215ebab41cfSHaggai Eran 
216ebab41cfSHaggai Eran 	return ib_create_qp(pd, &init_attr);
217ebab41cfSHaggai Eran }
218ebab41cfSHaggai Eran 
modify_to_rts(struct mlx5_ib_gsi_qp * gsi,struct ib_qp * qp,u16 pkey_index)219ebab41cfSHaggai Eran static int modify_to_rts(struct mlx5_ib_gsi_qp *gsi, struct ib_qp *qp,
220cfc1a89eSMaor Gottlieb 			 u16 pkey_index)
221ebab41cfSHaggai Eran {
222ebab41cfSHaggai Eran 	struct mlx5_ib_dev *dev = to_mdev(qp->device);
223ebab41cfSHaggai Eran 	struct ib_qp_attr attr;
224ebab41cfSHaggai Eran 	int mask;
225ebab41cfSHaggai Eran 	int ret;
226ebab41cfSHaggai Eran 
227ebab41cfSHaggai Eran 	mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY | IB_QP_PORT;
228ebab41cfSHaggai Eran 	attr.qp_state = IB_QPS_INIT;
229cfc1a89eSMaor Gottlieb 	attr.pkey_index = pkey_index;
230ebab41cfSHaggai Eran 	attr.qkey = IB_QP1_QKEY;
231ebab41cfSHaggai Eran 	attr.port_num = gsi->port_num;
232ebab41cfSHaggai Eran 	ret = ib_modify_qp(qp, &attr, mask);
233ebab41cfSHaggai Eran 	if (ret) {
234ebab41cfSHaggai Eran 		mlx5_ib_err(dev, "could not change QP%d state to INIT: %d\n",
235ebab41cfSHaggai Eran 			    qp->qp_num, ret);
236ebab41cfSHaggai Eran 		return ret;
237ebab41cfSHaggai Eran 	}
238ebab41cfSHaggai Eran 
239ebab41cfSHaggai Eran 	attr.qp_state = IB_QPS_RTR;
240ebab41cfSHaggai Eran 	ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
241ebab41cfSHaggai Eran 	if (ret) {
242ebab41cfSHaggai Eran 		mlx5_ib_err(dev, "could not change QP%d state to RTR: %d\n",
243ebab41cfSHaggai Eran 			    qp->qp_num, ret);
244ebab41cfSHaggai Eran 		return ret;
245ebab41cfSHaggai Eran 	}
246ebab41cfSHaggai Eran 
247ebab41cfSHaggai Eran 	attr.qp_state = IB_QPS_RTS;
248ebab41cfSHaggai Eran 	attr.sq_psn = 0;
249ebab41cfSHaggai Eran 	ret = ib_modify_qp(qp, &attr, IB_QP_STATE | IB_QP_SQ_PSN);
250ebab41cfSHaggai Eran 	if (ret) {
251ebab41cfSHaggai Eran 		mlx5_ib_err(dev, "could not change QP%d state to RTS: %d\n",
252ebab41cfSHaggai Eran 			    qp->qp_num, ret);
253ebab41cfSHaggai Eran 		return ret;
254ebab41cfSHaggai Eran 	}
255ebab41cfSHaggai Eran 
256ebab41cfSHaggai Eran 	return 0;
257ebab41cfSHaggai Eran }
258ebab41cfSHaggai Eran 
setup_qp(struct mlx5_ib_gsi_qp * gsi,u16 qp_index)259ebab41cfSHaggai Eran static void setup_qp(struct mlx5_ib_gsi_qp *gsi, u16 qp_index)
260ebab41cfSHaggai Eran {
261ebab41cfSHaggai Eran 	struct ib_device *device = gsi->rx_qp->device;
262ebab41cfSHaggai Eran 	struct mlx5_ib_dev *dev = to_mdev(device);
263cfc1a89eSMaor Gottlieb 	int pkey_index = qp_index;
264cfc1a89eSMaor Gottlieb 	struct mlx5_ib_qp *mqp;
265ebab41cfSHaggai Eran 	struct ib_qp *qp;
266ebab41cfSHaggai Eran 	unsigned long flags;
267ebab41cfSHaggai Eran 	u16 pkey;
268ebab41cfSHaggai Eran 	int ret;
269ebab41cfSHaggai Eran 
270cfc1a89eSMaor Gottlieb 	if (MLX5_CAP_GEN(dev->mdev,  port_type) != MLX5_CAP_PORT_TYPE_IB)
271cfc1a89eSMaor Gottlieb 		pkey_index = 0;
272cfc1a89eSMaor Gottlieb 
273cfc1a89eSMaor Gottlieb 	ret = ib_query_pkey(device, gsi->port_num, pkey_index, &pkey);
274ebab41cfSHaggai Eran 	if (ret) {
275ebab41cfSHaggai Eran 		mlx5_ib_warn(dev, "unable to read P_Key at port %d, index %d\n",
276ebab41cfSHaggai Eran 			     gsi->port_num, qp_index);
277ebab41cfSHaggai Eran 		return;
278ebab41cfSHaggai Eran 	}
279ebab41cfSHaggai Eran 
280ebab41cfSHaggai Eran 	if (!pkey) {
281ebab41cfSHaggai Eran 		mlx5_ib_dbg(dev, "invalid P_Key at port %d, index %d.  Skipping.\n",
282ebab41cfSHaggai Eran 			    gsi->port_num, qp_index);
283ebab41cfSHaggai Eran 		return;
284ebab41cfSHaggai Eran 	}
285ebab41cfSHaggai Eran 
286ebab41cfSHaggai Eran 	spin_lock_irqsave(&gsi->lock, flags);
287ebab41cfSHaggai Eran 	qp = gsi->tx_qps[qp_index];
288ebab41cfSHaggai Eran 	spin_unlock_irqrestore(&gsi->lock, flags);
289ebab41cfSHaggai Eran 	if (qp) {
290ebab41cfSHaggai Eran 		mlx5_ib_dbg(dev, "already existing GSI TX QP at port %d, index %d. Skipping\n",
291ebab41cfSHaggai Eran 			    gsi->port_num, qp_index);
292ebab41cfSHaggai Eran 		return;
293ebab41cfSHaggai Eran 	}
294ebab41cfSHaggai Eran 
295ebab41cfSHaggai Eran 	qp = create_gsi_ud_qp(gsi);
296ebab41cfSHaggai Eran 	if (IS_ERR(qp)) {
297ebab41cfSHaggai Eran 		mlx5_ib_warn(dev, "unable to create hardware UD QP for GSI: %ld\n",
298ebab41cfSHaggai Eran 			     PTR_ERR(qp));
299ebab41cfSHaggai Eran 		return;
300ebab41cfSHaggai Eran 	}
301ebab41cfSHaggai Eran 
302cfc1a89eSMaor Gottlieb 	mqp = to_mqp(qp);
303cfc1a89eSMaor Gottlieb 	if (dev->lag_active)
304cfc1a89eSMaor Gottlieb 		mqp->gsi_lag_port = qp_index + 1;
305cfc1a89eSMaor Gottlieb 	ret = modify_to_rts(gsi, qp, pkey_index);
306ebab41cfSHaggai Eran 	if (ret)
307ebab41cfSHaggai Eran 		goto err_destroy_qp;
308ebab41cfSHaggai Eran 
309ebab41cfSHaggai Eran 	spin_lock_irqsave(&gsi->lock, flags);
310ebab41cfSHaggai Eran 	WARN_ON_ONCE(gsi->tx_qps[qp_index]);
311ebab41cfSHaggai Eran 	gsi->tx_qps[qp_index] = qp;
312ebab41cfSHaggai Eran 	spin_unlock_irqrestore(&gsi->lock, flags);
313ebab41cfSHaggai Eran 
314ebab41cfSHaggai Eran 	return;
315ebab41cfSHaggai Eran 
316ebab41cfSHaggai Eran err_destroy_qp:
317ebab41cfSHaggai Eran 	WARN_ON_ONCE(qp);
318ebab41cfSHaggai Eran }
319ebab41cfSHaggai Eran 
mlx5_ib_gsi_modify_qp(struct ib_qp * qp,struct ib_qp_attr * attr,int attr_mask)320d16e91daSHaggai Eran int mlx5_ib_gsi_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
321d16e91daSHaggai Eran 			  int attr_mask)
322d16e91daSHaggai Eran {
323d16e91daSHaggai Eran 	struct mlx5_ib_dev *dev = to_mdev(qp->device);
324f8225e34SLeon Romanovsky 	struct mlx5_ib_qp *mqp = to_mqp(qp);
325f8225e34SLeon Romanovsky 	struct mlx5_ib_gsi_qp *gsi = &mqp->gsi;
3268c9e7f03SLeon Romanovsky 	u16 qp_index;
327d16e91daSHaggai Eran 	int ret;
328d16e91daSHaggai Eran 
329d16e91daSHaggai Eran 	mlx5_ib_dbg(dev, "modifying GSI QP to state %d\n", attr->qp_state);
330d16e91daSHaggai Eran 
331d16e91daSHaggai Eran 	ret = ib_modify_qp(gsi->rx_qp, attr, attr_mask);
332ebab41cfSHaggai Eran 	if (ret) {
333ebab41cfSHaggai Eran 		mlx5_ib_warn(dev, "unable to modify GSI rx QP: %d\n", ret);
334f8225e34SLeon Romanovsky 		return ret;
335ebab41cfSHaggai Eran 	}
336ebab41cfSHaggai Eran 
3378c9e7f03SLeon Romanovsky 	if (to_mqp(gsi->rx_qp)->state != IB_QPS_RTS)
3388c9e7f03SLeon Romanovsky 		return 0;
3398c9e7f03SLeon Romanovsky 
3408c9e7f03SLeon Romanovsky 	for (qp_index = 0; qp_index < gsi->num_qps; ++qp_index)
3418c9e7f03SLeon Romanovsky 		setup_qp(gsi, qp_index);
342f8225e34SLeon Romanovsky 	return 0;
343d16e91daSHaggai Eran }
344d16e91daSHaggai Eran 
mlx5_ib_gsi_query_qp(struct ib_qp * qp,struct ib_qp_attr * qp_attr,int qp_attr_mask,struct ib_qp_init_attr * qp_init_attr)345d16e91daSHaggai Eran int mlx5_ib_gsi_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
346d16e91daSHaggai Eran 			 int qp_attr_mask,
347d16e91daSHaggai Eran 			 struct ib_qp_init_attr *qp_init_attr)
348d16e91daSHaggai Eran {
349f8225e34SLeon Romanovsky 	struct mlx5_ib_qp *mqp = to_mqp(qp);
350f8225e34SLeon Romanovsky 	struct mlx5_ib_gsi_qp *gsi = &mqp->gsi;
351d16e91daSHaggai Eran 	int ret;
352d16e91daSHaggai Eran 
353d16e91daSHaggai Eran 	ret = ib_query_qp(gsi->rx_qp, qp_attr, qp_attr_mask, qp_init_attr);
354d16e91daSHaggai Eran 	qp_init_attr->cap = gsi->cap;
355d16e91daSHaggai Eran 	return ret;
356d16e91daSHaggai Eran }
357d16e91daSHaggai Eran 
358ea6dc203SHaggai Eran /* Call with gsi->lock locked */
mlx5_ib_add_outstanding_wr(struct mlx5_ib_qp * mqp,struct ib_ud_wr * wr,struct ib_wc * wc)359f8225e34SLeon Romanovsky static int mlx5_ib_add_outstanding_wr(struct mlx5_ib_qp *mqp,
360ea6dc203SHaggai Eran 				      struct ib_ud_wr *wr, struct ib_wc *wc)
361ea6dc203SHaggai Eran {
362f8225e34SLeon Romanovsky 	struct mlx5_ib_gsi_qp *gsi = &mqp->gsi;
363ea6dc203SHaggai Eran 	struct mlx5_ib_dev *dev = to_mdev(gsi->rx_qp->device);
364ea6dc203SHaggai Eran 	struct mlx5_ib_gsi_wr *gsi_wr;
365ea6dc203SHaggai Eran 
366ea6dc203SHaggai Eran 	if (gsi->outstanding_pi == gsi->outstanding_ci + gsi->cap.max_send_wr) {
367ea6dc203SHaggai Eran 		mlx5_ib_warn(dev, "no available GSI work request.\n");
368ea6dc203SHaggai Eran 		return -ENOMEM;
369ea6dc203SHaggai Eran 	}
370ea6dc203SHaggai Eran 
371b0ffeb53SSlava Shwartsman 	gsi_wr = &gsi->outstanding_wrs[gsi->outstanding_pi %
372b0ffeb53SSlava Shwartsman 				       gsi->cap.max_send_wr];
373b0ffeb53SSlava Shwartsman 	gsi->outstanding_pi++;
374ea6dc203SHaggai Eran 
375ea6dc203SHaggai Eran 	if (!wc) {
376ea6dc203SHaggai Eran 		memset(&gsi_wr->wc, 0, sizeof(gsi_wr->wc));
377ea6dc203SHaggai Eran 		gsi_wr->wc.pkey_index = wr->pkey_index;
378ea6dc203SHaggai Eran 		gsi_wr->wc.wr_id = wr->wr.wr_id;
379ea6dc203SHaggai Eran 	} else {
380ea6dc203SHaggai Eran 		gsi_wr->wc = *wc;
381ea6dc203SHaggai Eran 		gsi_wr->completed = true;
382ea6dc203SHaggai Eran 	}
383ea6dc203SHaggai Eran 
384ea6dc203SHaggai Eran 	gsi_wr->cqe.done = &handle_single_completion;
385ea6dc203SHaggai Eran 	wr->wr.wr_cqe = &gsi_wr->cqe;
386ea6dc203SHaggai Eran 
387ea6dc203SHaggai Eran 	return 0;
388ea6dc203SHaggai Eran }
389ea6dc203SHaggai Eran 
39083cae2afSHaggai Eran /* Call with gsi->lock locked */
mlx5_ib_gsi_silent_drop(struct mlx5_ib_qp * mqp,struct ib_ud_wr * wr)391f8225e34SLeon Romanovsky static int mlx5_ib_gsi_silent_drop(struct mlx5_ib_qp *mqp, struct ib_ud_wr *wr)
39283cae2afSHaggai Eran {
39383cae2afSHaggai Eran 	struct ib_wc wc = {
39483cae2afSHaggai Eran 		{ .wr_id = wr->wr.wr_id },
39583cae2afSHaggai Eran 		.status = IB_WC_SUCCESS,
39683cae2afSHaggai Eran 		.opcode = IB_WC_SEND,
397f8225e34SLeon Romanovsky 		.qp = &mqp->ibqp,
39883cae2afSHaggai Eran 	};
39983cae2afSHaggai Eran 	int ret;
40083cae2afSHaggai Eran 
401f8225e34SLeon Romanovsky 	ret = mlx5_ib_add_outstanding_wr(mqp, wr, &wc);
40283cae2afSHaggai Eran 	if (ret)
40383cae2afSHaggai Eran 		return ret;
40483cae2afSHaggai Eran 
405f8225e34SLeon Romanovsky 	generate_completions(mqp);
40683cae2afSHaggai Eran 
40783cae2afSHaggai Eran 	return 0;
40883cae2afSHaggai Eran }
40983cae2afSHaggai Eran 
41083cae2afSHaggai Eran /* Call with gsi->lock locked */
get_tx_qp(struct mlx5_ib_gsi_qp * gsi,struct ib_ud_wr * wr)41183cae2afSHaggai Eran static struct ib_qp *get_tx_qp(struct mlx5_ib_gsi_qp *gsi, struct ib_ud_wr *wr)
41283cae2afSHaggai Eran {
41383cae2afSHaggai Eran 	struct mlx5_ib_dev *dev = to_mdev(gsi->rx_qp->device);
414cfc1a89eSMaor Gottlieb 	struct mlx5_ib_ah *ah = to_mah(wr->ah);
41583cae2afSHaggai Eran 	int qp_index = wr->pkey_index;
41683cae2afSHaggai Eran 
417cfc1a89eSMaor Gottlieb 	if (!gsi->num_qps)
41883cae2afSHaggai Eran 		return gsi->rx_qp;
41983cae2afSHaggai Eran 
420cfc1a89eSMaor Gottlieb 	if (dev->lag_active && ah->xmit_port)
421cfc1a89eSMaor Gottlieb 		qp_index = ah->xmit_port - 1;
422cfc1a89eSMaor Gottlieb 
42383cae2afSHaggai Eran 	if (qp_index >= gsi->num_qps)
42483cae2afSHaggai Eran 		return NULL;
42583cae2afSHaggai Eran 
42683cae2afSHaggai Eran 	return gsi->tx_qps[qp_index];
42783cae2afSHaggai Eran }
42883cae2afSHaggai Eran 
mlx5_ib_gsi_post_send(struct ib_qp * qp,const struct ib_send_wr * wr,const struct ib_send_wr ** bad_wr)429d34ac5cdSBart Van Assche int mlx5_ib_gsi_post_send(struct ib_qp *qp, const struct ib_send_wr *wr,
430d34ac5cdSBart Van Assche 			  const struct ib_send_wr **bad_wr)
431d16e91daSHaggai Eran {
432f8225e34SLeon Romanovsky 	struct mlx5_ib_qp *mqp = to_mqp(qp);
433f8225e34SLeon Romanovsky 	struct mlx5_ib_gsi_qp *gsi = &mqp->gsi;
43483cae2afSHaggai Eran 	struct ib_qp *tx_qp;
435ea6dc203SHaggai Eran 	unsigned long flags;
436ea6dc203SHaggai Eran 	int ret;
437d16e91daSHaggai Eran 
438ea6dc203SHaggai Eran 	for (; wr; wr = wr->next) {
439ea6dc203SHaggai Eran 		struct ib_ud_wr cur_wr = *ud_wr(wr);
440ea6dc203SHaggai Eran 
441ea6dc203SHaggai Eran 		cur_wr.wr.next = NULL;
442ea6dc203SHaggai Eran 
443ea6dc203SHaggai Eran 		spin_lock_irqsave(&gsi->lock, flags);
44483cae2afSHaggai Eran 		tx_qp = get_tx_qp(gsi, &cur_wr);
44583cae2afSHaggai Eran 		if (!tx_qp) {
446f8225e34SLeon Romanovsky 			ret = mlx5_ib_gsi_silent_drop(mqp, &cur_wr);
44783cae2afSHaggai Eran 			if (ret)
44883cae2afSHaggai Eran 				goto err;
44983cae2afSHaggai Eran 			spin_unlock_irqrestore(&gsi->lock, flags);
45083cae2afSHaggai Eran 			continue;
45183cae2afSHaggai Eran 		}
45283cae2afSHaggai Eran 
453f8225e34SLeon Romanovsky 		ret = mlx5_ib_add_outstanding_wr(mqp, &cur_wr, NULL);
454ea6dc203SHaggai Eran 		if (ret)
455ea6dc203SHaggai Eran 			goto err;
456ea6dc203SHaggai Eran 
45783cae2afSHaggai Eran 		ret = ib_post_send(tx_qp, &cur_wr.wr, bad_wr);
458ea6dc203SHaggai Eran 		if (ret) {
459ea6dc203SHaggai Eran 			/* Undo the effect of adding the outstanding wr */
460b5671afeSPrabhath Sajeepa 			gsi->outstanding_pi--;
461ea6dc203SHaggai Eran 			goto err;
462ea6dc203SHaggai Eran 		}
463ea6dc203SHaggai Eran 		spin_unlock_irqrestore(&gsi->lock, flags);
464ea6dc203SHaggai Eran 	}
465ea6dc203SHaggai Eran 
466ea6dc203SHaggai Eran 	return 0;
467ea6dc203SHaggai Eran 
468ea6dc203SHaggai Eran err:
469ea6dc203SHaggai Eran 	spin_unlock_irqrestore(&gsi->lock, flags);
470ea6dc203SHaggai Eran 	*bad_wr = wr;
471ea6dc203SHaggai Eran 	return ret;
472d16e91daSHaggai Eran }
473d16e91daSHaggai Eran 
mlx5_ib_gsi_post_recv(struct ib_qp * qp,const struct ib_recv_wr * wr,const struct ib_recv_wr ** bad_wr)474d34ac5cdSBart Van Assche int mlx5_ib_gsi_post_recv(struct ib_qp *qp, const struct ib_recv_wr *wr,
475d34ac5cdSBart Van Assche 			  const struct ib_recv_wr **bad_wr)
476d16e91daSHaggai Eran {
477f8225e34SLeon Romanovsky 	struct mlx5_ib_qp *mqp = to_mqp(qp);
478f8225e34SLeon Romanovsky 	struct mlx5_ib_gsi_qp *gsi = &mqp->gsi;
479d16e91daSHaggai Eran 
480d16e91daSHaggai Eran 	return ib_post_recv(gsi->rx_qp, wr, bad_wr);
481d16e91daSHaggai Eran }
4827722f47eSHaggai Eran 
mlx5_ib_gsi_pkey_change(struct mlx5_ib_gsi_qp * gsi)4837722f47eSHaggai Eran void mlx5_ib_gsi_pkey_change(struct mlx5_ib_gsi_qp *gsi)
4847722f47eSHaggai Eran {
4858c9e7f03SLeon Romanovsky 	u16 qp_index;
4867722f47eSHaggai Eran 
4878c9e7f03SLeon Romanovsky 	for (qp_index = 0; qp_index < gsi->num_qps; ++qp_index)
4888c9e7f03SLeon Romanovsky 		setup_qp(gsi, qp_index);
4897722f47eSHaggai Eran }
490