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