diff --git a/ibacm/prov/acmp/src/acmp.c b/ibacm/prov/acmp/src/acmp.c
index 884fc484c223..0324ae2f40b3 100644
--- a/ibacm/prov/acmp/src/acmp.c
+++ b/ibacm/prov/acmp/src/acmp.c
@@ -2453,20 +2453,16 @@ acmp_get_ep(struct acmp_port *port, struct acm_endpoint *endpoint)
 static uint16_t acmp_get_pkey_index(struct acm_endpoint *endpoint)
 {
 	struct acmp_port *port;
-	int ret;
-	__be16 pkey;
-	uint16_t i;
+	int i;
 
 	port = acmp_get_port(endpoint);
 	if (!port)
 		return 0;
-
-	for (i = 0, ret = 0; !ret; i++) {
-		ret = ibv_query_pkey(port->dev->verbs, port->port_num, i, &pkey);
-		if (!ret && endpoint->pkey == be16toh(pkey))
-			return i;
-	}
-	return 0;
+	i = ibv_get_pkey_index(port->dev->verbs, port->port_num,
+			       htobe16(endpoint->pkey));
+	if (i < 0)
+		return 0;
+	return i;
 }
 
 static void acmp_close_endpoint(void *ep_context)
diff --git a/libibverbs/man/CMakeLists.txt b/libibverbs/man/CMakeLists.txt
index 99c57d737e73..234b34e86d4e 100644
--- a/libibverbs/man/CMakeLists.txt
+++ b/libibverbs/man/CMakeLists.txt
@@ -33,6 +33,7 @@ rdma_man_pages(
   ibv_get_device_guid.3.md
   ibv_get_device_list.3
   ibv_get_device_name.3.md
+  ibv_get_pkey_index.3.md
   ibv_get_srq_num.3.md
   ibv_inc_rkey.3.md
   ibv_modify_qp.3
diff --git a/libibverbs/man/ibv_get_pkey_index.3.md b/libibverbs/man/ibv_get_pkey_index.3.md
new file mode 100644
index 000000000000..729f18217ee9
--- /dev/null
+++ b/libibverbs/man/ibv_get_pkey_index.3.md
@@ -0,0 +1,48 @@
+---
+date: 2018-07-16
+footer: libibverbs
+header: "Libibverbs Programmer's Manual"
+layout: page
+license: 'Licensed under the OpenIB.org BSD license (FreeBSD Variant) - See COPYING.md'
+section: 3
+title: IBV_GET_PKEY_INDEX
+---
+
+# NAME
+
+ibv_get_pkey_index - obtain the index in the P_Key table of a P_Key
+
+# SYNOPSIS
+
+```c
+#include <infiniband/verbs.h>
+
+int ibv_get_pkey_index(struct ibv_context *context,
+                       uint8_t port_num,
+                       __be16 pkey);
+```
+
+# DESCRIPTION
+
+Every InfiniBand HCA maintains a P_Key table for each of its ports that is
+indexed by an integer and with a P_Key in each element. Certain InfiniBand
+data structures that work with P_Keys expect a P_Key index, e.g. **struct
+ibv_qp_attr** and **struct ib_mad_addr**. Hence the function
+**ibv_get_pkey_index()** that accepts a P_Key in network byte order and that
+returns an index in the P_Key table as result.
+
+# RETURN VALUE
+
+**ibv_get_pkey_index()** returns the P_Key index on success, and -1 on error.
+
+# SEE ALSO
+
+**ibv_open_device**(3),
+**ibv_query_device**(3),
+**ibv_query_gid**(3),
+**ibv_query_pkey**(3),
+**ibv_query_port**(3)
+
+# AUTHOR
+
+Bart Van Assche <bvanassche@acm.org>
diff --git a/libibverbs/verbs.c b/libibverbs/verbs.c
index a0aac3681f08..fde550309d36 100644
--- a/libibverbs/verbs.c
+++ b/libibverbs/verbs.c
@@ -200,6 +200,22 @@ LATEST_SYMVER_FUNC(ibv_query_pkey, 1_1, "IBVERBS_1.1",
 	return 0;
 }
 
+LATEST_SYMVER_FUNC(ibv_get_pkey_index, 1_1, "IBVERBS_1.1",
+		   int,
+		   struct ibv_context *context, uint8_t port_num, __be16 pkey)
+{
+	__be16 pkey_i;
+	int i, ret;
+
+	for (i = 0; ; i++) {
+		ret = ibv_query_pkey(context, port_num, i, &pkey_i);
+		if (ret < 0)
+			return ret;
+		if (pkey == pkey_i)
+			return i;
+	}
+}
+
 LATEST_SYMVER_FUNC(ibv_alloc_pd, 1_1, "IBVERBS_1.1",
 		   struct ibv_pd *,
 		   struct ibv_context *context)
diff --git a/libibverbs/verbs.h b/libibverbs/verbs.h
index 086f7862f62c..ad44c7d8990e 100644
--- a/libibverbs/verbs.h
+++ b/libibverbs/verbs.h
@@ -1969,6 +1969,12 @@ int ibv_query_gid(struct ibv_context *context, uint8_t port_num,
 int ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
 		   int index, __be16 *pkey);
 
+/**
+ * ibv_get_pkey_index - Translate a P_Key into a P_Key index
+ */
+int ibv_get_pkey_index(struct ibv_context *context, uint8_t port_num,
+		       __be16 pkey);
+
 /**
  * ibv_alloc_pd - Allocate a protection domain
  */
diff --git a/librdmacm/cma.c b/librdmacm/cma.c
index 5251c7ea34fc..5e738e3b0feb 100644
--- a/librdmacm/cma.c
+++ b/librdmacm/cma.c
@@ -1092,33 +1092,17 @@ static int ucma_modify_qp_err(struct rdma_cm_id *id)
 	return rdma_seterrno(ibv_modify_qp(id->qp, &qp_attr, IBV_QP_STATE));
 }
 
