Linux RDMA and InfiniBand development
 help / color / mirror / Atom feed
* [PATCH v2 07/10] iw_cxgb4: Add CQ management functions.
From: Steve Wise @ 2010-04-09 20:54 UTC (permalink / raw)
  To: linux-rdma-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20100409205336.9813.84868.stgit-T4OLL4TyM9aNDNWfRnPdfg@public.gmane.org>

Signed-off-by: Steve Wise <swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org>
---

 drivers/infiniband/hw/cxgb4/cq.c |  882 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 882 insertions(+), 0 deletions(-)
 create mode 100644 drivers/infiniband/hw/cxgb4/cq.c

diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
new file mode 100644
index 0000000..6b4b6f0
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -0,0 +1,882 @@
+/*
+ * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "iw_cxgb4.h"
+
+static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+		      struct c4iw_dev_ucontext *uctx)
+{
+	struct fw_ri_res_wr *res_wr;
+	struct fw_ri_res *res;
+	int wr_len;
+	struct c4iw_wr_wait wr_wait;
+	struct sk_buff *skb;
+	int ret;
+
+	wr_len = sizeof *res_wr + sizeof *res;
+	skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+	if (!skb)
+		return -ENOMEM;
+	set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
+
+	res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
+	memset(res_wr, 0, wr_len);
+	res_wr->op_nres = cpu_to_be32(
+			FW_WR_OP(FW_RI_RES_WR) |
+			V_FW_RI_RES_WR_NRES(1) |
+			FW_WR_COMPL(1));
+	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
+	res_wr->cookie = (u64)&wr_wait;
+	res = res_wr->res;
+	res->u.cq.restype = FW_RI_RES_TYPE_CQ;
+	res->u.cq.op = FW_RI_RES_OP_RESET;
+	res->u.cq.iqid = cpu_to_be32(cq->cqid);
+
+	c4iw_init_wr_wait(&wr_wait);
+	ret = c4iw_ofld_send(rdev, skb);
+	if (!ret) {
+		wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
+		if (!wr_wait.done) {
+			printk(KERN_ERR MOD "Device %s not responding!\n",
+			       pci_name(rdev->lldi.pdev));
+			rdev->flags = T4_FATAL_ERROR;
+			ret = -EIO;
+		} else
+			ret = wr_wait.ret;
+	}
+
+	kfree(cq->sw_queue);
+	dma_free_coherent(&(rdev->lldi.pdev->dev),
+			  cq->memsize, cq->queue,
+			  pci_unmap_addr(cq, mapping));
+	c4iw_put_cqid(rdev, cq->cqid, uctx);
+	return ret;
+}
+
+static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+		     struct c4iw_dev_ucontext *uctx)
+{
+	struct fw_ri_res_wr *res_wr;
+	struct fw_ri_res *res;
+	int wr_len;
+	int user = (uctx != &rdev->uctx);
+	struct c4iw_wr_wait wr_wait;
+	int ret;
+	struct sk_buff *skb;
+
+	cq->cqid = c4iw_get_cqid(rdev, uctx);
+	if (!cq->cqid) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	if (!user) {
+		cq->sw_queue = kzalloc(cq->memsize, GFP_KERNEL);
+		if (!cq->sw_queue) {
+			ret = -ENOMEM;
+			goto err2;
+		}
+	}
+	cq->queue = dma_alloc_coherent(&rdev->lldi.pdev->dev, cq->memsize,
+				       &cq->dma_addr, GFP_KERNEL);
+	if (!cq->queue) {
+		ret = -ENOMEM;
+		goto err3;
+	}
+	pci_unmap_addr_set(cq, mapping, cq->dma_addr);
+	memset(cq->queue, 0, cq->memsize);
+
+	/* build fw_ri_res_wr */
+	wr_len = sizeof *res_wr + sizeof *res;
+
+	skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+	if (!skb) {
+		ret = -ENOMEM;
+		goto err4;
+	}
+	set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
+
+	res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
+	memset(res_wr, 0, wr_len);
+	res_wr->op_nres = cpu_to_be32(
+			FW_WR_OP(FW_RI_RES_WR) |
+			V_FW_RI_RES_WR_NRES(1) |
+			FW_WR_COMPL(1));
+	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
+	res_wr->cookie = (u64)&wr_wait;
+	res = res_wr->res;
+	res->u.cq.restype = FW_RI_RES_TYPE_CQ;
+	res->u.cq.op = FW_RI_RES_OP_WRITE;
+	res->u.cq.iqid = cpu_to_be32(cq->cqid);
+	res->u.cq.iqandst_to_iqandstindex = cpu_to_be32(
+			V_FW_RI_RES_WR_IQANUS(0) |
+			V_FW_RI_RES_WR_IQANUD(1) |
+			F_FW_RI_RES_WR_IQANDST |
+			V_FW_RI_RES_WR_IQANDSTINDEX(*rdev->lldi.rxq_ids));
+	res->u.cq.iqdroprss_to_iqesize = cpu_to_be16(
+			F_FW_RI_RES_WR_IQDROPRSS |
+			V_FW_RI_RES_WR_IQPCIECH(2) |
+			V_FW_RI_RES_WR_IQINTCNTTHRESH(0) |
+			F_FW_RI_RES_WR_IQO |
+			V_FW_RI_RES_WR_IQESIZE(1));
+	res->u.cq.iqsize = cpu_to_be16(cq->size);
+	res->u.cq.iqaddr = cpu_to_be64(cq->dma_addr);
+
+	c4iw_init_wr_wait(&wr_wait);
+
+	ret = c4iw_ofld_send(rdev, skb);
+	if (ret)
+		goto err4;
+	PDBG("%s wait_event wr_wait %p\n", __func__, &wr_wait);
+	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
+	if (!wr_wait.done) {
+		printk(KERN_ERR MOD "Device %s not responding!\n",
+		       pci_name(rdev->lldi.pdev));
+		rdev->flags = T4_FATAL_ERROR;
+		ret = -EIO;
+	} else
+		ret = wr_wait.ret;
+	if (ret)
+		goto err4;
+
+	cq->gen = 1;
+	cq->gts = rdev->lldi.gts_reg;
+	cq->rdev = rdev;
+	if (user) {
+		cq->ugts = (u64)pci_resource_start(rdev->lldi.pdev, 2) +
+					(cq->cqid << rdev->cqshift);
+		cq->ugts &= PAGE_MASK;
+	}
+	return 0;
+err4:
+	dma_free_coherent(&rdev->lldi.pdev->dev, cq->memsize, cq->queue,
+			  pci_unmap_addr(cq, mapping));
+err3:
+	kfree(cq->sw_queue);
+err2:
+	c4iw_put_cqid(rdev, cq->cqid, uctx);
+err1:
+	return ret;
+}
+
+static void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq)
+{
+	struct t4_cqe cqe;
+
+	PDBG("%s wq %p cq %p sw_cidx %u sw_pidx %u\n", __func__,
+	     wq, cq, cq->sw_cidx, cq->sw_pidx);
+	memset(&cqe, 0, sizeof(cqe));
+	cqe.header = cpu_to_be32(V_CQE_STATUS(T4_ERR_SWFLUSH) |
+				 V_CQE_OPCODE(FW_RI_SEND) |
+				 V_CQE_TYPE(0) |
+				 V_CQE_SWCQE(1) |
+				 V_CQE_QPID(wq->rq.qid));
+	cqe.bits_type_ts = cpu_to_be64(V_CQE_GENBIT((u64)cq->gen));
+	cq->sw_queue[cq->sw_pidx] = cqe;
+	t4_swcq_produce(cq);
+}
+
+int c4iw_flush_rq(struct t4_wq *wq, struct t4_cq *cq, int count)
+{
+	int flushed = 0;
+	int in_use = wq->rq.in_use - count;
+
+	BUG_ON(in_use < 0);
+	PDBG("%s wq %p cq %p rq.in_use %u skip count %u\n", __func__,
+	     wq, cq, wq->rq.in_use, count);
+	while (in_use--) {
+		insert_recv_cqe(wq, cq);
+		flushed++;
+	}
+	return flushed;
+}
+
+static void insert_sq_cqe(struct t4_wq *wq, struct t4_cq *cq,
+			  struct t4_swsqe *swcqe)
+{
+	struct t4_cqe cqe;
+
+	PDBG("%s wq %p cq %p sw_cidx %u sw_pidx %u\n", __func__,
+	     wq, cq, cq->sw_cidx, cq->sw_pidx);
+	memset(&cqe, 0, sizeof(cqe));
+	cqe.header = cpu_to_be32(V_CQE_STATUS(T4_ERR_SWFLUSH) |
+				 V_CQE_OPCODE(swcqe->opcode) |
+				 V_CQE_TYPE(1) |
+				 V_CQE_SWCQE(1) |
+				 V_CQE_QPID(wq->sq.qid));
+	CQE_WRID_SQ_IDX(&cqe) = swcqe->idx;
+	cqe.bits_type_ts = cpu_to_be64(V_CQE_GENBIT((u64)cq->gen));
+	cq->sw_queue[cq->sw_pidx] = cqe;
+	t4_swcq_produce(cq);
+}
+
+int c4iw_flush_sq(struct t4_wq *wq, struct t4_cq *cq, int count)
+{
+	int flushed = 0;
+	struct t4_swsqe *swsqe = &wq->sq.sw_sq[wq->sq.cidx + count];
+	int in_use = wq->sq.in_use - count;
+
+	BUG_ON(in_use < 0);
+	while (in_use--) {
+		swsqe->signaled = 0;
+		insert_sq_cqe(wq, cq, swsqe);
+		swsqe++;
+		if (swsqe == (wq->sq.sw_sq + wq->sq.size))
+			swsqe = wq->sq.sw_sq;
+		flushed++;
+	}
+	return flushed;
+}
+
+/*
+ * Move all CQEs from the HWCQ into the SWCQ.
+ */
+void c4iw_flush_hw_cq(struct t4_cq *cq)
+{
+	struct t4_cqe *cqe = NULL, *swcqe;
+	int ret;
+
+	PDBG("%s cq %p cqid 0x%x\n", __func__, cq, cq->cqid);
+	ret = t4_next_hw_cqe(cq, &cqe);
+	while (!ret) {
+		PDBG("%s flushing hwcq cidx 0x%x swcq pidx 0x%x\n",
+		     __func__, cq->cidx, cq->sw_pidx);
+		swcqe = &cq->sw_queue[cq->sw_pidx];
+		*swcqe = *cqe;
+		swcqe->header |= cpu_to_be32(V_CQE_SWCQE(1));
+		t4_swcq_produce(cq);
+		t4_hwcq_consume(cq);
+		ret = t4_next_hw_cqe(cq, &cqe);
+	}
+}
+
+static int cqe_completes_wr(struct t4_cqe *cqe, struct t4_wq *wq)
+{
+	if (CQE_OPCODE(cqe) == FW_RI_TERMINATE)
+		return 0;
+
+	if ((CQE_OPCODE(cqe) == FW_RI_RDMA_WRITE) && RQ_TYPE(cqe))
+		return 0;
+
+	if ((CQE_OPCODE(cqe) == FW_RI_READ_RESP) && SQ_TYPE(cqe))
+		return 0;
+
+	if (CQE_SEND_OPCODE(cqe) && RQ_TYPE(cqe) && t4_rq_empty(wq))
+		return 0;
+	return 1;
+}
+
+void c4iw_count_scqes(struct t4_cq *cq, struct t4_wq *wq, int *count)
+{
+	struct t4_cqe *cqe;
+	u32 ptr;
+
+	*count = 0;
+	ptr = cq->sw_cidx;
+	while (ptr != cq->sw_pidx) {
+		cqe = &cq->sw_queue[ptr];
+		if ((SQ_TYPE(cqe) || ((CQE_OPCODE(cqe) == FW_RI_READ_RESP) &&
+				      wq->sq.oldest_read)) &&
+		    (CQE_QPID(cqe) == wq->sq.qid))
+			(*count)++;
+		if (++ptr == cq->size)
+			ptr = 0;
+	}
+	PDBG("%s cq %p count %d\n", __func__, cq, *count);
+}
+
+void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count)
+{
+	struct t4_cqe *cqe;
+	u32 ptr;
+
+	*count = 0;
+	PDBG("%s count zero %d\n", __func__, *count);
+	ptr = cq->sw_cidx;
+	while (ptr != cq->sw_pidx) {
+		cqe = &cq->sw_queue[ptr];
+		if (RQ_TYPE(cqe) && (CQE_OPCODE(cqe) != FW_RI_READ_RESP) &&
+		    (CQE_QPID(cqe) == wq->rq.qid) && cqe_completes_wr(cqe, wq))
+			(*count)++;
+		if (++ptr == cq->size)
+			ptr = 0;
+	}
+	PDBG("%s cq %p count %d\n", __func__, cq, *count);
+}
+
+static void flush_completed_wrs(struct t4_wq *wq, struct t4_cq *cq)
+{
+	struct t4_swsqe *swsqe;
+	u16 ptr = wq->sq.cidx;
+	int count = wq->sq.in_use;
+	int unsignaled = 0;
+
+	swsqe = &wq->sq.sw_sq[ptr];
+	while (count--)
+		if (!swsqe->signaled) {
+			if (++ptr == wq->sq.size)
+				ptr = 0;
+			swsqe = &wq->sq.sw_sq[ptr];
+			unsignaled++;
+		} else if (swsqe->complete) {
+
+			/*
+			 * Insert this completed cqe into the swcq.
+			 */
+			PDBG("%s moving cqe into swcq sq idx %u cq idx %u\n",
+			     __func__, ptr, cq->sw_pidx);
+			swsqe->cqe.header |= htonl(V_CQE_SWCQE(1));
+			cq->sw_queue[cq->sw_pidx] = swsqe->cqe;
+			t4_swcq_produce(cq);
+			swsqe->signaled = 0;
+			wq->sq.in_use -= unsignaled;
+			break;
+		} else
+			break;
+}
+
+static void create_read_req_cqe(struct t4_wq *wq, struct t4_cqe *hw_cqe,
+				struct t4_cqe *read_cqe)
+{
+	read_cqe->u.scqe.cidx = wq->sq.oldest_read->idx;
+	read_cqe->len = cpu_to_be32(wq->sq.oldest_read->read_len);
+	read_cqe->header = htonl(V_CQE_QPID(CQE_QPID(hw_cqe)) |
+				 V_CQE_SWCQE(SW_CQE(hw_cqe)) |
+				 V_CQE_OPCODE(FW_RI_READ_REQ) |
+				 V_CQE_TYPE(1));
+}
+
+/*
+ * Return a ptr to the next read wr in the SWSQ or NULL.
+ */
+static void advance_oldest_read(struct t4_wq *wq)
+{
+
+	u32 rptr = wq->sq.oldest_read - wq->sq.sw_sq + 1;
+
+	if (rptr == wq->sq.size)
+		rptr = 0;
+	while (rptr != wq->sq.pidx) {
+		wq->sq.oldest_read = &wq->sq.sw_sq[rptr];
+
+		if (wq->sq.oldest_read->opcode == FW_RI_READ_REQ)
+			return;
+		if (++rptr == wq->sq.size)
+			rptr = 0;
+	}
+	wq->sq.oldest_read = NULL;
+}
+
+/*
+ * poll_cq
+ *
+ * Caller must:
+ *     check the validity of the first CQE,
+ *     supply the wq assicated with the qpid.
+ *
+ * credit: cq credit to return to sge.
+ * cqe_flushed: 1 iff the CQE is flushed.
+ * cqe: copy of the polled CQE.
+ *
+ * return value:
+ *    0		    CQE returned ok.
+ *    -EAGAIN       CQE skipped, try again.
+ *    -EOVERFLOW    CQ overflow detected.
+ */
+static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+		   u8 *cqe_flushed, u64 *cookie, u32 *credit)
+{
+	int ret = 0;
+	struct t4_cqe *hw_cqe, read_cqe;
+
+	*cqe_flushed = 0;
+	*credit = 0;
+	ret = t4_next_cqe(cq, &hw_cqe);
+	if (ret)
+		return ret;
+
+	PDBG("%s CQE OVF %u qpid 0x%0x genbit %u type %u status 0x%0x"
+	     " opcode 0x%0x len 0x%0x wrid_hi_stag 0x%x wrid_low_msn 0x%x\n",
+	     __func__, CQE_OVFBIT(hw_cqe), CQE_QPID(hw_cqe),
+	     CQE_GENBIT(hw_cqe), CQE_TYPE(hw_cqe), CQE_STATUS(hw_cqe),
+	     CQE_OPCODE(hw_cqe), CQE_LEN(hw_cqe), CQE_WRID_HI(hw_cqe),
+	     CQE_WRID_LOW(hw_cqe));
+
+	/*
+	 * skip cqe's not affiliated with a QP.
+	 */
+	if (wq == NULL) {
+		ret = -EAGAIN;
+		goto skip_cqe;
+	}
+
+	/*
+	 * Gotta tweak READ completions:
+	 *	1) the cqe doesn't contain the sq_wptr from the wr.
+	 *	2) opcode not reflected from the wr.
+	 *	3) read_len not reflected from the wr.
+	 *	4) cq_type is RQ_TYPE not SQ_TYPE.
+	 */
+	if (RQ_TYPE(hw_cqe) && (CQE_OPCODE(hw_cqe) == FW_RI_READ_RESP)) {
+
+		/*
+		 * If this is an unsolicited read response, then the read
+		 * was generated by the kernel driver as part of peer-2-peer
+		 * connection setup.  So ignore the completion.
+		 */
+		if (!wq->sq.oldest_read) {
+			if (CQE_STATUS(hw_cqe))
+				t4_set_wq_in_error(wq);
+			ret = -EAGAIN;
+			goto skip_cqe;
+		}
+
+		/*
+		 * Don't write to the HWCQ, so create a new read req CQE
+		 * in local memory.
+		 */
+		create_read_req_cqe(wq, hw_cqe, &read_cqe);
+		hw_cqe = &read_cqe;
+		advance_oldest_read(wq);
+	}
+
+	if (CQE_STATUS(hw_cqe) || t4_wq_in_error(wq)) {
+		*cqe_flushed = t4_wq_in_error(wq);
+		t4_set_wq_in_error(wq);
+		goto proc_cqe;
+	}
+
+	/*
+	 * RECV completion.
+	 */
+	if (RQ_TYPE(hw_cqe)) {
+
+		/*
+		 * HW only validates 4 bits of MSN.  So we must validate that
+		 * the MSN in the SEND is the next expected MSN.  If its not,
+		 * then we complete this with T4_ERR_MSN and mark the wq in
+		 * error.
+		 */
+
+		if (t4_rq_empty(wq)) {
+			t4_set_wq_in_error(wq);
+			ret = -EAGAIN;
+			goto skip_cqe;
+		}
+		if (unlikely((CQE_WRID_MSN(hw_cqe) != (wq->rq.msn)))) {
+			t4_set_wq_in_error(wq);
+			hw_cqe->header |= htonl(V_CQE_STATUS(T4_ERR_MSN));
+			goto proc_cqe;
+		}
+		goto proc_cqe;
+	}
+
+	/*
+	 * If we get here its a send completion.
+	 *
+	 * Handle out of order completion. These get stuffed
+	 * in the SW SQ. Then the SW SQ is walked to move any
+	 * now in-order completions into the SW CQ.  This handles
+	 * 2 cases:
+	 *	1) reaping unsignaled WRs when the first subsequent
+	 *	   signaled WR is completed.
+	 *	2) out of order read completions.
+	 */
+	if (!SW_CQE(hw_cqe) && (CQE_WRID_SQ_IDX(hw_cqe) != wq->sq.cidx)) {
+		struct t4_swsqe *swsqe;
+
+		PDBG("%s out of order completion going in sw_sq at idx %u\n",
+		     __func__, CQE_WRID_SQ_IDX(hw_cqe));
+		swsqe = &wq->sq.sw_sq[CQE_WRID_SQ_IDX(hw_cqe)];
+		swsqe->cqe = *hw_cqe;
+		swsqe->complete = 1;
+		ret = -EAGAIN;
+		goto flush_wq;
+	}
+
+proc_cqe:
+	*cqe = *hw_cqe;
+
+	/*
+	 * Reap the associated WR(s) that are freed up with this
+	 * completion.
+	 */
+	if (SQ_TYPE(hw_cqe)) {
+		wq->sq.cidx = CQE_WRID_SQ_IDX(hw_cqe);
+		PDBG("%s completing sq idx %u\n", __func__, wq->sq.cidx);
+		*cookie = wq->sq.sw_sq[wq->sq.cidx].wr_id;
+		t4_sq_consume(wq);
+	} else {
+		PDBG("%s completing rq idx %u\n", __func__, wq->rq.cidx);
+		*cookie = wq->rq.sw_rq[wq->rq.cidx].wr_id;
+		BUG_ON(t4_rq_empty(wq));
+		t4_rq_consume(wq);
+	}
+
+flush_wq:
+	/*
+	 * Flush any completed cqes that are now in-order.
+	 */
+	flush_completed_wrs(wq, cq);
+
+skip_cqe:
+	if (SW_CQE(hw_cqe)) {
+		PDBG("%s cq %p cqid 0x%x skip sw cqe cidx %u\n",
+		     __func__, cq, cq->cqid, cq->sw_cidx);
+		t4_swcq_consume(cq);
+	} else {
+		PDBG("%s cq %p cqid 0x%x skip hw cqe cidx %u\n",
+		     __func__, cq, cq->cqid, cq->cidx);
+		t4_hwcq_consume(cq);
+	}
+	return ret;
+}
+
+/*
+ * Get one cq entry from c4iw and map it to openib.
+ *
+ * Returns:
+ *	0			cqe returned
+ *	-ENODATA		EMPTY;
+ *	-EAGAIN			caller must try again
+ *	any other -errno	fatal error
+ */
+static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
+{
+	struct c4iw_qp *qhp = NULL;
+	struct t4_cqe cqe = {0, 0}, *rd_cqe;
+	struct t4_wq *wq;
+	u32 credit = 0;
+	u8 cqe_flushed;
+	u64 cookie = 0;
+	int ret;
+
+	ret = t4_next_cqe(&chp->cq, &rd_cqe);
+
+	if (ret)
+		return ret;
+
+	qhp = get_qhp(chp->rhp, CQE_QPID(rd_cqe));
+	if (!qhp)
+		wq = NULL;
+	else {
+		spin_lock(&qhp->lock);
+		wq = &(qhp->wq);
+	}
+	ret = poll_cq(wq, &(chp->cq), &cqe, &cqe_flushed, &cookie, &credit);
+	if (ret)
+		goto out;
+
+	wc->wr_id = cookie;
+	wc->qp = &qhp->ibqp;
+	wc->vendor_err = CQE_STATUS(&cqe);
+	wc->wc_flags = 0;
+
+	PDBG("%s qpid 0x%x type %d opcode %d status 0x%x len %u wrid hi 0x%x "
+	     "lo 0x%x cookie 0x%llx\n", __func__, CQE_QPID(&cqe),
+	     CQE_TYPE(&cqe), CQE_OPCODE(&cqe), CQE_STATUS(&cqe), CQE_LEN(&cqe),
+	     CQE_WRID_HI(&cqe), CQE_WRID_LOW(&cqe), (unsigned long long)cookie);
+
+	if (CQE_TYPE(&cqe) == 0) {
+		if (!CQE_STATUS(&cqe))
+			wc->byte_len = CQE_LEN(&cqe);
+		else
+			wc->byte_len = 0;
+		wc->opcode = IB_WC_RECV;
+		if (CQE_OPCODE(&cqe) == FW_RI_SEND_WITH_INV ||
+		    CQE_OPCODE(&cqe) == FW_RI_SEND_WITH_SE_INV) {
+			wc->ex.invalidate_rkey = CQE_WRID_STAG(&cqe);
+			wc->wc_flags |= IB_WC_WITH_INVALIDATE;
+		}
+	} else {
+		switch (CQE_OPCODE(&cqe)) {
+		case FW_RI_RDMA_WRITE:
+			wc->opcode = IB_WC_RDMA_WRITE;
+			break;
+		case FW_RI_READ_REQ:
+			wc->opcode = IB_WC_RDMA_READ;
+			wc->byte_len = CQE_LEN(&cqe);
+			break;
+		case FW_RI_SEND_WITH_INV:
+		case FW_RI_SEND_WITH_SE_INV:
+			wc->opcode = IB_WC_SEND;
+			wc->wc_flags |= IB_WC_WITH_INVALIDATE;
+			break;
+		case FW_RI_SEND:
+		case FW_RI_SEND_WITH_SE:
+			wc->opcode = IB_WC_SEND;
+			break;
+		case FW_RI_BIND_MW:
+			wc->opcode = IB_WC_BIND_MW;
+			break;
+
+		case FW_RI_LOCAL_INV:
+			wc->opcode = IB_WC_LOCAL_INV;
+			break;
+		case FW_RI_FAST_REGISTER:
+			wc->opcode = IB_WC_FAST_REG_MR;
+			break;
+		default:
+			printk(KERN_ERR MOD "Unexpected opcode %d "
+			       "in the CQE received for QPID=0x%0x\n",
+			       CQE_OPCODE(&cqe), CQE_QPID(&cqe));
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	if (cqe_flushed)
+		wc->status = IB_WC_WR_FLUSH_ERR;
+	else {
+
+		switch (CQE_STATUS(&cqe)) {
+		case T4_ERR_SUCCESS:
+			wc->status = IB_WC_SUCCESS;
+			break;
+		case T4_ERR_STAG:
+			wc->status = IB_WC_LOC_ACCESS_ERR;
+			break;
+		case T4_ERR_PDID:
+			wc->status = IB_WC_LOC_PROT_ERR;
+			break;
+		case T4_ERR_QPID:
+		case T4_ERR_ACCESS:
+			wc->status = IB_WC_LOC_ACCESS_ERR;
+			break;
+		case T4_ERR_WRAP:
+			wc->status = IB_WC_GENERAL_ERR;
+			break;
+		case T4_ERR_BOUND:
+			wc->status = IB_WC_LOC_LEN_ERR;
+			break;
+		case T4_ERR_INVALIDATE_SHARED_MR:
+		case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND:
+			wc->status = IB_WC_MW_BIND_ERR;
+			break;
+		case T4_ERR_CRC:
+		case T4_ERR_MARKER:
+		case T4_ERR_PDU_LEN_ERR:
+		case T4_ERR_OUT_OF_RQE:
+		case T4_ERR_DDP_VERSION:
+		case T4_ERR_RDMA_VERSION:
+		case T4_ERR_DDP_QUEUE_NUM:
+		case T4_ERR_MSN:
+		case T4_ERR_TBIT:
+		case T4_ERR_MO:
+		case T4_ERR_MSN_RANGE:
+		case T4_ERR_IRD_OVERFLOW:
+		case T4_ERR_OPCODE:
+			wc->status = IB_WC_FATAL_ERR;
+			break;
+		case T4_ERR_SWFLUSH:
+			wc->status = IB_WC_WR_FLUSH_ERR;
+			break;
+		default:
+			printk(KERN_ERR MOD
+			       "Unexpected cqe_status 0x%x for QPID=0x%0x\n",
+			       CQE_STATUS(&cqe), CQE_QPID(&cqe));
+			ret = -EINVAL;
+		}
+	}
+out:
+	if (wq)
+		spin_unlock(&qhp->lock);
+	return ret;
+}
+
+int c4iw_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+	struct c4iw_cq *chp;
+	unsigned long flags;
+	int npolled;
+	int err = 0;
+
+	chp = to_c4iw_cq(ibcq);
+
+	spin_lock_irqsave(&chp->lock, flags);
+	for (npolled = 0; npolled < num_entries; ++npolled) {
+		do {
+			err = c4iw_poll_cq_one(chp, wc + npolled);
+		} while (err == -EAGAIN);
+		if (err)
+			break;
+	}
+	spin_unlock_irqrestore(&chp->lock, flags);
+	return !err || err == -ENODATA ? npolled : err;
+}
+
+int c4iw_destroy_cq(struct ib_cq *ib_cq)
+{
+	struct c4iw_cq *chp;
+	struct c4iw_ucontext *ucontext;
+
+	PDBG("%s ib_cq %p\n", __func__, ib_cq);
+	chp = to_c4iw_cq(ib_cq);
+
+	remove_handle(chp->rhp, &chp->rhp->cqidr, chp->cq.cqid);
+	atomic_dec(&chp->refcnt);
+	wait_event(chp->wait, !atomic_read(&chp->refcnt));
+
+	ucontext = ib_cq->uobject ? to_c4iw_ucontext(ib_cq->uobject->context)
+				  : NULL;
+	destroy_cq(&chp->rhp->rdev, &chp->cq,
+		   ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx);
+	kfree(chp);
+	return 0;
+}
+
+struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
+			     int vector, struct ib_ucontext *ib_context,
+			     struct ib_udata *udata)
+{
+	struct c4iw_dev *rhp;
+	struct c4iw_cq *chp;
+	struct c4iw_create_cq_resp uresp;
+	struct c4iw_ucontext *ucontext = NULL;
+	int ret;
+	size_t memsize;
+	struct c4iw_mm_entry *mm, *mm2;
+
+	PDBG("%s ib_dev %p entries %d\n", __func__, ibdev, entries);
+
+	rhp = to_c4iw_dev(ibdev);
+
+	chp = kzalloc(sizeof(*chp), GFP_KERNEL);
+	if (!chp)
+		return ERR_PTR(-ENOMEM);
+
+	if (ib_context)
+		ucontext = to_c4iw_ucontext(ib_context);
+
+	/* account for the status page. */
+	entries++;
+
+	/*
+	 * entries must be multiple of 16 for HW.
+	 */
+	entries = roundup(entries, 16);
+	memsize = entries * sizeof *chp->cq.queue;
+
+	/*
+	 * memsize must be a multiple of the page size if its a user cq.
+	 */
+	if (ucontext)
+		memsize = roundup(memsize, PAGE_SIZE);
+	chp->cq.size = entries;
+	chp->cq.memsize = memsize;
+
+	ret = create_cq(&rhp->rdev, &chp->cq,
+			ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+	if (ret)
+		goto err1;
+
+	chp->rhp = rhp;
+	chp->cq.size--;				/* status page */
+	chp->ibcq.cqe = chp->cq.size;
+	spin_lock_init(&chp->lock);
+	atomic_set(&chp->refcnt, 1);
+	init_waitqueue_head(&chp->wait);
+	ret = insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid);
+	if (ret)
+		goto err2;
+
+	if (ucontext) {
+		mm = kmalloc(sizeof *mm, GFP_KERNEL);
+		if (!mm)
+			goto err3;
+		mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
+		if (!mm2)
+			goto err4;
+
+		uresp.qid_mask = rhp->rdev.cqmask;
+		uresp.cqid = chp->cq.cqid;
+		uresp.size = chp->cq.size;
+		uresp.memsize = chp->cq.memsize;
+		spin_lock(&ucontext->mmap_lock);
+		uresp.key = ucontext->key;
+		ucontext->key += PAGE_SIZE;
+		uresp.gts_key = ucontext->key;
+		ucontext->key += PAGE_SIZE;
+		spin_unlock(&ucontext->mmap_lock);
+		ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
+		if (ret)
+			goto err5;
+
+		mm->key = uresp.key;
+		mm->addr = virt_to_phys(chp->cq.queue);
+		mm->len = chp->cq.memsize;
+		insert_mmap(ucontext, mm);
+
+		mm2->key = uresp.gts_key;
+		mm2->addr = chp->cq.ugts;
+		mm2->len = PAGE_SIZE;
+		insert_mmap(ucontext, mm2);
+	}
+	PDBG("%s cqid 0x%0x chp %p size %u memsize %lu, dma_addr 0x%0llx\n",
+	     __func__, chp->cq.cqid, chp, chp->cq.size,
+	     chp->cq.memsize,
+	     (unsigned long long) chp->cq.dma_addr);
+	return &chp->ibcq;
+err5:
+	kfree(mm2);
+err4:
+	kfree(mm);
+err3:
+	remove_handle(rhp, &rhp->cqidr, chp->cq.cqid);
+err2:
+	destroy_cq(&chp->rhp->rdev, &chp->cq,
+		   ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+err1:
+	kfree(chp);
+	return ERR_PTR(ret);
+}
+
+int c4iw_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
+{
+	return -ENOSYS;
+}
+
+int c4iw_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+{
+	struct c4iw_cq *chp;
+	int ret;
+	unsigned long flag;
+
+	chp = to_c4iw_cq(ibcq);
+	spin_lock_irqsave(&chp->lock, flag);
+	ret = t4_arm_cq(&chp->cq,
+			(flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED);
+	spin_unlock_irqrestore(&chp->lock, flag);
+	if (ret && !(flags & IB_CQ_REPORT_MISSED_EVENTS))
+		ret = 0;
+	return ret;
+}

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 08/10] iw_cxgb4: Add QP management functions.
From: Steve Wise @ 2010-04-09 20:54 UTC (permalink / raw)
  To: linux-rdma-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20100409205336.9813.84868.stgit-T4OLL4TyM9aNDNWfRnPdfg@public.gmane.org>

Signed-off-by: Steve Wise <swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org>
---

 drivers/infiniband/hw/cxgb4/qp.c | 1542 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 1542 insertions(+), 0 deletions(-)
 create mode 100644 drivers/infiniband/hw/cxgb4/qp.c

diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
new file mode 100644
index 0000000..6f71192
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -0,0 +1,1542 @@
+/*
+ * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "iw_cxgb4.h"
+
+static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+		      struct c4iw_dev_ucontext *uctx)
+{
+	/*
+	 * uP clears EQ contexts when the connection exits rdma mode,
+	 * so no need to post a RESET WR for these EQs.
+	 */
+	dma_free_coherent(&(rdev->lldi.pdev->dev),
+			  wq->rq.memsize, wq->rq.queue,
+			  pci_unmap_addr(&wq->rq, mapping));
+	dma_free_coherent(&(rdev->lldi.pdev->dev),
+			  wq->sq.memsize, wq->sq.queue,
+			  pci_unmap_addr(&wq->sq, mapping));
+	c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
+	kfree(wq->rq.sw_rq);
+	kfree(wq->sq.sw_sq);
+	c4iw_put_qpid(rdev, wq->rq.qid, uctx);
+	c4iw_put_qpid(rdev, wq->sq.qid, uctx);
+	return 0;
+}
+
+static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+		     struct t4_cq *rcq, struct t4_cq *scq,
+		     struct c4iw_dev_ucontext *uctx)
+{
+	int user = (uctx != &rdev->uctx);
+	struct fw_ri_res_wr *res_wr;
+	struct fw_ri_res *res;
+	int wr_len;
+	struct c4iw_wr_wait wr_wait;
+	struct sk_buff *skb;
+	int ret;
+	int eqsize;
+
+	wq->sq.qid = c4iw_get_qpid(rdev, uctx);
+	if (!wq->sq.qid)
+		return -ENOMEM;
+
+	wq->rq.qid = c4iw_get_qpid(rdev, uctx);
+	if (!wq->rq.qid)
+		goto err1;
+
+	if (!user) {
+		wq->sq.sw_sq = kzalloc(wq->sq.size * sizeof *wq->sq.sw_sq,
+				 GFP_KERNEL);
+		if (!wq->sq.sw_sq)
+			goto err2;
+
+		wq->rq.sw_rq = kzalloc(wq->rq.size * sizeof *wq->rq.sw_rq,
+				 GFP_KERNEL);
+		if (!wq->rq.sw_rq)
+			goto err3;
+	}
+
+	/*
+	 * RQT must be a power of 2.
+	 */
+	wq->rq.rqt_size = roundup_pow_of_two(wq->rq.size);
+	wq->rq.rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rq.rqt_size);
+	if (!wq->rq.rqt_hwaddr)
+		goto err4;
+
+	wq->sq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
+					  wq->sq.memsize, &(wq->sq.dma_addr),
+					  GFP_KERNEL);
+	if (!wq->sq.queue)
+		goto err5;
+	memset(wq->sq.queue, 0, wq->sq.memsize);
+	pci_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
+
+	wq->rq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
+					  wq->rq.memsize, &(wq->rq.dma_addr),
+					  GFP_KERNEL);
+	if (!wq->rq.queue)
+		goto err6;
+	PDBG("%s sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n",
+		__func__, wq->sq.queue, virt_to_phys(wq->sq.queue),
+		wq->rq.queue, virt_to_phys(wq->rq.queue));
+	memset(wq->rq.queue, 0, wq->rq.memsize);
+	pci_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr);
+
+	wq->db = rdev->lldi.db_reg;
+	wq->gts = rdev->lldi.gts_reg;
+	if (user) {
+		wq->sq.udb = (u64)pci_resource_start(rdev->lldi.pdev, 2) +
+					(wq->sq.qid << rdev->qpshift);
+		wq->sq.udb &= PAGE_MASK;
+		wq->rq.udb = (u64)pci_resource_start(rdev->lldi.pdev, 2) +
+					(wq->rq.qid << rdev->qpshift);
+		wq->rq.udb &= PAGE_MASK;
+	}
+	wq->rdev = rdev;
+	wq->rq.msn = 1;
+
+	/* build fw_ri_res_wr */
+	wr_len = sizeof *res_wr + 2 * sizeof *res;
+
+	skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+	if (!skb) {
+		ret = -ENOMEM;
+		goto err7;
+	}
+	set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
+
+	res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
+	memset(res_wr, 0, wr_len);
+	res_wr->op_nres = cpu_to_be32(
+			FW_WR_OP(FW_RI_RES_WR) |
+			V_FW_RI_RES_WR_NRES(2) |
+			FW_WR_COMPL(1));
+	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
+	res_wr->cookie = (u64)&wr_wait;
+	res = res_wr->res;
+	res->u.sqrq.restype = FW_RI_RES_TYPE_SQ;
+	res->u.sqrq.op = FW_RI_RES_OP_WRITE;
+
+	/*
+	 * eqsize is the number of 64B entries plus the status page size.
+	 */
+	eqsize = wq->sq.size * T4_SQ_NUM_SLOTS + T4_EQ_STATUS_ENTRIES;
+
+	res->u.sqrq.fetchszm_to_iqid = cpu_to_be32(
+		V_FW_RI_RES_WR_HOSTFCMODE(0) |	/* no host cidx updates */
+		V_FW_RI_RES_WR_CPRIO(0) |	/* don't keep in chip cache */
+		V_FW_RI_RES_WR_PCIECHN(0) |	/* set by uP at ri_init time */
+		V_FW_RI_RES_WR_IQID(scq->cqid));
+	res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
+		V_FW_RI_RES_WR_DCAEN(0) |
+		V_FW_RI_RES_WR_DCACPU(0) |
+		V_FW_RI_RES_WR_FBMIN(3) |
+		V_FW_RI_RES_WR_FBMAX(3) |
+		V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
+		V_FW_RI_RES_WR_CIDXFTHRESH(0) |
+		V_FW_RI_RES_WR_EQSIZE(eqsize));
+	res->u.sqrq.eqid = cpu_to_be32(wq->sq.qid);
+	res->u.sqrq.eqaddr = cpu_to_be64(wq->sq.dma_addr);
+	res++;
+	res->u.sqrq.restype = FW_RI_RES_TYPE_RQ;
+	res->u.sqrq.op = FW_RI_RES_OP_WRITE;
+
+	/*
+	 * eqsize is the number of 64B entries plus the status page size.
+	 */
+	eqsize = wq->rq.size * T4_RQ_NUM_SLOTS + T4_EQ_STATUS_ENTRIES;
+	res->u.sqrq.fetchszm_to_iqid = cpu_to_be32(
+		V_FW_RI_RES_WR_HOSTFCMODE(0) |	/* no host cidx updates */
+		V_FW_RI_RES_WR_CPRIO(0) |	/* don't keep in chip cache */
+		V_FW_RI_RES_WR_PCIECHN(0) |	/* set by uP at ri_init time */
+		V_FW_RI_RES_WR_IQID(rcq->cqid));
+	res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
+		V_FW_RI_RES_WR_DCAEN(0) |
+		V_FW_RI_RES_WR_DCACPU(0) |
+		V_FW_RI_RES_WR_FBMIN(3) |
+		V_FW_RI_RES_WR_FBMAX(3) |
+		V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
+		V_FW_RI_RES_WR_CIDXFTHRESH(0) |
+		V_FW_RI_RES_WR_EQSIZE(eqsize));
+	res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid);
+	res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr);
+
+	c4iw_init_wr_wait(&wr_wait);
+
+	ret = c4iw_ofld_send(rdev, skb);
+	if (ret)
+		goto err7;
+	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
+	if (!wr_wait.done) {
+		printk(KERN_ERR MOD "Device %s not responding!\n",
+		       pci_name(rdev->lldi.pdev));
+		rdev->flags = T4_FATAL_ERROR;
+		ret = -EIO;
+	} else
+		ret = wr_wait.ret;
+	if (ret)
+		goto err7;
+
+	PDBG("%s sqid 0x%x rqid 0x%x kdb 0x%p squdb 0x%llx rqudb 0x%llx\n",
+	     __func__, wq->sq.qid, wq->rq.qid, wq->db,
+	     (unsigned long long)wq->sq.udb, (unsigned long long)wq->rq.udb);
+
+	return 0;
+err7:
+	dma_free_coherent(&(rdev->lldi.pdev->dev),
+			  wq->rq.memsize, wq->rq.queue,
+			  pci_unmap_addr(&wq->rq, mapping));
+err6:
+	dma_free_coherent(&(rdev->lldi.pdev->dev),
+			  wq->sq.memsize, wq->sq.queue,
+			  pci_unmap_addr(&wq->sq, mapping));
+err5:
+	c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
+err4:
+	kfree(wq->rq.sw_rq);
+err3:
+	kfree(wq->sq.sw_sq);
+err2:
+	c4iw_put_qpid(rdev, wq->rq.qid, uctx);
+err1:
+	c4iw_put_qpid(rdev, wq->sq.qid, uctx);
+	return -ENOMEM;
+}
+
+static int build_rdma_send(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+{
+	int i;
+	u32 plen;
+	int size;
+	u8 *datap;
+
+	if (wr->num_sge > T4_MAX_SEND_SGE)
+		return -EINVAL;
+	switch (wr->opcode) {
+	case IB_WR_SEND:
+		if (wr->send_flags & IB_SEND_SOLICITED)
+			wqe->send.sendop_pkd = cpu_to_be32(
+				V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_SE));
+		else
+			wqe->send.sendop_pkd = cpu_to_be32(
+				V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND));
+		wqe->send.stag_inv = 0;
+		break;
+	case IB_WR_SEND_WITH_INV:
+		if (wr->send_flags & IB_SEND_SOLICITED)
+			wqe->send.sendop_pkd = cpu_to_be32(
+				V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_SE_INV));
+		else
+			wqe->send.sendop_pkd = cpu_to_be32(
+				V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_INV));
+		wqe->send.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	plen = 0;
+	if (wr->num_sge) {
+		if (wr->send_flags & IB_SEND_INLINE) {
+			datap = (u8 *)wqe->send.immd_src[0].data;
+			for (i = 0; i < wr->num_sge; i++) {
+				if ((plen + wr->sg_list[i].length) >
+				    T4_MAX_SEND_INLINE) {
+					return -EMSGSIZE;
+				}
+				plen += wr->sg_list[i].length;
+				memcpy(datap,
+				     (void *)(unsigned long)wr->sg_list[i].addr,
+				     wr->sg_list[i].length);
+				datap += wr->sg_list[i].length;
+			}
+			wqe->send.immd_src[0].op = FW_RI_DATA_IMMD;
+			wqe->send.immd_src[0].r1 = 0;
+			wqe->send.immd_src[0].r2 = 0;
+			wqe->send.immd_src[0].immdlen = cpu_to_be32(plen);
+			size = sizeof wqe->send + sizeof(struct fw_ri_immd) +
+			       plen;
+		} else {
+			for (i = 0; i < wr->num_sge; i++) {
+				if ((plen + wr->sg_list[i].length) < plen)
+					return -EMSGSIZE;
+				plen += wr->sg_list[i].length;
+				wqe->send.isgl_src[0].sge[i].stag =
+					cpu_to_be32(wr->sg_list[i].lkey);
+				wqe->send.isgl_src[0].sge[i].len =
+					cpu_to_be32(wr->sg_list[i].length);
+				wqe->send.isgl_src[0].sge[i].to =
+					cpu_to_be64(wr->sg_list[i].addr);
+			}
+			wqe->send.isgl_src[0].op = FW_RI_DATA_ISGL;
+			wqe->send.isgl_src[0].r1 = 0;
+			wqe->send.isgl_src[0].nsge = cpu_to_be16(wr->num_sge);
+			wqe->send.isgl_src[0].r2 = 0;
+			size = sizeof wqe->send + sizeof(struct fw_ri_isgl) +
+			       wr->num_sge * sizeof(struct fw_ri_sge);
+		}
+	} else {
+		wqe->send.immd_src[0].op = FW_RI_DATA_IMMD;
+		wqe->send.immd_src[0].r1 = 0;
+		wqe->send.immd_src[0].r2 = 0;
+		wqe->send.immd_src[0].immdlen = 0;
+		size = sizeof wqe->send + sizeof(struct fw_ri_immd);
+	}
+	*len16 = DIV_ROUND_UP(size, 16);
+	wqe->send.plen = cpu_to_be32(plen);
+	return 0;
+}
+
+static int build_rdma_write(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+{
+	int i;
+	u32 plen;
+	int size;
+	u8 *datap;
+
+	if (wr->num_sge > T4_MAX_WRITE_SGE)
+		return -EINVAL;
+	wqe->write.r2 = 0;
+	wqe->write.stag_sink = cpu_to_be32(wr->wr.rdma.rkey);
+	wqe->write.to_sink = cpu_to_be64(wr->wr.rdma.remote_addr);
+	plen = 0;
+	if (wr->num_sge) {
+		if (wr->send_flags & IB_SEND_INLINE) {
+			datap = (u8 *)wqe->write.immd_src[0].data;
+			for (i = 0; i < wr->num_sge; i++) {
+				if ((plen + wr->sg_list[i].length) >
+				    T4_MAX_WRITE_INLINE) {
+					return -EMSGSIZE;
+				}
+				plen += wr->sg_list[i].length;
+				memcpy(datap,
+				     (void *)(unsigned long)wr->sg_list[i].addr,
+				     wr->sg_list[i].length);
+				datap += wr->sg_list[i].length;
+			}
+			wqe->write.immd_src[0].op = FW_RI_DATA_IMMD;
+			wqe->write.immd_src[0].r1 = 0;
+			wqe->write.immd_src[0].r2 = 0;
+			wqe->write.immd_src[0].immdlen = cpu_to_be32(plen);
+			size = sizeof wqe->write + sizeof(struct fw_ri_immd) +
+			       plen;
+		} else {
+			for (i = 0; i < wr->num_sge; i++) {
+				if ((plen + wr->sg_list[i].length) < plen)
+					return -EMSGSIZE;
+				plen += wr->sg_list[i].length;
+				wqe->write.isgl_src[0].sge[i].stag =
+					cpu_to_be32(wr->sg_list[i].lkey);
+				wqe->write.isgl_src[0].sge[i].len =
+					cpu_to_be32(wr->sg_list[i].length);
+				wqe->write.isgl_src[0].sge[i].to =
+					cpu_to_be64(wr->sg_list[i].addr);
+			}
+			wqe->write.isgl_src[0].op = FW_RI_DATA_ISGL;
+			wqe->write.isgl_src[0].r1 = 0;
+			wqe->write.isgl_src[0].nsge = cpu_to_be16(wr->num_sge);
+			wqe->write.isgl_src[0].r2 = 0;
+			size = sizeof wqe->write + sizeof(struct fw_ri_isgl) +
+			       wr->num_sge * sizeof(struct fw_ri_sge);
+		}
+	} else {
+		wqe->write.immd_src[0].op = FW_RI_DATA_IMMD;
+		wqe->write.immd_src[0].r1 = 0;
+		wqe->write.immd_src[0].r2 = 0;
+		wqe->write.immd_src[0].immdlen = 0;
+		size = sizeof wqe->write + sizeof(struct fw_ri_immd);
+	}
+	*len16 = DIV_ROUND_UP(size, 16);
+	wqe->write.plen = cpu_to_be32(plen);
+	return 0;
+}
+
+static int build_rdma_read(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+{
+	if (wr->num_sge > 1)
+		return -EINVAL;
+	if (wr->num_sge) {
+		wqe->read.stag_src = cpu_to_be32(wr->wr.rdma.rkey);
+		wqe->read.to_src_hi = cpu_to_be32((u32)(wr->wr.rdma.remote_addr
+							>> 32));
+		wqe->read.to_src_lo = cpu_to_be32((u32)wr->wr.rdma.remote_addr);
+		wqe->read.stag_sink = cpu_to_be32(wr->sg_list[0].lkey);
+		wqe->read.plen = cpu_to_be32(wr->sg_list[0].length);
+		wqe->read.to_sink_hi = cpu_to_be32((u32)(wr->sg_list[0].addr
+							 >> 32));
+		wqe->read.to_sink_lo = cpu_to_be32((u32)(wr->sg_list[0].addr));
+	} else {
+		wqe->read.stag_src = cpu_to_be32(2);
+		wqe->read.to_src_hi = 0;
+		wqe->read.to_src_lo = 0;
+		wqe->read.stag_sink = cpu_to_be32(2);
+		wqe->read.plen = 0;
+		wqe->read.to_sink_hi = 0;
+		wqe->read.to_sink_lo = 0;
+	}
+	wqe->read.r2 = 0;
+	wqe->read.r5 = 0;
+	*len16 = DIV_ROUND_UP(sizeof wqe->read, 16);
+	return 0;
+}
+
+static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
+			   struct ib_recv_wr *wr, u8 *len16)
+{
+	int i;
+	int plen = 0;
+
+	for (i = 0; i < wr->num_sge; i++) {
+		if ((plen + wr->sg_list[i].length) < plen)
+			return -EMSGSIZE;
+		plen += wr->sg_list[i].length;
+		wqe->recv.isgl.sge[i].stag =
+			cpu_to_be32(wr->sg_list[i].lkey);
+		wqe->recv.isgl.sge[i].len =
+			cpu_to_be32(wr->sg_list[i].length);
+		wqe->recv.isgl.sge[i].to =
+			cpu_to_be64(wr->sg_list[i].addr);
+	}
+	for (; i < T4_MAX_RECV_SGE; i++) {
+		wqe->recv.isgl.sge[i].stag = 0;
+		wqe->recv.isgl.sge[i].len = 0;
+		wqe->recv.isgl.sge[i].to = 0;
+	}
+	wqe->recv.isgl.op = FW_RI_DATA_ISGL;
+	wqe->recv.isgl.r1 = 0;
+	wqe->recv.isgl.nsge = cpu_to_be16(wr->num_sge);
+	wqe->recv.isgl.r2 = 0;
+	*len16 = DIV_ROUND_UP(sizeof wqe->recv +
+			      wr->num_sge * sizeof(struct fw_ri_sge), 16);
+	return 0;
+}
+
+static int build_fastreg(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+{
+
+	struct fw_ri_immd *imdp;
+	__be64 *p;
+	int i;
+	int pbllen = roundup(wr->wr.fast_reg.page_list_len * sizeof(u64), 32);
+
+	if (wr->wr.fast_reg.page_list_len > T4_MAX_FR_DEPTH)
+		return -EINVAL;
+
+	wqe->fr.qpbinde_to_dcacpu = 0;
+	wqe->fr.pgsz_shift = wr->wr.fast_reg.page_shift - 12;
+	wqe->fr.addr_type = FW_RI_VA_BASED_TO;
+	wqe->fr.mem_perms = c4iw_ib_to_tpt_access(wr->wr.fast_reg.access_flags);
+	wqe->fr.len_hi = 0;
+	wqe->fr.len_lo = cpu_to_be32(wr->wr.fast_reg.length);
+	wqe->fr.stag = cpu_to_be32(wr->wr.fast_reg.rkey);
+	wqe->fr.va_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);
+	wqe->fr.va_lo_fbo = cpu_to_be32(wr->wr.fast_reg.iova_start &
+					0xffffffff);
+	if (pbllen > T4_MAX_FR_IMMD) {
+		struct c4iw_fr_page_list *c4pl =
+				to_c4iw_fr_page_list(wr->wr.fast_reg.page_list);
+		struct fw_ri_dsgl *sglp;
+
+		sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1);
+		sglp->op = FW_RI_DATA_DSGL;
+		sglp->r1 = 0;
+		sglp->nsge = cpu_to_be16(1);
+		sglp->addr0 = cpu_to_be64(c4pl->dma_addr);
+		sglp->len0 = cpu_to_be32(pbllen);
+
+		*len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *sglp, 16);
+	} else {
+		imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
+		imdp->op = FW_RI_DATA_IMMD;
+		imdp->r1 = 0;
+		imdp->r2 = 0;
+		imdp->immdlen = cpu_to_be32(pbllen);
+		p = (__be64 *)(imdp + 1);
+		for (i = 0; i < wr->wr.fast_reg.page_list_len; i++, p++)
+			*p = cpu_to_be64(
+				(u64)wr->wr.fast_reg.page_list->page_list[i]);
+		*len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen,
+				      16);
+	}
+	return 0;
+}
+
+static int build_inv_stag(union t4_wr *wqe, struct ib_send_wr *wr,
+			  u8 *len16)
+{
+	wqe->inv.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey);
+	wqe->inv.r2 = 0;
+	*len16 = DIV_ROUND_UP(sizeof wqe->inv, 16);
+	return 0;
+}
+
+void c4iw_qp_add_ref(struct ib_qp *qp)
+{
+	PDBG("%s ib_qp %p\n", __func__, qp);
+	atomic_inc(&(to_c4iw_qp(qp)->refcnt));
+}
+
+void c4iw_qp_rem_ref(struct ib_qp *qp)
+{
+	PDBG("%s ib_qp %p\n", __func__, qp);
+	if (atomic_dec_and_test(&(to_c4iw_qp(qp)->refcnt)))
+		wake_up(&(to_c4iw_qp(qp)->wait));
+}
+
+int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+		   struct ib_send_wr **bad_wr)
+{
+	int err = 0;
+	u8 len16 = 0;
+	enum fw_wr_opcodes fw_opcode = 0;
+	enum fw_ri_wr_flags fw_flags;
+	struct c4iw_qp *qhp;
+	union t4_wr *wqe;
+	u32 num_wrs;
+	struct t4_swsqe *swsqe;
+	unsigned long flag;
+	u16 idx = 0;
+
+	qhp = to_c4iw_qp(ibqp);
+	spin_lock_irqsave(&qhp->lock, flag);
+	if (t4_wq_in_error(&qhp->wq)) {
+		spin_unlock_irqrestore(&qhp->lock, flag);
+		return -EINVAL;
+	}
+	num_wrs = t4_sq_avail(&qhp->wq);
+	if (num_wrs == 0) {
+		spin_unlock_irqrestore(&qhp->lock, flag);
+		return -ENOMEM;
+	}
+	while (wr) {
+		if (num_wrs == 0) {
+			err = -ENOMEM;
+			*bad_wr = wr;
+			break;
+		}
+		wqe = &qhp->wq.sq.queue[qhp->wq.sq.pidx];
+		fw_flags = 0;
+		if (wr->send_flags & IB_SEND_SOLICITED)
+			fw_flags |= FW_RI_SOLICITED_EVENT_FLAG;
+		if (wr->send_flags & IB_SEND_SIGNALED)
+			fw_flags |= FW_RI_COMPLETION_FLAG;
+		swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx];
+		switch (wr->opcode) {
+		case IB_WR_SEND_WITH_INV:
+		case IB_WR_SEND:
+			if (wr->send_flags & IB_SEND_FENCE)
+				fw_flags |= FW_RI_READ_FENCE_FLAG;
+			fw_opcode = FW_RI_SEND_WR;
+			if (wr->opcode == IB_WR_SEND)
+				swsqe->opcode = FW_RI_SEND;
+			else
+				swsqe->opcode = FW_RI_SEND_WITH_INV;
+			err = build_rdma_send(wqe, wr, &len16);
+			break;
+		case IB_WR_RDMA_WRITE:
+			fw_opcode = FW_RI_RDMA_WRITE_WR;
+			swsqe->opcode = FW_RI_RDMA_WRITE;
+			err = build_rdma_write(wqe, wr, &len16);
+			break;
+		case IB_WR_RDMA_READ:
+			fw_opcode = FW_RI_RDMA_READ_WR;
+			swsqe->opcode = FW_RI_READ_REQ;
+			fw_flags = 0;
+			err = build_rdma_read(wqe, wr, &len16);
+			if (err)
+				break;
+			swsqe->read_len = wr->sg_list[0].length;
+			if (!qhp->wq.sq.oldest_read)
+				qhp->wq.sq.oldest_read = swsqe;
+			break;
+		case IB_WR_FAST_REG_MR:
+			fw_opcode = FW_RI_FR_NSMR_WR;
+			swsqe->opcode = FW_RI_FAST_REGISTER;
+			err = build_fastreg(wqe, wr, &len16);
+			break;
+		case IB_WR_LOCAL_INV:
+			fw_opcode = FW_RI_INV_LSTAG_WR;
+			swsqe->opcode = FW_RI_LOCAL_INV;
+			err = build_inv_stag(wqe, wr, &len16);
+			break;
+		default:
+			PDBG("%s post of type=%d TBD!\n", __func__,
+			     wr->opcode);
+			err = -EINVAL;
+		}
+		if (err) {
+			*bad_wr = wr;
+			break;
+		}
+		swsqe->idx = qhp->wq.sq.pidx;
+		swsqe->complete = 0;
+		swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED);
+		swsqe->wr_id = wr->wr_id;
+
+		init_wr_hdr(wqe, qhp->wq.sq.pidx, fw_opcode, fw_flags, len16);
+
+		PDBG("%s cookie 0x%llx pidx 0x%x opcode 0x%x read_len %u\n",
+		     __func__, (unsigned long long)wr->wr_id, qhp->wq.sq.pidx,
+		     swsqe->opcode, swsqe->read_len);
+		wr = wr->next;
+		num_wrs--;
+		t4_sq_produce(&qhp->wq);
+		idx++;
+	}
+	if (t4_wq_db_enabled(&qhp->wq))
+		t4_ring_sq_db(&qhp->wq, idx);
+	spin_unlock_irqrestore(&qhp->lock, flag);
+	return err;
+}
+
+int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+		      struct ib_recv_wr **bad_wr)
+{
+	int err = 0;
+	struct c4iw_qp *qhp;
+	union t4_recv_wr *wqe;
+	u32 num_wrs;
+	u8 len16 = 0;
+	unsigned long flag;
+	u16 idx = 0;
+
+	qhp = to_c4iw_qp(ibqp);
+	spin_lock_irqsave(&qhp->lock, flag);
+	if (t4_wq_in_error(&qhp->wq)) {
+		spin_unlock_irqrestore(&qhp->lock, flag);
+		return -EINVAL;
+	}
+	num_wrs = t4_rq_avail(&qhp->wq);
+	if (num_wrs == 0) {
+		spin_unlock_irqrestore(&qhp->lock, flag);
+		return -ENOMEM;
+	}
+	while (wr) {
+		if (wr->num_sge > T4_MAX_RECV_SGE) {
+			err = -EINVAL;
+			*bad_wr = wr;
+			break;
+		}
+		wqe = &qhp->wq.rq.queue[qhp->wq.rq.pidx];
+		if (num_wrs)
+			err = build_rdma_recv(qhp, wqe, wr, &len16);
+		else
+			err = -ENOMEM;
+		if (err) {
+			*bad_wr = wr;
+			break;
+		}
+
+		qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].wr_id = wr->wr_id;
+
+		wqe->recv.opcode = FW_RI_RECV_WR;
+		wqe->recv.r1 = 0;
+		wqe->recv.wrid = qhp->wq.rq.pidx;
+		wqe->recv.r2[0] = 0;
+		wqe->recv.r2[1] = 0;
+		wqe->recv.r2[2] = 0;
+		wqe->recv.len16 = len16;
+		if (len16 < 5)
+			wqe->flits[8] = 0;
+
+		PDBG("%s cookie 0x%llx pidx %u\n", __func__,
+		     (unsigned long long) wr->wr_id, qhp->wq.rq.pidx);
+		t4_rq_produce(&qhp->wq);
+		wr = wr->next;
+		num_wrs--;
+		idx++;
+	}
+	if (t4_wq_db_enabled(&qhp->wq))
+		t4_ring_rq_db(&qhp->wq, idx);
+	spin_unlock_irqrestore(&qhp->lock, flag);
+	return err;
+}
+
+int c4iw_bind_mw(struct ib_qp *qp, struct ib_mw *mw, struct ib_mw_bind *mw_bind)
+{
+	return -ENOSYS;
+}
+
+static inline void build_term_codes(struct t4_cqe *err_cqe, u8 *layer_type,
+				    u8 *ecode)
+{
+	int status;
+	int tagged;
+	int opcode;
+	int rqtype;
+	int send_inv;
+
+	status = CQE_STATUS(err_cqe);
+	opcode = CQE_OPCODE(err_cqe);
+	rqtype = RQ_TYPE(err_cqe);
+	send_inv = (opcode == FW_RI_SEND_WITH_INV) ||
+		   (opcode == FW_RI_SEND_WITH_SE_INV);
+	tagged = (opcode == FW_RI_RDMA_WRITE) ||
+		 (rqtype && (opcode == FW_RI_READ_RESP));
+
+	switch (status) {
+	case T4_ERR_STAG:
+		if (send_inv) {
+			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+			*ecode = RDMAP_CANT_INV_STAG;
+		} else {
+			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+			*ecode = RDMAP_INV_STAG;
+		}
+		break;
+	case T4_ERR_PDID:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		if ((opcode == FW_RI_SEND_WITH_INV) ||
+		    (opcode == FW_RI_SEND_WITH_SE_INV))
+			*ecode = RDMAP_CANT_INV_STAG;
+		else
+			*ecode = RDMAP_STAG_NOT_ASSOC;
+		break;
+	case T4_ERR_QPID:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		*ecode = RDMAP_STAG_NOT_ASSOC;
+		break;
+	case T4_ERR_ACCESS:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		*ecode = RDMAP_ACC_VIOL;
+		break;
+	case T4_ERR_WRAP:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		*ecode = RDMAP_TO_WRAP;
+		break;
+	case T4_ERR_BOUND:
+		if (tagged) {
+			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
+			*ecode = DDPT_BASE_BOUNDS;
+		} else {
+			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+			*ecode = RDMAP_BASE_BOUNDS;
+		}
+		break;
+	case T4_ERR_INVALIDATE_SHARED_MR:
+	case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+		*ecode = RDMAP_CANT_INV_STAG;
+		break;
+	case T4_ERR_ECC:
+	case T4_ERR_ECC_PSTAG:
+	case T4_ERR_INTERNAL_ERR:
+		*layer_type = LAYER_RDMAP|RDMAP_LOCAL_CATA;
+		*ecode = 0;
+		break;
+	case T4_ERR_OUT_OF_RQE:
+		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+		*ecode = DDPU_INV_MSN_NOBUF;
+		break;
+	case T4_ERR_PBL_ADDR_BOUND:
+		*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
+		*ecode = DDPT_BASE_BOUNDS;
+		break;
+	case T4_ERR_CRC:
+		*layer_type = LAYER_MPA|DDP_LLP;
+		*ecode = MPA_CRC_ERR;
+		break;
+	case T4_ERR_MARKER:
+		*layer_type = LAYER_MPA|DDP_LLP;
+		*ecode = MPA_MARKER_ERR;
+		break;
+	case T4_ERR_PDU_LEN_ERR:
+		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+		*ecode = DDPU_MSG_TOOBIG;
+		break;
+	case T4_ERR_DDP_VERSION:
+		if (tagged) {
+			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
+			*ecode = DDPT_INV_VERS;
+		} else {
+			*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+			*ecode = DDPU_INV_VERS;
+		}
+		break;
+	case T4_ERR_RDMA_VERSION:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+		*ecode = RDMAP_INV_VERS;
+		break;
+	case T4_ERR_OPCODE:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+		*ecode = RDMAP_INV_OPCODE;
+		break;
+	case T4_ERR_DDP_QUEUE_NUM:
+		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+		*ecode = DDPU_INV_QN;
+		break;
+	case T4_ERR_MSN:
+	case T4_ERR_MSN_GAP:
+	case T4_ERR_MSN_RANGE:
+	case T4_ERR_IRD_OVERFLOW:
+		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+		*ecode = DDPU_INV_MSN_RANGE;
+		break;
+	case T4_ERR_TBIT:
+		*layer_type = LAYER_DDP|DDP_LOCAL_CATA;
+		*ecode = 0;
+		break;
+	case T4_ERR_MO:
+		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+		*ecode = DDPU_INV_MO;
+		break;
+	default:
+		*layer_type = LAYER_RDMAP|DDP_LOCAL_CATA;
+		*ecode = 0;
+		break;
+	}
+}
+
+int c4iw_post_zb_read(struct c4iw_qp *qhp)
+{
+	union t4_wr *wqe;
+	struct sk_buff *skb;
+	u8 len16;
+
+	PDBG("%s enter\n", __func__);
+	skb = alloc_skb(40, GFP_KERNEL);
+	if (!skb) {
+		printk(KERN_ERR "%s cannot send zb_read!!\n", __func__);
+		return -ENOMEM;
+	}
+	set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
+
+	wqe = (union t4_wr *)skb_put(skb, sizeof wqe->read);
+	memset(wqe, 0, sizeof wqe->read);
+	wqe->read.r2 = cpu_to_be64(0);
+	wqe->read.stag_sink = cpu_to_be32(1);
+	wqe->read.to_sink_hi = cpu_to_be32(0);
+	wqe->read.to_sink_lo = cpu_to_be32(1);
+	wqe->read.stag_src = cpu_to_be32(1);
+	wqe->read.plen = cpu_to_be32(0);
+	wqe->read.to_src_hi = cpu_to_be32(0);
+	wqe->read.to_src_lo = cpu_to_be32(1);
+	len16 = DIV_ROUND_UP(sizeof wqe->read, 16);
+	init_wr_hdr(wqe, 0, FW_RI_RDMA_READ_WR, FW_RI_COMPLETION_FLAG, len16);
+
+	return c4iw_ofld_send(&qhp->rhp->rdev, skb);
+}
+
+/*
+ * This posts a TERMINATE with layer=RDMA, type=catastrophic.
+ */
+int c4iw_post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe)
+{
+	union t4_wr *wqe;
+	struct terminate_message *term;
+	struct sk_buff *skb;
+	struct fw_ri_immd *immd;
+	int wr_len;
+
+	PDBG("%s %d\n", __func__, __LINE__);
+
+	wr_len = sizeof wqe->send + sizeof *immd + sizeof *term;
+	skb = alloc_skb(wr_len, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_ERR "%s cannot send TERMINATE!\n", __func__);
+		return -ENOMEM;
+	}
+	set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
+
+	wqe = (union t4_wr *)skb_put(skb, wr_len);
+	memset(wqe, 0, wr_len);
+	wqe->send.sendop_pkd =
+		cpu_to_be32(V_FW_RI_SEND_WR_SENDOP(FW_RI_TERMINATE));
+	wqe->send.plen = cpu_to_be32(sizeof *term);
+	immd = &wqe->send.immd_src[0];
+	immd->op = FW_RI_DATA_IMMD;
+	immd->r1 = 0;
+	immd->r2 = 0;
+	immd->immdlen = cpu_to_be32(sizeof *term);
+
+	term = (struct terminate_message *)(immd + 1);
+	build_term_codes(err_cqe, &term->layer_etype, &term->ecode);
+	init_wr_hdr(wqe, 0, FW_RI_SEND_WR,
+		    FW_RI_COMPLETION_FLAG | FW_RI_NOTIFICATION_FLAG,
+		    DIV_ROUND_UP(wr_len, 16));
+	return c4iw_ofld_send(&qhp->rhp->rdev, skb);
+}
+
+/*
+ * Assumes qhp lock is held.
+ */
+static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
+		       struct c4iw_cq *schp, unsigned long *flag)
+{
+	int count;
+	int flushed;
+
+	PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
+	/* take a ref on the qhp since we must release the lock */
+	atomic_inc(&qhp->refcnt);
+	spin_unlock_irqrestore(&qhp->lock, *flag);
+
+	/* locking heirarchy: cq lock first, then qp lock. */
+	spin_lock_irqsave(&rchp->lock, *flag);
+	spin_lock(&qhp->lock);
+	c4iw_flush_hw_cq(&rchp->cq);
+	c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
+	flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
+	spin_unlock(&qhp->lock);
+	spin_unlock_irqrestore(&rchp->lock, *flag);
+	if (flushed)
+		(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
+
+	/* locking heirarchy: cq lock first, then qp lock. */
+	spin_lock_irqsave(&schp->lock, *flag);
+	spin_lock(&qhp->lock);
+	c4iw_flush_hw_cq(&schp->cq);
+	c4iw_count_scqes(&schp->cq, &qhp->wq, &count);
+	flushed = c4iw_flush_sq(&qhp->wq, &schp->cq, count);
+	spin_unlock(&qhp->lock);
+	spin_unlock_irqrestore(&schp->lock, *flag);
+	if (flushed)
+		(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
+
+	/* deref */
+	if (atomic_dec_and_test(&qhp->refcnt))
+		wake_up(&qhp->wait);
+
+	spin_lock_irqsave(&qhp->lock, *flag);
+}
+
+static void flush_qp(struct c4iw_qp *qhp, unsigned long *flag)
+{
+	struct c4iw_cq *rchp, *schp;
+
+	rchp = get_chp(qhp->rhp, qhp->attr.rcq);
+	schp = get_chp(qhp->rhp, qhp->attr.scq);
+
+	if (qhp->ibqp.uobject) {
+		t4_set_wq_in_error(&qhp->wq);
+		t4_set_cq_in_error(&rchp->cq);
+		if (schp != rchp)
+			t4_set_cq_in_error(&schp->cq);
+		return;
+	}
+	__flush_qp(qhp, rchp, schp, flag);
+}
+
+static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
+{
+	struct fw_ri_wr *wqe;
+	int ret;
+	struct c4iw_wr_wait wr_wait;
+	struct sk_buff *skb;
+
+	PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
+	     qhp->ep->hwtid);
+
+	skb = alloc_skb(sizeof *wqe, GFP_KERNEL | __GFP_NOFAIL);
+	if (!skb)
+		return -ENOMEM;
+	set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
+
+	wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
+	memset(wqe, 0, sizeof *wqe);
+	wqe->op_compl = cpu_to_be32(
+		FW_WR_OP(FW_RI_INIT_WR) |
+		FW_WR_COMPL(1));
+	wqe->flowid_len16 = cpu_to_be32(
+		FW_WR_FLOWID(qhp->ep->hwtid) |
+		FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
+	wqe->cookie = (u64)&wr_wait;
+
+	wqe->u.fini.type = FW_RI_TYPE_FINI;
+	c4iw_init_wr_wait(&wr_wait);
+	ret = c4iw_ofld_send(&rhp->rdev, skb);
+	if (ret)
+		goto out;
+
+	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
+	if (!wr_wait.done) {
+		printk(KERN_ERR MOD "Device %s not responding!\n",
+		       pci_name(rhp->rdev.lldi.pdev));
+		rhp->rdev.flags = T4_FATAL_ERROR;
+		ret = -EIO;
+	} else
+		ret = wr_wait.ret;
+out:
+	PDBG("%s ret %d\n", __func__, ret);
+	return ret;
+}
+
+static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
+{
+	struct fw_ri_wr *wqe;
+	int ret;
+	struct c4iw_wr_wait wr_wait;
+	struct sk_buff *skb;
+
+	PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
+	     qhp->ep->hwtid);
+
+	skb = alloc_skb(sizeof *wqe, GFP_KERNEL | __GFP_NOFAIL);
+	if (!skb)
+		return -ENOMEM;
+	set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
+
+	wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
+	memset(wqe, 0, sizeof *wqe);
+	wqe->op_compl = cpu_to_be32(
+		FW_WR_OP(FW_RI_INIT_WR) |
+		FW_WR_COMPL(1));
+	wqe->flowid_len16 = cpu_to_be32(
+		FW_WR_FLOWID(qhp->ep->hwtid) |
+		FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
+
+	wqe->cookie = (u64)&wr_wait;
+
+	wqe->u.init.type = FW_RI_TYPE_INIT;
+	wqe->u.init.mpareqbit_p2ptype =
+		V_FW_RI_WR_MPAREQBIT(qhp->attr.mpa_attr.initiator) |
+		V_FW_RI_WR_P2PTYPE(1);
+	wqe->u.init.mpa_attrs = FW_RI_MPA_IETF_ENABLE;
+	if (qhp->attr.mpa_attr.recv_marker_enabled)
+		wqe->u.init.mpa_attrs |= FW_RI_MPA_RX_MARKER_ENABLE;
+	if (qhp->attr.mpa_attr.xmit_marker_enabled)
+		wqe->u.init.mpa_attrs |= FW_RI_MPA_TX_MARKER_ENABLE;
+	if (qhp->attr.mpa_attr.crc_enabled)
+		wqe->u.init.mpa_attrs |= FW_RI_MPA_CRC_ENABLE;
+
+	wqe->u.init.qp_caps = FW_RI_QP_RDMA_READ_ENABLE |
+			    FW_RI_QP_RDMA_WRITE_ENABLE |
+			    FW_RI_QP_BIND_ENABLE;
+	if (!qhp->ibqp.uobject)
+		wqe->u.init.qp_caps |= FW_RI_QP_FAST_REGISTER_ENABLE |
+				     FW_RI_QP_STAG0_ENABLE;
+	wqe->u.init.nrqe = cpu_to_be16(t4_rqes_posted(&qhp->wq));
+	wqe->u.init.pdid = cpu_to_be32(qhp->attr.pd);
+	wqe->u.init.qpid = cpu_to_be32(qhp->wq.sq.qid);
+	wqe->u.init.sq_eqid = cpu_to_be32(qhp->wq.sq.qid);
+	wqe->u.init.rq_eqid = cpu_to_be32(qhp->wq.rq.qid);
+	wqe->u.init.scqid = cpu_to_be32(qhp->attr.scq);
+	wqe->u.init.rcqid = cpu_to_be32(qhp->attr.rcq);
+	wqe->u.init.ord_max = cpu_to_be32(qhp->attr.max_ord);
+	wqe->u.init.ird_max = cpu_to_be32(qhp->attr.max_ird);
+	wqe->u.init.iss = cpu_to_be32(qhp->ep->snd_seq);
+	wqe->u.init.irs = cpu_to_be32(qhp->ep->rcv_seq);
+	wqe->u.init.hwrqsize = cpu_to_be32(qhp->wq.rq.rqt_size);
+	wqe->u.init.hwrqaddr = cpu_to_be32(qhp->wq.rq.rqt_hwaddr -
+					 rhp->rdev.lldi.vr->rq.start);
+
+	c4iw_init_wr_wait(&wr_wait);
+	ret = c4iw_ofld_send(&rhp->rdev, skb);
+	if (ret)
+		goto out;
+
+	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
+	if (!wr_wait.done) {
+		printk(KERN_ERR MOD "Device %s not responding!\n",
+		       pci_name(rhp->rdev.lldi.pdev));
+		rhp->rdev.flags = T4_FATAL_ERROR;
+		ret = -EIO;
+	} else
+		ret = wr_wait.ret;
+out:
+	PDBG("%s ret %d\n", __func__, ret);
+	return ret;
+}
+
+int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
+		   enum c4iw_qp_attr_mask mask,
+		   struct c4iw_qp_attributes *attrs,
+		   int internal)
+{
+	int ret = 0;
+	struct c4iw_qp_attributes newattr = qhp->attr;
+	unsigned long flag;
+	int disconnect = 0;
+	int terminate = 0;
+	int abort = 0;
+	int free = 0;
+	struct c4iw_ep *ep = NULL;
+
+	PDBG("%s qhp %p sqid 0x%x rqid 0x%x ep %p state %d -> %d\n", __func__,
+	     qhp, qhp->wq.sq.qid, qhp->wq.rq.qid, qhp->ep, qhp->attr.state,
+	     (mask & C4IW_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1);
+
+	spin_lock_irqsave(&qhp->lock, flag);
+
+	/* Process attr changes if in IDLE */
+	if (mask & C4IW_QP_ATTR_VALID_MODIFY) {
+		if (qhp->attr.state != C4IW_QP_STATE_IDLE) {
+			ret = -EIO;
+			goto out;
+		}
+		if (mask & C4IW_QP_ATTR_ENABLE_RDMA_READ)
+			newattr.enable_rdma_read = attrs->enable_rdma_read;
+		if (mask & C4IW_QP_ATTR_ENABLE_RDMA_WRITE)
+			newattr.enable_rdma_write = attrs->enable_rdma_write;
+		if (mask & C4IW_QP_ATTR_ENABLE_RDMA_BIND)
+			newattr.enable_bind = attrs->enable_bind;
+		if (mask & C4IW_QP_ATTR_MAX_ORD) {
+			if (attrs->max_ord > T4_MAX_READ_DEPTH) {
+				ret = -EINVAL;
+				goto out;
+			}
+			newattr.max_ord = attrs->max_ord;
+		}
+		if (mask & C4IW_QP_ATTR_MAX_IRD) {
+			if (attrs->max_ird > T4_MAX_READ_DEPTH) {
+				ret = -EINVAL;
+				goto out;
+			}
+			newattr.max_ird = attrs->max_ird;
+		}
+		qhp->attr = newattr;
+	}
+
+	if (!(mask & C4IW_QP_ATTR_NEXT_STATE))
+		goto out;
+	if (qhp->attr.state == attrs->next_state)
+		goto out;
+
+	switch (qhp->attr.state) {
+	case C4IW_QP_STATE_IDLE:
+		switch (attrs->next_state) {
+		case C4IW_QP_STATE_RTS:
+			if (!(mask & C4IW_QP_ATTR_LLP_STREAM_HANDLE)) {
+				ret = -EINVAL;
+				goto out;
+			}
+			if (!(mask & C4IW_QP_ATTR_MPA_ATTR)) {
+				ret = -EINVAL;
+				goto out;
+			}
+			qhp->attr.mpa_attr = attrs->mpa_attr;
+			qhp->attr.llp_stream_handle = attrs->llp_stream_handle;
+			qhp->ep = qhp->attr.llp_stream_handle;
+			qhp->attr.state = C4IW_QP_STATE_RTS;
+
+			/*
+			 * Ref the endpoint here and deref when we
+			 * disassociate the endpoint from the QP.  This
+			 * happens in CLOSING->IDLE transition or *->ERROR
+			 * transition.
+			 */
+			c4iw_get_ep(&qhp->ep->com);
+			spin_unlock_irqrestore(&qhp->lock, flag);
+			ret = rdma_init(rhp, qhp);
+			spin_lock_irqsave(&qhp->lock, flag);
+			if (ret)
+				goto err;
+			break;
+		case C4IW_QP_STATE_ERROR:
+			qhp->attr.state = C4IW_QP_STATE_ERROR;
+			flush_qp(qhp, &flag);
+			break;
+		default:
+			ret = -EINVAL;
+			goto out;
+		}
+		break;
+	case C4IW_QP_STATE_RTS:
+		switch (attrs->next_state) {
+		case C4IW_QP_STATE_CLOSING:
+			BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2);
+			qhp->attr.state = C4IW_QP_STATE_CLOSING;
+			if (!internal) {
+				abort = 0;
+				disconnect = 1;
+				ep = qhp->ep;
+				c4iw_get_ep(&ep->com);
+			}
+			spin_unlock_irqrestore(&qhp->lock, flag);
+			ret = rdma_fini(rhp, qhp);
+			spin_lock_irqsave(&qhp->lock, flag);
+			if (ret) {
+				abort = 1;
+				goto err;
+			}
+			break;
+		case C4IW_QP_STATE_TERMINATE:
+			qhp->attr.state = C4IW_QP_STATE_TERMINATE;
+			if (qhp->ibqp.uobject)
+				t4_set_wq_in_error(&qhp->wq);
+			if (!internal)
+				terminate = 1;
+			break;
+		case C4IW_QP_STATE_ERROR:
+			qhp->attr.state = C4IW_QP_STATE_ERROR;
+			if (!internal) {
+				abort = 1;
+				disconnect = 1;
+				ep = qhp->ep;
+				c4iw_get_ep(&ep->com);
+			}
+			goto err;
+			break;
+		default:
+			ret = -EINVAL;
+			goto out;
+		}
+		break;
+	case C4IW_QP_STATE_CLOSING:
+		if (!internal) {
+			ret = -EINVAL;
+			goto out;
+		}
+		switch (attrs->next_state) {
+		case C4IW_QP_STATE_IDLE:
+			flush_qp(qhp, &flag);
+			qhp->attr.state = C4IW_QP_STATE_IDLE;
+			qhp->attr.llp_stream_handle = NULL;
+			c4iw_put_ep(&qhp->ep->com);
+			qhp->ep = NULL;
+			wake_up(&qhp->wait);
+			break;
+		case C4IW_QP_STATE_ERROR:
+			goto err;
+		default:
+			ret = -EINVAL;
+			goto err;
+		}
+		break;
+	case C4IW_QP_STATE_ERROR:
+		if (attrs->next_state != C4IW_QP_STATE_IDLE) {
+			ret = -EINVAL;
+			goto out;
+		}
+		if (!t4_sq_empty(&qhp->wq) || !t4_rq_empty(&qhp->wq)) {
+			ret = -EINVAL;
+			goto out;
+		}
+		qhp->attr.state = C4IW_QP_STATE_IDLE;
+		break;
+	case C4IW_QP_STATE_TERMINATE:
+		if (!internal) {
+			ret = -EINVAL;
+			goto out;
+		}
+		goto err;
+		break;
+	default:
+		printk(KERN_ERR "%s in a bad state %d\n",
+		       __func__, qhp->attr.state);
+		ret = -EINVAL;
+		goto err;
+		break;
+	}
+	goto out;
+err:
+	PDBG("%s disassociating ep %p qpid 0x%x\n", __func__, qhp->ep,
+	     qhp->wq.sq.qid);
+
+	/* disassociate the LLP connection */
+	qhp->attr.llp_stream_handle = NULL;
+	ep = qhp->ep;
+	qhp->ep = NULL;
+	qhp->attr.state = C4IW_QP_STATE_ERROR;
+	free = 1;
+	wake_up(&qhp->wait);
+	BUG_ON(!ep);
+	flush_qp(qhp, &flag);
+out:
+	spin_unlock_irqrestore(&qhp->lock, flag);
+
+	if (terminate)
+		c4iw_post_terminate(qhp, NULL);
+
+	/*
+	 * If disconnect is 1, then we need to initiate a disconnect
+	 * on the EP.  This can be a normal close (RTS->CLOSING) or
+	 * an abnormal close (RTS/CLOSING->ERROR).
+	 */
+	if (disconnect) {
+		c4iw_ep_disconnect(ep, abort, GFP_KERNEL);
+		c4iw_put_ep(&ep->com);
+	}
+
+	/*
+	 * If free is 1, then we've disassociated the EP from the QP
+	 * and we need to dereference the EP.
+	 */
+	if (free)
+		c4iw_put_ep(&ep->com);
+
+	PDBG("%s exit state %d\n", __func__, qhp->attr.state);
+	return ret;
+}
+
+int c4iw_destroy_qp(struct ib_qp *ib_qp)
+{
+	struct c4iw_dev *rhp;
+	struct c4iw_qp *qhp;
+	struct c4iw_qp_attributes attrs;
+	struct c4iw_ucontext *ucontext;
+
+	qhp = to_c4iw_qp(ib_qp);
+	rhp = qhp->rhp;
+
+	attrs.next_state = C4IW_QP_STATE_ERROR;
+	c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
+	wait_event(qhp->wait, !qhp->ep);
+
+	remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
+	remove_handle(rhp, &rhp->qpidr, qhp->wq.rq.qid);
+	atomic_dec(&qhp->refcnt);
+	wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
+
+	ucontext = ib_qp->uobject ?
+		   to_c4iw_ucontext(ib_qp->uobject->context) : NULL;
+	destroy_qp(&rhp->rdev, &qhp->wq,
+		   ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+
+	PDBG("%s ib_qp %p qpid 0x%0x\n", __func__, ib_qp, qhp->wq.sq.qid);
+	kfree(qhp);
+	return 0;
+}
+
+struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+			     struct ib_udata *udata)
+{
+	struct c4iw_dev *rhp;
+	struct c4iw_qp *qhp;
+	struct c4iw_pd *php;
+	struct c4iw_cq *schp;
+	struct c4iw_cq *rchp;
+	struct c4iw_create_qp_resp uresp;
+	int sqsize, rqsize;
+	struct c4iw_ucontext *ucontext;
+	int ret;
+	struct c4iw_mm_entry *mm1, *mm2, *mm3, *mm4;
+
+	PDBG("%s ib_pd %p\n", __func__, pd);
+
+	if (attrs->qp_type != IB_QPT_RC)
+		return ERR_PTR(-EINVAL);
+
+	php = to_c4iw_pd(pd);
+	rhp = php->rhp;
+	schp = get_chp(rhp, ((struct c4iw_cq *)attrs->send_cq)->cq.cqid);
+	rchp = get_chp(rhp, ((struct c4iw_cq *)attrs->recv_cq)->cq.cqid);
+	if (!schp || !rchp)
+		return ERR_PTR(-EINVAL);
+
+	if (attrs->cap.max_inline_data > T4_MAX_SEND_INLINE)
+		return ERR_PTR(-EINVAL);
+
+	rqsize = roundup(attrs->cap.max_recv_wr + 1, 16);
+	if (rqsize > T4_MAX_RQ_SIZE)
+		return ERR_PTR(-E2BIG);
+
+	sqsize = roundup(attrs->cap.max_send_wr + 1, 16);
+	if (sqsize > T4_MAX_SQ_SIZE)
+		return ERR_PTR(-E2BIG);
+
+	ucontext = pd->uobject ? to_c4iw_ucontext(pd->uobject->context) : NULL;
+
+
+	qhp = kzalloc(sizeof(*qhp), GFP_KERNEL);
+	if (!qhp)
+		return ERR_PTR(-ENOMEM);
+	qhp->wq.sq.size = sqsize;
+	qhp->wq.sq.memsize = (sqsize + 1) * sizeof *qhp->wq.sq.queue;
+	qhp->wq.rq.size = rqsize;
+	qhp->wq.rq.memsize = (rqsize + 1) * sizeof *qhp->wq.rq.queue;
+
+	if (ucontext) {
+		qhp->wq.sq.memsize = roundup(qhp->wq.sq.memsize, PAGE_SIZE);
+		qhp->wq.rq.memsize = roundup(qhp->wq.rq.memsize, PAGE_SIZE);
+	}
+
+	PDBG("%s sqsize %u sqmemsize %lu rqsize %u rqmemsize %lu\n",
+	     __func__, sqsize, qhp->wq.sq.memsize, rqsize, qhp->wq.rq.memsize);
+
+	ret = create_qp(&rhp->rdev, &qhp->wq, &schp->cq, &rchp->cq,
+			ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+	if (ret)
+		goto err1;
+
+	attrs->cap.max_recv_wr = rqsize - 1;
+	attrs->cap.max_send_wr = sqsize - 1;
+	attrs->cap.max_inline_data = T4_MAX_SEND_INLINE;
+
+	qhp->rhp = rhp;
+	qhp->attr.pd = php->pdid;
+	qhp->attr.scq = ((struct c4iw_cq *) attrs->send_cq)->cq.cqid;
+	qhp->attr.rcq = ((struct c4iw_cq *) attrs->recv_cq)->cq.cqid;
+	qhp->attr.sq_num_entries = attrs->cap.max_send_wr;
+	qhp->attr.rq_num_entries = attrs->cap.max_recv_wr;
+	qhp->attr.sq_max_sges = attrs->cap.max_send_sge;
+	qhp->attr.sq_max_sges_rdma_write = attrs->cap.max_send_sge;
+	qhp->attr.rq_max_sges = attrs->cap.max_recv_sge;
+	qhp->attr.state = C4IW_QP_STATE_IDLE;
+	qhp->attr.next_state = C4IW_QP_STATE_IDLE;
+	qhp->attr.enable_rdma_read = 1;
+	qhp->attr.enable_rdma_write = 1;
+	qhp->attr.enable_bind = 1;
+	qhp->attr.max_ord = 1;
+	qhp->attr.max_ird = 1;
+	spin_lock_init(&qhp->lock);
+	init_waitqueue_head(&qhp->wait);
+	atomic_set(&qhp->refcnt, 1);
+
+	ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
+	if (ret)
+		goto err2;
+
+	ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.rq.qid);
+	if (ret)
+		goto err3;
+
+	if (udata) {
+		mm1 = kmalloc(sizeof *mm1, GFP_KERNEL);
+		if (!mm1) {
+			ret = -ENOMEM;
+			goto err4;
+		}
+		mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
+		if (!mm2) {
+			ret = -ENOMEM;
+			goto err5;
+		}
+		mm3 = kmalloc(sizeof *mm3, GFP_KERNEL);
+		if (!mm3) {
+			ret = -ENOMEM;
+			goto err6;
+		}
+		mm4 = kmalloc(sizeof *mm4, GFP_KERNEL);
+		if (!mm4) {
+			ret = -ENOMEM;
+			goto err7;
+		}
+
+		uresp.qid_mask = rhp->rdev.qpmask;
+		uresp.sqid = qhp->wq.sq.qid;
+		uresp.sq_size = qhp->wq.sq.size;
+		uresp.sq_memsize = qhp->wq.sq.memsize;
+		uresp.rqid = qhp->wq.rq.qid;
+		uresp.rq_size = qhp->wq.rq.size;
+		uresp.rq_memsize = qhp->wq.rq.memsize;
+		spin_lock(&ucontext->mmap_lock);
+		uresp.sq_key = ucontext->key;
+		ucontext->key += PAGE_SIZE;
+		uresp.rq_key = ucontext->key;
+		ucontext->key += PAGE_SIZE;
+		uresp.sq_db_gts_key = ucontext->key;
+		ucontext->key += PAGE_SIZE;
+		uresp.rq_db_gts_key = ucontext->key;
+		ucontext->key += PAGE_SIZE;
+		spin_unlock(&ucontext->mmap_lock);
+		ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
+		if (ret)
+			goto err8;
+		mm1->key = uresp.sq_key;
+		mm1->addr = virt_to_phys(qhp->wq.sq.queue);
+		mm1->len = PAGE_ALIGN(qhp->wq.sq.memsize);
+		insert_mmap(ucontext, mm1);
+		mm2->key = uresp.rq_key;
+		mm2->addr = virt_to_phys(qhp->wq.rq.queue);
+		mm2->len = PAGE_ALIGN(qhp->wq.rq.memsize);
+		insert_mmap(ucontext, mm2);
+		mm3->key = uresp.sq_db_gts_key;
+		mm3->addr = qhp->wq.sq.udb;
+		mm3->len = PAGE_SIZE;
+		insert_mmap(ucontext, mm3);
+		mm4->key = uresp.rq_db_gts_key;
+		mm4->addr = qhp->wq.rq.udb;
+		mm4->len = PAGE_SIZE;
+		insert_mmap(ucontext, mm4);
+	}
+	qhp->ibqp.qp_num = qhp->wq.sq.qid;
+	init_timer(&(qhp->timer));
+	PDBG("%s qhp %p sq_num_entries %d, rq_num_entries %d qpid 0x%0x\n",
+	     __func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
+	     qhp->wq.sq.qid);
+	return &qhp->ibqp;
+err8:
+	kfree(mm4);
+err7:
+	kfree(mm3);
+err6:
+	kfree(mm2);
+err5:
+	kfree(mm1);
+err4:
+	remove_handle(rhp, &rhp->qpidr, qhp->wq.rq.qid);
+err3:
+	remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
+err2:
+	destroy_qp(&rhp->rdev, &qhp->wq,
+		   ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+err1:
+	kfree(qhp);
+	return ERR_PTR(ret);
+}
+
+int c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+		      int attr_mask, struct ib_udata *udata)
+{
+	struct c4iw_dev *rhp;
+	struct c4iw_qp *qhp;
+	enum c4iw_qp_attr_mask mask = 0;
+	struct c4iw_qp_attributes attrs;
+
+	PDBG("%s ib_qp %p\n", __func__, ibqp);
+
+	/* iwarp does not support the RTR state */
+	if ((attr_mask & IB_QP_STATE) && (attr->qp_state == IB_QPS_RTR))
+		attr_mask &= ~IB_QP_STATE;
+
+	/* Make sure we still have something left to do */
+	if (!attr_mask)
+		return 0;
+
+	memset(&attrs, 0, sizeof attrs);
+	qhp = to_c4iw_qp(ibqp);
+	rhp = qhp->rhp;
+
+	attrs.next_state = c4iw_convert_state(attr->qp_state);
+	attrs.enable_rdma_read = (attr->qp_access_flags &
+			       IB_ACCESS_REMOTE_READ) ?  1 : 0;
+	attrs.enable_rdma_write = (attr->qp_access_flags &
+				IB_ACCESS_REMOTE_WRITE) ? 1 : 0;
+	attrs.enable_bind = (attr->qp_access_flags & IB_ACCESS_MW_BIND) ? 1 : 0;
+
+
+	mask |= (attr_mask & IB_QP_STATE) ? C4IW_QP_ATTR_NEXT_STATE : 0;
+	mask |= (attr_mask & IB_QP_ACCESS_FLAGS) ?
+			(C4IW_QP_ATTR_ENABLE_RDMA_READ |
+			 C4IW_QP_ATTR_ENABLE_RDMA_WRITE |
+			 C4IW_QP_ATTR_ENABLE_RDMA_BIND) : 0;
+
+	return c4iw_modify_qp(rhp, qhp, mask, &attrs, 0);
+}
+
+struct ib_qp *c4iw_get_qp(struct ib_device *dev, int qpn)
+{
+	PDBG("%s ib_dev %p qpn 0x%x\n", __func__, dev, qpn);
+	return (struct ib_qp *)get_qhp(to_c4iw_dev(dev), qpn);
+}

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 09/10] iw_cxgb4: Add event management functions.
From: Steve Wise @ 2010-04-09 20:54 UTC (permalink / raw)
  To: linux-rdma-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20100409205336.9813.84868.stgit-T4OLL4TyM9aNDNWfRnPdfg@public.gmane.org>

