[IB] uverbs: have kernel return QP capabilities
Move the computation of QP capabilities (max scatter/gather entries, max inline data, etc) into the kernel, and have the uverbs module return the values as part of the create QP response. This keeps precise knowledge of device limits in the low-level kernel driver. This requires an ABI bump, so while we're making changes, get rid of the max_sge parameter for the modify SRQ command -- it's not used and shouldn't be there. Signed-off-by: Jack Morgenstein <jackm@mellanox.co.il> Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:

committed by
Roland Dreier

parent
ec914c52d6
commit
77369ed31d
@@ -1060,6 +1060,8 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
|
||||
dev_lim->hca.arbel.resize_srq = field & 1;
|
||||
MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET);
|
||||
dev_lim->max_sg = min_t(int, field, dev_lim->max_sg);
|
||||
MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET);
|
||||
dev_lim->max_desc_sz = min_t(int, size, dev_lim->max_desc_sz);
|
||||
MTHCA_GET(size, outbox, QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET);
|
||||
dev_lim->mpt_entry_sz = size;
|
||||
MTHCA_GET(field, outbox, QUERY_DEV_LIM_PBL_SZ_OFFSET);
|
||||
|
@@ -131,6 +131,7 @@ struct mthca_limits {
|
||||
int max_sg;
|
||||
int num_qps;
|
||||
int max_wqes;
|
||||
int max_desc_sz;
|
||||
int max_qp_init_rdma;
|
||||
int reserved_qps;
|
||||
int num_srqs;
|
||||
|
@@ -168,6 +168,7 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim
|
||||
mdev->limits.max_srq_wqes = dev_lim->max_srq_sz;
|
||||
mdev->limits.reserved_srqs = dev_lim->reserved_srqs;
|
||||
mdev->limits.reserved_eecs = dev_lim->reserved_eecs;
|
||||
mdev->limits.max_desc_sz = dev_lim->max_desc_sz;
|
||||
/*
|
||||
* Subtract 1 from the limit because we need to allocate a
|
||||
* spare CQE so the HCA HW can tell the difference between an
|
||||
|
@@ -616,11 +616,11 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
init_attr->cap.max_inline_data = 0;
|
||||
init_attr->cap.max_send_wr = qp->sq.max;
|
||||
init_attr->cap.max_recv_wr = qp->rq.max;
|
||||
init_attr->cap.max_send_sge = qp->sq.max_gs;
|
||||
init_attr->cap.max_recv_sge = qp->rq.max_gs;
|
||||
init_attr->cap.max_inline_data = qp->max_inline_data;
|
||||
|
||||
return &qp->ibqp;
|
||||
}
|
||||
|
@@ -251,6 +251,7 @@ struct mthca_qp {
|
||||
struct mthca_wq sq;
|
||||
enum ib_sig_type sq_policy;
|
||||
int send_wqe_offset;
|
||||
int max_inline_data;
|
||||
|
||||
u64 *wrid;
|
||||
union mthca_buf queue;
|
||||
|
@@ -885,6 +885,48 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mthca_adjust_qp_caps(struct mthca_dev *dev,
|
||||
struct mthca_pd *pd,
|
||||
struct mthca_qp *qp)
|
||||
{
|
||||
int max_data_size;
|
||||
|
||||
/*
|
||||
* Calculate the maximum size of WQE s/g segments, excluding
|
||||
* the next segment and other non-data segments.
|
||||
*/
|
||||
max_data_size = min(dev->limits.max_desc_sz, 1 << qp->sq.wqe_shift) -
|
||||
sizeof (struct mthca_next_seg);
|
||||
|
||||
switch (qp->transport) {
|
||||
case MLX:
|
||||
max_data_size -= 2 * sizeof (struct mthca_data_seg);
|
||||
break;
|
||||
|
||||
case UD:
|
||||
if (mthca_is_memfree(dev))
|
||||
max_data_size -= sizeof (struct mthca_arbel_ud_seg);
|
||||
else
|
||||
max_data_size -= sizeof (struct mthca_tavor_ud_seg);
|
||||
break;
|
||||
|
||||
default:
|
||||
max_data_size -= sizeof (struct mthca_raddr_seg);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We don't support inline data for kernel QPs (yet). */
|
||||
if (!pd->ibpd.uobject)
|
||||
qp->max_inline_data = 0;
|
||||
else
|
||||
qp->max_inline_data = max_data_size - MTHCA_INLINE_HEADER_SIZE;
|
||||
|
||||
qp->sq.max_gs = max_data_size / sizeof (struct mthca_data_seg);
|
||||
qp->rq.max_gs = (min(dev->limits.max_desc_sz, 1 << qp->rq.wqe_shift) -
|
||||
sizeof (struct mthca_next_seg)) /
|
||||
sizeof (struct mthca_data_seg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and register buffer for WQEs. qp->rq.max, sq.max,
|
||||
* rq.max_gs and sq.max_gs must all be assigned.
|
||||
@@ -902,27 +944,53 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
|
||||
size = sizeof (struct mthca_next_seg) +
|
||||
qp->rq.max_gs * sizeof (struct mthca_data_seg);
|
||||
|
||||
if (size > dev->limits.max_desc_sz)
|
||||
return -EINVAL;
|
||||
|
||||
for (qp->rq.wqe_shift = 6; 1 << qp->rq.wqe_shift < size;
|
||||
qp->rq.wqe_shift++)
|
||||
; /* nothing */
|
||||
|
||||
size = sizeof (struct mthca_next_seg) +
|
||||
qp->sq.max_gs * sizeof (struct mthca_data_seg);
|
||||
size = qp->sq.max_gs * sizeof (struct mthca_data_seg);
|
||||
switch (qp->transport) {
|
||||
case MLX:
|
||||
size += 2 * sizeof (struct mthca_data_seg);
|
||||
break;
|
||||
|
||||
case UD:
|
||||
if (mthca_is_memfree(dev))
|
||||
size += sizeof (struct mthca_arbel_ud_seg);
|
||||
else
|
||||
size += sizeof (struct mthca_tavor_ud_seg);
|
||||
size += mthca_is_memfree(dev) ?
|
||||
sizeof (struct mthca_arbel_ud_seg) :
|
||||
sizeof (struct mthca_tavor_ud_seg);
|
||||
break;
|
||||
|
||||
case UC:
|
||||
size += sizeof (struct mthca_raddr_seg);
|
||||
break;
|
||||
|
||||
case RC:
|
||||
size += sizeof (struct mthca_raddr_seg);
|
||||
/*
|
||||
* An atomic op will require an atomic segment, a
|
||||
* remote address segment and one scatter entry.
|
||||
*/
|
||||
size = max_t(int, size,
|
||||
sizeof (struct mthca_atomic_seg) +
|
||||
sizeof (struct mthca_raddr_seg) +
|
||||
sizeof (struct mthca_data_seg));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* bind seg is as big as atomic + raddr segs */
|
||||
size += sizeof (struct mthca_bind_seg);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make sure that we have enough space for a bind request */
|
||||
size = max_t(int, size, sizeof (struct mthca_bind_seg));
|
||||
|
||||
size += sizeof (struct mthca_next_seg);
|
||||
|
||||
if (size > dev->limits.max_desc_sz)
|
||||
return -EINVAL;
|
||||
|
||||
for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size;
|
||||
qp->sq.wqe_shift++)
|
||||
; /* nothing */
|
||||
@@ -1066,6 +1134,8 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
mthca_adjust_qp_caps(dev, pd, qp);
|
||||
|
||||
/*
|
||||
* If this is a userspace QP, we're done now. The doorbells
|
||||
* will be allocated and buffers will be initialized in
|
||||
|
Reference in New Issue
Block a user