-static int ucma_find_pkey(struct cma_device *cma_dev, uint8_t port_num,
-			  __be16 pkey, uint16_t *pkey_index)
-{
-	int ret, i;
-	__be16 chk_pkey;
-
-	for (i = 0, ret = 0; !ret; i++) {
-		ret = ibv_query_pkey(cma_dev->verbs, port_num, i, &chk_pkey);
-		if (!ret && pkey == chk_pkey) {
-			*pkey_index = (uint16_t) i;
-			return 0;
-		}
-	}
-	return ERR(EINVAL);
-}
-
 static int ucma_init_conn_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp)
 {
 	struct ibv_qp_attr qp_attr;
 	int ret;
 
-	ret = ucma_find_pkey(id_priv->cma_dev, id_priv->id.port_num,
-			     id_priv->id.route.addr.addr.ibaddr.pkey,
-			     &qp_attr.pkey_index);
-	if (ret)
-		return ret;
+	ret = ibv_get_pkey_index(id_priv->cma_dev->verbs, id_priv->id.port_num,
+				 id_priv->id.route.addr.addr.ibaddr.pkey);
+	if (ret < 0)
+		return ERR(EINVAL);
 
+	qp_attr.pkey_index = ret;
 	qp_attr.port_num = id_priv->id.port_num;
 	qp_attr.qp_state = IBV_QPS_INIT;
 	qp_attr.qp_access_flags = 0;
@@ -1149,12 +1133,12 @@ static int ucma_init_ud_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp)
 	struct ibv_qp_attr qp_attr;
 	int ret;
 
-	ret = ucma_find_pkey(id_priv->cma_dev, id_priv->id.port_num,
-			     id_priv->id.route.addr.addr.ibaddr.pkey,
-			     &qp_attr.pkey_index);
-	if (ret)
-		return ret;
+	ret = ibv_get_pkey_index(id_priv->cma_dev->verbs, id_priv->id.port_num,
+				 id_priv->id.route.addr.addr.ibaddr.pkey);
+	if (ret < 0)
+		return ERR(EINVAL);
 
+	qp_attr.pkey_index = ret;
 	qp_attr.port_num = id_priv->id.port_num;
 	qp_attr.qp_state = IBV_QPS_INIT;
 	qp_attr.qkey = RDMA_UDP_QKEY;