Signed-off-by: Steve Wise <swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org>
---

 drivers/infiniband/hw/cxgb4/ev.c |  224 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 224 insertions(+), 0 deletions(-)
 create mode 100644 drivers/infiniband/hw/cxgb4/ev.c

diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
new file mode 100644
index 0000000..8d00415
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb4/ev.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/slab.h>
+#include <linux/mman.h>
+#include <net/sock.h>
+
+#include "iw_cxgb4.h"
+
+static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
+			  struct c4iw_qp *qhp,
+			  struct t4_cqe *err_cqe,
+			  enum ib_event_type ib_event,
+			  int send_term)
+{
+	struct ib_event event;
+	struct c4iw_qp_attributes attrs;
+
+	if ((qhp->attr.state == C4IW_QP_STATE_ERROR) ||
+	    (qhp->attr.state == C4IW_QP_STATE_TERMINATE)) {
+		PDBG("%s AE received after RTS - "
+		     "qp state %d qpid 0x%x status 0x%x\n", __func__,
+		     qhp->attr.state, qhp->wq.sq.qid, CQE_STATUS(err_cqe));
+		return;
+	}
+
+	printk(KERN_ERR "%s - AE qpid 0x%x opcode %d status 0x%x "
+	       "type %d wrid.hi 0x%x wrid.lo 0x%x\n", __func__,
+	       CQE_QPID(err_cqe), CQE_OPCODE(err_cqe),
+	       CQE_STATUS(err_cqe), CQE_TYPE(err_cqe),
+	       CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe));
+
+	if (qhp->attr.state == C4IW_QP_STATE_RTS) {
+		attrs.next_state = C4IW_QP_STATE_TERMINATE;
+		c4iw_modify_qp(qhp->rhp, qhp, C4IW_QP_ATTR_NEXT_STATE,
+			       &attrs, 1);
+		if (send_term)
+			c4iw_post_terminate(qhp, err_cqe);
+	}
+
+	event.event = ib_event;
+	event.device = chp->ibcq.device;
+	if (ib_event == IB_EVENT_CQ_ERR)
+		event.element.cq = &chp->ibcq;
+	else
+		event.element.qp = &qhp->ibqp;
+	if (qhp->ibqp.event_handler)
+		(*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
+
+	(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
+}
+
+void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
+{
+	struct c4iw_cq *chp;
+	struct c4iw_qp *qhp;
+	u32 cqid;
+
+	spin_lock(&dev->lock);
+	qhp = get_qhp(dev, CQE_QPID(err_cqe));
+	if (!qhp) {
+		printk(KERN_ERR MOD "BAD AE qpid 0x%x opcode %d "
+		       "status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x\n",
+		       CQE_QPID(err_cqe),
+		       CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe),
+		       CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe),
+		       CQE_WRID_LOW(err_cqe));
+		spin_unlock(&dev->lock);
+		goto out;
+	}
+
+	if (SQ_TYPE(err_cqe))
+		cqid = qhp->attr.scq;
+	else
+		cqid = qhp->attr.rcq;
+	chp = get_chp(dev, cqid);
+	if (!chp) {
+		printk(KERN_ERR MOD "BAD AE cqid 0x%x qpid 0x%x opcode %d "
+		       "status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x\n",
+		       cqid, CQE_QPID(err_cqe),
+		       CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe),
+		       CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe),
+		       CQE_WRID_LOW(err_cqe));
+		spin_unlock(&dev->lock);
+		goto out;
+	}
+
+	c4iw_qp_add_ref(&qhp->ibqp);
+	atomic_inc(&chp->refcnt);
+	spin_unlock(&dev->lock);
+
+	/*
+	 * 1) completion of our sending a TERMINATE.
+	 * 2) incoming TERMINATE message.
+	 */
+	if ((CQE_OPCODE(err_cqe) == FW_RI_TERMINATE) &&
+	    (CQE_STATUS(err_cqe) == 0)) {
+		if (SQ_TYPE(err_cqe)) {
+			PDBG("%s QPID 0x%x ep %p disconnecting\n",
+			     __func__, qhp->wq.sq.qid, qhp->ep);
+			c4iw_ep_disconnect(qhp->ep, 0, GFP_ATOMIC);
+		} else {
+			PDBG("%s post REQ_ERR AE QPID 0x%x\n", __func__,
+			     qhp->wq.sq.qid);
+			post_qp_event(dev, chp, qhp, err_cqe,
+				      IB_EVENT_QP_REQ_ERR, 0);
+			c4iw_ep_disconnect(qhp->ep, 0, GFP_ATOMIC);
+		}
+		goto done;
+	}
+
+	/* Bad incoming Read request */
+	if (SQ_TYPE(err_cqe) &&
+	    (CQE_OPCODE(err_cqe) == FW_RI_READ_RESP)) {
+		post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_REQ_ERR, 1);
+		goto done;
+	}
+
+	/* Bad incoming write */
+	if (RQ_TYPE(err_cqe) &&
+	    (CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE)) {
+		post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_REQ_ERR, 1);
+		goto done;
+	}
+
+	switch (CQE_STATUS(err_cqe)) {
+
+	/* Completion Events */
+	case T4_ERR_SUCCESS:
+		printk(KERN_ERR MOD "AE with status 0!\n");
+		break;
+
+	case T4_ERR_STAG:
+	case T4_ERR_PDID:
+	case T4_ERR_QPID:
+	case T4_ERR_ACCESS:
+	case T4_ERR_WRAP:
+	case T4_ERR_BOUND:
+	case T4_ERR_INVALIDATE_SHARED_MR:
+	case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND:
+		post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_ACCESS_ERR,
+			      1);
+		break;
+
+	/* Device Fatal Errors */
+	case T4_ERR_ECC:
+	case T4_ERR_ECC_PSTAG:
+	case T4_ERR_INTERNAL_ERR:
+		post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_DEVICE_FATAL, 1);
+		break;
+
+	/* QP Fatal Errors */
+	case T4_ERR_OUT_OF_RQE:
+	case T4_ERR_PBL_ADDR_BOUND:
+	case T4_ERR_CRC:
+	case T4_ERR_MARKER:
+	case T4_ERR_PDU_LEN_ERR:
+	case T4_ERR_DDP_VERSION:
+	case T4_ERR_RDMA_VERSION:
+	case T4_ERR_OPCODE:
+	case T4_ERR_DDP_QUEUE_NUM:
+	case T4_ERR_MSN:
+	case T4_ERR_TBIT:
+	case T4_ERR_MO:
+	case T4_ERR_MSN_GAP:
+	case T4_ERR_MSN_RANGE:
+	case T4_ERR_RQE_ADDR_BOUND:
+	case T4_ERR_IRD_OVERFLOW:
+		post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_FATAL, 1);
+		break;
+
+	default:
+		printk(KERN_ERR MOD "Unknown T4 status 0x%x QPID 0x%x\n",
+		       CQE_STATUS(err_cqe), qhp->wq.sq.qid);
+		post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_FATAL, 1);
+		break;
+	}
+done:
+	if (atomic_dec_and_test(&chp->refcnt))
+		wake_up(&chp->wait);
+	c4iw_qp_rem_ref(&qhp->ibqp);
+out:
+	return;
+}
+
+int c4iw_ev_handler(struct c4iw_dev *dev, u32 qid)
+{
+	struct c4iw_cq *chp;
+
+	chp = get_chp(dev, qid);
+	if (chp)
+		(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
+	else
+		PDBG("%s unknown cqid 0x%x\n", __func__, qid);
+	return 0;
+}

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 10/10] iw_cxgb4: Add id and hw resource management functions.
From: Steve Wise @ 2010-04-09 20:54 UTC (permalink / raw)
  To: linux-rdma-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20100409205336.9813.84868.stgit-T4OLL4TyM9aNDNWfRnPdfg@public.gmane.org>

