diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index a27399a..b04a104 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -61,6 +61,9 @@
 /** Maximum size for inline data. */
 #define MLX4_PMD_MAX_INLINE 0
 
+/** Fixed RSS hash key size in bytes. Cannot be modified. */
+#define MLX4_RSS_HASH_KEY_SIZE 40
+
 /**
  * Maximum number of cached Memory Pools (MPs) per TX queue. Each RTE MP
  * from which buffers are to be transmitted will have to be mapped by this
diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
index 9978e5d..171fe3f 100644
--- a/drivers/net/mlx4/mlx4_rxq.c
+++ b/drivers/net/mlx4/mlx4_rxq.c
@@ -268,18 +268,64 @@ mlx4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	rxq->qp = ibv_create_qp
-		(priv->pd,
-		 &(struct ibv_qp_init_attr){
-			.send_cq = rxq->cq,
-			.recv_cq = rxq->cq,
-			.cap = {
-				.max_recv_wr =
-					RTE_MIN(priv->device_attr.max_qp_wr,
-						desc),
-				.max_recv_sge = 1,
+	rxq->wq = ibv_create_wq
+		(priv->ctx,
+		 &(struct ibv_wq_init_attr){
+			.wq_type = IBV_WQT_RQ,
+			.max_wr = RTE_MIN(priv->device_attr.max_qp_wr, desc),
+			.max_sge = 1,
+			.pd = priv->pd,
+			.cq = rxq->cq,
+		 });
+	if (!rxq->wq) {
+		rte_errno = errno ? errno : EINVAL;
+		ERROR("%p: WQ creation failure: %s",
+		      (void *)dev, strerror(rte_errno));
+		goto error;
+	}
+	ret = ibv_modify_wq
+		(rxq->wq,
+		 &(struct ibv_wq_attr){
+			.attr_mask = IBV_WQ_ATTR_STATE,
+			.wq_state = IBV_WQS_RDY,
+		 });
+	if (ret) {
+		rte_errno = ret;
+		ERROR("%p: WQ state to IBV_WPS_RDY failed: %s",
+		      (void *)dev, strerror(rte_errno));
+		goto error;
+	}
+	rxq->ind = ibv_create_rwq_ind_table
+		(priv->ctx,
+		 &(struct ibv_rwq_ind_table_init_attr){
+			.log_ind_tbl_size = 0,
+			.ind_tbl = (struct ibv_wq *[]){
+				rxq->wq,
 			},
+			.comp_mask = 0,
+		 });
+	if (!rxq->ind) {
+		rte_errno = errno ? errno : EINVAL;
+		ERROR("%p: indirection table creation failure: %s",
+		      (void *)dev, strerror(errno));
+		goto error;
+	}
+	rxq->qp = ibv_create_qp_ex
+		(priv->ctx,
+		 &(struct ibv_qp_init_attr_ex){
+			.comp_mask = (IBV_QP_INIT_ATTR_PD |
+				      IBV_QP_INIT_ATTR_RX_HASH |
+				      IBV_QP_INIT_ATTR_IND_TABLE),
 			.qp_type = IBV_QPT_RAW_PACKET,
+			.pd = priv->pd,
+			.rwq_ind_tbl = rxq->ind,
+			.rx_hash_conf = {
+				.rx_hash_function = IBV_RX_HASH_FUNC_TOEPLITZ,
+				.rx_hash_key_len = MLX4_RSS_HASH_KEY_SIZE,
+				.rx_hash_key =
+					(uint8_t [MLX4_RSS_HASH_KEY_SIZE]){ 0 },
+				.rx_hash_fields_mask = 0,
+			},
 		 });
 	if (!rxq->qp) {
 		rte_errno = errno ? errno : EINVAL;
@@ -306,8 +352,8 @@ mlx4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_post_recv(rxq->qp, &(*rxq->elts)[0].wr,
-			    &(struct ibv_recv_wr *){ NULL });
+	ret = ibv_post_wq_recv(rxq->wq, &(*rxq->elts)[0].wr,
+			       &(struct ibv_recv_wr *){ NULL });
 	if (ret) {
 		rte_errno = ret;
 		ERROR("%p: ibv_post_recv() failed: %s",
@@ -373,6 +419,10 @@ mlx4_rx_queue_release(void *dpdk_rxq)
 	mlx4_rxq_free_elts(rxq);
 	if (rxq->qp)
 		claim_zero(ibv_destroy_qp(rxq->qp));
+	if (rxq->ind)
+		claim_zero(ibv_destroy_rwq_ind_table(rxq->ind));
+	if (rxq->wq)
+		claim_zero(ibv_destroy_wq(rxq->wq));
 	if (rxq->cq)
 		claim_zero(ibv_destroy_cq(rxq->cq));
 	if (rxq->channel)
diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
index b5e7777..859f1bd 100644
--- a/drivers/net/mlx4/mlx4_rxtx.c
+++ b/drivers/net/mlx4/mlx4_rxtx.c
@@ -459,7 +459,7 @@ mlx4_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
 	/* Repost WRs. */
 	*wr_next = NULL;
 	assert(wr_head);
-	ret = ibv_post_recv(rxq->qp, wr_head, &wr_bad);
+	ret = ibv_post_wq_recv(rxq->wq, wr_head, &wr_bad);
 	if (unlikely(ret)) {
 		/* Inability to repost WRs is fatal. */
 		DEBUG("%p: recv_burst(): failed (ret=%d)",
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
index d90f2f9..897fd2a 100644
--- a/drivers/net/mlx4/mlx4_rxtx.h
+++ b/drivers/net/mlx4/mlx4_rxtx.h
@@ -73,6 +73,8 @@ struct rxq {
 	struct rte_mempool *mp; /**< Memory pool for allocations. */
 	struct ibv_mr *mr; /**< Memory region (for mp). */
 	struct ibv_cq *cq; /**< Completion queue. */
+	struct ibv_wq *wq; /**< Work queue. */
+	struct ibv_rwq_ind_table *ind; /**< Indirection table. */
 	struct ibv_qp *qp; /**< Queue pair. */
 	struct ibv_comp_channel *channel; /**< Rx completion channel. */
 	unsigned int port_id; /**< Port ID for incoming packets. */
