summaryrefslogtreecommitdiff
path: root/drivers/infiniband/sw/rdmavt/qp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/sw/rdmavt/qp.c')
-rw-r--r--drivers/infiniband/sw/rdmavt/qp.c194
1 files changed, 69 insertions, 125 deletions
diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c
index e9f3d356b361..134a79eecfcb 100644
--- a/drivers/infiniband/sw/rdmavt/qp.c
+++ b/drivers/infiniband/sw/rdmavt/qp.c
@@ -1,48 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright(c) 2016 - 2020 Intel Corporation.
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * BSD LICENSE
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * - Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
*/
#include <linux/hash.h>
@@ -139,7 +97,7 @@ static void cacheless_memcpy(void *dst, void *src, size_t n)
* there are no security issues. The extra fault recovery machinery
* is not invoked.
*/
- __copy_user_nocache(dst, (void __user *)src, n, 0);
+ __copy_user_nocache(dst, (void __user *)src, n);
}
void rvt_wss_exit(struct rvt_dev_info *rdi)
@@ -506,8 +464,6 @@ void rvt_qp_exit(struct rvt_dev_info *rdi)
if (qps_inuse)
rvt_pr_err(rdi, "QP memory leak! %u still in use\n",
qps_inuse);
- if (!rdi->qp_dev)
- return;
kfree(rdi->qp_dev->qp_table);
free_qpn_table(&rdi->qp_dev->qpn_table);
@@ -536,7 +492,7 @@ static int alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
{
u32 i, offset, max_scan, qpn;
struct rvt_qpn_map *map;
- u32 ret;
+ int ret;
u32 max_qpn = exclude_prefix == RVT_AIP_QP_PREFIX ?
RVT_AIP_QPN_MAX : RVT_QPN_MAX;
@@ -554,7 +510,8 @@ static int alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
else
qpt->flags |= n;
spin_unlock(&qpt->lock);
- goto bail;
+
+ return ret;
}
qpn = qpt->last + qpt->incr;
@@ -574,7 +531,8 @@ static int alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
if (!test_and_set_bit(offset, map->page)) {
qpt->last = qpn;
ret = qpn;
- goto bail;
+
+ return ret;
}
offset += qpt->incr;
/*
@@ -609,10 +567,7 @@ static int alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
qpn = mk_qpn(qpt, map, offset);
}
- ret = -ENOMEM;
-
-bail:
- return ret;
+ return -ENOMEM;
}
/**
@@ -1058,7 +1013,7 @@ static int alloc_ud_wq_attr(struct rvt_qp *qp, int node)
/**
* rvt_create_qp - create a queue pair for a device
- * @ibpd: the protection domain who's device we create the queue pair for
+ * @ibqp: the queue pair
* @init_attr: the attributes of the queue pair
* @udata: user data for libibverbs.so
*
@@ -1066,47 +1021,45 @@ static int alloc_ud_wq_attr(struct rvt_qp *qp, int node)
* unique idea of what queue pair numbers mean. For instance there is a reserved
* range for PSM.
*
- * Return: the queue pair on success, otherwise returns an errno.
+ * Return: 0 on success, otherwise returns an errno.
*
* Called by the ib_create_qp() core verbs function.
*/
-struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
- struct ib_qp_init_attr *init_attr,
- struct ib_udata *udata)
+int rvt_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
{
- struct rvt_qp *qp;
- int err;
+ struct rvt_qp *qp = ibqp_to_rvtqp(ibqp);
+ int ret = -ENOMEM;
struct rvt_swqe *swq = NULL;
size_t sz;
- size_t sg_list_sz;
- struct ib_qp *ret = ERR_PTR(-ENOMEM);
- struct rvt_dev_info *rdi = ib_to_rvt(ibpd->device);
+ size_t sg_list_sz = 0;
+ struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device);
void *priv = NULL;
size_t sqsize;
u8 exclude_prefix = 0;
if (!rdi)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (init_attr->create_flags & ~IB_QP_CREATE_NETDEV_USE)
- return ERR_PTR(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
if (init_attr->cap.max_send_sge > rdi->dparms.props.max_send_sge ||
init_attr->cap.max_send_wr > rdi->dparms.props.max_qp_wr)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
/* Check receive queue parameters if no SRQ is specified. */
if (!init_attr->srq) {
if (init_attr->cap.max_recv_sge >
rdi->dparms.props.max_recv_sge ||
init_attr->cap.max_recv_wr > rdi->dparms.props.max_qp_wr)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (init_attr->cap.max_send_sge +
init_attr->cap.max_send_wr +
init_attr->cap.max_recv_sge +
init_attr->cap.max_recv_wr == 0)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
sqsize =
init_attr->cap.max_send_wr + 1 +
@@ -1115,8 +1068,8 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
case IB_QPT_SMI:
case IB_QPT_GSI:
if (init_attr->port_num == 0 ||
- init_attr->port_num > ibpd->device->phys_port_cnt)
- return ERR_PTR(-EINVAL);
+ init_attr->port_num > ibqp->device->phys_port_cnt)
+ return -EINVAL;
fallthrough;
case IB_QPT_UC:
case IB_QPT_RC:
@@ -1124,10 +1077,8 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
sz = struct_size(swq, sg_list, init_attr->cap.max_send_sge);
swq = vzalloc_node(array_size(sz, sqsize), rdi->dparms.node);
if (!swq)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
- sz = sizeof(*qp);
- sg_list_sz = 0;
if (init_attr->srq) {
struct rvt_srq *srq = ibsrq_to_rvtsrq(init_attr->srq);
@@ -1137,10 +1088,10 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
} else if (init_attr->cap.max_recv_sge > 1)
sg_list_sz = sizeof(*qp->r_sg_list) *
(init_attr->cap.max_recv_sge - 1);
- qp = kzalloc_node(sz + sg_list_sz, GFP_KERNEL,
- rdi->dparms.node);
- if (!qp)
- goto bail_swq;
+ qp->r_sg_list =
+ kzalloc_node(sg_list_sz, GFP_KERNEL, rdi->dparms.node);
+ if (!qp->r_sg_list)
+ goto bail_qp;
qp->allowed_ops = get_allowed_ops(init_attr->qp_type);
RCU_INIT_POINTER(qp->next, NULL);
@@ -1155,9 +1106,8 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
}
/* initialize timers needed for rc qp */
timer_setup(&qp->s_timer, rvt_rc_timeout, 0);
- hrtimer_init(&qp->s_rnr_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- qp->s_rnr_timer.function = rvt_rc_rnr_retry;
+ hrtimer_setup(&qp->s_rnr_timer, rvt_rc_rnr_retry, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
/*
* Driver needs to set up it's private QP structure and do any
@@ -1165,7 +1115,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
*/
priv = rdi->driver_f.qp_priv_alloc(rdi, qp);
if (IS_ERR(priv)) {
- ret = priv;
+ ret = PTR_ERR(priv);
goto bail_qp;
}
qp->priv = priv;
@@ -1179,12 +1129,10 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
sizeof(struct rvt_rwqe);
- err = rvt_alloc_rq(&qp->r_rq, qp->r_rq.size * sz,
+ ret = rvt_alloc_rq(&qp->r_rq, qp->r_rq.size * sz,
rdi->dparms.node, udata);
- if (err) {
- ret = ERR_PTR(err);
+ if (ret)
goto bail_driver_priv;
- }
}
/*
@@ -1205,40 +1153,35 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
qp->s_max_sge = init_attr->cap.max_send_sge;
if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
qp->s_flags = RVT_S_SIGNAL_REQ_WR;
- err = alloc_ud_wq_attr(qp, rdi->dparms.node);
- if (err) {
- ret = (ERR_PTR(err));
+ ret = alloc_ud_wq_attr(qp, rdi->dparms.node);
+ if (ret)
goto bail_rq_rvt;
- }
if (init_attr->create_flags & IB_QP_CREATE_NETDEV_USE)
exclude_prefix = RVT_AIP_QP_PREFIX;
- err = alloc_qpn(rdi, &rdi->qp_dev->qpn_table,
+ ret = alloc_qpn(rdi, &rdi->qp_dev->qpn_table,
init_attr->qp_type,
init_attr->port_num,
exclude_prefix);
- if (err < 0) {
- ret = ERR_PTR(err);
+ if (ret < 0)
goto bail_rq_wq;
- }
- qp->ibqp.qp_num = err;
+
+ qp->ibqp.qp_num = ret;
if (init_attr->create_flags & IB_QP_CREATE_NETDEV_USE)
qp->ibqp.qp_num |= RVT_AIP_QP_BASE;
qp->port_num = init_attr->port_num;
rvt_init_qp(rdi, qp, init_attr->qp_type);
if (rdi->driver_f.qp_priv_init) {
- err = rdi->driver_f.qp_priv_init(rdi, qp, init_attr);
- if (err) {
- ret = ERR_PTR(err);
+ ret = rdi->driver_f.qp_priv_init(rdi, qp, init_attr);
+ if (ret)
goto bail_rq_wq;
- }
}
break;
default:
/* Don't support raw QPs */
- return ERR_PTR(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
init_attr->cap.max_inline_data = 0;
@@ -1251,28 +1194,24 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
if (!qp->r_rq.wq) {
__u64 offset = 0;
- err = ib_copy_to_udata(udata, &offset,
+ ret = ib_copy_to_udata(udata, &offset,
sizeof(offset));
- if (err) {
- ret = ERR_PTR(err);
+ if (ret)
goto bail_qpn;
- }
} else {
u32 s = sizeof(struct rvt_rwq) + qp->r_rq.size * sz;
qp->ip = rvt_create_mmap_info(rdi, s, udata,
qp->r_rq.wq);
if (IS_ERR(qp->ip)) {
- ret = ERR_CAST(qp->ip);
+ ret = PTR_ERR(qp->ip);
goto bail_qpn;
}
- err = ib_copy_to_udata(udata, &qp->ip->offset,
+ ret = ib_copy_to_udata(udata, &qp->ip->offset,
sizeof(qp->ip->offset));
- if (err) {
- ret = ERR_PTR(err);
+ if (ret)
goto bail_ip;
- }
}
qp->pid = current->pid;
}
@@ -1280,7 +1219,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
spin_lock(&rdi->n_qps_lock);
if (rdi->n_qps_allocated == rdi->dparms.props.max_qp) {
spin_unlock(&rdi->n_qps_lock);
- ret = ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
goto bail_ip;
}
@@ -1306,9 +1245,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
spin_unlock_irq(&rdi->pending_lock);
}
- ret = &qp->ibqp;
-
- return ret;
+ return 0;
bail_ip:
if (qp->ip)
@@ -1328,11 +1265,8 @@ bail_driver_priv:
bail_qp:
kfree(qp->s_ack_queue);
- kfree(qp);
-
-bail_swq:
+ kfree(qp->r_sg_list);
vfree(swq);
-
return ret;
}
@@ -1362,7 +1296,7 @@ int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err)
if (qp->s_flags & (RVT_S_TIMER | RVT_S_WAIT_RNR)) {
qp->s_flags &= ~(RVT_S_TIMER | RVT_S_WAIT_RNR);
- del_timer(&qp->s_timer);
+ timer_delete(&qp->s_timer);
}
if (qp->s_flags & RVT_S_ANY_WAIT_SEND)
@@ -1762,11 +1696,11 @@ int rvt_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
kvfree(qp->r_rq.kwq);
rdi->driver_f.qp_priv_free(rdi, qp);
kfree(qp->s_ack_queue);
+ kfree(qp->r_sg_list);
rdma_destroy_ah_attr(&qp->remote_ah_attr);
rdma_destroy_ah_attr(&qp->alt_ah_attr);
free_ud_wq_attr(qp);
vfree(qp->s_wq);
- kfree(qp);
return 0;
}
@@ -2102,7 +2036,7 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
wqe = rvt_get_swqe_ptr(qp, qp->s_head);
/* cplen has length from above */
- memcpy(&wqe->wr, wr, cplen);
+ memcpy(&wqe->ud_wr, wr, cplen);
wqe->length = 0;
j = 0;
@@ -2611,7 +2545,7 @@ void rvt_stop_rc_timers(struct rvt_qp *qp)
/* Remove QP from all timers */
if (qp->s_flags & (RVT_S_TIMER | RVT_S_WAIT_RNR)) {
qp->s_flags &= ~(RVT_S_TIMER | RVT_S_WAIT_RNR);
- del_timer(&qp->s_timer);
+ timer_delete(&qp->s_timer);
hrtimer_try_to_cancel(&qp->s_rnr_timer);
}
}
@@ -2640,7 +2574,7 @@ static void rvt_stop_rnr_timer(struct rvt_qp *qp)
*/
void rvt_del_timers_sync(struct rvt_qp *qp)
{
- del_timer_sync(&qp->s_timer);
+ timer_delete_sync(&qp->s_timer);
hrtimer_cancel(&qp->s_rnr_timer);
}
EXPORT_SYMBOL(rvt_del_timers_sync);
@@ -2650,7 +2584,7 @@ EXPORT_SYMBOL(rvt_del_timers_sync);
*/
static void rvt_rc_timeout(struct timer_list *t)
{
- struct rvt_qp *qp = from_timer(qp, t, s_timer);
+ struct rvt_qp *qp = timer_container_of(qp, t, s_timer);
struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
unsigned long flags;
@@ -2661,7 +2595,7 @@ static void rvt_rc_timeout(struct timer_list *t)
qp->s_flags &= ~RVT_S_TIMER;
rvp->n_rc_timeouts++;
- del_timer(&qp->s_timer);
+ timer_delete(&qp->s_timer);
trace_rvt_rc_timeout(qp, qp->s_last_psn + 1);
if (rdi->driver_f.notify_restart_rc)
rdi->driver_f.notify_restart_rc(qp,
@@ -2837,7 +2771,7 @@ void rvt_qp_iter(struct rvt_dev_info *rdi,
EXPORT_SYMBOL(rvt_qp_iter);
/*
- * This should be called with s_lock held.
+ * This should be called with s_lock and r_lock held.
*/
void rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
enum ib_wc_status status)
@@ -3135,6 +3069,8 @@ do_write:
case IB_WR_ATOMIC_FETCH_AND_ADD:
if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
goto inv_err;
+ if (unlikely(wqe->atomic_wr.remote_addr & (sizeof(u64) - 1)))
+ goto inv_err;
if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
wqe->atomic_wr.remote_addr,
wqe->atomic_wr.rkey,
@@ -3194,7 +3130,9 @@ send_comp:
rvp->n_loop_pkts++;
flush_send:
sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
+ spin_lock(&sqp->r_lock);
rvt_send_complete(sqp, wqe, send_status);
+ spin_unlock(&sqp->r_lock);
if (local_ops) {
atomic_dec(&sqp->local_ops_pending);
local_ops = 0;
@@ -3248,9 +3186,15 @@ serr:
spin_unlock_irqrestore(&qp->r_lock, flags);
serr_no_r_lock:
spin_lock_irqsave(&sqp->s_lock, flags);
+ spin_lock(&sqp->r_lock);
rvt_send_complete(sqp, wqe, send_status);
+ spin_unlock(&sqp->r_lock);
if (sqp->ibqp.qp_type == IB_QPT_RC) {
- int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
+ int lastwqe;
+
+ spin_lock(&sqp->r_lock);
+ lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
+ spin_unlock(&sqp->r_lock);
sqp->s_flags &= ~RVT_S_BUSY;
spin_unlock_irqrestore(&sqp->s_lock, flags);