Signed-off-by: Steve Wise <swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org>
---

 drivers/infiniband/hw/cxgb4/resource.c |  417 ++++++++++++++++++++++++++++++++
 1 files changed, 417 insertions(+), 0 deletions(-)
 create mode 100644 drivers/infiniband/hw/cxgb4/resource.c

diff --git a/drivers/infiniband/hw/cxgb4/resource.c b/drivers/infiniband/hw/cxgb4/resource.c
new file mode 100644
index 0000000..fb195d1
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb4/resource.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Crude resource management */
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/genalloc.h>
+#include "iw_cxgb4.h"
+
+#define RANDOM_SIZE 16
+
+static int __c4iw_init_resource_fifo(struct kfifo *fifo,
+				   spinlock_t *fifo_lock,
+				   u32 nr, u32 skip_low,
+				   u32 skip_high,
+				   int random)
+{
+	u32 i, j, entry = 0, idx;
+	u32 random_bytes;
+	u32 rarray[16];
+	spin_lock_init(fifo_lock);
+
+	if (kfifo_alloc(fifo, nr * sizeof(u32), GFP_KERNEL))
+		return -ENOMEM;
+
+	for (i = 0; i < skip_low + skip_high; i++)
+		kfifo_in(fifo, (unsigned char *) &entry, sizeof(u32));
+	if (random) {
+		j = 0;
+		random_bytes = random32();
+		for (i = 0; i < RANDOM_SIZE; i++)
+			rarray[i] = i + skip_low;
+		for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) {
+			if (j >= RANDOM_SIZE) {
+				j = 0;
+				random_bytes = random32();
+			}
+			idx = (random_bytes >> (j * 2)) & 0xF;
+			kfifo_in(fifo,
+				(unsigned char *) &rarray[idx],
+				sizeof(u32));
+			rarray[idx] = i;
+			j++;
+		}
+		for (i = 0; i < RANDOM_SIZE; i++)
+			kfifo_in(fifo,
+				(unsigned char *) &rarray[i],
+				sizeof(u32));
+	} else
+		for (i = skip_low; i < nr - skip_high; i++)
+			kfifo_in(fifo, (unsigned char *) &i, sizeof(u32));
+
+	for (i = 0; i < skip_low + skip_high; i++)
+		if (kfifo_out_locked(fifo, (unsigned char *) &entry,
+				     sizeof(u32), fifo_lock))
+			break;
+	return 0;
+}
+
+static int c4iw_init_resource_fifo(struct kfifo *fifo, spinlock_t * fifo_lock,
+				   u32 nr, u32 skip_low, u32 skip_high)
+{
+	return __c4iw_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
+					  skip_high, 0);
+}
+
+static int c4iw_init_resource_fifo_random(struct kfifo *fifo,
+				   spinlock_t *fifo_lock,
+				   u32 nr, u32 skip_low, u32 skip_high)
+{
+	return __c4iw_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
+					  skip_high, 1);
+}
+
+static int c4iw_init_qid_fifo(struct c4iw_rdev *rdev)
+{
+	u32 i;
+
+	spin_lock_init(&rdev->resource.qid_fifo_lock);
+
+	if (kfifo_alloc(&rdev->resource.qid_fifo, T4_MAX_QIDS * sizeof(u32),
+			GFP_KERNEL))
+		return -ENOMEM;
+
+	for (i = T4_QID_BASE; i < T4_QID_BASE + T4_MAX_QIDS; i++)
+		if (!(i & rdev->qpmask))
+			kfifo_in(&rdev->resource.qid_fifo,
+				    (unsigned char *) &i, sizeof(u32));
+	return 0;
+}
+
+/* nr_* must be power of 2 */
+int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid)
+{
+	int err = 0;
+	err = c4iw_init_resource_fifo_random(&rdev->resource.tpt_fifo,
+					     &rdev->resource.tpt_fifo_lock,
+					     nr_tpt, 1, 0);
+	if (err)
+		goto tpt_err;
+	err = c4iw_init_qid_fifo(rdev);
+	if (err)
+		goto qid_err;
+	err = c4iw_init_resource_fifo(&rdev->resource.pdid_fifo,
+				      &rdev->resource.pdid_fifo_lock,
+				      nr_pdid, 1, 0);
+	if (err)
+		goto pdid_err;
+	return 0;
+pdid_err:
+	kfifo_free(&rdev->resource.qid_fifo);
+qid_err:
+	kfifo_free(&rdev->resource.tpt_fifo);
+tpt_err:
+	return -ENOMEM;
+}
+
+/*
+ * returns 0 if no resource available
+ */
+u32 c4iw_get_resource(struct kfifo *fifo, spinlock_t *lock)
+{
+	u32 entry;
+	if (kfifo_out_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock))
+		return entry;
+	else
+		return 0;
+}
+
+void c4iw_put_resource(struct kfifo *fifo, u32 entry, spinlock_t *lock)
+{
+	PDBG("%s entry 0x%x\n", __func__, entry);
+	kfifo_in_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock);
+}
+
+u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
+{
+	struct c4iw_qid_list *entry;
+	u32 qid;
+	int i;
+
+	mutex_lock(&uctx->lock);
+	if (!list_empty(&uctx->cqids)) {
+		entry = list_entry(uctx->cqids.next, struct c4iw_qid_list,
+				   entry);
+		list_del(&entry->entry);
+		qid = entry->qid;
+		kfree(entry);
+	} else {
+		qid = c4iw_get_resource(&rdev->resource.qid_fifo,
+					&rdev->resource.qid_fifo_lock);
+		if (!qid)
+			goto out;
+		for (i = qid+1; i & rdev->qpmask; i++) {
+			entry = kmalloc(sizeof *entry, GFP_KERNEL);
+			if (!entry)
+				goto out;
+			entry->qid = i;
+			list_add_tail(&entry->entry, &uctx->cqids);
+		}
+
+		/*
+		 * now put the same ids on the qp list since they all
+		 * map to the same db/gts page.
+		 */
+		entry = kmalloc(sizeof *entry, GFP_KERNEL);
+		if (!entry)
+			goto out;
+		entry->qid = qid;
+		list_add_tail(&entry->entry, &uctx->qpids);
+		for (i = qid+1; i & rdev->qpmask; i++) {
+			entry = kmalloc(sizeof *entry, GFP_KERNEL);
+			if (!entry)
+				goto out;
+			entry->qid = i;
+			list_add_tail(&entry->entry, &uctx->qpids);
+		}
+	}
+out:
+	mutex_unlock(&uctx->lock);
+	PDBG("%s qid 0x%x\n", __func__, qid);
+	return qid;
+}
+
+void c4iw_put_cqid(struct c4iw_rdev *rdev, u32 qid,
+		   struct c4iw_dev_ucontext *uctx)
+{
+	struct c4iw_qid_list *entry;
+
+	entry = kmalloc(sizeof *entry, GFP_KERNEL);
+	if (!entry)
+		return;
+	PDBG("%s qid 0x%x\n", __func__, qid);
+	entry->qid = qid;
+	mutex_lock(&uctx->lock);
+	list_add_tail(&entry->entry, &uctx->cqids);
+	mutex_unlock(&uctx->lock);
+}
+
+u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
+{
+	struct c4iw_qid_list *entry;
+	u32 qid;
+	int i;
+
+	mutex_lock(&uctx->lock);
+	if (!list_empty(&uctx->qpids)) {
+		entry = list_entry(uctx->qpids.next, struct c4iw_qid_list,
+				   entry);
+		list_del(&entry->entry);
+		qid = entry->qid;
+		kfree(entry);
+	} else {
+		qid = c4iw_get_resource(&rdev->resource.qid_fifo,
+					&rdev->resource.qid_fifo_lock);
+		if (!qid)
+			goto out;
+		for (i = qid+1; i & rdev->qpmask; i++) {
+			entry = kmalloc(sizeof *entry, GFP_KERNEL);
+			if (!entry)
+				goto out;
+			entry->qid = i;
+			list_add_tail(&entry->entry, &uctx->qpids);
+		}
+
+		/*
+		 * now put the same ids on the cq list since they all
+		 * map to the same db/gts page.
+		 */
+		entry = kmalloc(sizeof *entry, GFP_KERNEL);
+		if (!entry)
+			goto out;
+		entry->qid = qid;
+		list_add_tail(&entry->entry, &uctx->cqids);
+		for (i = qid; i & rdev->qpmask; i++) {
+			entry = kmalloc(sizeof *entry, GFP_KERNEL);
+			if (!entry)
+				goto out;
+			entry->qid = i;
+			list_add_tail(&entry->entry, &uctx->cqids);
+		}
+	}
+out:
+	mutex_unlock(&uctx->lock);
+	PDBG("%s qid 0x%x\n", __func__, qid);
+	return qid;
+}
+
+void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qid,
+		   struct c4iw_dev_ucontext *uctx)
+{
+	struct c4iw_qid_list *entry;
+
+	entry = kmalloc(sizeof *entry, GFP_KERNEL);
+	if (!entry)
+		return;
+	PDBG("%s qid 0x%x\n", __func__, qid);
+	entry->qid = qid;
+	mutex_lock(&uctx->lock);
+	list_add_tail(&entry->entry, &uctx->qpids);
+	mutex_unlock(&uctx->lock);
+}
+
+void c4iw_destroy_resource(struct c4iw_resource *rscp)
+{
+	kfifo_free(&rscp->tpt_fifo);
+	kfifo_free(&rscp->qid_fifo);
+	kfifo_free(&rscp->pdid_fifo);
+}
+
+/*
+ * PBL Memory Manager.  Uses Linux generic allocator.
+ */
+
+#define MIN_PBL_SHIFT 8			/* 256B == min PBL size (32 entries) */
+
+u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
+{
+	unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
+	PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+	return (u32)addr;
+}
+
+void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+{
+	PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
+	gen_pool_free(rdev->pbl_pool, (unsigned long)addr, size);
+}
+
+int c4iw_pblpool_create(struct c4iw_rdev *rdev)
+{
+	unsigned pbl_start, pbl_chunk, pbl_top;
+
+	rdev->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1);
+	if (!rdev->pbl_pool)
+		return -ENOMEM;
+
+	pbl_start = rdev->lldi.vr->pbl.start;
+	pbl_chunk = rdev->lldi.vr->pbl.size;
+	pbl_top = pbl_start + pbl_chunk;
+
+	while (pbl_start < pbl_top) {
+		pbl_chunk = min(pbl_top - pbl_start + 1, pbl_chunk);
+		if (gen_pool_add(rdev->pbl_pool, pbl_start, pbl_chunk, -1)) {
+			PDBG("%s failed to add PBL chunk (%x/%x)\n",
+			     __func__, pbl_start, pbl_chunk);
+			if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
+				printk(KERN_WARNING MOD
+				       "Failed to add all PBL chunks (%x/%x)\n",
+				       pbl_start,
+				       pbl_top - pbl_start);
+				return 0;
+			}
+			pbl_chunk >>= 1;
+		} else {
+			PDBG("%s added PBL chunk (%x/%x)\n",
+			     __func__, pbl_start, pbl_chunk);
+			pbl_start += pbl_chunk;
+		}
+	}
+
+	return 0;
+}
+
+void c4iw_pblpool_destroy(struct c4iw_rdev *rdev)
+{
+	gen_pool_destroy(rdev->pbl_pool);
+}
+
+/*
+ * RQT Memory Manager.  Uses Linux generic allocator.
+ */
+
+#define MIN_RQT_SHIFT 10	/* 1KB == min RQT size (16 entries) */
+
+u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
+{
+	unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6);
+	PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6);
+	return (u32)addr;
+}
+
+void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+{
+	PDBG("%s addr 0x%x size %d\n", __func__, addr, size << 6);
+	gen_pool_free(rdev->rqt_pool, (unsigned long)addr, size << 6);
+}
+
+int c4iw_rqtpool_create(struct c4iw_rdev *rdev)
+{
+	unsigned rqt_start, rqt_chunk, rqt_top;
+
+	rdev->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1);
+	if (!rdev->rqt_pool)
+		return -ENOMEM;
+
+	rqt_start = rdev->lldi.vr->rq.start;
+	rqt_chunk = rdev->lldi.vr->rq.size;
+	rqt_top = rqt_start + rqt_chunk;
+
+	while (rqt_start < rqt_top) {
+		rqt_chunk = min(rqt_top - rqt_start + 1, rqt_chunk);
+		if (gen_pool_add(rdev->rqt_pool, rqt_start, rqt_chunk, -1)) {
+			PDBG("%s failed to add RQT chunk (%x/%x)\n",
+			     __func__, rqt_start, rqt_chunk);
+			if (rqt_chunk <= 1024 << MIN_RQT_SHIFT) {
+				printk(KERN_WARNING MOD
+				       "Failed to add all RQT chunks (%x/%x)\n",
+				       rqt_start, rqt_top - rqt_start);
+				return 0;
+			}
+			rqt_chunk >>= 1;
+		} else {
+			PDBG("%s added RQT chunk (%x/%x)\n",
+			     __func__, rqt_start, rqt_chunk);
+			rqt_start += rqt_chunk;
+		}
+	}
+	return 0;
+}
+
+void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev)
+{
+	gen_pool_destroy(rdev->rqt_pool);
+}

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH v3 0/2] Using multi-smps on the wire in libibnetdisc
From: Sasha Khapyorsky @ 2010-04-09 23:21 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100402172330.819b8ef6.weiny2-i2BcT+NCU+M@public.gmane.org>

