From 8572e1e6b07d4d6fbbd11d57792a76257103a601 Mon Sep 17 00:00:00 2001
From: Shai Brandes <shaibran@amazon.com>
Date: Mon, 13 Nov 2023 10:15:50 +0200
Subject: [PATCH] net/ena: backport ena driver v2.8.0 for dpdk 20.11.9

This patch upgrades the ena driver to version 2.8.0 on top of
DPDK LTS 20.11.9. For the set of changes introduced by this
version since the driver version currently in use, see the
release notes under:
https://github.com/amzn/amzn-drivers/blob/master/userspace/dpdk

Signed-off-by: Shai Brandes <shaibran@amazon.com>
---
 drivers/net/ena/base/ena_com.c                |  804 +++++--
 drivers/net/ena/base/ena_com.h                |  221 +-
 .../net/ena/base/ena_defs/ena_admin_defs.h    |  211 +-
 .../net/ena/base/ena_defs/ena_eth_io_defs.h   |   18 +-
 drivers/net/ena/base/ena_defs/ena_gen_info.h  |    4 +-
 drivers/net/ena/base/ena_defs/ena_regs_defs.h |   12 +
 drivers/net/ena/base/ena_eth_com.c            |  117 +-
 drivers/net/ena/base/ena_eth_com.h            |   43 +-
 drivers/net/ena/base/ena_plat.h               |   18 -
 drivers/net/ena/base/ena_plat_dpdk.h          |  359 +--
 drivers/net/ena/ena_ethdev.c                  | 1976 ++++++++++++-----
 drivers/net/ena/ena_ethdev.h                  |  120 +-
 drivers/net/ena/ena_logs.h                    |   21 +-
 drivers/net/ena/ena_rss.c                     |  590 +++++
 drivers/net/ena/meson.build                   |   15 +-
 15 files changed, 3445 insertions(+), 1084 deletions(-)
 create mode 100644 drivers/net/ena/ena_rss.c

diff --git a/drivers/net/ena/base/ena_com.c b/drivers/net/ena/base/ena_com.c
index 00dea4bfc7..6953a1fa33 100644
--- a/drivers/net/ena/base/ena_com.c
+++ b/drivers/net/ena/base/ena_com.c
@@ -38,6 +38,12 @@
 
 #define ENA_MAX_ADMIN_POLL_US 5000
 
+/* PHC definitions */
+#define ENA_PHC_DEFAULT_EXPIRE_TIMEOUT_USEC 20
+#define ENA_PHC_DEFAULT_BLOCK_TIMEOUT_USEC 1000
+#define ENA_PHC_TIMESTAMP_ERROR 0xFFFFFFFFFFFFFFFF
+#define ENA_PHC_REQ_ID_OFFSET 0xDEAD
+
 /*****************************************************************************/
 /*****************************************************************************/
 /*****************************************************************************/
@@ -70,7 +76,7 @@ static int ena_com_mem_addr_set(struct ena_com_dev *ena_dev,
 				       dma_addr_t addr)
 {
 	if ((addr & GENMASK_ULL(ena_dev->dma_addr_bits - 1, 0)) != addr) {
-		ena_trc_err("dma address has more bits that the device supports\n");
+		ena_trc_err(ena_dev, "DMA address has more bits than the device supports\n");
 		return ENA_COM_INVAL;
 	}
 
@@ -80,16 +86,17 @@ static int ena_com_mem_addr_set(struct ena_com_dev *ena_dev,
 	return 0;
 }
 
-static int ena_com_admin_init_sq(struct ena_com_admin_queue *queue)
+static int ena_com_admin_init_sq(struct ena_com_admin_queue *admin_queue)
 {
-	struct ena_com_admin_sq *sq = &queue->sq;
-	u16 size = ADMIN_SQ_SIZE(queue->q_depth);
+	struct ena_com_dev *ena_dev = admin_queue->ena_dev;
+	struct ena_com_admin_sq *sq = &admin_queue->sq;
+	u16 size = ADMIN_SQ_SIZE(admin_queue->q_depth);
 
-	ENA_MEM_ALLOC_COHERENT(queue->q_dmadev, size, sq->entries, sq->dma_addr,
+	ENA_MEM_ALLOC_COHERENT(admin_queue->q_dmadev, size, sq->entries, sq->dma_addr,
 			       sq->mem_handle);
 
 	if (!sq->entries) {
-		ena_trc_err("memory allocation failed\n");
+		ena_trc_err(ena_dev, "Memory allocation failed\n");
 		return ENA_COM_NO_MEM;
 	}
 
@@ -102,16 +109,17 @@ static int ena_com_admin_init_sq(struct ena_com_admin_queue *queue)
 	return 0;
 }
 
-static int ena_com_admin_init_cq(struct ena_com_admin_queue *queue)
+static int ena_com_admin_init_cq(struct ena_com_admin_queue *admin_queue)
 {
-	struct ena_com_admin_cq *cq = &queue->cq;
-	u16 size = ADMIN_CQ_SIZE(queue->q_depth);
+	struct ena_com_dev *ena_dev = admin_queue->ena_dev;
+	struct ena_com_admin_cq *cq = &admin_queue->cq;
+	u16 size = ADMIN_CQ_SIZE(admin_queue->q_depth);
 
-	ENA_MEM_ALLOC_COHERENT(queue->q_dmadev, size, cq->entries, cq->dma_addr,
+	ENA_MEM_ALLOC_COHERENT(admin_queue->q_dmadev, size, cq->entries, cq->dma_addr,
 			       cq->mem_handle);
 
 	if (!cq->entries)  {
-		ena_trc_err("memory allocation failed\n");
+		ena_trc_err(ena_dev, "Memory allocation failed\n");
 		return ENA_COM_NO_MEM;
 	}
 
@@ -121,22 +129,22 @@ static int ena_com_admin_init_cq(struct ena_com_admin_queue *queue)
 	return 0;
 }
 
-static int ena_com_admin_init_aenq(struct ena_com_dev *dev,
+static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev,
 				   struct ena_aenq_handlers *aenq_handlers)
 {
-	struct ena_com_aenq *aenq = &dev->aenq;
+	struct ena_com_aenq *aenq = &ena_dev->aenq;
 	u32 addr_low, addr_high, aenq_caps;
 	u16 size;
 
-	dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH;
+	ena_dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH;
 	size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH);
-	ENA_MEM_ALLOC_COHERENT(dev->dmadev, size,
+	ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, size,
 			aenq->entries,
 			aenq->dma_addr,
 			aenq->mem_handle);
 
 	if (!aenq->entries) {
-		ena_trc_err("memory allocation failed\n");
+		ena_trc_err(ena_dev, "Memory allocation failed\n");
 		return ENA_COM_NO_MEM;
 	}
 
@@ -146,18 +154,18 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *dev,
 	addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(aenq->dma_addr);
 	addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(aenq->dma_addr);
 
-	ENA_REG_WRITE32(dev->bus, addr_low, dev->reg_bar + ENA_REGS_AENQ_BASE_LO_OFF);
-	ENA_REG_WRITE32(dev->bus, addr_high, dev->reg_bar + ENA_REGS_AENQ_BASE_HI_OFF);
+	ENA_REG_WRITE32(ena_dev->bus, addr_low, ena_dev->reg_bar + ENA_REGS_AENQ_BASE_LO_OFF);
+	ENA_REG_WRITE32(ena_dev->bus, addr_high, ena_dev->reg_bar + ENA_REGS_AENQ_BASE_HI_OFF);
 
 	aenq_caps = 0;
-	aenq_caps |= dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK;
+	aenq_caps |= ena_dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK;
 	aenq_caps |= (sizeof(struct ena_admin_aenq_entry) <<
 		ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) &
 		ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK;
-	ENA_REG_WRITE32(dev->bus, aenq_caps, dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF);
+	ENA_REG_WRITE32(ena_dev->bus, aenq_caps, ena_dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF);
 
 	if (unlikely(!aenq_handlers)) {
-		ena_trc_err("aenq handlers pointer is NULL\n");
+		ena_trc_err(ena_dev, "AENQ handlers pointer is NULL\n");
 		return ENA_COM_INVAL;
 	}
 
@@ -173,31 +181,34 @@ static void comp_ctxt_release(struct ena_com_admin_queue *queue,
 	ATOMIC32_DEC(&queue->outstanding_cmds);
 }
 
-static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *queue,
+static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *admin_queue,
 					  u16 command_id, bool capture)
 {
-	if (unlikely(command_id >= queue->q_depth)) {
-		ena_trc_err("command id is larger than the queue size. cmd_id: %u queue size %d\n",
-			    command_id, queue->q_depth);
+	if (unlikely(command_id >= admin_queue->q_depth)) {
+		ena_trc_err(admin_queue->ena_dev,
+			    "Command id is larger than the queue size. cmd_id: %u queue size %d\n",
+			    command_id, admin_queue->q_depth);
 		return NULL;
 	}
 
-	if (unlikely(!queue->comp_ctx)) {
-		ena_trc_err("Completion context is NULL\n");
+	if (unlikely(!admin_queue->comp_ctx)) {
+		ena_trc_err(admin_queue->ena_dev,
+			    "Completion context is NULL\n");
 		return NULL;
 	}
 
-	if (unlikely(queue->comp_ctx[command_id].occupied && capture)) {
-		ena_trc_err("Completion context is occupied\n");
+	if (unlikely(admin_queue->comp_ctx[command_id].occupied && capture)) {
+		ena_trc_err(admin_queue->ena_dev,
+			    "Completion context is occupied\n");
 		return NULL;
 	}
 
 	if (capture) {
-		ATOMIC32_INC(&queue->outstanding_cmds);
-		queue->comp_ctx[command_id].occupied = true;
+		ATOMIC32_INC(&admin_queue->outstanding_cmds);
+		admin_queue->comp_ctx[command_id].occupied = true;
 	}
 
-	return &queue->comp_ctx[command_id];
+	return &admin_queue->comp_ctx[command_id];
 }
 
 static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue,
@@ -218,7 +229,7 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu
 	/* In case of queue FULL */
 	cnt = (u16)ATOMIC32_READ(&admin_queue->outstanding_cmds);
 	if (cnt >= admin_queue->q_depth) {
-		ena_trc_dbg("admin queue is full.\n");
+		ena_trc_dbg(admin_queue->ena_dev, "Admin queue is full.\n");
 		admin_queue->stats.out_of_space++;
 		return ERR_PTR(ENA_COM_NO_SPACE);
 	}
@@ -260,20 +271,21 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu
 	return comp_ctx;
 }
 
-static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *queue)
+static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *admin_queue)
 {
-	size_t size = queue->q_depth * sizeof(struct ena_comp_ctx);
+	struct ena_com_dev *ena_dev = admin_queue->ena_dev;
+	size_t size = admin_queue->q_depth * sizeof(struct ena_comp_ctx);
 	struct ena_comp_ctx *comp_ctx;
 	u16 i;
 
-	queue->comp_ctx = ENA_MEM_ALLOC(queue->q_dmadev, size);
-	if (unlikely(!queue->comp_ctx)) {
-		ena_trc_err("memory allocation failed\n");
+	admin_queue->comp_ctx = ENA_MEM_ALLOC(admin_queue->q_dmadev, size);
+	if (unlikely(!admin_queue->comp_ctx)) {
+		ena_trc_err(ena_dev, "Memory allocation failed\n");
 		return ENA_COM_NO_MEM;
 	}
 
-	for (i = 0; i < queue->q_depth; i++) {
-		comp_ctx = get_comp_ctxt(queue, i, false);
+	for (i = 0; i < admin_queue->q_depth; i++) {
+		comp_ctx = get_comp_ctxt(admin_queue, i, false);
 		if (comp_ctx)
 			ENA_WAIT_EVENT_INIT(comp_ctx->wait_event);
 	}
@@ -341,7 +353,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
 		}
 
 		if (!io_sq->desc_addr.virt_addr) {
-			ena_trc_err("memory allocation failed\n");
+			ena_trc_err(ena_dev, "Memory allocation failed\n");
 			return ENA_COM_NO_MEM;
 		}
 	}
@@ -354,7 +366,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
 			ENA_COM_BOUNCE_BUFFER_CNTRL_CNT;
 		io_sq->bounce_buf_ctrl.next_to_use = 0;
 
-		size = io_sq->bounce_buf_ctrl.buffer_size *
+		size = (size_t)io_sq->bounce_buf_ctrl.buffer_size *
 			io_sq->bounce_buf_ctrl.buffers_num;
 
 		ENA_MEM_ALLOC_NODE(ena_dev->dmadev,
@@ -366,7 +378,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
 			io_sq->bounce_buf_ctrl.base_buffer = ENA_MEM_ALLOC(ena_dev->dmadev, size);
 
 		if (!io_sq->bounce_buf_ctrl.base_buffer) {
-			ena_trc_err("bounce buffer memory allocation failed\n");
+			ena_trc_err(ena_dev, "Bounce buffer memory allocation failed\n");
 			return ENA_COM_NO_MEM;
 		}
 
@@ -431,7 +443,7 @@ static int ena_com_init_io_cq(struct ena_com_dev *ena_dev,
 	}
 
 	if (!io_cq->cdesc_addr.virt_addr) {
-		ena_trc_err("memory allocation failed\n");
+		ena_trc_err(ena_dev, "Memory allocation failed\n");
 		return ENA_COM_NO_MEM;
 	}
 
@@ -452,7 +464,8 @@ static void ena_com_handle_single_admin_completion(struct ena_com_admin_queue *a
 
 	comp_ctx = get_comp_ctxt(admin_queue, cmd_id, false);
 	if (unlikely(!comp_ctx)) {
-		ena_trc_err("comp_ctx is NULL. Changing the admin queue running state\n");
+		ena_trc_err(admin_queue->ena_dev,
+			    "comp_ctx is NULL. Changing the admin queue running state\n");
 		admin_queue->running_state = false;
 		return;
 	}
@@ -504,10 +517,12 @@ static void ena_com_handle_admin_completion(struct ena_com_admin_queue *admin_qu
 	admin_queue->stats.completed_cmd += comp_num;
 }
 
-static int ena_com_comp_status_to_errno(u8 comp_status)
+static int ena_com_comp_status_to_errno(struct ena_com_admin_queue *admin_queue,
+					u8 comp_status)
 {
 	if (unlikely(comp_status != 0))
-		ena_trc_err("admin command failed[%u]\n", comp_status);
+		ena_trc_err(admin_queue->ena_dev,
+			    "Admin command failed[%u]\n", comp_status);
 
 	switch (comp_status) {
 	case ENA_ADMIN_SUCCESS:
@@ -554,7 +569,8 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c
 			break;
 
 		if (ENA_TIME_EXPIRE(timeout)) {
-			ena_trc_err("Wait for completion (polling) timeout\n");
+			ena_trc_err(admin_queue->ena_dev,
+				    "Wait for completion (polling) timeout\n");
 			/* ENA didn't have any completion */
 			ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags);
 			admin_queue->stats.no_completion++;
@@ -570,7 +586,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c
 	}
 
 	if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) {
-		ena_trc_err("Command was aborted\n");
+		ena_trc_err(admin_queue->ena_dev, "Command was aborted\n");
 		ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags);
 		admin_queue->stats.aborted_cmd++;
 		ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags);
@@ -579,9 +595,10 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c
 	}
 
 	ENA_WARN(comp_ctx->status != ENA_CMD_COMPLETED,
-		 "Invalid comp status %d\n", comp_ctx->status);
+		 admin_queue->ena_dev, "Invalid comp status %d\n",
+		 comp_ctx->status);
 
-	ret = ena_com_comp_status_to_errno(comp_ctx->comp_status);
+	ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status);
 err:
 	comp_ctxt_release(admin_queue, comp_ctx);
 	return ret;
@@ -623,7 +640,7 @@ static int ena_com_set_llq(struct ena_com_dev *ena_dev)
 					    sizeof(resp));
 
 	if (unlikely(ret))
-		ena_trc_err("Failed to set LLQ configurations: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to set LLQ configurations: %d\n", ret);
 
 	return ret;
 }
@@ -645,9 +662,9 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 		llq_info->header_location_ctrl =
 			llq_default_cfg->llq_header_location;
 	} else {
-		ena_trc_err("Invalid header location control, supported: 0x%x\n",
+		ena_trc_err(ena_dev, "Invalid header location control, supported: 0x%x\n",
 			    supported_feat);
-		return -EINVAL;
+		return ENA_COM_INVAL;
 	}
 
 	if (likely(llq_info->header_location_ctrl == ENA_ADMIN_INLINE_HEADER)) {
@@ -660,12 +677,12 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 			} else if (supported_feat & ENA_ADMIN_SINGLE_DESC_PER_ENTRY) {
 				llq_info->desc_stride_ctrl = ENA_ADMIN_SINGLE_DESC_PER_ENTRY;
 			} else {
-				ena_trc_err("Invalid desc_stride_ctrl, supported: 0x%x\n",
+				ena_trc_err(ena_dev, "Invalid desc_stride_ctrl, supported: 0x%x\n",
 					    supported_feat);
-				return -EINVAL;
+				return ENA_COM_INVAL;
 			}
 
-			ena_trc_err("Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+			ena_trc_err(ena_dev, "Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
 				    llq_default_cfg->llq_stride_ctrl,
 				    supported_feat,
 				    llq_info->desc_stride_ctrl);
@@ -689,11 +706,12 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 			llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
 			llq_info->desc_list_entry_size = 256;
 		} else {
-			ena_trc_err("Invalid entry_size_ctrl, supported: 0x%x\n", supported_feat);
-			return -EINVAL;
+			ena_trc_err(ena_dev, "Invalid entry_size_ctrl, supported: 0x%x\n",
+				    supported_feat);
+			return ENA_COM_INVAL;
 		}
 
-		ena_trc_err("Default llq ring entry size is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+		ena_trc_err(ena_dev, "Default llq ring entry size is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
 			    llq_default_cfg->llq_ring_entry_size,
 			    supported_feat,
 			    llq_info->desc_list_entry_size);
@@ -702,9 +720,9 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 		/* The desc list entry size should be whole multiply of 8
 		 * This requirement comes from __iowrite64_copy()
 		 */
-		ena_trc_err("illegal entry size %d\n",
+		ena_trc_err(ena_dev, "Illegal entry size %d\n",
 			    llq_info->desc_list_entry_size);
-		return -EINVAL;
+		return ENA_COM_INVAL;
 	}
 
 	if (llq_info->desc_stride_ctrl == ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY)
@@ -726,12 +744,12 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 		} else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8) {
 			llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8;
 		} else {
-			ena_trc_err("Invalid descs_num_before_header, supported: 0x%x\n",
+			ena_trc_err(ena_dev, "Invalid descs_num_before_header, supported: 0x%x\n",
 				    supported_feat);
-			return -EINVAL;
+			return ENA_COM_INVAL;
 		}
 
-		ena_trc_err("Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+		ena_trc_err(ena_dev, "Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
 			    llq_default_cfg->llq_num_decs_before_header,
 			    supported_feat,
 			    llq_info->descs_num_before_header);
@@ -750,7 +768,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 
 	rc = ena_com_set_llq(ena_dev);
 	if (rc)
-		ena_trc_err("Cannot set LLQ configuration: %d\n", rc);
+		ena_trc_err(ena_dev, "Cannot set LLQ configuration: %d\n", rc);
 
 	return rc;
 }
@@ -776,13 +794,15 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com
 		ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags);
 
 		if (comp_ctx->status == ENA_CMD_COMPLETED) {
-			ena_trc_err("The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n",
+			ena_trc_err(admin_queue->ena_dev,
+				    "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n",
 				    comp_ctx->cmd_opcode, admin_queue->auto_polling ? "ON" : "OFF");
 			/* Check if fallback to polling is enabled */
 			if (admin_queue->auto_polling)
 				admin_queue->polling = true;
 		} else {
-			ena_trc_err("The ena device didn't send a completion for the admin cmd %d status %d\n",
+			ena_trc_err(admin_queue->ena_dev,
+				    "The ena device didn't send a completion for the admin cmd %d status %d\n",
 				    comp_ctx->cmd_opcode, comp_ctx->status);
 		}
 		/* Check if shifted to polling mode.
@@ -796,7 +816,7 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com
 		}
 	}
 
-	ret = ena_com_comp_status_to_errno(comp_ctx->comp_status);
+	ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status);
 err:
 	comp_ctxt_release(admin_queue, comp_ctx);
 	return ret;
@@ -844,7 +864,7 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
 	}
 
 	if (unlikely(i == timeout)) {
-		ena_trc_err("reading reg failed for timeout. expected: req id[%hu] offset[%hu] actual: req id[%hu] offset[%hu]\n",
+		ena_trc_err(ena_dev, "Reading reg failed for timeout. expected: req id[%u] offset[%u] actual: req id[%u] offset[%u]\n",
 			    mmio_read->seq_num,
 			    offset,
 			    read_resp->req_id,
@@ -854,7 +874,7 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
 	}
 
 	if (read_resp->reg_off != offset) {
-		ena_trc_err("Read failure: wrong offset provided\n");
+		ena_trc_err(ena_dev, "Read failure: wrong offset provided\n");
 		ret = ENA_MMIO_READ_TIMEOUT;
 	} else {
 		ret = read_resp->reg_val;
@@ -913,7 +933,7 @@ static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev,
 					    sizeof(destroy_resp));
 
 	if (unlikely(ret && (ret != ENA_COM_NO_DEVICE)))
-		ena_trc_err("failed to destroy io sq error: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to destroy io sq error: %d\n", ret);
 
 	return ret;
 }
@@ -969,7 +989,7 @@ static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout,
 		val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
 
 		if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) {
-			ena_trc_err("Reg read timeout occurred\n");
+			ena_trc_err(ena_dev, "Reg read timeout occurred\n");
 			return ENA_COM_TIMER_EXPIRED;
 		}
 
@@ -1009,7 +1029,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev,
 	int ret;
 
 	if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) {
-		ena_trc_dbg("Feature %d isn't supported\n", feature_id);
+		ena_trc_dbg(ena_dev, "Feature %d isn't supported\n", feature_id);
 		return ENA_COM_UNSUPPORTED;
 	}
 
@@ -1028,7 +1048,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev,
 				   &get_cmd.control_buffer.address,
 				   control_buf_dma_addr);
 	if (unlikely(ret)) {
-		ena_trc_err("memory address set failed\n");
+		ena_trc_err(ena_dev, "Memory address set failed\n");
 		return ret;
 	}
 
@@ -1045,7 +1065,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev,
 					    sizeof(*get_resp));
 
 	if (unlikely(ret))
-		ena_trc_err("Failed to submit get_feature command %d error: %d\n",
+		ena_trc_err(ena_dev, "Failed to submit get_feature command %d error: %d\n",
 			    feature_id, ret);
 
 	return ret;
@@ -1157,7 +1177,7 @@ static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev,
 
 	if ((get_resp.u.ind_table.min_size > log_size) ||
 	    (get_resp.u.ind_table.max_size < log_size)) {
-		ena_trc_err("indirect table size doesn't fit. requested size: %d while min is:%d and max %d\n",
+		ena_trc_err(ena_dev, "Indirect table size doesn't fit. requested size: %d while min is:%d and max %d\n",
 			    1 << log_size,
 			    1 << get_resp.u.ind_table.min_size,
 			    1 << get_resp.u.ind_table.max_size);
@@ -1261,7 +1281,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev,
 					   &create_cmd.sq_ba,
 					   io_sq->desc_addr.phys_addr);
 		if (unlikely(ret)) {
-			ena_trc_err("memory address set failed\n");
+			ena_trc_err(ena_dev, "Memory address set failed\n");
 			return ret;
 		}
 	}
@@ -1272,7 +1292,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev,
 					    (struct ena_admin_acq_entry *)&cmd_completion,
 					    sizeof(cmd_completion));
 	if (unlikely(ret)) {
-		ena_trc_err("Failed to create IO SQ. error: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to create IO SQ. error: %d\n", ret);
 		return ret;
 	}
 
@@ -1282,15 +1302,12 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev,
 		(uintptr_t)cmd_completion.sq_doorbell_offset);
 
 	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
-		io_sq->header_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar
-				+ cmd_completion.llq_headers_offset);
-
 		io_sq->desc_addr.pbuf_dev_addr =
 			(u8 __iomem *)((uintptr_t)ena_dev->mem_bar +
 			cmd_completion.llq_descriptors_offset);
 	}
 
-	ena_trc_dbg("created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth);
+	ena_trc_dbg(ena_dev, "Created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth);
 
 	return ret;
 }
@@ -1324,7 +1341,7 @@ static void ena_com_update_intr_delay_resolution(struct ena_com_dev *ena_dev,
 	u16 prev_intr_delay_resolution = ena_dev->intr_delay_resolution;
 
 	if (unlikely(!intr_delay_resolution)) {
-		ena_trc_err("Illegal intr_delay_resolution provided. Going to use default 1 usec resolution\n");
+		ena_trc_err(ena_dev, "Illegal intr_delay_resolution provided. Going to use default 1 usec resolution\n");
 		intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION;
 	}
 
@@ -1359,24 +1376,27 @@ int ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue,
 	comp_ctx = ena_com_submit_admin_cmd(admin_queue, cmd, cmd_size,
 					    comp, comp_size);
 	if (IS_ERR(comp_ctx)) {
-		if (comp_ctx == ERR_PTR(ENA_COM_NO_DEVICE))
-			ena_trc_dbg("Failed to submit command [%ld]\n",
-				    PTR_ERR(comp_ctx));
+		ret = PTR_ERR(comp_ctx);
+		if (ret == ENA_COM_NO_DEVICE)
+			ena_trc_dbg(admin_queue->ena_dev,
+				    "Failed to submit command [%d]\n",
+				    ret);
 		else
-			ena_trc_err("Failed to submit command [%ld]\n",
-				    PTR_ERR(comp_ctx));
+			ena_trc_err(admin_queue->ena_dev,
+				    "Failed to submit command [%d]\n",
+				    ret);
 
-		return (int)PTR_ERR(comp_ctx);
+		return ret;
 	}
 
 	ret = ena_com_wait_and_process_admin_cq(comp_ctx, admin_queue);
 	if (unlikely(ret)) {
 		if (admin_queue->running_state)
-			ena_trc_err("Failed to process command. ret = %d\n",
-				    ret);
+			ena_trc_err(admin_queue->ena_dev,
+				    "Failed to process command. ret = %d\n", ret);
 		else
-			ena_trc_dbg("Failed to process command. ret = %d\n",
-				    ret);
+			ena_trc_dbg(admin_queue->ena_dev,
+				    "Failed to process command. ret = %d\n", ret);
 	}
 	return ret;
 }
@@ -1405,7 +1425,7 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev,
 				   &create_cmd.cq_ba,
 				   io_cq->cdesc_addr.phys_addr);
 	if (unlikely(ret)) {
-		ena_trc_err("memory address set failed\n");
+		ena_trc_err(ena_dev, "Memory address set failed\n");
 		return ret;
 	}
 
@@ -1415,7 +1435,7 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev,
 					    (struct ena_admin_acq_entry *)&cmd_completion,
 					    sizeof(cmd_completion));
 	if (unlikely(ret)) {
-		ena_trc_err("Failed to create IO CQ. error: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to create IO CQ. error: %d\n", ret);
 		return ret;
 	}
 
@@ -1424,17 +1444,12 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev,
 	io_cq->unmask_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
 		cmd_completion.cq_interrupt_unmask_register_offset);
 
-	if (cmd_completion.cq_head_db_register_offset)
-		io_cq->cq_head_db_reg =
-			(u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
-			cmd_completion.cq_head_db_register_offset);
-
 	if (cmd_completion.numa_node_register_offset)
 		io_cq->numa_node_cfg_reg =
 			(u32 __iomem *)((uintptr_t)ena_dev->reg_bar +
 			cmd_completion.numa_node_register_offset);
 
-	ena_trc_dbg("created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth);
+	ena_trc_dbg(ena_dev, "Created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth);
 
 	return ret;
 }
@@ -1444,7 +1459,7 @@ int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid,
 			    struct ena_com_io_cq **io_cq)
 {
 	if (qid >= ENA_TOTAL_NUM_QUEUES) {
-		ena_trc_err("Invalid queue number %d but the max is %d\n",
+		ena_trc_err(ena_dev, "Invalid queue number %d but the max is %d\n",
 			    qid, ENA_TOTAL_NUM_QUEUES);
 		return ENA_COM_INVAL;
 	}
@@ -1510,7 +1525,7 @@ int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev,
 					    sizeof(destroy_resp));
 
 	if (unlikely(ret && (ret != ENA_COM_NO_DEVICE)))
-		ena_trc_err("Failed to destroy IO CQ. error: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to destroy IO CQ. error: %d\n", ret);
 
 	return ret;
 }
@@ -1534,7 +1549,7 @@ void ena_com_admin_aenq_enable(struct ena_com_dev *ena_dev)
 {
 	u16 depth = ena_dev->aenq.q_depth;
 
-	ENA_WARN(ena_dev->aenq.head != depth, "Invalid AENQ state\n");
+	ENA_WARN(ena_dev->aenq.head != depth, ena_dev, "Invalid AENQ state\n");
 
 	/* Init head_db to mark that all entries in the queue
 	 * are initially available
@@ -1552,12 +1567,12 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag)
 
 	ret = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_AENQ_CONFIG, 0);
 	if (ret) {
-		ena_trc_info("Can't get aenq configuration\n");
+		ena_trc_info(ena_dev, "Can't get aenq configuration\n");
 		return ret;
 	}
 
 	if ((get_resp.u.aenq.supported_groups & groups_flag) != groups_flag) {
-		ena_trc_warn("Trying to set unsupported aenq events. supported flag: 0x%x asked flag: 0x%x\n",
+		ena_trc_warn(ena_dev, "Trying to set unsupported aenq events. supported flag: 0x%x asked flag: 0x%x\n",
 			     get_resp.u.aenq.supported_groups,
 			     groups_flag);
 		return ENA_COM_UNSUPPORTED;
@@ -1578,7 +1593,7 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag)
 					    sizeof(resp));
 
 	if (unlikely(ret))
-		ena_trc_err("Failed to config AENQ ret: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to config AENQ ret: %d\n", ret);
 
 	return ret;
 }
@@ -1589,17 +1604,17 @@ int ena_com_get_dma_width(struct ena_com_dev *ena_dev)
 	u32 width;
 
 	if (unlikely(caps == ENA_MMIO_READ_TIMEOUT)) {
-		ena_trc_err("Reg read timeout occurred\n");
+		ena_trc_err(ena_dev, "Reg read timeout occurred\n");
 		return ENA_COM_TIMER_EXPIRED;
 	}
 
 	width = (caps & ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK) >>
 		ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT;
 
-	ena_trc_dbg("ENA dma width: %d\n", width);
+	ena_trc_dbg(ena_dev, "ENA dma width: %d\n", width);
 
 	if ((width < 32) || width > ENA_MAX_PHYS_ADDR_SIZE_BITS) {
-		ena_trc_err("DMA width illegal value: %d\n", width);
+		ena_trc_err(ena_dev, "DMA width illegal value: %d\n", width);
 		return ENA_COM_INVAL;
 	}
 
@@ -1623,16 +1638,16 @@ int ena_com_validate_version(struct ena_com_dev *ena_dev)
 
 	if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) ||
 		     (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) {
-		ena_trc_err("Reg read timeout occurred\n");
+		ena_trc_err(ena_dev, "Reg read timeout occurred\n");
 		return ENA_COM_TIMER_EXPIRED;
 	}
 
-	ena_trc_info("ena device version: %d.%d\n",
+	ena_trc_info(ena_dev, "ENA device version: %d.%d\n",
 		     (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >>
 		     ENA_REGS_VERSION_MAJOR_VERSION_SHIFT,
 		     ver & ENA_REGS_VERSION_MINOR_VERSION_MASK);
 
-	ena_trc_info("ena controller version: %d.%d.%d implementation version %d\n",
+	ena_trc_info(ena_dev, "ENA controller version: %d.%d.%d implementation version %d\n",
 		     (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK)
 		     >> ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT,
 		     (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK)
@@ -1648,7 +1663,7 @@ int ena_com_validate_version(struct ena_com_dev *ena_dev)
 
 	/* Validate the ctrl version without the implementation ID */
 	if (ctrl_ver_masked < MIN_ENA_CTRL_VER) {
-		ena_trc_err("ENA ctrl version is lower than the minimal ctrl version the driver supports\n");
+		ena_trc_err(ena_dev, "ENA ctrl version is lower than the minimal ctrl version the driver supports\n");
 		return -1;
 	}
 
@@ -1724,6 +1739,220 @@ void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev,
 	ena_dev->admin_queue.auto_polling = polling;
 }
 
+bool ena_com_phc_supported(struct ena_com_dev *ena_dev)
+{
+	return ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_PHC_CONFIG);
+}
+
+int ena_com_phc_init(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_phc_info *phc = &ena_dev->phc;
+
+	memset(phc, 0x0, sizeof(*phc));
+
+	/* Allocate shared mem used PHC timestamp retrieved from device */
+	ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev,
+			       sizeof(*phc->virt_addr),
+			       phc->virt_addr,
+			       phc->phys_addr,
+			       phc->mem_handle);
+	if (unlikely(!phc->virt_addr))
+		return ENA_COM_NO_MEM;
+
+	ENA_SPINLOCK_INIT(phc->lock);
+
+	phc->virt_addr->req_id = 0;
+	phc->virt_addr->timestamp = 0;
+
+	return 0;
+}
+
+int ena_com_phc_config(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_phc_info *phc = &ena_dev->phc;
+	struct ena_admin_get_feat_resp get_feat_resp;
+	struct ena_admin_set_feat_resp set_feat_resp;
+	struct ena_admin_set_feat_cmd set_feat_cmd;
+	int ret = 0;
+
+	/* Get device PHC default configuration */
+	ret = ena_com_get_feature(ena_dev, &get_feat_resp, ENA_ADMIN_PHC_CONFIG, 0);
+	if (unlikely(ret)) {
+		ena_trc_err(ena_dev, "Failed to get PHC feature configuration, error: %d\n", ret);
+		return ret;
+	}
+
+	/* Supporting only readless PHC retrieval */
+	if (get_feat_resp.u.phc.type != ENA_ADMIN_PHC_TYPE_READLESS) {
+		ena_trc_err(ena_dev, "Unsupported PHC type, error: %d\n", ENA_COM_UNSUPPORTED);
+		return ENA_COM_UNSUPPORTED;
+	}
+
+	/* Update PHC doorbell offset according to device value, used to write req_id to PHC bar */
+	phc->doorbell_offset = get_feat_resp.u.phc.doorbell_offset;
+
+	/* Update PHC expire timeout according to device or default driver value */
+	phc->expire_timeout_usec = (get_feat_resp.u.phc.expire_timeout_usec) ?
+				    get_feat_resp.u.phc.expire_timeout_usec :
+				    ENA_PHC_DEFAULT_EXPIRE_TIMEOUT_USEC;
+
+	/* Update PHC block timeout according to device or default driver value */
+	phc->block_timeout_usec = (get_feat_resp.u.phc.block_timeout_usec) ?
+				   get_feat_resp.u.phc.block_timeout_usec :
+				   ENA_PHC_DEFAULT_BLOCK_TIMEOUT_USEC;
+
+	/* Sanity check - expire timeout must not be above skip timeout */
+	if (phc->expire_timeout_usec > phc->block_timeout_usec)
+		phc->expire_timeout_usec = phc->block_timeout_usec;
+
+	/* Prepare PHC feature command with PHC output address */
+	memset(&set_feat_cmd, 0x0, sizeof(set_feat_cmd));
+	set_feat_cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+	set_feat_cmd.feat_common.feature_id = ENA_ADMIN_PHC_CONFIG;
+	set_feat_cmd.u.phc.output_length = sizeof(*phc->virt_addr);
+	ret = ena_com_mem_addr_set(ena_dev, &set_feat_cmd.u.phc.output_address, phc->phys_addr);
+	if (unlikely(ret)) {
+		ena_trc_err(ena_dev, "Failed setting PHC output address, error: %d\n", ret);
+		return ret;
+	}
+
+	/* Send PHC feature command to the device */
+	ret = ena_com_execute_admin_command(&ena_dev->admin_queue,
+					    (struct ena_admin_aq_entry *)&set_feat_cmd,
+					    sizeof(set_feat_cmd),
+					    (struct ena_admin_acq_entry *)&set_feat_resp,
+					    sizeof(set_feat_resp));
+
+	if (unlikely(ret)) {
+		ena_trc_err(ena_dev, "Failed to enable PHC, error: %d\n", ret);
+		return ret;
+	}
+
+	phc->active = true;
+	ena_trc_dbg(ena_dev, "PHC is active in the device\n");
+
+	return ret;
+}
+
+void ena_com_phc_destroy(struct ena_com_dev *ena_dev)
+{
+	struct ena_com_phc_info *phc = &ena_dev->phc;
+
+	phc->active = false;
+
+	/* In case PHC is not supported by the device, silently exiting */
+	if (!phc->virt_addr)
+		return;
+
+	ENA_MEM_FREE_COHERENT(ena_dev->dmadev,
+			      sizeof(*phc->virt_addr),
+			      phc->virt_addr,
+			      phc->phys_addr,
+			      phc->mem_handle);
+	phc->virt_addr = NULL;
+
+	ENA_SPINLOCK_DESTROY(phc->lock);
+}
+
+int ena_com_phc_get(struct ena_com_dev *ena_dev, u64 *timestamp)
+{
+	volatile struct ena_admin_phc_resp *read_resp = ena_dev->phc.virt_addr;
+	struct ena_com_phc_info *phc = &ena_dev->phc;
+	ena_time_high_res_t initial_time = ENA_TIME_INIT_HIGH_RES();
+	static ena_time_high_res_t start_time;
+	unsigned long flags = 0;
+	ena_time_high_res_t expire_time;
+	ena_time_high_res_t block_time;
+	int ret = ENA_COM_OK;
+
+	if (!phc->active) {
+		ena_trc_err(ena_dev, "PHC feature is not active in the device\n");
+		return ENA_COM_UNSUPPORTED;
+	}
+
+	ENA_SPINLOCK_LOCK(phc->lock, flags);
+
+	/* Check if PHC is in blocked state */
+	if (unlikely(ENA_TIME_COMPARE_HIGH_RES(start_time, initial_time))) {
+		/* Check if blocking time expired */
+		block_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(start_time, phc->block_timeout_usec);
+		if (!ENA_TIME_EXPIRE_HIGH_RES(block_time)) {
+			/* PHC is still in blocked state, skip PHC request */
+			phc->stats.phc_skp++;
+			ret = ENA_COM_DEVICE_BUSY;
+			goto skip;
+		}
+
+		/* PHC is in active state, update statistics according to req_id and timestamp */
+		if ((READ_ONCE16(read_resp->req_id) != phc->req_id) ||
+				read_resp->timestamp == ENA_PHC_TIMESTAMP_ERROR)
+			/* Device didn't update req_id during blocking time or timestamp is invalid,
+			 * this indicates on a device error
+			 */
+			phc->stats.phc_err++;
+		else
+			/* Device updated req_id during blocking time with valid timestamp */
+			phc->stats.phc_exp++;
+	}
+
+	/* Setting relative timeouts */
+	start_time = ENA_GET_SYSTEM_TIME_HIGH_RES();
+	block_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(start_time, phc->block_timeout_usec);
+	expire_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(start_time, phc->expire_timeout_usec);
+
+	/* We expect the device to return this req_id once the new PHC timestamp is updated */
+	phc->req_id++;
+
+	/* Initialize PHC shared memory with different req_id value to be able to identify once the
+	 * device changes it to req_id
+	 */
+	read_resp->req_id = phc->req_id + ENA_PHC_REQ_ID_OFFSET;
+
+	/* Writing req_id to PHC bar */
+	ENA_REG_WRITE32(ena_dev->bus, phc->req_id, ena_dev->reg_bar + phc->doorbell_offset);
+
+	/* Stalling until the device updates req_id */
+	while (1) {
+		if (unlikely(ENA_TIME_EXPIRE_HIGH_RES(expire_time))) {
+			/* Gave up waiting for updated req_id, PHC enters into blocked state until
+			 * passing blocking time
+			 */
+			ret = ENA_COM_DEVICE_BUSY;
+			break;
+		}
+
+		/* Check if req_id was updated by the device */
+		if (READ_ONCE16(read_resp->req_id) != phc->req_id) {
+			/* req_id was not updated by the device, check again on next loop */
+			continue;
+		}
+
+		/* req_id was updated which indicates that PHC timestamp was updated too */
+		*timestamp = read_resp->timestamp;
+
+		/* PHC timestamp validty check */
+		if (unlikely(*timestamp == ENA_PHC_TIMESTAMP_ERROR)) {
+			/* Retrieved invalid PHC timestamp, PHC enters into blocked state until
+			 * passing blocking time
+			 */
+			ret = ENA_COM_DEVICE_BUSY;
+			break;
+		}
+
+		/* Retrieved valid PHC timestamp */
+		phc->stats.phc_cnt++;
+
+		/* This indicates PHC state is active */
+		start_time = initial_time;
+		break;
+	}
+
+skip:
+	ENA_SPINLOCK_UNLOCK(phc->lock, flags);
+
+	return ret;
+}
+
 int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev)
 {
 	struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
@@ -1796,12 +2025,12 @@ int ena_com_admin_init(struct ena_com_dev *ena_dev,
 	dev_sts = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
 
 	if (unlikely(dev_sts == ENA_MMIO_READ_TIMEOUT)) {
-		ena_trc_err("Reg read timeout occurred\n");
+		ena_trc_err(ena_dev, "Reg read timeout occurred\n");
 		return ENA_COM_TIMER_EXPIRED;
 	}
 
 	if (!(dev_sts & ENA_REGS_DEV_STS_READY_MASK)) {
-		ena_trc_err("Device isn't ready, abort com init\n");
+		ena_trc_err(ena_dev, "Device isn't ready, abort com init\n");
 		return ENA_COM_NO_DEVICE;
 	}
 
@@ -1879,7 +2108,7 @@ int ena_com_create_io_queue(struct ena_com_dev *ena_dev,
 	int ret;
 
 	if (ctx->qid >= ENA_TOTAL_NUM_QUEUES) {
-		ena_trc_err("Qid (%d) is bigger than max num of queues (%d)\n",
+		ena_trc_err(ena_dev, "Qid (%d) is bigger than max num of queues (%d)\n",
 			    ctx->qid, ENA_TOTAL_NUM_QUEUES);
 		return ENA_COM_INVAL;
 	}
@@ -1938,7 +2167,7 @@ void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid)
 	struct ena_com_io_cq *io_cq;
 
 	if (qid >= ENA_TOTAL_NUM_QUEUES) {
-		ena_trc_err("Qid (%d) is bigger than max num of queues (%d)\n",
+		ena_trc_err(ena_dev, "Qid (%d) is bigger than max num of queues (%d)\n",
 			    qid, ENA_TOTAL_NUM_QUEUES);
 		return;
 	}
@@ -1958,6 +2187,55 @@ int ena_com_get_link_params(struct ena_com_dev *ena_dev,
 	return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG, 0);
 }
 
+static int ena_get_dev_stats(struct ena_com_dev *ena_dev,
+			     struct ena_com_stats_ctx *ctx,
+			     enum ena_admin_get_stats_type type)
+{
+	struct ena_admin_acq_get_stats_resp *get_resp = &ctx->get_resp;
+	struct ena_admin_aq_get_stats_cmd *get_cmd = &ctx->get_cmd;
+	struct ena_com_admin_queue *admin_queue;
+	int ret;
+
+	admin_queue = &ena_dev->admin_queue;
+
+	get_cmd->aq_common_descriptor.opcode = ENA_ADMIN_GET_STATS;
+	get_cmd->aq_common_descriptor.flags = 0;
+	get_cmd->type = type;
+
+	ret = ena_com_execute_admin_command(admin_queue,
+					    (struct ena_admin_aq_entry *)get_cmd,
+					    sizeof(*get_cmd),
+					    (struct ena_admin_acq_entry *)get_resp,
+					    sizeof(*get_resp));
+
+	if (unlikely(ret))
+		ena_trc_err(ena_dev, "Failed to get stats. error: %d\n", ret);
+
+	return ret;
+}
+
+static void ena_com_set_supported_customer_metrics(struct ena_com_dev *ena_dev)
+{
+	struct ena_customer_metrics *customer_metrics;
+	struct ena_com_stats_ctx ctx;
+	int ret;
+
+	customer_metrics = &ena_dev->customer_metrics;
+	if (!ena_com_get_cap(ena_dev, ENA_ADMIN_CUSTOMER_METRICS)) {
+		customer_metrics->supported_metrics = ENA_ADMIN_CUSTOMER_METRICS_MIN_SUPPORT_MASK;
+		return;
+	}
+
+	memset(&ctx, 0x0, sizeof(ctx));
+	ctx.get_cmd.requested_metrics = ENA_ADMIN_CUSTOMER_METRICS_SUPPORT_MASK;
+	ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_CUSTOMER_METRICS);
+	if (likely(ret == 0))
+		customer_metrics->supported_metrics =
+			ctx.get_resp.u.customer_metrics.reported_metrics;
+	else
+		ena_trc_err(ena_dev, "Failed to query customer metrics support. error: %d\n", ret);
+}
+
 int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
 			      struct ena_com_dev_get_features_ctx *get_feat_ctx)
 {
@@ -1973,6 +2251,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
 	       sizeof(get_resp.u.dev_attr));
 
 	ena_dev->supported_features = get_resp.u.dev_attr.supported_features;
+	ena_dev->capabilities = get_resp.u.dev_attr.capabilities;
 
 	if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
 		rc = ena_com_get_feature(ena_dev, &get_resp,
@@ -1982,7 +2261,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
 			return rc;
 
 		if (get_resp.u.max_queue_ext.version != ENA_FEATURE_MAX_QUEUE_EXT_VER)
-			return -EINVAL;
+			return ENA_COM_INVAL;
 
 		memcpy(&get_feat_ctx->max_queue_ext, &get_resp.u.max_queue_ext,
 		       sizeof(get_resp.u.max_queue_ext));
@@ -2029,7 +2308,8 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
 	else
 		return rc;
 
-	rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ, 0);
+	rc = ena_com_get_feature(ena_dev, &get_resp,
+				 ENA_ADMIN_LLQ, ENA_ADMIN_LLQ_FEATURE_VERSION_1);
 	if (!rc)
 		memcpy(&get_feat_ctx->llq, &get_resp.u.llq,
 		       sizeof(get_resp.u.llq));
@@ -2038,16 +2318,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
 	else
 		return rc;
 
-	rc = ena_com_get_feature(ena_dev, &get_resp,
-				 ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG, 0);
-	if (!rc)
-		memcpy(&get_feat_ctx->ind_table, &get_resp.u.ind_table,
-		       sizeof(get_resp.u.ind_table));
-	else if (rc == ENA_COM_UNSUPPORTED)
-		memset(&get_feat_ctx->ind_table, 0x0,
-		       sizeof(get_feat_ctx->ind_table));
-	else
-		return rc;
+	ena_com_set_supported_customer_metrics(ena_dev);
 
 	return 0;
 }
@@ -2060,10 +2331,10 @@ void ena_com_admin_q_comp_intr_handler(struct ena_com_dev *ena_dev)
 /* ena_handle_specific_aenq_event:
  * return the handler that is relevant to the specific event group
  */
-static ena_aenq_handler ena_com_get_specific_aenq_cb(struct ena_com_dev *dev,
+static ena_aenq_handler ena_com_get_specific_aenq_cb(struct ena_com_dev *ena_dev,
 						     u16 group)
 {
-	struct ena_aenq_handlers *aenq_handlers = dev->aenq.aenq_handlers;
+	struct ena_aenq_handlers *aenq_handlers = ena_dev->aenq.aenq_handlers;
 
 	if ((group < ENA_MAX_HANDLERS) && aenq_handlers->handlers[group])
 		return aenq_handlers->handlers[group];
@@ -2075,11 +2346,11 @@ static ena_aenq_handler ena_com_get_specific_aenq_cb(struct ena_com_dev *dev,
  * handles the aenq incoming events.
  * pop events from the queue and apply the specific handler
  */
-void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data)
+void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data)
 {
 	struct ena_admin_aenq_entry *aenq_e;
 	struct ena_admin_aenq_common_desc *aenq_common;
-	struct ena_com_aenq *aenq  = &dev->aenq;
+	struct ena_com_aenq *aenq  = &ena_dev->aenq;
 	u64 timestamp;
 	ena_aenq_handler handler_cb;
 	u16 masked_head, processed = 0;
@@ -2100,14 +2371,14 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data)
 
 		timestamp = (u64)aenq_common->timestamp_low |
 			((u64)aenq_common->timestamp_high << 32);
-		ENA_TOUCH(timestamp); /* In case debug is disabled */
-		ena_trc_dbg("AENQ! Group[%x] Syndrome[%x] timestamp: [%" ENA_PRIu64 "s]\n",
+
+		ena_trc_dbg(ena_dev, "AENQ! Group[%x] Syndrome[%x] timestamp: [%" ENA_PRIU64 "s]\n",
 			    aenq_common->group,
 			    aenq_common->syndrome,
 			    timestamp);
 
 		/* Handle specific event*/
-		handler_cb = ena_com_get_specific_aenq_cb(dev,
+		handler_cb = ena_com_get_specific_aenq_cb(ena_dev,
 							  aenq_common->group);
 		handler_cb(data, aenq_e); /* call the actual event handler*/
 
@@ -2132,14 +2403,15 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data)
 
 	/* write the aenq doorbell after all AENQ descriptors were read */
 	mb();
-	ENA_REG_WRITE32_RELAXED(dev->bus, (u32)aenq->head,
-				dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF);
+	ENA_REG_WRITE32_RELAXED(ena_dev->bus, (u32)aenq->head,
+				ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF);
 	mmiowb();
 }
 
 int ena_com_dev_reset(struct ena_com_dev *ena_dev,
 		      enum ena_regs_reset_reason_types reset_reason)
 {
+	u32 reset_reason_msb, reset_reason_lsb;
 	u32 stat, timeout, cap, reset_val;
 	int rc;
 
@@ -2148,26 +2420,46 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev,
 
 	if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) ||
 		     (cap == ENA_MMIO_READ_TIMEOUT))) {
-		ena_trc_err("Reg read32 timeout occurred\n");
+		ena_trc_err(ena_dev, "Reg read32 timeout occurred\n");
 		return ENA_COM_TIMER_EXPIRED;
 	}
 
 	if ((stat & ENA_REGS_DEV_STS_READY_MASK) == 0) {
-		ena_trc_err("Device isn't ready, can't reset device\n");
+		ena_trc_err(ena_dev, "Device isn't ready, can't reset device\n");
 		return ENA_COM_INVAL;
 	}
 
 	timeout = (cap & ENA_REGS_CAPS_RESET_TIMEOUT_MASK) >>
 			ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT;
 	if (timeout == 0) {
-		ena_trc_err("Invalid timeout value\n");
+		ena_trc_err(ena_dev, "Invalid timeout value\n");
 		return ENA_COM_INVAL;
 	}
 
 	/* start reset */
 	reset_val = ENA_REGS_DEV_CTL_DEV_RESET_MASK;
-	reset_val |= (reset_reason << ENA_REGS_DEV_CTL_RESET_REASON_SHIFT) &
-			ENA_REGS_DEV_CTL_RESET_REASON_MASK;
+
+	/* For backward compatibility, device will interpret
+	 * bits 24-27 as MSB, bits 28-31 as LSB
+	 */
+	reset_reason_lsb = ENA_FIELD_GET(reset_reason, ENA_RESET_REASON_LSB_MASK,
+					 ENA_RESET_REASON_LSB_OFFSET);
+
+	reset_reason_msb = ENA_FIELD_GET(reset_reason, ENA_RESET_REASON_MSB_MASK,
+					 ENA_RESET_REASON_MSB_OFFSET);
+
+	reset_val |= reset_reason_lsb << ENA_REGS_DEV_CTL_RESET_REASON_SHIFT;
+
+	if (ena_com_get_cap(ena_dev, ENA_ADMIN_EXTENDED_RESET_REASONS)) {
+		reset_val |= reset_reason_msb << ENA_REGS_DEV_CTL_RESET_REASON_EXT_SHIFT;
+	} else if (reset_reason_msb) {
+		/* In case the device does not support intended
+		 * extended reset reason fallback to generic
+		 */
+		reset_val = ENA_REGS_DEV_CTL_DEV_RESET_MASK;
+		reset_val |= (ENA_REGS_RESET_GENERIC << ENA_REGS_DEV_CTL_RESET_REASON_SHIFT) &
+			      ENA_REGS_DEV_CTL_RESET_REASON_MASK;
+	}
 	ENA_REG_WRITE32(ena_dev->bus, reset_val, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF);
 
 	/* Write again the MMIO read request address */
@@ -2176,7 +2468,7 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev,
 	rc = wait_for_reset_state(ena_dev, timeout,
 				  ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK);
 	if (rc != 0) {
-		ena_trc_err("Reset indication didn't turn on\n");
+		ena_trc_err(ena_dev, "Reset indication didn't turn on\n");
 		return rc;
 	}
 
@@ -2184,7 +2476,7 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev,
 	ENA_REG_WRITE32(ena_dev->bus, 0, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF);
 	rc = wait_for_reset_state(ena_dev, timeout, 0);
 	if (rc != 0) {
-		ena_trc_err("Reset indication didn't turn off\n");
+		ena_trc_err(ena_dev, "Reset indication didn't turn off\n");
 		return rc;
 	}
 
@@ -2199,44 +2491,42 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev,
 	return 0;
 }
 
-static int ena_get_dev_stats(struct ena_com_dev *ena_dev,
-			     struct ena_com_stats_ctx *ctx,
-			     enum ena_admin_get_stats_type type)
+int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
+			  struct ena_admin_eni_stats *stats)
 {
-	struct ena_admin_aq_get_stats_cmd *get_cmd = &ctx->get_cmd;
-	struct ena_admin_acq_get_stats_resp *get_resp = &ctx->get_resp;
-	struct ena_com_admin_queue *admin_queue;
+	struct ena_com_stats_ctx ctx;
 	int ret;
 
-	admin_queue = &ena_dev->admin_queue;
-
-	get_cmd->aq_common_descriptor.opcode = ENA_ADMIN_GET_STATS;
-	get_cmd->aq_common_descriptor.flags = 0;
-	get_cmd->type = type;
-
-	ret =  ena_com_execute_admin_command(admin_queue,
-					     (struct ena_admin_aq_entry *)get_cmd,
-					     sizeof(*get_cmd),
-					     (struct ena_admin_acq_entry *)get_resp,
-					     sizeof(*get_resp));
+	if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) {
+		ena_trc_err(ena_dev, "Capability %d isn't supported\n", ENA_ADMIN_ENI_STATS);
+		return ENA_COM_UNSUPPORTED;
+	}
 
-	if (unlikely(ret))
-		ena_trc_err("Failed to get stats. error: %d\n", ret);
+	memset(&ctx, 0x0, sizeof(ctx));
+	ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_ENI);
+	if (likely(ret == 0))
+		memcpy(stats, &ctx.get_resp.u.eni_stats,
+		       sizeof(ctx.get_resp.u.eni_stats));
 
 	return ret;
 }
 
-int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
-			  struct ena_admin_eni_stats *stats)
+int ena_com_get_ena_srd_info(struct ena_com_dev *ena_dev,
+			      struct ena_admin_ena_srd_info *info)
 {
 	struct ena_com_stats_ctx ctx;
 	int ret;
 
+	if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENA_SRD_INFO)) {
+		ena_trc_err(ena_dev, "Capability %d isn't supported\n", ENA_ADMIN_ENA_SRD_INFO);
+		return ENA_COM_UNSUPPORTED;
+	}
+
 	memset(&ctx, 0x0, sizeof(ctx));
-	ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_ENI);
+	ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_ENA_SRD);
 	if (likely(ret == 0))
-		memcpy(stats, &ctx.get_resp.u.eni_stats,
-		       sizeof(ctx.get_resp.u.eni_stats));
+		memcpy(info, &ctx.get_resp.u.ena_srd_info,
+		       sizeof(ctx.get_resp.u.ena_srd_info));
 
 	return ret;
 }
@@ -2256,7 +2546,49 @@ int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
 	return ret;
 }
 
-int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu)
+int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 len)
+{
+	struct ena_admin_aq_get_stats_cmd *get_cmd;
+	struct ena_com_stats_ctx ctx;
+	int ret;
+
+	if (unlikely(len > ena_dev->customer_metrics.buffer_len)) {
+		ena_trc_err(ena_dev, "Invalid buffer size %u. The given buffer is too big.\n", len);
+		return ENA_COM_INVAL;
+	}
+
+	if (!ena_com_get_cap(ena_dev, ENA_ADMIN_CUSTOMER_METRICS)) {
+		ena_trc_err(ena_dev, "Capability %d not supported.\n", ENA_ADMIN_CUSTOMER_METRICS);
+		return ENA_COM_UNSUPPORTED;
+	}
+
+	if (!ena_dev->customer_metrics.supported_metrics) {
+		ena_trc_err(ena_dev, "No supported customer metrics.\n");
+		return ENA_COM_UNSUPPORTED;
+	}
+
+	get_cmd = &ctx.get_cmd;
+	memset(&ctx, 0x0, sizeof(ctx));
+	ret = ena_com_mem_addr_set(ena_dev,
+		&get_cmd->u.control_buffer.address,
+		ena_dev->customer_metrics.buffer_dma_addr);
+	if (unlikely(ret)) {
+		ena_trc_err(ena_dev, "Memory address set failed.\n");
+		return ret;
+	}
+
+	get_cmd->u.control_buffer.length = ena_dev->customer_metrics.buffer_len;
+	get_cmd->requested_metrics = ena_dev->customer_metrics.supported_metrics;
+	ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_CUSTOMER_METRICS);
+	if (likely(ret == 0))
+		memcpy(buffer, ena_dev->customer_metrics.buffer_virt_addr, len);
+	else
+		ena_trc_err(ena_dev, "Failed to get customer metrics. error: %d\n", ret);
+
+	return ret;
+}
+
+int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu)
 {
 	struct ena_com_admin_queue *admin_queue;
 	struct ena_admin_set_feat_cmd cmd;
@@ -2264,7 +2596,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu)
 	int ret;
 
 	if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) {
-		ena_trc_dbg("Feature %d isn't supported\n", ENA_ADMIN_MTU);
+		ena_trc_dbg(ena_dev, "Feature %d isn't supported\n", ENA_ADMIN_MTU);
 		return ENA_COM_UNSUPPORTED;
 	}
 
@@ -2274,7 +2606,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu)
 	cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
 	cmd.aq_common_descriptor.flags = 0;
 	cmd.feat_common.feature_id = ENA_ADMIN_MTU;
-	cmd.u.mtu.mtu = (u32)mtu;
+	cmd.u.mtu.mtu = mtu;
 
 	ret = ena_com_execute_admin_command(admin_queue,
 					    (struct ena_admin_aq_entry *)&cmd,
@@ -2283,7 +2615,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu)
 					    sizeof(resp));
 
 	if (unlikely(ret))
-		ena_trc_err("Failed to set mtu %d. error: %d\n", mtu, ret);
+		ena_trc_err(ena_dev, "Failed to set mtu %d. error: %d\n", mtu, ret);
 
 	return ret;
 }
@@ -2297,7 +2629,7 @@ int ena_com_get_offload_settings(struct ena_com_dev *ena_dev,
 	ret = ena_com_get_feature(ena_dev, &resp,
 				  ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0);
 	if (unlikely(ret)) {
-		ena_trc_err("Failed to get offload capabilities %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to get offload capabilities %d\n", ret);
 		return ret;
 	}
 
@@ -2317,7 +2649,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
 
 	if (!ena_com_check_supported_feature_id(ena_dev,
 						ENA_ADMIN_RSS_HASH_FUNCTION)) {
-		ena_trc_dbg("Feature %d isn't supported\n",
+		ena_trc_dbg(ena_dev, "Feature %d isn't supported\n",
 			    ENA_ADMIN_RSS_HASH_FUNCTION);
 		return ENA_COM_UNSUPPORTED;
 	}
@@ -2329,7 +2661,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
 		return ret;
 
 	if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) {
-		ena_trc_err("Func hash %d isn't supported by device, abort\n",
+		ena_trc_err(ena_dev, "Func hash %d isn't supported by device, abort\n",
 			    rss->hash_func);
 		return ENA_COM_UNSUPPORTED;
 	}
@@ -2347,7 +2679,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
 				   &cmd.control_buffer.address,
 				   rss->hash_key_dma_addr);
 	if (unlikely(ret)) {
-		ena_trc_err("memory address set failed\n");
+		ena_trc_err(ena_dev, "Memory address set failed\n");
 		return ret;
 	}
 
@@ -2359,7 +2691,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
 					    (struct ena_admin_acq_entry *)&resp,
 					    sizeof(resp));
 	if (unlikely(ret)) {
-		ena_trc_err("Failed to set hash function %d. error: %d\n",
+		ena_trc_err(ena_dev, "Failed to set hash function %d. error: %d\n",
 			    rss->hash_func, ret);
 		return ENA_COM_INVAL;
 	}
@@ -2391,31 +2723,21 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev,
 		return rc;
 
 	if (!(BIT(func) & get_resp.u.flow_hash_func.supported_func)) {
-		ena_trc_err("Flow hash function %d isn't supported\n", func);
+		ena_trc_err(ena_dev, "Flow hash function %d isn't supported\n", func);
 		return ENA_COM_UNSUPPORTED;
 	}
 
-	switch (func) {
-	case ENA_ADMIN_TOEPLITZ:
-		if (key) {
-			if (key_len != sizeof(hash_key->key)) {
-				ena_trc_err("key len (%hu) doesn't equal the supported size (%zu)\n",
-					     key_len, sizeof(hash_key->key));
-				return ENA_COM_INVAL;
-			}
-			memcpy(hash_key->key, key, key_len);
-			rss->hash_init_val = init_val;
-			hash_key->key_parts = key_len / sizeof(hash_key->key[0]);
+	if (func == ENA_ADMIN_TOEPLITZ && key) {
+		if (key_len != sizeof(hash_key->key)) {
+			ena_trc_err(ena_dev, "key len (%u) doesn't equal the supported size (%zu)\n",
+				    key_len, sizeof(hash_key->key));
+			return ENA_COM_INVAL;
 		}
-		break;
-	case ENA_ADMIN_CRC32:
-		rss->hash_init_val = init_val;
-		break;
-	default:
-		ena_trc_err("Invalid hash function (%d)\n", func);
-		return ENA_COM_INVAL;
+		memcpy(hash_key->key, key, key_len);
+		hash_key->key_parts = key_len / sizeof(hash_key->key[0]);
 	}
 
+	rss->hash_init_val = init_val;
 	old_func = rss->hash_func;
 	rss->hash_func = func;
 	rc = ena_com_set_hash_function(ena_dev);
@@ -2498,7 +2820,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev)
 
 	if (!ena_com_check_supported_feature_id(ena_dev,
 						ENA_ADMIN_RSS_HASH_INPUT)) {
-		ena_trc_dbg("Feature %d isn't supported\n",
+		ena_trc_dbg(ena_dev, "Feature %d isn't supported\n",
 			    ENA_ADMIN_RSS_HASH_INPUT);
 		return ENA_COM_UNSUPPORTED;
 	}
@@ -2517,7 +2839,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev)
 				   &cmd.control_buffer.address,
 				   rss->hash_ctrl_dma_addr);
 	if (unlikely(ret)) {
-		ena_trc_err("memory address set failed\n");
+		ena_trc_err(ena_dev, "Memory address set failed\n");
 		return ret;
 	}
 	cmd.control_buffer.length = sizeof(*hash_ctrl);
@@ -2528,7 +2850,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev)
 					    (struct ena_admin_acq_entry *)&resp,
 					    sizeof(resp));
 	if (unlikely(ret))
-		ena_trc_err("Failed to set hash input. error: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to set hash input. error: %d\n", ret);
 
 	return ret;
 }
@@ -2578,7 +2900,7 @@ int ena_com_set_default_hash_ctrl(struct ena_com_dev *ena_dev)
 		available_fields = hash_ctrl->selected_fields[i].fields &
 				hash_ctrl->supported_fields[i].fields;
 		if (available_fields != hash_ctrl->selected_fields[i].fields) {
-			ena_trc_err("hash control doesn't support all the desire configuration. proto %x supported %x selected %x\n",
+			ena_trc_err(ena_dev, "Hash control doesn't support all the desire configuration. proto %x supported %x selected %x\n",
 				    i, hash_ctrl->supported_fields[i].fields,
 				    hash_ctrl->selected_fields[i].fields);
 			return ENA_COM_UNSUPPORTED;
@@ -2604,7 +2926,7 @@ int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev,
 	int rc;
 
 	if (proto >= ENA_ADMIN_RSS_PROTO_NUM) {
-		ena_trc_err("Invalid proto num (%u)\n", proto);
+		ena_trc_err(ena_dev, "Invalid proto num (%u)\n", proto);
 		return ENA_COM_INVAL;
 	}
 
@@ -2616,7 +2938,7 @@ int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev,
 	/* Make sure all the fields are supported */
 	supported_fields = hash_ctrl->supported_fields[proto].fields;
 	if ((hash_fields & supported_fields) != hash_fields) {
-		ena_trc_err("proto %d doesn't support the required fields %x. supports only: %x\n",
+		ena_trc_err(ena_dev, "Proto %d doesn't support the required fields %x. supports only: %x\n",
 			    proto, hash_fields, supported_fields);
 	}
 
@@ -2657,14 +2979,14 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev)
 
 	if (!ena_com_check_supported_feature_id(ena_dev,
 						ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) {
-		ena_trc_dbg("Feature %d isn't supported\n",
+		ena_trc_dbg(ena_dev, "Feature %d isn't supported\n",
 			    ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG);
 		return ENA_COM_UNSUPPORTED;
 	}
 
 	ret = ena_com_ind_tbl_convert_to_device(ena_dev);
 	if (ret) {
-		ena_trc_err("Failed to convert host indirection table to device table\n");
+		ena_trc_err(ena_dev, "Failed to convert host indirection table to device table\n");
 		return ret;
 	}
 
@@ -2681,11 +3003,11 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev)
 				   &cmd.control_buffer.address,
 				   rss->rss_ind_tbl_dma_addr);
 	if (unlikely(ret)) {
-		ena_trc_err("memory address set failed\n");
+		ena_trc_err(ena_dev, "Memory address set failed\n");
 		return ret;
 	}
 
-	cmd.control_buffer.length = (u32)(1ULL << rss->tbl_log_size) *
+	cmd.control_buffer.length = (1ULL << rss->tbl_log_size) *
 		sizeof(struct ena_admin_rss_ind_table_entry);
 
 	ret = ena_com_execute_admin_command(admin_queue,
@@ -2695,7 +3017,7 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev)
 					    sizeof(resp));
 
 	if (unlikely(ret))
-		ena_trc_err("Failed to set indirect table. error: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to set indirect table. error: %d\n", ret);
 
 	return ret;
 }
@@ -2707,7 +3029,7 @@ int ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl)
 	u32 tbl_size;
 	int i, rc;
 
-	tbl_size = (u32)(1ULL << rss->tbl_log_size) *
+	tbl_size = (1ULL << rss->tbl_log_size) *
 		sizeof(struct ena_admin_rss_ind_table_entry);
 
 	rc = ena_com_get_feature_ex(ena_dev, &get_resp,
@@ -2809,6 +3131,23 @@ int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev,
 	return 0;
 }
 
+int ena_com_allocate_customer_metrics_buffer(struct ena_com_dev *ena_dev)
+{
+	struct ena_customer_metrics *customer_metrics = &ena_dev->customer_metrics;
+
+	ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev,
+			       customer_metrics->buffer_len,
+			       customer_metrics->buffer_virt_addr,
+			       customer_metrics->buffer_dma_addr,
+			       customer_metrics->buffer_dma_handle);
+	if (unlikely(customer_metrics->buffer_virt_addr == NULL))
+		return ENA_COM_NO_MEM;
+
+	customer_metrics->buffer_len = ENA_CUSTOMER_METRICS_BUFFER_SIZE;
+
+	return 0;
+}
+
 void ena_com_delete_host_info(struct ena_com_dev *ena_dev)
 {
 	struct ena_host_attribute *host_attr = &ena_dev->host_attr;
@@ -2837,6 +3176,21 @@ void ena_com_delete_debug_area(struct ena_com_dev *ena_dev)
 	}
 }
 
+void ena_com_delete_customer_metrics_buffer(struct ena_com_dev *ena_dev)
+{
+	struct ena_customer_metrics *customer_metrics = &ena_dev->customer_metrics;
+
+	if (customer_metrics->buffer_virt_addr) {
+		ENA_MEM_FREE_COHERENT(ena_dev->dmadev,
+				      customer_metrics->buffer_len,
+				      customer_metrics->buffer_virt_addr,
+				      customer_metrics->buffer_dma_addr,
+				      customer_metrics->buffer_dma_handle);
+		customer_metrics->buffer_virt_addr = NULL;
+		customer_metrics->buffer_len = 0;
+	}
+}
+
 int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
 {
 	struct ena_host_attribute *host_attr = &ena_dev->host_attr;
@@ -2860,7 +3214,7 @@ int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
 				   &cmd.u.host_attr.debug_ba,
 				   host_attr->debug_area_dma_addr);
 	if (unlikely(ret)) {
-		ena_trc_err("memory address set failed\n");
+		ena_trc_err(ena_dev, "Memory address set failed\n");
 		return ret;
 	}
 
@@ -2868,7 +3222,7 @@ int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
 				   &cmd.u.host_attr.os_info_ba,
 				   host_attr->host_info_dma_addr);
 	if (unlikely(ret)) {
-		ena_trc_err("memory address set failed\n");
+		ena_trc_err(ena_dev, "Memory address set failed\n");
 		return ret;
 	}
 
@@ -2881,7 +3235,7 @@ int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
 					    sizeof(resp));
 
 	if (unlikely(ret))
-		ena_trc_err("Failed to set host attributes: %d\n", ret);
+		ena_trc_err(ena_dev, "Failed to set host attributes: %d\n", ret);
 
 	return ret;
 }
@@ -2893,12 +3247,13 @@ bool ena_com_interrupt_moderation_supported(struct ena_com_dev *ena_dev)
 						  ENA_ADMIN_INTERRUPT_MODERATION);
 }
 
-static int ena_com_update_nonadaptive_moderation_interval(u32 coalesce_usecs,
+static int ena_com_update_nonadaptive_moderation_interval(struct ena_com_dev *ena_dev,
+							  u32 coalesce_usecs,
 							  u32 intr_delay_resolution,
 							  u32 *intr_moder_interval)
 {
 	if (!intr_delay_resolution) {
-		ena_trc_err("Illegal interrupt delay granularity value\n");
+		ena_trc_err(ena_dev, "Illegal interrupt delay granularity value\n");
 		return ENA_COM_FAULT;
 	}
 
@@ -2907,11 +3262,11 @@ static int ena_com_update_nonadaptive_moderation_interval(u32 coalesce_usecs,
 	return 0;
 }
 
-
 int ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev,
 						      u32 tx_coalesce_usecs)
 {
-	return ena_com_update_nonadaptive_moderation_interval(tx_coalesce_usecs,
+	return ena_com_update_nonadaptive_moderation_interval(ena_dev,
+							      tx_coalesce_usecs,
 							      ena_dev->intr_delay_resolution,
 							      &ena_dev->intr_moder_tx_interval);
 }
@@ -2919,7 +3274,8 @@ int ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_de
 int ena_com_update_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev,
 						      u32 rx_coalesce_usecs)
 {
-	return ena_com_update_nonadaptive_moderation_interval(rx_coalesce_usecs,
+	return ena_com_update_nonadaptive_moderation_interval(ena_dev,
+							      rx_coalesce_usecs,
 							      ena_dev->intr_delay_resolution,
 							      &ena_dev->intr_moder_rx_interval);
 }
@@ -2935,12 +3291,12 @@ int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev)
 
 	if (rc) {
 		if (rc == ENA_COM_UNSUPPORTED) {
-			ena_trc_dbg("Feature %d isn't supported\n",
+			ena_trc_dbg(ena_dev, "Feature %d isn't supported\n",
 				    ENA_ADMIN_INTERRUPT_MODERATION);
 			rc = 0;
 		} else {
-			ena_trc_err("Failed to get interrupt moderation admin cmd. rc: %d\n",
-				    rc);
+			ena_trc_err(ena_dev,
+				    "Failed to get interrupt moderation admin cmd. rc: %d\n", rc);
 		}
 
 		/* no moderation supported, disable adaptive support */
@@ -2988,8 +3344,8 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
 		(llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc));
 
 	if (unlikely(ena_dev->tx_max_header_size == 0)) {
-		ena_trc_err("the size of the LLQ entry is smaller than needed\n");
-		return -EINVAL;
+		ena_trc_err(ena_dev, "The size of the LLQ entry is smaller than needed\n");
+		return ENA_COM_INVAL;
 	}
 
 	ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV;
diff --git a/drivers/net/ena/base/ena_com.h b/drivers/net/ena/base/ena_com.h
index 64d8f247cb..cd054595d7 100644
--- a/drivers/net/ena/base/ena_com.h
+++ b/drivers/net/ena/base/ena_com.h
@@ -23,19 +23,27 @@
 #define ADMIN_CQ_SIZE(depth)	((depth) * sizeof(struct ena_admin_acq_entry))
 #define ADMIN_AENQ_SIZE(depth)	((depth) * sizeof(struct ena_admin_aenq_entry))
 
-#define ENA_CDESC_RING_SIZE_ALIGNMENT	(1 << 12) /* 4K */
+/* Macros used to extract LSB/MSB from the
+ * enums defining the reset reasons
+ */
+#define ENA_RESET_REASON_LSB_OFFSET			    0
+#define ENA_RESET_REASON_LSB_MASK			    0xf
+#define ENA_RESET_REASON_MSB_OFFSET			    4
+#define ENA_RESET_REASON_MSB_MASK			    0xf0
+
+#define ENA_CUSTOMER_METRICS_BUFFER_SIZE 512
 
 /*****************************************************************************/
 /*****************************************************************************/
 /* ENA adaptive interrupt moderation settings */
 
 #define ENA_INTR_INITIAL_TX_INTERVAL_USECS ENA_INTR_INITIAL_TX_INTERVAL_USECS_PLAT
-#define ENA_INTR_INITIAL_RX_INTERVAL_USECS 0
+#define ENA_INTR_INITIAL_RX_INTERVAL_USECS ENA_INTR_INITIAL_RX_INTERVAL_USECS_PLAT
 #define ENA_DEFAULT_INTR_DELAY_RESOLUTION 1
 
 #define ENA_HASH_KEY_SIZE 40
 
-#define ENA_HW_HINTS_NO_TIMEOUT 0xFFFF
+#define ENA_HW_HINTS_NO_TIMEOUT	0xFFFF
 
 #define ENA_FEATURE_MAX_QUEUE_EXT_VER 1
 
@@ -94,8 +102,6 @@ struct ena_com_io_cq {
 	/* Interrupt unmask register */
 	u32 __iomem *unmask_reg;
 
-	/* The completion queue head doorbell register */
-	u32 __iomem *cq_head_db_reg;
 
 	/* numa configuration register (for TPH) */
 	u32 __iomem *numa_node_cfg_reg;
@@ -103,13 +109,13 @@ struct ena_com_io_cq {
 	/* The value to write to the above register to unmask
 	 * the interrupt of this queue
 	 */
-	u32 msix_vector;
+	u32 msix_vector ____cacheline_aligned;
 
 	enum queue_direction direction;
 
 	/* holds the number of cdesc of the current packet */
 	u16 cur_rx_pkt_cdesc_count;
-	/* save the firt cdesc idx of the current packet */
+	/* save the first cdesc idx of the current packet */
 	u16 cur_rx_pkt_cdesc_start_idx;
 
 	u16 q_depth;
@@ -119,7 +125,6 @@ struct ena_com_io_cq {
 	/* Device queue index */
 	u16 idx;
 	u16 head;
-	u16 last_head_update;
 	u8 phase;
 	u8 cdesc_entry_size_in_bytes;
 
@@ -144,7 +149,6 @@ struct ena_com_io_sq {
 	void *bus;
 
 	u32 __iomem *db_addr;
-	u8 __iomem *header_addr;
 
 	enum queue_direction direction;
 	enum ena_admin_placement_policy_type mem_queue_type;
@@ -201,6 +205,13 @@ struct ena_com_stats_admin {
 	u64 no_completion;
 };
 
+struct ena_com_stats_phc {
+	u64 phc_cnt;
+	u64 phc_exp;
+	u64 phc_skp;
+	u64 phc_err;
+};
+
 struct ena_com_admin_queue {
 	void *q_dmadev;
 	void *bus;
@@ -255,6 +266,46 @@ struct ena_com_mmio_read {
 	ena_spinlock_t lock;
 };
 
+/* PTP hardware clock (PHC) MMIO read data info */
+struct ena_com_phc_info {
+	/* Internal PHC statistics */
+	struct ena_com_stats_phc stats;
+
+	/* PHC shared memory - virtual address */
+	struct ena_admin_phc_resp *virt_addr;
+
+	/* Spin lock to ensure a single outstanding PHC read */
+	ena_spinlock_t lock;
+
+	/* PHC doorbell address as an offset to PCIe MMIO REG BAR */
+	u32 doorbell_offset;
+
+	/* Shared memory read expire timeout (usec)
+	 * Max time for valid PHC retrieval, passing this threshold will fail the get time request
+	 * and block new PHC requests for block_timeout_usec in order to prevent floods on busy
+	 * device
+	 */
+	u32 expire_timeout_usec;
+
+	/* Shared memory read abort timeout (usec)
+	 * PHC requests block period, blocking starts once PHC request expired in order to prevent
+	 * floods on busy device, any PHC requests during block period will be skipped
+	 */
+	u32 block_timeout_usec;
+
+	/* Request id sent to the device */
+	u16 req_id;
+
+	/* True if PHC is active in the device */
+	bool active;
+
+	/* PHC shared memory - memory handle */
+	ena_mem_handle_t mem_handle;
+
+	/* PHC shared memory - physical address */
+	dma_addr_t phys_addr;
+};
+
 struct ena_rss {
 	/* Indirect table */
 	u16 *host_rss_ind_tbl;
@@ -277,6 +328,17 @@ struct ena_rss {
 
 };
 
+struct ena_customer_metrics {
+	/* in correlation with ENA_ADMIN_CUSTOMER_METRICS_SUPPORT_MASK
+	 * and ena_admin_customer_metrics_id
+	 */
+	uint64_t supported_metrics;
+	dma_addr_t buffer_dma_addr;
+	void *buffer_virt_addr;
+	ena_mem_handle_t buffer_dma_handle;
+	u32 buffer_len;
+};
+
 struct ena_host_attribute {
 	/* Debug area */
 	u8 *debug_area_virt_addr;
@@ -300,16 +362,21 @@ struct ena_com_dev {
 	void __iomem *mem_bar;
 	void *dmadev;
 	void *bus;
+	ena_netdev *net_device;
 
 	enum ena_admin_placement_policy_type tx_mem_queue_type;
 	u32 tx_max_header_size;
 	u16 stats_func; /* Selected function for extended statistic dump */
 	u16 stats_queue; /* Selected queue for extended statistic dump */
 
+	u32 ena_min_poll_delay_us;
+
 	struct ena_com_mmio_read mmio_read;
+	struct ena_com_phc_info phc;
 
 	struct ena_rss rss;
 	u32 supported_features;
+	u32 capabilities;
 	u32 dma_addr_bits;
 
 	struct ena_host_attribute host_attr;
@@ -326,7 +393,7 @@ struct ena_com_dev {
 
 	struct ena_com_llq_info llq_info;
 
-	u32 ena_min_poll_delay_us;
+	struct ena_customer_metrics customer_metrics;
 };
 
 struct ena_com_dev_get_features_ctx {
@@ -337,7 +404,6 @@ struct ena_com_dev_get_features_ctx {
 	struct ena_admin_feature_offload_desc offload;
 	struct ena_admin_ena_hw_hints hw_hints;
 	struct ena_admin_feature_llq_desc llq;
-	struct ena_admin_feature_rss_ind_table ind_table;
 };
 
 struct ena_com_create_io_ctx {
@@ -375,6 +441,40 @@ extern "C" {
  */
 int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev);
 
+/* ena_com_phc_init - Allocate and initialize PHC feature
+ * @ena_dev: ENA communication layer struct
+ * @note: This method assumes PHC is supported by the device
+ * @return - 0 on success, negative value on failure
+ */
+int ena_com_phc_init(struct ena_com_dev *ena_dev);
+
+/* ena_com_phc_supported - Return if PHC feature is supported by the device
+ * @ena_dev: ENA communication layer struct
+ * @note: This method must be called after getting supported features
+ * @return - supported or not
+ */
+bool ena_com_phc_supported(struct ena_com_dev *ena_dev);
+
+/* ena_com_phc_config - Configure PHC feature
+ * @ena_dev: ENA communication layer struct
+ * Configure PHC feature in driver and device
+ * @note: This method assumes PHC is supported by the device
+ * @return - 0 on success, negative value on failure
+ */
+int ena_com_phc_config(struct ena_com_dev *ena_dev);
+
+/* ena_com_phc_destroy - Destroy PHC feature
+ * @ena_dev: ENA communication layer struct
+ */
+void ena_com_phc_destroy(struct ena_com_dev *ena_dev);
+
+/* ena_com_phc_get - Retrieve PHC timestamp
+ * @ena_dev: ENA communication layer struct
+ * @timestamp: Retrieve PHC timestamp
+ * @return - 0 on success, negative value on failure
+ */
+int ena_com_phc_get(struct ena_com_dev *ena_dev, u64 *timestamp);
+
 /* ena_com_set_mmio_read_mode - Enable/disable the indirect mmio reg read mechanism
  * @ena_dev: ENA communication layer struct
  * @readless_supported: readless mode (enable/disable)
@@ -522,7 +622,7 @@ void ena_com_admin_q_comp_intr_handler(struct ena_com_dev *ena_dev);
  * This method goes over the async event notification queue and calls the proper
  * aenq handler.
  */
-void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data);
+void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data);
 
 /* ena_com_abort_admin_commands - Abort all the outstanding admin commands.
  * @ena_dev: ENA communication layer struct
@@ -611,13 +711,31 @@ int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
 int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
 			  struct ena_admin_eni_stats *stats);
 
+/* ena_com_get_ena_srd_info - Get ENA SRD network interface statistics
+ * @ena_dev: ENA communication layer struct
+ * @info: ena srd stats and flags
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_ena_srd_info(struct ena_com_dev *ena_dev,
+			     struct ena_admin_ena_srd_info *info);
+
+/* ena_com_get_customer_metrics - Get customer metrics for network interface
+ * @ena_dev: ENA communication layer struct
+ * @buffer: buffer for returned customer metrics
+ * @len: size of the buffer
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 len);
+
 /* ena_com_set_dev_mtu - Configure the device mtu.
  * @ena_dev: ENA communication layer struct
  * @mtu: mtu value
  *
  * @return: 0 on Success and negative value otherwise.
  */
-int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu);
+int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu);
 
 /* ena_com_get_offload_settings - Retrieve the device offloads capabilities
  * @ena_dev: ENA communication layer struct
@@ -821,6 +939,13 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev);
 int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev,
 				u32 debug_area_size);
 
+/* ena_com_allocate_customer_metrics_buffer - Allocate customer metrics resources.
+ * @ena_dev: ENA communication layer struct
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_allocate_customer_metrics_buffer(struct ena_com_dev *ena_dev);
+
 /* ena_com_delete_debug_area - Free the debug area resources.
  * @ena_dev: ENA communication layer struct
  *
@@ -835,6 +960,13 @@ void ena_com_delete_debug_area(struct ena_com_dev *ena_dev);
  */
 void ena_com_delete_host_info(struct ena_com_dev *ena_dev);
 
+/* ena_com_delete_customer_metrics_buffer - Free the customer metrics resources.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Free the allocated customer metrics area.
+ */
+void ena_com_delete_customer_metrics_buffer(struct ena_com_dev *ena_dev);
+
 /* ena_com_set_host_attributes - Update the device with the host
  * attributes (debug area and host info) base address.
  * @ena_dev: ENA communication layer struct
@@ -944,6 +1076,26 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
 			    struct ena_admin_feature_llq_desc *llq_features,
 			    struct ena_llq_configurations *llq_default_config);
 
+/* ena_com_io_sq_to_ena_dev - Extract ena_com_dev using contained field io_sq.
+ * @io_sq: IO submit queue struct
+ *
+ * @return - ena_com_dev struct extracted from io_sq
+ */
+static inline struct ena_com_dev *ena_com_io_sq_to_ena_dev(struct ena_com_io_sq *io_sq)
+{
+	return container_of(io_sq, struct ena_com_dev, io_sq_queues[io_sq->qid]);
+}
+
+/* ena_com_io_cq_to_ena_dev - Extract ena_com_dev using contained field io_cq.
+ * @io_sq: IO submit queue struct
+ *
+ * @return - ena_com_dev struct extracted from io_sq
+ */
+static inline struct ena_com_dev *ena_com_io_cq_to_ena_dev(struct ena_com_io_cq *io_cq)
+{
+	return container_of(io_cq, struct ena_com_dev, io_cq_queues[io_cq->qid]);
+}
+
 static inline bool ena_com_get_adaptive_moderation_enabled(struct ena_com_dev *ena_dev)
 {
 	return ena_dev->adaptive_coalescing;
@@ -959,18 +1111,55 @@ static inline void ena_com_disable_adaptive_moderation(struct ena_com_dev *ena_d
 	ena_dev->adaptive_coalescing = false;
 }
 
+/* ena_com_get_cap - query whether device supports a capability.
+ * @ena_dev: ENA communication layer struct
+ * @cap_id: enum value representing the capability
+ *
+ * @return - true if capability is supported or false otherwise
+ */
+static inline bool ena_com_get_cap(struct ena_com_dev *ena_dev,
+				   enum ena_admin_aq_caps_id cap_id)
+{
+	return !!(ena_dev->capabilities & BIT(cap_id));
+}
+
+/* ena_com_get_customer_metric_support - query whether device supports a given customer metric.
+ * @ena_dev: ENA communication layer struct
+ * @metric_id: enum value representing the customer metric
+ *
+ * @return - true if customer metric is supported or false otherwise
+ */
+static inline bool ena_com_get_customer_metric_support(struct ena_com_dev *ena_dev,
+						       enum ena_admin_customer_metrics_id metric_id)
+{
+	return !!(ena_dev->customer_metrics.supported_metrics & BIT64(metric_id));
+}
+
+/* ena_com_get_customer_metric_count - return the number of supported customer metrics.
+ * @ena_dev: ENA communication layer struct
+ *
+ * @return - the number of supported customer metrics
+ */
+static inline int ena_com_get_customer_metric_count(struct ena_com_dev *ena_dev)
+{
+	return ENA_BITS_PER_U64(ena_dev->customer_metrics.supported_metrics);
+}
+
 /* ena_com_update_intr_reg - Prepare interrupt register
  * @intr_reg: interrupt register to update.
  * @rx_delay_interval: Rx interval in usecs
  * @tx_delay_interval: Tx interval in usecs
  * @unmask: unmask enable/disable
+ * @no_moderation_update: 0 - Indicates that any of the TX/RX intervals was
+ *                        updated, 1 - otherwise
  *
  * Prepare interrupt update register with the supplied parameters.
  */
 static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg,
 					   u32 rx_delay_interval,
 					   u32 tx_delay_interval,
-					   bool unmask)
+					   bool unmask,
+					   bool no_moderation_update)
 {
 	intr_reg->intr_control = 0;
 	intr_reg->intr_control |= rx_delay_interval &
@@ -982,6 +1171,10 @@ static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg,
 
 	if (unmask)
 		intr_reg->intr_control |= ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK;
+
+	intr_reg->intr_control |=
+		(((u32)no_moderation_update) << ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_SHIFT) &
+			ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_MASK;
 }
 
 static inline u8 *ena_com_get_next_bounce_buffer(struct ena_com_io_bounce_buffer_control *bounce_buf_ctrl)
diff --git a/drivers/net/ena/base/ena_defs/ena_admin_defs.h b/drivers/net/ena/base/ena_defs/ena_admin_defs.h
index 40c2db717c..fa43e22918 100644
--- a/drivers/net/ena/base/ena_defs/ena_admin_defs.h
+++ b/drivers/net/ena/base/ena_defs/ena_admin_defs.h
@@ -5,8 +5,26 @@
 #ifndef _ENA_ADMIN_H_
 #define _ENA_ADMIN_H_
 
+#define ENA_ADMIN_EXTRA_PROPERTIES_STRING_LEN 32
+#define ENA_ADMIN_EXTRA_PROPERTIES_COUNT     32
+
 #define ENA_ADMIN_RSS_KEY_PARTS              10
 
+#define ENA_ADMIN_CUSTOMER_METRICS_SUPPORT_MASK 0x3F
+#define ENA_ADMIN_CUSTOMER_METRICS_MIN_SUPPORT_MASK 0x1F
+
+ /* customer metrics - in correlation with
+  * ENA_ADMIN_CUSTOMER_METRICS_SUPPORT_MASK
+  */
+enum ena_admin_customer_metrics_id {
+	ENA_ADMIN_BW_IN_ALLOWANCE_EXCEEDED         = 0,
+	ENA_ADMIN_BW_OUT_ALLOWANCE_EXCEEDED        = 1,
+	ENA_ADMIN_PPS_ALLOWANCE_EXCEEDED           = 2,
+	ENA_ADMIN_CONNTRACK_ALLOWANCE_EXCEEDED     = 3,
+	ENA_ADMIN_LINKLOCAL_ALLOWANCE_EXCEEDED     = 4,
+	ENA_ADMIN_CONNTRACK_ALLOWANCE_AVAILABLE    = 5,
+};
+
 enum ena_admin_aq_opcode {
 	ENA_ADMIN_CREATE_SQ                         = 1,
 	ENA_ADMIN_DESTROY_SQ                        = 2,
@@ -47,9 +65,27 @@ enum ena_admin_aq_feature_id {
 	ENA_ADMIN_AENQ_CONFIG                       = 26,
 	ENA_ADMIN_LINK_CONFIG                       = 27,
 	ENA_ADMIN_HOST_ATTR_CONFIG                  = 28,
+	ENA_ADMIN_PHC_CONFIG                        = 29,
 	ENA_ADMIN_FEATURES_OPCODE_NUM               = 32,
 };
 
+/* feature version for the set/get ENA_ADMIN_LLQ feature admin commands */
+enum ena_admin_llq_feature_version {
+	/* legacy base version in older drivers */
+	ENA_ADMIN_LLQ_FEATURE_VERSION_0_LEGACY      = 0,
+	/* support entry_size recommendation by device */
+	ENA_ADMIN_LLQ_FEATURE_VERSION_1             = 1,
+};
+
+/* device capabilities */
+enum ena_admin_aq_caps_id {
+	ENA_ADMIN_ENI_STATS                         = 0,
+	/* ENA SRD customer metrics */
+	ENA_ADMIN_ENA_SRD_INFO                      = 1,
+	ENA_ADMIN_CUSTOMER_METRICS                  = 2,
+	ENA_ADMIN_EXTENDED_RESET_REASONS	    = 3,
+};
+
 enum ena_admin_placement_policy_type {
 	/* descriptors and headers are in host memory */
 	ENA_ADMIN_PLACEMENT_POLICY_HOST             = 1,
@@ -96,6 +132,10 @@ enum ena_admin_get_stats_type {
 	ENA_ADMIN_GET_STATS_TYPE_EXTENDED           = 1,
 	/* extra HW stats for specific network interface */
 	ENA_ADMIN_GET_STATS_TYPE_ENI                = 2,
+	/* extra HW stats for ENA SRD */
+	ENA_ADMIN_GET_STATS_TYPE_ENA_SRD            = 3,
+	ENA_ADMIN_GET_STATS_TYPE_CUSTOMER_METRICS   = 4,
+
 };
 
 enum ena_admin_get_stats_scope {
@@ -103,6 +143,20 @@ enum ena_admin_get_stats_scope {
 	ENA_ADMIN_ETH_TRAFFIC                       = 1,
 };
 
+enum ena_admin_get_phc_type {
+	ENA_ADMIN_PHC_TYPE_READLESS                 = 0,
+};
+
+/* ENA SRD configuration for ENI */
+enum ena_admin_ena_srd_flags {
+	/* Feature enabled */
+	ENA_ADMIN_ENA_SRD_ENABLED                   = BIT(0),
+	/* UDP support enabled */
+	ENA_ADMIN_ENA_SRD_UDP_ENABLED               = BIT(1),
+	/* Bypass Rx UDP ordering */
+	ENA_ADMIN_ENA_SRD_UDP_ORDERING_BYPASS_ENABLED = BIT(2),
+};
+
 struct ena_admin_aq_common_desc {
 	/* 11:0 : command_id
 	 * 15:12 : reserved12
@@ -360,6 +414,9 @@ struct ena_admin_aq_get_stats_cmd {
 	 * stats of other device
 	 */
 	uint16_t device_id;
+
+	/* a bitmap representing the requested metric values */
+	uint64_t requested_metrics;
 };
 
 /* Basic Statistics Command. */
@@ -387,6 +444,10 @@ struct ena_admin_basic_stats {
 	uint32_t tx_drops_low;
 
 	uint32_t tx_drops_high;
+
+	uint32_t rx_overruns_low;
+
+	uint32_t rx_overruns_high;
 };
 
 /* ENI Statistics Command. */
@@ -416,6 +477,40 @@ struct ena_admin_eni_stats {
 	uint64_t linklocal_allowance_exceeded;
 };
 
+struct ena_admin_ena_srd_stats {
+	/* Number of packets transmitted over ENA SRD */
+	uint64_t ena_srd_tx_pkts;
+
+	/* Number of packets transmitted or could have been
+	 * transmitted over ENA SRD
+	 */
+	uint64_t ena_srd_eligible_tx_pkts;
+
+	/* Number of packets received over ENA SRD */
+	uint64_t ena_srd_rx_pkts;
+
+	/* Percentage of the ENA SRD resources that is in use */
+	uint64_t ena_srd_resource_utilization;
+};
+
+/* ENA SRD Statistics Command */
+struct ena_admin_ena_srd_info {
+	/* ENA SRD configuration bitmap. See ena_admin_ena_srd_flags for
+	 * details
+	 */
+	uint64_t flags;
+
+	struct ena_admin_ena_srd_stats ena_srd_stats;
+};
+
+/* Customer Metrics Command. */
+struct ena_admin_customer_metrics {
+	/* A bitmap representing the reported customer metrics according to
+	 * the order they are reported
+	 */
+	uint64_t reported_metrics;
+};
+
 struct ena_admin_acq_get_stats_resp {
 	struct ena_admin_acq_common_desc acq_common_desc;
 
@@ -425,6 +520,10 @@ struct ena_admin_acq_get_stats_resp {
 		struct ena_admin_basic_stats basic_stats;
 
 		struct ena_admin_eni_stats eni_stats;
+
+		struct ena_admin_ena_srd_info ena_srd_info;
+
+		struct ena_admin_customer_metrics customer_metrics;
 	} u;
 };
 
@@ -457,7 +556,10 @@ struct ena_admin_device_attr_feature_desc {
 	 */
 	uint32_t supported_features;
 
-	uint32_t reserved3;
+	/* bitmap of ena_admin_aq_caps_id, which represents device
+	 * capabilities.
+	 */
+	uint32_t capabilities;
 
 	/* Indicates how many bits are used physical address access. */
 	uint32_t phys_addr_width;
@@ -578,8 +680,17 @@ struct ena_admin_feature_llq_desc {
 	/* the stride control the driver selected to use */
 	uint16_t descriptors_stride_ctrl_enabled;
 
+	/* feature version of device resp to either GET/SET commands. */
+	uint8_t feature_version;
+
+	/* llq entry size recommended by the device,
+	 * values correlated to enum ena_admin_llq_ring_entry_size.
+	 * used only for GET command.
+	 */
+	uint8_t entry_size_recommended;
+
 	/* reserved */
-	uint32_t reserved1;
+	uint8_t reserved1[2];
 
 	/* accelerated low latency queues requirement. driver needs to
 	 * support those requirements in order to use accelerated llq
@@ -822,7 +933,8 @@ enum ena_admin_os_type {
 	ENA_ADMIN_OS_FREEBSD                        = 4,
 	ENA_ADMIN_OS_IPXE                           = 5,
 	ENA_ADMIN_OS_ESXI                           = 6,
-	ENA_ADMIN_OS_GROUPS_NUM                     = 6,
+	ENA_ADMIN_OS_MACOS                          = 7,
+	ENA_ADMIN_OS_GROUPS_NUM                     = 7,
 };
 
 struct ena_admin_host_info {
@@ -866,12 +978,14 @@ struct ena_admin_host_info {
 
 	uint16_t reserved;
 
-	/* 0 : mutable_rss_table_size
+	/* 0 : reserved
 	 * 1 : rx_offset
 	 * 2 : interrupt_moderation
 	 * 3 : rx_buf_mirroring
 	 * 4 : rss_configurable_function_key
-	 * 31:5 : reserved
+	 * 5 : reserved
+	 * 6 : rx_page_reuse
+	 * 31:7 : reserved
 	 */
 	uint32_t driver_supported_features;
 };
@@ -956,6 +1070,43 @@ struct ena_admin_queue_ext_feature_desc {
 	};
 };
 
+struct ena_admin_feature_phc_desc {
+	/* PHC type as defined in enum ena_admin_get_phc_type,
+	 * used only for GET command.
+	 */
+	uint8_t type;
+
+	/* Reserved - MBZ */
+	uint8_t reserved1[3];
+
+	/* PHC doorbell address as an offset to PCIe MMIO REG BAR,
+	 * used only for GET command.
+	 */
+	uint32_t doorbell_offset;
+
+	/* Max time for valid PHC retrieval, passing this threshold will
+	 * fail the get-time request and block PHC requests for
+	 * block_timeout_usec, used only for GET command.
+	 */
+	uint32_t expire_timeout_usec;
+
+	/* PHC requests block period, blocking starts if PHC request expired
+	 * in order to prevent floods on busy device,
+	 * used only for GET command.
+	 */
+	uint32_t block_timeout_usec;
+
+	/* Shared PHC physical address (ena_admin_phc_resp),
+	 * used only for SET command.
+	 */
+	struct ena_common_mem_addr output_address;
+
+	/* Shared PHC Size (ena_admin_phc_resp),
+	 * used only for SET command.
+	 */
+	uint32_t output_length;
+};
+
 struct ena_admin_get_feat_resp {
 	struct ena_admin_acq_common_desc acq_common_desc;
 
@@ -986,6 +1137,8 @@ struct ena_admin_get_feat_resp {
 
 		struct ena_admin_ena_hw_hints hw_hints;
 
+		struct ena_admin_feature_phc_desc phc;
+
 		struct ena_admin_get_extra_properties_strings_desc extra_properties_strings;
 
 		struct ena_admin_get_extra_properties_flags_desc extra_properties_flags;
@@ -1022,6 +1175,9 @@ struct ena_admin_set_feat_cmd {
 
 		/* LLQ configuration */
 		struct ena_admin_feature_llq_desc llq;
+
+		/* PHC configuration */
+		struct ena_admin_feature_phc_desc phc;
 	} u;
 };
 
@@ -1057,12 +1213,11 @@ enum ena_admin_aenq_group {
 	ENA_ADMIN_WARNING                           = 2,
 	ENA_ADMIN_NOTIFICATION                      = 3,
 	ENA_ADMIN_KEEP_ALIVE                        = 4,
-	ENA_ADMIN_AENQ_GROUPS_NUM                   = 5,
+	ENA_ADMIN_REFRESH_CAPABILITIES              = 5,
+	ENA_ADMIN_AENQ_GROUPS_NUM                   = 6,
 };
 
 enum ena_admin_aenq_notification_syndrome {
-	ENA_ADMIN_SUSPEND                           = 0,
-	ENA_ADMIN_RESUME                            = 1,
 	ENA_ADMIN_UPDATE_HINTS                      = 2,
 };
 
@@ -1090,6 +1245,10 @@ struct ena_admin_aenq_keep_alive_desc {
 	uint32_t tx_drops_low;
 
 	uint32_t tx_drops_high;
+
+	uint32_t rx_overruns_low;
+
+	uint32_t rx_overruns_high;
 };
 
 struct ena_admin_ena_mmio_req_read_less_resp {
@@ -1101,6 +1260,16 @@ struct ena_admin_ena_mmio_req_read_less_resp {
 	uint32_t reg_val;
 };
 
+struct ena_admin_phc_resp {
+	uint16_t req_id;
+
+	uint8_t reserved1[6];
+
+	uint64_t timestamp;
+
+	uint8_t reserved2[48];
+};
+
 /* aq_common_desc */
 #define ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK            GENMASK(11, 0)
 #define ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK                 BIT(0)
@@ -1189,7 +1358,6 @@ struct ena_admin_ena_mmio_req_read_less_resp {
 #define ENA_ADMIN_HOST_INFO_DEVICE_MASK                     GENMASK(7, 3)
 #define ENA_ADMIN_HOST_INFO_BUS_SHIFT                       8
 #define ENA_ADMIN_HOST_INFO_BUS_MASK                        GENMASK(15, 8)
-#define ENA_ADMIN_HOST_INFO_MUTABLE_RSS_TABLE_SIZE_MASK     BIT(0)
 #define ENA_ADMIN_HOST_INFO_RX_OFFSET_SHIFT                 1
 #define ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK                  BIT(1)
 #define ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_SHIFT      2
@@ -1198,6 +1366,8 @@ struct ena_admin_ena_mmio_req_read_less_resp {
 #define ENA_ADMIN_HOST_INFO_RX_BUF_MIRRORING_MASK           BIT(3)
 #define ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_SHIFT 4
 #define ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK BIT(4)
+#define ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_SHIFT             6
+#define ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_MASK              BIT(6)
 
 /* feature_rss_ind_table */
 #define ENA_ADMIN_FEATURE_RSS_IND_TABLE_ONE_ENTRY_UPDATE_MASK BIT(0)
@@ -1619,16 +1789,6 @@ static inline void set_ena_admin_host_info_bus(struct ena_admin_host_info *p, ui
 	p->bdf |= (val << ENA_ADMIN_HOST_INFO_BUS_SHIFT) & ENA_ADMIN_HOST_INFO_BUS_MASK;
 }
 
-static inline uint32_t get_ena_admin_host_info_mutable_rss_table_size(const struct ena_admin_host_info *p)
-{
-	return p->driver_supported_features & ENA_ADMIN_HOST_INFO_MUTABLE_RSS_TABLE_SIZE_MASK;
-}
-
-static inline void set_ena_admin_host_info_mutable_rss_table_size(struct ena_admin_host_info *p, uint32_t val)
-{
-	p->driver_supported_features |= val & ENA_ADMIN_HOST_INFO_MUTABLE_RSS_TABLE_SIZE_MASK;
-}
-
 static inline uint32_t get_ena_admin_host_info_rx_offset(const struct ena_admin_host_info *p)
 {
 	return (p->driver_supported_features & ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK) >> ENA_ADMIN_HOST_INFO_RX_OFFSET_SHIFT;
@@ -1669,6 +1829,19 @@ static inline void set_ena_admin_host_info_rss_configurable_function_key(struct
 	p->driver_supported_features |= (val << ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_SHIFT) & ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK;
 }
 
+static inline uint32_t get_ena_admin_host_info_rx_page_reuse(const struct ena_admin_host_info *p)
+{
+	return (p->driver_supported_features & ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_MASK) >>
+			ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_SHIFT;
+}
+
+static inline void set_ena_admin_host_info_rx_page_reuse(struct ena_admin_host_info *p,
+								    uint32_t val)
+{
+	p->driver_supported_features |= (val << ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_SHIFT) &
+			ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_MASK;
+}
+
 static inline uint8_t get_ena_admin_feature_rss_ind_table_one_entry_update(const struct ena_admin_feature_rss_ind_table *p)
 {
 	return p->flags & ENA_ADMIN_FEATURE_RSS_IND_TABLE_ONE_ENTRY_UPDATE_MASK;
diff --git a/drivers/net/ena/base/ena_defs/ena_eth_io_defs.h b/drivers/net/ena/base/ena_defs/ena_eth_io_defs.h
index 2b934fff08..2107d17fdf 100644
--- a/drivers/net/ena/base/ena_defs/ena_eth_io_defs.h
+++ b/drivers/net/ena/base/ena_defs/ena_eth_io_defs.h
@@ -261,7 +261,8 @@ struct ena_eth_io_intr_reg {
 	/* 14:0 : rx_intr_delay
 	 * 29:15 : tx_intr_delay
 	 * 30 : intr_unmask
-	 * 31 : reserved
+	 * 31 : no_moderation_update - 0 - moderation
+	 *    updated, 1 - moderation not updated
 	 */
 	uint32_t intr_control;
 };
@@ -381,6 +382,8 @@ struct ena_eth_io_numa_node_cfg_reg {
 #define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK              GENMASK(29, 15)
 #define ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT               30
 #define ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK                BIT(30)
+#define ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_SHIFT      31
+#define ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_MASK       BIT(31)
 
 /* numa_node_cfg_reg */
 #define ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK              GENMASK(7, 0)
@@ -918,6 +921,19 @@ static inline void set_ena_eth_io_intr_reg_intr_unmask(struct ena_eth_io_intr_re
 	p->intr_control |= (val << ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT) & ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK;
 }
 
+static inline uint32_t get_ena_eth_io_intr_reg_no_mod_update(const struct ena_eth_io_intr_reg *p)
+{
+	return (p->intr_control & ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_MASK) >>
+			ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_SHIFT;
+}
+
+static inline void set_ena_eth_io_intr_reg_no_mod_update(struct ena_eth_io_intr_reg *p,
+									     uint32_t val)
+{
+	p->intr_control |= (val << ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_SHIFT) &
+			ENA_ETH_IO_INTR_REG_NO_MODERATION_UPDATE_MASK;
+}
+
 static inline uint32_t get_ena_eth_io_numa_node_cfg_reg_numa(const struct ena_eth_io_numa_node_cfg_reg *p)
 {
 	return p->numa_cfg & ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK;
diff --git a/drivers/net/ena/base/ena_defs/ena_gen_info.h b/drivers/net/ena/base/ena_defs/ena_gen_info.h
index 54bbfda11f..fc62201ccf 100644
--- a/drivers/net/ena/base/ena_defs/ena_gen_info.h
+++ b/drivers/net/ena/base/ena_defs/ena_gen_info.h
@@ -2,5 +2,5 @@
  * Copyright (c) 2015-2020 Amazon.com, Inc. or its affiliates.
  * All rights reserved.
  */
-#define	ENA_GEN_DATE	"Sun Apr 26 13:45:21 DST 2020"
-#define	ENA_GEN_COMMIT	"37aa7c3"
+#define	ENA_GEN_DATE	"Thu 14 Apr 2022 12:50:30 PM IDT"
+#define	ENA_GEN_COMMIT	"35388392"
diff --git a/drivers/net/ena/base/ena_defs/ena_regs_defs.h b/drivers/net/ena/base/ena_defs/ena_regs_defs.h
index 639cd98c0a..6a33f74812 100644
--- a/drivers/net/ena/base/ena_defs/ena_regs_defs.h
+++ b/drivers/net/ena/base/ena_defs/ena_regs_defs.h
@@ -21,6 +21,8 @@ enum ena_regs_reset_reason_types {
 	ENA_REGS_RESET_USER_TRIGGER                 = 12,
 	ENA_REGS_RESET_GENERIC                      = 13,
 	ENA_REGS_RESET_MISS_INTERRUPT               = 14,
+	ENA_REGS_RESET_SUSPECTED_POLL_STARVATION    = 15,
+	ENA_REGS_RESET_RX_DESCRIPTOR_MALFORMED	    = 16,
 	ENA_REGS_RESET_LAST,
 };
 
@@ -52,6 +54,11 @@ enum ena_regs_reset_reason_types {
 #define ENA_REGS_MMIO_RESP_HI_OFF                           0x64
 #define ENA_REGS_RSS_IND_ENTRY_UPDATE_OFF                   0x68
 
+/* phc_registers offsets */
+
+/* 100 base */
+#define ENA_REGS_PHC_DB_OFF                                 0x100
+
 /* version register */
 #define ENA_REGS_VERSION_MINOR_VERSION_MASK                 0xff
 #define ENA_REGS_VERSION_MAJOR_VERSION_SHIFT                8
@@ -98,6 +105,8 @@ enum ena_regs_reset_reason_types {
 #define ENA_REGS_DEV_CTL_QUIESCENT_MASK                     0x4
 #define ENA_REGS_DEV_CTL_IO_RESUME_SHIFT                    3
 #define ENA_REGS_DEV_CTL_IO_RESUME_MASK                     0x8
+#define ENA_REGS_DEV_CTL_RESET_REASON_EXT_SHIFT             24
+#define ENA_REGS_DEV_CTL_RESET_REASON_EXT_MASK              0xf000000
 #define ENA_REGS_DEV_CTL_RESET_REASON_SHIFT                 28
 #define ENA_REGS_DEV_CTL_RESET_REASON_MASK                  0xf0000000
 
@@ -128,4 +137,7 @@ enum ena_regs_reset_reason_types {
 #define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_SHIFT          16
 #define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_MASK           0xffff0000
 
+/* phc_db_req_id register */
+#define ENA_REGS_PHC_DB_REQ_ID_MASK                         0xffff
+
 #endif /* _ENA_REGS_H_ */
diff --git a/drivers/net/ena/base/ena_eth_com.c b/drivers/net/ena/base/ena_eth_com.c
index 042dc1c20e..32090259cd 100644
--- a/drivers/net/ena/base/ena_eth_com.c
+++ b/drivers/net/ena/base/ena_eth_com.c
@@ -57,12 +57,14 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
 
 	if (is_llq_max_tx_burst_exists(io_sq)) {
 		if (unlikely(!io_sq->entries_in_tx_burst_left)) {
-			ena_trc_err("Error: trying to send more packets than tx burst allows\n");
+			ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+				    "Error: trying to send more packets than tx burst allows\n");
 			return ENA_COM_NO_SPACE;
 		}
 
 		io_sq->entries_in_tx_burst_left--;
-		ena_trc_dbg("decreasing entries_in_tx_burst_left of queue %d to %d\n",
+		ena_trc_dbg(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Decreasing entries_in_tx_burst_left of queue %d to %d\n",
 			    io_sq->qid, io_sq->entries_in_tx_burst_left);
 	}
 
@@ -101,12 +103,14 @@ static int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq,
 		llq_info->descs_num_before_header * io_sq->desc_entry_size;
 
 	if (unlikely((header_offset + header_len) >  llq_info->desc_list_entry_size)) {
-		ena_trc_err("trying to write header larger than llq entry can accommodate\n");
+		ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Trying to write header larger than llq entry can accommodate\n");
 		return ENA_COM_FAULT;
 	}
 
 	if (unlikely(!bounce_buffer)) {
-		ena_trc_err("bounce buffer is NULL\n");
+		ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Bounce buffer is NULL\n");
 		return ENA_COM_FAULT;
 	}
 
@@ -124,7 +128,8 @@ static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
 	bounce_buffer = pkt_ctrl->curr_bounce_buf;
 
 	if (unlikely(!bounce_buffer)) {
-		ena_trc_err("bounce buffer is NULL\n");
+		ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Bounce buffer is NULL\n");
 		return NULL;
 	}
 
@@ -145,11 +150,12 @@ static int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
 		return ENA_COM_OK;
 
 	/* bounce buffer was used, so write it and get a new one */
-	if (pkt_ctrl->idx) {
+	if (likely(pkt_ctrl->idx)) {
 		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
 							pkt_ctrl->curr_bounce_buf);
 		if (unlikely(rc)) {
-			ena_trc_err("failed to write bounce buffer to device\n");
+			ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+				    "Failed to write bounce buffer to device\n");
 			return rc;
 		}
 
@@ -182,7 +188,8 @@ static int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
 		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
 							pkt_ctrl->curr_bounce_buf);
 		if (unlikely(rc)) {
-			ena_trc_err("failed to write bounce buffer to device\n");
+			ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+				    "Failed to write bounce buffer to device\n");
 			return rc;
 		}
 
@@ -225,41 +232,55 @@ static struct ena_eth_io_rx_cdesc_base *
 		idx * io_cq->cdesc_entry_size_in_bytes);
 }
 
-static u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
-					   u16 *first_cdesc_idx)
+static int ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
+				    u16 *first_cdesc_idx,
+				    u16 *num_descs)
 {
+	u16 count = io_cq->cur_rx_pkt_cdesc_count, head_masked;
 	struct ena_eth_io_rx_cdesc_base *cdesc;
-	u16 count = 0, head_masked;
 	u32 last = 0;
 
 	do {
+		u32 status;
+
 		cdesc = ena_com_get_next_rx_cdesc(io_cq);
 		if (!cdesc)
 			break;
+		status = READ_ONCE32(cdesc->status);
 
 		ena_com_cq_inc_head(io_cq);
+		if (unlikely((status & ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK) >>
+		    ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT && count != 0)) {
+			struct ena_com_dev *dev = ena_com_io_cq_to_ena_dev(io_cq);
+
+			ena_trc_err(dev,
+				    "First bit is on in descriptor #%d on q_id: %d, req_id: %u\n",
+				    count, io_cq->qid, cdesc->req_id);
+			return ENA_COM_FAULT;
+		}
 		count++;
-		last = (READ_ONCE32(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >>
+		last = (status & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >>
 			ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT;
 	} while (!last);
 
 	if (last) {
 		*first_cdesc_idx = io_cq->cur_rx_pkt_cdesc_start_idx;
-		count += io_cq->cur_rx_pkt_cdesc_count;
 
 		head_masked = io_cq->head & (io_cq->q_depth - 1);
 
+		*num_descs = count;
 		io_cq->cur_rx_pkt_cdesc_count = 0;
 		io_cq->cur_rx_pkt_cdesc_start_idx = head_masked;
 
-		ena_trc_dbg("ena q_id: %d packets were completed. first desc idx %u descs# %d\n",
+		ena_trc_dbg(ena_com_io_cq_to_ena_dev(io_cq),
+			    "ENA q_id: %d packets were completed. first desc idx %u descs# %d\n",
 			    io_cq->qid, *first_cdesc_idx, count);
 	} else {
-		io_cq->cur_rx_pkt_cdesc_count += count;
-		count = 0;
+		io_cq->cur_rx_pkt_cdesc_count = count;
+		*num_descs = 0;
 	}
 
-	return count;
+	return ENA_COM_OK;
 }
 
 static int ena_com_create_meta(struct ena_com_io_sq *io_sq,
@@ -318,9 +339,6 @@ static int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
 	 * compare it to the stored version, just create the meta
 	 */
 	if (io_sq->disable_meta_caching) {
-		if (unlikely(!ena_tx_ctx->meta_valid))
-			return ENA_COM_INVAL;
-
 		*have_meta = true;
 		return ena_com_create_meta(io_sq, ena_meta);
 	}
@@ -337,8 +355,9 @@ static int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
 	return ENA_COM_OK;
 }
 
-static void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
-					struct ena_eth_io_rx_cdesc_base *cdesc)
+static void ena_com_rx_set_flags(struct ena_com_io_cq *io_cq,
+				 struct ena_com_rx_ctx *ena_rx_ctx,
+				 struct ena_eth_io_rx_cdesc_base *cdesc)
 {
 	ena_rx_ctx->l3_proto = cdesc->status &
 		ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK;
@@ -359,7 +378,8 @@ static void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
 		(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK) >>
 		ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT;
 
-	ena_trc_dbg("ena_rx_ctx->l3_proto %d ena_rx_ctx->l4_proto %d\nena_rx_ctx->l3_csum_err %d ena_rx_ctx->l4_csum_err %d\nhash frag %d frag: %d cdesc_status: %x\n",
+	ena_trc_dbg(ena_com_io_cq_to_ena_dev(io_cq),
+		    "l3_proto %d l4_proto %d l3_csum_err %d l4_csum_err %d hash %d frag %d cdesc_status %x\n",
 		    ena_rx_ctx->l3_proto,
 		    ena_rx_ctx->l4_proto,
 		    ena_rx_ctx->l3_csum_err,
@@ -388,23 +408,26 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
 	u64 addr_hi;
 
 	ENA_WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_TX,
-		 "wrong Q type");
+		 ena_com_io_sq_to_ena_dev(io_sq), "wrong Q type");
 
 	/* num_bufs +1 for potential meta desc */
 	if (unlikely(!ena_com_sq_have_enough_space(io_sq, num_bufs + 1))) {
-		ena_trc_dbg("Not enough space in the tx queue\n");
+		ena_trc_dbg(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Not enough space in the tx queue\n");
 		return ENA_COM_NO_MEM;
 	}
 
 	if (unlikely(header_len > io_sq->tx_max_header_size)) {
-		ena_trc_err("header size is too large %d max header: %d\n",
+		ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Header size is too large %d max header: %d\n",
 			    header_len, io_sq->tx_max_header_size);
 		return ENA_COM_INVAL;
 	}
 
 	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV
 		     && !buffer_to_push)) {
-		ena_trc_err("push header wasn't provided on LLQ mode\n");
+		ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Push header wasn't provided in LLQ mode\n");
 		return ENA_COM_INVAL;
 	}
 
@@ -414,7 +437,8 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
 
 	rc = ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx, &have_meta);
 	if (unlikely(rc)) {
-		ena_trc_err("failed to create and store tx meta desc\n");
+		ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Failed to create and store tx meta desc\n");
 		return rc;
 	}
 
@@ -422,7 +446,8 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
 	if (unlikely(!num_bufs && !header_len)) {
 		rc = ena_com_close_bounce_buffer(io_sq);
 		if (rc)
-			ena_trc_err("failed to write buffers to LLQ\n");
+			ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+				    "Failed to write buffers to LLQ\n");
 		*nb_hw_desc = io_sq->tail - start_tail;
 		return rc;
 	}
@@ -483,7 +508,8 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
 		if (likely(i != 0)) {
 			rc = ena_com_sq_update_tail(io_sq);
 			if (unlikely(rc)) {
-				ena_trc_err("failed to update sq tail\n");
+				ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+					    "Failed to update sq tail\n");
 				return rc;
 			}
 
@@ -515,13 +541,12 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
 
 	rc = ena_com_sq_update_tail(io_sq);
 	if (unlikely(rc)) {
-		ena_trc_err("failed to update sq tail of the last descriptor\n");
+		ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Failed to update sq tail of the last descriptor\n");
 		return rc;
 	}
 
 	rc = ena_com_close_bounce_buffer(io_sq);
-	if (rc)
-		ena_trc_err("failed when closing bounce buffer\n");
 
 	*nb_hw_desc = io_sq->tail - start_tail;
 	return rc;
@@ -537,21 +562,27 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
 	u16 cdesc_idx = 0;
 	u16 nb_hw_desc;
 	u16 i = 0;
+	int rc;
 
 	ENA_WARN(io_cq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX,
-		 "wrong Q type");
+		 ena_com_io_cq_to_ena_dev(io_cq), "wrong Q type");
+
+	rc = ena_com_cdesc_rx_pkt_get(io_cq, &cdesc_idx, &nb_hw_desc);
+	if (unlikely(rc != ENA_COM_OK))
+		return ENA_COM_FAULT;
 
-	nb_hw_desc = ena_com_cdesc_rx_pkt_get(io_cq, &cdesc_idx);
 	if (nb_hw_desc == 0) {
 		ena_rx_ctx->descs = nb_hw_desc;
 		return 0;
 	}
 
-	ena_trc_dbg("fetch rx packet: queue %d completed desc: %d\n",
+	ena_trc_dbg(ena_com_io_cq_to_ena_dev(io_cq),
+		    "Fetch rx packet: queue %d completed desc: %d\n",
 		    io_cq->qid, nb_hw_desc);
 
 	if (unlikely(nb_hw_desc > ena_rx_ctx->max_bufs)) {
-		ena_trc_err("Too many RX cdescs (%d) > MAX(%d)\n",
+		ena_trc_err(ena_com_io_cq_to_ena_dev(io_cq),
+			    "Too many RX cdescs (%d) > MAX(%d)\n",
 			    nb_hw_desc, ena_rx_ctx->max_bufs);
 		return ENA_COM_NO_SPACE;
 	}
@@ -575,13 +606,15 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
 	/* Update SQ head ptr */
 	io_sq->next_to_comp += nb_hw_desc;
 
-	ena_trc_dbg("[%s][QID#%d] Updating SQ head to: %d\n", __func__,
+	ena_trc_dbg(ena_com_io_cq_to_ena_dev(io_cq),
+		    "[%s][QID#%d] Updating SQ head to: %d\n", __func__,
 		    io_sq->qid, io_sq->next_to_comp);
 
 	/* Get rx flags from the last pkt */
-	ena_com_rx_set_flags(ena_rx_ctx, cdesc);
+	ena_com_rx_set_flags(io_cq, ena_rx_ctx, cdesc);
 
 	ena_rx_ctx->descs = nb_hw_desc;
+
 	return 0;
 }
 
@@ -592,7 +625,7 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
 	struct ena_eth_io_rx_desc *desc;
 
 	ENA_WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX,
-		 "wrong Q type");
+		 ena_com_io_sq_to_ena_dev(io_sq), "wrong Q type");
 
 	if (unlikely(!ena_com_sq_have_enough_space(io_sq, 1)))
 		return ENA_COM_NO_SPACE;
@@ -612,6 +645,10 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
 
 	desc->req_id = req_id;
 
+	ena_trc_dbg(ena_com_io_sq_to_ena_dev(io_sq),
+		    "[%s] Adding single RX desc, Queue: %u, req_id: %u\n",
+		    __func__, io_sq->qid, req_id);
+
 	desc->buff_addr_lo = (u32)ena_buf->paddr;
 	desc->buff_addr_hi =
 		((ena_buf->paddr & GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32);
diff --git a/drivers/net/ena/base/ena_eth_com.h b/drivers/net/ena/base/ena_eth_com.h
index 7dda16cd9f..cee4f35124 100644
--- a/drivers/net/ena/base/ena_eth_com.h
+++ b/drivers/net/ena/base/ena_eth_com.h
@@ -11,8 +11,10 @@ extern "C" {
 #endif
 #include "ena_com.h"
 
-/* head update threshold in units of (queue size / ENA_COMP_HEAD_THRESH) */
-#define ENA_COMP_HEAD_THRESH 4
+/* we allow 2 DMA descriptors per LLQ entry */
+#define ENA_LLQ_ENTRY_DESC_CHUNK_SIZE	(2 * sizeof(struct ena_eth_io_tx_desc))
+#define ENA_LLQ_HEADER		(128UL - ENA_LLQ_ENTRY_DESC_CHUNK_SIZE)
+#define ENA_LLQ_LARGE_HEADER	(256UL - ENA_LLQ_ENTRY_DESC_CHUNK_SIZE)
 
 struct ena_com_tx_ctx {
 	struct ena_com_tx_meta ena_meta;
@@ -48,7 +50,7 @@ struct ena_com_rx_ctx {
 	bool frag;
 	u32 hash;
 	u16 descs;
-	int max_bufs;
+	u16 max_bufs;
 	u8 pkt_offset;
 };
 
@@ -143,7 +145,8 @@ static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq,
 						   llq_info->descs_per_entry);
 	}
 
-	ena_trc_dbg("queue: %d num_descs: %d num_entries_needed: %d\n",
+	ena_trc_dbg(ena_com_io_sq_to_ena_dev(io_sq),
+		    "Queue: %d num_descs: %d num_entries_needed: %d\n",
 		    io_sq->qid, num_descs, num_entries_needed);
 
 	return num_entries_needed > io_sq->entries_in_tx_burst_left;
@@ -154,41 +157,22 @@ static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq)
 	u16 max_entries_in_tx_burst = io_sq->llq_info.max_entries_in_tx_burst;
 	u16 tail = io_sq->tail;
 
-	ena_trc_dbg("write submission queue doorbell for queue: %d tail: %d\n",
+	ena_trc_dbg(ena_com_io_sq_to_ena_dev(io_sq),
+		    "Write submission queue doorbell for queue: %d tail: %d\n",
 		    io_sq->qid, tail);
 
 	ENA_REG_WRITE32(io_sq->bus, tail, io_sq->db_addr);
 
 	if (is_llq_max_tx_burst_exists(io_sq)) {
-		ena_trc_dbg("reset available entries in tx burst for queue %d to %d\n",
-			     io_sq->qid, max_entries_in_tx_burst);
+		ena_trc_dbg(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Reset available entries in tx burst for queue %d to %d\n",
+			    io_sq->qid, max_entries_in_tx_burst);
 		io_sq->entries_in_tx_burst_left = max_entries_in_tx_burst;
 	}
 
 	return 0;
 }
 
-static inline int ena_com_update_dev_comp_head(struct ena_com_io_cq *io_cq)
-{
-	u16 unreported_comp, head;
-	bool need_update;
-
-	if (unlikely(io_cq->cq_head_db_reg)) {
-		head = io_cq->head;
-		unreported_comp = head - io_cq->last_head_update;
-		need_update = unreported_comp > (io_cq->q_depth / ENA_COMP_HEAD_THRESH);
-
-		if (unlikely(need_update)) {
-			ena_trc_dbg("Write completion queue doorbell for queue %d: head: %d\n",
-				    io_cq->qid, head);
-			ENA_REG_WRITE32(io_cq->bus, head, io_cq->cq_head_db_reg);
-			io_cq->last_head_update = head;
-		}
-	}
-
-	return 0;
-}
-
 static inline void ena_com_update_numa_node(struct ena_com_io_cq *io_cq,
 					    u8 numa_node)
 {
@@ -243,7 +227,8 @@ static inline int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq,
 
 	*req_id = READ_ONCE16(cdesc->req_id);
 	if (unlikely(*req_id >= io_cq->q_depth)) {
-		ena_trc_err("Invalid req id %d\n", cdesc->req_id);
+		ena_trc_err(ena_com_io_cq_to_ena_dev(io_cq),
+			    "Invalid req id %d\n", cdesc->req_id);
 		return ENA_COM_INVAL;
 	}
 
diff --git a/drivers/net/ena/base/ena_plat.h b/drivers/net/ena/base/ena_plat.h
index 2583823080..abd2d8b6c4 100644
--- a/drivers/net/ena/base/ena_plat.h
+++ b/drivers/net/ena/base/ena_plat.h
@@ -6,24 +6,6 @@
 #ifndef ENA_PLAT_H_
 #define ENA_PLAT_H_
 
-#if defined(ENA_IPXE)
-#include <ena_plat_ipxe.h>
-#elif defined(__linux__)
-#if defined(__KERNEL__)
-#include <ena_plat_linux.h>
-#else
 #include <ena_plat_dpdk.h>
-#endif
-#elif defined(__FreeBSD__)
-#if defined(_KERNEL)
-#include <ena_plat_fbsd.h>
-#else
-#include <ena_plat_dpdk.h>
-#endif
-#elif defined(_WIN32)
-#include <ena_plat_windows.h>
-#else
-#error "Invalid platform"
-#endif
 
 #endif /* ENA_PLAT_H_ */
diff --git a/drivers/net/ena/base/ena_plat_dpdk.h b/drivers/net/ena/base/ena_plat_dpdk.h
index bd8ebad9a7..e661541132 100644
--- a/drivers/net/ena/base/ena_plat_dpdk.h
+++ b/drivers/net/ena/base/ena_plat_dpdk.h
@@ -14,6 +14,7 @@
 #include <string.h>
 #include <errno.h>
 
+#include <rte_ethdev_driver.h>
 #include <rte_atomic.h>
 #include <rte_branch_prediction.h>
 #include <rte_cycles.h>
@@ -23,6 +24,8 @@
 #include <rte_memzone.h>
 #include <rte_prefetch.h>
 #include <rte_spinlock.h>
+#include <rte_bitops.h>
+
 
 #include <sys/time.h>
 #include <rte_memcpy.h>
@@ -32,11 +35,14 @@ typedef uint32_t u32;
 typedef uint16_t u16;
 typedef uint8_t u8;
 
+typedef struct rte_eth_dev ena_netdev;
 typedef uint64_t dma_addr_t;
+
 #ifndef ETIME
 #define ETIME ETIMEDOUT
 #endif
 
+#define ENA_PRIU64 PRIu64
 #define ena_atomic32_t rte_atomic32_t
 #define ena_mem_handle_t const struct rte_memzone *
 
@@ -53,9 +59,12 @@ typedef uint64_t dma_addr_t;
 #define ENA_COM_TRY_AGAIN	-EAGAIN
 #define ENA_COM_UNSUPPORTED    -EOPNOTSUPP
 #define ENA_COM_EIO    -EIO
+#define ENA_COM_DEVICE_BUSY	-EBUSY
 
 #define ____cacheline_aligned __rte_cache_aligned
 
+#define ENA_CDESC_RING_SIZE_ALIGNMENT  (1 << 12) /* 4K */
+
 #define ENA_ABORT() abort()
 
 #define ENA_MSLEEP(x) rte_delay_us_sleep(x * 1000)
@@ -63,8 +72,11 @@ typedef uint64_t dma_addr_t;
 #define ENA_UDELAY(x) rte_delay_us_block(x)
 
 #define ENA_TOUCH(x) ((void)(x))
-/* Avoid nested declaration on arm64, as it may define rte_memcpy as memcpy. */
-#if defined(RTE_ARCH_X86)
+/* Redefine memcpy with caution: rte_memcpy can be simply aliased to memcpy, so
+ * make the redefinition only if it's safe (and beneficial) to do so.
+ */
+#if defined(RTE_ARCH_X86) || defined(RTE_ARCH_ARM64_MEMCPY) || \
+	defined(RTE_ARCH_ARM_NEON_MEMCPY)
 #undef memcpy
 #define memcpy rte_memcpy
 #endif
@@ -74,8 +86,16 @@ typedef uint64_t dma_addr_t;
 #define mmiowb rte_io_wmb
 #define __iomem
 
+#ifndef READ_ONCE
+#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))
+#endif
+
+#define READ_ONCE8(var) READ_ONCE(var)
+#define READ_ONCE16(var) READ_ONCE(var)
+#define READ_ONCE32(var) READ_ONCE(var)
+
 #define US_PER_S 1000000
-#define ENA_GET_SYSTEM_USECS()						\
+#define ENA_GET_SYSTEM_USECS()						       \
 	(rte_get_timer_cycles() * US_PER_S / rte_get_timer_hz())
 
 extern int ena_logtype_com;
@@ -91,182 +111,169 @@ extern int ena_logtype_com;
 
 #define BITS_PER_LONG_LONG (__SIZEOF_LONG_LONG__ * 8)
 #define U64_C(x) x ## ULL
-#define BIT(nr)         (1UL << (nr))
+#define BIT(nr)	RTE_BIT32(nr)
+#define BIT64(nr)	RTE_BIT64(nr)
 #define BITS_PER_LONG	(__SIZEOF_LONG__ * 8)
 #define GENMASK(h, l)	(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
-#define GENMASK_ULL(h, l) (((~0ULL) - (1ULL << (l)) + 1) & \
+#define GENMASK_ULL(h, l) (((~0ULL) - (1ULL << (l)) + 1) &		       \
 			  (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
 
-#ifdef RTE_LIBRTE_ENA_COM_DEBUG
-#define ena_trc_log(level, fmt, arg...) \
-	rte_log(RTE_LOG_ ## level, ena_logtype_com, \
-		"[ENA_COM: %s]" fmt, __func__, ##arg)
-
-#define ena_trc_dbg(format, arg...)	ena_trc_log(DEBUG, format, ##arg)
-#define ena_trc_info(format, arg...)	ena_trc_log(INFO, format, ##arg)
-#define ena_trc_warn(format, arg...)	ena_trc_log(WARNING, format, ##arg)
-#define ena_trc_err(format, arg...)	ena_trc_log(ERR, format, ##arg)
-#else
-#define ena_trc_dbg(format, arg...) do { } while (0)
-#define ena_trc_info(format, arg...) do { } while (0)
-#define ena_trc_warn(format, arg...) do { } while (0)
-#define ena_trc_err(format, arg...) do { } while (0)
-#endif /* RTE_LIBRTE_ENA_COM_DEBUG */
-
-#define ENA_WARN(cond, format, arg...)                                 \
-do {                                                                   \
-       if (unlikely(cond)) {                                           \
-               ena_trc_err(                                            \
-                       "Warn failed on %s:%s:%d:" format,              \
-                       __FILE__, __func__, __LINE__, ##arg);           \
-       }                                                               \
-} while (0)
+#define ena_trc_log(dev, level, fmt, arg...)				       \
+	(								       \
+		ENA_TOUCH(dev),						       \
+		rte_log(RTE_LOG_ ## level, ena_logtype_com,		       \
+			"[ENA_COM: %s]" fmt, __func__, ##arg)		       \
+	)
+
+#define ena_trc_dbg(dev, format, arg...) ena_trc_log(dev, DEBUG, format, ##arg)
+#define ena_trc_info(dev, format, arg...) ena_trc_log(dev, INFO, format, ##arg)
+#define ena_trc_warn(dev, format, arg...) ena_trc_log(dev, WARNING, format, ##arg)
+#define ena_trc_err(dev, format, arg...) ena_trc_log(dev, ERR, format, ##arg)
+
+#define ENA_WARN(cond, dev, format, arg...)				       \
+	do {								       \
+		if (unlikely(cond)) {					       \
+			ena_trc_err(dev,				       \
+				"Warn failed on %s:%s:%d:" format,	       \
+				__FILE__, __func__, __LINE__, ##arg);	       \
+		}							       \
+	} while (0)
 
 /* Spinlock related methods */
 #define ena_spinlock_t rte_spinlock_t
-#define ENA_SPINLOCK_INIT(spinlock) rte_spinlock_init(&spinlock)
-#define ENA_SPINLOCK_LOCK(spinlock, flags)				\
-	({(void)flags; rte_spinlock_lock(&spinlock); })
-#define ENA_SPINLOCK_UNLOCK(spinlock, flags)				\
-	({(void)flags; rte_spinlock_unlock(&(spinlock)); })
-#define ENA_SPINLOCK_DESTROY(spinlock) ((void)spinlock)
-
-#define q_waitqueue_t			\
-	struct {			\
-		pthread_cond_t cond;	\
-		pthread_mutex_t mutex;	\
-	}
-
-#define ena_wait_queue_t q_waitqueue_t
-
-#define ENA_WAIT_EVENT_INIT(waitqueue)					\
-	do {								\
-		pthread_mutex_init(&(waitqueue).mutex, NULL);		\
-		pthread_cond_init(&(waitqueue).cond, NULL);		\
+#define ENA_SPINLOCK_INIT(spinlock) rte_spinlock_init(&(spinlock))
+#define ENA_SPINLOCK_LOCK(spinlock, flags)				       \
+	({(void)(flags); rte_spinlock_lock(&(spinlock)); })
+#define ENA_SPINLOCK_UNLOCK(spinlock, flags)				       \
+	({(void)(flags); rte_spinlock_unlock(&(spinlock)); })
+#define ENA_SPINLOCK_DESTROY(spinlock) ((void)(spinlock))
+
+typedef struct {
+	pthread_cond_t cond;
+	pthread_mutex_t mutex;
+	uint8_t flag;
+} ena_wait_event_t;
+
+#define ENA_WAIT_EVENT_INIT(waitevent)					       \
+	do {								       \
+		ena_wait_event_t *_we = &(waitevent);			       \
+		pthread_mutex_init(&_we->mutex, NULL);			       \
+		pthread_cond_init(&_we->cond, NULL);			       \
+		_we->flag = 0;						       \
 	} while (0)
 
-#define ENA_WAIT_EVENT_WAIT(waitevent, timeout)				\
-	do {								\
-		struct timespec wait;					\
-		struct timeval now;					\
-		unsigned long timeout_us;				\
-		gettimeofday(&now, NULL);				\
-		wait.tv_sec = now.tv_sec + timeout / 1000000UL;		\
-		timeout_us = timeout % 1000000UL;			\
-		wait.tv_nsec = (now.tv_usec + timeout_us) * 1000UL;	\
-		pthread_mutex_lock(&waitevent.mutex);			\
-		pthread_cond_timedwait(&waitevent.cond,			\
-				&waitevent.mutex, &wait);		\
-		pthread_mutex_unlock(&waitevent.mutex);			\
+#define ENA_WAIT_EVENT_WAIT(waitevent, timeout)				       \
+	do {								       \
+		ena_wait_event_t *_we = &(waitevent);			       \
+		typeof(timeout) _tmo = (timeout);			       \
+		int ret = 0;						       \
+		struct timespec wait;					       \
+		struct timeval now;					       \
+		unsigned long timeout_us;				       \
+		gettimeofday(&now, NULL);				       \
+		wait.tv_sec = now.tv_sec + _tmo / 1000000UL;		       \
+		timeout_us = _tmo % 1000000UL;				       \
+		wait.tv_nsec = (now.tv_usec + timeout_us) * 1000UL;	       \
+		pthread_mutex_lock(&_we->mutex);			       \
+		while (ret == 0 && !_we->flag) {			       \
+			ret = pthread_cond_timedwait(&_we->cond,	       \
+				&_we->mutex, &wait);			       \
+		}							       \
+		/* Asserts only if not working on ena_wait_event_t */	       \
+		if (unlikely(ret != 0 && ret != ETIMEDOUT))		       \
+			ena_trc_err(NULL,				       \
+				"Invalid wait event. pthread ret: %d\n", ret); \
+		else if (unlikely(ret == ETIMEDOUT))			       \
+			ena_trc_err(NULL,				       \
+				"Timeout waiting for " #waitevent "\n");       \
+		_we->flag = 0;						       \
+		pthread_mutex_unlock(&_we->mutex);			       \
+	} while (0)
+#define ENA_WAIT_EVENT_SIGNAL(waitevent)				       \
+	do {								       \
+		ena_wait_event_t *_we = &(waitevent);			       \
+		pthread_mutex_lock(&_we->mutex);			       \
+		_we->flag = 1;						       \
+		pthread_cond_signal(&_we->cond);			       \
+		pthread_mutex_unlock(&_we->mutex);			       \
 	} while (0)
-#define ENA_WAIT_EVENT_SIGNAL(waitevent) pthread_cond_signal(&waitevent.cond)
 /* pthread condition doesn't need to be rearmed after usage */
 #define ENA_WAIT_EVENT_CLEAR(...)
-#define ENA_WAIT_EVENT_DESTROY(waitqueue) ((void)(waitqueue))
+#define ENA_WAIT_EVENT_DESTROY(waitevent) ((void)(waitevent))
 
-#define ena_wait_event_t ena_wait_queue_t
 #define ENA_MIGHT_SLEEP()
 
 #define ena_time_t uint64_t
-#define ENA_TIME_EXPIRE(timeout)  (timeout < rte_get_timer_cycles())
-#define ENA_GET_SYSTEM_TIMEOUT(timeout_us)                             \
-       (timeout_us * rte_get_timer_hz() / 1000000 + rte_get_timer_cycles())
+#define ena_time_high_res_t uint64_t
 
-/*
- * Each rte_memzone should have unique name.
- * To satisfy it, count number of allocations and add it to name.
+/* Note that high resolution timers are not used by the ENA PMD for now.
+ * Although these macro definitions compile, it shall fail the
+ * compilation in case the unimplemented API is called prematurely.
  */
-extern rte_atomic32_t ena_alloc_cnt;
-
-#define ENA_MEM_ALLOC_COHERENT_ALIGNED(					\
-	dmadev, size, virt, phys, handle, alignment)			\
-	do {								\
-		const struct rte_memzone *mz = NULL;			\
-		ENA_TOUCH(dmadev); ENA_TOUCH(handle);			\
-		if (size > 0) {						\
-			char z_name[RTE_MEMZONE_NAMESIZE];		\
-			snprintf(z_name, sizeof(z_name),		\
-			 "ena_alloc_%d",				\
-			 rte_atomic32_add_return(&ena_alloc_cnt, 1));	\
-			mz = rte_memzone_reserve_aligned(z_name, size,	\
-					SOCKET_ID_ANY,			\
-					RTE_MEMZONE_IOVA_CONTIG,	\
-					alignment);			\
-			handle = mz;					\
-		}							\
-		if (mz == NULL) {					\
-			virt = NULL;					\
-			phys = 0;					\
-		} else {						\
-			memset(mz->addr, 0, size);			\
-			virt = mz->addr;				\
-			phys = mz->iova;				\
-		}							\
+#define ENA_TIME_EXPIRE(timeout)  ((timeout) < rte_get_timer_cycles())
+#define ENA_TIME_EXPIRE_HIGH_RES(timeout) (RTE_SET_USED(timeout), 0)
+#define ENA_TIME_INIT_HIGH_RES() 0
+#define ENA_TIME_COMPARE_HIGH_RES(time1, time2) (RTE_SET_USED(time1), RTE_SET_USED(time2), 0)
+#define ENA_GET_SYSTEM_TIMEOUT(timeout_us) \
+	((timeout_us) * rte_get_timer_hz() / 1000000 + rte_get_timer_cycles())
+#define ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(current_time, timeout_us) \
+	(RTE_SET_USED(current_time), RTE_SET_USED(timeout_us), 0)
+#define ENA_GET_SYSTEM_TIME_HIGH_RES() 0
+
+const struct rte_memzone *
+ena_mem_alloc_coherent(struct rte_eth_dev_data *data, size_t size,
+		       int socket_id, unsigned int alignment, void **virt_addr,
+		       dma_addr_t *phys_addr);
+
+#define ENA_MEM_ALLOC_COHERENT_ALIGNED(					       \
+	dmadev, size, virt, phys, mem_handle, alignment)		       \
+	do {								       \
+		void *virt_addr;					       \
+		dma_addr_t phys_addr;					       \
+		(mem_handle) = ena_mem_alloc_coherent((dmadev), (size),	       \
+			SOCKET_ID_ANY, (alignment), &virt_addr, &phys_addr);   \
+		(virt) = virt_addr;					       \
+		(phys) = phys_addr;					       \
 	} while (0)
-#define ENA_MEM_ALLOC_COHERENT(dmadev, size, virt, phys, handle)	\
-		ENA_MEM_ALLOC_COHERENT_ALIGNED(				\
-			dmadev,						\
-			size,						\
-			virt,						\
-			phys,						\
-			handle,						\
-			RTE_CACHE_LINE_SIZE)
-#define ENA_MEM_FREE_COHERENT(dmadev, size, virt, phys, handle) 	\
-		({ ENA_TOUCH(size); ENA_TOUCH(phys);			\
-		   ENA_TOUCH(dmadev);					\
-		   rte_memzone_free(handle); })
-
-#define ENA_MEM_ALLOC_COHERENT_NODE_ALIGNED(				\
-	dmadev, size, virt, phys, mem_handle, node, dev_node, alignment) \
-	do {								\
-		const struct rte_memzone *mz = NULL;			\
-		ENA_TOUCH(dmadev); ENA_TOUCH(dev_node);			\
-		if (size > 0) {						\
-			char z_name[RTE_MEMZONE_NAMESIZE];		\
-			snprintf(z_name, sizeof(z_name),		\
-			 "ena_alloc_%d",				\
-			 rte_atomic32_add_return(&ena_alloc_cnt, 1));   \
-			mz = rte_memzone_reserve_aligned(z_name, size, node, \
-				RTE_MEMZONE_IOVA_CONTIG, alignment);	\
-			mem_handle = mz;				\
-		}							\
-		if (mz == NULL) {					\
-			virt = NULL;					\
-			phys = 0;					\
-		} else {						\
-			memset(mz->addr, 0, size);			\
-			virt = mz->addr;				\
-			phys = mz->iova;				\
-		}							\
+#define ENA_MEM_ALLOC_COHERENT(dmadev, size, virt, phys, mem_handle)	       \
+		ENA_MEM_ALLOC_COHERENT_ALIGNED(dmadev, size, virt, phys,       \
+			mem_handle, RTE_CACHE_LINE_SIZE)
+#define ENA_MEM_FREE_COHERENT(dmadev, size, virt, phys, mem_handle)	       \
+		({ ENA_TOUCH(size); ENA_TOUCH(phys); ENA_TOUCH(dmadev);	       \
+		   rte_memzone_free(mem_handle); })
+
+#define ENA_MEM_ALLOC_COHERENT_NODE_ALIGNED(				       \
+	dmadev, size, virt, phys, mem_handle, node, dev_node, alignment)       \
+	do {								       \
+		void *virt_addr;					       \
+		dma_addr_t phys_addr;					       \
+		ENA_TOUCH(dev_node);					       \
+		(mem_handle) = ena_mem_alloc_coherent((dmadev), (size),	       \
+			(node), (alignment), &virt_addr, &phys_addr);      \
+		(virt) = virt_addr;					       \
+		(phys) = phys_addr;					       \
 	} while (0)
-#define ENA_MEM_ALLOC_COHERENT_NODE(					\
-	dmadev, size, virt, phys, mem_handle, node, dev_node)		\
-		ENA_MEM_ALLOC_COHERENT_NODE_ALIGNED(			\
-			dmadev,						\
-			size,						\
-			virt,						\
-			phys,						\
-			mem_handle,					\
-			node,						\
-			dev_node,					\
-			RTE_CACHE_LINE_SIZE)
-#define ENA_MEM_ALLOC_NODE(dmadev, size, virt, node, dev_node) \
-	do {								\
-		ENA_TOUCH(dmadev); ENA_TOUCH(dev_node);			\
-		virt = rte_zmalloc_socket(NULL, size, 0, node);		\
+#define ENA_MEM_ALLOC_COHERENT_NODE(					       \
+	dmadev, size, virt, phys, mem_handle, node, dev_node)		       \
+		ENA_MEM_ALLOC_COHERENT_NODE_ALIGNED(dmadev, size, virt,	phys,  \
+			mem_handle, node, dev_node, RTE_CACHE_LINE_SIZE)
+#define ENA_MEM_ALLOC_NODE(dmadev, size, virt, node, dev_node)		       \
+	do {								       \
+		ENA_TOUCH(dmadev); ENA_TOUCH(dev_node);			       \
+		virt = rte_zmalloc_socket(NULL, size, 0, node);		       \
 	} while (0)
 
 #define ENA_MEM_ALLOC(dmadev, size) rte_zmalloc(NULL, size, 1)
-#define ENA_MEM_FREE(dmadev, ptr, size)					\
+#define ENA_MEM_FREE(dmadev, ptr, size)					       \
 	({ ENA_TOUCH(dmadev); ENA_TOUCH(size); rte_free(ptr); })
 
 #define ENA_DB_SYNC(mem_handle) ((void)mem_handle)
 
-#define ENA_REG_WRITE32(bus, value, reg)				\
+#define ENA_REG_WRITE32(bus, value, reg)				       \
 	({ (void)(bus); rte_write32((value), (reg)); })
-#define ENA_REG_WRITE32_RELAXED(bus, value, reg)			\
+#define ENA_REG_WRITE32_RELAXED(bus, value, reg)			       \
 	({ (void)(bus); rte_write32_relaxed((value), (reg)); })
-#define ENA_REG_READ32(bus, reg)					\
+#define ENA_REG_READ32(bus, reg)					       \
 	({ (void)(bus); rte_read32_relaxed((reg)); })
 
 #define ATOMIC32_INC(i32_ptr) rte_atomic32_inc(i32_ptr)
@@ -286,33 +293,24 @@ extern rte_atomic32_t ena_alloc_cnt;
 #define might_sleep()
 
 #define prefetch(x) rte_prefetch0(x)
-#define prefetchw(x) prefetch(x)
+#define prefetchw(x) rte_prefetch0_write(x)
 
 #define lower_32_bits(x) ((uint32_t)(x))
 #define upper_32_bits(x) ((uint32_t)(((x) >> 16) >> 16))
 
-#define ENA_TIME_EXPIRE(timeout)  (timeout < rte_get_timer_cycles())
-#define ENA_GET_SYSTEM_TIMEOUT(timeout_us)				\
-    (timeout_us * rte_get_timer_hz() / 1000000 + rte_get_timer_cycles())
+#define ENA_GET_SYSTEM_TIMEOUT(timeout_us)				       \
+	((timeout_us) * rte_get_timer_hz() / 1000000 + rte_get_timer_cycles())
 #define ENA_WAIT_EVENTS_DESTROY(admin_queue) ((void)(admin_queue))
 
-#ifndef READ_ONCE
-#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))
-#endif
-
-#define READ_ONCE8(var) READ_ONCE(var)
-#define READ_ONCE16(var) READ_ONCE(var)
-#define READ_ONCE32(var) READ_ONCE(var)
-
 /* The size must be 8 byte align */
-#define ENA_MEMCPY_TO_DEVICE_64(dst, src, size)				\
-	do {								\
-		int count, i;						\
-		uint64_t *to = (uint64_t *)(dst);			\
-		const uint64_t *from = (const uint64_t *)(src);		\
-		count = (size) / 8;					\
-		for (i = 0; i < count; i++, from++, to++)		\
-			rte_write64_relaxed(*from, to);			\
+#define ENA_MEMCPY_TO_DEVICE_64(dst, src, size)				       \
+	do {								       \
+		int count, i;						       \
+		uint64_t *to = (uint64_t *)(dst);			       \
+		const uint64_t *from = (const uint64_t *)(src);		       \
+		count = (size) / 8;					       \
+		for (i = 0; i < count; i++, from++, to++)		       \
+			rte_write64_relaxed(*from, to);			       \
 	} while(0)
 
 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
@@ -324,8 +322,25 @@ void ena_rss_key_fill(void *key, size_t size);
 #define ENA_RSS_FILL_KEY(key, size) ena_rss_key_fill(key, size)
 
 #define ENA_INTR_INITIAL_TX_INTERVAL_USECS_PLAT 0
-
-#define ENA_PRIu64 PRIu64
+#define ENA_INTR_INITIAL_RX_INTERVAL_USECS_PLAT 0
 
 #include "ena_includes.h"
+
+#define ENA_BITS_PER_U64(bitmap) (ena_bits_per_u64(bitmap))
+
+#define ENA_FIELD_GET(value, mask, offset) (((value) & (mask)) >> (offset))
+
+static __rte_always_inline int ena_bits_per_u64(uint64_t bitmap)
+{
+	int count = 0;
+
+	while (bitmap) {
+		bitmap &= (bitmap - 1);
+		count++;
+	}
+
+	return count;
+}
+
+
 #endif /* DPDK_ENA_COM_ENA_PLAT_DPDK_H_ */
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index aa2b52ed47..54ac276ca8 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -4,12 +4,6 @@
  */
 
 #include <rte_string_fns.h>
-#include <rte_ether.h>
-#include <rte_ethdev_driver.h>
-#include <rte_ethdev_pci.h>
-#include <rte_tcp.h>
-#include <rte_atomic.h>
-#include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_version.h>
 #include <rte_net.h>
@@ -27,30 +21,27 @@
 #include <ena_eth_io_defs.h>
 
 #define DRV_MODULE_VER_MAJOR	2
-#define DRV_MODULE_VER_MINOR	2
-#define DRV_MODULE_VER_SUBMINOR	1
-
-#define ENA_IO_TXQ_IDX(q)	(2 * (q))
-#define ENA_IO_RXQ_IDX(q)	(2 * (q) + 1)
-/*reverse version of ENA_IO_RXQ_IDX*/
-#define ENA_IO_RXQ_IDX_REV(q)	((q - 1) / 2)
+#define DRV_MODULE_VER_MINOR	8
+#define DRV_MODULE_VER_SUBMINOR	0
 
 #define __MERGE_64B_H_L(h, l) (((uint64_t)h << 32) | l)
-#define TEST_BIT(val, bit_shift) (val & (1UL << bit_shift))
 
 #define GET_L4_HDR_LEN(mbuf)					\
 	((rte_pktmbuf_mtod_offset(mbuf,	struct rte_tcp_hdr *,	\
 		mbuf->l3_len + mbuf->l2_len)->data_off) >> 4)
 
-#define ENA_RX_RSS_TABLE_LOG_SIZE  7
-#define ENA_RX_RSS_TABLE_SIZE	(1 << ENA_RX_RSS_TABLE_LOG_SIZE)
-#define ENA_HASH_KEY_SIZE	40
 #define ETH_GSTRING_LEN	32
 
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define ARRAY_SIZE(x) RTE_DIM(x)
 
 #define ENA_MIN_RING_DESC	128
 
+/*
+ * We should try to keep ENA_CLEANUP_BUF_SIZE lower than
+ * RTE_MEMPOOL_CACHE_MAX_SIZE, so we can fit this in mempool local cache.
+ */
+#define ENA_CLEANUP_BUF_SIZE	256
+
 #define ENA_PTYPE_HAS_HASH	(RTE_PTYPE_L4_TCP | RTE_PTYPE_L4_UDP)
 
 struct ena_stats {
@@ -69,60 +60,90 @@ struct ena_stats {
 #define ENA_STAT_TX_ENTRY(stat) \
 	ENA_STAT_ENTRY(stat, tx)
 
-#define ENA_STAT_ENI_ENTRY(stat) \
-	ENA_STAT_ENTRY(stat, eni)
+#define ENA_STAT_METRICS_ENTRY(stat) \
+	ENA_STAT_ENTRY(stat, metrics)
 
 #define ENA_STAT_GLOBAL_ENTRY(stat) \
 	ENA_STAT_ENTRY(stat, dev)
 
+#define ENA_STAT_ENA_SRD_ENTRY(stat) \
+	ENA_STAT_ENTRY(stat, srd)
+
 /* Device arguments */
 #define ENA_DEVARG_LARGE_LLQ_HDR "large_llq_hdr"
+/* Timeout in seconds after which a single uncompleted Tx packet should be
+ * considered as a missing.
+ */
+#define ENA_DEVARG_MISS_TXC_TO "miss_txc_to"
+/*
+ * Controls whether LLQ should be used (if available). Enabled by default.
+ * NOTE: It's highly not recommended to disable the LLQ, as it may lead to a
+ * huge performance degradation on 6th generation AWS instances.
+ */
+#define ENA_DEVARG_ENABLE_LLQ "enable_llq"
 
 /*
  * Each rte_memzone should have unique name.
  * To satisfy it, count number of allocation and add it to name.
  */
-rte_atomic32_t ena_alloc_cnt;
+rte_atomic64_t ena_alloc_cnt;
 
 static const struct ena_stats ena_stats_global_strings[] = {
 	ENA_STAT_GLOBAL_ENTRY(wd_expired),
 	ENA_STAT_GLOBAL_ENTRY(dev_start),
 	ENA_STAT_GLOBAL_ENTRY(dev_stop),
 	ENA_STAT_GLOBAL_ENTRY(tx_drops),
+	ENA_STAT_GLOBAL_ENTRY(rx_overruns),
 };
 
-static const struct ena_stats ena_stats_eni_strings[] = {
-	ENA_STAT_ENI_ENTRY(bw_in_allowance_exceeded),
-	ENA_STAT_ENI_ENTRY(bw_out_allowance_exceeded),
-	ENA_STAT_ENI_ENTRY(pps_allowance_exceeded),
-	ENA_STAT_ENI_ENTRY(conntrack_allowance_exceeded),
-	ENA_STAT_ENI_ENTRY(linklocal_allowance_exceeded),
+/*
+ * The legacy metrics (also known as eni stats) consisted of 5 stats, while the reworked
+ * metrics (also known as customer metrics) support an additional stat.
+ */
+static struct ena_stats ena_stats_metrics_strings[] = {
+	ENA_STAT_METRICS_ENTRY(bw_in_allowance_exceeded),
+	ENA_STAT_METRICS_ENTRY(bw_out_allowance_exceeded),
+	ENA_STAT_METRICS_ENTRY(pps_allowance_exceeded),
+	ENA_STAT_METRICS_ENTRY(conntrack_allowance_exceeded),
+	ENA_STAT_METRICS_ENTRY(linklocal_allowance_exceeded),
+	ENA_STAT_METRICS_ENTRY(conntrack_allowance_available),
+};
+
+static const struct ena_stats ena_stats_srd_strings[] = {
+	ENA_STAT_ENA_SRD_ENTRY(ena_srd_mode),
+	ENA_STAT_ENA_SRD_ENTRY(ena_srd_tx_pkts),
+	ENA_STAT_ENA_SRD_ENTRY(ena_srd_eligible_tx_pkts),
+	ENA_STAT_ENA_SRD_ENTRY(ena_srd_rx_pkts),
+	ENA_STAT_ENA_SRD_ENTRY(ena_srd_resource_utilization),
 };
 
 static const struct ena_stats ena_stats_tx_strings[] = {
 	ENA_STAT_TX_ENTRY(cnt),
 	ENA_STAT_TX_ENTRY(bytes),
 	ENA_STAT_TX_ENTRY(prepare_ctx_err),
-	ENA_STAT_TX_ENTRY(linearize),
-	ENA_STAT_TX_ENTRY(linearize_failed),
 	ENA_STAT_TX_ENTRY(tx_poll),
 	ENA_STAT_TX_ENTRY(doorbells),
 	ENA_STAT_TX_ENTRY(bad_req_id),
 	ENA_STAT_TX_ENTRY(available_desc),
+	ENA_STAT_TX_ENTRY(missed_tx),
 };
 
 static const struct ena_stats ena_stats_rx_strings[] = {
 	ENA_STAT_RX_ENTRY(cnt),
 	ENA_STAT_RX_ENTRY(bytes),
 	ENA_STAT_RX_ENTRY(refill_partial),
-	ENA_STAT_RX_ENTRY(bad_csum),
+	ENA_STAT_RX_ENTRY(l3_csum_bad),
+	ENA_STAT_RX_ENTRY(l4_csum_bad),
+	ENA_STAT_RX_ENTRY(l4_csum_good),
 	ENA_STAT_RX_ENTRY(mbuf_alloc_fail),
 	ENA_STAT_RX_ENTRY(bad_desc_num),
 	ENA_STAT_RX_ENTRY(bad_req_id),
 };
 
 #define ENA_STATS_ARRAY_GLOBAL	ARRAY_SIZE(ena_stats_global_strings)
-#define ENA_STATS_ARRAY_ENI	ARRAY_SIZE(ena_stats_eni_strings)
+#define ENA_STATS_ARRAY_METRICS	ARRAY_SIZE(ena_stats_metrics_strings)
+#define ENA_STATS_ARRAY_METRICS_LEGACY	(ENA_STATS_ARRAY_METRICS - 1)
+#define ENA_STATS_ARRAY_ENA_SRD	ARRAY_SIZE(ena_stats_srd_strings)
 #define ENA_STATS_ARRAY_TX	ARRAY_SIZE(ena_stats_tx_strings)
 #define ENA_STATS_ARRAY_RX	ARRAY_SIZE(ena_stats_rx_strings)
 
@@ -175,9 +196,9 @@ static const struct rte_pci_id pci_id_ena_map[] = {
 
 static struct ena_aenq_handlers aenq_handlers;
 
-static int ena_device_init(struct ena_com_dev *ena_dev,
-			   struct ena_com_dev_get_features_ctx *get_feat_ctx,
-			   bool *wd_state);
+static int ena_device_init(struct ena_adapter *adapter,
+			   struct rte_pci_device *pdev,
+			   struct ena_com_dev_get_features_ctx *get_feat_ctx);
 static int ena_dev_configure(struct rte_eth_dev *dev);
 static void ena_tx_map_mbuf(struct ena_ring *tx_ring,
 	struct ena_tx_buffer *tx_info,
@@ -185,7 +206,7 @@ static void ena_tx_map_mbuf(struct ena_ring *tx_ring,
 	void **push_header,
 	uint16_t *header_len);
 static int ena_xmit_mbuf(struct ena_ring *tx_ring, struct rte_mbuf *mbuf);
-static void ena_tx_cleanup(struct ena_ring *tx_ring);
+static int ena_tx_cleanup(void *txp, uint32_t free_pkt_cnt);
 static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 				  uint16_t nb_pkts);
 static uint16_t eth_ena_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
@@ -224,11 +245,11 @@ static void ena_rx_queue_release_bufs(struct ena_ring *ring);
 static void ena_tx_queue_release_bufs(struct ena_ring *ring);
 static int ena_link_update(struct rte_eth_dev *dev,
 			   int wait_to_complete);
-static int ena_create_io_queue(struct ena_ring *ring);
+static int ena_create_io_queue(struct rte_eth_dev *dev, struct ena_ring *ring);
 static void ena_queue_stop(struct ena_ring *ring);
 static void ena_queue_stop_all(struct rte_eth_dev *dev,
 			      enum ena_ring_type ring_type);
-static int ena_queue_start(struct ena_ring *ring);
+static int ena_queue_start(struct rte_eth_dev *dev, struct ena_ring *ring);
 static int ena_queue_start_all(struct rte_eth_dev *dev,
 			       enum ena_ring_type ring_type);
 static void ena_stats_restart(struct rte_eth_dev *dev);
@@ -238,12 +259,6 @@ static uint64_t ena_get_rx_queue_offloads(struct ena_adapter *adapter);
 static uint64_t ena_get_tx_queue_offloads(struct ena_adapter *adapter);
 static int ena_infos_get(struct rte_eth_dev *dev,
 			 struct rte_eth_dev_info *dev_info);
-static int ena_rss_reta_update(struct rte_eth_dev *dev,
-			       struct rte_eth_rss_reta_entry64 *reta_conf,
-			       uint16_t reta_size);
-static int ena_rss_reta_query(struct rte_eth_dev *dev,
-			      struct rte_eth_rss_reta_entry64 *reta_conf,
-			      uint16_t reta_size);
 static void ena_interrupt_handler_rte(void *cb_arg);
 static void ena_timer_wd_callback(struct rte_timer *timer, void *arg);
 static void ena_destroy_device(struct rte_eth_dev *eth_dev);
@@ -251,6 +266,10 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev);
 static int ena_xstats_get_names(struct rte_eth_dev *dev,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int n);
+static int ena_xstats_get_names_by_id(struct rte_eth_dev *dev,
+				      struct rte_eth_xstat_name *xstats_names,
+				      const uint64_t *ids,
+				      unsigned int size);
 static int ena_xstats_get(struct rte_eth_dev *dev,
 			  struct rte_eth_xstat *stats,
 			  unsigned int n);
@@ -263,44 +282,337 @@ static int ena_process_bool_devarg(const char *key,
 				   void *opaque);
 static int ena_parse_devargs(struct ena_adapter *adapter,
 			     struct rte_devargs *devargs);
-static int ena_copy_eni_stats(struct ena_adapter *adapter);
+static void ena_copy_customer_metrics(struct ena_adapter *adapter,
+					uint64_t *buf,
+					size_t buf_size);
+static void ena_copy_ena_srd_info(struct ena_adapter *adapter,
+				  struct ena_stats_srd *srd_info);
+static int ena_setup_rx_intr(struct rte_eth_dev *dev);
+static int ena_rx_queue_intr_enable(struct rte_eth_dev *dev,
+				    uint16_t queue_id);
+static int ena_rx_queue_intr_disable(struct rte_eth_dev *dev,
+				     uint16_t queue_id);
+static int ena_configure_aenq(struct ena_adapter *adapter);
+static int ena_mp_primary_handle(const struct rte_mp_msg *mp_msg,
+				 const void *peer);
 
 static const struct eth_dev_ops ena_dev_ops = {
-	.dev_configure        = ena_dev_configure,
-	.dev_infos_get        = ena_infos_get,
-	.rx_queue_setup       = ena_rx_queue_setup,
-	.tx_queue_setup       = ena_tx_queue_setup,
-	.dev_start            = ena_start,
-	.dev_stop             = ena_stop,
-	.link_update          = ena_link_update,
-	.stats_get            = ena_stats_get,
-	.xstats_get_names     = ena_xstats_get_names,
-	.xstats_get	      = ena_xstats_get,
-	.xstats_get_by_id     = ena_xstats_get_by_id,
-	.mtu_set              = ena_mtu_set,
-	.rx_queue_release     = ena_rx_queue_release,
-	.tx_queue_release     = ena_tx_queue_release,
-	.dev_close            = ena_close,
-	.dev_reset            = ena_dev_reset,
-	.reta_update          = ena_rss_reta_update,
-	.reta_query           = ena_rss_reta_query,
+	.dev_configure          = ena_dev_configure,
+	.dev_infos_get          = ena_infos_get,
+	.rx_queue_setup         = ena_rx_queue_setup,
+	.tx_queue_setup         = ena_tx_queue_setup,
+	.dev_start              = ena_start,
+	.dev_stop               = ena_stop,
+	.link_update            = ena_link_update,
+	.stats_get              = ena_stats_get,
+	.xstats_get_names       = ena_xstats_get_names,
+	.xstats_get_names_by_id = ena_xstats_get_names_by_id,
+	.xstats_get             = ena_xstats_get,
+	.xstats_get_by_id       = ena_xstats_get_by_id,
+	.mtu_set                = ena_mtu_set,
+	.rx_queue_release       = ena_rx_queue_release,
+	.tx_queue_release       = ena_tx_queue_release,
+	.dev_close              = ena_close,
+	.dev_reset              = ena_dev_reset,
+	.reta_update            = ena_rss_reta_update,
+	.reta_query             = ena_rss_reta_query,
+	.rx_queue_intr_enable   = ena_rx_queue_intr_enable,
+	.rx_queue_intr_disable  = ena_rx_queue_intr_disable,
+	.rss_hash_update        = ena_rss_hash_update,
+	.rss_hash_conf_get      = ena_rss_hash_conf_get,
+	.tx_done_cleanup        = ena_tx_cleanup,
+};
+
+/*********************************************************************
+ *  Multi-Process communication bits
+ *********************************************************************/
+/* rte_mp IPC message name */
+#define ENA_MP_NAME	"net_ena_mp"
+/* Request timeout in seconds */
+#define ENA_MP_REQ_TMO	5
+
+/** Proxy request type */
+enum ena_mp_req {
+	ENA_MP_DEV_STATS_GET,
+	ENA_MP_ENI_STATS_GET,
+	ENA_MP_MTU_SET,
+	ENA_MP_IND_TBL_GET,
+	ENA_MP_IND_TBL_SET,
+	ENA_MP_CUSTOMER_METRICS_GET,
+	ENA_MP_SRD_STATS_GET,
 };
 
-void ena_rss_key_fill(void *key, size_t size)
+/** Proxy message body. Shared between requests and responses. */
+struct ena_mp_body {
+	/* Message type */
+	enum ena_mp_req type;
+	int port_id;
+	/* Processing result. Set in replies. 0 if message succeeded, negative
+	 * error code otherwise.
+	 */
+	int result;
+	union {
+		int mtu; /* For ENA_MP_MTU_SET */
+	} args;
+};
+
+/**
+ * Initialize IPC message.
+ *
+ * @param[out] msg
+ *   Pointer to the message to initialize.
+ * @param[in] type
+ *   Message type.
+ * @param[in] port_id
+ *   Port ID of target device.
+ *
+ */
+static void
+mp_msg_init(struct rte_mp_msg *msg, enum ena_mp_req type, int port_id)
 {
-	static bool key_generated;
-	static uint8_t default_key[ENA_HASH_KEY_SIZE];
-	size_t i;
+	struct ena_mp_body *body = (struct ena_mp_body *)&msg->param;
+
+	memset(msg, 0, sizeof(*msg));
+	strlcpy(msg->name, ENA_MP_NAME, sizeof(msg->name));
+	msg->len_param = sizeof(*body);
+	body->type = type;
+	body->port_id = port_id;
+}
 
-	if (!key_generated) {
-		for (i = 0; i < RTE_DIM(default_key); ++i)
-			default_key[i] = rte_rand() & 0xff;
-		key_generated = true;
+/*********************************************************************
+ *  Multi-Process communication PMD API
+ *********************************************************************/
+/**
+ * Define proxy request descriptor
+ *
+ * Used to define all structures and functions required for proxying a given
+ * function to the primary process including the code to perform to prepare the
+ * request and process the response.
+ *
+ * @param[in] f
+ *   Name of the function to proxy
+ * @param[in] t
+ *   Message type to use
+ * @param[in] prep
+ *   Body of a function to prepare the request in form of a statement
+ *   expression. It is passed all the original function arguments along with two
+ *   extra ones:
+ *   - struct ena_adapter *adapter - PMD data of the device calling the proxy.
+ *   - struct ena_mp_body *req - body of a request to prepare.
+ * @param[in] proc
+ *   Body of a function to process the response in form of a statement
+ *   expression. It is passed all the original function arguments along with two
+ *   extra ones:
+ *   - struct ena_adapter *adapter - PMD data of the device calling the proxy.
+ *   - struct ena_mp_body *rsp - body of a response to process.
+ * @param ...
+ *   Proxied function's arguments
+ *
+ * @note Inside prep and proc any parameters which aren't used should be marked
+ *       as such (with ENA_TOUCH or __rte_unused).
+ */
+#define ENA_PROXY_DESC(f, t, prep, proc, ...)			\
+	static const enum ena_mp_req mp_type_ ## f =  t;	\
+	static const char *mp_name_ ## f = #t;			\
+	static void mp_prep_ ## f(struct ena_adapter *adapter,	\
+				  struct ena_mp_body *req,	\
+				  __VA_ARGS__)			\
+	{							\
+		prep;						\
+	}							\
+	static void mp_proc_ ## f(struct ena_adapter *adapter,	\
+				  struct ena_mp_body *rsp,	\
+				  __VA_ARGS__)			\
+	{							\
+		proc;						\
 	}
 
-	RTE_ASSERT(size <= sizeof(default_key));
-	rte_memcpy(key, default_key, RTE_MIN(size, sizeof(default_key)));
-}
+/**
+ * Proxy wrapper for calling primary functions in a secondary process.
+ *
+ * Depending on whether called in primary or secondary process, calls the
+ * @p func directly or proxies the call to the primary process via rte_mp IPC.
+ * This macro requires a proxy request descriptor to be defined for @p func
+ * using ENA_PROXY_DESC() macro.
+ *
+ * @param[in/out] a
+ *   Device PMD data. Used for sending the message and sharing message results
+ *   between primary and secondary.
+ * @param[in] f
+ *   Function to proxy.
+ * @param ...
+ *   Arguments of @p func.
+ *
+ * @return
+ *   - 0: Processing succeeded and response handler was called.
+ *   - -EPERM: IPC is unavailable on this platform. This means only primary
+ *             process may call the proxied function.
+ *   - -EIO:   IPC returned error on request send. Inspect rte_errno detailed
+ *             error code.
+ *   - Negative error code from the proxied function.
+ *
+ * @note This mechanism is geared towards control-path tasks. Avoid calling it
+ *       in fast-path unless unbound delays are allowed. This is due to the IPC
+ *       mechanism itself (socket based).
+ * @note Due to IPC parameter size limitations the proxy logic shares call
+ *       results through the struct ena_adapter shared memory. This makes the
+ *       proxy mechanism strictly single-threaded. Therefore be sure to make all
+ *       calls to the same proxied function under the same lock.
+ */
+#define ENA_PROXY(a, f, ...)						\
+({									\
+	struct ena_adapter *_a = (a);					\
+	struct timespec ts = { .tv_sec = ENA_MP_REQ_TMO };		\
+	struct ena_mp_body *req, *rsp;					\
+	struct rte_mp_reply mp_rep;					\
+	struct rte_mp_msg mp_req;					\
+	int ret;							\
+									\
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {		\
+		ret = f(__VA_ARGS__);					\
+	} else {							\
+		/* Prepare and send request */				\
+		req = (struct ena_mp_body *)&mp_req.param;		\
+		mp_msg_init(&mp_req, mp_type_ ## f, _a->edev_data->port_id); \
+		mp_prep_ ## f(_a, req, ## __VA_ARGS__);			\
+									\
+		ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);	\
+		if (likely(!ret)) {					\
+			RTE_ASSERT(mp_rep.nb_received == 1);		\
+			rsp = (struct ena_mp_body *)&mp_rep.msgs[0].param; \
+			ret = rsp->result;				\
+			if (ret == 0) {					\
+				mp_proc_##f(_a, rsp, ## __VA_ARGS__);	\
+			} else {					\
+				PMD_DRV_LOG(ERR,			\
+					    "%s returned error: %d\n",	\
+					    mp_name_ ## f, rsp->result);\
+			}						\
+			free(mp_rep.msgs);				\
+		} else if (rte_errno == ENOTSUP) {			\
+			PMD_DRV_LOG(ERR,				\
+				    "No IPC, can't proxy to primary\n");\
+			ret = -rte_errno;				\
+		} else {						\
+			PMD_DRV_LOG(ERR, "Request %s failed: %s\n",	\
+				    mp_name_ ## f,			\
+				    rte_strerror(rte_errno));		\
+			ret = -EIO;					\
+		}							\
+	}								\
+	ret;								\
+})
+
+/*********************************************************************
+ *  Multi-Process communication request descriptors
+ *********************************************************************/
+
+ENA_PROXY_DESC(ena_com_get_dev_basic_stats, ENA_MP_DEV_STATS_GET,
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(req);
+	ENA_TOUCH(ena_dev);
+	ENA_TOUCH(stats);
+}),
+({
+	ENA_TOUCH(rsp);
+	ENA_TOUCH(ena_dev);
+	if (stats != &adapter->basic_stats)
+		rte_memcpy(stats, &adapter->basic_stats, sizeof(*stats));
+}),
+	struct ena_com_dev *ena_dev, struct ena_admin_basic_stats *stats);
+
+ENA_PROXY_DESC(ena_com_get_eni_stats, ENA_MP_ENI_STATS_GET,
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(req);
+	ENA_TOUCH(ena_dev);
+	ENA_TOUCH(stats);
+}),
+({
+	ENA_TOUCH(rsp);
+	ENA_TOUCH(ena_dev);
+	if (stats != (struct ena_admin_eni_stats *)&adapter->metrics_stats)
+		rte_memcpy(stats, &adapter->metrics_stats, sizeof(*stats));
+}),
+	struct ena_com_dev *ena_dev, struct ena_admin_eni_stats *stats);
+
+ENA_PROXY_DESC(ena_com_set_dev_mtu, ENA_MP_MTU_SET,
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(ena_dev);
+	req->args.mtu = mtu;
+}),
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(rsp);
+	ENA_TOUCH(ena_dev);
+	ENA_TOUCH(mtu);
+}),
+	struct ena_com_dev *ena_dev, int mtu);
+
+ENA_PROXY_DESC(ena_com_indirect_table_set, ENA_MP_IND_TBL_SET,
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(req);
+	ENA_TOUCH(ena_dev);
+}),
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(rsp);
+	ENA_TOUCH(ena_dev);
+}),
+	struct ena_com_dev *ena_dev);
+
+ENA_PROXY_DESC(ena_com_indirect_table_get, ENA_MP_IND_TBL_GET,
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(req);
+	ENA_TOUCH(ena_dev);
+	ENA_TOUCH(ind_tbl);
+}),
+({
+	ENA_TOUCH(rsp);
+	ENA_TOUCH(ena_dev);
+	if (ind_tbl != adapter->indirect_table)
+		rte_memcpy(ind_tbl, adapter->indirect_table,
+			   sizeof(adapter->indirect_table));
+}),
+	struct ena_com_dev *ena_dev, u32 *ind_tbl);
+
+ENA_PROXY_DESC(ena_com_get_customer_metrics, ENA_MP_CUSTOMER_METRICS_GET,
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(req);
+	ENA_TOUCH(ena_dev);
+	ENA_TOUCH(buf);
+	ENA_TOUCH(buf_size);
+}),
+({
+	ENA_TOUCH(rsp);
+	ENA_TOUCH(ena_dev);
+	ENA_TOUCH(buf_size);
+	if (buf != (char *)&adapter->metrics_stats)
+		rte_memcpy(buf, &adapter->metrics_stats, adapter->metrics_num * sizeof(uint64_t));
+}),
+	struct ena_com_dev *ena_dev, char *buf, size_t buf_size);
+
+ENA_PROXY_DESC(ena_com_get_ena_srd_info, ENA_MP_SRD_STATS_GET,
+({
+	ENA_TOUCH(adapter);
+	ENA_TOUCH(req);
+	ENA_TOUCH(ena_dev);
+	ENA_TOUCH(info);
+}),
+({
+	ENA_TOUCH(rsp);
+	ENA_TOUCH(ena_dev);
+	if ((struct ena_stats_srd *)info != &adapter->srd_stats)
+		rte_memcpy((struct ena_stats_srd *)info,
+				&adapter->srd_stats,
+				sizeof(struct ena_stats_srd));
+}),
+	struct ena_com_dev *ena_dev, struct ena_admin_ena_srd_info *info);
 
 static inline void ena_trigger_reset(struct ena_adapter *adapter,
 				     enum ena_regs_reset_reason_types reason)
@@ -311,9 +623,12 @@ static inline void ena_trigger_reset(struct ena_adapter *adapter,
 	}
 }
 
-static inline void ena_rx_mbuf_prepare(struct rte_mbuf *mbuf,
-				       struct ena_com_rx_ctx *ena_rx_ctx)
+static inline void ena_rx_mbuf_prepare(struct ena_ring *rx_ring,
+				       struct rte_mbuf *mbuf,
+				       struct ena_com_rx_ctx *ena_rx_ctx,
+				       bool fill_hash)
 {
+	struct ena_stats_rx *rx_stats = &rx_ring->rx_stats;
 	uint64_t ol_flags = 0;
 	uint32_t packet_type = 0;
 
@@ -324,18 +639,21 @@ static inline void ena_rx_mbuf_prepare(struct rte_mbuf *mbuf,
 
 	if (ena_rx_ctx->l3_proto == ENA_ETH_IO_L3_PROTO_IPV4) {
 		packet_type |= RTE_PTYPE_L3_IPV4;
-		if (unlikely(ena_rx_ctx->l3_csum_err))
+		if (unlikely(ena_rx_ctx->l3_csum_err)) {
+			++rx_stats->l3_csum_bad;
 			ol_flags |= PKT_RX_IP_CKSUM_BAD;
-		else
+		} else {
 			ol_flags |= PKT_RX_IP_CKSUM_GOOD;
+		}
 	} else if (ena_rx_ctx->l3_proto == ENA_ETH_IO_L3_PROTO_IPV6) {
 		packet_type |= RTE_PTYPE_L3_IPV6;
 	}
 
-	if (!ena_rx_ctx->l4_csum_checked || ena_rx_ctx->frag)
+	if (!ena_rx_ctx->l4_csum_checked || ena_rx_ctx->frag) {
 		ol_flags |= PKT_RX_L4_CKSUM_UNKNOWN;
-	else
-		if (unlikely(ena_rx_ctx->l4_csum_err))
+	} else {
+		if (unlikely(ena_rx_ctx->l4_csum_err)) {
+			++rx_stats->l4_csum_bad;
 			/*
 			 * For the L4 Rx checksum offload the HW may indicate
 			 * bad checksum although it's valid. Because of that,
@@ -343,10 +661,14 @@ static inline void ena_rx_mbuf_prepare(struct rte_mbuf *mbuf,
 			 * re-verify the checksum.
 			 */
 			ol_flags |= PKT_RX_L4_CKSUM_UNKNOWN;
-		else
+		} else {
+			++rx_stats->l4_csum_good;
 			ol_flags |= PKT_RX_L4_CKSUM_GOOD;
+		}
+	}
 
-	if (likely((packet_type & ENA_PTYPE_HAS_HASH) && !ena_rx_ctx->frag)) {
+	if (fill_hash &&
+	    likely((packet_type & ENA_PTYPE_HAS_HASH) && !ena_rx_ctx->frag)) {
 		ol_flags |= PKT_RX_RSS_HASH;
 		mbuf->hash.rss = ena_rx_ctx->hash;
 	}
@@ -430,9 +752,11 @@ static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id)
 	}
 
 	if (tx_info)
-		PMD_DRV_LOG(ERR, "tx_info doesn't have valid mbuf\n");
+		PMD_TX_LOG(ERR, "tx_info doesn't have valid mbuf. queue %d:%d req_id %u\n",
+			tx_ring->port_id, tx_ring->id, req_id);
 	else
-		PMD_DRV_LOG(ERR, "Invalid req_id: %hu\n", req_id);
+		PMD_TX_LOG(ERR, "Invalid req_id: %hu in queue %d:%d\n",
+			req_id, tx_ring->port_id, tx_ring->id);
 
 	/* Trigger device reset */
 	++tx_ring->tx_stats.bad_req_id;
@@ -469,7 +793,8 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev)
 	host_info->num_cpus = rte_lcore_count();
 
 	host_info->driver_supported_features =
-		ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK;
+		ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK |
+		ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK;
 
 	rc = ena_com_set_host_attributes(ena_dev);
 	if (rc) {
@@ -488,11 +813,15 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev)
 }
 
 /* This function calculates the number of xstats based on the current config */
-static unsigned int ena_xstats_calc_num(struct rte_eth_dev *dev)
+static unsigned int ena_xstats_calc_num(struct rte_eth_dev_data *data)
 {
-	return ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENI +
-		(dev->data->nb_tx_queues * ENA_STATS_ARRAY_TX) +
-		(dev->data->nb_rx_queues * ENA_STATS_ARRAY_RX);
+	struct ena_adapter *adapter = data->dev_private;
+
+	return ENA_STATS_ARRAY_GLOBAL +
+		adapter->metrics_num +
+		ENA_STATS_ARRAY_ENA_SRD +
+		(data->nb_tx_queues * ENA_STATS_ARRAY_TX) +
+		(data->nb_rx_queues * ENA_STATS_ARRAY_RX);
 }
 
 static void ena_config_debug_area(struct ena_adapter *adapter)
@@ -500,7 +829,7 @@ static void ena_config_debug_area(struct ena_adapter *adapter)
 	u32 debug_area_size;
 	int rc, ss_count;
 
-	ss_count = ena_xstats_calc_num(adapter->rte_dev);
+	ss_count = ena_xstats_calc_num(adapter->edev_data);
 
 	/* allocate 32 bytes for each string and 64bit for the value */
 	debug_area_size = ss_count * ETH_GSTRING_LEN + sizeof(u64) * ss_count;
@@ -549,7 +878,7 @@ static int ena_close(struct rte_eth_dev *dev)
 	rte_intr_disable(intr_handle);
 	rte_intr_callback_unregister(intr_handle,
 				     ena_interrupt_handler_rte,
-				     adapter);
+				     dev);
 
 	/*
 	 * MAC is not allocated dynamically. Setting NULL should prevent from
@@ -565,154 +894,16 @@ ena_dev_reset(struct rte_eth_dev *dev)
 {
 	int rc = 0;
 
+	/* Cannot release memory in secondary process */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		PMD_DRV_LOG(WARNING, "dev_reset not supported in secondary.\n");
+		return -EPERM;
+	}
+
 	ena_destroy_device(dev);
 	rc = eth_ena_dev_init(dev);
 	if (rc)
-		PMD_INIT_LOG(CRIT, "Cannot initialize device");
-
-	return rc;
-}
-
-static int ena_rss_reta_update(struct rte_eth_dev *dev,
-			       struct rte_eth_rss_reta_entry64 *reta_conf,
-			       uint16_t reta_size)
-{
-	struct ena_adapter *adapter = dev->data->dev_private;
-	struct ena_com_dev *ena_dev = &adapter->ena_dev;
-	int rc, i;
-	u16 entry_value;
-	int conf_idx;
-	int idx;
-
-	if ((reta_size == 0) || (reta_conf == NULL))
-		return -EINVAL;
-
-	if (reta_size > ENA_RX_RSS_TABLE_SIZE) {
-		PMD_DRV_LOG(WARNING,
-			"indirection table %d is bigger than supported (%d)\n",
-			reta_size, ENA_RX_RSS_TABLE_SIZE);
-		return -EINVAL;
-	}
-
-	for (i = 0 ; i < reta_size ; i++) {
-		/* each reta_conf is for 64 entries.
-		 * to support 128 we use 2 conf of 64
-		 */
-		conf_idx = i / RTE_RETA_GROUP_SIZE;
-		idx = i % RTE_RETA_GROUP_SIZE;
-		if (TEST_BIT(reta_conf[conf_idx].mask, idx)) {
-			entry_value =
-				ENA_IO_RXQ_IDX(reta_conf[conf_idx].reta[idx]);
-
-			rc = ena_com_indirect_table_fill_entry(ena_dev,
-							       i,
-							       entry_value);
-			if (unlikely(rc && rc != ENA_COM_UNSUPPORTED)) {
-				PMD_DRV_LOG(ERR,
-					"Cannot fill indirect table\n");
-				return rc;
-			}
-		}
-	}
-
-	rte_spinlock_lock(&adapter->admin_lock);
-	rc = ena_com_indirect_table_set(ena_dev);
-	rte_spinlock_unlock(&adapter->admin_lock);
-	if (unlikely(rc && rc != ENA_COM_UNSUPPORTED)) {
-		PMD_DRV_LOG(ERR, "Cannot flush the indirect table\n");
-		return rc;
-	}
-
-	PMD_DRV_LOG(DEBUG, "%s(): RSS configured %d entries  for port %d\n",
-		__func__, reta_size, adapter->rte_dev->data->port_id);
-
-	return 0;
-}
-
-/* Query redirection table. */
-static int ena_rss_reta_query(struct rte_eth_dev *dev,
-			      struct rte_eth_rss_reta_entry64 *reta_conf,
-			      uint16_t reta_size)
-{
-	struct ena_adapter *adapter = dev->data->dev_private;
-	struct ena_com_dev *ena_dev = &adapter->ena_dev;
-	int rc;
-	int i;
-	u32 indirect_table[ENA_RX_RSS_TABLE_SIZE] = {0};
-	int reta_conf_idx;
-	int reta_idx;
-
-	if (reta_size == 0 || reta_conf == NULL)
-		return -EINVAL;
-
-	rte_spinlock_lock(&adapter->admin_lock);
-	rc = ena_com_indirect_table_get(ena_dev, indirect_table);
-	rte_spinlock_unlock(&adapter->admin_lock);
-	if (unlikely(rc && rc != ENA_COM_UNSUPPORTED)) {
-		PMD_DRV_LOG(ERR, "cannot get indirect table\n");
-		return -ENOTSUP;
-	}
-
-	for (i = 0 ; i < reta_size ; i++) {
-		reta_conf_idx = i / RTE_RETA_GROUP_SIZE;
-		reta_idx = i % RTE_RETA_GROUP_SIZE;
-		if (TEST_BIT(reta_conf[reta_conf_idx].mask, reta_idx))
-			reta_conf[reta_conf_idx].reta[reta_idx] =
-				ENA_IO_RXQ_IDX_REV(indirect_table[i]);
-	}
-
-	return 0;
-}
-
-static int ena_rss_init_default(struct ena_adapter *adapter)
-{
-	struct ena_com_dev *ena_dev = &adapter->ena_dev;
-	uint16_t nb_rx_queues = adapter->rte_dev->data->nb_rx_queues;
-	int rc, i;
-	u32 val;
-
-	rc = ena_com_rss_init(ena_dev, ENA_RX_RSS_TABLE_LOG_SIZE);
-	if (unlikely(rc)) {
-		PMD_DRV_LOG(ERR, "Cannot init indirect table\n");
-		goto err_rss_init;
-	}
-
-	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
-		val = i % nb_rx_queues;
-		rc = ena_com_indirect_table_fill_entry(ena_dev, i,
-						       ENA_IO_RXQ_IDX(val));
-		if (unlikely(rc && (rc != ENA_COM_UNSUPPORTED))) {
-			PMD_DRV_LOG(ERR, "Cannot fill indirect table\n");
-			goto err_fill_indir;
-		}
-	}
-
-	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_CRC32, NULL,
-					ENA_HASH_KEY_SIZE, 0xFFFFFFFF);
-	if (unlikely(rc && (rc != ENA_COM_UNSUPPORTED))) {
-		PMD_DRV_LOG(INFO, "Cannot fill hash function\n");
-		goto err_fill_indir;
-	}
-
-	rc = ena_com_set_default_hash_ctrl(ena_dev);
-	if (unlikely(rc && (rc != ENA_COM_UNSUPPORTED))) {
-		PMD_DRV_LOG(INFO, "Cannot fill hash control\n");
-		goto err_fill_indir;
-	}
-
-	rc = ena_com_indirect_table_set(ena_dev);
-	if (unlikely(rc && (rc != ENA_COM_UNSUPPORTED))) {
-		PMD_DRV_LOG(ERR, "Cannot flush the indirect table\n");
-		goto err_fill_indir;
-	}
-	PMD_DRV_LOG(DEBUG, "RSS configured for port %d\n",
-		adapter->rte_dev->data->port_id);
-
-	return 0;
-
-err_fill_indir:
-	ena_com_rss_destroy(ena_dev);
-err_rss_init:
+		PMD_INIT_LOG(CRIT, "Cannot initialize device\n");
 
 	return rc;
 }
@@ -743,20 +934,20 @@ static void ena_rx_queue_release(void *queue)
 
 	/* Free ring resources */
 	if (ring->rx_buffer_info)
-		rte_free(ring->rx_buffer_info);
+	rte_free(ring->rx_buffer_info);
 	ring->rx_buffer_info = NULL;
 
 	if (ring->rx_refill_buffer)
-		rte_free(ring->rx_refill_buffer);
+	rte_free(ring->rx_refill_buffer);
 	ring->rx_refill_buffer = NULL;
 
 	if (ring->empty_rx_reqs)
-		rte_free(ring->empty_rx_reqs);
+	rte_free(ring->empty_rx_reqs);
 	ring->empty_rx_reqs = NULL;
 
 	ring->configured = 0;
 
-	PMD_DRV_LOG(NOTICE, "RX Queue %d:%d released\n",
+	PMD_DRV_LOG(NOTICE, "Rx queue %d:%d released\n",
 		ring->port_id, ring->id);
 }
 
@@ -766,13 +957,13 @@ static void ena_tx_queue_release(void *queue)
 
 	/* Free ring resources */
 	if (ring->push_buf_intermediate_buf)
-		rte_free(ring->push_buf_intermediate_buf);
+	rte_free(ring->push_buf_intermediate_buf);
 
 	if (ring->tx_buffer_info)
-		rte_free(ring->tx_buffer_info);
+	rte_free(ring->tx_buffer_info);
 
 	if (ring->empty_tx_reqs)
-		rte_free(ring->empty_tx_reqs);
+	rte_free(ring->empty_tx_reqs);
 
 	ring->empty_tx_reqs = NULL;
 	ring->tx_buffer_info = NULL;
@@ -780,7 +971,7 @@ static void ena_tx_queue_release(void *queue)
 
 	ring->configured = 0;
 
-	PMD_DRV_LOG(NOTICE, "TX Queue %d:%d released\n",
+	PMD_DRV_LOG(NOTICE, "Tx queue %d:%d released\n",
 		ring->port_id, ring->id);
 }
 
@@ -845,19 +1036,19 @@ static int ena_queue_start_all(struct rte_eth_dev *dev,
 			if (ring_type == ENA_RING_TYPE_RX) {
 				ena_assert_msg(
 					dev->data->rx_queues[i] == &queues[i],
-					"Inconsistent state of rx queues\n");
+					"Inconsistent state of Rx queues\n");
 			} else {
 				ena_assert_msg(
 					dev->data->tx_queues[i] == &queues[i],
-					"Inconsistent state of tx queues\n");
+					"Inconsistent state of Tx queues\n");
 			}
 
-			rc = ena_queue_start(&queues[i]);
+			rc = ena_queue_start(dev, &queues[i]);
 
 			if (rc) {
 				PMD_INIT_LOG(ERR,
-					     "failed to start queue %d type(%d)",
-					     i, ring_type);
+					"Failed to start queue[%d] of type(%d)\n",
+					i, ring_type);
 				goto err;
 			}
 		}
@@ -873,32 +1064,6 @@ static int ena_queue_start_all(struct rte_eth_dev *dev,
 	return rc;
 }
 
-static uint32_t ena_get_mtu_conf(struct ena_adapter *adapter)
-{
-	uint32_t max_frame_len = adapter->max_mtu;
-
-	if (adapter->rte_eth_dev_data->dev_conf.rxmode.offloads &
-	    DEV_RX_OFFLOAD_JUMBO_FRAME)
-		max_frame_len =
-			adapter->rte_eth_dev_data->dev_conf.rxmode.max_rx_pkt_len;
-
-	return max_frame_len;
-}
-
-static int ena_check_valid_conf(struct ena_adapter *adapter)
-{
-	uint32_t max_frame_len = ena_get_mtu_conf(adapter);
-
-	if (max_frame_len > adapter->max_mtu || max_frame_len < ENA_MIN_MTU) {
-		PMD_INIT_LOG(ERR, "Unsupported MTU of %d. "
-				  "max mtu: %d, min mtu: %d",
-			     max_frame_len, adapter->max_mtu, ENA_MIN_MTU);
-		return ENA_COM_UNSUPPORTED;
-	}
-
-	return 0;
-}
-
 static int
 ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx,
 		       bool use_large_llq_hdr)
@@ -961,7 +1126,7 @@ ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx,
 		     ENA_ADMIN_PLACEMENT_POLICY_DEV)) {
 			max_tx_queue_size /= 2;
 			PMD_INIT_LOG(INFO,
-				"Forcing large headers and decreasing maximum TX queue size to %d\n",
+				"Forcing large headers and decreasing maximum Tx queue size to %d\n",
 				max_tx_queue_size);
 		} else {
 			PMD_INIT_LOG(ERR,
@@ -970,7 +1135,7 @@ ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx,
 	}
 
 	if (unlikely(max_rx_queue_size == 0 || max_tx_queue_size == 0)) {
-		PMD_INIT_LOG(ERR, "Invalid queue size");
+		PMD_INIT_LOG(ERR, "Invalid queue size\n");
 		return -EFAULT;
 	}
 
@@ -1000,13 +1165,11 @@ static int ena_stats_get(struct rte_eth_dev *dev,
 	int i;
 	int max_rings_stats;
 
-	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
-		return -ENOTSUP;
-
 	memset(&ena_stats, 0, sizeof(ena_stats));
 
 	rte_spinlock_lock(&adapter->admin_lock);
-	rc = ena_com_get_dev_basic_stats(ena_dev, &ena_stats);
+	rc = ENA_PROXY(adapter, ena_com_get_dev_basic_stats, ena_dev,
+		       &ena_stats);
 	rte_spinlock_unlock(&adapter->admin_lock);
 	if (unlikely(rc)) {
 		PMD_DRV_LOG(ERR, "Could not retrieve statistics from ENA\n");
@@ -1065,19 +1228,11 @@ static int ena_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	ena_dev = &adapter->ena_dev;
 	ena_assert_msg(ena_dev != NULL, "Uninitialized device\n");
 
-	if (mtu > ena_get_mtu_conf(adapter) || mtu < ENA_MIN_MTU) {
-		PMD_DRV_LOG(ERR,
-			"Invalid MTU setting. new_mtu: %d "
-			"max mtu: %d min mtu: %d\n",
-			mtu, ena_get_mtu_conf(adapter), ENA_MIN_MTU);
-		return -EINVAL;
-	}
-
-	rc = ena_com_set_dev_mtu(ena_dev, mtu);
+	rc = ENA_PROXY(adapter, ena_com_set_dev_mtu, ena_dev, mtu);
 	if (rc)
 		PMD_DRV_LOG(ERR, "Could not set MTU: %d\n", mtu);
 	else
-		PMD_DRV_LOG(NOTICE, "Set MTU: %d\n", mtu);
+		PMD_DRV_LOG(NOTICE, "MTU set to: %d\n", mtu);
 
 	return rc;
 }
@@ -1087,8 +1242,15 @@ static int ena_start(struct rte_eth_dev *dev)
 	struct ena_adapter *adapter = dev->data->dev_private;
 	uint64_t ticks;
 	int rc = 0;
+	uint16_t i;
+
+	/* Cannot allocate memory in secondary process */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		PMD_DRV_LOG(WARNING, "dev_start not supported in secondary.\n");
+		return -EPERM;
+	}
 
-	rc = ena_check_valid_conf(adapter);
+	rc = ena_setup_rx_intr(dev);
 	if (rc)
 		return rc;
 
@@ -1100,9 +1262,8 @@ static int ena_start(struct rte_eth_dev *dev)
 	if (rc)
 		goto err_start_tx;
 
-	if (adapter->rte_dev->data->dev_conf.rxmode.mq_mode &
-	    ETH_MQ_RX_RSS_FLAG && adapter->rte_dev->data->nb_rx_queues > 0) {
-		rc = ena_rss_init_default(adapter);
+	if (adapter->edev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG) {
+		rc = ena_rss_configure(adapter);
 		if (rc)
 			goto err_rss_init;
 	}
@@ -1114,11 +1275,16 @@ static int ena_start(struct rte_eth_dev *dev)
 
 	ticks = rte_get_timer_hz();
 	rte_timer_reset(&adapter->timer_wd, ticks, PERIODICAL, rte_lcore_id(),
-			ena_timer_wd_callback, adapter);
+			ena_timer_wd_callback, dev);
 
 	++adapter->dev_stats.dev_start;
 	adapter->state = ENA_ADAPTER_STATE_RUNNING;
 
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
+	for (i = 0; i < dev->data->nb_tx_queues; i++)
+		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
+
 	return 0;
 
 err_rss_init:
@@ -1132,8 +1298,17 @@ static int ena_stop(struct rte_eth_dev *dev)
 {
 	struct ena_adapter *adapter = dev->data->dev_private;
 	struct ena_com_dev *ena_dev = &adapter->ena_dev;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+	uint16_t i;
 	int rc;
 
+	/* Cannot free memory in secondary process */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		PMD_DRV_LOG(WARNING, "dev_stop not supported in secondary.\n");
+		return -EPERM;
+	}
+
 	rte_timer_stop_sync(&adapter->timer_wd);
 	ena_queue_stop_all(dev, ENA_RING_TYPE_TX);
 	ena_queue_stop_all(dev, ENA_RING_TYPE_RX);
@@ -1141,20 +1316,39 @@ static int ena_stop(struct rte_eth_dev *dev)
 	if (adapter->trigger_reset) {
 		rc = ena_com_dev_reset(ena_dev, adapter->reset_reason);
 		if (rc)
-			PMD_DRV_LOG(ERR, "Device reset failed rc=%d\n", rc);
+			PMD_DRV_LOG(ERR, "Device reset failed, rc: %d\n", rc);
+	}
+
+	rte_intr_disable(intr_handle);
+
+	rte_intr_efd_disable(intr_handle);
+
+	/* Cleanup vector list */
+	if (intr_handle->intr_vec != NULL) {
+		rte_free(intr_handle->intr_vec);
+		intr_handle->intr_vec = NULL;
 	}
 
+	rte_intr_enable(intr_handle);
+
 	++adapter->dev_stats.dev_stop;
 	adapter->state = ENA_ADAPTER_STATE_STOPPED;
 	dev->data->dev_started = 0;
 
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
+	for (i = 0; i < dev->data->nb_tx_queues; i++)
+		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
+
 	return 0;
 }
 
-static int ena_create_io_queue(struct ena_ring *ring)
+static int ena_create_io_queue(struct rte_eth_dev *dev, struct ena_ring *ring)
 {
-	struct ena_adapter *adapter;
-	struct ena_com_dev *ena_dev;
+	struct ena_adapter *adapter = ring->adapter;
+	struct ena_com_dev *ena_dev = &adapter->ena_dev;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct ena_com_create_io_ctx ctx =
 		/* policy set to _HOST just to satisfy icc compiler */
 		{ ENA_ADMIN_PLACEMENT_POLICY_HOST,
@@ -1163,9 +1357,7 @@ static int ena_create_io_queue(struct ena_ring *ring)
 	unsigned int i;
 	int rc;
 
-	adapter = ring->adapter;
-	ena_dev = &adapter->ena_dev;
-
+	ctx.msix_vector = -1;
 	if (ring->type == ENA_RING_TYPE_TX) {
 		ena_qid = ENA_IO_TXQ_IDX(ring->id);
 		ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX;
@@ -1175,18 +1367,19 @@ static int ena_create_io_queue(struct ena_ring *ring)
 	} else {
 		ena_qid = ENA_IO_RXQ_IDX(ring->id);
 		ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
+		if (rte_intr_dp_is_en(intr_handle))
+			ctx.msix_vector = intr_handle->intr_vec[ring->id];
 		for (i = 0; i < ring->ring_size; i++)
 			ring->empty_rx_reqs[i] = i;
 	}
 	ctx.queue_size = ring->ring_size;
 	ctx.qid = ena_qid;
-	ctx.msix_vector = -1; /* interrupts not used */
 	ctx.numa_node = ring->numa_socket_id;
 
 	rc = ena_com_create_io_queue(ena_dev, &ctx);
 	if (rc) {
 		PMD_DRV_LOG(ERR,
-			"failed to create io queue #%d (qid:%d) rc: %d\n",
+			"Failed to create IO queue[%d] (qid:%d), rc: %d\n",
 			ring->id, ena_qid, rc);
 		return rc;
 	}
@@ -1196,7 +1389,7 @@ static int ena_create_io_queue(struct ena_ring *ring)
 				     &ring->ena_com_io_cq);
 	if (rc) {
 		PMD_DRV_LOG(ERR,
-			"Failed to get io queue handlers. queue num %d rc: %d\n",
+			"Failed to get IO queue[%d] handlers, rc: %d\n",
 			ring->id, rc);
 		ena_com_destroy_io_queue(ena_dev, ena_qid);
 		return rc;
@@ -1205,6 +1398,10 @@ static int ena_create_io_queue(struct ena_ring *ring)
 	if (ring->type == ENA_RING_TYPE_TX)
 		ena_com_update_numa_node(ring->ena_com_io_cq, ctx.numa_node);
 
+	/* Start with Rx interrupts being masked. */
+	if (ring->type == ENA_RING_TYPE_RX && rte_intr_dp_is_en(intr_handle))
+		ena_rx_queue_intr_disable(dev, ring->id);
+
 	return 0;
 }
 
@@ -1241,16 +1438,16 @@ static void ena_queue_stop_all(struct rte_eth_dev *dev,
 			ena_queue_stop(&queues[i]);
 }
 
-static int ena_queue_start(struct ena_ring *ring)
+static int ena_queue_start(struct rte_eth_dev *dev, struct ena_ring *ring)
 {
 	int rc, bufs_num;
 
 	ena_assert_msg(ring->configured == 1,
 		       "Trying to start unconfigured queue\n");
 
-	rc = ena_create_io_queue(ring);
+	rc = ena_create_io_queue(dev, ring);
 	if (rc) {
-		PMD_INIT_LOG(ERR, "Failed to create IO queue!");
+		PMD_INIT_LOG(ERR, "Failed to create IO queue\n");
 		return rc;
 	}
 
@@ -1268,7 +1465,7 @@ static int ena_queue_start(struct ena_ring *ring)
 	if (rc != bufs_num) {
 		ena_com_destroy_io_queue(&ring->adapter->ena_dev,
 					 ENA_IO_RXQ_IDX(ring->id));
-		PMD_INIT_LOG(ERR, "Failed to populate rx ring !");
+		PMD_INIT_LOG(ERR, "Failed to populate Rx ring\n");
 		return ENA_COM_FAULT;
 	}
 	/* Flush per-core RX buffers pools cache as they can be used on other
@@ -1288,26 +1485,27 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev,
 	struct ena_ring *txq = NULL;
 	struct ena_adapter *adapter = dev->data->dev_private;
 	unsigned int i;
+	uint16_t dyn_thresh;
 
 	txq = &adapter->tx_ring[queue_idx];
 
 	if (txq->configured) {
 		PMD_DRV_LOG(CRIT,
-			"API violation. Queue %d is already configured\n",
+			"API violation. Queue[%d] is already configured\n",
 			queue_idx);
 		return ENA_COM_FAULT;
 	}
 
 	if (!rte_is_power_of_2(nb_desc)) {
 		PMD_DRV_LOG(ERR,
-			"Unsupported size of TX queue: %d is not a power of 2.\n",
+			"Unsupported size of Tx queue: %d is not a power of 2.\n",
 			nb_desc);
 		return -EINVAL;
 	}
 
 	if (nb_desc > adapter->max_tx_ring_size) {
 		PMD_DRV_LOG(ERR,
-			"Unsupported size of TX queue (max size: %d)\n",
+			"Unsupported size of Tx queue (max size: %d)\n",
 			adapter->max_tx_ring_size);
 		return -EINVAL;
 	}
@@ -1319,31 +1517,36 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev,
 	txq->size_mask = nb_desc - 1;
 	txq->numa_socket_id = socket_id;
 	txq->pkts_without_db = false;
+	txq->last_cleanup_ticks = 0;
 
-	txq->tx_buffer_info = rte_zmalloc("txq->tx_buffer_info",
-					  sizeof(struct ena_tx_buffer) *
-					  txq->ring_size,
-					  RTE_CACHE_LINE_SIZE);
+	txq->tx_buffer_info = rte_zmalloc_socket("txq->tx_buffer_info",
+		sizeof(struct ena_tx_buffer) * txq->ring_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (!txq->tx_buffer_info) {
-		PMD_DRV_LOG(ERR, "failed to alloc mem for tx buffer info\n");
+		PMD_DRV_LOG(ERR,
+			"Failed to allocate memory for Tx buffer info\n");
 		return -ENOMEM;
 	}
 
-	txq->empty_tx_reqs = rte_zmalloc("txq->empty_tx_reqs",
-					 sizeof(u16) * txq->ring_size,
-					 RTE_CACHE_LINE_SIZE);
+	txq->empty_tx_reqs = rte_zmalloc_socket("txq->empty_tx_reqs",
+		sizeof(uint16_t) * txq->ring_size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (!txq->empty_tx_reqs) {
-		PMD_DRV_LOG(ERR, "failed to alloc mem for tx reqs\n");
+		PMD_DRV_LOG(ERR,
+			"Failed to allocate memory for empty Tx requests\n");
 		rte_free(txq->tx_buffer_info);
 		return -ENOMEM;
 	}
 
 	txq->push_buf_intermediate_buf =
-		rte_zmalloc("txq->push_buf_intermediate_buf",
-			    txq->tx_max_header_size,
-			    RTE_CACHE_LINE_SIZE);
+		rte_zmalloc_socket("txq->push_buf_intermediate_buf",
+			txq->tx_max_header_size,
+			RTE_CACHE_LINE_SIZE,
+			socket_id);
 	if (!txq->push_buf_intermediate_buf) {
-		PMD_DRV_LOG(ERR, "failed to alloc push buff for LLQ\n");
+		PMD_DRV_LOG(ERR, "Failed to alloc push buffer for LLQ\n");
 		rte_free(txq->tx_buffer_info);
 		rte_free(txq->empty_tx_reqs);
 		return -ENOMEM;
@@ -1352,10 +1555,21 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev,
 	for (i = 0; i < txq->ring_size; i++)
 		txq->empty_tx_reqs[i] = i;
 
-	if (tx_conf != NULL) {
-		txq->offloads =
-			tx_conf->offloads | dev->data->dev_conf.txmode.offloads;
+	txq->offloads = tx_conf->offloads | dev->data->dev_conf.txmode.offloads;
+
+	/* Check if caller provided the Tx cleanup threshold value. */
+	if (tx_conf->tx_free_thresh != 0) {
+		txq->tx_free_thresh = tx_conf->tx_free_thresh;
+	} else {
+		dyn_thresh = txq->ring_size -
+			txq->ring_size / ENA_REFILL_THRESH_DIVIDER;
+		txq->tx_free_thresh = RTE_MAX(dyn_thresh,
+			txq->ring_size - ENA_REFILL_THRESH_PACKET);
 	}
+
+	txq->missing_tx_completion_threshold =
+		RTE_MIN(txq->ring_size / 2, ENA_DEFAULT_MISSING_COMP);
+
 	/* Store pointer to this queue in upper layer */
 	txq->configured = 1;
 	dev->data->tx_queues[queue_idx] = txq;
@@ -1367,32 +1581,33 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev,
 			      uint16_t queue_idx,
 			      uint16_t nb_desc,
 			      unsigned int socket_id,
-			      __rte_unused const struct rte_eth_rxconf *rx_conf,
+			      const struct rte_eth_rxconf *rx_conf,
 			      struct rte_mempool *mp)
 {
 	struct ena_adapter *adapter = dev->data->dev_private;
 	struct ena_ring *rxq = NULL;
 	size_t buffer_size;
 	int i;
+	uint16_t dyn_thresh;
 
 	rxq = &adapter->rx_ring[queue_idx];
 	if (rxq->configured) {
 		PMD_DRV_LOG(CRIT,
-			"API violation. Queue %d is already configured\n",
+			"API violation. Queue[%d] is already configured\n",
 			queue_idx);
 		return ENA_COM_FAULT;
 	}
 
 	if (!rte_is_power_of_2(nb_desc)) {
 		PMD_DRV_LOG(ERR,
-			"Unsupported size of RX queue: %d is not a power of 2.\n",
+			"Unsupported size of Rx queue: %d is not a power of 2.\n",
 			nb_desc);
 		return -EINVAL;
 	}
 
 	if (nb_desc > adapter->max_rx_ring_size) {
 		PMD_DRV_LOG(ERR,
-			"Unsupported size of RX queue (max size: %d)\n",
+			"Unsupported size of Rx queue (max size: %d)\n",
 			adapter->max_rx_ring_size);
 		return -EINVAL;
 	}
@@ -1401,7 +1616,7 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev,
 	buffer_size = rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM;
 	if (buffer_size < ENA_RX_BUF_MIN_SIZE) {
 		PMD_DRV_LOG(ERR,
-			"Unsupported size of RX buffer: %zu (min size: %d)\n",
+			"Unsupported size of Rx buffer: %zu (min size: %d)\n",
 			buffer_size, ENA_RX_BUF_MIN_SIZE);
 		return -EINVAL;
 	}
@@ -1414,30 +1629,35 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev,
 	rxq->numa_socket_id = socket_id;
 	rxq->mb_pool = mp;
 
-	rxq->rx_buffer_info = rte_zmalloc("rxq->buffer_info",
+	rxq->rx_buffer_info = rte_zmalloc_socket("rxq->buffer_info",
 		sizeof(struct ena_rx_buffer) * nb_desc,
-		RTE_CACHE_LINE_SIZE);
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (!rxq->rx_buffer_info) {
-		PMD_DRV_LOG(ERR, "failed to alloc mem for rx buffer info\n");
+		PMD_DRV_LOG(ERR,
+			"Failed to allocate memory for Rx buffer info\n");
 		return -ENOMEM;
 	}
 
-	rxq->rx_refill_buffer = rte_zmalloc("rxq->rx_refill_buffer",
-					    sizeof(struct rte_mbuf *) * nb_desc,
-					    RTE_CACHE_LINE_SIZE);
-
+	rxq->rx_refill_buffer = rte_zmalloc_socket("rxq->rx_refill_buffer",
+		sizeof(struct rte_mbuf *) * nb_desc,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (!rxq->rx_refill_buffer) {
-		PMD_DRV_LOG(ERR, "failed to alloc mem for rx refill buffer\n");
+		PMD_DRV_LOG(ERR,
+			"Failed to allocate memory for Rx refill buffer\n");
 		rte_free(rxq->rx_buffer_info);
 		rxq->rx_buffer_info = NULL;
 		return -ENOMEM;
 	}
 
-	rxq->empty_rx_reqs = rte_zmalloc("rxq->empty_rx_reqs",
-					 sizeof(uint16_t) * nb_desc,
-					 RTE_CACHE_LINE_SIZE);
+	rxq->empty_rx_reqs = rte_zmalloc_socket("rxq->empty_rx_reqs",
+		sizeof(uint16_t) * nb_desc,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
 	if (!rxq->empty_rx_reqs) {
-		PMD_DRV_LOG(ERR, "failed to alloc mem for empty rx reqs\n");
+		PMD_DRV_LOG(ERR,
+			"Failed to allocate memory for empty Rx requests\n");
 		rte_free(rxq->rx_buffer_info);
 		rxq->rx_buffer_info = NULL;
 		rte_free(rxq->rx_refill_buffer);
@@ -1448,6 +1668,16 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev,
 	for (i = 0; i < nb_desc; i++)
 		rxq->empty_rx_reqs[i] = i;
 
+	rxq->offloads = rx_conf->offloads | dev->data->dev_conf.rxmode.offloads;
+
+	if (rx_conf->rx_free_thresh != 0) {
+		rxq->rx_free_thresh = rx_conf->rx_free_thresh;
+	} else {
+		dyn_thresh = rxq->ring_size / ENA_REFILL_THRESH_DIVIDER;
+		rxq->rx_free_thresh = RTE_MIN(dyn_thresh,
+			(uint16_t)(ENA_REFILL_THRESH_PACKET));
+	}
+
 	/* Store pointer to this queue in upper layer */
 	rxq->configured = 1;
 	dev->data->rx_queues[queue_idx] = rxq;
@@ -1468,7 +1698,7 @@ static int ena_add_single_rx_desc(struct ena_com_io_sq *io_sq,
 	/* pass resource to device */
 	rc = ena_com_add_single_rx_desc(io_sq, &ebuf, id);
 	if (unlikely(rc != 0))
-		PMD_DRV_LOG(WARNING, "failed adding rx desc\n");
+		PMD_RX_LOG(WARNING, "Failed adding Rx desc\n");
 
 	return rc;
 }
@@ -1478,23 +1708,28 @@ static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count)
 	unsigned int i;
 	int rc;
 	uint16_t next_to_use = rxq->next_to_use;
-	uint16_t in_use, req_id;
+	uint16_t req_id;
+#ifdef RTE_ETHDEV_DEBUG_RX
+	uint16_t in_use;
+#endif
 	struct rte_mbuf **mbufs = rxq->rx_refill_buffer;
 
 	if (unlikely(!count))
 		return 0;
 
+#ifdef RTE_ETHDEV_DEBUG_RX
 	in_use = rxq->ring_size - 1 -
 		ena_com_free_q_entries(rxq->ena_com_io_sq);
-	ena_assert_msg(((in_use + count) < rxq->ring_size),
-		"bad ring state\n");
+	if (unlikely((in_use + count) >= rxq->ring_size))
+		PMD_RX_LOG(ERR, "Bad Rx ring state\n");
+#endif
 
 	/* get resources for incoming packets */
 	rc = rte_pktmbuf_alloc_bulk(rxq->mb_pool, mbufs, count);
 	if (unlikely(rc < 0)) {
 		rte_atomic64_inc(&rxq->adapter->drv_stats->rx_nombuf);
 		++rxq->rx_stats.mbuf_alloc_fail;
-		PMD_RX_LOG(DEBUG, "there are no enough free buffers");
+		PMD_RX_LOG(DEBUG, "There are not enough free buffers\n");
 		return 0;
 	}
 
@@ -1517,8 +1752,9 @@ static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count)
 	}
 
 	if (unlikely(i < count)) {
-		PMD_DRV_LOG(WARNING, "refilled rx qid %d with only %d "
-			"buffers (from %d)\n", rxq->id, i, count);
+		PMD_RX_LOG(WARNING,
+			"Refilled Rx queue[%d] with only %d/%d buffers\n",
+			rxq->id, i, count);
 		rte_pktmbuf_free_bulk(&mbufs[i], count - i);
 		++rxq->rx_stats.refill_partial;
 	}
@@ -1534,10 +1770,28 @@ static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count)
 	return i;
 }
 
-static int ena_device_init(struct ena_com_dev *ena_dev,
-			   struct ena_com_dev_get_features_ctx *get_feat_ctx,
-			   bool *wd_state)
+static size_t ena_get_metrics_entries(struct ena_adapter *adapter)
+{
+	struct ena_com_dev *ena_dev = &adapter->ena_dev;
+	size_t metrics_num = 0;
+
+	if (ena_com_get_cap(ena_dev, ENA_ADMIN_CUSTOMER_METRICS))
+		metrics_num = ENA_STATS_ARRAY_METRICS;
+	else if (ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS))
+		metrics_num = ENA_STATS_ARRAY_METRICS_LEGACY;
+	PMD_DRV_LOG(NOTICE, "0x%x customer metrics are supported\n", (unsigned int)metrics_num);
+	if (metrics_num > ENA_MAX_CUSTOMER_METRICS) {
+		PMD_DRV_LOG(NOTICE, "Not enough space for the requested customer metrics\n");
+		metrics_num = ENA_MAX_CUSTOMER_METRICS;
+	}
+	return metrics_num;
+}
+
+static int ena_device_init(struct ena_adapter *adapter,
+			   struct rte_pci_device *pdev,
+			   struct ena_com_dev_get_features_ctx *get_feat_ctx)
 {
+	struct ena_com_dev *ena_dev = &adapter->ena_dev;
 	uint32_t aenq_groups;
 	int rc;
 	bool readless_supported;
@@ -1545,29 +1799,27 @@ static int ena_device_init(struct ena_com_dev *ena_dev,
 	/* Initialize mmio registers */
 	rc = ena_com_mmio_reg_read_request_init(ena_dev);
 	if (rc) {
-		PMD_DRV_LOG(ERR, "failed to init mmio read less\n");
+		PMD_DRV_LOG(ERR, "Failed to init MMIO read less\n");
 		return rc;
 	}
 
 	/* The PCIe configuration space revision id indicate if mmio reg
 	 * read is disabled.
 	 */
-	readless_supported =
-		!(((struct rte_pci_device *)ena_dev->dmadev)->id.class_id
-			       & ENA_MMIO_DISABLE_REG_READ);
+	readless_supported = !(pdev->id.class_id & ENA_MMIO_DISABLE_REG_READ);
 	ena_com_set_mmio_read_mode(ena_dev, readless_supported);
 
 	/* reset device */
 	rc = ena_com_dev_reset(ena_dev, ENA_REGS_RESET_NORMAL);
 	if (rc) {
-		PMD_DRV_LOG(ERR, "cannot reset device\n");
+		PMD_DRV_LOG(ERR, "Cannot reset device\n");
 		goto err_mmio_read_less;
 	}
 
 	/* check FW version */
 	rc = ena_com_validate_version(ena_dev);
 	if (rc) {
-		PMD_DRV_LOG(ERR, "device version is too low\n");
+		PMD_DRV_LOG(ERR, "Device version is too low\n");
 		goto err_mmio_read_less;
 	}
 
@@ -1577,7 +1829,7 @@ static int ena_device_init(struct ena_com_dev *ena_dev,
 	rc = ena_com_admin_init(ena_dev, &aenq_handlers);
 	if (rc) {
 		PMD_DRV_LOG(ERR,
-			"cannot initialize ena admin queue with device\n");
+			"Cannot initialize ENA admin queue\n");
 		goto err_mmio_read_less;
 	}
 
@@ -1593,7 +1845,7 @@ static int ena_device_init(struct ena_com_dev *ena_dev,
 	rc = ena_com_get_dev_attr_feat(ena_dev, get_feat_ctx);
 	if (rc) {
 		PMD_DRV_LOG(ERR,
-			"cannot get attribute for ena device rc= %d\n", rc);
+			"Cannot get attribute for ENA device, rc: %d\n", rc);
 		goto err_admin_init;
 	}
 
@@ -1604,13 +1856,10 @@ static int ena_device_init(struct ena_com_dev *ena_dev,
 		      BIT(ENA_ADMIN_WARNING);
 
 	aenq_groups &= get_feat_ctx->aenq.supported_groups;
-	rc = ena_com_set_aenq_config(ena_dev, aenq_groups);
-	if (rc) {
-		PMD_DRV_LOG(ERR, "Cannot configure aenq groups rc: %d\n", rc);
-		goto err_admin_init;
-	}
 
-	*wd_state = !!(aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE));
+	adapter->all_aenq_groups = aenq_groups;
+	/* The actual supported number of metrics is negotiated with the device at runtime */
+	adapter->metrics_num = ena_get_metrics_entries(adapter);
 
 	return 0;
 
@@ -1625,17 +1874,18 @@ static int ena_device_init(struct ena_com_dev *ena_dev,
 
 static void ena_interrupt_handler_rte(void *cb_arg)
 {
-	struct ena_adapter *adapter = cb_arg;
+	struct rte_eth_dev *dev = cb_arg;
+	struct ena_adapter *adapter = dev->data->dev_private;
 	struct ena_com_dev *ena_dev = &adapter->ena_dev;
 
 	ena_com_admin_q_comp_intr_handler(ena_dev);
 	if (likely(adapter->state != ENA_ADAPTER_STATE_CLOSED))
-		ena_com_aenq_intr_handler(ena_dev, adapter);
+		ena_com_aenq_intr_handler(ena_dev, dev);
 }
 
 static void check_for_missing_keep_alive(struct ena_adapter *adapter)
 {
-	if (!adapter->wd_state)
+	if (!(adapter->active_aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE)))
 		return;
 
 	if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT)
@@ -1653,22 +1903,104 @@ static void check_for_missing_keep_alive(struct ena_adapter *adapter)
 static void check_for_admin_com_state(struct ena_adapter *adapter)
 {
 	if (unlikely(!ena_com_get_admin_running_state(&adapter->ena_dev))) {
-		PMD_DRV_LOG(ERR, "ENA admin queue is not in running state!\n");
+		PMD_DRV_LOG(ERR, "ENA admin queue is not in running state\n");
 		ena_trigger_reset(adapter, ENA_REGS_RESET_ADMIN_TO);
 	}
 }
 
+static int check_for_tx_completion_in_queue(struct ena_adapter *adapter,
+					    struct ena_ring *tx_ring)
+{
+	struct ena_tx_buffer *tx_buf;
+	uint64_t timestamp;
+	uint64_t completion_delay;
+	uint32_t missed_tx = 0;
+	unsigned int i;
+	int rc = 0;
+
+	for (i = 0; i < tx_ring->ring_size; ++i) {
+		tx_buf = &tx_ring->tx_buffer_info[i];
+		timestamp = tx_buf->timestamp;
+
+		if (timestamp == 0)
+			continue;
+
+		completion_delay = rte_get_timer_cycles() - timestamp;
+		if (completion_delay > adapter->missing_tx_completion_to) {
+			if (unlikely(!tx_buf->print_once)) {
+				PMD_TX_LOG(WARNING,
+					"Found a Tx that wasn't completed on time, qid %d, index %d. "
+					"Missing Tx outstanding for %" PRIu64 " msecs.\n",
+					tx_ring->id, i,	completion_delay /
+					rte_get_timer_hz() * 1000);
+				tx_buf->print_once = true;
+			}
+			++missed_tx;
+		}
+	}
+
+	if (unlikely(missed_tx > tx_ring->missing_tx_completion_threshold)) {
+		PMD_DRV_LOG(ERR,
+			"The number of lost Tx completions is above the threshold (%d > %d). "
+			"Trigger the device reset.\n",
+			missed_tx,
+			tx_ring->missing_tx_completion_threshold);
+		adapter->reset_reason = ENA_REGS_RESET_MISS_TX_CMPL;
+		adapter->trigger_reset = true;
+		rc = -EIO;
+	}
+
+	tx_ring->tx_stats.missed_tx += missed_tx;
+
+	return rc;
+}
+
+static void check_for_tx_completions(struct ena_adapter *adapter)
+{
+	struct ena_ring *tx_ring;
+	uint64_t tx_cleanup_delay;
+	size_t qid;
+	int budget;
+	uint16_t nb_tx_queues = adapter->edev_data->nb_tx_queues;
+
+	if (adapter->missing_tx_completion_to == ENA_HW_HINTS_NO_TIMEOUT)
+		return;
+
+	nb_tx_queues = adapter->edev_data->nb_tx_queues;
+	budget = adapter->missing_tx_completion_budget;
+
+	qid = adapter->last_tx_comp_qid;
+	while (budget-- > 0) {
+		tx_ring = &adapter->tx_ring[qid];
+
+		/* Tx cleanup is called only by the burst function and can be
+		 * called dynamically by the application. Also cleanup is
+		 * limited by the threshold. To avoid false detection of the
+		 * missing HW Tx completion, get the delay since last cleanup
+		 * function was called.
+		 */
+		tx_cleanup_delay = rte_get_timer_cycles() -
+			tx_ring->last_cleanup_ticks;
+		if (tx_cleanup_delay < adapter->tx_cleanup_stall_delay)
+			check_for_tx_completion_in_queue(adapter, tx_ring);
+		qid = (qid + 1) % nb_tx_queues;
+	}
+
+	adapter->last_tx_comp_qid = qid;
+}
+
 static void ena_timer_wd_callback(__rte_unused struct rte_timer *timer,
 				  void *arg)
 {
-	struct ena_adapter *adapter = arg;
-	struct rte_eth_dev *dev = adapter->rte_dev;
+	struct rte_eth_dev *dev = arg;
+	struct ena_adapter *adapter = dev->data->dev_private;
 
 	if (unlikely(adapter->trigger_reset))
 		return;
 
 	check_for_missing_keep_alive(adapter);
 	check_for_admin_com_state(adapter);
+	check_for_tx_completions(adapter);
 
 	if (unlikely(adapter->trigger_reset)) {
 		PMD_DRV_LOG(ERR, "Trigger reset is on\n");
@@ -1708,6 +2040,14 @@ ena_set_queues_placement_policy(struct ena_adapter *adapter,
 	int rc;
 	u32 llq_feature_mask;
 
+	if (!adapter->enable_llq) {
+		PMD_DRV_LOG(WARNING,
+			"NOTE: LLQ has been disabled as per user's request. "
+			"This may lead to a huge performance degradation!\n");
+		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+		return 0;
+	}
+
 	llq_feature_mask = 1 << ENA_ADMIN_LLQ;
 	if (!(ena_dev->supported_features & llq_feature_mask)) {
 		PMD_DRV_LOG(INFO,
@@ -1725,8 +2065,8 @@ ena_set_queues_placement_policy(struct ena_adapter *adapter,
 
 	rc = ena_com_config_dev_mode(ena_dev, llq, llq_default_configurations);
 	if (unlikely(rc)) {
-		PMD_INIT_LOG(WARNING, "Failed to config dev mode. "
-			"Fallback to host mode policy.");
+		PMD_INIT_LOG(WARNING,
+			"Failed to config dev mode. Fallback to host mode policy.\n");
 		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
 		return 0;
 	}
@@ -1770,7 +2110,7 @@ static uint32_t ena_calc_max_io_queue_num(struct ena_com_dev *ena_dev,
 	max_num_io_queues = RTE_MIN(max_num_io_queues, io_tx_cq_num);
 
 	if (unlikely(max_num_io_queues == 0)) {
-		PMD_DRV_LOG(ERR, "Number of IO queues should not be 0\n");
+		PMD_DRV_LOG(ERR, "Number of IO queues cannot not be 0\n");
 		return -EFAULT;
 	}
 
@@ -1821,6 +2161,24 @@ ena_set_offloads(struct ena_offloads *offloads,
 		offloads->rx_offloads |= ENA_RX_RSS_HASH;
 }
 
+static int ena_init_once(void)
+{
+	static bool init_done;
+
+	if (init_done)
+		return 0;
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		/* Init timer subsystem for the ENA timer service. */
+		rte_timer_subsystem_init();
+		/* Register handler for requests from secondary processes. */
+		rte_mp_action_register(ENA_MP_NAME, ena_mp_primary_handle);
+	}
+
+	init_done = true;
+	return 0;
+}
+
 static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 {
 	struct ena_calc_queue_size_ctx calc_queue_ctx = { 0 };
@@ -1835,13 +2193,16 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 	int rc;
 	static int adapters_found;
 	bool disable_meta_caching;
-	bool wd_state = false;
 
 	eth_dev->dev_ops = &ena_dev_ops;
 	eth_dev->rx_pkt_burst = &eth_ena_recv_pkts;
 	eth_dev->tx_pkt_burst = &eth_ena_xmit_pkts;
 	eth_dev->tx_pkt_prepare = &eth_ena_prep_pkts;
 
+	rc = ena_init_once();
+	if (rc != 0)
+		return rc;
+
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 		return 0;
 
@@ -1850,13 +2211,11 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 	memset(adapter, 0, sizeof(struct ena_adapter));
 	ena_dev = &adapter->ena_dev;
 
-	adapter->rte_eth_dev_data = eth_dev->data;
-	adapter->rte_dev = eth_dev;
+	adapter->edev_data = eth_dev->data;
 
 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
-	adapter->pdev = pci_dev;
 
-	PMD_INIT_LOG(INFO, "Initializing %x:%x:%x.%d",
+	PMD_INIT_LOG(INFO, "Initializing " PCI_PRI_FMT "\n",
 		     pci_dev->addr.domain,
 		     pci_dev->addr.bus,
 		     pci_dev->addr.devid,
@@ -1868,39 +2227,55 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 	adapter->dev_mem_base = pci_dev->mem_resource[ENA_MEM_BAR].addr;
 
 	if (!adapter->regs) {
-		PMD_INIT_LOG(CRIT, "Failed to access registers BAR(%d)",
+		PMD_INIT_LOG(CRIT, "Failed to access registers BAR(%d)\n",
 			     ENA_REGS_BAR);
 		return -ENXIO;
 	}
 
 	ena_dev->reg_bar = adapter->regs;
-	ena_dev->dmadev = adapter->pdev;
+	/* Pass device data as a pointer which can be passed to the IO functions
+	 * by the ena_com (for example - the memory allocation).
+	 */
+	ena_dev->dmadev = eth_dev->data;
 
 	adapter->id_number = adapters_found;
 
 	snprintf(adapter->name, ENA_NAME_MAX_LEN, "ena_%d",
 		 adapter->id_number);
 
+	/* Assign default devargs values */
+	adapter->missing_tx_completion_to = ENA_TX_TIMEOUT;
+	adapter->enable_llq = true;
+	adapter->use_large_llq_hdr = false;
+
 	rc = ena_parse_devargs(adapter, pci_dev->device.devargs);
 	if (rc != 0) {
 		PMD_INIT_LOG(CRIT, "Failed to parse devargs\n");
 		goto err;
 	}
+	rc = ena_com_allocate_customer_metrics_buffer(ena_dev);
+	if (rc != 0) {
+		PMD_INIT_LOG(CRIT, "Failed to allocate customer metrics buffer\n");
+		goto err;
+	}
 
 	/* device specific initialization routine */
-	rc = ena_device_init(ena_dev, &get_feat_ctx, &wd_state);
+	rc = ena_device_init(adapter, pci_dev, &get_feat_ctx);
 	if (rc) {
-		PMD_INIT_LOG(CRIT, "Failed to init ENA device");
-		goto err;
+		PMD_INIT_LOG(CRIT, "Failed to init ENA device\n");
+		goto err_metrics_delete;
 	}
-	adapter->wd_state = wd_state;
+
+	/* Check if device supports LSC */
+	if (!(adapter->all_aenq_groups & BIT(ENA_ADMIN_LINK_CHANGE)))
+		adapter->edev_data->dev_flags &= ~RTE_ETH_DEV_INTR_LSC;
 
 	set_default_llq_configurations(&llq_config, &get_feat_ctx.llq,
 		adapter->use_large_llq_hdr);
 	rc = ena_set_queues_placement_policy(adapter, ena_dev,
 					     &get_feat_ctx.llq, &llq_config);
 	if (unlikely(rc)) {
-		PMD_INIT_LOG(CRIT, "Failed to set placement policy");
+		PMD_INIT_LOG(CRIT, "Failed to set placement policy\n");
 		return rc;
 	}
 
@@ -1951,26 +2326,31 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 			get_feat_ctx.dev_attr.mac_addr,
 			(struct rte_ether_addr *)adapter->mac_addr);
 
+	rc = ena_com_rss_init(ena_dev, ENA_RX_RSS_TABLE_LOG_SIZE);
+	if (unlikely(rc != 0)) {
+		PMD_DRV_LOG(ERR, "Failed to initialize RSS in ENA device\n");
+		goto err_delete_debug_area;
+	}
+
 	adapter->drv_stats = rte_zmalloc("adapter stats",
 					 sizeof(*adapter->drv_stats),
 					 RTE_CACHE_LINE_SIZE);
 	if (!adapter->drv_stats) {
-		PMD_DRV_LOG(ERR, "failed to alloc mem for adapter stats\n");
+		PMD_DRV_LOG(ERR,
+			"Failed to allocate memory for adapter statistics\n");
 		rc = -ENOMEM;
-		goto err_delete_debug_area;
+		goto err_rss_destroy;
 	}
 
 	rte_spinlock_init(&adapter->admin_lock);
 
 	rte_intr_callback_register(intr_handle,
 				   ena_interrupt_handler_rte,
-				   adapter);
+				   eth_dev);
 	rte_intr_enable(intr_handle);
 	ena_com_set_admin_polling_mode(ena_dev, false);
 	ena_com_admin_aenq_enable(ena_dev);
 
-	if (adapters_found == 0)
-		rte_timer_subsystem_init();
 	rte_timer_init(&adapter->timer_wd);
 
 	adapters_found++;
@@ -1978,13 +2358,16 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 
 	return 0;
 
+err_rss_destroy:
+	ena_com_rss_destroy(ena_dev);
 err_delete_debug_area:
 	ena_com_delete_debug_area(ena_dev);
 
 err_device_destroy:
 	ena_com_delete_host_info(ena_dev);
 	ena_com_admin_destroy(ena_dev);
-
+err_metrics_delete:
+	ena_com_delete_customer_metrics_buffer(ena_dev);
 err:
 	return rc;
 }
@@ -2002,6 +2385,8 @@ static void ena_destroy_device(struct rte_eth_dev *eth_dev)
 	if (adapter->state != ENA_ADAPTER_STATE_CLOSED)
 		ena_close(eth_dev);
 
+	ena_com_rss_destroy(ena_dev);
+
 	ena_com_delete_debug_area(ena_dev);
 	ena_com_delete_host_info(ena_dev);
 
@@ -2009,6 +2394,7 @@ static void ena_destroy_device(struct rte_eth_dev *eth_dev)
 	ena_com_wait_for_abort_completion(ena_dev);
 	ena_com_admin_destroy(ena_dev);
 	ena_com_mmio_reg_read_request_destroy(ena_dev);
+	ena_com_delete_customer_metrics_buffer(ena_dev);
 
 	adapter->state = ENA_ADAPTER_STATE_FREE;
 }
@@ -2026,6 +2412,7 @@ static int eth_ena_dev_uninit(struct rte_eth_dev *eth_dev)
 static int ena_dev_configure(struct rte_eth_dev *dev)
 {
 	struct ena_adapter *adapter = dev->data->dev_private;
+	int rc;
 
 	adapter->state = ENA_ADAPTER_STATE_CONFIG;
 
@@ -2038,7 +2425,22 @@ static int ena_dev_configure(struct rte_eth_dev *dev)
 	 */
 	dev->data->scattered_rx = 1;
 
-	return 0;
+	adapter->last_tx_comp_qid = 0;
+
+	adapter->missing_tx_completion_budget =
+		RTE_MIN(ENA_MONITORED_TX_QUEUES, dev->data->nb_tx_queues);
+
+	/* To avoid detection of the spurious Tx completion timeout due to
+	 * application not calling the Tx cleanup function, set timeout for the
+	 * Tx queue which should be half of the missing completion timeout for a
+	 * safety. If there will be a lot of missing Tx completions in the
+	 * queue, they will be detected sooner or later.
+	 */
+	adapter->tx_cleanup_stall_delay = adapter->missing_tx_completion_to / 2;
+
+	rc = ena_configure_aenq(adapter);
+
+	return rc;
 }
 
 static void ena_init_rings(struct ena_adapter *adapter,
@@ -2107,6 +2509,8 @@ static uint64_t ena_get_tx_port_offloads(struct ena_adapter *adapter)
 
 	port_offloads |= DEV_TX_OFFLOAD_MULTI_SEGS;
 
+	port_offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+
 	return port_offloads;
 }
 
@@ -2119,9 +2523,12 @@ static uint64_t ena_get_rx_queue_offloads(struct ena_adapter *adapter)
 
 static uint64_t ena_get_tx_queue_offloads(struct ena_adapter *adapter)
 {
+	uint64_t queue_offloads = 0;
 	RTE_SET_USED(adapter);
 
-	return 0;
+	queue_offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+
+	return queue_offloads;
 }
 
 static int ena_infos_get(struct rte_eth_dev *dev,
@@ -2153,11 +2560,14 @@ static int ena_infos_get(struct rte_eth_dev *dev,
 	dev_info->rx_queue_offload_capa = ena_get_rx_queue_offloads(adapter);
 	dev_info->tx_queue_offload_capa = ena_get_tx_queue_offloads(adapter);
 
-	dev_info->flow_type_rss_offloads = ETH_RSS_IP | ETH_RSS_TCP |
-					   ETH_RSS_UDP;
+	dev_info->flow_type_rss_offloads = ENA_ALL_RSS_HF;
+	dev_info->hash_key_size = ENA_HASH_KEY_SIZE;
 
 	dev_info->min_rx_bufsize = ENA_MIN_FRAME_LEN;
-	dev_info->max_rx_pktlen  = adapter->max_mtu;
+	dev_info->max_rx_pktlen  = adapter->max_mtu + RTE_ETHER_HDR_LEN +
+		RTE_ETHER_CRC_LEN;
+	dev_info->min_mtu = ENA_MIN_MTU;
+	dev_info->max_mtu = adapter->max_mtu;
 	dev_info->max_mac_addrs = 1;
 
 	dev_info->max_rx_queues = adapter->max_num_io_queues;
@@ -2291,20 +2701,24 @@ static uint16_t eth_ena_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 {
 	struct ena_ring *rx_ring = (struct ena_ring *)(rx_queue);
 	unsigned int free_queue_entries;
-	unsigned int refill_threshold;
 	uint16_t next_to_clean = rx_ring->next_to_clean;
 	uint16_t descs_in_use;
 	struct rte_mbuf *mbuf;
 	uint16_t completed;
 	struct ena_com_rx_ctx ena_rx_ctx;
 	int i, rc = 0;
+	bool fill_hash;
 
+#ifdef RTE_ETHDEV_DEBUG_RX
 	/* Check adapter state */
 	if (unlikely(rx_ring->adapter->state != ENA_ADAPTER_STATE_RUNNING)) {
-		PMD_DRV_LOG(ALERT,
+		PMD_RX_LOG(ALERT,
 			"Trying to receive pkts while device is NOT running\n");
 		return 0;
 	}
+#endif
+
+	fill_hash = rx_ring->offloads & DEV_RX_OFFLOAD_RSS_HASH;
 
 	descs_in_use = rx_ring->ring_size -
 		ena_com_free_q_entries(rx_ring->ena_com_io_sq) - 1;
@@ -2320,7 +2734,9 @@ static uint16_t eth_ena_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 				    rx_ring->ena_com_io_sq,
 				    &ena_rx_ctx);
 		if (unlikely(rc)) {
-			PMD_DRV_LOG(ERR, "ena_com_rx_pkt error %d\n", rc);
+			PMD_RX_LOG(ERR,
+				"Failed to get the packet from the device, rc: %d\n",
+				rc);
 			if (rc == ENA_COM_NO_SPACE) {
 				++rx_ring->rx_stats.bad_desc_num;
 				ena_trigger_reset(rx_ring->adapter,
@@ -2349,13 +2765,11 @@ static uint16_t eth_ena_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 		}
 
 		/* fill mbuf attributes if any */
-		ena_rx_mbuf_prepare(mbuf, &ena_rx_ctx);
+		ena_rx_mbuf_prepare(rx_ring, mbuf, &ena_rx_ctx, fill_hash);
 
 		if (unlikely(mbuf->ol_flags &
-				(PKT_RX_IP_CKSUM_BAD | PKT_RX_L4_CKSUM_BAD))) {
+				(PKT_RX_IP_CKSUM_BAD | PKT_RX_L4_CKSUM_BAD)))
 			rte_atomic64_inc(&rx_ring->adapter->drv_stats->ierrors);
-			++rx_ring->rx_stats.bad_csum;
-		}
 
 		rx_pkts[completed] = mbuf;
 		rx_ring->rx_stats.bytes += mbuf->pkt_len;
@@ -2365,13 +2779,9 @@ static uint16_t eth_ena_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 	rx_ring->next_to_clean = next_to_clean;
 
 	free_queue_entries = ena_com_free_q_entries(rx_ring->ena_com_io_sq);
-	refill_threshold =
-		RTE_MIN(rx_ring->ring_size / ENA_REFILL_THRESH_DIVIDER,
-		(unsigned int)ENA_REFILL_THRESH_PACKET);
 
 	/* Burst refill to save doorbells, memory barriers, const interval */
-	if (free_queue_entries > refill_threshold) {
-		ena_com_update_dev_comp_head(rx_ring->ena_com_io_cq);
+	if (free_queue_entries >= rx_ring->rx_free_thresh) {
 		ena_populate_rx_queue(rx_ring, free_queue_entries);
 	}
 
@@ -2414,6 +2824,17 @@ eth_ena_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 			return i;
 		}
 
+		if (unlikely(m->nb_segs >= tx_ring->sgl_size &&
+		    !(tx_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV &&
+		      m->nb_segs == tx_ring->sgl_size &&
+		      m->data_len < tx_ring->tx_max_header_size))) {
+			PMD_TX_LOG(DEBUG,
+				"mbuf[%" PRIu32 "] has too many segments: %" PRIu16 "\n",
+				i, m->nb_segs);
+			rte_errno = EINVAL;
+			return i;
+		}
+
 #ifdef RTE_LIBRTE_ETHDEV_DEBUG
 		/* Check if requested offload is also enabled for the queue */
 		if ((ol_flags & PKT_TX_IP_CKSUM &&
@@ -2546,56 +2967,6 @@ static void ena_update_hints(struct ena_adapter *adapter,
 	}
 }
 
-static int ena_check_space_and_linearize_mbuf(struct ena_ring *tx_ring,
-					      struct rte_mbuf *mbuf)
-{
-	struct ena_com_dev *ena_dev;
-	int num_segments, header_len, rc;
-
-	ena_dev = &tx_ring->adapter->ena_dev;
-	num_segments = mbuf->nb_segs;
-	header_len = mbuf->data_len;
-
-	if (likely(num_segments < tx_ring->sgl_size))
-		goto checkspace;
-
-	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV &&
-	    (num_segments == tx_ring->sgl_size) &&
-	    (header_len < tx_ring->tx_max_header_size))
-		goto checkspace;
-
-	/* Checking for space for 2 additional metadata descriptors due to
-	 * possible header split and metadata descriptor. Linearization will
-	 * be needed so we reduce the segments number from num_segments to 1
-	 */
-	if (!ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq, 3)) {
-		PMD_DRV_LOG(DEBUG, "Not enough space in the tx queue\n");
-		return ENA_COM_NO_MEM;
-	}
-	++tx_ring->tx_stats.linearize;
-	rc = rte_pktmbuf_linearize(mbuf);
-	if (unlikely(rc)) {
-		PMD_DRV_LOG(WARNING, "Mbuf linearize failed\n");
-		rte_atomic64_inc(&tx_ring->adapter->drv_stats->ierrors);
-		++tx_ring->tx_stats.linearize_failed;
-		return rc;
-	}
-
-	return 0;
-
-checkspace:
-	/* Checking for space for 2 additional metadata descriptors due to
-	 * possible header split and metadata descriptor
-	 */
-	if (!ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
-					  num_segments + 2)) {
-		PMD_DRV_LOG(DEBUG, "Not enough space in the tx queue\n");
-		return ENA_COM_NO_MEM;
-	}
-
-	return 0;
-}
-
 static void ena_tx_map_mbuf(struct ena_ring *tx_ring,
 	struct ena_tx_buffer *tx_info,
 	struct rte_mbuf *mbuf,
@@ -2680,15 +3051,21 @@ static int ena_xmit_mbuf(struct ena_ring *tx_ring, struct rte_mbuf *mbuf)
 	int nb_hw_desc;
 	int rc;
 
-	rc = ena_check_space_and_linearize_mbuf(tx_ring, mbuf);
-	if (unlikely(rc))
-		return rc;
+	/* Checking for space for 2 additional metadata descriptors due to
+	 * possible header split and metadata descriptor
+	 */
+	if (!ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+					  mbuf->nb_segs + 2)) {
+		PMD_DRV_LOG(DEBUG, "Not enough space in the tx queue\n");
+		return ENA_COM_NO_MEM;
+	}
 
 	next_to_use = tx_ring->next_to_use;
 
 	req_id = tx_ring->empty_tx_reqs[next_to_use];
 	tx_info = &tx_ring->tx_buffer_info[req_id];
 	tx_info->num_of_bufs = 0;
+	RTE_ASSERT(tx_info->mbuf == NULL);
 
 	ena_tx_map_mbuf(tx_ring, tx_info, mbuf, &push_header, &header_len);
 
@@ -2704,8 +3081,8 @@ static int ena_xmit_mbuf(struct ena_ring *tx_ring, struct rte_mbuf *mbuf)
 
 	if (unlikely(ena_com_is_doorbell_needed(tx_ring->ena_com_io_sq,
 			&ena_tx_ctx))) {
-		PMD_DRV_LOG(DEBUG,
-			"llq tx max burst size of queue %d achieved, writing doorbell to send burst\n",
+		PMD_TX_LOG(DEBUG,
+			"LLQ Tx max burst size of queue %d achieved, writing doorbell to send burst\n",
 			tx_ring->id);
 		ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
 		tx_ring->tx_stats.doorbells++;
@@ -2724,6 +3101,7 @@ static int ena_xmit_mbuf(struct ena_ring *tx_ring, struct rte_mbuf *mbuf)
 	}
 
 	tx_info->tx_descs = nb_hw_desc;
+	tx_info->timestamp = rte_get_timer_cycles();
 
 	tx_ring->tx_stats.cnt++;
 	tx_ring->tx_stats.bytes += mbuf->pkt_len;
@@ -2734,16 +3112,47 @@ static int ena_xmit_mbuf(struct ena_ring *tx_ring, struct rte_mbuf *mbuf)
 	return 0;
 }
 
-static void ena_tx_cleanup(struct ena_ring *tx_ring)
+static __rte_always_inline size_t
+ena_tx_cleanup_mbuf_fast(struct rte_mbuf **mbufs_to_clean,
+			 struct rte_mbuf *mbuf,
+			 size_t mbuf_cnt,
+			 size_t buf_size)
+{
+	struct rte_mbuf *m_next;
+
+	while (mbuf != NULL) {
+		m_next = mbuf->next;
+		mbufs_to_clean[mbuf_cnt++] = mbuf;
+		if (mbuf_cnt == buf_size) {
+			rte_mempool_put_bulk(mbufs_to_clean[0]->pool, (void **)mbufs_to_clean,
+				(unsigned int)mbuf_cnt);
+			mbuf_cnt = 0;
+		}
+		mbuf = m_next;
+	}
+
+	return mbuf_cnt;
+}
+
+static int ena_tx_cleanup(void *txp, uint32_t free_pkt_cnt)
 {
-	unsigned int cleanup_budget;
+	struct rte_mbuf *mbufs_to_clean[ENA_CLEANUP_BUF_SIZE];
+	struct ena_ring *tx_ring = (struct ena_ring *)txp;
+	size_t mbuf_cnt = 0;
 	unsigned int total_tx_descs = 0;
+	unsigned int total_tx_pkts = 0;
+	uint16_t cleanup_budget;
 	uint16_t next_to_clean = tx_ring->next_to_clean;
+	bool fast_free = tx_ring->offloads & DEV_TX_OFFLOAD_MBUF_FAST_FREE;
 
-	cleanup_budget = RTE_MIN(tx_ring->ring_size / ENA_REFILL_THRESH_DIVIDER,
-		(unsigned int)ENA_REFILL_THRESH_PACKET);
+	/*
+	 * If free_pkt_cnt is equal to 0, it means that the user requested
+	 * full cleanup, so attempt to release all Tx descriptors
+	 * (ring_size - 1 -> size_mask)
+	 */
+	cleanup_budget = (free_pkt_cnt == 0) ? tx_ring->size_mask : free_pkt_cnt;
 
-	while (likely(total_tx_descs < cleanup_budget)) {
+	while (likely(total_tx_pkts < cleanup_budget)) {
 		struct rte_mbuf *mbuf;
 		struct ena_tx_buffer *tx_info;
 		uint16_t req_id;
@@ -2756,14 +3165,21 @@ static void ena_tx_cleanup(struct ena_ring *tx_ring)
 
 		/* Get Tx info & store how many descs were processed  */
 		tx_info = &tx_ring->tx_buffer_info[req_id];
+		tx_info->timestamp = 0;
 
 		mbuf = tx_info->mbuf;
-		rte_pktmbuf_free(mbuf);
+		if (fast_free) {
+			mbuf_cnt = ena_tx_cleanup_mbuf_fast(mbufs_to_clean, mbuf, mbuf_cnt,
+				ENA_CLEANUP_BUF_SIZE);
+		} else {
+			rte_pktmbuf_free(mbuf);
+		}
 
 		tx_info->mbuf = NULL;
 		tx_ring->empty_tx_reqs[next_to_clean] = req_id;
 
 		total_tx_descs += tx_info->tx_descs;
+		total_tx_pkts++;
 
 		/* Put back descriptor to the ring for reuse */
 		next_to_clean = ENA_IDX_NEXT_MASKED(next_to_clean,
@@ -2774,22 +3190,38 @@ static void ena_tx_cleanup(struct ena_ring *tx_ring)
 		/* acknowledge completion of sent packets */
 		tx_ring->next_to_clean = next_to_clean;
 		ena_com_comp_ack(tx_ring->ena_com_io_sq, total_tx_descs);
-		ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq);
 	}
+
+	if (mbuf_cnt != 0)
+		rte_mempool_put_bulk(mbufs_to_clean[0]->pool,
+			(void **)mbufs_to_clean, mbuf_cnt);
+
+	/* Notify completion handler that full cleanup was performed */
+	if (free_pkt_cnt == 0 || total_tx_pkts < cleanup_budget)
+		tx_ring->last_cleanup_ticks = rte_get_timer_cycles();
+
+	return total_tx_pkts;
 }
 
 static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 				  uint16_t nb_pkts)
 {
 	struct ena_ring *tx_ring = (struct ena_ring *)(tx_queue);
+	int available_desc;
 	uint16_t sent_idx = 0;
 
+#ifdef RTE_ETHDEV_DEBUG_TX
 	/* Check adapter state */
 	if (unlikely(tx_ring->adapter->state != ENA_ADAPTER_STATE_RUNNING)) {
-		PMD_DRV_LOG(ALERT,
+		PMD_TX_LOG(ALERT,
 			"Trying to xmit pkts while device is NOT running\n");
 		return 0;
 	}
+#endif
+
+	available_desc = ena_com_free_q_entries(tx_ring->ena_com_io_sq);
+	if (available_desc < tx_ring->tx_free_thresh)
+		ena_tx_cleanup((void *)tx_ring, 0);
 
 	for (sent_idx = 0; sent_idx < nb_pkts; sent_idx++) {
 		if (ena_xmit_mbuf(tx_ring, tx_pkts[sent_idx]))
@@ -2799,9 +3231,6 @@ static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 			tx_ring->size_mask)]);
 	}
 
-	tx_ring->tx_stats.available_desc =
-		ena_com_free_q_entries(tx_ring->ena_com_io_sq);
-
 	/* If there are ready packets to be xmitted... */
 	if (likely(tx_ring->pkts_without_db)) {
 		/* ...let HW do its best :-) */
@@ -2810,8 +3239,6 @@ static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 		tx_ring->pkts_without_db = false;
 	}
 
-	ena_tx_cleanup(tx_ring);
-
 	tx_ring->tx_stats.available_desc =
 		ena_com_free_q_entries(tx_ring->ena_com_io_sq);
 	tx_ring->tx_stats.tx_poll++;
@@ -2819,29 +3246,68 @@ static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 	return sent_idx;
 }
 
-int ena_copy_eni_stats(struct ena_adapter *adapter)
+static void ena_copy_customer_metrics(struct ena_adapter *adapter, uint64_t *buf,
+					     size_t num_metrics)
 {
-	struct ena_admin_eni_stats admin_eni_stats;
+	struct ena_com_dev *ena_dev = &adapter->ena_dev;
 	int rc;
 
-	rte_spinlock_lock(&adapter->admin_lock);
-	rc = ena_com_get_eni_stats(&adapter->ena_dev, &admin_eni_stats);
-	rte_spinlock_unlock(&adapter->admin_lock);
-	if (rc != 0) {
-		if (rc == ENA_COM_UNSUPPORTED) {
-			PMD_DRV_LOG(DEBUG,
-				"Retrieving ENI metrics is not supported.\n");
-		} else {
+	if (ena_com_get_cap(ena_dev, ENA_ADMIN_CUSTOMER_METRICS)) {
+		if (num_metrics != ENA_STATS_ARRAY_METRICS) {
+			PMD_DRV_LOG(ERR, "Detected discrepancy in the number of customer metrics");
+			return;
+		}
+		rte_spinlock_lock(&adapter->admin_lock);
+		rc = ENA_PROXY(adapter,
+					ena_com_get_customer_metrics,
+					&adapter->ena_dev,
+					(char *)buf,
+					num_metrics * sizeof(uint64_t));
+		rte_spinlock_unlock(&adapter->admin_lock);
+		if (rc != 0) {
+			PMD_DRV_LOG(WARNING, "Failed to get customer metrics, rc: %d\n", rc);
+			return;
+		}
+
+	} else if (ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) {
+		if (num_metrics != ENA_STATS_ARRAY_METRICS_LEGACY) {
+			PMD_DRV_LOG(ERR, "Detected discrepancy in the number of legacy metrics");
+			return;
+		}
+
+		rte_spinlock_lock(&adapter->admin_lock);
+		rc = ENA_PROXY(adapter,
+			       ena_com_get_eni_stats,
+			       &adapter->ena_dev,
+			       (struct ena_admin_eni_stats *)buf);
+		rte_spinlock_unlock(&adapter->admin_lock);
+		if (rc != 0) {
 			PMD_DRV_LOG(WARNING,
-				"Failed to get ENI metrics: %d\n", rc);
+				"Failed to get ENI metrics, rc: %d\n", rc);
+			return;
 		}
-		return rc;
 	}
+}
 
-	rte_memcpy(&adapter->eni_stats, &admin_eni_stats,
-		sizeof(struct ena_stats_eni));
+static void ena_copy_ena_srd_info(struct ena_adapter *adapter,
+		struct ena_stats_srd *srd_info)
+{
+	int rc;
 
-	return 0;
+	if (!ena_com_get_cap(&adapter->ena_dev, ENA_ADMIN_ENA_SRD_INFO))
+		return;
+
+	rte_spinlock_lock(&adapter->admin_lock);
+	rc = ENA_PROXY(adapter,
+		       ena_com_get_ena_srd_info,
+		       &adapter->ena_dev,
+		       (struct ena_admin_ena_srd_info *)srd_info);
+	rte_spinlock_unlock(&adapter->admin_lock);
+	if (rc != ENA_COM_OK && rc != ENA_COM_UNSUPPORTED) {
+		PMD_DRV_LOG(WARNING,
+				"Failed to get ENA express srd info, rc: %d\n", rc);
+		return;
+	}
 }
 
 /**
@@ -2861,7 +3327,8 @@ static int ena_xstats_get_names(struct rte_eth_dev *dev,
 				struct rte_eth_xstat_name *xstats_names,
 				unsigned int n)
 {
-	unsigned int xstats_count = ena_xstats_calc_num(dev);
+	struct ena_adapter *adapter = dev->data->dev_private;
+	unsigned int xstats_count = ena_xstats_calc_num(dev->data);
 	unsigned int stat, i, count = 0;
 
 	if (n < xstats_count || !xstats_names)
@@ -2871,9 +3338,14 @@ static int ena_xstats_get_names(struct rte_eth_dev *dev,
 		strcpy(xstats_names[count].name,
 			ena_stats_global_strings[stat].name);
 
-	for (stat = 0; stat < ENA_STATS_ARRAY_ENI; stat++, count++)
-		strcpy(xstats_names[count].name,
-			ena_stats_eni_strings[stat].name);
+	for (stat = 0; stat < adapter->metrics_num; stat++, count++)
+		rte_strscpy(xstats_names[count].name,
+			    ena_stats_metrics_strings[stat].name,
+			    RTE_ETH_XSTATS_NAME_SIZE);
+	for (stat = 0; stat < ENA_STATS_ARRAY_ENA_SRD; stat++, count++)
+		rte_strscpy(xstats_names[count].name,
+			    ena_stats_srd_strings[stat].name,
+			    RTE_ETH_XSTATS_NAME_SIZE);
 
 	for (stat = 0; stat < ENA_STATS_ARRAY_RX; stat++)
 		for (i = 0; i < dev->data->nb_rx_queues; i++, count++)
@@ -2892,6 +3364,96 @@ static int ena_xstats_get_names(struct rte_eth_dev *dev,
 	return xstats_count;
 }
 
+/**
+ * DPDK callback to retrieve names of extended device statistics for the given
+ * ids.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] xstats_names
+ *   Buffer to insert names into.
+ * @param ids
+ *   IDs array for which the names should be retrieved.
+ * @param size
+ *   Number of ids.
+ *
+ * @return
+ *   Positive value: number of xstats names. Negative value: error code.
+ */
+static int ena_xstats_get_names_by_id(struct rte_eth_dev *dev,
+				      struct rte_eth_xstat_name *xstats_names,
+				      const uint64_t *ids,
+				      unsigned int size)
+{
+	struct ena_adapter *adapter = dev->data->dev_private;
+	uint64_t xstats_count = ena_xstats_calc_num(dev->data);
+	uint64_t id, qid;
+	unsigned int i;
+
+	if (xstats_names == NULL)
+		return xstats_count;
+
+	for (i = 0; i < size; ++i) {
+		id = ids[i];
+		if (id > xstats_count) {
+			PMD_DRV_LOG(ERR,
+				"ID value out of range: id=%" PRIu64 ", xstats_num=%" PRIu64 "\n",
+				 id, xstats_count);
+			return -EINVAL;
+		}
+
+		if (id < ENA_STATS_ARRAY_GLOBAL) {
+			strcpy(xstats_names[i].name,
+			       ena_stats_global_strings[id].name);
+			continue;
+		}
+
+		id -= ENA_STATS_ARRAY_GLOBAL;
+		if (id < adapter->metrics_num) {
+			rte_strscpy(xstats_names[i].name,
+				    ena_stats_metrics_strings[id].name,
+				    RTE_ETH_XSTATS_NAME_SIZE);
+			continue;
+		}
+
+		id -= adapter->metrics_num;
+
+		if (id < ENA_STATS_ARRAY_ENA_SRD) {
+			rte_strscpy(xstats_names[i].name,
+				    ena_stats_srd_strings[id].name,
+				    RTE_ETH_XSTATS_NAME_SIZE);
+			continue;
+		}
+		id -= ENA_STATS_ARRAY_ENA_SRD;
+
+		if (id < ENA_STATS_ARRAY_RX) {
+			qid = id / dev->data->nb_rx_queues;
+			id %= dev->data->nb_rx_queues;
+			snprintf(xstats_names[i].name,
+				 sizeof(xstats_names[i].name),
+				 "rx_q%" PRIu64 "d_%s",
+				 qid, ena_stats_rx_strings[id].name);
+			continue;
+		}
+
+		id -= ENA_STATS_ARRAY_RX;
+		/* Although this condition is not needed, it was added for
+		 * compatibility if new xstat structure would be ever added.
+		 */
+		if (id < ENA_STATS_ARRAY_TX) {
+			qid = id / dev->data->nb_tx_queues;
+			id %= dev->data->nb_tx_queues;
+			snprintf(xstats_names[i].name,
+				 sizeof(xstats_names[i].name),
+				 "tx_q%" PRIu64 "_%s",
+				 qid, ena_stats_tx_strings[id].name);
+			continue;
+		}
+	}
+
+	return i;
+}
+
 /**
  * DPDK callback to get extended device statistics.
  *
@@ -2910,10 +3472,12 @@ static int ena_xstats_get(struct rte_eth_dev *dev,
 			  unsigned int n)
 {
 	struct ena_adapter *adapter = dev->data->dev_private;
-	unsigned int xstats_count = ena_xstats_calc_num(dev);
+	unsigned int xstats_count = ena_xstats_calc_num(dev->data);
 	unsigned int stat, i, count = 0;
 	int stat_offset;
 	void *stats_begin;
+	uint64_t metrics_stats[ENA_MAX_CUSTOMER_METRICS];
+	struct ena_stats_srd srd_info = {0};
 
 	if (n < xstats_count)
 		return xstats_count;
@@ -2930,19 +3494,25 @@ static int ena_xstats_get(struct rte_eth_dev *dev,
 			((char *)stats_begin + stat_offset));
 	}
 
-	/* Even if the function below fails, we should copy previous (or initial
-	 * values) to keep structure of rte_eth_xstat consistent.
-	 */
-	ena_copy_eni_stats(adapter);
-	for (stat = 0; stat < ENA_STATS_ARRAY_ENI; stat++, count++) {
-		stat_offset = ena_stats_eni_strings[stat].stat_offset;
-		stats_begin = &adapter->eni_stats;
+	ena_copy_customer_metrics(adapter, metrics_stats, adapter->metrics_num);
+	stats_begin = metrics_stats;
+	for (stat = 0; stat < adapter->metrics_num; stat++, count++) {
+		stat_offset = ena_stats_metrics_strings[stat].stat_offset;
 
 		xstats[count].id = count;
 		xstats[count].value = *((uint64_t *)
 		    ((char *)stats_begin + stat_offset));
 	}
 
+	ena_copy_ena_srd_info(adapter, &srd_info);
+	stats_begin = &srd_info;
+	for (stat = 0; stat < ENA_STATS_ARRAY_ENA_SRD; stat++, count++) {
+		stat_offset = ena_stats_srd_strings[stat].stat_offset;
+		xstats[count].id = count;
+		xstats[count].value = *((uint64_t *)
+		    ((char *)stats_begin + stat_offset));
+	}
+
 	for (stat = 0; stat < ENA_STATS_ARRAY_RX; stat++) {
 		for (i = 0; i < dev->data->nb_rx_queues; i++, count++) {
 			stat_offset = ena_stats_rx_strings[stat].stat_offset;
@@ -2979,7 +3549,10 @@ static int ena_xstats_get_by_id(struct rte_eth_dev *dev,
 	unsigned int i;
 	int qid;
 	int valid = 0;
-	bool was_eni_copied = false;
+	bool were_metrics_copied = false;
+	bool was_srd_info_copied = false;
+	uint64_t metrics_stats[ENA_MAX_CUSTOMER_METRICS];
+	struct ena_stats_srd srd_info = {0};
 
 	for (i = 0; i < n; ++i) {
 		id = ids[i];
@@ -2992,22 +3565,44 @@ static int ena_xstats_get_by_id(struct rte_eth_dev *dev,
 
 		/* Check if id belongs to ENI statistics */
 		id -= ENA_STATS_ARRAY_GLOBAL;
-		if (id < ENA_STATS_ARRAY_ENI) {
-			/* Avoid reading ENI stats multiple times in a single
+		if (id < adapter->metrics_num) {
+			/* Avoid reading metrics multiple times in a single
 			 * function call, as it requires communication with the
 			 * admin queue.
 			 */
-			if (!was_eni_copied) {
-				was_eni_copied = true;
-				ena_copy_eni_stats(adapter);
+			if (!were_metrics_copied) {
+				were_metrics_copied = true;
+				ena_copy_customer_metrics(adapter,
+						metrics_stats,
+						adapter->metrics_num);
 			}
-			values[i] = *((uint64_t *)&adapter->eni_stats + id);
+
+			values[i] = *((uint64_t *)&metrics_stats + id);
+			++valid;
+			continue;
+		}
+
+		/* Check if id belongs to SRD info statistics */
+		id -= adapter->metrics_num;
+
+		if (id < ENA_STATS_ARRAY_ENA_SRD) {
+			/*
+			 * Avoid reading srd info multiple times in a single
+			 * function call, as it requires communication with the
+			 * admin queue.
+			 */
+			if (!was_srd_info_copied) {
+				was_srd_info_copied = true;
+				ena_copy_ena_srd_info(adapter, &srd_info);
+			}
+			values[i] = *((uint64_t *)&adapter->srd_stats + id);
 			++valid;
 			continue;
 		}
 
 		/* Check if id belongs to rx queue statistics */
-		id -= ENA_STATS_ARRAY_ENI;
+		id -= ENA_STATS_ARRAY_ENA_SRD;
+
 		rx_entries = ENA_STATS_ARRAY_RX * dev->data->nb_rx_queues;
 		if (id < rx_entries) {
 			qid = id % dev->data->nb_rx_queues;
@@ -3033,6 +3628,45 @@ static int ena_xstats_get_by_id(struct rte_eth_dev *dev,
 	return valid;
 }
 
+static int ena_process_uint_devarg(const char *key,
+				  const char *value,
+				  void *opaque)
+{
+	struct ena_adapter *adapter = opaque;
+	char *str_end;
+	uint64_t uint_value;
+
+	uint_value = strtoull(value, &str_end, 10);
+	if (value == str_end) {
+		PMD_INIT_LOG(ERR,
+			"Invalid value for key '%s'. Only uint values are accepted.\n",
+			key);
+		return -EINVAL;
+	}
+
+	if (strcmp(key, ENA_DEVARG_MISS_TXC_TO) == 0) {
+		if (uint_value > ENA_MAX_TX_TIMEOUT_SECONDS) {
+			PMD_INIT_LOG(ERR,
+				"Tx timeout too high: %" PRIu64 " sec. Maximum allowed: %d sec.\n",
+				uint_value, ENA_MAX_TX_TIMEOUT_SECONDS);
+			return -EINVAL;
+		} else if (uint_value == 0) {
+			PMD_INIT_LOG(INFO,
+				"Check for missing Tx completions has been disabled.\n");
+			adapter->missing_tx_completion_to =
+				ENA_HW_HINTS_NO_TIMEOUT;
+		} else {
+			PMD_INIT_LOG(INFO,
+				"Tx packet completion timeout set to %" PRIu64 " seconds.\n",
+				uint_value);
+			adapter->missing_tx_completion_to =
+				uint_value * rte_get_timer_hz();
+		}
+	}
+
+	return 0;
+}
+
 static int ena_process_bool_devarg(const char *key,
 				   const char *value,
 				   void *opaque)
@@ -3055,6 +3689,8 @@ static int ena_process_bool_devarg(const char *key,
 	/* Now, assign it to the proper adapter field. */
 	if (strcmp(key, ENA_DEVARG_LARGE_LLQ_HDR) == 0)
 		adapter->use_large_llq_hdr = bool_value;
+	else if (strcmp(key, ENA_DEVARG_ENABLE_LLQ) == 0)
+		adapter->enable_llq = bool_value;
 
 	return 0;
 }
@@ -3064,6 +3700,8 @@ static int ena_parse_devargs(struct ena_adapter *adapter,
 {
 	static const char * const allowed_args[] = {
 		ENA_DEVARG_LARGE_LLQ_HDR,
+		ENA_DEVARG_MISS_TXC_TO,
+		ENA_DEVARG_ENABLE_LLQ,
 		NULL,
 	};
 	struct rte_kvargs *kvlist;
@@ -3081,12 +3719,205 @@ static int ena_parse_devargs(struct ena_adapter *adapter,
 
 	rc = rte_kvargs_process(kvlist, ENA_DEVARG_LARGE_LLQ_HDR,
 		ena_process_bool_devarg, adapter);
+	if (rc != 0)
+		goto exit;
+	rc = rte_kvargs_process(kvlist, ENA_DEVARG_MISS_TXC_TO,
+		ena_process_uint_devarg, adapter);
+	if (rc != 0)
+		goto exit;
+	rc = rte_kvargs_process(kvlist, ENA_DEVARG_ENABLE_LLQ,
+		ena_process_bool_devarg, adapter);
 
+exit:
 	rte_kvargs_free(kvlist);
 
 	return rc;
 }
 
+static int ena_setup_rx_intr(struct rte_eth_dev *dev)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+	int rc;
+	uint16_t vectors_nb, i;
+	bool rx_intr_requested = dev->data->dev_conf.intr_conf.rxq;
+
+	if (!rx_intr_requested)
+		return 0;
+
+	if (!rte_intr_cap_multiple(intr_handle)) {
+		PMD_DRV_LOG(ERR,
+			"Rx interrupt requested, but it isn't supported by the PCI driver\n");
+		return -ENOTSUP;
+	}
+
+	/* Disable interrupt mapping before the configuration starts. */
+	rte_intr_disable(intr_handle);
+
+	/* Verify if there are enough vectors available. */
+	vectors_nb = dev->data->nb_rx_queues;
+	if (vectors_nb > RTE_MAX_RXTX_INTR_VEC_ID) {
+		PMD_DRV_LOG(ERR,
+			"Too many Rx interrupts requested, maximum number: %d\n",
+			RTE_MAX_RXTX_INTR_VEC_ID);
+		rc = -ENOTSUP;
+		goto enable_intr;
+	}
+
+	intr_handle->intr_vec =	rte_zmalloc("intr_vec",
+		dev->data->nb_rx_queues * sizeof(*intr_handle->intr_vec), 0);
+	if (intr_handle->intr_vec == NULL) {
+		PMD_DRV_LOG(ERR,
+			"Failed to allocate interrupt vector for %d queues\n",
+			dev->data->nb_rx_queues);
+		rc = -ENOMEM;
+		goto enable_intr;
+	}
+
+	rc = rte_intr_efd_enable(intr_handle, vectors_nb);
+	if (rc != 0)
+		goto free_intr_vec;
+
+	if (!rte_intr_allow_others(intr_handle)) {
+		PMD_DRV_LOG(ERR,
+			"Not enough interrupts available to use both ENA Admin and Rx interrupts\n");
+		goto disable_intr_efd;
+	}
+
+	for (i = 0; i < vectors_nb; ++i)
+		intr_handle->intr_vec[i] = RTE_INTR_VEC_RXTX_OFFSET + i;
+
+	rte_intr_enable(intr_handle);
+	return 0;
+
+disable_intr_efd:
+	rte_intr_efd_disable(intr_handle);
+free_intr_vec:
+	rte_free(intr_handle->intr_vec);
+	intr_handle->intr_vec = NULL;
+enable_intr:
+	rte_intr_enable(intr_handle);
+	return rc;
+}
+
+static void ena_rx_queue_intr_set(struct rte_eth_dev *dev,
+				 uint16_t queue_id,
+				 bool unmask)
+{
+	struct ena_adapter *adapter = dev->data->dev_private;
+	struct ena_ring *rxq = &adapter->rx_ring[queue_id];
+	struct ena_eth_io_intr_reg intr_reg;
+
+	ena_com_update_intr_reg(&intr_reg, 0, 0, unmask, 1);
+	ena_com_unmask_intr(rxq->ena_com_io_cq, &intr_reg);
+}
+
+static int ena_rx_queue_intr_enable(struct rte_eth_dev *dev,
+				    uint16_t queue_id)
+{
+	ena_rx_queue_intr_set(dev, queue_id, true);
+
+	return 0;
+}
+
+static int ena_rx_queue_intr_disable(struct rte_eth_dev *dev,
+				     uint16_t queue_id)
+{
+	ena_rx_queue_intr_set(dev, queue_id, false);
+
+	return 0;
+}
+
+static int ena_configure_aenq(struct ena_adapter *adapter)
+{
+	uint32_t aenq_groups = adapter->all_aenq_groups;
+	int rc;
+
+	/* All_aenq_groups holds all AENQ functions supported by the device and
+	 * the HW, so at first we need to be sure the LSC request is valid.
+	 */
+	if (adapter->edev_data->dev_conf.intr_conf.lsc != 0) {
+		if (!(aenq_groups & BIT(ENA_ADMIN_LINK_CHANGE))) {
+			PMD_DRV_LOG(ERR,
+				"LSC requested, but it's not supported by the AENQ\n");
+			return -EINVAL;
+		}
+	} else {
+		/* If LSC wasn't enabled by the app, let's enable all supported
+		 * AENQ procedures except the LSC.
+		 */
+		aenq_groups &= ~BIT(ENA_ADMIN_LINK_CHANGE);
+	}
+
+	rc = ena_com_set_aenq_config(&adapter->ena_dev, aenq_groups);
+	if (rc != 0) {
+		PMD_DRV_LOG(ERR, "Cannot configure AENQ groups, rc=%d\n", rc);
+		return rc;
+	}
+
+	adapter->active_aenq_groups = aenq_groups;
+
+	return 0;
+}
+
+int ena_mp_indirect_table_set(struct ena_adapter *adapter)
+{
+	return ENA_PROXY(adapter, ena_com_indirect_table_set, &adapter->ena_dev);
+}
+
+int ena_mp_indirect_table_get(struct ena_adapter *adapter,
+			      uint32_t *indirect_table)
+{
+	return ENA_PROXY(adapter, ena_com_indirect_table_get, &adapter->ena_dev,
+		indirect_table);
+}
+
+/*********************************************************************
+ *  ena_plat_dpdk.h functions implementations
+ *********************************************************************/
+
+const struct rte_memzone *
+ena_mem_alloc_coherent(struct rte_eth_dev_data *data, size_t size,
+		       int socket_id, unsigned int alignment, void **virt_addr,
+		       dma_addr_t *phys_addr)
+{
+	char z_name[RTE_MEMZONE_NAMESIZE];
+	struct ena_adapter *adapter = data->dev_private;
+	const struct rte_memzone *memzone;
+	int rc;
+
+	rc = snprintf(z_name, RTE_MEMZONE_NAMESIZE, "ena_p%d_mz%" PRIu64 "",
+		data->port_id, adapter->memzone_cnt);
+	if (rc >= RTE_MEMZONE_NAMESIZE) {
+		PMD_DRV_LOG(ERR,
+			"Name for the ena_com memzone is too long. Port: %d, mz_num: %" PRIu64 "\n",
+			data->port_id, adapter->memzone_cnt);
+		goto error;
+	}
+	adapter->memzone_cnt++;
+
+	memzone = rte_memzone_reserve_aligned(z_name, size, socket_id,
+		RTE_MEMZONE_IOVA_CONTIG, alignment);
+	if (memzone == NULL) {
+		PMD_DRV_LOG(ERR, "Failed to allocate ena_com memzone: %s\n",
+			z_name);
+		goto error;
+	}
+
+	memset(memzone->addr, 0, size);
+	*virt_addr = memzone->addr;
+	*phys_addr = memzone->iova;
+
+	return memzone;
+
+error:
+	*virt_addr = NULL;
+	*phys_addr = 0;
+
+	return NULL;
+}
+
+
 /*********************************************************************
  *  PMD configuration
  *********************************************************************/
@@ -3113,21 +3944,19 @@ static struct rte_pci_driver rte_ena_pmd = {
 RTE_PMD_REGISTER_PCI(net_ena, rte_ena_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_ena, pci_id_ena_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_ena, "* igb_uio | uio_pci_generic | vfio-pci");
-RTE_PMD_REGISTER_PARAM_STRING(net_ena, ENA_DEVARG_LARGE_LLQ_HDR "=<0|1>");
+RTE_PMD_REGISTER_PARAM_STRING(net_ena,
+	ENA_DEVARG_LARGE_LLQ_HDR "=<0|1> "
+	ENA_DEVARG_ENABLE_LLQ "=<0|1> "
+	ENA_DEVARG_MISS_TXC_TO "=<uint>");
 RTE_LOG_REGISTER(ena_logtype_init, pmd.net.ena.init, NOTICE);
 RTE_LOG_REGISTER(ena_logtype_driver, pmd.net.ena.driver, NOTICE);
 #ifdef RTE_LIBRTE_ENA_DEBUG_RX
-RTE_LOG_REGISTER(ena_logtype_rx, pmd.net.ena.rx, NOTICE);
+RTE_LOG_REGISTER(ena_logtype_rx, pmd.net.ena.rx, DEBUG);
 #endif
 #ifdef RTE_LIBRTE_ENA_DEBUG_TX
-RTE_LOG_REGISTER(ena_logtype_tx, pmd.net.ena.tx, NOTICE);
-#endif
-#ifdef RTE_LIBRTE_ENA_DEBUG_TX_FREE
-RTE_LOG_REGISTER(ena_logtype_tx_free, pmd.net.ena.tx_free, NOTICE);
-#endif
-#ifdef RTE_LIBRTE_ENA_COM_DEBUG
-RTE_LOG_REGISTER(ena_logtype_com, pmd.net.ena.com, NOTICE);
+RTE_LOG_REGISTER(ena_logtype_tx, pmd.net.ena.tx, DEBUG);
 #endif
+RTE_LOG_REGISTER(ena_logtype_com, pmd.net.ena.com, WARNING);
 
 /******************************************************************************
  ******************************** AENQ Handlers *******************************
@@ -3135,14 +3964,12 @@ RTE_LOG_REGISTER(ena_logtype_com, pmd.net.ena.com, NOTICE);
 static void ena_update_on_link_change(void *adapter_data,
 				      struct ena_admin_aenq_entry *aenq_e)
 {
-	struct rte_eth_dev *eth_dev;
-	struct ena_adapter *adapter;
+	struct rte_eth_dev *eth_dev = adapter_data;
+	struct ena_adapter *adapter = eth_dev->data->dev_private;
 	struct ena_admin_aenq_link_change_desc *aenq_link_desc;
 	uint32_t status;
 
-	adapter = adapter_data;
 	aenq_link_desc = (struct ena_admin_aenq_link_change_desc *)aenq_e;
-	eth_dev = adapter->rte_dev;
 
 	status = get_ena_admin_aenq_link_change_desc_link_status(aenq_link_desc);
 	adapter->link_status = status;
@@ -3151,14 +3978,15 @@ static void ena_update_on_link_change(void *adapter_data,
 	rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL);
 }
 
-static void ena_notification(void *data,
+static void ena_notification(void *adapter_data,
 			     struct ena_admin_aenq_entry *aenq_e)
 {
-	struct ena_adapter *adapter = data;
+	struct rte_eth_dev *eth_dev = adapter_data;
+	struct ena_adapter *adapter = eth_dev->data->dev_private;
 	struct ena_admin_ena_hw_hints *hints;
 
 	if (aenq_e->aenq_common_desc.group != ENA_ADMIN_NOTIFICATION)
-		PMD_DRV_LOG(WARNING, "Invalid group(%x) expected %x\n",
+		PMD_DRV_LOG(WARNING, "Invalid AENQ group: %x. Expected: %x\n",
 			aenq_e->aenq_common_desc.group,
 			ENA_ADMIN_NOTIFICATION);
 
@@ -3169,7 +3997,7 @@ static void ena_notification(void *data,
 		ena_update_hints(adapter, hints);
 		break;
 	default:
-		PMD_DRV_LOG(ERR, "Invalid aenq notification link state %d\n",
+		PMD_DRV_LOG(ERR, "Invalid AENQ notification link state: %d\n",
 			aenq_e->aenq_common_desc.syndrome);
 	}
 }
@@ -3177,19 +4005,23 @@ static void ena_notification(void *data,
 static void ena_keep_alive(void *adapter_data,
 			   __rte_unused struct ena_admin_aenq_entry *aenq_e)
 {
-	struct ena_adapter *adapter = adapter_data;
+	struct rte_eth_dev *eth_dev = adapter_data;
+	struct ena_adapter *adapter = eth_dev->data->dev_private;
 	struct ena_admin_aenq_keep_alive_desc *desc;
 	uint64_t rx_drops;
 	uint64_t tx_drops;
+	uint64_t rx_overruns;
 
 	adapter->timestamp_wd = rte_get_timer_cycles();
 
 	desc = (struct ena_admin_aenq_keep_alive_desc *)aenq_e;
 	rx_drops = ((uint64_t)desc->rx_drops_high << 32) | desc->rx_drops_low;
 	tx_drops = ((uint64_t)desc->tx_drops_high << 32) | desc->tx_drops_low;
+	rx_overruns = ((uint64_t)desc->rx_overruns_high << 32) | desc->rx_overruns_low;
 
 	adapter->drv_stats->rx_drops = rx_drops;
 	adapter->dev_stats.tx_drops = tx_drops;
+	adapter->dev_stats.rx_overruns = rx_overruns;
 }
 
 /**
@@ -3198,8 +4030,8 @@ static void ena_keep_alive(void *adapter_data,
 static void unimplemented_aenq_handler(__rte_unused void *data,
 				       __rte_unused struct ena_admin_aenq_entry *aenq_e)
 {
-	PMD_DRV_LOG(ERR, "Unknown event was received or event with "
-			  "unimplemented handler\n");
+	PMD_DRV_LOG(ERR,
+		"Unknown event was received or event with unimplemented handler\n");
 }
 
 static struct ena_aenq_handlers aenq_handlers = {
@@ -3210,3 +4042,73 @@ static struct ena_aenq_handlers aenq_handlers = {
 	},
 	.unimplemented_handler = unimplemented_aenq_handler
 };
+
+/*********************************************************************
+ *  Multi-Process communication request handling (in primary)
+ *********************************************************************/
+static int
+ena_mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
+{
+	const struct ena_mp_body *req =
+		(const struct ena_mp_body *)mp_msg->param;
+	struct ena_adapter *adapter;
+	struct ena_com_dev *ena_dev;
+	struct ena_mp_body *rsp;
+	struct rte_mp_msg mp_rsp;
+	struct rte_eth_dev *dev;
+	int res = 0;
+
+	rsp = (struct ena_mp_body *)&mp_rsp.param;
+	mp_msg_init(&mp_rsp, req->type, req->port_id);
+
+	if (!rte_eth_dev_is_valid_port(req->port_id)) {
+		rte_errno = ENODEV;
+		res = -rte_errno;
+		PMD_DRV_LOG(ERR, "Unknown port %d in request %d\n",
+			    req->port_id, req->type);
+		goto end;
+	}
+	dev = &rte_eth_devices[req->port_id];
+	adapter = dev->data->dev_private;
+	ena_dev = &adapter->ena_dev;
+
+	switch (req->type) {
+	case ENA_MP_DEV_STATS_GET:
+		res = ena_com_get_dev_basic_stats(ena_dev,
+						  &adapter->basic_stats);
+		break;
+	case ENA_MP_ENI_STATS_GET:
+		res = ena_com_get_eni_stats(ena_dev,
+			(struct ena_admin_eni_stats *)&adapter->metrics_stats);
+		break;
+	case ENA_MP_MTU_SET:
+		res = ena_com_set_dev_mtu(ena_dev, req->args.mtu);
+		break;
+	case ENA_MP_IND_TBL_GET:
+		res = ena_com_indirect_table_get(ena_dev,
+						 adapter->indirect_table);
+		break;
+	case ENA_MP_IND_TBL_SET:
+		res = ena_com_indirect_table_set(ena_dev);
+		break;
+	case ENA_MP_CUSTOMER_METRICS_GET:
+		res = ena_com_get_customer_metrics(ena_dev,
+				(char *)adapter->metrics_stats,
+				sizeof(uint64_t) * adapter->metrics_num);
+		break;
+	case ENA_MP_SRD_STATS_GET:
+		res = ena_com_get_ena_srd_info(ena_dev,
+				(struct ena_admin_ena_srd_info *)&adapter->srd_stats);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Unknown request type %d\n", req->type);
+		res = -EINVAL;
+		break;
+	}
+
+end:
+	/* Save processing result in the reply */
+	rsp->result = res;
+	/* Return just IPC processing status */
+	return rte_mp_reply(&mp_rsp, peer);
+}
diff --git a/drivers/net/ena/ena_ethdev.h b/drivers/net/ena/ena_ethdev.h
index 7bb3ff2b9e..12291147e6 100644
--- a/drivers/net/ena/ena_ethdev.h
+++ b/drivers/net/ena/ena_ethdev.h
@@ -6,10 +6,16 @@
 #ifndef _ENA_ETHDEV_H_
 #define _ENA_ETHDEV_H_
 
+#include <rte_atomic.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
 #include <rte_cycles.h>
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 #include <rte_timer.h>
+#include <rte_dev.h>
+#include <rte_net.h>
 
 #include "ena_com.h"
 
@@ -23,6 +29,9 @@
 #define ENA_RX_BUF_MIN_SIZE	1400
 #define ENA_DEFAULT_RING_SIZE	1024
 
+#define ENA_RX_RSS_TABLE_LOG_SIZE	7
+#define ENA_RX_RSS_TABLE_SIZE		(1 << ENA_RX_RSS_TABLE_LOG_SIZE)
+
 #define ENA_MIN_MTU		128
 
 #define ENA_MMIO_DISABLE_REG_READ	BIT(0)
@@ -30,6 +39,11 @@
 #define ENA_WD_TIMEOUT_SEC	3
 #define ENA_DEVICE_KALIVE_TIMEOUT (ENA_WD_TIMEOUT_SEC * rte_get_timer_hz())
 
+#define ENA_TX_TIMEOUT			(5 * rte_get_timer_hz())
+#define ENA_MAX_TX_TIMEOUT_SECONDS	60
+#define ENA_MONITORED_TX_QUEUES		3
+#define ENA_DEFAULT_MISSING_COMP	256U
+
 /* While processing submitted and completed descriptors (rx and tx path
  * respectively) in a loop it is desired to:
  *  - perform batch submissions while populating submission queue
@@ -40,9 +54,30 @@
 #define ENA_REFILL_THRESH_DIVIDER      8
 #define ENA_REFILL_THRESH_PACKET       256
 
+/*
+ * The max customer metrics is equal or bigger than the ENI metrics. That
+ * assumption simplifies the fallback to the legacy metrics mechanism.
+ */
+#define ENA_MAX_CUSTOMER_METRICS	6
+
 #define ENA_IDX_NEXT_MASKED(idx, mask) (((idx) + 1) & (mask))
 #define ENA_IDX_ADD_MASKED(idx, n, mask) (((idx) + (n)) & (mask))
 
+#define ENA_RX_RSS_TABLE_LOG_SIZE	7
+#define ENA_RX_RSS_TABLE_SIZE		(1 << ENA_RX_RSS_TABLE_LOG_SIZE)
+
+#define ENA_HASH_KEY_SIZE		40
+
+#define ENA_ALL_RSS_HF (ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_NONFRAG_IPV4_UDP | \
+			ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_NONFRAG_IPV6_UDP)
+
+#define ENA_IO_TXQ_IDX(q)		(2 * (q))
+#define ENA_IO_RXQ_IDX(q)		(2 * (q) + 1)
+/* Reversed version of ENA_IO_RXQ_IDX */
+#define ENA_IO_RXQ_IDX_REV(q)		(((q) - 1) / 2)
+
+extern struct ena_shared_data *ena_shared_data;
+
 struct ena_adapter;
 
 enum ena_ring_type {
@@ -54,6 +89,8 @@ struct ena_tx_buffer {
 	struct rte_mbuf *mbuf;
 	unsigned int tx_descs;
 	unsigned int num_of_bufs;
+	uint64_t timestamp;
+	bool print_once;
 	struct ena_com_buf bufs[ENA_PKT_MAX_BUFS];
 };
 
@@ -76,19 +113,20 @@ struct ena_stats_tx {
 	u64 cnt;
 	u64 bytes;
 	u64 prepare_ctx_err;
-	u64 linearize;
-	u64 linearize_failed;
 	u64 tx_poll;
 	u64 doorbells;
 	u64 bad_req_id;
 	u64 available_desc;
+	u64 missed_tx;
 };
 
 struct ena_stats_rx {
 	u64 cnt;
 	u64 bytes;
 	u64 refill_partial;
-	u64 bad_csum;
+	u64 l3_csum_bad;
+	u64 l4_csum_bad;
+	u64 l4_csum_good;
 	u64 mbuf_alloc_fail;
 	u64 bad_desc_num;
 	u64 bad_req_id;
@@ -97,6 +135,7 @@ struct ena_stats_rx {
 struct ena_ring {
 	u16 next_to_use;
 	u16 next_to_clean;
+	uint64_t last_cleanup_ticks;
 
 	enum ena_ring_type type;
 	enum ena_admin_placement_policy_type tx_mem_queue_type;
@@ -121,6 +160,11 @@ struct ena_ring {
 	struct ena_com_io_cq *ena_com_io_cq;
 	struct ena_com_io_sq *ena_com_io_sq;
 
+	union {
+		uint16_t tx_free_thresh;
+		uint16_t rx_free_thresh;
+	};
+
 	struct ena_com_rx_buf_info ena_bufs[ENA_PKT_MAX_BUFS]
 						__rte_cache_aligned;
 
@@ -145,6 +189,8 @@ struct ena_ring {
 	};
 
 	unsigned int numa_socket_id;
+
+	uint32_t missing_tx_completion_threshold;
 } __rte_cache_aligned;
 
 enum ena_adapter_state {
@@ -173,9 +219,10 @@ struct ena_stats_dev {
 	 * As a workaround it is being published as an extended statistic.
 	 */
 	u64 tx_drops;
+	u64 rx_overruns;
 };
 
-struct ena_stats_eni {
+struct ena_stats_metrics {
 	/*
 	 * The number of packets shaped due to inbound aggregate BW
 	 * allowance being exceeded
@@ -199,6 +246,27 @@ struct ena_stats_eni {
 	 * allowance being exceeded
 	 */
 	uint64_t linklocal_allowance_exceeded;
+	 /*
+	  * The number of available connections
+	  */
+	uint64_t conntrack_allowance_available;
+};
+
+struct ena_stats_srd {
+	/* Describes which ENA Express features are enabled */
+	uint64_t ena_srd_mode;
+
+	/* Number of packets transmitted over ENA SRD */
+	uint64_t ena_srd_tx_pkts;
+
+	/* Number of packets transmitted or could have been transmitted over ENA SRD */
+	uint64_t ena_srd_eligible_tx_pkts;
+
+	/* Number of packets received over ENA SRD */
+	uint64_t ena_srd_rx_pkts;
+
+	/* Percentage of the ENA SRD resources that is in use */
+	uint64_t ena_srd_resource_utilization;
 };
 
 struct ena_offloads {
@@ -209,9 +277,7 @@ struct ena_offloads {
 /* board specific private data structure */
 struct ena_adapter {
 	/* OS defined structs */
-	struct rte_pci_device *pdev;
-	struct rte_eth_dev_data *rte_eth_dev_data;
-	struct rte_eth_dev *rte_dev;
+	struct rte_eth_dev_data *edev_data;
 
 	struct ena_com_dev ena_dev __rte_cache_aligned;
 
@@ -255,13 +321,47 @@ struct ena_adapter {
 	uint64_t keep_alive_timeout;
 
 	struct ena_stats_dev dev_stats;
-	struct ena_stats_eni eni_stats;
+	struct ena_admin_basic_stats basic_stats;
 
-	bool trigger_reset;
+	u32 indirect_table[ENA_RX_RSS_TABLE_SIZE];
+
+	uint32_t all_aenq_groups;
+	uint32_t active_aenq_groups;
 
-	bool wd_state;
+	bool trigger_reset;
 
+	bool enable_llq;
 	bool use_large_llq_hdr;
+
+	uint32_t last_tx_comp_qid;
+	uint64_t missing_tx_completion_to;
+	uint64_t missing_tx_completion_budget;
+	uint64_t tx_cleanup_stall_delay;
+
+	uint64_t memzone_cnt;
+
+	/*
+	 * Helper variables for holding the information about the supported
+	 * metrics.
+	 */
+	uint64_t metrics_stats[ENA_MAX_CUSTOMER_METRICS] __rte_cache_aligned;
+	uint16_t metrics_num;
+	struct ena_stats_srd srd_stats __rte_cache_aligned;
 };
 
+int ena_mp_indirect_table_set(struct ena_adapter *adapter);
+int ena_mp_indirect_table_get(struct ena_adapter *adapter,
+			      uint32_t *indirect_table);
+int ena_rss_reta_update(struct rte_eth_dev *dev,
+			struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t reta_size);
+int ena_rss_reta_query(struct rte_eth_dev *dev,
+		       struct rte_eth_rss_reta_entry64 *reta_conf,
+		       uint16_t reta_size);
+int ena_rss_hash_update(struct rte_eth_dev *dev,
+			struct rte_eth_rss_conf *rss_conf);
+int ena_rss_hash_conf_get(struct rte_eth_dev *dev,
+			  struct rte_eth_rss_conf *rss_conf);
+int ena_rss_configure(struct ena_adapter *adapter);
+
 #endif /* _ENA_ETHDEV_H_ */
diff --git a/drivers/net/ena/ena_logs.h b/drivers/net/ena/ena_logs.h
index 9053c9183f..43f16458ea 100644
--- a/drivers/net/ena/ena_logs.h
+++ b/drivers/net/ena/ena_logs.h
@@ -9,38 +9,29 @@
 extern int ena_logtype_init;
 #define PMD_INIT_LOG(level, fmt, args...) \
 	rte_log(RTE_LOG_ ## level, ena_logtype_init, \
-		"%s(): " fmt "\n", __func__, ## args)
+		"%s(): " fmt, __func__, ## args)
 
-#ifdef RTE_LIBRTE_ENA_DEBUG_RX
+#ifdef RTE_ETHDEV_DEBUG_RX
 extern int ena_logtype_rx;
 #define PMD_RX_LOG(level, fmt, args...)			\
 	rte_log(RTE_LOG_ ## level, ena_logtype_rx,	\
-		"%s(): " fmt "\n", __func__, ## args)
+		"%s(): " fmt, __func__, ## args)
 #else
 #define PMD_RX_LOG(level, fmt, args...) do { } while (0)
 #endif
 
-#ifdef RTE_LIBRTE_ENA_DEBUG_TX
+#ifdef RTE_ETHDEV_DEBUG_TX
 extern int ena_logtype_tx;
 #define PMD_TX_LOG(level, fmt, args...)			\
 	rte_log(RTE_LOG_ ## level, ena_logtype_tx,	\
-		"%s(): " fmt "\n", __func__, ## args)
+		"%s(): " fmt, __func__, ## args)
 #else
 #define PMD_TX_LOG(level, fmt, args...) do { } while (0)
 #endif
 
-#ifdef RTE_LIBRTE_ENA_DEBUG_TX_FREE
-extern int ena_logtype_tx_free;
-#define PMD_TX_FREE_LOG(level, fmt, args...)			\
-	rte_log(RTE_LOG_ ## level, ena_logtype_tx_free,	\
-		"%s(): " fmt "\n", __func__, ## args)
-#else
-#define PMD_TX_FREE_LOG(level, fmt, args...) do { } while (0)
-#endif
-
 extern int ena_logtype_driver;
 #define PMD_DRV_LOG(level, fmt, args...) \
 	rte_log(RTE_LOG_ ## level, ena_logtype_driver, \
-		"%s(): " fmt "\n", __func__, ## args)
+		"%s(): " fmt, __func__, ## args)
 
 #endif /* _ENA_LOGS_H_ */
diff --git a/drivers/net/ena/ena_rss.c b/drivers/net/ena/ena_rss.c
new file mode 100644
index 0000000000..03b0ef7ebc
--- /dev/null
+++ b/drivers/net/ena/ena_rss.c
@@ -0,0 +1,590 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2020 Amazon.com, Inc. or its affiliates.
+ * All rights reserved.
+ */
+
+#include "ena_ethdev.h"
+#include "ena_logs.h"
+
+#include <ena_admin_defs.h>
+
+#define TEST_BIT(val, bit_shift) ((val) & (1UL << (bit_shift)))
+
+#define ENA_HF_RSS_ALL_L2	(ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA)
+#define ENA_HF_RSS_ALL_L3	(ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA)
+#define ENA_HF_RSS_ALL_L4	(ENA_ADMIN_RSS_L4_SP | ENA_ADMIN_RSS_L4_DP)
+#define ENA_HF_RSS_ALL_L3_L4	(ENA_HF_RSS_ALL_L3 | ENA_HF_RSS_ALL_L4)
+#define ENA_HF_RSS_ALL_L2_L3_L4	(ENA_HF_RSS_ALL_L2 | ENA_HF_RSS_ALL_L3_L4)
+
+enum ena_rss_hash_fields {
+	ENA_HF_RSS_TCP4		= ENA_HF_RSS_ALL_L3_L4,
+	ENA_HF_RSS_UDP4		= ENA_HF_RSS_ALL_L3_L4,
+	ENA_HF_RSS_TCP6		= ENA_HF_RSS_ALL_L3_L4,
+	ENA_HF_RSS_UDP6		= ENA_HF_RSS_ALL_L3_L4,
+	ENA_HF_RSS_IP4		= ENA_HF_RSS_ALL_L3,
+	ENA_HF_RSS_IP6		= ENA_HF_RSS_ALL_L3,
+	ENA_HF_RSS_IP4_FRAG	= ENA_HF_RSS_ALL_L3,
+	ENA_HF_RSS_NOT_IP	= ENA_HF_RSS_ALL_L2,
+	ENA_HF_RSS_TCP6_EX	= ENA_HF_RSS_ALL_L3_L4,
+	ENA_HF_RSS_IP6_EX	= ENA_HF_RSS_ALL_L3,
+};
+
+static int ena_fill_indirect_table_default(struct ena_com_dev *ena_dev,
+					   size_t tbl_size,
+					   size_t queue_num);
+static uint64_t ena_admin_hf_to_eth_hf(enum ena_admin_flow_hash_proto proto,
+				       uint16_t field);
+static uint16_t ena_eth_hf_to_admin_hf(enum ena_admin_flow_hash_proto proto,
+				       uint64_t rss_hf);
+static int ena_set_hash_fields(struct ena_com_dev *ena_dev, uint64_t rss_hf);
+static int ena_rss_hash_set(struct ena_com_dev *ena_dev,
+			    struct rte_eth_rss_conf *rss_conf,
+			    bool default_allowed);
+static void ena_reorder_rss_hash_key(uint8_t *reordered_key,
+				     uint8_t *key,
+				     size_t key_size);
+static int ena_get_rss_hash_key(struct ena_com_dev *ena_dev, uint8_t *rss_key);
+
+void ena_rss_key_fill(void *key, size_t size)
+{
+	static bool key_generated;
+	static uint8_t default_key[ENA_HASH_KEY_SIZE];
+	size_t i;
+
+	if (!key_generated) {
+		for (i = 0; i < RTE_DIM(default_key); ++i)
+			default_key[i] = rte_rand() & 0xff;
+		key_generated = true;
+	}
+
+	RTE_ASSERT(size <= sizeof(default_key));
+	rte_memcpy(key, default_key, RTE_MIN(size, sizeof(default_key)));
+}
+
+int ena_rss_reta_update(struct rte_eth_dev *dev,
+			struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t reta_size)
+{
+	struct ena_adapter *adapter = dev->data->dev_private;
+	struct ena_com_dev *ena_dev = &adapter->ena_dev;
+	int rc, i;
+	u16 entry_value;
+	int conf_idx;
+	int idx;
+
+	if (reta_size == 0 || reta_conf == NULL)
+		return -EINVAL;
+
+	if (!(dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_RSS_HASH)) {
+		PMD_DRV_LOG(ERR,
+			"RSS was not configured for the PMD\n");
+		return -ENOTSUP;
+	}
+
+	if (reta_size > ENA_RX_RSS_TABLE_SIZE) {
+		PMD_DRV_LOG(WARNING,
+			"Requested indirection table size (%d) is bigger than supported: %d\n",
+			reta_size, ENA_RX_RSS_TABLE_SIZE);
+		return -EINVAL;
+	}
+
+	/* Prevent RETA table structure update races */
+	rte_spinlock_lock(&adapter->admin_lock);
+	for (i = 0 ; i < reta_size ; i++) {
+		/* Each reta_conf is for 64 entries.
+		 * To support 128 we use 2 conf of 64.
+		 */
+		conf_idx = i / RTE_RETA_GROUP_SIZE;
+		idx = i % RTE_RETA_GROUP_SIZE;
+		if (TEST_BIT(reta_conf[conf_idx].mask, idx)) {
+			entry_value =
+				ENA_IO_RXQ_IDX(reta_conf[conf_idx].reta[idx]);
+
+			rc = ena_com_indirect_table_fill_entry(ena_dev, i,
+				entry_value);
+			if (unlikely(rc != 0)) {
+				PMD_DRV_LOG(ERR,
+					"Cannot fill indirection table\n");
+				rte_spinlock_unlock(&adapter->admin_lock);
+				return rc;
+			}
+		}
+	}
+
+	rc = ena_mp_indirect_table_set(adapter);
+	rte_spinlock_unlock(&adapter->admin_lock);
+	if (unlikely(rc != 0)) {
+		PMD_DRV_LOG(ERR, "Cannot set the indirection table\n");
+		return rc;
+	}
+
+	PMD_DRV_LOG(DEBUG, "RSS configured %d entries for port %d\n",
+		reta_size, dev->data->port_id);
+
+	return 0;
+}
+
+/* Query redirection table. */
+int ena_rss_reta_query(struct rte_eth_dev *dev,
+		       struct rte_eth_rss_reta_entry64 *reta_conf,
+		       uint16_t reta_size)
+{
+	uint32_t indirect_table[ENA_RX_RSS_TABLE_SIZE];
+	struct ena_adapter *adapter = dev->data->dev_private;
+	int rc;
+	int i;
+	int reta_conf_idx;
+	int reta_idx;
+
+	if (reta_size == 0 || reta_conf == NULL)
+		return -EINVAL;
+
+	if (!(dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_RSS_HASH)) {
+		PMD_DRV_LOG(ERR,
+			"RSS was not configured for the PMD\n");
+		return -ENOTSUP;
+	}
+
+	rte_spinlock_lock(&adapter->admin_lock);
+	rc = ena_mp_indirect_table_get(adapter, indirect_table);
+	rte_spinlock_unlock(&adapter->admin_lock);
+	if (unlikely(rc != 0)) {
+		PMD_DRV_LOG(ERR, "Cannot get indirection table\n");
+		return rc;
+	}
+
+	for (i = 0 ; i < reta_size ; i++) {
+		reta_conf_idx = i / RTE_RETA_GROUP_SIZE;
+		reta_idx = i % RTE_RETA_GROUP_SIZE;
+		if (TEST_BIT(reta_conf[reta_conf_idx].mask, reta_idx))
+			reta_conf[reta_conf_idx].reta[reta_idx] =
+				ENA_IO_RXQ_IDX_REV(indirect_table[i]);
+	}
+
+	return 0;
+}
+
+static int ena_fill_indirect_table_default(struct ena_com_dev *ena_dev,
+					   size_t tbl_size,
+					   size_t queue_num)
+{
+	size_t i;
+	int rc;
+	uint16_t val;
+
+	for (i = 0; i < tbl_size; ++i) {
+		val = i % queue_num;
+		rc = ena_com_indirect_table_fill_entry(ena_dev, i,
+			ENA_IO_RXQ_IDX(val));
+		if (unlikely(rc != 0)) {
+			PMD_DRV_LOG(DEBUG,
+				"Failed to set %zu indirection table entry with val %" PRIu16 "\n",
+				i, val);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static uint64_t ena_admin_hf_to_eth_hf(enum ena_admin_flow_hash_proto proto,
+				       uint16_t fields)
+{
+	uint64_t rss_hf = 0;
+
+	/* If no fields are activated, then RSS is disabled for this proto */
+	if ((fields & ENA_HF_RSS_ALL_L2_L3_L4) == 0)
+		return 0;
+
+	/* Convert proto to ETH flag */
+	switch (proto) {
+	case ENA_ADMIN_RSS_TCP4:
+		rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP;
+		break;
+	case ENA_ADMIN_RSS_UDP4:
+		rss_hf |= ETH_RSS_NONFRAG_IPV4_UDP;
+		break;
+	case ENA_ADMIN_RSS_TCP6:
+		rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP;
+		break;
+	case ENA_ADMIN_RSS_UDP6:
+		rss_hf |= ETH_RSS_NONFRAG_IPV6_UDP;
+		break;
+	case ENA_ADMIN_RSS_IP4:
+		rss_hf |= ETH_RSS_IPV4;
+		break;
+	case ENA_ADMIN_RSS_IP6:
+		rss_hf |= ETH_RSS_IPV6;
+		break;
+	case ENA_ADMIN_RSS_IP4_FRAG:
+		rss_hf |= ETH_RSS_FRAG_IPV4;
+		break;
+	case ENA_ADMIN_RSS_NOT_IP:
+		rss_hf |= ETH_RSS_L2_PAYLOAD;
+		break;
+	case ENA_ADMIN_RSS_TCP6_EX:
+		rss_hf |= ETH_RSS_IPV6_TCP_EX;
+		break;
+	case ENA_ADMIN_RSS_IP6_EX:
+		rss_hf |= ETH_RSS_IPV6_EX;
+		break;
+	default:
+		break;
+	};
+
+	/* Check if only DA or SA is being used for L3. */
+	switch (fields & ENA_HF_RSS_ALL_L3) {
+	case ENA_ADMIN_RSS_L3_SA:
+		rss_hf |= ETH_RSS_L3_SRC_ONLY;
+		break;
+	case ENA_ADMIN_RSS_L3_DA:
+		rss_hf |= ETH_RSS_L3_DST_ONLY;
+		break;
+	default:
+		break;
+	};
+
+	/* Check if only DA or SA is being used for L4. */
+	switch (fields & ENA_HF_RSS_ALL_L4) {
+	case ENA_ADMIN_RSS_L4_SP:
+		rss_hf |= ETH_RSS_L4_SRC_ONLY;
+		break;
+	case ENA_ADMIN_RSS_L4_DP:
+		rss_hf |= ETH_RSS_L4_DST_ONLY;
+		break;
+	default:
+		break;
+	};
+
+	return rss_hf;
+}
+
+static uint16_t ena_eth_hf_to_admin_hf(enum ena_admin_flow_hash_proto proto,
+				       uint64_t rss_hf)
+{
+	uint16_t fields_mask = 0;
+
+	/* L2 always uses source and destination addresses. */
+	fields_mask = ENA_ADMIN_RSS_L2_DA | ENA_ADMIN_RSS_L2_SA;
+
+	/* Determine which fields of L3 should be used. */
+	switch (rss_hf & (ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY)) {
+	case ETH_RSS_L3_DST_ONLY:
+		fields_mask |= ENA_ADMIN_RSS_L3_DA;
+		break;
+	case ETH_RSS_L3_SRC_ONLY:
+		fields_mask |= ENA_ADMIN_RSS_L3_SA;
+		break;
+	default:
+		/*
+		 * If SRC nor DST aren't set, it means both of them should be
+		 * used.
+		 */
+		fields_mask |= ENA_HF_RSS_ALL_L3;
+	}
+
+	/* Determine which fields of L4 should be used. */
+	switch (rss_hf & (ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY)) {
+	case ETH_RSS_L4_DST_ONLY:
+		fields_mask |= ENA_ADMIN_RSS_L4_DP;
+		break;
+	case ETH_RSS_L4_SRC_ONLY:
+		fields_mask |= ENA_ADMIN_RSS_L4_SP;
+		break;
+	default:
+		/*
+		 * If SRC nor DST aren't set, it means both of them should be
+		 * used.
+		 */
+		fields_mask |= ENA_HF_RSS_ALL_L4;
+	}
+
+	/* Return appropriate hash fields. */
+	switch (proto) {
+	case ENA_ADMIN_RSS_TCP4:
+		return ENA_HF_RSS_TCP4 & fields_mask;
+	case ENA_ADMIN_RSS_UDP4:
+		return ENA_HF_RSS_UDP4 & fields_mask;
+	case ENA_ADMIN_RSS_TCP6:
+		return ENA_HF_RSS_TCP6 & fields_mask;
+	case ENA_ADMIN_RSS_UDP6:
+		return ENA_HF_RSS_UDP6 & fields_mask;
+	case ENA_ADMIN_RSS_IP4:
+		return ENA_HF_RSS_IP4 & fields_mask;
+	case ENA_ADMIN_RSS_IP6:
+		return ENA_HF_RSS_IP6 & fields_mask;
+	case ENA_ADMIN_RSS_IP4_FRAG:
+		return ENA_HF_RSS_IP4_FRAG & fields_mask;
+	case ENA_ADMIN_RSS_NOT_IP:
+		return ENA_HF_RSS_NOT_IP & fields_mask;
+	case ENA_ADMIN_RSS_TCP6_EX:
+		return ENA_HF_RSS_TCP6_EX & fields_mask;
+	case ENA_ADMIN_RSS_IP6_EX:
+		return ENA_HF_RSS_IP6_EX & fields_mask;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int ena_set_hash_fields(struct ena_com_dev *ena_dev, uint64_t rss_hf)
+{
+	struct ena_admin_proto_input selected_fields[ENA_ADMIN_RSS_PROTO_NUM] = {};
+	int rc, i;
+
+	/* Turn on appropriate fields for each requested packet type */
+	if ((rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) != 0)
+		selected_fields[ENA_ADMIN_RSS_TCP4].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP4, rss_hf);
+
+	if ((rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) != 0)
+		selected_fields[ENA_ADMIN_RSS_UDP4].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_UDP4, rss_hf);
+
+	if ((rss_hf & ETH_RSS_NONFRAG_IPV6_TCP) != 0)
+		selected_fields[ENA_ADMIN_RSS_TCP6].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP6, rss_hf);
+
+	if ((rss_hf & ETH_RSS_NONFRAG_IPV6_UDP) != 0)
+		selected_fields[ENA_ADMIN_RSS_UDP6].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_UDP6, rss_hf);
+
+	if ((rss_hf & ETH_RSS_IPV4) != 0)
+		selected_fields[ENA_ADMIN_RSS_IP4].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP4, rss_hf);
+
+	if ((rss_hf & ETH_RSS_IPV6) != 0)
+		selected_fields[ENA_ADMIN_RSS_IP6].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP6, rss_hf);
+
+	if ((rss_hf & ETH_RSS_FRAG_IPV4) != 0)
+		selected_fields[ENA_ADMIN_RSS_IP4_FRAG].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP4_FRAG, rss_hf);
+
+	if ((rss_hf & ETH_RSS_L2_PAYLOAD) != 0)
+		selected_fields[ENA_ADMIN_RSS_NOT_IP].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_NOT_IP, rss_hf);
+
+	if ((rss_hf & ETH_RSS_IPV6_TCP_EX) != 0)
+		selected_fields[ENA_ADMIN_RSS_TCP6_EX].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP6_EX, rss_hf);
+
+	if ((rss_hf & ETH_RSS_IPV6_EX) != 0)
+		selected_fields[ENA_ADMIN_RSS_IP6_EX].fields =
+			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP6_EX, rss_hf);
+
+	/* Try to write them to the device */
+	for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; i++) {
+		rc = ena_com_fill_hash_ctrl(ena_dev,
+			(enum ena_admin_flow_hash_proto)i,
+			selected_fields[i].fields);
+		if (unlikely(rc != 0)) {
+			PMD_DRV_LOG(DEBUG,
+				"Failed to set ENA HF %d with fields %" PRIu16 "\n",
+				i, selected_fields[i].fields);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int ena_rss_hash_set(struct ena_com_dev *ena_dev,
+			    struct rte_eth_rss_conf *rss_conf,
+			    bool default_allowed)
+{
+	uint8_t hw_rss_key[ENA_HASH_KEY_SIZE];
+	uint8_t *rss_key;
+	int rc;
+
+	if (rss_conf->rss_key != NULL) {
+		/* Reorder the RSS key bytes for the hardware requirements. */
+		ena_reorder_rss_hash_key(hw_rss_key, rss_conf->rss_key,
+			ENA_HASH_KEY_SIZE);
+		rss_key = hw_rss_key;
+	} else {
+		rss_key = NULL;
+	}
+
+	/* If the rss_key is NULL, then the randomized key will be used. */
+	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ,
+		rss_key, ENA_HASH_KEY_SIZE, 0);
+	if (rc != 0 && !(default_allowed && rc == ENA_COM_UNSUPPORTED)) {
+		PMD_DRV_LOG(ERR,
+			"Failed to set RSS hash function in the device\n");
+		return rc;
+	}
+
+	rc = ena_set_hash_fields(ena_dev, rss_conf->rss_hf);
+	if (rc == ENA_COM_UNSUPPORTED) {
+		if (rss_conf->rss_key == NULL && !default_allowed) {
+			PMD_DRV_LOG(ERR,
+				"Setting RSS hash fields is not supported\n");
+			return -ENOTSUP;
+		}
+		PMD_DRV_LOG(WARNING,
+			"Setting RSS hash fields is not supported. Using default values: 0x%" PRIx64 "\n",
+			(uint64_t)(ENA_ALL_RSS_HF));
+	} else if (rc != 0)  {
+		PMD_DRV_LOG(ERR, "Failed to set RSS hash fields\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+/* ENA HW interprets the RSS key in reverse bytes order. Because of that, the
+ * key must be processed upon interaction with ena_com layer.
+ */
+static void ena_reorder_rss_hash_key(uint8_t *reordered_key,
+				     uint8_t *key,
+				     size_t key_size)
+{
+	size_t i, rev_i;
+
+	for (i = 0, rev_i = key_size - 1; i < key_size; ++i, --rev_i)
+		reordered_key[i] = key[rev_i];
+}
+
+static int ena_get_rss_hash_key(struct ena_com_dev *ena_dev, uint8_t *rss_key)
+{
+	uint8_t hw_rss_key[ENA_HASH_KEY_SIZE];
+	int rc;
+
+	/* The default RSS hash key cannot be retrieved from the HW. Unless it's
+	 * explicitly set, this operation shouldn't be supported.
+	 */
+	if (ena_dev->rss.hash_key == NULL) {
+		PMD_DRV_LOG(WARNING,
+			"Retrieving default RSS hash key is not supported\n");
+		return -ENOTSUP;
+	}
+
+	rc = ena_com_get_hash_key(ena_dev, hw_rss_key);
+	if (rc != 0)
+		return rc;
+
+	ena_reorder_rss_hash_key(rss_key, hw_rss_key, ENA_HASH_KEY_SIZE);
+
+	return 0;
+}
+
+int ena_rss_configure(struct ena_adapter *adapter)
+{
+	struct rte_eth_rss_conf *rss_conf;
+	struct ena_com_dev *ena_dev;
+	int rc;
+
+	ena_dev = &adapter->ena_dev;
+	rss_conf = &adapter->edev_data->dev_conf.rx_adv_conf.rss_conf;
+
+	if (adapter->edev_data->nb_rx_queues == 0)
+		return 0;
+
+	/* Restart the indirection table. The number of queues could change
+	 * between start/stop calls, so it must be reinitialized with default
+	 * values.
+	 */
+	rc = ena_fill_indirect_table_default(ena_dev, ENA_RX_RSS_TABLE_SIZE,
+		adapter->edev_data->nb_rx_queues);
+	if (unlikely(rc != 0)) {
+		PMD_DRV_LOG(ERR,
+			"Failed to fill indirection table with default values\n");
+		return rc;
+	}
+
+	rc = ena_com_indirect_table_set(ena_dev);
+	if (unlikely(rc != 0 && rc != ENA_COM_UNSUPPORTED)) {
+		PMD_DRV_LOG(ERR,
+			"Failed to set indirection table in the device\n");
+		return rc;
+	}
+
+	rc = ena_rss_hash_set(ena_dev, rss_conf, true);
+	if (unlikely(rc != 0)) {
+		PMD_DRV_LOG(ERR, "Failed to set RSS hash\n");
+		return rc;
+	}
+
+	PMD_DRV_LOG(DEBUG, "RSS configured for port %d\n",
+		adapter->edev_data->port_id);
+
+	return 0;
+}
+
+int ena_rss_hash_update(struct rte_eth_dev *dev,
+			struct rte_eth_rss_conf *rss_conf)
+{
+	struct ena_adapter *adapter = dev->data->dev_private;
+	int rc;
+
+	rte_spinlock_lock(&adapter->admin_lock);
+	rc = ena_rss_hash_set(&adapter->ena_dev, rss_conf, false);
+	rte_spinlock_unlock(&adapter->admin_lock);
+	if (unlikely(rc != 0)) {
+		PMD_DRV_LOG(ERR, "Failed to set RSS hash\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+int ena_rss_hash_conf_get(struct rte_eth_dev *dev,
+			  struct rte_eth_rss_conf *rss_conf)
+{
+	struct ena_adapter *adapter = dev->data->dev_private;
+	struct ena_com_dev *ena_dev = &adapter->ena_dev;
+	enum ena_admin_flow_hash_proto proto;
+	uint64_t rss_hf = 0;
+	int rc, i;
+	uint16_t admin_hf;
+	static bool warn_once;
+
+	if (!(dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_RSS_HASH)) {
+		PMD_DRV_LOG(ERR, "RSS was not configured for the PMD\n");
+		return -ENOTSUP;
+	}
+
+	if (rss_conf->rss_key != NULL) {
+		rc = ena_get_rss_hash_key(ena_dev, rss_conf->rss_key);
+		if (unlikely(rc != 0)) {
+			PMD_DRV_LOG(ERR,
+				"Cannot retrieve RSS hash key, err: %d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; ++i) {
+		proto = (enum ena_admin_flow_hash_proto)i;
+		rte_spinlock_lock(&adapter->admin_lock);
+		rc = ena_com_get_hash_ctrl(ena_dev, proto, &admin_hf);
+		rte_spinlock_unlock(&adapter->admin_lock);
+		if (rc == ENA_COM_UNSUPPORTED) {
+			/* As some devices may support only reading rss hash
+			 * key and not the hash ctrl, we want to notify the
+			 * caller that this feature is only partially supported
+			 * and do not return an error - the caller could be
+			 * interested only in the key value.
+			 */
+			if (!warn_once) {
+				PMD_DRV_LOG(WARNING,
+					"Reading hash control from the device is not supported. .rss_hf will contain a default value.\n");
+				warn_once = true;
+			}
+			rss_hf = ENA_ALL_RSS_HF;
+			break;
+		} else if (rc != 0) {
+			PMD_DRV_LOG(ERR,
+				"Failed to retrieve hash ctrl for proto: %d with err: %d\n",
+				i, rc);
+			return rc;
+		}
+
+		rss_hf |= ena_admin_hf_to_eth_hf(proto, admin_hf);
+	}
+
+	rss_conf->rss_hf = rss_hf;
+	return 0;
+}
diff --git a/drivers/net/ena/meson.build b/drivers/net/ena/meson.build
index 189903b901..d02ed3f64f 100644
--- a/drivers/net/ena/meson.build
+++ b/drivers/net/ena/meson.build
@@ -1,9 +1,18 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2018 Intel Corporation
 
-sources = files('ena_ethdev.c',
-	'base/ena_com.c',
-	'base/ena_eth_com.c')
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+sources = files(
+        'ena_ethdev.c',
+        'ena_rss.c',
+        'base/ena_com.c',
+        'base/ena_eth_com.c',
+)
 
 deps += ['timer']
 
-- 
2.17.1

