2018-11-29 02:22:31 +08:00
|
|
|
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
|
|
|
/*
|
|
|
|
* Copyright(c) 2018 Intel Corporation.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "hfi.h"
|
|
|
|
#include "verbs.h"
|
|
|
|
#include "tid_rdma.h"
|
|
|
|
|
2019-01-24 11:20:42 +08:00
|
|
|
/*
|
|
|
|
* J_KEY for kernel contexts when TID RDMA is used.
|
|
|
|
* See generate_jkey() in hfi.h for more information.
|
|
|
|
*/
|
|
|
|
#define TID_RDMA_JKEY 32
|
|
|
|
#define HFI1_KERNEL_MIN_JKEY HFI1_ADMIN_JKEY_RANGE
|
|
|
|
#define HFI1_KERNEL_MAX_JKEY (2 * HFI1_ADMIN_JKEY_RANGE - 1)
|
|
|
|
|
|
|
|
#define TID_RDMA_MAX_READ_SEGS_PER_REQ 6
|
|
|
|
#define TID_RDMA_MAX_WRITE_SEGS_PER_REQ 4
|
|
|
|
|
|
|
|
#define TID_OPFN_QP_CTXT_MASK 0xff
|
|
|
|
#define TID_OPFN_QP_CTXT_SHIFT 56
|
|
|
|
#define TID_OPFN_QP_KDETH_MASK 0xff
|
|
|
|
#define TID_OPFN_QP_KDETH_SHIFT 48
|
|
|
|
#define TID_OPFN_MAX_LEN_MASK 0x7ff
|
|
|
|
#define TID_OPFN_MAX_LEN_SHIFT 37
|
|
|
|
#define TID_OPFN_TIMEOUT_MASK 0x1f
|
|
|
|
#define TID_OPFN_TIMEOUT_SHIFT 32
|
|
|
|
#define TID_OPFN_RESERVED_MASK 0x3f
|
|
|
|
#define TID_OPFN_RESERVED_SHIFT 26
|
|
|
|
#define TID_OPFN_URG_MASK 0x1
|
|
|
|
#define TID_OPFN_URG_SHIFT 25
|
|
|
|
#define TID_OPFN_VER_MASK 0x7
|
|
|
|
#define TID_OPFN_VER_SHIFT 22
|
|
|
|
#define TID_OPFN_JKEY_MASK 0x3f
|
|
|
|
#define TID_OPFN_JKEY_SHIFT 16
|
|
|
|
#define TID_OPFN_MAX_READ_MASK 0x3f
|
|
|
|
#define TID_OPFN_MAX_READ_SHIFT 10
|
|
|
|
#define TID_OPFN_MAX_WRITE_MASK 0x3f
|
|
|
|
#define TID_OPFN_MAX_WRITE_SHIFT 4
|
|
|
|
|
|
|
|
/*
|
|
|
|
* OPFN TID layout
|
|
|
|
*
|
|
|
|
* 63 47 31 15
|
|
|
|
* NNNNNNNNKKKKKKKK MMMMMMMMMMMTTTTT DDDDDDUVVVJJJJJJ RRRRRRWWWWWWCCCC
|
|
|
|
* 3210987654321098 7654321098765432 1098765432109876 5432109876543210
|
|
|
|
* N - the context Number
|
|
|
|
* K - the Kdeth_qp
|
|
|
|
* M - Max_len
|
|
|
|
* T - Timeout
|
|
|
|
* D - reserveD
|
|
|
|
* V - version
|
|
|
|
* U - Urg capable
|
|
|
|
* J - Jkey
|
|
|
|
* R - max_Read
|
|
|
|
* W - max_Write
|
|
|
|
* C - Capcode
|
|
|
|
*/
|
|
|
|
|
|
|
|
static u64 tid_rdma_opfn_encode(struct tid_rdma_params *p)
|
|
|
|
{
|
|
|
|
return
|
|
|
|
(((u64)p->qp & TID_OPFN_QP_CTXT_MASK) <<
|
|
|
|
TID_OPFN_QP_CTXT_SHIFT) |
|
|
|
|
((((u64)p->qp >> 16) & TID_OPFN_QP_KDETH_MASK) <<
|
|
|
|
TID_OPFN_QP_KDETH_SHIFT) |
|
|
|
|
(((u64)((p->max_len >> PAGE_SHIFT) - 1) &
|
|
|
|
TID_OPFN_MAX_LEN_MASK) << TID_OPFN_MAX_LEN_SHIFT) |
|
|
|
|
(((u64)p->timeout & TID_OPFN_TIMEOUT_MASK) <<
|
|
|
|
TID_OPFN_TIMEOUT_SHIFT) |
|
|
|
|
(((u64)p->urg & TID_OPFN_URG_MASK) << TID_OPFN_URG_SHIFT) |
|
|
|
|
(((u64)p->jkey & TID_OPFN_JKEY_MASK) << TID_OPFN_JKEY_SHIFT) |
|
|
|
|
(((u64)p->max_read & TID_OPFN_MAX_READ_MASK) <<
|
|
|
|
TID_OPFN_MAX_READ_SHIFT) |
|
|
|
|
(((u64)p->max_write & TID_OPFN_MAX_WRITE_MASK) <<
|
|
|
|
TID_OPFN_MAX_WRITE_SHIFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tid_rdma_opfn_decode(struct tid_rdma_params *p, u64 data)
|
|
|
|
{
|
|
|
|
p->max_len = (((data >> TID_OPFN_MAX_LEN_SHIFT) &
|
|
|
|
TID_OPFN_MAX_LEN_MASK) + 1) << PAGE_SHIFT;
|
|
|
|
p->jkey = (data >> TID_OPFN_JKEY_SHIFT) & TID_OPFN_JKEY_MASK;
|
|
|
|
p->max_write = (data >> TID_OPFN_MAX_WRITE_SHIFT) &
|
|
|
|
TID_OPFN_MAX_WRITE_MASK;
|
|
|
|
p->max_read = (data >> TID_OPFN_MAX_READ_SHIFT) &
|
|
|
|
TID_OPFN_MAX_READ_MASK;
|
|
|
|
p->qp =
|
|
|
|
((((data >> TID_OPFN_QP_KDETH_SHIFT) & TID_OPFN_QP_KDETH_MASK)
|
|
|
|
<< 16) |
|
|
|
|
((data >> TID_OPFN_QP_CTXT_SHIFT) & TID_OPFN_QP_CTXT_MASK));
|
|
|
|
p->urg = (data >> TID_OPFN_URG_SHIFT) & TID_OPFN_URG_MASK;
|
|
|
|
p->timeout = (data >> TID_OPFN_TIMEOUT_SHIFT) & TID_OPFN_TIMEOUT_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tid_rdma_opfn_init(struct rvt_qp *qp, struct tid_rdma_params *p)
|
|
|
|
{
|
|
|
|
struct hfi1_qp_priv *priv = qp->priv;
|
|
|
|
|
|
|
|
p->qp = (kdeth_qp << 16) | priv->rcd->ctxt;
|
|
|
|
p->max_len = TID_RDMA_MAX_SEGMENT_SIZE;
|
|
|
|
p->jkey = priv->rcd->jkey;
|
|
|
|
p->max_read = TID_RDMA_MAX_READ_SEGS_PER_REQ;
|
|
|
|
p->max_write = TID_RDMA_MAX_WRITE_SEGS_PER_REQ;
|
|
|
|
p->timeout = qp->timeout;
|
|
|
|
p->urg = is_urg_masked(priv->rcd);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tid_rdma_conn_req(struct rvt_qp *qp, u64 *data)
|
|
|
|
{
|
|
|
|
struct hfi1_qp_priv *priv = qp->priv;
|
|
|
|
|
|
|
|
*data = tid_rdma_opfn_encode(&priv->tid_rdma.local);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tid_rdma_conn_reply(struct rvt_qp *qp, u64 data)
|
|
|
|
{
|
|
|
|
struct hfi1_qp_priv *priv = qp->priv;
|
|
|
|
struct tid_rdma_params *remote, *old;
|
|
|
|
bool ret = true;
|
|
|
|
|
|
|
|
old = rcu_dereference_protected(priv->tid_rdma.remote,
|
|
|
|
lockdep_is_held(&priv->opfn.lock));
|
|
|
|
data &= ~0xfULL;
|
|
|
|
/*
|
|
|
|
* If data passed in is zero, return true so as not to continue the
|
|
|
|
* negotiation process
|
|
|
|
*/
|
|
|
|
if (!data || !HFI1_CAP_IS_KSET(TID_RDMA))
|
|
|
|
goto null;
|
|
|
|
/*
|
|
|
|
* If kzalloc fails, return false. This will result in:
|
|
|
|
* * at the requester a new OPFN request being generated to retry
|
|
|
|
* the negotiation
|
|
|
|
* * at the responder, 0 being returned to the requester so as to
|
|
|
|
* disable TID RDMA at both the requester and the responder
|
|
|
|
*/
|
|
|
|
remote = kzalloc(sizeof(*remote), GFP_ATOMIC);
|
|
|
|
if (!remote) {
|
|
|
|
ret = false;
|
|
|
|
goto null;
|
|
|
|
}
|
|
|
|
|
|
|
|
tid_rdma_opfn_decode(remote, data);
|
|
|
|
priv->tid_timer_timeout_jiffies =
|
|
|
|
usecs_to_jiffies((((4096UL * (1UL << remote->timeout)) /
|
|
|
|
1000UL) << 3) * 7);
|
|
|
|
rcu_assign_pointer(priv->tid_rdma.remote, remote);
|
|
|
|
/*
|
|
|
|
* A TID RDMA READ request's segment size is not equal to
|
|
|
|
* remote->max_len only when the request's data length is smaller
|
|
|
|
* than remote->max_len. In that case, there will be only one segment.
|
|
|
|
* Therefore, when priv->pkts_ps is used to calculate req->cur_seg
|
|
|
|
* during retry, it will lead to req->cur_seg = 0, which is exactly
|
|
|
|
* what is expected.
|
|
|
|
*/
|
|
|
|
priv->pkts_ps = (u16)rvt_div_mtu(qp, remote->max_len);
|
|
|
|
priv->timeout_shift = ilog2(priv->pkts_ps - 1) + 1;
|
|
|
|
goto free;
|
|
|
|
null:
|
|
|
|
RCU_INIT_POINTER(priv->tid_rdma.remote, NULL);
|
|
|
|
priv->timeout_shift = 0;
|
|
|
|
free:
|
|
|
|
if (old)
|
|
|
|
kfree_rcu(old, rcu_head);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tid_rdma_conn_resp(struct rvt_qp *qp, u64 *data)
|
|
|
|
{
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
ret = tid_rdma_conn_reply(qp, *data);
|
|
|
|
*data = 0;
|
|
|
|
/*
|
|
|
|
* If tid_rdma_conn_reply() returns error, set *data as 0 to indicate
|
|
|
|
* TID RDMA could not be enabled. This will result in TID RDMA being
|
|
|
|
* disabled at the requester too.
|
|
|
|
*/
|
|
|
|
if (ret)
|
|
|
|
(void)tid_rdma_conn_req(qp, data);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tid_rdma_conn_error(struct rvt_qp *qp)
|
|
|
|
{
|
|
|
|
struct hfi1_qp_priv *priv = qp->priv;
|
|
|
|
struct tid_rdma_params *old;
|
|
|
|
|
|
|
|
old = rcu_dereference_protected(priv->tid_rdma.remote,
|
|
|
|
lockdep_is_held(&priv->opfn.lock));
|
|
|
|
RCU_INIT_POINTER(priv->tid_rdma.remote, NULL);
|
|
|
|
if (old)
|
|
|
|
kfree_rcu(old, rcu_head);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is called at context initialization time */
|
|
|
|
int hfi1_kern_exp_rcv_init(struct hfi1_ctxtdata *rcd, int reinit)
|
|
|
|
{
|
|
|
|
if (reinit)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
BUILD_BUG_ON(TID_RDMA_JKEY < HFI1_KERNEL_MIN_JKEY);
|
|
|
|
BUILD_BUG_ON(TID_RDMA_JKEY > HFI1_KERNEL_MAX_JKEY);
|
|
|
|
rcd->jkey = TID_RDMA_JKEY;
|
|
|
|
hfi1_set_ctxt_jkey(rcd->dd, rcd, rcd->jkey);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-29 02:22:31 +08:00
|
|
|
/**
|
|
|
|
* qp_to_rcd - determine the receive context used by a qp
|
|
|
|
* @qp - the qp
|
|
|
|
*
|
|
|
|
* This routine returns the receive context associated
|
|
|
|
* with a a qp's qpn.
|
|
|
|
*
|
|
|
|
* Returns the context.
|
|
|
|
*/
|
|
|
|
static struct hfi1_ctxtdata *qp_to_rcd(struct rvt_dev_info *rdi,
|
|
|
|
struct rvt_qp *qp)
|
|
|
|
{
|
|
|
|
struct hfi1_ibdev *verbs_dev = container_of(rdi,
|
|
|
|
struct hfi1_ibdev,
|
|
|
|
rdi);
|
|
|
|
struct hfi1_devdata *dd = container_of(verbs_dev,
|
|
|
|
struct hfi1_devdata,
|
|
|
|
verbs_dev);
|
|
|
|
unsigned int ctxt;
|
|
|
|
|
|
|
|
if (qp->ibqp.qp_num == 0)
|
|
|
|
ctxt = 0;
|
|
|
|
else
|
|
|
|
ctxt = ((qp->ibqp.qp_num >> dd->qos_shift) %
|
|
|
|
(dd->n_krcv_queues - 1)) + 1;
|
|
|
|
|
|
|
|
return dd->rcd[ctxt];
|
|
|
|
}
|
|
|
|
|
|
|
|
int hfi1_qp_priv_init(struct rvt_dev_info *rdi, struct rvt_qp *qp,
|
|
|
|
struct ib_qp_init_attr *init_attr)
|
|
|
|
{
|
|
|
|
struct hfi1_qp_priv *qpriv = qp->priv;
|
|
|
|
|
|
|
|
qpriv->rcd = qp_to_rcd(rdi, qp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|