Hi Ira,

On 17:23 Fri 02 Apr     , Ira Weiny wrote:
> 
> Have you had a chance to look at this yet?  If you want I can resend the latest version of the patches.

No needs. I'm looking at this right now...

Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 38/51] IB/qib: Add qib_sysfs.c
From: Ralph Campbell @ 2010-04-09 23:31 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Roland Dreier, linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20100408225002.GS9769-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>

On Thu, 2010-04-08 at 15:50 -0700, Jason Gunthorpe wrote:
> On Thu, Apr 08, 2010 at 03:26:41PM -0700, Ralph Campbell wrote:
> > On Thu, 2010-04-08 at 15:08 -0700, Jason Gunthorpe wrote:
> > > On Thu, Apr 08, 2010 at 02:29:53PM -0700, Ralph Campbell wrote:
> > > 
> > > > One other place that has multiple values is dumping the QSFP
> > > > data from the IB cable.
> > > 
> > > I was going to comment that building your own I2C subsystem is kinda
> > > strange, can't the in-kernel stuff be used?
> 
> > It is a bit strange but we have had this discussion before with
> > the ib_ipath driver. Basically, the devices connected to the bus
> > weren't really I2C compliant. Since we had to support the
> > non-standard parts, it was easier to have only one set of code
> > that could handle both.
> 
> Is this still true on qib? I didn't notice anything too obviously
> weird, and QSFPs are clearly standard i2c..
> 
> The i2c layer has a pretty flexible definition of i2c these days..
> 
> Jason

I would be very reluctant to change this code.
One device we have doesn't have an i2c address, the "address" is the
address of memory within the chip, not the address of the chip on the
bus.

Reading some of the QSFP cable's EEPROM caused another EEPROM
on the bus to be erased. We had to put in defensive code to
check for this case.

I'm not the expert who wrote this code (he retired) so I would have
to do a lot of work making sure the older parts and cables with
these problems worked after a major rewrite of the code.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH] tests/subnet_discover: verbose node discovery printout
From: Sasha Khapyorsky @ 2010-04-09 23:56 UTC (permalink / raw)
  To: Ira Weiny; +Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20100218124931.4d6ef34b.weiny2-i2BcT+NCU+M@public.gmane.org>


Improve verbosity levels: with '-v' print nodes as they are discovered,
more 'v' - more noise.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 tests/subnet_discover.c |   25 ++++++++++++++++---------
 1 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/tests/subnet_discover.c b/tests/subnet_discover.c
index 22b092a..44cd86e 100644
--- a/tests/subnet_discover.c
+++ b/tests/subnet_discover.c
@@ -52,7 +52,9 @@ static unsigned max_hops = 0;
 
 #define ERROR(fmt, ...) fprintf(stderr, "ERR: " fmt, ##__VA_ARGS__)
 #define VERBOSE(fmt, ...) if (verbose) fprintf(stderr, fmt, ##__VA_ARGS__)
-#define NOISE(fmt, ...) if (verbose > 1) fprintf(stderr, fmt, ##__VA_ARGS__)
+#define VERBOSE1(fmt, ...) if (verbose > 1) fprintf(stderr, fmt, ##__VA_ARGS__)
+#define VERBOSE2(fmt, ...) if (verbose > 2) fprintf(stderr, fmt, ##__VA_ARGS__)
+#define NOISE(fmt, ...) VERBOSE2(fmt, ##__VA_ARGS__)
 
 static const char *print_path(uint8_t path[], size_t path_cnt)
 {
@@ -116,8 +118,8 @@ static int send_request(int fd, int agent, uint64_t trid, uint8_t * path,
 		return -1;
 	}
 
-	VERBOSE("send %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id,
-		attr_mod, print_path(path, path_cnt));
+	VERBOSE1("send %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id,
+		 attr_mod, print_path(path, path_cnt));
 
 	return ret;
 }
@@ -239,8 +241,8 @@ static int send_query(int fd, int agent, unsigned node_id, uint8_t path[],
 		return -1;
 	}
 
-	VERBOSE("queue %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id,
-		attr_mod, print_path(path, path_cnt));
+	VERBOSE1("queue %016" PRIx64 ": attr %x, mod %x to %s\n", trid, attr_id,
+		 attr_mod, print_path(path, path_cnt));
 
 	run_request_queue(fd, agent);
 
