+/**
+ * Create verbs QP resources associated with a rxq.
+ *
+ * @param rxq
+ * Pointer to RX queue structure.
+ * @param desc
+ * Number of descriptors to configure in queue.
+ * @param inactive
+ * If true, the queue is disabled because its index is higher or
+ * equal to the real number of queues, which must be a power of 2.
+ * @param children_n
+ * The number of children in a parent case, zero for a child.
+ * @param rxq_parent
+ * The pointer to a parent RX structure for a child in RSS case,
+ * NULL for parent.
+ *
+ * @return
+ * 0 on success, errno value on failure.
+ */
+int
+rxq_create_qp(struct rxq *rxq,
+ uint16_t desc,
+ int inactive,
+ int children_n,
+ struct rxq *rxq_parent)
+{
+ int ret;
+ struct ibv_exp_qp_attr mod;
+ struct ibv_exp_query_intf_params params;
+ enum ibv_exp_query_intf_status status;
+ struct ibv_recv_wr *bad_wr;
+ int parent = (children_n > 0);
+ struct priv *priv = rxq->priv;
+
+#ifdef RSS_SUPPORT
+ if (priv->rss && !inactive && (rxq_parent || parent))
+ rxq->qp = rxq_setup_qp_rss(priv, rxq->cq, desc,
+ children_n, rxq->rd,
+ rxq_parent);
+ else
+#endif /* RSS_SUPPORT */
+ rxq->qp = rxq_setup_qp(priv, rxq->cq, desc, rxq->rd);
+ if (rxq->qp == NULL) {
+ ret = (errno ? errno : EINVAL);
+ ERROR("QP creation failure: %s",
+ strerror(ret));
+ return ret;
+ }
+ mod = (struct ibv_exp_qp_attr){
+ /* Move the QP to this state. */
+ .qp_state = IBV_QPS_INIT,
+ /* Primary port number. */
+ .port_num = priv->port
+ };
+ ret = ibv_exp_modify_qp(rxq->qp, &mod,
+ (IBV_EXP_QP_STATE |
+#ifdef RSS_SUPPORT
+ (parent ? IBV_EXP_QP_GROUP_RSS : 0) |
+#endif /* RSS_SUPPORT */
+ IBV_EXP_QP_PORT));
+ if (ret) {
+ ERROR("QP state to IBV_QPS_INIT failed: %s",
+ strerror(ret));
+ return ret;
+ }
+ if (!priv->isolated && (parent || !priv->rss)) {
+ /* Configure MAC and broadcast addresses. */
+ ret = rxq_mac_addrs_add(rxq);
+ if (ret) {
+ ERROR("QP flow attachment failed: %s",
+ strerror(ret));
+ return ret;
+ }
+ }
+ if (!parent) {
+ ret = ibv_post_recv(rxq->qp,
+ (rxq->sp ?
+ &(*rxq->elts.sp)[0].wr :
+ &(*rxq->elts.no_sp)[0].wr),
+ &bad_wr);
+ if (ret) {
+ ERROR("ibv_post_recv() failed for WR %p: %s",
+ (void *)bad_wr,
+ strerror(ret));
+ return ret;
+ }
+ }
+ mod = (struct ibv_exp_qp_attr){
+ .qp_state = IBV_QPS_RTR
+ };
+ ret = ibv_exp_modify_qp(rxq->qp, &mod, IBV_EXP_QP_STATE);
+ if (ret) {
+ ERROR("QP state to IBV_QPS_RTR failed: %s",
+ strerror(ret));
+ return ret;
+ }
+ params = (struct ibv_exp_query_intf_params){
+ .intf_scope = IBV_EXP_INTF_GLOBAL,
+ .intf = IBV_EXP_INTF_QP_BURST,
+ .obj = rxq->qp,
+ };
+ rxq->if_qp = ibv_exp_query_intf(priv->ctx, ¶ms, &status);
+ if (rxq->if_qp == NULL) {
+ ERROR("QP interface family query failed with status %d",
+ status);
+ return errno;
+ }
+ return 0;
+}
+