2006-02-27 22:39:52

by Chris Wright

[permalink] [raw]
Subject: [patch 39/39] [PATCH] IB/mthca: max_inline_data handling tweaks

-stable review patch. If anyone has any objections, please let us know.
------------------

Fix a case where copying max_inline_data from a successful create_qp
capabilities output to create_qp input could cause EINVAL error:

mthca_set_qp_size must check max_inline_data directly against
max_desc_sz; checking qp->sq.max_gs is wrong since max_inline_data
depends on the qp type and does not involve max_sg.

Signed-off-by: Jack Morgenstein <[email protected]>
Signed-off-by: "Michael S. Tsirkin" <[email protected]>
Signed-off-by: Roland Dreier <[email protected]>
Signed-off-by: Chris Wright <[email protected]>
---
fixes http://article.gmane.org/gmane.linux.drivers.openib/21118

drivers/infiniband/hw/mthca/mthca_qp.c | 62 +++++++++++++++++++--------------
1 files changed, 36 insertions(+), 26 deletions(-)

--- linux-2.6.15.4.orig/drivers/infiniband/hw/mthca/mthca_qp.c
+++ linux-2.6.15.4/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -885,18 +885,13 @@ int mthca_modify_qp(struct ib_qp *ibqp,
return err;
}

-static void mthca_adjust_qp_caps(struct mthca_dev *dev,
- struct mthca_pd *pd,
- struct mthca_qp *qp)
+static int mthca_max_data_size(struct mthca_dev *dev, struct mthca_qp *qp, int desc_sz)
{
- 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);
+ int max_data_size = desc_sz - sizeof (struct mthca_next_seg);

switch (qp->transport) {
case MLX:
@@ -915,11 +910,24 @@ static void mthca_adjust_qp_caps(struct
break;
}

+ return max_data_size;
+}
+
+static inline int mthca_max_inline_data(struct mthca_pd *pd, int max_data_size)
+{
/* 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;
+ return pd->ibpd.uobject ? max_data_size - MTHCA_INLINE_HEADER_SIZE : 0;
+}
+
+static void mthca_adjust_qp_caps(struct mthca_dev *dev,
+ struct mthca_pd *pd,
+ struct mthca_qp *qp)
+{
+ int max_data_size = mthca_max_data_size(dev, qp,
+ min(dev->limits.max_desc_sz,
+ 1 << qp->sq.wqe_shift));
+
+ qp->max_inline_data = mthca_max_inline_data(pd, max_data_size);

qp->sq.max_gs = min_t(int, dev->limits.max_sg,
max_data_size / sizeof (struct mthca_data_seg));
@@ -1186,13 +1194,23 @@ static int mthca_alloc_qp_common(struct
}

static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap,
- struct mthca_qp *qp)
+ struct mthca_pd *pd, struct mthca_qp *qp)
{
+ int max_data_size = mthca_max_data_size(dev, qp, dev->limits.max_desc_sz);
+
/* Sanity check QP size before proceeding */
- if (cap->max_send_wr > dev->limits.max_wqes ||
- cap->max_recv_wr > dev->limits.max_wqes ||
- cap->max_send_sge > dev->limits.max_sg ||
- cap->max_recv_sge > dev->limits.max_sg)
+ if (cap->max_send_wr > dev->limits.max_wqes ||
+ cap->max_recv_wr > dev->limits.max_wqes ||
+ cap->max_send_sge > dev->limits.max_sg ||
+ cap->max_recv_sge > dev->limits.max_sg ||
+ cap->max_inline_data > mthca_max_inline_data(pd, max_data_size))
+ return -EINVAL;
+
+ /*
+ * For MLX transport we need 2 extra S/G entries:
+ * one for the header and one for the checksum at the end
+ */
+ if (qp->transport == MLX && cap->max_recv_sge + 2 > dev->limits.max_sg)
return -EINVAL;

if (mthca_is_memfree(dev)) {
@@ -1211,14 +1229,6 @@ static int mthca_set_qp_size(struct mthc
MTHCA_INLINE_CHUNK_SIZE) /
sizeof (struct mthca_data_seg));

- /*
- * For MLX transport we need 2 extra S/G entries:
- * one for the header and one for the checksum at the end
- */
- if ((qp->transport == MLX && qp->sq.max_gs + 2 > dev->limits.max_sg) ||
- qp->sq.max_gs > dev->limits.max_sg || qp->rq.max_gs > dev->limits.max_sg)
- return -EINVAL;
-
return 0;
}

@@ -1233,7 +1243,7 @@ int mthca_alloc_qp(struct mthca_dev *dev
{
int err;

- err = mthca_set_qp_size(dev, cap, qp);
+ err = mthca_set_qp_size(dev, cap, pd, qp);
if (err)
return err;

@@ -1276,7 +1286,7 @@ int mthca_alloc_sqp(struct mthca_dev *de
u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1;
int err;

- err = mthca_set_qp_size(dev, cap, &sqp->qp);
+ err = mthca_set_qp_size(dev, cap, pd, &sqp->qp);
if (err)
return err;


--