@@ -384,8 +386,8 @@ static void connect_ports(unsigned node1_id, unsigned port1_num,
 {
 	struct port *port1 = &node_array[node1_id]->ports[port1_num];
 	struct port *port2 = &node_array[node2_id]->ports[port2_num];
-	VERBOSE("connecting %u:%u <--> %u:%u\n",
-		node1_id, port1_num, node2_id, port2_num);
+	VERBOSE1("connecting %u:%u <--> %u:%u\n",
+		 node1_id, port1_num, node2_id, port2_num);
 	port1->remote = port2;
 	port2->remote = port1;
 }
@@ -410,6 +412,11 @@ static int process_node(void *umad, unsigned remote_id, int fd, int agent,
 
 	node = node_array[id];
 
+	VERBOSE("%-5s %-6s with guid 0x%" PRIx64 " discovered at %s\n",
+		node_is_new ? "new" : "known",
+		node->is_switch ? "Switch" : "Ca", node->guid,
+		print_path(path, path_cnt));
+
 	node->ports[port_num].guid =
 	    mad_get_field64(node_info, 0, IB_NODE_PORT_GUID_F);
 
@@ -472,8 +479,8 @@ static int recv_smp_resp(int fd, int agent, uint8_t * umad, uint8_t path[])
 
 	node_id = trid & 0xffff;
 
-	VERBOSE("recv %016" PRIx64 ": attr %x, mod %x from %s\n", trid, attr_id,
-		attr_mod, print_path(path, path_cnt));
+	VERBOSE1("recv %016" PRIx64 ": attr %x, mod %x from %s\n", trid,
+		 attr_id, attr_mod, print_path(path, path_cnt));
 
 	switch (attr_id) {
 	case IB_ATTR_NODE_INFO:
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH v2 38/51] IB/qib: Add qib_sysfs.c
From: Ralph Campbell @ 2010-04-10  0:13 UTC (permalink / raw)
  To: Roland Dreier; +Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <adask75vdbs.fsf-BjVyx320WGW9gfZ95n9DRSW4+XlvGpQz@public.gmane.org>

On Thu, 2010-04-08 at 14:33 -0700, Roland Dreier wrote:
> > This was for debugging and clearly could use a better method.
>  > Some stats are definitely useful and having files per value
>  > would make scripting easier too.
>  > I could add /sys/class/infiniband/qib0/ports/1/diag_counters/*
>  > 
>  > One other place that has multiple values is dumping the QSFP
>  > data from the IB cable.
> 
> You can stick debugging data under debugfs.  Or just kill it for now and
> figure out how to add it back later.

OK. I replaced the /sys/class/infiniband/qib0/stats file with

% ls /sys/class/infiniband/qib0/ports/1/diag_counters/
dmawait     pkt_drops        rc_dupreq   rc_seqnak    rnr_naks
loop_pkts   rc_acks          rc_qacks    rc_timeouts  seq_naks
other_naks  rc_delayed_comp  rc_resends  rdma_seq     unaligned

These are all simple counter values.

For the QSFP data, I hope I can leave it as is since it is
related to the link state that the other files contain.
It is a read-only file so no issue with trying to set a value.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 38/51] IB/qib: Add qib_sysfs.c
From: Jason Gunthorpe @ 2010-04-10  0:21 UTC (permalink / raw)
  To: Ralph Campbell
  Cc: Roland Dreier, linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1270855886.2278.52.camel-/vjeY7uYZjrPXfVEPVhPGq6RkeBMCJyt@public.gmane.org>

On Fri, Apr 09, 2010 at 04:31:26PM -0700, Ralph Campbell wrote:

> I would be very reluctant to change this code.
> One device we have doesn't have an i2c address, the "address" is the
> address of memory within the chip, not the address of the chip on the
> bus.

Fair enough.. But mixing not-i2c + QSFP real i2c on the same bus =
too scary for me :)

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 38/51] IB/qib: Add qib_sysfs.c
From: Jason Gunthorpe @ 2010-04-10  0:27 UTC (permalink / raw)
  To: Ralph Campbell
  Cc: Roland Dreier, linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1270858404.2278.64.camel-/vjeY7uYZjrPXfVEPVhPGq6RkeBMCJyt@public.gmane.org>

On Fri, Apr 09, 2010 at 05:13:24PM -0700, Ralph Campbell wrote:

> For the QSFP data, I hope I can leave it as is since it is
> related to the link state that the other files contain.
> It is a read-only file so no issue with trying to set a value.

There was some flack for other stuff like this a while back.

IMHO, it would be appropriate to have a hex dump of the entire QFSP
EEPROM and leave parsing to userspace, or put the parsed version in
debugfs..

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v3 0/2] Using multi-smps on the wire in libibnetdisc
From: Sasha Khapyorsky @ 2010-04-10  0:52 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100218124931.4d6ef34b.weiny2-i2BcT+NCU+M@public.gmane.org>

On 12:49 Thu 18 Feb     , Ira Weiny wrote:
> After the discussion with Hal I decided it would be safer to just limit the number of outstanding MAD's to 2.  This v3 version changes that.

I don't think that diagnostic tools (something used for investigations)
should have "less" priority then regular program like OpenSM, but
doesn't matter - number 'X' is fine to begin with.

> Patch 2/2 remains the same but I am just sending it to be complete.

I'm applying the whole series with few additions (will post here) - this
is a good start.

Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH] libibnetdisc: code cleanups
From: Sasha Khapyorsky @ 2010-04-10  0:55 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100410005245.GH4808@me>


Make newly introduced local functions to be static. Remove not needed
braces. Simplify some expressions.

Fix indentations using osm_indent script.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 infiniband-diags/libibnetdisc/src/chassis.c        |    2 +-
 infiniband-diags/libibnetdisc/src/ibnetdisc.c      |  150 +++++++++-----------
 .../libibnetdisc/src/ibnetdisc_cache.c             |    9 +-
 infiniband-diags/libibnetdisc/src/internal.h       |   23 ++--
 infiniband-diags/libibnetdisc/src/query_smp.c      |   68 ++++-----
 5 files changed, 113 insertions(+), 139 deletions(-)

diff --git a/infiniband-diags/libibnetdisc/src/chassis.c b/infiniband-diags/libibnetdisc/src/chassis.c
index c8f6b6c..1a839d9 100644
--- a/infiniband-diags/libibnetdisc/src/chassis.c
+++ b/infiniband-diags/libibnetdisc/src/chassis.c
@@ -38,7 +38,7 @@
 /*========================================================*/
 
 #if HAVE_CONFIG_H
-#  include <config.h>
+#include <config.h>
 #endif				/* HAVE_CONFIG_H */
 
 #include <stdlib.h>
diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
index b084373..4780810 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -34,7 +34,7 @@
  */
 
 #if HAVE_CONFIG_H
-#  include <config.h>
+#include <config.h>
 #endif				/* HAVE_CONFIG_H */
 
 #define _GNU_SOURCE
@@ -59,54 +59,41 @@ static int max_smps_on_wire = DEFAULT_MAX_SMP_ON_WIRE;
 int ibdebug;
 
 /* forward declare */
-int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
-		    ibnd_node_t * node);
+static int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
+			   ibnd_node_t * node);
 
-
-static int recv_switch_info(smp_engine_t *engine, ibnd_smp_t * smp,
-			    uint8_t *mad, void *cb_data)
+static int recv_switch_info(smp_engine_t * engine, ibnd_smp_t * smp,
+			    uint8_t * mad, void *cb_data)
 {
 	uint8_t *switch_info = mad + IB_SMP_DATA_OFFS;
-	ibnd_node_t * node = (ibnd_node_t *)cb_data;
+	ibnd_node_t *node = cb_data;
 	memcpy(node->switchinfo, switch_info, sizeof(node->switchinfo));
 	mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F,
 			 &node->smaenhsp0);
 	return 0;
 }
+
 static int query_switch_info(smp_engine_t * engine, ib_portid_t * portid,
-		      ibnd_node_t *node)
+			     ibnd_node_t * node)
 {
 	node->smaenhsp0 = 0;	/* assume base SP0 */
-	return (issue_smp(engine, portid, IB_ATTR_SWITCH_INFO, 0, recv_switch_info,
-			  (void *)node));
+	return issue_smp(engine, portid, IB_ATTR_SWITCH_INFO, 0,
+			 recv_switch_info, node);
 }
 
 static int add_port_to_dpath(ib_dr_path_t * path, int nextport)
 {
-	if (path->cnt + 2 >= sizeof(path->p)) {
+	if (path->cnt > sizeof(path->p) - 1)
 		return -1;
-	}
 	++path->cnt;
 	path->p[path->cnt] = (uint8_t) nextport;
 	return path->cnt;
 }
 
-#if 0
-static void retract_dpath(ib_portid_t * path)
-{
-	path->drpath.cnt--;	/* restore path */
-	if (path->drpath.cnt == 0 && path->lid) {
-		/* return to lid based routing on this path */
-		path->drpath.drslid = 0;
-		path->drpath.drdlid = 0;
-	}
-}
-#endif
-
-static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid, int nextport)
+static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid,
+			int nextport)
 {
-	int rc = 0;
-	ibnd_scan_t *scan = (ibnd_scan_t *)engine->user_data;
+	ibnd_scan_t *scan = engine->user_data;
 	ibnd_fabric_t *fabric = scan->fabric;
 
 	if (portid->lid) {
@@ -117,37 +104,39 @@ static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid, int nextpor
 				IBND_ERROR("Failed to resolve self\n");
 				return -1;
 			}
-
 		portid->drpath.drslid = (uint16_t) scan->selfportid.lid;
 		portid->drpath.drdlid = 0xFFFF;
 	}
 
-	rc = add_port_to_dpath(&portid->drpath, nextport);
-	if (rc < 0)
+	if (add_port_to_dpath(&portid->drpath, nextport) < 0) {
 		IBND_ERROR("add port %d to DR path failed; %s\n", nextport,
 			   portid2str(portid));
+		return -1;
+	}
 
-	if (rc != -1 && portid->drpath.cnt > fabric->maxhops_discovered)
+	if (portid->drpath.cnt > fabric->maxhops_discovered)
 		fabric->maxhops_discovered = portid->drpath.cnt;
-	return rc;
+
+	return 1;
 }
 
 static int recv_node_desc(smp_engine_t * engine, ibnd_smp_t * smp,
-			  uint8_t *mad, void *cb_data)
+			  uint8_t * mad, void *cb_data)
 {
 	uint8_t *node_desc = mad + IB_SMP_DATA_OFFS;
-	ibnd_node_t *node = (ibnd_node_t *)cb_data;
+	ibnd_node_t *node = cb_data;
 	memcpy(node->nodedesc, node_desc, sizeof(node->nodedesc));
 	return 0;
 }
 
-int query_node_desc(smp_engine_t * engine, ib_portid_t * portid, ibnd_node_t *node)
+static int query_node_desc(smp_engine_t * engine, ib_portid_t * portid,
+			   ibnd_node_t * node)
 {
-	return (issue_smp(engine, portid, IB_ATTR_NODE_DESC, 0, recv_node_desc,
-			  (void *)node));
+	return issue_smp(engine, portid, IB_ATTR_NODE_DESC, 0,
+			 recv_node_desc, node);
 }
 
-static void debug_port(ib_portid_t *portid, ibnd_port_t * port)
+static void debug_port(ib_portid_t * portid, ibnd_port_t * port)
 {
 	char width[64], speed[64];
 	int iwidth;
@@ -164,11 +153,11 @@ static void debug_port(ib_portid_t *portid, ibnd_port_t * port)
 	     mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed));
 }
 
-static int recv_port_info(smp_engine_t *engine, ibnd_smp_t * smp,
-			  uint8_t *mad, void *cb_data)
+static int recv_port_info(smp_engine_t * engine, ibnd_smp_t * smp,
+			  uint8_t * mad, void *cb_data)
 {
-	ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric;
-	ibnd_node_t *node = (ibnd_node_t *)cb_data;
+	ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric;
+	ibnd_node_t *node = cb_data;
 	ibnd_port_t *port;
 	uint8_t *port_info = mad + IB_SMP_DATA_OFFS;
 	uint8_t port_num, local_port;
@@ -205,12 +194,9 @@ static int recv_port_info(smp_engine_t *engine, ibnd_smp_t * smp,
 
 	debug_port(&smp->path, port);
 
-	if (port_num &&
-	    (mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F)
-	    == IB_PORT_PHYS_STATE_LINKUP)
-		&&
-	    (node->type == IB_NODE_SWITCH || node == fabric->from_node)) {
-
+	if (port_num && mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F)
+	    == IB_PORT_PHYS_STATE_LINKUP
+	    && (node->type == IB_NODE_SWITCH || node == fabric->from_node)) {
 		ib_portid_t path = smp->path;
 		if (extend_dpath(engine, &path, port_num) != -1)
 			query_node_info(engine, &path, node);
@@ -218,19 +204,20 @@ static int recv_port_info(smp_engine_t *engine, ibnd_smp_t * smp,
 
 	return 0;
 }
-int query_port_info(smp_engine_t * engine, ib_portid_t * portid,
-		    ibnd_node_t *node, int portnum)
+
+static int query_port_info(smp_engine_t * engine, ib_portid_t * portid,
+			   ibnd_node_t * node, int portnum)
 {
 	IBND_DEBUG("Query Port Info; %s (%lx):%d\n", portid2str(portid),
 		   node->guid, portnum);
-	return (issue_smp(engine, portid, IB_ATTR_PORT_INFO, portnum, recv_port_info,
-			  (void *)node));
+	return issue_smp(engine, portid, IB_ATTR_PORT_INFO, portnum,
+			 recv_port_info, node);
 }
 
 static ibnd_node_t *create_node(smp_engine_t * engine, ib_portid_t * path,
-				uint8_t *node_info)
+				uint8_t * node_info)
 {
-	ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric;
+	ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric;
 	ibnd_node_t *rc = calloc(1, sizeof(*rc));
 	if (!rc) {
 		IBND_ERROR("OOM: node creation failed\n");
@@ -238,9 +225,9 @@ static ibnd_node_t *create_node(smp_engine_t * engine, ib_portid_t * path,
 	}
 
 	/* decode just a couple of fields for quicker reference. */
-	mad_decode_field(node_info, IB_NODE_GUID_F, &(rc->guid));
-	mad_decode_field(node_info, IB_NODE_TYPE_F, &(rc->type));
-	mad_decode_field(node_info, IB_NODE_NPORTS_F, &(rc->numports));
+	mad_decode_field(node_info, IB_NODE_GUID_F, &rc->guid);
+	mad_decode_field(node_info, IB_NODE_TYPE_F, &rc->type);
+	mad_decode_field(node_info, IB_NODE_NPORTS_F, &rc->numports);
 
 	rc->ports = calloc(rc->numports + 1, sizeof(*rc->ports));
 	if (!rc->ports) {
@@ -265,8 +252,9 @@ static ibnd_node_t *create_node(smp_engine_t * engine, ib_portid_t * path,
 
 static int get_last_port(ib_portid_t * path)
 {
-	return (path->drpath.p[path->drpath.cnt]);
+	return path->drpath.p[path->drpath.cnt];
 }
+
 static void link_ports(ibnd_node_t * node, ibnd_port_t * port,
 		       ibnd_node_t * remotenode, ibnd_port_t * remoteport)
 {
@@ -278,17 +266,17 @@ static void link_ports(ibnd_node_t * node, ibnd_port_t * port,
 		port->remoteport->remoteport = NULL;
 	if (remoteport->remoteport)
 		remoteport->remoteport->remoteport = NULL;
-	port->remoteport = (ibnd_port_t *) remoteport;
-	remoteport->remoteport = (ibnd_port_t *) port;
+	port->remoteport = remoteport;
+	remoteport->remoteport = port;
 }
 
-static int recv_node_info(smp_engine_t *engine, ibnd_smp_t * smp,
-			  uint8_t *mad, void *cb_data)
+static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,
+			  uint8_t * mad, void *cb_data)
 {
-	ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric;
+	ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric;
 	int i = 0;
 	uint8_t *node_info = mad + IB_SMP_DATA_OFFS;
-	ibnd_node_t * rem_node = (ibnd_node_t *)cb_data;
+	ibnd_node_t *rem_node = cb_data;
 	ibnd_node_t *node;
 	int node_is_new = 0;
 	uint64_t node_guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F);
@@ -303,9 +291,8 @@ static int recv_node_info(smp_engine_t *engine, ibnd_smp_t * smp,
 			return -1;
 		node_is_new = 1;
 	}
-	IBND_DEBUG("Found %s node GUID %lx (%s)\n",
-		   (node_is_new) ? "new": "old", node->guid,
-		   portid2str(&smp->path));
+	IBND_DEBUG("Found %s node GUID %lx (%s)\n", node_is_new ? "new" : "old",
+		   node->guid, portid2str(&smp->path));
 
 	port = node->ports[port_num];
 	if (!port) {
@@ -316,7 +303,7 @@ static int recv_node_info(smp_engine_t *engine, ibnd_smp_t * smp,
 	}
 	port->guid = port_guid;
 
-	if (rem_node == NULL) /* this is the start node */
+	if (rem_node == NULL)	/* this is the start node */
 		fabric->from_node = node;
 	else {
 		/* link ports... */
@@ -326,7 +313,7 @@ static int recv_node_info(smp_engine_t *engine, ibnd_smp_t * smp,
 			IBND_ERROR("Internal Error; "
 				   "Node(%p) %lx Port %d no port created!?!?!?\n\n",
 				   rem_node, rem_node->guid, rem_port_num);
-			return (-1);
+			return -1;
 		}
 
 		link_ports(node, port, rem_node, rem_node->ports[rem_port_num]);
@@ -342,19 +329,19 @@ static int recv_node_info(smp_engine_t *engine, ibnd_smp_t * smp,
 
 	/* process all the ports on this node */
 	for (i = (node->type == IB_NODE_SWITCH) ? 0 : 1;
-		i <= node->numports; i++) {
-			query_port_info(engine, &smp->path, node, i);
+	     i <= node->numports; i++) {
+		query_port_info(engine, &smp->path, node, i);
 	}
 
 	return 0;
 }
 
-int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
-		    ibnd_node_t * node)
+static int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
+			   ibnd_node_t * node)
 {
 	IBND_DEBUG("Query Node Info; %s\n", portid2str(portid));
-	return (issue_smp(engine, portid, IB_ATTR_NODE_INFO, 0, recv_node_info,
-			  (void *)node));
+	return issue_smp(engine, portid, IB_ATTR_NODE_INFO, 0,
+			 recv_node_info, node);
 }
 
 ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric, uint64_t guid)
@@ -402,9 +389,8 @@ ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t * fabric, char *dr_str)
 
 	rc = fabric->from_node;
 
-	if (str2drpath(&path, dr_str, 0, 0) == -1) {
+	if (str2drpath(&path, dr_str, 0, 0) == -1)
 		return NULL;
-	}
 
 	for (i = 0; i <= path.cnt; i++) {
 		ibnd_port_t *remote_port = NULL;
@@ -464,7 +450,7 @@ int ibnd_set_max_smps_on_wire(int i)
 	return rc;
 }
 
-ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
+ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
 				    ib_portid_t * from, int hops)
 {
 	ibnd_fabric_t *fabric = NULL;
@@ -477,9 +463,8 @@ ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
 		return NULL;
 
 	/* if not everything how much? */
-	if (hops >= 0) {
+	if (hops >= 0)
 		max_hops = hops;
-	}
 
 	/* If not specified start from "my" port */
 	if (!from)
@@ -493,17 +478,16 @@ ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
 
 	memset(fabric, 0, sizeof(*fabric));
 
-	memset(&(scan.selfportid), 0, sizeof(scan.selfportid));
+	memset(&scan.selfportid, 0, sizeof(scan.selfportid));
 	scan.fabric = fabric;
 
 	smp_engine_init(&engine, ibmad_port, &scan, max_smps_on_wire);
 
 	IBND_DEBUG("from %s\n", portid2str(from));
 
-	if (!query_node_info(&engine, from, NULL)) {
+	if (!query_node_info(&engine, from, NULL))
 		if (process_mads(&engine) != 0)
 			goto error;
-	}
 
 	if (group_nodes(fabric))
 		goto error;
diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc_cache.c b/infiniband-diags/libibnetdisc/src/ibnetdisc_cache.c
index d94b85a..26157d7 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc_cache.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc_cache.c
@@ -34,7 +34,7 @@
  */
 
 #if HAVE_CONFIG_H
-#  include <config.h>
+#include <config.h>
 #endif				/* HAVE_CONFIG_H */
 
 #define _GNU_SOURCE
@@ -377,8 +377,8 @@ static int _load_node(int fd, ibnd_fabric_cache_t * fabric_cache)
 					  &node_cache->port_cache_keys[i].guid);
 			offset +=
 			    _unmarshall8(buf + offset,
-					 &node_cache->port_cache_keys[i].
-					 portnum);
+					 &node_cache->
+					 port_cache_keys[i].portnum);
 		}
 	}
 
@@ -573,8 +573,7 @@ static int _rebuild_ports(ibnd_fabric_cache_t * fabric_cache)
 
 		if (port_cache->remoteport_flag) {
 			if (!(remoteport_cache = _find_port(fabric_cache,
-							    &port_cache->
-							    remoteport_cache_key)))
+							    &port_cache->remoteport_cache_key)))
 			{
 				IBND_DEBUG
 				    ("Cache invalid: cannot find remote port\n");
diff --git a/infiniband-diags/libibnetdisc/src/internal.h b/infiniband-diags/libibnetdisc/src/internal.h
index 61b644d..179eac6 100644
--- a/infiniband-diags/libibnetdisc/src/internal.h
+++ b/infiniband-diags/libibnetdisc/src/internal.h
@@ -60,36 +60,35 @@ typedef struct ibnd_scan {
 	ibnd_fabric_t *fabric;
 } ibnd_scan_t;
 
-
 typedef struct ibnd_smp ibnd_smp_t;
 typedef struct smp_engine smp_engine_t;
-typedef int (*smp_comp_cb_t)(smp_engine_t *engine, ibnd_smp_t * smp,
-			     uint8_t *mad_resp, void *cb_data);
+typedef int (*smp_comp_cb_t) (smp_engine_t * engine, ibnd_smp_t * smp,
+			      uint8_t * mad_resp, void *cb_data);
 struct ibnd_smp {
 	cl_map_item_t on_wire;
-	struct ibnd_smp * qnext;
+	struct ibnd_smp *qnext;
 	smp_comp_cb_t cb;
-	void * cb_data;
+	void *cb_data;
 	ib_portid_t path;
 	ib_rpc_t rpc;
 };
+
 struct smp_engine {
 	struct ibmad_port *ibmad_port;
 	ibnd_smp_t *smp_queue_head;
 	ibnd_smp_t *smp_queue_tail;
-	void * user_data;
+	void *user_data;
 	cl_qmap_t smps_on_wire;
 	int num_smps_outstanding;
 	int max_smps_on_wire;
 };
 
 void smp_engine_init(smp_engine_t * engine, struct ibmad_port *ibmad_port,
-		     void * user_data, int max_smps_on_wire);
-int issue_smp(smp_engine_t *engine, ib_portid_t * portid,
-	      unsigned attrid, unsigned mod,
-	      smp_comp_cb_t cb, void * cb_data);
-int process_mads(smp_engine_t *engine);
-void smp_engine_destroy(smp_engine_t *engine);
+		     void *user_data, int max_smps_on_wire);
+int issue_smp(smp_engine_t * engine, ib_portid_t * portid,
+	      unsigned attrid, unsigned mod, smp_comp_cb_t cb, void *cb_data);
+int process_mads(smp_engine_t * engine);
+void smp_engine_destroy(smp_engine_t * engine);
 
 void add_to_nodeguid_hash(ibnd_node_t * node, ibnd_node_t * hash[]);
 
diff --git a/infiniband-diags/libibnetdisc/src/query_smp.c b/infiniband-diags/libibnetdisc/src/query_smp.c
index 1ace05e..a6878b6 100644
--- a/infiniband-diags/libibnetdisc/src/query_smp.c
+++ b/infiniband-diags/libibnetdisc/src/query_smp.c
@@ -36,8 +36,7 @@
 #include <infiniband/umad.h>
 #include "internal.h"
 
-void
-queue_smp(smp_engine_t *engine, ibnd_smp_t *smp)
+static void queue_smp(smp_engine_t * engine, ibnd_smp_t * smp)
 {
 	smp->qnext = NULL;
 	if (!engine->smp_queue_head) {
@@ -49,8 +48,7 @@ queue_smp(smp_engine_t *engine, ibnd_smp_t *smp)
 	}
 }
 
-ibnd_smp_t *
-get_smp(smp_engine_t *engine)
+static ibnd_smp_t *get_smp(smp_engine_t * engine)
 {
 	ibnd_smp_t *head = engine->smp_queue_head;
 	ibnd_smp_t *tail = engine->smp_queue_tail;
@@ -63,7 +61,7 @@ get_smp(smp_engine_t *engine)
 	return rc;
 }
 
-int send_smp(ibnd_smp_t * smp, struct ibmad_port *srcport)
+static int send_smp(ibnd_smp_t * smp, struct ibmad_port *srcport)
 {
 	int rc = 0;
 	uint8_t umad[1024];
@@ -89,7 +87,7 @@ int send_smp(ibnd_smp_t * smp, struct ibmad_port *srcport)
 	return 0;
 }
 
-static int process_smp_queue(smp_engine_t *engine)
+static int process_smp_queue(smp_engine_t * engine)
 {
 	int rc = 0;
 	ibnd_smp_t *smp;
@@ -98,17 +96,16 @@ static int process_smp_queue(smp_engine_t *engine)
 		if (!smp)
 			return 0;
 
-		cl_qmap_insert(&engine->smps_on_wire, (uint32_t)smp->rpc.trid,
-			       (cl_map_item_t *)smp);
+		cl_qmap_insert(&engine->smps_on_wire, (uint32_t) smp->rpc.trid,
+			       (cl_map_item_t *) smp);
 		if ((rc = send_smp(smp, engine->ibmad_port)) != 0)
 			return rc;
 	}
 	return 0;
 }
 
