Extend create QP to get a Receive Work Queue indirection table

Extend create QP to get a Receive Work Queue indirection table,
this is needed to enable RSS on some set of Receive Work Queues.

Signed-off-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
diff --git a/include/infiniband/kern-abi.h b/include/infiniband/kern-abi.h
index 674045b..9f7964e 100644
--- a/include/infiniband/kern-abi.h
+++ b/include/infiniband/kern-abi.h
@@ -657,11 +657,17 @@
 	__u32 reserved;
 };
 
+enum ibv_create_qp_ex_kernel_mask {
+	IBV_CREATE_QP_EX_KERNEL_MASK_IND_TABLE = 1 << 0,
+};
+
 struct ibv_create_qp_ex {
 	struct ex_hdr	hdr;
 	struct ibv_create_qp_common base;
 	__u32 comp_mask;
 	__u32 create_flags;
+	__u32 ind_tbl_handle;
+	__u32 reserved1;
 };
 
 struct ibv_create_qp_resp_ex {
diff --git a/include/infiniband/verbs.h b/include/infiniband/verbs.h
index 491e254..284bac5 100644
--- a/include/infiniband/verbs.h
+++ b/include/infiniband/verbs.h
@@ -712,7 +712,8 @@
 	IBV_QP_INIT_ATTR_XRCD		= 1 << 1,
 	IBV_QP_INIT_ATTR_CREATE_FLAGS	= 1 << 2,
 	IBV_QP_INIT_ATTR_MAX_TSO_HEADER = 1 << 3,
-	IBV_QP_INIT_ATTR_RESERVED	= 1 << 4
+	IBV_QP_INIT_ATTR_IND_TABLE	= 1 << 4,
+	IBV_QP_INIT_ATTR_RESERVED	= 1 << 5
 };
 
 enum ibv_qp_create_flags {
@@ -734,6 +735,7 @@
 	struct ibv_xrcd	       *xrcd;
 	uint32_t                create_flags;
 	uint16_t		max_tso_header;
+	struct ibv_rwq_ind_table       *rwq_ind_tbl;
 };
 
 enum ibv_qp_open_attr_mask {
diff --git a/src/cmd.c b/src/cmd.c
index 11f5de9..21f972a 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -830,12 +830,22 @@
 			return EINVAL;
 
 		cmd->pd_handle	= qp_attr->pd->handle;
-		cmd->send_cq_handle = qp_attr->send_cq->handle;
+		if (qp_attr->comp_mask & IBV_QP_INIT_ATTR_IND_TABLE) {
+			if (cmd->max_recv_wr || cmd->max_recv_sge ||
+			    cmd->recv_cq_handle || qp_attr->srq)
+				return EINVAL;
 
-		if (qp_attr->qp_type != IBV_QPT_XRC_SEND) {
-			cmd->recv_cq_handle = qp_attr->recv_cq->handle;
-			cmd->srq_handle = qp_attr->srq ? qp_attr->srq->handle :
-							 0;
+			/* send_cq is optinal */
+			if (qp_attr->cap.max_send_wr)
+				cmd->send_cq_handle = qp_attr->send_cq->handle;
+		} else {
+			cmd->send_cq_handle = qp_attr->send_cq->handle;
+
+			if (qp_attr->qp_type != IBV_QPT_XRC_SEND) {
+				cmd->recv_cq_handle = qp_attr->recv_cq->handle;
+				cmd->srq_handle = qp_attr->srq ? qp_attr->srq->handle :
+								 0;
+			}
 		}
 	}
 
@@ -933,6 +943,14 @@
 		cmd->create_flags = qp_attr->create_flags;
 	}
 
+	if (qp_attr->comp_mask & IBV_QP_INIT_ATTR_IND_TABLE) {
+		if (cmd_core_size < offsetof(struct ibv_create_qp_ex, ind_tbl_handle) +
+				    sizeof(cmd->ind_tbl_handle))
+			return EINVAL;
+		cmd->ind_tbl_handle = qp_attr->rwq_ind_tbl->ind_tbl_handle;
+		cmd->comp_mask = IBV_CREATE_QP_EX_KERNEL_MASK_IND_TABLE;
+	}
+
 	err = write(context->cmd_fd, cmd, cmd_size);
 	if (err != cmd_size)
 		return errno;