-int issue_smp(smp_engine_t *engine, ib_portid_t * portid,
-	      unsigned attrid, unsigned mod,
-	      smp_comp_cb_t cb, void * cb_data)
+int issue_smp(smp_engine_t * engine, ib_portid_t * portid,
+	      unsigned attrid, unsigned mod, smp_comp_cb_t cb, void *cb_data)
 {
 	ibnd_smp_t *smp = calloc(1, sizeof *smp);
 	if (!smp) {
@@ -127,22 +124,21 @@ int issue_smp(smp_engine_t *engine, ib_portid_t * portid,
 	smp->rpc.dataoffs = IB_SMP_DATA_OFFS;
 	smp->rpc.trid = mad_trid();
 
-	if ((portid->lid <= 0) ||
-	    (portid->drpath.drslid == 0xffff) ||
-	    (portid->drpath.drdlid == 0xffff))
-		smp->rpc.mgtclass = IB_SMI_DIRECT_CLASS; /* direct SMI */
+	if (portid->lid <= 0 || portid->drpath.drslid == 0xffff ||
+	    portid->drpath.drdlid == 0xffff)
+		smp->rpc.mgtclass = IB_SMI_DIRECT_CLASS;	/* direct SMI */
 	else
-		smp->rpc.mgtclass = IB_SMI_CLASS; /* Lid routed SMI */
+		smp->rpc.mgtclass = IB_SMI_CLASS;	/* Lid routed SMI */
 
 	portid->sl = 0;
 	portid->qp = 0;
 
 	engine->num_smps_outstanding++;
 	queue_smp(engine, smp);
-	return (process_smp_queue(engine));
+	return process_smp_queue(engine);
 }
 
-int process_one_recv(smp_engine_t *engine)
+static int process_one_recv(smp_engine_t * engine)
 {
 	int rc = 0;
 	int status = 0;
@@ -166,12 +162,11 @@ int process_one_recv(smp_engine_t *engine)
 	rc = process_smp_queue(engine);
 
 	mad = umad_get_mad(umad);
-	trid = (uint32_t)mad_get_field64(mad, 0, IB_MAD_TRID_F);
+	trid = (uint32_t) mad_get_field64(mad, 0, IB_MAD_TRID_F);
 
-	smp = (ibnd_smp_t *)cl_qmap_remove(&engine->smps_on_wire, trid);
-	if ((cl_map_item_t *)smp == cl_qmap_end(&engine->smps_on_wire)) {
-		IBND_ERROR("Failed to find matching smp for trid (%x)\n",
-			   trid);
+	smp = (ibnd_smp_t *) cl_qmap_remove(&engine->smps_on_wire, trid);
+	if ((cl_map_item_t *) smp == cl_qmap_end(&engine->smps_on_wire)) {
+		IBND_ERROR("Failed to find matching smp for trid (%x)\n", trid);
 		return -1;
 	}
 
@@ -180,27 +175,25 @@ int process_one_recv(smp_engine_t *engine)
 
 	if ((status = umad_status(umad))) {
 		IBND_ERROR("umad (%s Attr 0x%x:%u) bad status %d; %s\n",
-			portid2str(&smp->path),
-			smp->rpc.attr.id, smp->rpc.attr.mod,
-			status, strerror(status));
+			   portid2str(&smp->path), smp->rpc.attr.id,
+			   smp->rpc.attr.mod, status, strerror(status));
 	} else if ((status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F))) {
-			IBND_ERROR("mad (%s Attr 0x%x:%u) bad status 0x%x\n",
-				   portid2str(&smp->path),
-				   smp->rpc.attr.id, smp->rpc.attr.mod,
-				   status);
+		IBND_ERROR("mad (%s Attr 0x%x:%u) bad status 0x%x\n",
+			   portid2str(&smp->path), smp->rpc.attr.id,
+			   smp->rpc.attr.mod, status);
 	} else
 		rc = smp->cb(engine, smp, mad, smp->cb_data);
 
 error:
 	free(smp);
 	engine->num_smps_outstanding--;
-	return (rc);
+	return rc;
 }
 
 void smp_engine_init(smp_engine_t * engine, struct ibmad_port *ibmad_port,
-		     void * user_data, int max_smps_on_wire)
+		     void *user_data, int max_smps_on_wire)
 {
-	memset(engine, '\0', sizeof(*engine));
+	memset(engine, 0, sizeof(*engine));
 	engine->ibmad_port = ibmad_port;
 	engine->user_data = user_data;
 	cl_qmap_init(&engine->smps_on_wire);
@@ -208,7 +201,7 @@ void smp_engine_init(smp_engine_t * engine, struct ibmad_port *ibmad_port,
 	engine->max_smps_on_wire = max_smps_on_wire;
 }
 
-void smp_engine_destroy(smp_engine_t *engine)
+void smp_engine_destroy(smp_engine_t * engine)
 {
 	cl_map_item_t *item;
 	ibnd_smp_t *smp;
@@ -217,15 +210,14 @@ void smp_engine_destroy(smp_engine_t *engine)
 	smp = get_smp(engine);
 	if (smp)
 		IBND_ERROR("outstanding SMP's\n");
-	for (/* */; smp; smp = get_smp(engine)) {
+	for ( /* */ ; smp; smp = get_smp(engine))
 		free(smp);
-	}
 
 	/* remove smps from the wire queue */
 	item = cl_qmap_head(&engine->smps_on_wire);
 	if (item != cl_qmap_end(&engine->smps_on_wire))
 		IBND_ERROR("outstanding SMP's on wire\n");
-	for (/* */; item != cl_qmap_end(&engine->smps_on_wire);
+	for ( /* */ ; item != cl_qmap_end(&engine->smps_on_wire);
 	     item = cl_qmap_head(&engine->smps_on_wire)) {
 		cl_qmap_remove_item(&engine->smps_on_wire, item);
 		free(item);
@@ -234,7 +226,7 @@ void smp_engine_destroy(smp_engine_t *engine)
 	engine->num_smps_outstanding = 0;
 }
 
-int process_mads(smp_engine_t *engine)
+int process_mads(smp_engine_t * engine)
 {
 	int rc = 0;
 	while (engine->num_smps_outstanding > 0) {
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] libibnetdisc: restore show_progress functionality
From: Sasha Khapyorsky @ 2010-04-10  0:56 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100410005536.GI4808@me>


Restore show_progress functionality. This output is used by scripts like
'dump_lfts.sh -D', also sometimes useful for debug.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 infiniband-diags/libibnetdisc/src/ibnetdisc.c |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
index 4780810..b438d4f 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -270,6 +270,18 @@ static void link_ports(ibnd_node_t * node, ibnd_port_t * port,
 	remoteport->remoteport = port;
 }
 
+static void dump_endnode(ib_portid_t * path, char *prompt,
+			 ibnd_node_t * node, ibnd_port_t * port)
+{
+	char type[64];
+	mad_dump_node_type(type, sizeof(type), &node->type, sizeof(int));
+	printf("%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d \"%s\"\n",
+	       portid2str(path), prompt, type, node->guid,
+	       node->type == IB_NODE_SWITCH ? 0 : port->portnum,
+	       port->base_lid, port->base_lid + (1 << port->lmc) - 1,
+	       node->nodedesc);
+}
+
 static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,
 			  uint8_t * mad, void *cb_data)
 {
@@ -303,6 +315,10 @@ static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,
 	}
 	port->guid = port_guid;
 
+	if (show_progress)
+		dump_endnode(&smp->path, node_is_new ? "new" : "known",
+			     node, port);
+
 	if (rem_node == NULL)	/* this is the start node */
 		fabric->from_node = node;
 	else {
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] libibnetdisc: restore hops limited discovery
From: Sasha Khapyorsky @ 2010-04-10  0:57 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100410005536.GI4808@me>


Restore hops limited discovery.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 infiniband-diags/libibnetdisc/src/ibnetdisc.c |   12 ++++++------
 infiniband-diags/libibnetdisc/src/internal.h  |    1 +
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
index b438d4f..4012eff 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -96,6 +96,9 @@ static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid,
 	ibnd_scan_t *scan = engine->user_data;
 	ibnd_fabric_t *fabric = scan->fabric;
 
+	if (scan->max_hops && fabric->maxhops_discovered >= scan->max_hops)
+		return 0;
+
 	if (portid->lid) {
 		/* If we were LID routed we need to set up the drslid */
 		if (!scan->selfportid.lid)
@@ -198,7 +201,7 @@ static int recv_port_info(smp_engine_t * engine, ibnd_smp_t * smp,
 	    == IB_PORT_PHYS_STATE_LINKUP
 	    && (node->type == IB_NODE_SWITCH || node == fabric->from_node)) {
 		ib_portid_t path = smp->path;
-		if (extend_dpath(engine, &path, port_num) != -1)
+		if (extend_dpath(engine, &path, port_num) > 0)
 			query_node_info(engine, &path, node);
 	}
 
@@ -471,17 +474,12 @@ ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
 {
 	ibnd_fabric_t *fabric = NULL;
 	ib_portid_t my_portid = { 0 };
-	int max_hops = MAXHOPS - 1;	/* default find everything */
 	smp_engine_t engine;
 	ibnd_scan_t scan;
 
 	if (_check_ibmad_port(ibmad_port) < 0)
 		return NULL;
 
-	/* if not everything how much? */
-	if (hops >= 0)
-		max_hops = hops;
-
 	/* If not specified start from "my" port */
 	if (!from)
 		from = &my_portid;
@@ -496,6 +494,8 @@ ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
 
 	memset(&scan.selfportid, 0, sizeof(scan.selfportid));
 	scan.fabric = fabric;
+	if (hops >= 0)
+		scan.max_hops = hops;
 
 	smp_engine_init(&engine, ibmad_port, &scan, max_smps_on_wire);
 
diff --git a/infiniband-diags/libibnetdisc/src/internal.h b/infiniband-diags/libibnetdisc/src/internal.h
index 179eac6..05e254d 100644
--- a/infiniband-diags/libibnetdisc/src/internal.h
+++ b/infiniband-diags/libibnetdisc/src/internal.h
@@ -58,6 +58,7 @@
 typedef struct ibnd_scan {
 	ib_portid_t selfportid;
 	ibnd_fabric_t *fabric;
+	unsigned max_hops;
 } ibnd_scan_t;
 
 typedef struct ibnd_smp ibnd_smp_t;
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] libibnetdisc: keep total number of used SMPs
From: Sasha Khapyorsky @ 2010-04-10  0:57 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100410005536.GI4808@me>


Keep and track total number of used SMPs in smp engine structure
(total_smps field) and for statistic purpose return it with fabric
object (total_mads_used field).

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 .../libibnetdisc/include/infiniband/ibnetdisc.h    |    3 ++-
 infiniband-diags/libibnetdisc/src/ibnetdisc.c      |    2 ++
 infiniband-diags/libibnetdisc/src/internal.h       |    1 +
 infiniband-diags/libibnetdisc/src/query_smp.c      |    1 +
 4 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
index 556014e..8c38c94 100644
--- a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
+++ b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
@@ -143,7 +143,8 @@ typedef struct ibnd_fabric {
 	ibnd_node_t *nodes;
 	/* NULL terminated list of all chassis found in the fabric */
 	ibnd_chassis_t *chassis;
-	int maxhops_discovered;
+	unsigned maxhops_discovered;
+	unsigned total_mads_used;
 
 	/* internal use only */
 	ibnd_node_t *nodestbl[HTSZ];
diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
index 4012eff..65126dd 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -505,6 +505,8 @@ ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
 		if (process_mads(&engine) != 0)
 			goto error;
 
+	fabric->total_mads_used = engine.total_smps;
+
 	if (group_nodes(fabric))
 		goto error;
 
diff --git a/infiniband-diags/libibnetdisc/src/internal.h b/infiniband-diags/libibnetdisc/src/internal.h
index 05e254d..d2d4826 100644
--- a/infiniband-diags/libibnetdisc/src/internal.h
+++ b/infiniband-diags/libibnetdisc/src/internal.h
@@ -82,6 +82,7 @@ struct smp_engine {
 	cl_qmap_t smps_on_wire;
 	int num_smps_outstanding;
 	int max_smps_on_wire;
+	unsigned total_smps;
 };
 
 void smp_engine_init(smp_engine_t * engine, struct ibmad_port *ibmad_port,
diff --git a/infiniband-diags/libibnetdisc/src/query_smp.c b/infiniband-diags/libibnetdisc/src/query_smp.c
index a6878b6..1ec9752 100644
--- a/infiniband-diags/libibnetdisc/src/query_smp.c
+++ b/infiniband-diags/libibnetdisc/src/query_smp.c
@@ -133,6 +133,7 @@ int issue_smp(smp_engine_t * engine, ib_portid_t * portid,
 	portid->sl = 0;
 	portid->qp = 0;
 
+	engine->total_smps++;
 	engine->num_smps_outstanding++;
 	queue_smp(engine, smp);
 	return process_smp_queue(engine);
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] infiniband-diags/ibnetdiscover: report number of used MADs
From: Sasha Khapyorsky @ 2010-04-10  0:58 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100410005752.GL4808@me>


When '--max_hops,-m' option is specified report (in comment) a total
number of used MADs for discovery aside of number of hops.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 infiniband-diags/src/ibnetdiscover.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/infiniband-diags/src/ibnetdiscover.c b/infiniband-diags/src/ibnetdiscover.c
index 1ff8ef6..32776ad 100644
--- a/infiniband-diags/src/ibnetdiscover.c
+++ b/infiniband-diags/src/ibnetdiscover.c
@@ -444,8 +444,9 @@ int dump_topology(int group, ibnd_fabric_t * fabric)
 
 	fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t));
 	if (report_max_hops)
-		fprintf(f, "# Reported max hops discovered: %d\n",
-			fabric->maxhops_discovered);
+		fprintf(f, "# Reported max hops discovered: %u\n"
+			"# Total MADs used: %u\n",
+			fabric->maxhops_discovered, fabric->total_mads_used);
 	fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n",
 		fabric->from_node->guid,
 		mad_get_field64(fabric->from_node->info, 0,
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] libibnetdisc: no backward NodeInfo queries
From: Sasha Khapyorsky @ 2010-04-10  0:58 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100410005819.GM4808@me>


Then switch is reached via port N we don't need to query back via this
port - source node is discovered already. Finally this saves some amount
of unnecessary MADs.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 infiniband-diags/libibnetdisc/src/ibnetdisc.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
index 65126dd..03b678e 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -199,7 +199,8 @@ static int recv_port_info(smp_engine_t * engine, ibnd_smp_t * smp,
 
 	if (port_num && mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F)
 	    == IB_PORT_PHYS_STATE_LINKUP
-	    && (node->type == IB_NODE_SWITCH || node == fabric->from_node)) {
+	    && ((node->type == IB_NODE_SWITCH && port_num != local_port) ||
+		 node == fabric->from_node)) {
 		ib_portid_t path = smp->path;
 		if (extend_dpath(engine, &path, port_num) > 0)
 			query_node_info(engine, &path, node);
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] libibnetdisc: config struct for ibnd_discover_fabric()
From: Sasha Khapyorsky @ 2010-04-10  1:00 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100410005857.GN4808@me>


Instead of using static configuration parameters/flags and to have API
functions to set up each one (and so add new API when any new flag is
added) use just single configuration structure which is reenterently
passed by to ibnd_fabric_discover() function.

In order to not change API a lot we will keep some "padding" space in
this configuration structure, so it will be extendable for future
parameters/flags.

Remove old config related functions.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 .../libibnetdisc/include/infiniband/ibnetdisc.h    |   14 ++++--
 infiniband-diags/libibnetdisc/src/ibnetdisc.c      |   49 +++++---------------
 infiniband-diags/libibnetdisc/src/internal.h       |    2 +-
 infiniband-diags/libibnetdisc/src/libibnetdisc.map |    3 -
 infiniband-diags/libibnetdisc/test/testleaks.c     |   23 ++++-----
 infiniband-diags/src/iblinkinfo.c                  |   22 +++------
 infiniband-diags/src/ibnetdiscover.c               |   17 ++----
 infiniband-diags/src/ibqueryerrors.c               |   17 ++----
 8 files changed, 53 insertions(+), 94 deletions(-)

diff --git a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
index 8c38c94..136282c 100644
--- a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
+++ b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
@@ -129,6 +129,14 @@ typedef struct ibnd_chassis {
 
 #define HTSZ 137
 
+typedef struct ibnd_config {
+	unsigned max_smps;
+	unsigned show_progress;
+	unsigned max_hops;
+	unsigned debug;
+	uint8_t pad[64];
+} ibnd_config_t;
+
 /** =========================================================================
  * Fabric
  * Main fabric object which is returned and represents the data discovered
@@ -157,12 +165,10 @@ typedef struct ibnd_fabric {
 /** =========================================================================
  * Initialization (fabric operations)
  */
-MAD_EXPORT void ibnd_debug(int i);
-MAD_EXPORT void ibnd_show_progress(int i);
-MAD_EXPORT int ibnd_set_max_smps_on_wire(int i);
 
 MAD_EXPORT ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
-					       ib_portid_t * from, int hops);
+					       ib_portid_t * from,
+					       struct ibnd_config *config);
 	/**
 	 * open: (required) ibmad_port object from libibmad
 	 * from: (optional) specify the node to start scanning from.
diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
index 03b678e..6b02c2b 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -54,10 +54,6 @@
 #include "internal.h"
 #include "chassis.h"
 
-static int show_progress = 0;
-static int max_smps_on_wire = DEFAULT_MAX_SMP_ON_WIRE;
-int ibdebug;
-
 /* forward declare */
 static int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
 			   ibnd_node_t * node);
@@ -96,7 +92,8 @@ static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid,
 	ibnd_scan_t *scan = engine->user_data;
 	ibnd_fabric_t *fabric = scan->fabric;
 
-	if (scan->max_hops && fabric->maxhops_discovered >= scan->max_hops)
+	if (scan->cfg->max_hops &&
+	    fabric->maxhops_discovered >= scan->cfg->max_hops)
 		return 0;
 
 	if (portid->lid) {
@@ -289,7 +286,8 @@ static void dump_endnode(ib_portid_t * path, char *prompt,
 static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,
 			  uint8_t * mad, void *cb_data)
 {
-	ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric;
+	ibnd_scan_t *scan = engine->user_data;
+	ibnd_fabric_t *fabric = scan->fabric;
 	int i = 0;
 	uint8_t *node_info = mad + IB_SMP_DATA_OFFS;
 	ibnd_node_t *rem_node = cb_data;
@@ -319,7 +317,7 @@ static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,
 	}
 	port->guid = port_guid;
 
-	if (show_progress)
+	if (scan->cfg->show_progress)
 		dump_endnode(&smp->path, node_is_new ? "new" : "known",
 			     node, port);
 
@@ -463,16 +461,10 @@ void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric)
 	}
 }
 
-int ibnd_set_max_smps_on_wire(int i)
-{
-	int rc = max_smps_on_wire;
-	max_smps_on_wire = i;
-	return rc;
-}
-
-ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
-				    ib_portid_t * from, int hops)
+ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
+				    ib_portid_t * from, struct ibnd_config *cfg)
 {
+	struct ibnd_config default_config = { 0 };
 	ibnd_fabric_t *fabric = NULL;
 	ib_portid_t my_portid = { 0 };
 	smp_engine_t engine;
@@ -495,10 +487,11 @@ ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
 
 	memset(&scan.selfportid, 0, sizeof(scan.selfportid));
 	scan.fabric = fabric;
-	if (hops >= 0)
-		scan.max_hops = hops;
+	if (!cfg)
+		scan.cfg = &default_config;
 
-	smp_engine_init(&engine, ibmad_port, &scan, max_smps_on_wire);
+	smp_engine_init(&engine, ibmad_port, &scan, cfg->max_smps ?
+			cfg->max_smps : DEFAULT_MAX_SMP_ON_WIRE);
 
 	IBND_DEBUG("from %s\n", portid2str(from));
 
@@ -555,24 +548,6 @@ void ibnd_destroy_fabric(ibnd_fabric_t * fabric)
 	free(fabric);
 }
 
-void ibnd_debug(int i)
-{
-	if (i) {
-		ibdebug++;
-		madrpc_show_errors(1);
-		umad_debug(i);
-	} else {
-		ibdebug = 0;
-		madrpc_show_errors(0);
-		umad_debug(0);
-	}
-}
-
-void ibnd_show_progress(int i)
-{
-	show_progress = i;
-}
-
 void ibnd_iter_nodes(ibnd_fabric_t * fabric, ibnd_iter_node_func_t func,
 		     void *user_data)
 {
diff --git a/infiniband-diags/libibnetdisc/src/internal.h b/infiniband-diags/libibnetdisc/src/internal.h
index d2d4826..57034f9 100644
--- a/infiniband-diags/libibnetdisc/src/internal.h
+++ b/infiniband-diags/libibnetdisc/src/internal.h
@@ -58,7 +58,7 @@
 typedef struct ibnd_scan {
 	ib_portid_t selfportid;
 	ibnd_fabric_t *fabric;
-	unsigned max_hops;
+	struct ibnd_config *cfg;
 } ibnd_scan_t;
 
 typedef struct ibnd_smp ibnd_smp_t;
diff --git a/infiniband-diags/libibnetdisc/src/libibnetdisc.map b/infiniband-diags/libibnetdisc/src/libibnetdisc.map
index 30f7ab9..8a56fbb 100644
--- a/infiniband-diags/libibnetdisc/src/libibnetdisc.map
+++ b/infiniband-diags/libibnetdisc/src/libibnetdisc.map
@@ -1,7 +1,5 @@
 IBNETDISC_1.0 {
 	global:
-		ibnd_debug;
-		ibnd_show_progress;
 		ibnd_discover_fabric;
 		ibnd_destroy_fabric;
 		ibnd_load_fabric;
@@ -16,6 +14,5 @@ IBNETDISC_1.0 {
 		ibnd_get_chassis_slot_str;
 		ibnd_iter_nodes;
 		ibnd_iter_nodes_type;
-		ibnd_set_max_smps_on_wire;
 	local: *;
 };
diff --git a/infiniband-diags/libibnetdisc/test/testleaks.c b/infiniband-diags/libibnetdisc/test/testleaks.c
index cb5651e..da2fc0a 100644
--- a/infiniband-diags/libibnetdisc/test/testleaks.c
+++ b/infiniband-diags/libibnetdisc/test/testleaks.c
@@ -77,6 +77,7 @@ void usage(void)
 
 int main(int argc, char **argv)
 {
+	struct ibnd_config config = { 0 };
 	int rc = 0;
 	char *ca = 0;
 	int ca_port = 0;
@@ -84,7 +85,6 @@ int main(int argc, char **argv)
 	uint64_t guid = 0;
 	char *dr_path = NULL;
 	char *from = NULL;
-	int hops = 0;
 	ib_portid_t port_id;
 	int iters = -1;
 
@@ -118,7 +118,7 @@ int main(int argc, char **argv)
 			break;
 		switch (ch) {
 		case 2:
-			ibnd_debug(1);
+			config.debug++;
 			break;
 		case 'f':
 			from = strdup(optarg);
@@ -133,7 +133,7 @@ int main(int argc, char **argv)
 			dr_path = strdup(optarg);
 			break;
 		case 'n':
-			hops = (int)strtol(optarg, NULL, 0);
+			config.max_hops = strtoul(optarg, NULL, 0);
 			break;
 		case 'i':
 			iters = (int)strtol(optarg, NULL, 0);
@@ -161,21 +161,18 @@ int main(int argc, char **argv)
 			/* only scan part of the fabric */
 			str2drpath(&(port_id.drpath), from, 0, 0);
 			if ((fabric = ibnd_discover_fabric(ibmad_port,
-							   &port_id,
-							   hops)) == NULL) {
+							   &port_id, &config))
+			    == NULL) {
 				fprintf(stderr, "discover failed\n");
 				rc = 1;
 				goto close_port;
 			}
 			guid = 0;
-		} else {
-			if ((fabric =
-			     ibnd_discover_fabric(ibmad_port, NULL,
-						  -1)) == NULL) {
-				fprintf(stderr, "discover failed\n");
-				rc = 1;
-				goto close_port;
-			}
+		} else if ((fabric = ibnd_discover_fabric(ibmad_port, NULL,
+							  &config)) == NULL) {
+			fprintf(stderr, "discover failed\n");
+			rc = 1;
+			goto close_port;
 		}
 
 		ibnd_destroy_fabric(fabric);
diff --git a/infiniband-diags/src/iblinkinfo.c b/infiniband-diags/src/iblinkinfo.c
index 5627dc9..029573f 100644
--- a/infiniband-diags/src/iblinkinfo.c
+++ b/infiniband-diags/src/iblinkinfo.c
@@ -61,13 +61,11 @@ static uint64_t guid = 0;
 static char *guid_str = NULL;
 static char *dr_path = NULL;
 static int all = 0;
-static int hops = 0;
 
 static int down_links_only = 0;
 static int line_mode = 0;
 static int add_sw_settings = 0;
 static int print_port_guids = 0;
-static int outstanding_smps = 0; /* use default from lib */
 
 static unsigned int get_max(unsigned int num)
 {
@@ -242,6 +240,7 @@ void print_switch(ibnd_node_t * node, void *user_data)
 
 static int process_opt(void *context, int ch, char *optarg)
 {
+	struct ibnd_config *cfg = context;
 	switch (ch) {
 	case 1:
 		node_name_map_file = strdup(optarg);
@@ -260,7 +259,7 @@ static int process_opt(void *context, int ch, char *optarg)
 		all = 1;
 		break;
 	case 'n':
-		hops = (int)strtol(optarg, NULL, 0);
+		cfg->max_hops = strtoul(optarg, NULL, 0);
 		break;
 	case 'd':
 		down_links_only = 1;
@@ -277,7 +276,7 @@ static int process_opt(void *context, int ch, char *optarg)
 	case 'R':		/* nop */
 		break;
 	case 'o':
-		outstanding_smps = atoi(optarg);
+		cfg->max_smps = strtoul(optarg, NULL, 0);
 		break;
 	default:
 		return -1;
@@ -288,6 +287,7 @@ static int process_opt(void *context, int ch, char *optarg)
 
 int main(int argc, char **argv)
 {
+	struct ibnd_config config = { 0 };
 	int rc = 0;
 	int resolved = -1;
 	ibnd_fabric_t *fabric = NULL;
@@ -324,15 +324,12 @@ int main(int argc, char **argv)
 	};
 	char usage_args[] = "";
 
-	ibdiag_process_opts(argc, argv, NULL, "SDandlpgRGL", opts, process_opt,
-			    usage_args, NULL);
+	ibdiag_process_opts(argc, argv, &config, "SDandlpgRGL", opts,
+			    process_opt, usage_args, NULL);
 
 	argc -= optind;
 	argv += optind;
 
-	if (ibverbose)
-		ibnd_debug(1);
-
 	ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
 	if (!ibmad_port) {
 		fprintf(stderr, "Failed to open %s port %d", ibd_ca,
@@ -345,9 +342,6 @@ int main(int argc, char **argv)
 
 	node_name_map = open_node_name_map(node_name_map_file);
 
-	if (outstanding_smps)
-		ibnd_set_max_smps_on_wire(outstanding_smps);
-
 	if (dr_path && load_cache_file) {
 		fprintf(stderr, "Cannot specify cache and direct route path\n");
 		exit(1);
@@ -377,12 +371,12 @@ int main(int argc, char **argv)
 	} else {
 		if (resolved >= 0 &&
 		    !(fabric =
-		      ibnd_discover_fabric(ibmad_port, &port_id, hops)))
+		      ibnd_discover_fabric(ibmad_port, &port_id, &config)))
 			IBWARN("Single node discover failed;"
 			       " attempting full scan\n");
 
 		if (!fabric &&
-		    !(fabric = ibnd_discover_fabric(ibmad_port, NULL, -1))) {
+		    !(fabric = ibnd_discover_fabric(ibmad_port, NULL, &config))) {
 			fprintf(stderr, "discover failed\n");
 			rc = 1;
 			goto close_port;
diff --git a/infiniband-diags/src/ibnetdiscover.c b/infiniband-diags/src/ibnetdiscover.c
index 32776ad..f40d0f9 100644
--- a/infiniband-diags/src/ibnetdiscover.c
+++ b/infiniband-diags/src/ibnetdiscover.c
@@ -67,7 +67,6 @@ static char *cache_file = NULL;
 static char *load_cache_file = NULL;
 
 static int report_max_hops = 0;
-static int outstanding_smps = 0; /* use default from lib */
 
 /**
  * Define our own conversion functions to maintain compatibility with the old
@@ -616,6 +615,7 @@ static int list, group, ports_report;
 
 static int process_opt(void *context, int ch, char *optarg)
 {
+	struct ibnd_config *cfg = context;
 	switch (ch) {
 	case 1:
 		node_name_map_file = strdup(optarg);
@@ -627,7 +627,7 @@ static int process_opt(void *context, int ch, char *optarg)
 		load_cache_file = strdup(optarg);
 		break;
 	case 's':
-		ibnd_show_progress(1);
+		cfg->show_progress = 1;
 		break;
 	case 'l':
 		list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
@@ -651,7 +651,7 @@ static int process_opt(void *context, int ch, char *optarg)
 		report_max_hops = 1;
 		break;
 	case 'o':
-		outstanding_smps = atoi(optarg);
+		cfg->max_smps = strtoul(optarg, NULL, 0);
 		break;
 	default:
 		return -1;
@@ -662,6 +662,7 @@ static int process_opt(void *context, int ch, char *optarg)
 
 int main(int argc, char **argv)
 {
+	struct ibnd_config config = { 0 };
 	ibnd_fabric_t *fabric = NULL;
 
 	struct ibmad_port *ibmad_port;
@@ -689,7 +690,7 @@ int main(int argc, char **argv)
 	};
 	char usage_args[] = "[topology-file]";
 
-	ibdiag_process_opts(argc, argv, NULL, "sGDL", opts, process_opt,
+	ibdiag_process_opts(argc, argv, &config, "sGDL", opts, process_opt,
 			    usage_args, NULL);
 
 	f = stdout;
@@ -697,9 +698,6 @@ int main(int argc, char **argv)
 	argc -= optind;
 	argv += optind;
 
-	if (ibverbose)
-		ibnd_debug(1);
-
 	ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 2);
 	if (!ibmad_port)
 		IBERROR("Failed to open %s port %d", ibd_ca, ibd_ca_port);
@@ -712,15 +710,12 @@ int main(int argc, char **argv)
 
 	node_name_map = open_node_name_map(node_name_map_file);
 
-	if (outstanding_smps)
-		ibnd_set_max_smps_on_wire(outstanding_smps);
-
 	if (load_cache_file) {
 		if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL)
 			IBERROR("loading cached fabric failed\n");
 	} else {
 		if ((fabric =
-		     ibnd_discover_fabric(ibmad_port, NULL, -1)) == NULL)
+		     ibnd_discover_fabric(ibmad_port, NULL, &config)) == NULL)
 			IBERROR("discover failed\n");
 	}
 
diff --git a/infiniband-diags/src/ibqueryerrors.c b/infiniband-diags/src/ibqueryerrors.c
index 725e098..e896254 100644
--- a/infiniband-diags/src/ibqueryerrors.c
+++ b/infiniband-diags/src/ibqueryerrors.c
@@ -70,7 +70,6 @@ enum MAD_FIELDS suppressed_fields[SUP_MAX];
 char *dr_path = NULL;
 uint8_t node_type_to_print = 0;
 unsigned clear_errors = 0, clear_counts = 0, details = 0;
-static int outstanding_smps = 0; /* use default from lib */
 
 #define PRINT_SWITCH 0x1
 #define PRINT_CA     0x2
@@ -483,6 +482,7 @@ static void calculate_suppressed_fields(char *str)
 
 static int process_opt(void *context, int ch, char *optarg)
 {
+	struct ibnd_config *cfg = context;
 	switch (ch) {
 	case 's':
 		calculate_suppressed_fields(optarg);
@@ -532,7 +532,7 @@ static int process_opt(void *context, int ch, char *optarg)
 		clear_counts = 1;
 		break;
 	case 'o':
-		outstanding_smps = atoi(optarg);
+		cfg->max_smps = strtoul(optarg, NULL, 0);
 		break;
 	default:
 		return -1;
@@ -543,6 +543,7 @@ static int process_opt(void *context, int ch, char *optarg)
 
 int main(int argc, char **argv)
 {
+	struct ibnd_config config = { 0 };
 	int resolved = -1;
 	ib_portid_t portid = { 0 };
 	int rc = 0;
@@ -586,7 +587,7 @@ int main(int argc, char **argv)
 	char usage_args[] = "";
 
 	memset(suppressed_fields, 0, sizeof suppressed_fields);
-	ibdiag_process_opts(argc, argv, NULL, "scnSrRDGL", opts, process_opt,
+	ibdiag_process_opts(argc, argv, &config, "scnSrRDGL", opts, process_opt,
 			    usage_args, NULL);
 
 	argc -= optind;
@@ -595,9 +596,6 @@ int main(int argc, char **argv)
 	if (!node_type_to_print)
 		node_type_to_print = PRINT_ALL;
 
-	if (ibverbose)
-		ibnd_debug(1);
-
 	ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
 	if (!ibmad_port)
 		IBERROR("Failed to open port; %s:%d\n", ibd_ca, ibd_ca_port);
@@ -607,9 +605,6 @@ int main(int argc, char **argv)
 
 	node_name_map = open_node_name_map(node_name_map_file);
 
-	if (outstanding_smps)
-		ibnd_set_max_smps_on_wire(outstanding_smps);
-
 	if (dr_path && load_cache_file) {
 		fprintf(stderr, "Cannot specify cache and direct route path\n");
 		exit(1);
@@ -642,8 +637,8 @@ int main(int argc, char **argv)
 			IBWARN("Single node discover failed;"
 			       " attempting full scan");
 
-		if (!fabric &&
-		    !(fabric = ibnd_discover_fabric(ibmad_port, NULL, -1))) {
+		if (!fabric && !(fabric = ibnd_discover_fabric(ibmad_port, NULL,
+							       &config))) {
 			fprintf(stderr, "discover failed\n");
 			rc = 1;
 			goto close_port;
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [infiniband-diags] fix libibnetdisc corner case when user tries to re-cache a loaded cache
From: Sasha Khapyorsky @ 2010-04-10  1:04 UTC (permalink / raw)
  To: Al Chu; +Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1270833890.17987.16.camel-X2zTWyBD0EhliZ7u+bvwcg@public.gmane.org>

On 10:24 Fri 09 Apr     , Al Chu wrote:
> Hey Sasha,
> 
> Noticed this corner case.  If I load a ibnetdiscover cache, then try to
> re-cache it, the cache doesn't store things properly b/c I didn't
> reconstruct one fabric data structure properly.  This fixes that bug.
> 
> Al
> 
> -- 
> Albert Chu
> chu11-i2BcT+NCU+M@public.gmane.org
> Computer Scientist
> High Performance Systems Division
> Lawrence Livermore National Laboratory

> Date: Fri, 9 Apr 2010 10:12:47 -0700
> From: Albert Chu <chu11-i2BcT+NCU+M@public.gmane.org>
> Subject: [PATCH] fix libibnetdisc corner case when user tries to re-cache
>  a
> 	loaded cache
> Message-Id: <1270833600.17987.15.camel-X2zTWyBD0EhliZ7u+bvwcg@public.gmane.org>
> Mime-Version: 1.0
> Content-Transfer-Encoding: 7bit
> 
> 
> Signed-off-by: Albert Chu <chu11-i2BcT+NCU+M@public.gmane.org>

Applied. Thanks.

Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v2] libibnetdisc: config struct for ibnd_discover_fabric()
From: Sasha Khapyorsky @ 2010-04-10  1:41 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100410010050.GO4808@me>


Instead of using static configuration parameters/flags and to have API
functions to set up each one (and so add new API when any new flag is
added) use just single configuration structure which is reenterently
passed by to ibnd_fabric_discover() function.

In order to not change API a lot we will keep some "padding" space in
this configuration structure, so it will be extendable for future
parameters/flags.

Remove old config related functions.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
v2 - proper scan.cfg initialization (in ibnd_discover_fabric())

 .../libibnetdisc/include/infiniband/ibnetdisc.h    |   14 ++++--
 infiniband-diags/libibnetdisc/src/ibnetdisc.c      |   48 +++++---------------
 infiniband-diags/libibnetdisc/src/internal.h       |    2 +-
 infiniband-diags/libibnetdisc/src/libibnetdisc.map |    3 -
 infiniband-diags/libibnetdisc/test/testleaks.c     |   23 ++++-----
 infiniband-diags/src/iblinkinfo.c                  |   22 +++------
 infiniband-diags/src/ibnetdiscover.c               |   17 +++-----
 infiniband-diags/src/ibqueryerrors.c               |   17 +++-----
 8 files changed, 52 insertions(+), 94 deletions(-)

diff --git a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
index 8c38c94..136282c 100644
--- a/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
+++ b/infiniband-diags/libibnetdisc/include/infiniband/ibnetdisc.h
@@ -129,6 +129,14 @@ typedef struct ibnd_chassis {
 
 #define HTSZ 137
 
+typedef struct ibnd_config {
+	unsigned max_smps;
+	unsigned show_progress;
+	unsigned max_hops;
+	unsigned debug;
+	uint8_t pad[64];
+} ibnd_config_t;
+
 /** =========================================================================
  * Fabric
  * Main fabric object which is returned and represents the data discovered
@@ -157,12 +165,10 @@ typedef struct ibnd_fabric {
 /** =========================================================================
  * Initialization (fabric operations)
  */
-MAD_EXPORT void ibnd_debug(int i);
-MAD_EXPORT void ibnd_show_progress(int i);
-MAD_EXPORT int ibnd_set_max_smps_on_wire(int i);
 
 MAD_EXPORT ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
-					       ib_portid_t * from, int hops);
+					       ib_portid_t * from,
+					       struct ibnd_config *config);
 	/**
 	 * open: (required) ibmad_port object from libibmad
 	 * from: (optional) specify the node to start scanning from.
diff --git a/infiniband-diags/libibnetdisc/src/ibnetdisc.c b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
index 03b678e..0762867 100644
--- a/infiniband-diags/libibnetdisc/src/ibnetdisc.c
+++ b/infiniband-diags/libibnetdisc/src/ibnetdisc.c
@@ -54,10 +54,6 @@
 #include "internal.h"
 #include "chassis.h"
 
-static int show_progress = 0;
-static int max_smps_on_wire = DEFAULT_MAX_SMP_ON_WIRE;
-int ibdebug;
-
 /* forward declare */
 static int query_node_info(smp_engine_t * engine, ib_portid_t * portid,
 			   ibnd_node_t * node);
@@ -96,7 +92,8 @@ static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid,
 	ibnd_scan_t *scan = engine->user_data;
 	ibnd_fabric_t *fabric = scan->fabric;
 
-	if (scan->max_hops && fabric->maxhops_discovered >= scan->max_hops)
+	if (scan->cfg->max_hops &&
+	    fabric->maxhops_discovered >= scan->cfg->max_hops)
 		return 0;
 
 	if (portid->lid) {
@@ -289,7 +286,8 @@ static void dump_endnode(ib_portid_t * path, char *prompt,
 static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,
 			  uint8_t * mad, void *cb_data)
 {
-	ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric;
+	ibnd_scan_t *scan = engine->user_data;
+	ibnd_fabric_t *fabric = scan->fabric;
 	int i = 0;
 	uint8_t *node_info = mad + IB_SMP_DATA_OFFS;
 	ibnd_node_t *rem_node = cb_data;
@@ -319,7 +317,7 @@ static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,
 	}
 	port->guid = port_guid;
 
-	if (show_progress)
+	if (scan->cfg->show_progress)
 		dump_endnode(&smp->path, node_is_new ? "new" : "known",
 			     node, port);
 
@@ -463,16 +461,10 @@ void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric)
 	}
 }
 
-int ibnd_set_max_smps_on_wire(int i)
-{
-	int rc = max_smps_on_wire;
-	max_smps_on_wire = i;
-	return rc;
-}
-
-ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
-				    ib_portid_t * from, int hops)
+ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port *ibmad_port,
+				    ib_portid_t * from, struct ibnd_config *cfg)
 {
+	struct ibnd_config default_config = { 0 };
 	ibnd_fabric_t *fabric = NULL;
 	ib_portid_t my_portid = { 0 };
 	smp_engine_t engine;
@@ -495,10 +487,10 @@ ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
 
 	memset(&scan.selfportid, 0, sizeof(scan.selfportid));
 	scan.fabric = fabric;
-	if (hops >= 0)
-		scan.max_hops = hops;
+	scan.cfg = cfg ? cfg : &default_config;
 
-	smp_engine_init(&engine, ibmad_port, &scan, max_smps_on_wire);
+	smp_engine_init(&engine, ibmad_port, &scan, cfg->max_smps ?
+			cfg->max_smps : DEFAULT_MAX_SMP_ON_WIRE);
 
 	IBND_DEBUG("from %s\n", portid2str(from));
 
@@ -555,24 +547,6 @@ void ibnd_destroy_fabric(ibnd_fabric_t * fabric)
 	free(fabric);
 }
 
-void ibnd_debug(int i)
-{
-	if (i) {
-		ibdebug++;
-		madrpc_show_errors(1);
-		umad_debug(i);
-	} else {
-		ibdebug = 0;
-		madrpc_show_errors(0);
-		umad_debug(0);
-	}
-}
-
-void ibnd_show_progress(int i)
-{
-	show_progress = i;
-}
-
 void ibnd_iter_nodes(ibnd_fabric_t * fabric, ibnd_iter_node_func_t func,
 		     void *user_data)
 {
diff --git a/infiniband-diags/libibnetdisc/src/internal.h b/infiniband-diags/libibnetdisc/src/internal.h
index d2d4826..57034f9 100644
--- a/infiniband-diags/libibnetdisc/src/internal.h
+++ b/infiniband-diags/libibnetdisc/src/internal.h
@@ -58,7 +58,7 @@
 typedef struct ibnd_scan {
 	ib_portid_t selfportid;
 	ibnd_fabric_t *fabric;
-	unsigned max_hops;
+	struct ibnd_config *cfg;
 } ibnd_scan_t;
 
 typedef struct ibnd_smp ibnd_smp_t;
diff --git a/infiniband-diags/libibnetdisc/src/libibnetdisc.map b/infiniband-diags/libibnetdisc/src/libibnetdisc.map
index 30f7ab9..8a56fbb 100644
--- a/infiniband-diags/libibnetdisc/src/libibnetdisc.map
+++ b/infiniband-diags/libibnetdisc/src/libibnetdisc.map
@@ -1,7 +1,5 @@
 IBNETDISC_1.0 {
 	global:
-		ibnd_debug;
-		ibnd_show_progress;
 		ibnd_discover_fabric;
 		ibnd_destroy_fabric;
 		ibnd_load_fabric;
@@ -16,6 +14,5 @@ IBNETDISC_1.0 {
 		ibnd_get_chassis_slot_str;
 		ibnd_iter_nodes;
 		ibnd_iter_nodes_type;
-		ibnd_set_max_smps_on_wire;
 	local: *;
 };
diff --git a/infiniband-diags/libibnetdisc/test/testleaks.c b/infiniband-diags/libibnetdisc/test/testleaks.c
index cb5651e..da2fc0a 100644
--- a/infiniband-diags/libibnetdisc/test/testleaks.c
+++ b/infiniband-diags/libibnetdisc/test/testleaks.c
@@ -77,6 +77,7 @@ void usage(void)
 
 int main(int argc, char **argv)
 {
+	struct ibnd_config config = { 0 };
 	int rc = 0;
 	char *ca = 0;
 	int ca_port = 0;
@@ -84,7 +85,6 @@ int main(int argc, char **argv)
 	uint64_t guid = 0;
 	char *dr_path = NULL;
 	char *from = NULL;
-	int hops = 0;
 	ib_portid_t port_id;
 	int iters = -1;
 
@@ -118,7 +118,7 @@ int main(int argc, char **argv)
 			break;
 		switch (ch) {
 		case 2:
-			ibnd_debug(1);
+			config.debug++;
 			break;
 		case 'f':
 			from = strdup(optarg);
@@ -133,7 +133,7 @@ int main(int argc, char **argv)
 			dr_path = strdup(optarg);
 			break;
 		case 'n':
-			hops = (int)strtol(optarg, NULL, 0);
+			config.max_hops = strtoul(optarg, NULL, 0);
 			break;
 		case 'i':
 			iters = (int)strtol(optarg, NULL, 0);
@@ -161,21 +161,18 @@ int main(int argc, char **argv)
 			/* only scan part of the fabric */
 			str2drpath(&(port_id.drpath), from, 0, 0);
 			if ((fabric = ibnd_discover_fabric(ibmad_port,
-							   &port_id,
-							   hops)) == NULL) {
+							   &port_id, &config))
+			    == NULL) {
 				fprintf(stderr, "discover failed\n");
 				rc = 1;
 				goto close_port;
 			}
 			guid = 0;
-		} else {
-			if ((fabric =
-			     ibnd_discover_fabric(ibmad_port, NULL,
-						  -1)) == NULL) {
-				fprintf(stderr, "discover failed\n");
-				rc = 1;
-				goto close_port;
-			}
+		} else if ((fabric = ibnd_discover_fabric(ibmad_port, NULL,
+							  &config)) == NULL) {
+			fprintf(stderr, "discover failed\n");
+			rc = 1;
+			goto close_port;
 		}
 
 		ibnd_destroy_fabric(fabric);
diff --git a/infiniband-diags/src/iblinkinfo.c b/infiniband-diags/src/iblinkinfo.c
index 5627dc9..029573f 100644
--- a/infiniband-diags/src/iblinkinfo.c
+++ b/infiniband-diags/src/iblinkinfo.c
@@ -61,13 +61,11 @@ static uint64_t guid = 0;
 static char *guid_str = NULL;
 static char *dr_path = NULL;
 static int all = 0;
-static int hops = 0;
 
 static int down_links_only = 0;
 static int line_mode = 0;
 static int add_sw_settings = 0;
 static int print_port_guids = 0;
-static int outstanding_smps = 0; /* use default from lib */
 
 static unsigned int get_max(unsigned int num)
 {
@@ -242,6 +240,7 @@ void print_switch(ibnd_node_t * node, void *user_data)
 
 static int process_opt(void *context, int ch, char *optarg)
 {
+	struct ibnd_config *cfg = context;
 	switch (ch) {
 	case 1:
 		node_name_map_file = strdup(optarg);
@@ -260,7 +259,7 @@ static int process_opt(void *context, int ch, char *optarg)
 		all = 1;
 		break;
 	case 'n':
-		hops = (int)strtol(optarg, NULL, 0);
+		cfg->max_hops = strtoul(optarg, NULL, 0);
 		break;
 	case 'd':
 		down_links_only = 1;
@@ -277,7 +276,7 @@ static int process_opt(void *context, int ch, char *optarg)
 	case 'R':		/* nop */
 		break;
 	case 'o':
-		outstanding_smps = atoi(optarg);
+		cfg->max_smps = strtoul(optarg, NULL, 0);
 		break;
 	default:
 		return -1;
@@ -288,6 +287,7 @@ static int process_opt(void *context, int ch, char *optarg)
 
 int main(int argc, char **argv)
 {
+	struct ibnd_config config = { 0 };
 	int rc = 0;
 	int resolved = -1;
 	ibnd_fabric_t *fabric = NULL;
@@ -324,15 +324,12 @@ int main(int argc, char **argv)
 	};
 	char usage_args[] = "";
 
-	ibdiag_process_opts(argc, argv, NULL, "SDandlpgRGL", opts, process_opt,
-			    usage_args, NULL);
+	ibdiag_process_opts(argc, argv, &config, "SDandlpgRGL", opts,
+			    process_opt, usage_args, NULL);
 
 	argc -= optind;
 	argv += optind;
 
-	if (ibverbose)
-		ibnd_debug(1);
-
 	ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
 	if (!ibmad_port) {
 		fprintf(stderr, "Failed to open %s port %d", ibd_ca,
@@ -345,9 +342,6 @@ int main(int argc, char **argv)
 
 	node_name_map = open_node_name_map(node_name_map_file);
 
-	if (outstanding_smps)
-		ibnd_set_max_smps_on_wire(outstanding_smps);
-
 	if (dr_path && load_cache_file) {
 		fprintf(stderr, "Cannot specify cache and direct route path\n");
 		exit(1);
@@ -377,12 +371,12 @@ int main(int argc, char **argv)
 	} else {
 		if (resolved >= 0 &&
 		    !(fabric =
-		      ibnd_discover_fabric(ibmad_port, &port_id, hops)))
+		      ibnd_discover_fabric(ibmad_port, &port_id, &config)))
 			IBWARN("Single node discover failed;"
 			       " attempting full scan\n");
 
 		if (!fabric &&
-		    !(fabric = ibnd_discover_fabric(ibmad_port, NULL, -1))) {
+		    !(fabric = ibnd_discover_fabric(ibmad_port, NULL, &config))) {
 			fprintf(stderr, "discover failed\n");
 			rc = 1;
 			goto close_port;
diff --git a/infiniband-diags/src/ibnetdiscover.c b/infiniband-diags/src/ibnetdiscover.c
index 32776ad..f40d0f9 100644
--- a/infiniband-diags/src/ibnetdiscover.c
+++ b/infiniband-diags/src/ibnetdiscover.c
@@ -67,7 +67,6 @@ static char *cache_file = NULL;
 static char *load_cache_file = NULL;
 
 static int report_max_hops = 0;
-static int outstanding_smps = 0; /* use default from lib */
 
 /**
  * Define our own conversion functions to maintain compatibility with the old
@@ -616,6 +615,7 @@ static int list, group, ports_report;
 
 static int process_opt(void *context, int ch, char *optarg)
 {
+	struct ibnd_config *cfg = context;
 	switch (ch) {
 	case 1:
 		node_name_map_file = strdup(optarg);
@@ -627,7 +627,7 @@ static int process_opt(void *context, int ch, char *optarg)
 		load_cache_file = strdup(optarg);
 		break;
 	case 's':
-		ibnd_show_progress(1);
+		cfg->show_progress = 1;
 		break;
 	case 'l':
 		list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE;
@@ -651,7 +651,7 @@ static int process_opt(void *context, int ch, char *optarg)
 		report_max_hops = 1;
 		break;
 	case 'o':
-		outstanding_smps = atoi(optarg);
+		cfg->max_smps = strtoul(optarg, NULL, 0);
 		break;
 	default:
 		return -1;
@@ -662,6 +662,7 @@ static int process_opt(void *context, int ch, char *optarg)
 
 int main(int argc, char **argv)
 {
+	struct ibnd_config config = { 0 };
 	ibnd_fabric_t *fabric = NULL;
 
 	struct ibmad_port *ibmad_port;
@@ -689,7 +690,7 @@ int main(int argc, char **argv)
 	};
 	char usage_args[] = "[topology-file]";
 
-	ibdiag_process_opts(argc, argv, NULL, "sGDL", opts, process_opt,
+	ibdiag_process_opts(argc, argv, &config, "sGDL", opts, process_opt,
 			    usage_args, NULL);
 
 	f = stdout;
@@ -697,9 +698,6 @@ int main(int argc, char **argv)
 	argc -= optind;
 	argv += optind;
 
-	if (ibverbose)
-		ibnd_debug(1);
-
 	ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 2);
 	if (!ibmad_port)
 		IBERROR("Failed to open %s port %d", ibd_ca, ibd_ca_port);
@@ -712,15 +710,12 @@ int main(int argc, char **argv)
 
 	node_name_map = open_node_name_map(node_name_map_file);
 
-	if (outstanding_smps)
-		ibnd_set_max_smps_on_wire(outstanding_smps);
-
 	if (load_cache_file) {
 		if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL)
 			IBERROR("loading cached fabric failed\n");
 	} else {
 		if ((fabric =
-		     ibnd_discover_fabric(ibmad_port, NULL, -1)) == NULL)
+		     ibnd_discover_fabric(ibmad_port, NULL, &config)) == NULL)
 			IBERROR("discover failed\n");
 	}
 
diff --git a/infiniband-diags/src/ibqueryerrors.c b/infiniband-diags/src/ibqueryerrors.c
index 725e098..e896254 100644
--- a/infiniband-diags/src/ibqueryerrors.c
+++ b/infiniband-diags/src/ibqueryerrors.c
@@ -70,7 +70,6 @@ enum MAD_FIELDS suppressed_fields[SUP_MAX];
 char *dr_path = NULL;
 uint8_t node_type_to_print = 0;
 unsigned clear_errors = 0, clear_counts = 0, details = 0;
-static int outstanding_smps = 0; /* use default from lib */
 
 #define PRINT_SWITCH 0x1
 #define PRINT_CA     0x2
@@ -483,6 +482,7 @@ static void calculate_suppressed_fields(char *str)
 
 static int process_opt(void *context, int ch, char *optarg)
 {
+	struct ibnd_config *cfg = context;
 	switch (ch) {
 	case 's':
 		calculate_suppressed_fields(optarg);
@@ -532,7 +532,7 @@ static int process_opt(void *context, int ch, char *optarg)
 		clear_counts = 1;
 		break;
 	case 'o':
-		outstanding_smps = atoi(optarg);
+		cfg->max_smps = strtoul(optarg, NULL, 0);
 		break;
 	default:
 		return -1;
@@ -543,6 +543,7 @@ static int process_opt(void *context, int ch, char *optarg)
 
 int main(int argc, char **argv)
 {
+	struct ibnd_config config = { 0 };
 	int resolved = -1;
 	ib_portid_t portid = { 0 };
 	int rc = 0;
@@ -586,7 +587,7 @@ int main(int argc, char **argv)
 	char usage_args[] = "";
 
 	memset(suppressed_fields, 0, sizeof suppressed_fields);
-	ibdiag_process_opts(argc, argv, NULL, "scnSrRDGL", opts, process_opt,
+	ibdiag_process_opts(argc, argv, &config, "scnSrRDGL", opts, process_opt,
 			    usage_args, NULL);
 
 	argc -= optind;
@@ -595,9 +596,6 @@ int main(int argc, char **argv)
 	if (!node_type_to_print)
 		node_type_to_print = PRINT_ALL;
 
-	if (ibverbose)
-		ibnd_debug(1);
-
 	ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
 	if (!ibmad_port)
 		IBERROR("Failed to open port; %s:%d\n", ibd_ca, ibd_ca_port);
@@ -607,9 +605,6 @@ int main(int argc, char **argv)
 
 	node_name_map = open_node_name_map(node_name_map_file);
 
-	if (outstanding_smps)
-		ibnd_set_max_smps_on_wire(outstanding_smps);
-
 	if (dr_path && load_cache_file) {
 		fprintf(stderr, "Cannot specify cache and direct route path\n");
 		exit(1);
@@ -642,8 +637,8 @@ int main(int argc, char **argv)
 			IBWARN("Single node discover failed;"
 			       " attempting full scan");
 
-		if (!fabric &&
-		    !(fabric = ibnd_discover_fabric(ibmad_port, NULL, -1))) {
+		if (!fabric && !(fabric = ibnd_discover_fabric(ibmad_port, NULL,
+							       &config))) {
 			fprintf(stderr, "discover failed\n");
 			rc = 1;
 			goto close_port;
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] libibmad: add explicit extern for ibdebug prototype
From: Sasha Khapyorsky @ 2010-04-10 13:18 UTC (permalink / raw)
  To: Ira Weiny
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Hal Rosenstock
In-Reply-To: <20100218124931.4d6ef34b.weiny2-i2BcT+NCU+M@public.gmane.org>


'ibdebug' variable was not declared as 'extern', as result includers
(libraries and programs) may have its own copy of this variable. As
example libibnetdisc and ibnetdiscover.

Signed-off-by: Sasha Khapyorsky <sashak-smomgflXvOZWk0Htik3J/w@public.gmane.org>
---
 libibmad/include/infiniband/mad.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/libibmad/include/infiniband/mad.h b/libibmad/include/infiniband/mad.h
index 02ef551..0687c06 100644
--- a/libibmad/include/infiniband/mad.h
+++ b/libibmad/include/infiniband/mad.h
@@ -1031,7 +1031,7 @@ MAD_EXPORT ib_mad_dump_fn
     mad_dump_perfcounters_xmt_disc, mad_dump_perfcounters_rcv_err,
     mad_dump_portsamples_control;
 
-MAD_EXPORT int ibdebug;
+MAD_EXPORT extern int ibdebug;
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #ifndef ntohll
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] ummunotify: Userspace support for MMU notifications
From: Eric B Munson @ 2010-04-12  6:22 UTC (permalink / raw)
  To: akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA, rolandd-FYB4Gu1CFyUAvxtiuMwx3w,
	peterz-wEGCiKHe2LqWVfeAwA7xHQ, pavel-+ZI9xUNit7I,
	mingo-X9Un+BFzKDI, Eric B Munson

Andrew,

I am resubmitting this patch because I believe that the discussion
has shown this to be an acceptable solution.  I have fixed the 32 bit
build errors, but other than that change, the code is the same as
Roland's V3 patch.

From: Roland Dreier <rolandd-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>

As discussed in <http://article.gmane.org/gmane.linux.drivers.openib/61925>
and follow-up messages, libraries using RDMA would like to track
precisely when application code changes memory mapping via free(),
munmap(), etc.  Current pure-userspace solutions using malloc hooks
and other tricks are not robust, and the feeling among experts is that
the issue is unfixable without kernel help.

We solve this not by implementing the full API proposed in the email
linked above but rather with a simpler and more generic interface,
which may be useful in other contexts.  Specifically, we implement a
new character device driver, ummunotify, that creates a /dev/ummunotify
node.  A userspace process can open this node read-only and use the fd
as follows:

 1. ioctl() to register/unregister an address range to watch in the
    kernel (cf struct ummunotify_register_ioctl in <linux/ummunotify.h>).

 2. read() to retrieve events generated when a mapping in a watched
    address range is invalidated (cf struct ummunotify_event in
    <linux/ummunotify.h>).  select()/poll()/epoll() and SIGIO are
    handled for this IO.

 3. mmap() one page at offset 0 to map a kernel page that contains a
    generation counter that is incremented each time an event is
    generated.  This allows userspace to have a fast path that checks
    that no events have occurred without a system call.

Thanks to Jason Gunthorpe <jgunthorpe <at> obsidianresearch.com> for
suggestions on the interface design.  Also thanks to Jeff Squyres
<jsquyres <at> cisco.com> for prototyping support for this in Open MPI, which
helped find several bugs during development.

Signed-off-by: Roland Dreier <rolandd-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Signed-off-by: Eric B Munson <ebmunson-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

---

Changes since v3:
 - Fixed replaced [get|put] user with copy_[from|to]_user to fix x86
   builds
---
 Documentation/Makefile                  |    3 +-
 Documentation/ummunotify/Makefile       |    7 +
 Documentation/ummunotify/ummunotify.txt |  150 ++++++++
 Documentation/ummunotify/umn-test.c     |  200 +++++++++++
 drivers/char/Kconfig                    |   12 +
 drivers/char/Makefile                   |    1 +
 drivers/char/ummunotify.c               |  567 +++++++++++++++++++++++++++++++
 include/linux/ummunotify.h              |  121 +++++++
 8 files changed, 1060 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/ummunotify/Makefile
 create mode 100644 Documentation/ummunotify/ummunotify.txt
 create mode 100644 Documentation/ummunotify/umn-test.c
 create mode 100644 drivers/char/ummunotify.c
 create mode 100644 include/linux/ummunotify.h

diff --git a/Documentation/Makefile b/Documentation/Makefile
index 6fc7ea1..27ba76a 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,3 +1,4 @@
 obj-m := DocBook/ accounting/ auxdisplay/ connector/ \
 	filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \
-	pcmcia/ spi/ timers/ video4linux/ vm/ watchdog/src/
+	pcmcia/ spi/ timers/ video4linux/ vm/ ummunotify/ \
+	watchdog/src/
diff --git a/Documentation/ummunotify/Makefile b/Documentation/ummunotify/Makefile
new file mode 100644
index 0000000..89f31a0
--- /dev/null
+++ b/Documentation/ummunotify/Makefile
@@ -0,0 +1,7 @@
+# List of programs to build
+hostprogs-y := umn-test
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_umn-test.o += -I$(objtree)/usr/include
diff --git a/Documentation/ummunotify/ummunotify.txt b/Documentation/ummunotify/ummunotify.txt
new file mode 100644
index 0000000..78a79c2
--- /dev/null
+++ b/Documentation/ummunotify/ummunotify.txt
@@ -0,0 +1,150 @@
+UMMUNOTIFY
+
+  Ummunotify relays MMU notifier events to userspace.  This is useful
+  for libraries that need to track the memory mapping of applications;
+  for example, MPI implementations using RDMA want to cache memory
+  registrations for performance, but tracking all possible crazy cases
+  such as when, say, the FORTRAN runtime frees memory is impossible
+  without kernel help.
+
+Basic Model
+
+  A userspace process uses it by opening /dev/ummunotify, which
+  returns a file descriptor.  Interest in address ranges is registered
+  using ioctl() and MMU notifier events are retrieved using read(), as
+  described in more detail below.  Userspace can register multiple
+  address ranges to watch, and can unregister individual ranges.
+
+  Userspace can also mmap() a single read-only page at offset 0 on
+  this file descriptor.  This page contains (at offest 0) a single
+  64-bit generation counter that the kernel increments each time an
+  MMU notifier event occurs.  Userspace can use this to very quickly
+  check if there are any events to retrieve without needing to do a
+  system call.
+
+Control
+
+  To start using ummunotify, a process opens /dev/ummunotify in
+  read-only mode.  Control from userspace is done via ioctl(); the
+  defined ioctls are:
+
+    UMMUNOTIFY_EXCHANGE_FEATURES: This ioctl takes a single 32-bit
+      word of feature flags as input, and the kernel updates the
+      features flags word to contain only features requested by
+      userspace and also supported by the kernel.
+
+      This ioctl is only included for forward compatibility; no
+      feature flags are currently defined, and the kernel will simply
+      update any requested feature mask to 0.  The kernel will always
+      default to a feature mask of 0 if this ioctl is not used, so
+      current userspace does not need to perform this ioctl.
+
+    UMMUNOTIFY_REGISTER_REGION: Userspace uses this ioctl to tell the
+      kernel to start delivering events for an address range.  The
+      range is described using struct ummunotify_register_ioctl:
+
+	struct ummunotify_register_ioctl {
+		__u64	start;
+		__u64	end;
+		__u64	user_cookie;
+		__u32	flags;
+		__u32	reserved;
+	};
+
+      start and end give the range of userspace virtual addresses;
+      start is included in the range and end is not, so an example of
+      a 4 KB range would be start=0x1000, end=0x2000.
+
+      user_cookie is an opaque 64-bit quantity that is returned by the
+      kernel in events involving the range, and used by userspace to
+      stop watching the range.  Each registered address range must
+      have a distinct user_cookie.
+
+      It is fine with the kernel if userspace registers multiple
+      overlapping or even duplicate address ranges, as long as a
+      different cookie is used for each registration.
+
+      flags and reserved are included for forward compatibility;
+      userspace should simply set them to 0 for the current interface.
+
+    UMMUNOTIFY_UNREGISTER_REGION: Userspace passes in the 64-bit
+      user_cookie used to register a range to tell the kernel to stop
+      watching an address range.  Once this ioctl completes, the
+      kernel will not deliver any further events for the range that is
+      unregistered.
+
+Events
+
+  When an event occurs that invalidates some of a process's memory
+  mapping in an address range being watched, ummunotify queues an
+  event report for that address range.  If more than one event
+  invalidates parts of the same address range before userspace
+  retrieves the queued report, then further reports for the same range
+  will not be queued -- when userspace does read the queue, only a
+  single report for a given range will be returned.
+
+  If multiple ranges being watched are invalidated by a single event
+  (which is especially likely if userspace registers overlapping
+  ranges), then an event report structure will be queued for each
+  address range registration.
+
+  Userspace retrieves queued events via read() on the ummunotify file
+  descriptor; a buffer that is at least as big as struct
+  ummunotify_event should be used to retrieve event reports, and if a
+  larger buffer is passed to read(), multiple reports will be returned
+  (if available).
+
+  If the ummunotify file descriptor is in blocking mode, a read() call
+  will wait for an event report to be available.  Userspace may also
+  set the ummunotify file descriptor to non-blocking mode and use all
+  standard ways of waiting for data to be available on the ummunotify
+  file descriptor, including epoll/poll()/select() and SIGIO.
+
+  The format of event reports is:
+
+	struct ummunotify_event {
+		__u32	type;
+		__u32	flags;
+		__u64	hint_start;
+		__u64	hint_end;
+		__u64	user_cookie_counter;
+	};
+
+  where the type field is either UMMUNOTIFY_EVENT_TYPE_INVAL or
+  UMMUNOTIFY_EVENT_TYPE_LAST.  Events of type INVAL describe
+  invalidation events as follows: user_cookie_counter contains the
+  cookie passed in when userspace registered the range that the event
+  is for.  hint_start and hint_end contain the start address and end
+  address that were invalidated.
+
+  The flags word contains bit flags, with only UMMUNOTIFY_EVENT_FLAG_HINT
+  defined at the moment.  If HINT is set, then the invalidation event
+  invalidated less than the full address range and the kernel returns
+  the exact range invalidated; if HINT is not sent then hint_start and
+  hint_end are set to the original range registered by userspace.
+  (HINT will not be set if, for example, multiple events invalidated
+  disjoint parts of the range and so a single start/end pair cannot
+  represent the parts of the range that were invalidated)
+
+  If the event type is LAST, then the read operation has emptied the
+  list of invalidated regions, and the flags, hint_start and hint_end
+  fields are not used.  user_cookie_counter holds the value of the
+  kernel's generation counter (see below of more details) when the
+  empty list occurred.
+
+Generation Count
+
+  Userspace may mmap() a page on a ummunotify file descriptor via
+
+	mmap(NULL, sizeof (__u64), PROT_READ, MAP_SHARED, ummunotify_fd, 0);
+
+  to get a read-only mapping of the kernel's 64-bit generation
+  counter.  The kernel will increment this generation counter each
+  time an event report is queued.
+
+  Userspace can use the generation counter as a quick check to avoid
+  system calls; if the value read from the mapped kernel counter is
+  still equal to the value returned in user_cookie_counter for the
+  most recent LAST event retrieved, then no further events have been
+  queued and there is no need to try a read() on the ummunotify file
+  descriptor.
diff --git a/Documentation/ummunotify/umn-test.c b/Documentation/ummunotify/umn-test.c
new file mode 100644
index 0000000..143db2c
--- /dev/null
+++ b/Documentation/ummunotify/umn-test.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2009 Cisco Systems.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <linux/ummunotify.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define UMN_TEST_COOKIE 123
+
+static int		umn_fd;
+static volatile __u64  *umn_counter;
+
+static int umn_init(void)
+{
+	__u32 flags;
+
+	umn_fd = open("/dev/ummunotify", O_RDONLY);
+	if (umn_fd < 0) {
+		perror("open");
+		return 1;
+	}
+
+	if (ioctl(umn_fd, UMMUNOTIFY_EXCHANGE_FEATURES, &flags)) {
+		perror("exchange ioctl");
+		return 1;
+	}
+
+	printf("kernel feature flags: 0x%08x\n", flags);
+
+	umn_counter = mmap(NULL, sizeof *umn_counter, PROT_READ,
+			   MAP_SHARED, umn_fd, 0);
+	if (umn_counter == MAP_FAILED) {
+		perror("mmap");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int umn_register(void *buf, size_t size, __u64 cookie)
+{
+	struct ummunotify_register_ioctl r = {
+		.start		= (unsigned long) buf,
+		.end		= (unsigned long) buf + size,
+		.user_cookie	= cookie,
+	};
+
+	if (ioctl(umn_fd, UMMUNOTIFY_REGISTER_REGION, &r)) {
+		perror("register ioctl");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int umn_unregister(__u64 cookie)
+{
+	if (ioctl(umn_fd, UMMUNOTIFY_UNREGISTER_REGION, &cookie)) {
+		perror("unregister ioctl");
+		return 1;
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int			page_size;
+	__u64			old_counter;
+	void		       *t;
+	int			got_it;
+
+	if (umn_init())
+		return 1;
+
+	printf("\n");
+
+	old_counter = *umn_counter;
+	if (old_counter != 0) {
+		fprintf(stderr, "counter = %lld (expected 0)\n", old_counter);
+		return 1;
+	}
+
+	page_size = sysconf(_SC_PAGESIZE);
+	t = mmap(NULL, 3 * page_size, PROT_READ,
+		 MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
+
+	if (umn_register(t, 3 * page_size, UMN_TEST_COOKIE))
+		return 1;
+
+	munmap(t + page_size, page_size);
+
+	old_counter = *umn_counter;
+	if (old_counter != 1) {
+		fprintf(stderr, "counter = %lld (expected 1)\n", old_counter);
+		return 1;
+	}
+
+	got_it = 0;
+	while (1) {
+		struct ummunotify_event	ev;
+		int			len;
+
+		len = read(umn_fd, &ev, sizeof ev);
+		if (len < 0) {
+			perror("read event");
+			return 1;
+		}
+		if (len != sizeof ev) {
+			fprintf(stderr, "Read gave %d bytes (!= event size %zd)\n",
+				len, sizeof ev);
+			return 1;
+		}
+
+		switch (ev.type) {
+		case UMMUNOTIFY_EVENT_TYPE_INVAL:
+			if (got_it) {
+				fprintf(stderr, "Extra invalidate event\n");
+				return 1;
+			}
+			if (ev.user_cookie_counter != UMN_TEST_COOKIE) {
+				fprintf(stderr, "Invalidate event for cookie %lld (expected %d)\n",
+					ev.user_cookie_counter,
+					UMN_TEST_COOKIE);
+				return 1;
+			}
+
+			printf("Invalidate event:\tcookie %lld\n",
+			       ev.user_cookie_counter);
+
+			if (!(ev.flags & UMMUNOTIFY_EVENT_FLAG_HINT)) {
+				fprintf(stderr, "Hint flag not set\n");
+				return 1;
+			}
+
+			if (ev.hint_start != (uintptr_t) t + page_size ||
+			    ev.hint_end != (uintptr_t) t + page_size * 2) {
+				fprintf(stderr, "Got hint %llx..%llx, expected %p..%p\n",
+					ev.hint_start, ev.hint_end,
+					t + page_size, t + page_size * 2);
+				return 1;
+			}
+
+			printf("\t\t\thint %llx...%llx\n",
+			       ev.hint_start, ev.hint_end);
+
+			got_it = 1;
+			break;
+
+		case UMMUNOTIFY_EVENT_TYPE_LAST:
+			if (!got_it) {
+				fprintf(stderr, "Last event without invalidate event\n");
+				return 1;
+			}
+
+			printf("Empty event:\t\tcounter %lld\n",
+			       ev.user_cookie_counter);
+			goto done;
+
+		default:
+			fprintf(stderr, "unknown event type %d\n",
+				ev.type);
+			return 1;
+		}
+	}
+
+done:
+	umn_unregister(123);
+	munmap(t, page_size);
+
+	old_counter = *umn_counter;
+	if (old_counter != 1) {
+		fprintf(stderr, "counter = %lld (expected 1)\n", old_counter);
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 3141dd3..cf26019 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -1111,6 +1111,18 @@ config DEVPORT
 	depends on ISA || PCI
 	default y
 
+config UMMUNOTIFY
+       tristate "Userspace MMU notifications"
+       select MMU_NOTIFIER
+       help
+         The ummunotify (userspace MMU notification) driver creates a
+         character device that can be used by userspace libraries to
+         get notifications when an application's memory mapping
+         changed.  This is used, for example, by RDMA libraries to
+         improve the reliability of memory registration caching, since
+         the kernel's MMU notifications can be used to know precisely
+         when to shoot down a cached registration.
+
 source "drivers/s390/char/Kconfig"
 
 endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index f957edf..521e5de 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_NSC_GPIO)		+= nsc_gpio.o
 obj-$(CONFIG_CS5535_GPIO)	+= cs5535_gpio.o
 obj-$(CONFIG_GPIO_TB0219)	+= tb0219.o
 obj-$(CONFIG_TELCLOCK)		+= tlclk.o
+obj-$(CONFIG_UMMUNOTIFY)	+= ummunotify.o
 
 obj-$(CONFIG_MWAVE)		+= mwave/
 obj-$(CONFIG_AGP)		+= agp/
diff --git a/drivers/char/ummunotify.c b/drivers/char/ummunotify.c
new file mode 100644
index 0000000..c14df3f
--- /dev/null
+++ b/drivers/char/ummunotify.c
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 2009 Cisco Systems.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/mmu_notifier.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/rbtree.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/ummunotify.h>
+
+#include <asm/cacheflush.h>
+
+MODULE_AUTHOR("Roland Dreier");
+MODULE_DESCRIPTION("Userspace MMU notifiers");
+MODULE_LICENSE("GPL v2");
+
+/*
+ * Information about an address range userspace has asked us to watch.
+ *
+ * user_cookie: Opaque cookie given to us when userspace registers the
+ *   address range.
+ *
+ * start, end: Address range; start is inclusive, end is exclusive.
+ *
+ * hint_start, hint_end: If a single MMU notification event
+ *   invalidates the address range, we hold the actual range of
+ *   addresses that were invalidated (and set UMMUNOTIFY_FLAG_HINT).
+ *   If another event hits this range before userspace reads the
+ *   event, we give up and don't try to keep track of which subsets
+ *   got invalidated.
+ *
+ * flags: Holds the INVALID flag for ranges that are on the invalid
+ *   list and/or the HINT flag for ranges where the hint range holds
+ *   good information.
+ *
+ * node: Used to put the range into an rbtree we use to be able to
+ *   scan address ranges in order.
+ *
+ * list: Used to put the range on the invalid list when an MMU
+ *   notification event hits the range.
+ */
+enum {
+	UMMUNOTIFY_FLAG_INVALID	= 1,
+	UMMUNOTIFY_FLAG_HINT	= 2,
+};
+
+struct ummunotify_reg {
+	u64			user_cookie;
+	unsigned long		start;
+	unsigned long		end;
+	unsigned long		hint_start;
+	unsigned long		hint_end;
+	unsigned long		flags;
+	struct rb_node		node;
+	struct list_head	list;
+};
+
+/*
+ * Context attached to each file that userspace opens.
+ *
+ * mmu_notifier: MMU notifier registered for this context.
+ *
+ * mm: mm_struct for process that created the context; we use this to
+ *   hold a reference to the mm to make sure it doesn't go away until
+ *   we're done with it.
+ *
+ * reg_tree: RB tree of address ranges being watched, sorted by start
+ *   address.
+ *
+ * invalid_list: List of address ranges that have been invalidated by
+ *   MMU notification events; as userspace reads events, the address
+ *   range corresponding to the event is removed from the list.
+ *
+ * counter: Page that can be mapped read-only by userspace, which
+ *   holds a generation count that is incremented each time an event
+ *   occurs.
+ *
+ * lock: Spinlock used to protect all context.
+ *
+ * read_wait: Wait queue used to wait for data to become available in
+ *   blocking read()s.
+ *
+ * async_queue: Used to implement fasync().
+ *
+ * need_empty: Set when userspace reads an invalidation event, so that
+ *   read() knows it must generate an "empty" event when userspace
+ *   drains the invalid_list.
+ *
+ * used: Set after userspace does anything with the file, so that the
+ *   "exchange flags" ioctl() knows it's too late to change anything.
+ */
+struct ummunotify_file {
+	struct mmu_notifier	mmu_notifier;
+	struct mm_struct       *mm;
+	struct rb_root		reg_tree;
+	struct list_head	invalid_list;
+	u64		       *counter;
+	spinlock_t		lock;
+	wait_queue_head_t	read_wait;
+	struct fasync_struct   *async_queue;
+	int			need_empty;
+	int			used;
+};
+
+static void ummunotify_handle_notify(struct mmu_notifier *mn,
+				     unsigned long start, unsigned long end)
+{
+	struct ummunotify_file *priv =
+		container_of(mn, struct ummunotify_file, mmu_notifier);
+	struct rb_node *n;
+	struct ummunotify_reg *reg;
+	unsigned long flags;
+	int hit = 0;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	for (n = rb_first(&priv->reg_tree); n; n = rb_next(n)) {
+		reg = rb_entry(n, struct ummunotify_reg, node);
+
+		/*
+		 * Ranges overlap if they're not disjoint; and they're
+		 * disjoint if the end of one is before the start of
+		 * the other one.  So if both disjointness comparisons
+		 * fail then the ranges overlap.
+		 *
+		 * Since we keep the tree of regions we're watching
+		 * sorted by start address, we can end this loop as
+		 * soon as we hit a region that starts past the end of
+		 * the range for the event we're handling.
+		 */
+		if (reg->start >= end)
+			break;
+
+		/*
+		 * Just go to the next region if the start of the
+		 * range is after the end of the region -- there
+		 * might still be more overlapping ranges that have a
+		 * greater start.
+		 */
+		if (start >= reg->end)
+			continue;
+
+		hit = 1;
+
+		if (test_and_set_bit(UMMUNOTIFY_FLAG_INVALID, &reg->flags)) {
+			/* Already on invalid list */
+			clear_bit(UMMUNOTIFY_FLAG_HINT, &reg->flags);
+		} else {
+			list_add_tail(&reg->list, &priv->invalid_list);
+			set_bit(UMMUNOTIFY_FLAG_HINT, &reg->flags);
+			reg->hint_start = start;
+			reg->hint_end   = end;
+		}
+	}
+
+	if (hit) {
+		++(*priv->counter);
+		flush_dcache_page(virt_to_page(priv->counter));
+		wake_up_interruptible(&priv->read_wait);
+		kill_fasync(&priv->async_queue, SIGIO, POLL_IN);
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void ummunotify_invalidate_page(struct mmu_notifier *mn,
+				       struct mm_struct *mm,
+				       unsigned long addr)
+{
+	ummunotify_handle_notify(mn, addr, addr + PAGE_SIZE);
+}
+
+static void ummunotify_invalidate_range_start(struct mmu_notifier *mn,
+					      struct mm_struct *mm,
+					      unsigned long start,
+					      unsigned long end)
+{
+	ummunotify_handle_notify(mn, start, end);
+}
+
+static const struct mmu_notifier_ops ummunotify_mmu_notifier_ops = {
+	.invalidate_page	= ummunotify_invalidate_page,
+	.invalidate_range_start	= ummunotify_invalidate_range_start,
+};
+
+static int ummunotify_open(struct inode *inode, struct file *filp)
+{
+	struct ummunotify_file *priv;
+	int ret;
+
+	if (filp->f_mode & FMODE_WRITE)
+		return -EINVAL;
+
+	priv = kmalloc(sizeof *priv, GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->counter = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!priv->counter) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	priv->reg_tree = RB_ROOT;
+	INIT_LIST_HEAD(&priv->invalid_list);
+	spin_lock_init(&priv->lock);
+	init_waitqueue_head(&priv->read_wait);
+	priv->async_queue = NULL;
+	priv->need_empty  = 0;
+	priv->used	  = 0;
+
+	priv->mmu_notifier.ops = &ummunotify_mmu_notifier_ops;
+	/*
+	 * Register notifier last, since notifications can occur as
+	 * soon as we register....
+	 */
+	ret = mmu_notifier_register(&priv->mmu_notifier, current->mm);
+	if (ret)
+		goto err_page;
+
+	priv->mm = current->mm;
+	atomic_inc(&priv->mm->mm_count);
+
+	filp->private_data = priv;
+
+	return 0;
+
+err_page:
+	free_page((unsigned long) priv->counter);
+
+err:
+	kfree(priv);
+	return ret;
+}
+
+static int ummunotify_close(struct inode *inode, struct file *filp)
+{
+	struct ummunotify_file *priv = filp->private_data;
+	struct rb_node *n;
+	struct ummunotify_reg *reg;
+
+	mmu_notifier_unregister(&priv->mmu_notifier, priv->mm);
+	mmdrop(priv->mm);
+	free_page((unsigned long) priv->counter);
+
+	for (n = rb_first(&priv->reg_tree); n; n = rb_next(n)) {
+		reg = rb_entry(n, struct ummunotify_reg, node);
+		kfree(reg);
+	}
+
+	kfree(priv);
+
+	return 0;
+}
+
+static bool ummunotify_readable(struct ummunotify_file *priv)
+{
+	return priv->need_empty || !list_empty(&priv->invalid_list);
+}
+
+static ssize_t ummunotify_read(struct file *filp, char __user *buf,
+			       size_t count, loff_t *pos)
+{
+	struct ummunotify_file *priv = filp->private_data;
+	struct ummunotify_reg *reg;
+	ssize_t ret;
+	struct ummunotify_event *events;
+	int max;
+	int n;
+
+	priv->used = 1;
+
+	events = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!events) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	spin_lock_irq(&priv->lock);
+
+	while (!ummunotify_readable(priv)) {
+		spin_unlock_irq(&priv->lock);
+
+		if (filp->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			goto out;
+		}
+
+		if (wait_event_interruptible(priv->read_wait,
+					     ummunotify_readable(priv))) {
+			ret = -ERESTARTSYS;
+			goto out;
+		}
+
+		spin_lock_irq(&priv->lock);
+	}
+
+	max = min_t(size_t, PAGE_SIZE, count) / sizeof *events;
+
+	for (n = 0; n < max; ++n) {
+		if (list_empty(&priv->invalid_list)) {
+			events[n].type = UMMUNOTIFY_EVENT_TYPE_LAST;
+			events[n].user_cookie_counter = *priv->counter;
+			++n;
+			priv->need_empty = 0;
+			break;
+		}
+
+		reg = list_first_entry(&priv->invalid_list,
+				       struct ummunotify_reg, list);
+
+		events[n].type = UMMUNOTIFY_EVENT_TYPE_INVAL;
+		if (test_bit(UMMUNOTIFY_FLAG_HINT, &reg->flags)) {
+			events[n].flags	     = UMMUNOTIFY_EVENT_FLAG_HINT;
+			events[n].hint_start = max(reg->start, reg->hint_start);
+			events[n].hint_end   = min(reg->end, reg->hint_end);
+		} else {
+			events[n].hint_start = reg->start;
+			events[n].hint_end   = reg->end;
+		}
+		events[n].user_cookie_counter = reg->user_cookie;
+
+		list_del(&reg->list);
+		reg->flags = 0;
+		priv->need_empty = 1;
+	}
+
+	spin_unlock_irq(&priv->lock);
+
+	if (copy_to_user(buf, events, n * sizeof *events))
+		ret = -EFAULT;
+	else
+		ret = n * sizeof *events;
+
+out:
+	free_page((unsigned long) events);
+	return ret;
+}
+
+static unsigned int ummunotify_poll(struct file *filp,
+				    struct poll_table_struct *wait)
+{
+	struct ummunotify_file *priv = filp->private_data;
+
+	poll_wait(filp, &priv->read_wait, wait);
+
+	return ummunotify_readable(priv) ? (POLLIN | POLLRDNORM) : 0;
+}
+
+static long ummunotify_exchange_features(struct ummunotify_file *priv,
+					 __u32 __user *arg)
+{
+	u32 feature_mask;
+
+	if (priv->used)
+		return -EINVAL;
+
+	priv->used = 1;
+
+	if (copy_from_user(&feature_mask, arg, sizeof(feature_mask)))
+		return -EFAULT;
+
+	/* No extensions defined at present. */
+	feature_mask = 0;
+
+	if (copy_to_user(arg, &feature_mask, sizeof(feature_mask)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static long ummunotify_register_region(struct ummunotify_file *priv,
+				       void __user *arg)
+{
+	struct ummunotify_register_ioctl parm;
+	struct ummunotify_reg *reg, *treg;
+	struct rb_node **n = &priv->reg_tree.rb_node;
+	struct rb_node *pn;
+	int ret = 0;
+
+	if (copy_from_user(&parm, arg, sizeof parm))
+		return -EFAULT;
+
+	priv->used = 1;
+
+	reg = kmalloc(sizeof *reg, GFP_KERNEL);
+	if (!reg)
+		return -ENOMEM;
+
+	reg->user_cookie	= parm.user_cookie;
+	reg->start		= parm.start;
+	reg->end		= parm.end;
+	reg->flags		= 0;
+
+	spin_lock_irq(&priv->lock);
+
+	for (pn = rb_first(&priv->reg_tree); pn; pn = rb_next(pn)) {
+		treg = rb_entry(pn, struct ummunotify_reg, node);
+
+		if (treg->user_cookie == parm.user_cookie) {
+			kfree(reg);
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	pn = NULL;
+	while (*n) {
+		pn = *n;
+		treg = rb_entry(pn, struct ummunotify_reg, node);
+
+		if (reg->start <= treg->start)
+			n = &pn->rb_left;
+		else
+			n = &pn->rb_right;
+	}
+
+	rb_link_node(&reg->node, pn, n);
+	rb_insert_color(&reg->node, &priv->reg_tree);
+
+out:
+	spin_unlock_irq(&priv->lock);
+
+	return ret;
+}
+
+static long ummunotify_unregister_region(struct ummunotify_file *priv,
+					 __u64 __user *arg)
+{
+	u64 user_cookie;
+	struct rb_node *n;
+	struct ummunotify_reg *reg;
+	int ret = -EINVAL;
+
+	if (copy_from_user(&user_cookie, arg, sizeof(user_cookie)))
+		return -EFAULT;
+
+	spin_lock_irq(&priv->lock);
+
+	for (n = rb_first(&priv->reg_tree); n; n = rb_next(n)) {
+		reg = rb_entry(n, struct ummunotify_reg, node);
+
+		if (reg->user_cookie == user_cookie) {
+			rb_erase(n, &priv->reg_tree);
+			if (test_bit(UMMUNOTIFY_FLAG_INVALID, &reg->flags))
+				list_del(&reg->list);
+			kfree(reg);
+			ret = 0;
+			break;
+		}
+	}
+
+	spin_unlock_irq(&priv->lock);
+
+	return ret;
+}
+
+static long ummunotify_ioctl(struct file *filp, unsigned int cmd,
+			     unsigned long arg)
+{
+	struct ummunotify_file *priv = filp->private_data;
+	void __user *argp = (void __user *) arg;
+
+	switch (cmd) {
+	case UMMUNOTIFY_EXCHANGE_FEATURES:
+		return ummunotify_exchange_features(priv, argp);
+	case UMMUNOTIFY_REGISTER_REGION:
+		return ummunotify_register_region(priv, argp);
+	case UMMUNOTIFY_UNREGISTER_REGION:
+		return ummunotify_unregister_region(priv, argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static int ummunotify_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct ummunotify_file *priv = vma->vm_private_data;
+
+	if (vmf->pgoff != 0)
+		return VM_FAULT_SIGBUS;
+
+	vmf->page = virt_to_page(priv->counter);
+	get_page(vmf->page);
+
+	return 0;
+
+}
+
+static struct vm_operations_struct ummunotify_vm_ops = {
+	.fault		= ummunotify_fault,
+};
+
+static int ummunotify_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct ummunotify_file *priv = filp->private_data;
+
+	if (vma->vm_end - vma->vm_start != PAGE_SIZE || vma->vm_pgoff != 0)
+		return -EINVAL;
+
+	vma->vm_ops		= &ummunotify_vm_ops;
+	vma->vm_private_data	= priv;
+
+	return 0;
+}
+
+static int ummunotify_fasync(int fd, struct file *filp, int on)
+{
+	struct ummunotify_file *priv = filp->private_data;
+
+	return fasync_helper(fd, filp, on, &priv->async_queue);
+}
+
+static const struct file_operations ummunotify_fops = {
+	.owner		= THIS_MODULE,
+	.open		= ummunotify_open,
+	.release	= ummunotify_close,
+	.read		= ummunotify_read,
+	.poll		= ummunotify_poll,
+	.unlocked_ioctl	= ummunotify_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= ummunotify_ioctl,
+#endif
+	.mmap		= ummunotify_mmap,
+	.fasync		= ummunotify_fasync,
+};
+
+static struct miscdevice ummunotify_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "ummunotify",
+	.fops	= &ummunotify_fops,
+};
+
+static int __init ummunotify_init(void)
+{
+	return misc_register(&ummunotify_misc);
+}
+
+static void __exit ummunotify_cleanup(void)
+{
+	misc_deregister(&ummunotify_misc);
+}
+
+module_init(ummunotify_init);
+module_exit(ummunotify_cleanup);
diff --git a/include/linux/ummunotify.h b/include/linux/ummunotify.h
new file mode 100644
index 0000000..21b0d03
--- /dev/null
+++ b/include/linux/ummunotify.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2009 Cisco Systems.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _LINUX_UMMUNOTIFY_H
+#define _LINUX_UMMUNOTIFY_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/*
+ * Ummunotify relays MMU notifier events to userspace.  A userspace
+ * process uses it by opening /dev/ummunotify, which returns a file
+ * descriptor.  Interest in address ranges is registered using ioctl()
+ * and MMU notifier events are retrieved using read(), as described in
+ * more detail below.
+ *
+ * Userspace can also mmap() a single read-only page at offset 0 on
+ * this file descriptor.  This page contains (at offest 0) a single
+ * 64-bit generation counter that the kernel increments each time an
+ * MMU notifier event occurs.  Userspace can use this to very quickly
+ * check if there are any events to retrieve without needing to do a
+ * system call.
+ */
+
+/*
+ * struct ummunotify_register_ioctl describes an address range from
+ * start to end (including start but not including end) to be
+ * monitored.  user_cookie is an opaque handle that userspace assigns,
+ * and which is used to unregister.  flags and reserved are currently
+ * unused and should be set to 0 for forward compatibility.
+ */
+struct ummunotify_register_ioctl {
+	__u64	start;
+	__u64	end;
+	__u64	user_cookie;
+	__u32	flags;
+	__u32	reserved;
+};
+
+#define UMMUNOTIFY_MAGIC		'U'
+
+/*
+ * Forward compatibility: Userspace passes in a 32-bit feature mask
+ * with feature flags set indicating which extensions it wishes to
+ * use.  The kernel will return a feature mask with the bits of
+ * userspace's mask that the kernel implements; from that point on
+ * both userspace and the kernel should behave as described by the
+ * kernel's feature mask.
+ *
+ * If userspace does not perform a UMMUNOTIFY_EXCHANGE_FEATURES ioctl,
+ * then the kernel will use a feature mask of 0.
+ *
+ * No feature flags are currently defined, so the kernel will always
+ * return a feature mask of 0 at present.
+ */
+#define UMMUNOTIFY_EXCHANGE_FEATURES	_IOWR(UMMUNOTIFY_MAGIC, 1, __u32)
+
+/*
+ * Register interest in an address range; userspace should pass in a
+ * struct ummunotify_register_ioctl describing the region.
+ */
+#define UMMUNOTIFY_REGISTER_REGION	_IOW(UMMUNOTIFY_MAGIC, 2, \
+					     struct ummunotify_register_ioctl)
+/*
+ * Unregister interest in an address range; userspace should pass in
+ * the user_cookie value that was used to register the address range.
+ * No events for the address range will be reported once it is
+ * unregistered.
+ */
+#define UMMUNOTIFY_UNREGISTER_REGION	_IOW(UMMUNOTIFY_MAGIC, 3, __u64)
+
+/*
+ * Invalidation events are returned whenever the kernel changes the
+ * mapping for a monitored address.  These events are retrieved by
+ * read() on the ummunotify file descriptor, which will fill the
+ * read() buffer with struct ummunotify_event.
+ *
+ * If type field is INVAL, then user_cookie_counter holds the
+ * user_cookie for the region being reported; if the HINT flag is set
+ * then hint_start/hint_end hold the start and end of the mapping that
+ * was invalidated.  (If HINT is not set, then multiple events
+ * invalidated parts of the registered range and hint_start/hint_end
+ * and set to the start/end of the whole registered range)
+ *
+ * If type is LAST, then the read operation has emptied the list of
+ * invalidated regions, and user_cookie_counter holds the value of the
+ * kernel's generation counter when the empty list occurred.  The
+ * other fields are not filled in for this event.
+ */
+enum {
+	UMMUNOTIFY_EVENT_TYPE_INVAL	= 0,
+	UMMUNOTIFY_EVENT_TYPE_LAST	= 1,
+};
+
+enum {
+	UMMUNOTIFY_EVENT_FLAG_HINT	= 1 << 0,
+};
+
+struct ummunotify_event {
+	__u32	type;
+	__u32	flags;
+	__u64	hint_start;
+	__u64	hint_end;
+	__u64	user_cookie_counter;
+};
+
+#endif /* _LINUX_UMMUNOTIFY_H */
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Socket Direct Protocol: help
From: Andrea Gozzelino @ 2010-04-12  8:14 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA, rolandd-FYB4Gu1CFyUAvxtiuMwx3w,
	peterz-wEGCiKHe2LqWVfeAwA7xHQ, pavel-+ZI9xUNit7I,
	mingo-X9Un+BFzKDI, Eric B Munson, Steve Wise <swise@

Good morning,

I'm testing some Neteffect cards (Intel code E10G81GP - Neteffect
NE020.LP.1.SSR).
PC has Linux| (kernel version) 2.6.18-164.15.1.el5 | x86_64 x86_64
x86_64 GNU/Linux.

In this phase, I measure the bandwidth with the netserver/nerperf
(version netperf-2.4.5) ad hoc tests.
They work fine with TCP protocol - as OFED 1.5.1 example programs - and
they have some problems with SDP one.

I'm trying test with the command lines below:

server: LD_PRELOAD=/usr/local/lib64/libsdp.so netserver

client: LD_PRELOAD=/usr/local/lib64/libsdp.so netperf -H server_address
-c -C
-- -m 65536

The /etc/libsdp.conf file contains rules below:
use both listen * *:*
use both connect * *:*
log min-level 9 destination file libsdp.log

Client displays "Connection error: Can not allocate memory" and the
connection fails.
(original text on client log file:libsdp Error connect: failed for SDP
fd:6 with error:Cannot allocate memory)

The library path is:
/usr/local/lib64/libsdp.so


Could someone explain me how LD_PRELOAD environment variable must be
set?
I don't understand why the test work with TCP and not with SDP.
Could I work with wrong Linux kernel environment or parameters?

I don't know if there is a specific mailing list for SDP so I ask you
help.

Thank you very much,
Andrea 







Andrea Gozzelino

INFN - Laboratori Nazionali di Legnaro	(LNL)
Viale dell'Universita' 2
I-35020 - Legnaro (PD)- ITALIA
Tel: +39 049 8068346
Fax: +39 049 641925
Mail: andrea.gozzelino-PK20h7lG/Rc1GQ1Ptb7lUw@public.gmane.org			

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH V3 0/2] Add support for enhanced atomic operations
From: Vladimir Sokolovsky @ 2010-04-12  9:44 UTC (permalink / raw)
  To: Roland Dreier; +Cc: Håkon Bugge, linux-rdma-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <4BA0F623.1050606-LDSdmyG8hGV8YrgS2mwiifqBs+8SCbDb@public.gmane.org>

Vladimir Sokolovsky wrote:
> Roland Dreier wrote:
>>  > Hence, I think it would be cleaner if a new capability,
>>  > masked_atomic_cap, were introduced, using the original definitions
>>  > (NONE, HCA, GLOB).
>>
>> Vlad, what do you think about that?  The more I think about it, the
>> cleaner this seems to me.  And it doesn't even consume a device
>> capability flag bit, which is a nice bonus.
> 
> Hi Roland,
> Do you propose to use IB_ATOMIC_GLOB instead of IB_ATOMIC_HCA while setting
> atomic capability in the code below?
> 
>         props->atomic_cap          = dev->dev->caps.flags & 
> MLX4_DEV_CAP_FLAG_ATOMIC ?
>                 IB_ATOMIC_HCA : IB_ATOMIC_NONE;
> 
> Or add IB_MASKED_ATOMIC to ib_atomic_cap enum and use this one instead 
> of IB_ATOMIC_HCA?
> 
> All this, of course, comes to replace setting IB_DEVICE_MASKED_ATOMIC 
> for device capability.
> 
> Thanks,
> Vladimir
> 
> 

Hi Roland,
Can you comment?

Thanks,
Vladimir
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Socket Direct Protocol: help (2)
From: Andrea Gozzelino @ 2010-04-12 14:33 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA, rolandd-FYB4Gu1CFyUAvxtiuMwx3w,
	peterz-wEGCiKHe2LqWVfeAwA7xHQ, pavel-+ZI9xUNit7I,
	mingo-X9Un+BFzKDI, Eric B Munson, Steve Wise <swise@
In-Reply-To: <13381_1271060138_o3C8FUH8013968_2977669.1271060085255.SLOX.WebMail.wwwrun-XDIR3SKYeFbgKi2NxijLtw@public.gmane.org>

On Apr 12, 2010 10:14 AM, Andrea Gozzelino
<Andrea.Gozzelino-PK20h7lG/Rc1GQ1Ptb7lUw@public.gmane.org> wrote:

> Good morning,
> 
> I'm testing some Neteffect cards (Intel code E10G81GP - Neteffect
> NE020.LP.1.SSR).
> PC has Linux| (kernel version) 2.6.18-164.15.1.el5 | x86_64 x86_64
> x86_64 GNU/Linux.
> 
> In this phase, I measure the bandwidth with the netserver/nerperf
> (version netperf-2.4.5) ad hoc tests.
> They work fine with TCP protocol - as OFED 1.5.1 example programs -
> and
> they have some problems with SDP one.
> 
> I'm trying test with the command lines below:
> 
> server: LD_PRELOAD=/usr/local/lib64/libsdp.so netserver
> 
> client: LD_PRELOAD=/usr/local/lib64/libsdp.so netperf -H
> server_address
> -c -C
> -- -m 65536
> 
> The /etc/libsdp.conf file contains rules below:
> use both listen * *:*
> use both connect * *:*
> log min-level 9 destination file libsdp.log
> 
> Client displays "Connection error: Can not allocate memory" and the
> connection fails.
> (original text on client log file:libsdp Error connect: failed for SDP
> fd:6 with error:Cannot allocate memory)
> 
> The library path is:
> /usr/local/lib64/libsdp.so
> 
> 
> Could someone explain me how LD_PRELOAD environment variable must be
> set?
> I don't understand why the test work with TCP and not with SDP.
> Could I work with wrong Linux kernel environment or parameters?
> 
> I don't know if there is a specific mailing list for SDP so I ask you
> help.
> 
> Thank you very much,
> Andrea 
> 
> 
> 
> 
> 
> 
> 
> Andrea Gozzelino
> 
> INFN - Laboratori Nazionali di Legnaro	(LNL)
> Viale dell'Universita' 2
> I-35020 - Legnaro (PD)- ITALIA
> Tel: +39 049 8068346
> Fax: +39 049 641925
> Mail: andrea.gozzelino-PK20h7lG/Rc1GQ1Ptb7lUw@public.gmane.org			
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma"
> in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

Hi all,

I add that in kernel space SDP debug the error is:

command line: dmesg
sdp_init_qp:95 sdp_sock( 2100:2 40720:0): recv sge's. capability: 4
needed: 9
sdp_init_qp:95 sdp_sock( 2100:2 41203:0): recv sge's. capability: 4
needed: 9

The structure sdp_init_qp() is defined in
/usr/src/ofa_kernel-1.5.1/drivers/infiniband/ulp/sdp/sdp_cma.c (lines 76
- 141).

Could be a firmware problem?
I have this situation:
command line: ethtool -i eth2
driver: iw_nes
version: 1.5.0.0
firmware-version: 3.16
bus-info: 0000:03:00.0

Thank you very much,
Andrea
Andrea Gozzelino

INFN - Laboratori Nazionali di Legnaro	(LNL)
Viale dell'Universita' 2
I-35020 - Legnaro (PD)- ITALIA
Tel: +39 049 8068346
Fax: +39 049 641925
Mail: andrea.gozzelino-PK20h7lG/Rc1GQ1Ptb7lUw@public.gmane.org			

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox