Skip to contentSkip to conversation

ENA release 2.15.0

PATCH Superseded Shai Brandes 2 participants 18 messages Oct 18 – Oct 20

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v2 cover ENA release 2.15.0

Hello all,
This series upgrades HAL and fixes two PHC correctness issues,
an LLQ feature version not communicated to the device, and
a failed LLQ configuration zeroing the negotiated tx_max_header_size. Additionally it adds n-tuple Rx flow steering support through the rte_flow API. Review and comments are welcome

Best regards,
Shai Brandes

---
v2:
* Fixed Fedora compilation issue

Shai Brandes (13):
net/ena: avoid using un-needed admin response buffers net/ena/base: fix race in PHC destroy net/ena/base: fix missing barriers in PHC timestamp read net/ena/base: rename bounce buffer references net/ena/base: add LLQ policy inline helper net/ena/base: fix LLQ feature version sent to device net/ena/base: deduplicate LLQ entry write and advance net/ena/base: deduplicate meta caching config flag net/ena/base: split LLQ info into datapath and config net/ena/base: fix LLQ config failure flow net/ena: support flow API for n-tuple Rx steering net/ena/base: remove x86 Tx LLQ write barrier net/ena: upgrade driver version to 2.15.0

 doc/guides/nics/ena.rst                       |  26 +
 doc/guides/nics/features/ena.ini              |  10 +
 doc/guides/rel_notes/release_26_11.rst        |   6 +
 drivers/net/ena/base/ena_com.c                | 793 +++++++++++++-----
 drivers/net/ena/base/ena_com.h                | 115 ++-
 .../net/ena/base/ena_defs/ena_admin_defs.h    |  83 +-
 drivers/net/ena/base/ena_eth_com.c            | 131 +--
 drivers/net/ena/base/ena_eth_com.h            |  18 +-
 drivers/net/ena/base/ena_plat_dpdk.h          |   8 +
 drivers/net/ena/ena_ethdev.c                  |  73 +-
 drivers/net/ena/ena_ethdev.h                  |   3 +-
 drivers/net/ena/ena_flow.c                    | 542 ++++++++++++
 drivers/net/ena/ena_flow.h                    |  12 +
 drivers/net/ena/meson.build                   |   1 +
 14 files changed, 1512 insertions(+), 309 deletions(-)
 create mode 100644 drivers/net/ena/ena_flow.c
 create mode 100644 drivers/net/ena/ena_flow.h
Signature · 1 line
2.17.1
#1 lore raw

v3 cover ENA release 2.15.0

Hello all,
This series upgrades HAL and fixes two PHC correctness issues,
an LLQ feature version not communicated to the device, and
a failed LLQ configuration zeroing the negotiated tx_max_header_size. Additionally it adds n-tuple Rx flow steering support through the rte_flow API. Review and comments are welcome

Best regards,
Shai Brandes

---
v2:
* Fixed Fedora compilation issue

v3:
- Fixed a minor typo in a comment
- Rebased on next-net-for-main to fix the CI apply failure.
- Placed the ENA release-notes entry alphabetically before Broadcom bnxt.

Shai Brandes (13):
net/ena: avoid using un-needed admin response buffers net/ena/base: fix race in PHC destroy net/ena/base: fix missing barriers in PHC timestamp read net/ena/base: rename bounce buffer references net/ena/base: add LLQ policy inline helper net/ena/base: fix LLQ feature version sent to device net/ena/base: deduplicate LLQ entry write and advance net/ena/base: deduplicate meta caching config flag net/ena/base: split LLQ info into datapath and config net/ena/base: fix LLQ config failure flow net/ena: support flow API for n-tuple Rx steering net/ena/base: remove x86 Tx LLQ write barrier net/ena: upgrade driver version to 2.15.0

 doc/guides/nics/ena.rst                       |  26 +
 doc/guides/nics/features/ena.ini              |  10 +
 doc/guides/rel_notes/release_26_11.rst        |   6 +
 drivers/net/ena/base/ena_com.c                | 793 +++++++++++++-----
 drivers/net/ena/base/ena_com.h                | 115 ++-
 .../net/ena/base/ena_defs/ena_admin_defs.h    |  83 +-
 drivers/net/ena/base/ena_eth_com.c            | 131 +--
 drivers/net/ena/base/ena_eth_com.h            |  18 +-
 drivers/net/ena/base/ena_plat_dpdk.h          |   8 +
 drivers/net/ena/ena_ethdev.c                  |  73 +-
 drivers/net/ena/ena_ethdev.h                  |   3 +-
 drivers/net/ena/ena_flow.c                    | 542 ++++++++++++
 drivers/net/ena/ena_flow.h                    |  12 +
 drivers/net/ena/meson.build                   |   1 +
 14 files changed, 1512 insertions(+), 309 deletions(-)
 create mode 100644 drivers/net/ena/ena_flow.c
 create mode 100644 drivers/net/ena/ena_flow.h

base-commit: 3b99fca0dcd388585b24947e2a851001b159757b

Signature · 1 line
2.17.1
#2 lore raw

PATCH v3 1/13 net/ena: avoid using un-needed admin response buffers

There are admin commands that do not require a response parsing. For these, there's no need to set a response buffer.

---
 drivers/net/ena/base/ena_com.c | 356 +++++++++++++++++----------------
 1 file changed, 179 insertions(+), 177 deletions(-)
drivers/net/ena/base/ena_com.c +179 -177
index f0936a6262..b1fe0bcdf7 100644
@@ -613,6 +613,149 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c
 	return ret;
 }
 
+static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx,
+							struct ena_com_admin_queue *admin_queue)
+{
+	unsigned long flags = 0;
+	int ret;
+
+	ENA_WAIT_EVENT_WAIT(comp_ctx->wait_event,
+			    admin_queue->completion_timeout);
+
+	/* In case the command wasn't completed find out the root cause.
+	 * There might be 2 kinds of errors
+	 * 1) No completion (timeout reached)
+	 * 2) There is completion but the device didn't get any msi-x interrupt.
+	 */
+	if (unlikely(comp_ctx->status == ENA_CMD_SUBMITTED)) {
+		ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags);
+		ena_com_handle_admin_completion(admin_queue);
+		admin_queue->stats.no_completion++;
+		ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags);
+
+		ret = ENA_COM_TIMER_EXPIRED;
+		/* Now that the admin queue has been polled, check whether the
+		 * request was fulfilled by the device
+		 */
+		if (comp_ctx->status != ENA_CMD_COMPLETED) {
+			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);
+			goto close_aq;
+		}
+
+		admin_queue->is_missing_admin_interrupt = true;
+
+		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");
+		/* If fallback to polling is not enabled, missing an interrupt
+		 * is considered an error
+		 */
+		if (!admin_queue->auto_polling)
+			goto close_aq;
+
+		ena_com_set_admin_polling_mode(admin_queue->ena_dev, true);
+	} else if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) {
+		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);
+		ret = ENA_COM_NO_DEVICE;
+		goto err;
+	}
+
+	ret = ena_com_admin_status_to_errno(admin_queue, comp_ctx);
+	comp_ctxt_release(admin_queue, comp_ctx);
+
+	return ret;
+close_aq:
+	admin_queue->running_state = false;
+err:
+	comp_ctxt_release(admin_queue, comp_ctx);
+
+	return ret;
+}
+
+/* There are two types to wait for completion.
+ * Polling mode - wait until the completion is available.
+ * Async mode - wait on wait queue until the completion is ready
+ * (or the timeout expired).
+ * It is expected that the IRQ called ena_com_handle_admin_completion
+ * to mark the completions.
+ */
+static int ena_com_wait_and_process_admin_cq(struct ena_comp_ctx *comp_ctx,
+					     struct ena_com_admin_queue *admin_queue)
+{
+	if (admin_queue->polling)
+		return ena_com_wait_and_process_admin_cq_polling(comp_ctx,
+								 admin_queue);
+
+	return ena_com_wait_and_process_admin_cq_interrupts(comp_ctx,
+							    admin_queue);
+}
+
+/* ena_com_execute_admin_command - Execute admin command
+ * @admin_queue: admin queue.
+ * @cmd: the admin command to execute.
+ * @cmd_size: the command size.
+ * @cmd_completion: command completion return value.
+ * @cmd_comp_size: command completion size.
+
+ * Submit an admin command and then wait until the device returns a
+ * completion.
+ * The completion will be copied into cmd_comp.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+int ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue,
+				  struct ena_admin_aq_entry *cmd,
+				  size_t cmd_size,
+				  struct ena_admin_acq_entry *comp,
+				  size_t comp_size)
+{
+	struct ena_comp_ctx *comp_ctx;
+	int ret;
+
+	comp_ctx = ena_com_submit_admin_cmd(admin_queue, cmd, cmd_size,
+					    comp, comp_size);
+	if (IS_ERR(comp_ctx)) {
+		ret = PTR_ERR(comp_ctx);
+		if (ret != ENA_COM_NO_DEVICE)
+			ena_trc_err(admin_queue->ena_dev,
+				    "Failed to submit command [%d]\n",
+				    ret);
+
+		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(admin_queue->ena_dev,
+				    "Failed to process command [%d]\n",
+				    ret);
+	}
+	return ret;
+}
+
+/* ena_com_execute_admin_command_no_resp - Execute admin command without response payload
+ * @admin_queue: admin queue.
+ * @cmd: the admin command to execute.
+ * @cmd_size: the command size.
+ *
+ * Submit an admin command and then wait until the device returns a
+ * completion, no return payload is expected.
+ *
+ * @return - 0 on success, negative value on failure.
+ */
+static int ena_com_execute_admin_command_no_resp(struct ena_com_admin_queue *admin_queue,
+						 struct ena_admin_aq_entry *cmd,
+						 size_t cmd_size)
+{
+	return ena_com_execute_admin_command(admin_queue, cmd, cmd_size, NULL, 0);
+}
+
 /*
  * Set the LLQ configurations of the firmware
  *
@@ -623,7 +766,6 @@ static int ena_com_set_llq(struct ena_com_dev *ena_dev)
 {
 	struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
 	struct ena_com_admin_queue *admin_queue;
-	struct ena_admin_set_feat_resp resp;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
 
@@ -642,11 +784,9 @@ static int ena_com_set_llq(struct ena_com_dev *ena_dev)
 		BIT(ENA_ADMIN_DISABLE_META_CACHING) |
 		BIT(ENA_ADMIN_LIMIT_TX_BURST);
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&resp,
-					    sizeof(resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 
 	if (unlikely(ret))
 		ena_trc_err(ena_dev, "Failed to set LLQ configurations: %d\n", ret);
@@ -782,62 +922,6 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 	return rc;
 }
 
-static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx,
-							struct ena_com_admin_queue *admin_queue)
-{
-	unsigned long flags = 0;
-	int ret;
-
-	ENA_WAIT_EVENT_WAIT(comp_ctx->wait_event,
-			    admin_queue->completion_timeout);
-
-	/* In case the command wasn't completed find out the root cause.
-	 * There might be 2 kinds of errors
-	 * 1) No completion (timeout reached)
-	 * 2) There is completion but the device didn't get any msi-x interrupt.
-	 */
-	if (unlikely(comp_ctx->status == ENA_CMD_SUBMITTED)) {
-		ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags);
-		ena_com_handle_admin_completion(admin_queue);
-		admin_queue->stats.no_completion++;
-		ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags);
-
-		if (comp_ctx->status == ENA_CMD_COMPLETED) {
-			admin_queue->is_missing_admin_interrupt = true;
-			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(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.
-		 * This will happen if there is a completion without an interrupt
-		 * and autopolling mode is enabled. Continuing normal execution in such case
-		 */
-		if (!admin_queue->polling) {
-			admin_queue->running_state = false;
-			ret = ENA_COM_TIMER_EXPIRED;
-			goto err;
-		}
-	} else if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) {
-		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);
-		ret = ENA_COM_NO_DEVICE;
-		goto err;
-	}
-	ret = ena_com_admin_status_to_errno(admin_queue, comp_ctx);
-err:
-	comp_ctxt_release(admin_queue, comp_ctx);
-	return ret;
-}
-
 /* This method read the hardware device register through posting writes
  * and waiting for response
  * On timeout the function will return ENA_MMIO_READ_TIMEOUT
@@ -903,29 +987,10 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
 	return ret;
 }
 
-/* There are two types to wait for completion.
- * Polling mode - wait until the completion is available.
- * Async mode - wait on wait queue until the completion is ready
- * (or the timeout expired).
- * It is expected that the IRQ called ena_com_handle_admin_completion
- * to mark the completions.
- */
-static int ena_com_wait_and_process_admin_cq(struct ena_comp_ctx *comp_ctx,
-					     struct ena_com_admin_queue *admin_queue)
-{
-	if (admin_queue->polling)
-		return ena_com_wait_and_process_admin_cq_polling(comp_ctx,
-								 admin_queue);
-
-	return ena_com_wait_and_process_admin_cq_interrupts(comp_ctx,
-							    admin_queue);
-}
-
 static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev,
 				 struct ena_com_io_sq *io_sq)
 {
 	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
-	struct ena_admin_acq_destroy_sq_resp_desc destroy_resp;
 	struct ena_admin_aq_destroy_sq_cmd destroy_cmd;
 	u8 direction;
 	int ret;
@@ -945,11 +1010,9 @@ static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev,
 	destroy_cmd.sq.sq_idx = io_sq->idx;
 	destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_SQ;
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&destroy_cmd,
-					    sizeof(destroy_cmd),
-					    (struct ena_admin_acq_entry *)&destroy_resp,
-					    sizeof(destroy_resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&destroy_cmd,
+						    sizeof(destroy_cmd));
 
 	if (unlikely(ret && (ret != ENA_COM_NO_DEVICE)))
 		ena_trc_err(ena_dev, "Failed to destroy io sq error: %d\n", ret);
@@ -1152,7 +1215,6 @@ int ena_com_set_hw_timestamping_configuration(struct ena_com_dev *ena_dev,
 					      u8 tx_enable,
 					      u8 rx_enable)
 {
-	struct ena_admin_set_feat_resp resp;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
 
@@ -1170,11 +1232,9 @@ int ena_com_set_hw_timestamping_configuration(struct ena_com_dev *ena_dev,
 	cmd.u.hw_ts.rx = rx_enable ? ENA_ADMIN_HW_TIMESTAMP_RX_SUPPORT_ALL :
 				     ENA_ADMIN_HW_TIMESTAMP_RX_SUPPORT_NONE;
 
-	ret = ena_com_execute_admin_command(&ena_dev->admin_queue,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&resp,
-					    sizeof(resp));
+	ret = ena_com_execute_admin_command_no_resp(&ena_dev->admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 	if (unlikely(ret)) {
 		ena_trc_err(ena_dev,
 			    "Failed to set HW timestamping configuration, error: %d\n",
@@ -1469,37 +1529,6 @@ static void ena_com_update_intr_delay_resolution(struct ena_com_dev *ena_dev,
 /*******************************      API       ******************************/
 /*****************************************************************************/
 
-int ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue,
-				  struct ena_admin_aq_entry *cmd,
-				  size_t cmd_size,
-				  struct ena_admin_acq_entry *comp,
-				  size_t comp_size)
-{
-	struct ena_comp_ctx *comp_ctx;
-	int ret;
-
-	comp_ctx = ena_com_submit_admin_cmd(admin_queue, cmd, cmd_size,
-					    comp, comp_size);
-	if (IS_ERR(comp_ctx)) {
-		ret = PTR_ERR(comp_ctx);
-		if (ret != ENA_COM_NO_DEVICE)
-			ena_trc_err(admin_queue->ena_dev,
-				    "Failed to submit command [%d]\n",
-				    ret);
-
-		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(admin_queue->ena_dev,
-				    "Failed to process command [%d]\n",
-				    ret);
-	}
-	return ret;
-}
-
 int ena_com_create_io_cq(struct ena_com_dev *ena_dev,
 			 struct ena_com_io_cq *io_cq)
 {
@@ -1608,7 +1637,6 @@ int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev,
 			  struct ena_com_io_cq *io_cq)
 {
 	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
-	struct ena_admin_acq_destroy_cq_resp_desc destroy_resp;
 	struct ena_admin_aq_destroy_cq_cmd destroy_cmd;
 	int ret;
 
@@ -1617,11 +1645,9 @@ int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev,
 	destroy_cmd.cq_idx = io_cq->idx;
 	destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_CQ;
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&destroy_cmd,
-					    sizeof(destroy_cmd),
-					    (struct ena_admin_acq_entry *)&destroy_resp,
-					    sizeof(destroy_resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&destroy_cmd,
+						    sizeof(destroy_cmd));
 
 	if (unlikely(ret && (ret != ENA_COM_NO_DEVICE)))
 		ena_trc_err(ena_dev, "Failed to destroy IO CQ. error: %d\n", ret);
@@ -1660,7 +1686,6 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag)
 {
 	struct ena_com_admin_queue *admin_queue;
 	struct ena_admin_get_feat_resp get_resp;
-	struct ena_admin_set_feat_resp resp;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
 
@@ -1685,11 +1710,9 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag)
 	cmd.feat_common.feature_id = ENA_ADMIN_AENQ_CONFIG;
 	cmd.u.aenq.enabled_groups = groups_flag;
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&resp,
-					    sizeof(resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 
 	if (unlikely(ret))
 		ena_trc_err(ena_dev, "Failed to config AENQ ret: %d\n", ret);
@@ -1879,7 +1902,6 @@ 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;
 
@@ -1934,11 +1956,9 @@ int ena_com_phc_config(struct ena_com_dev *ena_dev)
 	}
 
 	/* 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));
+	ret = ena_com_execute_admin_command_no_resp(&ena_dev->admin_queue,
+						    (struct ena_admin_aq_entry *)&set_feat_cmd,
+						    sizeof(set_feat_cmd));
 
 	if (unlikely(ret)) {
 		ena_trc_err(ena_dev, "Failed to enable PHC, error: %d\n", ret);
@@ -2822,7 +2842,6 @@ int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32
 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_resp resp;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
 
@@ -2839,11 +2858,9 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu)
 	cmd.feat_common.feature_id = ENA_ADMIN_MTU;
 	cmd.u.mtu.mtu = mtu;
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&resp,
-					    sizeof(resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 
 	if (unlikely(ret))
 		ena_trc_err(ena_dev, "Failed to set mtu %d. error: %d\n", mtu, ret);
@@ -2859,7 +2876,6 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
 {
 	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
 	struct ena_admin_get_feat_resp get_resp;
-	struct ena_admin_set_feat_resp resp;
 	struct ena_rss *rss = &ena_dev->rss;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
@@ -2902,11 +2918,9 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
 
 	cmd.control_buffer.length = sizeof(*rss->hash_key);
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&resp,
-					    sizeof(resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 	if (unlikely(ret)) {
 		ena_trc_err(ena_dev, "Failed to set hash function %d. error: %d\n",
 			    rss->hash_func, ret);
@@ -3031,7 +3045,6 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev)
 	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
 	struct ena_admin_feature_rss_hash_control *hash_ctrl;
 	struct ena_rss *rss = &ena_dev->rss;
-	struct ena_admin_set_feat_resp resp;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
 
@@ -3063,11 +3076,9 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev)
 	}
 	cmd.control_buffer.length = sizeof(*hash_ctrl);
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&resp,
-					    sizeof(resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 	if (unlikely(ret))
 		ena_trc_err(ena_dev, "Failed to set hash input. error: %d\n", ret);
 
@@ -3195,7 +3206,6 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev)
 {
 	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
 	struct ena_rss *rss = &ena_dev->rss;
-	struct ena_admin_set_feat_resp resp;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
 
@@ -3232,11 +3242,9 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev)
 	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,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&resp,
-					    sizeof(resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 
 	if (unlikely(ret))
 		ena_trc_err(ena_dev, "Failed to set indirect table. error: %d\n", ret);
@@ -3420,7 +3428,6 @@ int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
 {
 	struct ena_host_attribute *host_attr = &ena_dev->host_attr;
 	struct ena_com_admin_queue *admin_queue;
-	struct ena_admin_set_feat_resp resp;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
 
@@ -3452,11 +3459,9 @@ int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
 
 	cmd.u.host_attr.debug_area_size = host_attr->debug_area_size;
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&resp,
-					    sizeof(resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 
 	if (unlikely(ret))
 		ena_trc_err(ena_dev, "Failed to set host attributes: %d\n", ret);
@@ -3579,7 +3584,6 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
 
 int ena_com_set_frag_bypass(struct ena_com_dev *ena_dev, bool enable)
 {
-	struct ena_admin_set_feat_resp set_feat_resp;
 	struct ena_com_admin_queue *admin_queue;
 	struct ena_admin_set_feat_cmd cmd;
 	int ret;
@@ -3599,11 +3603,9 @@ int ena_com_set_frag_bypass(struct ena_com_dev *ena_dev, bool enable)
 	cmd.feat_common.feature_version = ENA_ADMIN_FRAG_BYPASS_FEATURE_VERSION_0;
 	cmd.u.frag_bypass.enable = (u8)enable;
 
-	ret = ena_com_execute_admin_command(admin_queue,
-					    (struct ena_admin_aq_entry *)&cmd,
-					    sizeof(cmd),
-					    (struct ena_admin_acq_entry *)&set_feat_resp,
-					    sizeof(set_feat_resp));
+	ret = ena_com_execute_admin_command_no_resp(admin_queue,
+						    (struct ena_admin_aq_entry *)&cmd,
+						    sizeof(cmd));
 
 	if (unlikely(ret))
 		ena_trc_err(ena_dev, "Failed to enable frag bypass. error: %d\n", ret);
Signature · 1 line
2.17.1
#3 lore raw

PATCH v3 2/13 net/ena/base: fix race in PHC destroy

In reply to Shai Brandes

ena_com_phc_get_timestamp() checked phc->active and cached the resp pointer from ena_dev->phc.virt_addr before acquiring the PHC spinlock, so neither the liveness check nor the pointer read was serialised against teardown.

If ena_com_phc_destroy() runs in that window it clears active, releases the lock, frees the PHC DMA memory and sets virt_addr to NULL. The reader then dereferences either a pointer to already freed memory or a NULL virt_addr, depending on where it was preempted, crashing the application on PHC teardown or device reconfiguration.

Move the phc->active check and the resp pointer assignment inside the spinlock so that destroy cannot free the DMA memory while a timestamp read is in progress.

Fixes f73f53f7dc7a ("net/ena: upgrade HAL")
---
 drivers/net/ena/base/ena_com.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/ena/base/ena_com.c +5 -2
index b1fe0bcdf7..737626bcfa 100644
@@ -1996,20 +1996,23 @@ void ena_com_phc_destroy(struct ena_com_dev *ena_dev)
 
 int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
 {
-	volatile struct ena_admin_phc_resp *resp = ena_dev->phc.virt_addr;
 	const ena_time_high_res_t zero_system_time = ENA_TIME_INIT_HIGH_RES();
 	struct ena_com_phc_info *phc = &ena_dev->phc;
+	volatile struct ena_admin_phc_resp *resp;
 	ena_time_high_res_t expire_time;
 	ena_time_high_res_t block_time;
 	unsigned long flags = 0;
 	int ret = ENA_COM_OK;
 
+	ENA_SPINLOCK_LOCK(phc->lock, flags);
+
 	if (!phc->active) {
+		ENA_SPINLOCK_UNLOCK(phc->lock, flags);
 		ena_trc_err(ena_dev, "PHC feature is not active in the device\n");
 		return ENA_COM_UNSUPPORTED;
 	}
 
-	ENA_SPINLOCK_LOCK(phc->lock, flags);
+	resp = ena_dev->phc.virt_addr;
 
 	/* Check if PHC is in blocked state */
 	if (unlikely(ENA_TIME_COMPARE_HIGH_RES(phc->system_time, zero_system_time))) {
Signature · 1 line
2.17.1
#4 lore raw

PATCH v3 3/13 net/ena/base: fix missing barriers in PHC timestamp read

In reply to Shai Brandes

The PHC read path in ena_com_phc_get_timestamp() polls the shared error_bound and timestamp fields for a matching req_id to detect that the device has published a fresh reading. Both completion checks read the payload without a barrier after observing req_id.

On weakly-ordered architectures the CPU may load the payload fields before the req_id load is observed as updated, so a stale timestamp or error bound can be returned while the read is reported as valid.

Add dma_rmb() after both req_id completion checks to order the req_id load against the subsequent payload loads.

Fixes a14be4dd8693 ("net/ena/base: add PHC error statistics")
---
 drivers/net/ena/base/ena_com.c | 50 +++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 19 deletions(-)
drivers/net/ena/base/ena_com.c +31 -19
index 737626bcfa..49818c4bd0 100644
@@ -2037,27 +2037,34 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
 				    "PHC get time request 0x%x failed (device error)\n",
 				    phc->req_id);
 			phc->stats.phc_err_dv++;
-		} else if (resp->error_flags & ENA_PHC_ERROR_FLAGS) {
-			/* Device updated req_id during blocking time but got
-			 * a PHC error, this occurs if device:
-			 * - exceeded the get time request limit
-			 * - received an invalid timestamp
-			 * - received an excessively high error bound
-			 * - received an invalid error bound
-			 */
-			ena_trc_err(ena_dev,
-				    "PHC get time request 0x%x failed (error 0x%x)\n",
-				    phc->req_id,
-				    resp->error_flags);
-			phc->stats.phc_err_ts += !!(resp->error_flags &
-				ENA_ADMIN_PHC_ERROR_FLAG_TIMESTAMP);
-			phc->stats.phc_err_eb += !!(resp->error_flags &
-				ENA_ADMIN_PHC_ERROR_FLAG_ERROR_BOUND);
 		} else {
-			/* Device updated req_id during blocking time
-			 * with valid timestamp and error bound
+			/* Ensure PHC payload is read after req_id update
+			 * is observed
 			 */
-			phc->stats.phc_exp++;
+			dma_rmb();
+
+			if (resp->error_flags & ENA_PHC_ERROR_FLAGS) {
+				/* Device updated req_id during blocking time
+				 * but got a PHC error, this occurs if device:
+				 * - exceeded the get time request limit
+				 * - received an invalid timestamp
+				 * - received an excessively high error bound
+				 * - received an invalid error bound
+				 */
+				ena_trc_err(ena_dev,
+					    "PHC get time request 0x%x failed (error 0x%x)\n",
+					    phc->req_id,
+					    resp->error_flags);
+				phc->stats.phc_err_ts += !!(resp->error_flags &
+					ENA_ADMIN_PHC_ERROR_FLAG_TIMESTAMP);
+				phc->stats.phc_err_eb += !!(resp->error_flags &
+					ENA_ADMIN_PHC_ERROR_FLAG_ERROR_BOUND);
+			} else {
+				/* Device updated req_id during blocking time
+				 * with valid timestamp and error bound
+				 */
+				phc->stats.phc_exp++;
+			}
 		}
 	}
 
@@ -2100,6 +2107,11 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
 			continue;
 		}
 
+		/* Ensure PHC payload (timestamp, error_bound, error_flags)
+		 * is read after req_id update is observed
+		 */
+		dma_rmb();
+
 		/* req_id was updated by the device which indicates that
 		 * PHC timestamp, error_bound and error_flags are updated too,
 		 * checking errors before retrieving timestamp and
Signature · 1 line
2.17.1
#5 lore raw

PATCH v3 4/13 net/ena/base: rename bounce buffer references

In reply to Shai Brandes

Rename curr_bounce_buf pointer in sq llq packet control to curr_llq_entry for future use of llq not only with bounce buffers.

---
 drivers/net/ena/base/ena_com.c | 4 ++--
 drivers/net/ena/base/ena_com.h | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
drivers/net/ena/base/ena_com.c +2 -2
index 49818c4bd0..e9b9de21cb 100644
@@ -391,9 +391,9 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
 		       sizeof(io_sq->llq_info));
 
 		/* Initiate the first bounce buffer */
-		io_sq->llq_buf_ctrl.curr_bounce_buf =
+		io_sq->llq_buf_ctrl.curr_llq_entry =
 			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
-		memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
+		memset(io_sq->llq_buf_ctrl.curr_llq_entry,
 		       0x0, io_sq->llq_info.desc_list_entry_size);
 		io_sq->llq_buf_ctrl.descs_left_in_line =
 			io_sq->llq_info.descs_num_before_header;
drivers/net/ena/base/ena_com.h +1 -1
index 1d024cfea0..bd395fd90c 100644
@@ -138,7 +138,7 @@ struct ena_com_io_bounce_buffer_control {
 
 /* This struct is to keep tracking the current location of the next llq entry */
 struct ena_com_llq_pkt_ctrl {
-	u8 *curr_bounce_buf;
+	u8 *curr_llq_entry;
 	u16 idx;
 	u16 descs_left_in_line;
 };
Signature · 1 line
2.17.1
#6 lore raw

PATCH v3 5/13 net/ena/base: add LLQ policy inline helper

In reply to Shai Brandes

Introduce a helper to abstract the LLQ placement policy check, replacing direct mem_queue_type comparisons across ena-com.

---
 drivers/net/ena/base/ena_com.h     |  5 +++
 drivers/net/ena/base/ena_eth_com.c | 55 +++++++++++++++---------------
 drivers/net/ena/base/ena_eth_com.h |  6 ++--
 3 files changed, 35 insertions(+), 31 deletions(-)
drivers/net/ena/base/ena_com.h +5 -0
index bd395fd90c..c62fecdef2 100644
@@ -1139,6 +1139,11 @@ static inline struct ena_com_dev *ena_com_io_cq_to_ena_dev(struct ena_com_io_cq
 	return container_of(io_cq, struct ena_com_dev, io_cq_queues[io_cq->qid]);
 }
 
+static inline bool ena_com_sq_is_llq(struct ena_com_io_sq *io_sq)
+{
+	return io_sq->mem_queue_type != ENA_ADMIN_PLACEMENT_POLICY_HOST;
+}
+
 static inline bool ena_com_get_adaptive_moderation_enabled(struct ena_com_dev *ena_dev)
 {
 	return ena_dev->adaptive_coalescing;
drivers/net/ena/base/ena_eth_com.c +27 -28

160 lines not on this page · raw message

drivers/net/ena/base/ena_eth_com.h +3 -3
index f773699467..503cf45cf7 100644
@@ -110,7 +110,7 @@ static inline bool ena_com_sq_have_enough_space(struct ena_com_io_sq *io_sq,
 {
 	int temp;
 
-	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
+	if (unlikely(!ena_com_sq_is_llq(io_sq)))
 		return ena_com_free_q_entries(io_sq) >= required_buffers;
 
 	/* This calculation doesn't need to be 100% accurate. So to reduce
@@ -136,8 +136,8 @@ static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
 
 static inline bool is_llq_max_tx_burst_exists(struct ena_com_io_sq *io_sq)
 {
-	return (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) &&
-	       io_sq->llq_info.max_entries_in_tx_burst > 0;
+	return likely(ena_com_sq_is_llq(io_sq)) &&
+	       (io_sq->llq_info.max_entries_in_tx_burst > 0);
 }
 
 static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq,
Signature · 1 line
2.17.1
#7 lore raw

PATCH v3 6/13 net/ena/base: fix LLQ feature version sent to device

In reply to Shai Brandes

During LLQ configuration the driver reads the supported LLQ feature version from the device with a GET feature command, but leaves the feature_version field zeroed in the subsequent SET feature command.

The device therefore never learns which LLQ version the driver negotiated, and falls back to interpreting the configuration according to the base version regardless of what the driver actually agreed to, which can lead to a Tx descriptor layout mismatch between driver and device.

Store the feature version reported in the GET response and echo it back in the SET command so the negotiated version is communicated to the device.

Fixes b68309be44c0 ("net/ena/base: update communication layer for the ENAv2")
---
 drivers/net/ena/base/ena_com.c | 4 ++++
 drivers/net/ena/base/ena_com.h | 1 +
 2 files changed, 5 insertions(+)
drivers/net/ena/base/ena_com.c +4 -0
index e9b9de21cb..d3f1063b6c 100644
@@ -784,6 +784,8 @@ static int ena_com_set_llq(struct ena_com_dev *ena_dev)
 		BIT(ENA_ADMIN_DISABLE_META_CACHING) |
 		BIT(ENA_ADMIN_LIMIT_TX_BURST);
 
+	cmd.feat_common.feature_version = llq_info->feature_version;
+
 	ret = ena_com_execute_admin_command_no_resp(admin_queue,
 						    (struct ena_admin_aq_entry *)&cmd,
 						    sizeof(cmd));
@@ -805,6 +807,8 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 
 	memset(llq_info, 0, sizeof(*llq_info));
 
+	llq_info->feature_version = llq_features->feature_version;
+
 	supported_feat = llq_features->header_location_ctrl_supported;
 
 	if (likely(supported_feat & llq_default_cfg->llq_header_location)) {
drivers/net/ena/base/ena_com.h +1 -0
index c62fecdef2..7884d0dfc3 100644
@@ -93,6 +93,7 @@ struct ena_com_llq_info {
 	u16 descs_per_entry;
 	u16 max_entries_in_tx_burst;
 	bool disable_meta_caching;
+	u8 feature_version;
 };
 
 struct ena_com_io_cq {
Signature · 1 line
2.17.1
#8 lore raw

PATCH v3 7/13 net/ena/base: deduplicate LLQ entry write and advance

In reply to Shai Brandes

ena_com_close_llq_entry() and ena_com_sq_update_llq_tail() duplicate the same sequence for flushing the current LLQ entry to the device and moving on to the next one: write the bounce buffer, fetch the next bounce buffer and reset it.

Extract the common sequence into a new helper, ena_com_write_and_advance_llq_entry(), and call it from both sites.

No functional change.

---
 drivers/net/ena/base/ena_eth_com.c | 49 ++++++++++++++++--------------
 1 file changed, 27 insertions(+), 22 deletions(-)
drivers/net/ena/base/ena_eth_com.c +27 -22
index e3b2a753c4..ca15306859 100644
@@ -204,6 +204,29 @@ static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
 	return sq_desc;
 }
 
+static int ena_com_write_and_advance_llq_entry(struct ena_com_io_sq *io_sq)
+{
+	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	int rc;
+
+	rc = ena_com_write_bounce_buffer_to_dev(io_sq,
+						pkt_ctrl->curr_llq_entry);
+	if (unlikely(rc)) {
+		ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
+			    "Failed to write bounce buffer to device\n");
+		return rc;
+	}
+
+	pkt_ctrl->curr_llq_entry =
+		ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
+
+	memset(io_sq->llq_buf_ctrl.curr_llq_entry,
+	       0x0, llq_info->desc_list_entry_size);
+
+	return ENA_COM_OK;
+}
+
 static int ena_com_close_llq_entry(struct ena_com_io_sq *io_sq)
 {
 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
@@ -215,18 +238,9 @@ static int ena_com_close_llq_entry(struct ena_com_io_sq *io_sq)
 
 	/* bounce buffer was used, so write it and get a new one */
 	if (likely(pkt_ctrl->idx)) {
-		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
-							pkt_ctrl->curr_llq_entry);
-		if (unlikely(rc)) {
-			ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
-				    "Failed to write bounce buffer to device\n");
+		rc = ena_com_write_and_advance_llq_entry(io_sq);
+		if (unlikely(rc))
 			return rc;
-		}
-
-		pkt_ctrl->curr_llq_entry =
-			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
-		memset(io_sq->llq_buf_ctrl.curr_llq_entry,
-		       0x0, llq_info->desc_list_entry_size);
 	}
 
 	pkt_ctrl->idx = 0;
@@ -258,18 +272,9 @@ static int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
 	int rc;
 
 	if (!pkt_ctrl->descs_left_in_line) {
-		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
-							pkt_ctrl->curr_llq_entry);
-		if (unlikely(rc)) {
-			ena_trc_err(ena_com_io_sq_to_ena_dev(io_sq),
-				    "Failed to write bounce buffer to device\n");
+		rc = ena_com_write_and_advance_llq_entry(io_sq);
+		if (unlikely(rc))
 			return rc;
-		}
-
-		pkt_ctrl->curr_llq_entry =
-			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
-		memset(io_sq->llq_buf_ctrl.curr_llq_entry,
-		       0x0, llq_info->desc_list_entry_size);
 
 		pkt_ctrl->idx = 0;
 		pkt_ctrl->descs_left_in_line = llq_info->descs_per_entry;
Signature · 1 line
2.17.1
#9 lore raw

PATCH v3 8/13 net/ena/base: deduplicate meta caching config flag

In reply to Shai Brandes

struct ena_com_io_sq stores disable_meta_caching twice: once as a flat field, initialised from io_sq->llq_info.disable_meta_caching, and once inside the embedded llq_info structure. Both are assigned during queue configuration and never diverge afterwards, making the flat field redundant.

Remove the flat io_sq->disable_meta_caching field along with its initialisation, and read the value from llq_info directly on the metadata path.

No functional change.

---
 drivers/net/ena/base/ena_com.c     | 2 --
 drivers/net/ena/base/ena_com.h     | 1 -
 drivers/net/ena/base/ena_eth_com.c | 2 +-
 3 files changed, 1 insertion(+), 4 deletions(-)
drivers/net/ena/base/ena_com.c +0 -2
index d3f1063b6c..51bcf1b321 100644
@@ -397,8 +397,6 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
 		       0x0, io_sq->llq_info.desc_list_entry_size);
 		io_sq->llq_buf_ctrl.descs_left_in_line =
 			io_sq->llq_info.descs_num_before_header;
-		io_sq->disable_meta_caching =
-			io_sq->llq_info.disable_meta_caching;
 
 		if (io_sq->llq_info.max_entries_in_tx_burst > 0)
 			io_sq->entries_in_tx_burst_left =
drivers/net/ena/base/ena_com.h +0 -1
index 7884d0dfc3..063a8f021b 100644
@@ -153,7 +153,6 @@ struct ena_com_io_sq {
 	enum queue_direction direction;
 	enum ena_admin_placement_policy_type mem_queue_type;
 
-	bool disable_meta_caching;
 
 	u32 msix_vector;
 	struct ena_com_tx_meta cached_tx_meta;
drivers/net/ena/base/ena_eth_com.c +1 -1
index ca15306859..63624d169b 100644
@@ -439,7 +439,7 @@ static int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
 	/* When disable meta caching is set, don't bother to save the meta and
 	 * compare it to the stored version, just create the meta
 	 */
-	if (io_sq->disable_meta_caching) {
+	if (io_sq->llq_info.disable_meta_caching) {
 		*have_meta = true;
 		return ena_com_create_meta(io_sq, ena_meta);
 	}
Signature · 1 line
2.17.1
#10 lore raw

PATCH v3 9/13 net/ena/base: split LLQ info into datapath and config

In reply to Shai Brandes

struct ena_com_io_sq embeds the full struct ena_com_llq_info, although the Tx datapath reads only a small subset of its fields. The remaining members are consumed exclusively during device configuration.

Split struct ena_com_llq_info into struct ena_com_llq_info_common, holding the fields read on the datapath (desc_list_entry_size, descs_num_before_header, descs_per_entry, max_entries_in_tx_burst and disable_meta_caching), and the configuration-only members, which remain in the original structure.

Introduce struct ena_com_llq_info_runtime, comprising the common fields and entries_in_tx_burst_left, and embed it in struct ena_com_io_sq in place of the full structure.

No functional change.

---
 drivers/net/ena/base/ena_com.c     | 66 ++++++++++++++++--------------
 drivers/net/ena/base/ena_com.h     | 20 ++++++---
 drivers/net/ena/base/ena_eth_com.c | 18 ++++----
 drivers/net/ena/base/ena_eth_com.h | 14 +++----
 4 files changed, 66 insertions(+), 52 deletions(-)
drivers/net/ena/base/ena_com.c +36 -30
index 51bcf1b321..1ed73c1890 100644
@@ -367,7 +367,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
 	} else {
 		/* Allocate bounce buffers */
 		io_sq->bounce_buf_ctrl.buffer_size =
-			ena_dev->llq_info.desc_list_entry_size;
+			ena_dev->llq_info.common.desc_list_entry_size;
 		io_sq->bounce_buf_ctrl.buffers_num =
 			ENA_COM_BOUNCE_BUFFER_CNTRL_CNT;
 		io_sq->bounce_buf_ctrl.next_to_use = 0;
@@ -387,20 +387,20 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
 			return ENA_COM_NO_MEM;
 		}
 
-		memcpy(&io_sq->llq_info, &ena_dev->llq_info,
-		       sizeof(io_sq->llq_info));
+		memcpy(&io_sq->llq_runtime.common, &ena_dev->llq_info.common,
+		       sizeof(io_sq->llq_runtime.common));
 
 		/* Initiate the first bounce buffer */
 		io_sq->llq_buf_ctrl.curr_llq_entry =
 			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
 		memset(io_sq->llq_buf_ctrl.curr_llq_entry,
-		       0x0, io_sq->llq_info.desc_list_entry_size);
+		       0x0, io_sq->llq_runtime.common.desc_list_entry_size);
 		io_sq->llq_buf_ctrl.descs_left_in_line =
-			io_sq->llq_info.descs_num_before_header;
+			io_sq->llq_runtime.common.descs_num_before_header;
 
-		if (io_sq->llq_info.max_entries_in_tx_burst > 0)
-			io_sq->entries_in_tx_burst_left =
-				io_sq->llq_info.max_entries_in_tx_burst;
+		if (io_sq->llq_runtime.common.max_entries_in_tx_burst > 0)
+			io_sq->llq_runtime.entries_in_tx_burst_left =
+				io_sq->llq_runtime.common.max_entries_in_tx_burst;
 	}
 
 	io_sq->tail = 0;
@@ -775,7 +775,7 @@ static int ena_com_set_llq(struct ena_com_dev *ena_dev)
 
 	cmd.u.llq.header_location_ctrl_enabled = llq_info->header_location_ctrl;
 	cmd.u.llq.entry_size_ctrl_enabled = llq_info->desc_list_entry_size_ctrl;
-	cmd.u.llq.desc_num_before_header_enabled = llq_info->descs_num_before_header;
+	cmd.u.llq.desc_num_before_header_enabled = llq_info->common.descs_num_before_header;
 	cmd.u.llq.descriptors_stride_ctrl_enabled = llq_info->desc_stride_ctrl;
 
 	cmd.u.llq.accel_mode.u.set.enabled_flags =
@@ -845,17 +845,17 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 	supported_feat = llq_features->entry_size_ctrl_supported;
 	if (likely(supported_feat & llq_default_cfg->llq_ring_entry_size)) {
 		llq_info->desc_list_entry_size_ctrl = llq_default_cfg->llq_ring_entry_size;
-		llq_info->desc_list_entry_size = llq_default_cfg->llq_ring_entry_size_value;
+		llq_info->common.desc_list_entry_size = llq_default_cfg->llq_ring_entry_size_value;
 	} else {
 		if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_128B) {
 			llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
-			llq_info->desc_list_entry_size = 128;
+			llq_info->common.desc_list_entry_size = 128;
 		} else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_192B) {
 			llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_192B;
-			llq_info->desc_list_entry_size = 192;
+			llq_info->common.desc_list_entry_size = 192;
 		} else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_256B) {
 			llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
-			llq_info->desc_list_entry_size = 256;
+			llq_info->common.desc_list_entry_size = 256;
 		} else {
 			ena_trc_err(ena_dev, "Invalid entry_size_ctrl, supported: 0x%x\n",
 				    supported_feat);
@@ -865,35 +865,40 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 		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);
+			    llq_info->common.desc_list_entry_size);
 	}
-	if (unlikely(llq_info->desc_list_entry_size & 0x7)) {
+	if (unlikely(llq_info->common.desc_list_entry_size & 0x7)) {
 		/* The desc list entry size should be whole multiply of 8
 		 * This requirement comes from __iowrite64_copy()
 		 */
 		ena_trc_err(ena_dev, "Illegal entry size %d\n",
-			    llq_info->desc_list_entry_size);
+			    llq_info->common.desc_list_entry_size);
 		return ENA_COM_INVAL;
 	}
 
 	if (llq_info->desc_stride_ctrl == ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY)
-		llq_info->descs_per_entry = llq_info->desc_list_entry_size /
+		llq_info->common.descs_per_entry = llq_info->common.desc_list_entry_size /
 			sizeof(struct ena_eth_io_tx_desc);
 	else
-		llq_info->descs_per_entry = 1;
+		llq_info->common.descs_per_entry = 1;
 
 	supported_feat = llq_features->desc_num_before_header_supported;
 	if (likely(supported_feat & llq_default_cfg->llq_num_decs_before_header)) {
-		llq_info->descs_num_before_header = llq_default_cfg->llq_num_decs_before_header;
+		llq_info->common.descs_num_before_header =
+		llq_default_cfg->llq_num_decs_before_header;
 	} else {
 		if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2) {
-			llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
+			llq_info->common.descs_num_before_header =
+			ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
 		} else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1) {
-			llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1;
+			llq_info->common.descs_num_before_header =
+			ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1;
 		} else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4) {
-			llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4;
+			llq_info->common.descs_num_before_header =
+			ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4;
 		} 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;
+			llq_info->common.descs_num_before_header =
+			ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8;
 		} else {
 			ena_trc_err(ena_dev, "Invalid descs_num_before_header, supported: 0x%x\n",
 				    supported_feat);
@@ -903,19 +908,19 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
 		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);
+			    llq_info->common.descs_num_before_header);
 	}
 	/* Check for accelerated queue supported */
 	llq_accel_mode_get = llq_features->accel_mode.u.get;
 
-	llq_info->disable_meta_caching =
+	llq_info->common.disable_meta_caching =
 		!!(llq_accel_mode_get.supported_flags &
 		   BIT(ENA_ADMIN_DISABLE_META_CACHING));
 
 	if (llq_accel_mode_get.supported_flags & BIT(ENA_ADMIN_LIMIT_TX_BURST))
-		llq_info->max_entries_in_tx_burst =
+		llq_info->common.max_entries_in_tx_burst =
 			llq_accel_mode_get.max_tx_burst_size /
-			llq_default_cfg->llq_ring_entry_size_value;
+			llq_info->common.desc_list_entry_size;
 
 	rc = ena_com_set_llq(ena_dev);
 	if (unlikely(rc))
@@ -1055,7 +1060,8 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev,
 	if (io_sq->bounce_buf_ctrl.base_buffer) {
 		ENA_MEM_FREE(ena_dev->dmadev,
 			     io_sq->bounce_buf_ctrl.base_buffer,
-			     (io_sq->llq_info.desc_list_entry_size * ENA_COM_BOUNCE_BUFFER_CNTRL_CNT));
+			     (io_sq->llq_runtime.common.desc_list_entry_size *
+				ENA_COM_BOUNCE_BUFFER_CNTRL_CNT));
 		io_sq->bounce_buf_ctrl.base_buffer = NULL;
 	}
 }
@@ -3586,8 +3592,8 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
 	if (unlikely(rc))
 		return rc;
 
-	ena_dev->tx_max_header_size = llq_info->desc_list_entry_size -
-		(llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc));
+	ena_dev->tx_max_header_size = llq_info->common.desc_list_entry_size -
+		(llq_info->common.descs_num_before_header * sizeof(struct ena_eth_io_tx_desc));
 
 	if (unlikely(ena_dev->tx_max_header_size == 0)) {
 		ena_trc_err(ena_dev, "The size of the LLQ entry is smaller than needed\n");
drivers/net/ena/base/ena_com.h +14 -6
index 063a8f021b..94aa285cd8 100644
@@ -84,18 +84,27 @@ struct ena_com_tx_meta {
 	u16 l4_hdr_len; /* In words */
 };
 
-struct ena_com_llq_info {
-	u16 header_location_ctrl;
-	u16 desc_stride_ctrl;
-	u16 desc_list_entry_size_ctrl;
+struct ena_com_llq_info_common {
 	u16 desc_list_entry_size;
 	u16 descs_num_before_header;
 	u16 descs_per_entry;
 	u16 max_entries_in_tx_burst;
 	bool disable_meta_caching;
+};
+
+struct ena_com_llq_info {
+	struct ena_com_llq_info_common common;
+	u16 header_location_ctrl;
+	u16 desc_stride_ctrl;
+	u16 desc_list_entry_size_ctrl;
 	u8 feature_version;
 };
 
+struct ena_com_llq_info_runtime {
+	struct ena_com_llq_info_common common;
+	u16 entries_in_tx_burst_left;
+};
+
 struct ena_com_io_cq {
 	struct ena_com_io_desc_addr cdesc_addr;
 	void *bus;
@@ -156,7 +165,7 @@ struct ena_com_io_sq {
 
 	u32 msix_vector;
 	struct ena_com_tx_meta cached_tx_meta;
-	struct ena_com_llq_info llq_info;
+	struct ena_com_llq_info_runtime llq_runtime;
 	struct ena_com_llq_pkt_ctrl llq_buf_ctrl;
 	struct ena_com_io_bounce_buffer_control bounce_buf_ctrl;
 
@@ -171,7 +180,6 @@ struct ena_com_io_sq {
 	u8 phase;
 	u8 desc_entry_size;
 	u8 dma_addr_bits;
-	u16 entries_in_tx_burst_left;
 } ____cacheline_aligned;
 
 struct ena_com_admin_cq {
drivers/net/ena/base/ena_eth_com.c +9 -9
index 63624d169b..ea0fb374db 100644
@@ -112,7 +112,7 @@ static void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq)
 static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
 						     u8 *bounce_buffer)
 {
-	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	struct ena_com_llq_info_common *llq_info = &io_sq->llq_runtime.common;
 	u16 dst_tail_mask;
 	u32 dst_offset;
 
@@ -120,16 +120,16 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
 	dst_offset = dst_tail_mask * llq_info->desc_list_entry_size;
 
 	if (is_llq_max_tx_burst_exists(io_sq)) {
-		if (unlikely(!io_sq->entries_in_tx_burst_left)) {
+		if (unlikely(!io_sq->llq_runtime.entries_in_tx_burst_left)) {
 			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--;
+		io_sq->llq_runtime.entries_in_tx_burst_left--;
 		ena_trc_dbg(ena_com_io_sq_to_ena_dev(io_sq),
 			    "Decreasing entries_in_tx_burst_left of queue %u to %u\n",
-			    io_sq->qid, io_sq->entries_in_tx_burst_left);
+			    io_sq->qid, io_sq->llq_runtime.entries_in_tx_burst_left);
 	}
 
 	/* Make sure everything was written into the bounce buffer before
@@ -156,7 +156,7 @@ static int ena_com_write_header_to_llq_entry(struct ena_com_io_sq *io_sq,
 					  u16 header_len)
 {
 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
-	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	struct ena_com_llq_info_common *llq_info = &io_sq->llq_runtime.common;
 	u8 *curr_llq_entry = pkt_ctrl->curr_llq_entry;
 	u16 header_offset;
 
@@ -207,7 +207,7 @@ static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
 static int ena_com_write_and_advance_llq_entry(struct ena_com_io_sq *io_sq)
 {
 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
-	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	struct ena_com_llq_info_common *llq_info = &io_sq->llq_runtime.common;
 	int rc;
 
 	rc = ena_com_write_bounce_buffer_to_dev(io_sq,
@@ -230,7 +230,7 @@ static int ena_com_write_and_advance_llq_entry(struct ena_com_io_sq *io_sq)
 static int ena_com_close_llq_entry(struct ena_com_io_sq *io_sq)
 {
 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
-	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	struct ena_com_llq_info_common *llq_info = &io_sq->llq_runtime.common;
 	int rc;
 
 	if (unlikely(!ena_com_sq_is_llq(io_sq)))
@@ -268,7 +268,7 @@ static void *get_tx_sq_desc(struct ena_com_io_sq *io_sq)
 static int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
 {
 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
-	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+	struct ena_com_llq_info_common *llq_info = &io_sq->llq_runtime.common;
 	int rc;
 
 	if (!pkt_ctrl->descs_left_in_line) {
@@ -439,7 +439,7 @@ static int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
 	/* When disable meta caching is set, don't bother to save the meta and
 	 * compare it to the stored version, just create the meta
 	 */
-	if (io_sq->llq_info.disable_meta_caching) {
+	if (io_sq->llq_runtime.common.disable_meta_caching) {
 		*have_meta = true;
 		return ena_com_create_meta(io_sq, ena_meta);
 	}
drivers/net/ena/base/ena_eth_com.h +7 -7
index 503cf45cf7..514df12e9d 100644
@@ -118,7 +118,7 @@ static inline bool ena_com_sq_have_enough_space(struct ena_com_io_sq *io_sq,
 	 * (one for the header line and one to compensate the devision
 	 * down calculation.
 	 */
-	temp = required_buffers / io_sq->llq_info.descs_per_entry + 2;
+	temp = required_buffers / io_sq->llq_runtime.common.descs_per_entry + 2;
 
 	return ena_com_free_q_entries(io_sq) > temp;
 }
@@ -137,13 +137,13 @@ static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
 static inline bool is_llq_max_tx_burst_exists(struct ena_com_io_sq *io_sq)
 {
 	return likely(ena_com_sq_is_llq(io_sq)) &&
-	       (io_sq->llq_info.max_entries_in_tx_burst > 0);
+	       (io_sq->llq_runtime.common.max_entries_in_tx_burst > 0);
 }
 
 static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq,
 					      struct ena_com_tx_ctx *ena_tx_ctx)
 {
-	struct ena_com_llq_info *llq_info;
+	struct ena_com_llq_info_common *llq_info;
 	int descs_after_first_entry;
 	int num_entries_needed = 1;
 	u16 num_descs;
@@ -151,7 +151,7 @@ static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq,
 	if (!is_llq_max_tx_burst_exists(io_sq))
 		return false;
 
-	llq_info = &io_sq->llq_info;
+	llq_info = &io_sq->llq_runtime.common;
 	num_descs = ena_tx_ctx->num_bufs;
 
 	if (llq_info->disable_meta_caching ||
@@ -168,7 +168,7 @@ static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *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;
+	return num_entries_needed > io_sq->llq_runtime.entries_in_tx_burst_left;
 }
 
 static inline void ena_com_write_rx_sq_doorbell(struct ena_com_io_sq *io_sq)
@@ -184,7 +184,7 @@ static inline void ena_com_write_rx_sq_doorbell(struct ena_com_io_sq *io_sq)
 
 static inline void ena_com_write_tx_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 max_entries_in_tx_burst = io_sq->llq_runtime.common.max_entries_in_tx_burst;
 	u16 tail = io_sq->tail;
 
 	ena_trc_dbg(ena_com_io_sq_to_ena_dev(io_sq),
@@ -197,7 +197,7 @@ static inline void ena_com_write_tx_sq_doorbell(struct ena_com_io_sq *io_sq)
 		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;
+		io_sq->llq_runtime.entries_in_tx_burst_left = max_entries_in_tx_burst;
 	}
 }
 
Signature · 1 line
2.17.1
#11 lore raw

PATCH v3 10/13 net/ena/base: fix LLQ config failure flow

In reply to Shai Brandes

ena_com_config_dev_mode() computes tx_max_header_size directly into the ena_com_dev structure and only afterwards rejects the result if it came out zero. The error path therefore leaves the device with tx_max_header_size == 0, overwriting the value the device reported in ena_com_get_dev_attr_feat().

The failure is not fatal to the caller: the PMD logs it, falls back to host placement policy and continues, so the zeroed value stays in effect. It is then copied into the per-ring field, which sizes the Tx intermediate header buffer to zero and clamps header_len to zero on every transmit.

Compute the value into a local variable, validate it there, and store it into ena_dev only once it is known good, so a failed LLQ configuration leaves the previously negotiated value untouched.

Fixes b2b02edeb0d6 ("net/ena/base: upgrade HAL for new HW features")
---
 drivers/net/ena/base/ena_com.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ena/base/ena_com.c +4 -2
index 1ed73c1890..161d5b5ebd 100644
@@ -3581,6 +3581,7 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
 			    struct ena_llq_configurations *llq_default_cfg)
 {
 	struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
+	u32 llq_max_header_size;
 	int rc;
 
 	if (!llq_features->max_llq_num) {
@@ -3592,14 +3593,15 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
 	if (unlikely(rc))
 		return rc;
 
-	ena_dev->tx_max_header_size = llq_info->common.desc_list_entry_size -
+	llq_max_header_size = llq_info->common.desc_list_entry_size -
 		(llq_info->common.descs_num_before_header * sizeof(struct ena_eth_io_tx_desc));
 
-	if (unlikely(ena_dev->tx_max_header_size == 0)) {
+	if (unlikely(llq_max_header_size == 0)) {
 		ena_trc_err(ena_dev, "The size of the LLQ entry is smaller than needed\n");
 		return ENA_COM_INVAL;
 	}
 
+	ena_dev->tx_max_header_size = llq_max_header_size;
 	ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV;
 
 	return 0;
Signature · 1 line
2.17.1
#12 lore raw

PATCH v3 11/13 net/ena: support flow API for n-tuple Rx steering

In reply to Shai Brandes

Implement the flow_ops_get ethdev callback to expose hardware n-tuple Rx steering through the rte_flow API, allowing applications to direct selected traffic to dedicated Rx queues for workload isolation.

Supported patterns are IPv4, IPv6, TCP and UDP, matching source and destination addresses, source and destination ports and IP TOS/DSCP. The protocol is derived from the TCP or UDP item type. The only supported action is queue steering to a single Rx queue. Rules are accepted for ingress traffic in group 0 with priority 0. Item spec and mask are honoured, including default masks; ranges specified through the item last field are rejected, as are unsupported header fields.

Flow steering is reported as unsupported when the device exposes no rule entries.

Documented limitations: rules can only be created once the device is started, they are not retained across device stop, and a rule referencing an Rx queue that is removed by a later reconfiguration will cause matching packets to be dropped.

---
 doc/guides/nics/ena.rst                       |  26 +
 doc/guides/nics/features/ena.ini              |  10 +
 doc/guides/rel_notes/release_26_11.rst        |   4 +
 drivers/net/ena/base/ena_com.c                | 300 ++++++++++
 drivers/net/ena/base/ena_com.h                |  86 +++
 .../net/ena/base/ena_defs/ena_admin_defs.h    |  83 ++-
 drivers/net/ena/ena_ethdev.c                  |  71 ++-
 drivers/net/ena/ena_ethdev.h                  |   3 +-
 drivers/net/ena/ena_flow.c                    | 542 ++++++++++++++++++
 drivers/net/ena/ena_flow.h                    |  12 +
 drivers/net/ena/meson.build                   |   1 +
 11 files changed, 1135 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ena/ena_flow.c
 create mode 100644 drivers/net/ena/ena_flow.h
doc/guides/nics/ena.rst +26 -0
index d829e8854f..4c2f0e098a 100644
@@ -33,6 +33,7 @@ Supported features
 * Device reset upon failure
 * Rx interrupts
 * Rx HW packet timestamping
+* Rx flow steering
 
 Overview
 --------
@@ -59,6 +60,9 @@ Queue (LLQ), which saves several more microseconds.
 Rx hardware timestamping is available in the ENA driver
 on platforms that support this feature.
 
+Rx flow steering is available in the ENA driver
+on platforms that support this feature.
+
 Management Interface
 --------------------
 
@@ -248,6 +252,28 @@ There is possibility that there won't be enough event file descriptors to
 handle both admin and Rx interrupts. In that situation the Rx interrupt request
 will fail.
 
+**Rx flow steering support**
+
+ENA PMD supports steering ingress packets to a specific Rx queue
+using the generic flow API (``rte_flow``).
+A rule matches IPv4 or IPv6 packets, optionally followed by TCP or UDP,
+on any combination of source and destination addresses,
+TOS (IPv4) or traffic class (IPv6), and source and destination ports.
+Each rule has a single ``QUEUE`` action.
+
+The following limitations apply:
+
+* Only ingress rules in group 0 with priority 0 are supported.
+* The ``ETH`` item is accepted only as a wildcard, without matching fields.
+* Rules can be created only after the device is started.
+* ``RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`` is not advertised,
+  so the application must not rely on rules being kept across device stop,
+  and should flush them with ``rte_flow_flush()`` before stopping the device.
+* The queue index is checked only when the rule is created.
+  If the port is later reconfigured with fewer Rx queues,
+  the device silently drops the packets matching the rule.
+* The maximum number of rules is defined by the device.
+
 **Note about usage on \*.metal instances**
 
 On AWS, the metal instances are supporting IOMMU for both arm64 and x86_64 hosts.
doc/guides/nics/features/ena.ini +10 -0
index 037e0bad60..a8cbb6df1c 100644
@@ -22,3 +22,13 @@ Linux                = Y
 ARMv8                = Y
 x86-32               = Y
 x86-64               = Y
+
+[rte_flow items]
+eth                  = P
+ipv4                 = Y
+ipv6                 = Y
+tcp                  = Y
+udp                  = Y
+
+[rte_flow actions]
+queue                = Y
doc/guides/rel_notes/release_26_11.rst +4 -0
index 21ea1aed3d..a34b81c9b6 100644
@@ -133,6 +133,10 @@ New Features
     ``xdp_meta_rx_ts_valid_mask``.
   * Added ``read_clock`` operation to query the PTP hardware clock.
 
+* **Updated Amazon ENA (Elastic Network Adapter) ethernet driver.**
+
+  * Added Rx flow steering support using the generic flow API.
+
 * **Updated Broadcom bnxt driver.**
 
   * Added ``tx_dma_err_cmpl`` statistics to report Tx completions
drivers/net/ena/base/ena_com.c +300 -0

312 lines not on this page · raw message

drivers/net/ena/base/ena_com.h +86 -0

110 lines not on this page · raw message

drivers/net/ena/base/ena_defs/ena_admin_defs.h +82 -1

119 lines not on this page · raw message

drivers/net/ena/ena_ethdev.c +70 -1

128 lines not on this page · raw message

drivers/net/ena/ena_ethdev.h +2 -1
index b204b07767..7a7d4a4036 100644
@@ -15,7 +15,7 @@
 #include <rte_timer.h>
 #include <rte_dev.h>
 #include <rte_net.h>
-
+#include "ena_flow.h"
 #include "ena_com.h"
 
 #define ENA_REGS_BAR	0
@@ -343,6 +343,7 @@ struct ena_adapter {
 	struct ena_stats_dev dev_stats;
 	struct ena_admin_basic_stats basic_stats;
 
+	uint16_t flow_rule_count;
 	u32 *indirect_table;
 	size_t indirect_table_size;
 
drivers/net/ena/ena_flow.c new file +542 -0

542 lines not on this page · raw message

drivers/net/ena/ena_flow.h new file +12 -0
new file mode 100644
index 0000000000..e83aa56e87
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2024 Amazon.com, Inc. or its affiliates.
+ */
+#ifndef _ENA_FLOW_H_
+#define _ENA_FLOW_H_
+
+#include <rte_flow.h>
+
+/* Flow operations */
+extern const struct rte_flow_ops ena_flow_ops;
+
+#endif /* _ENA_FLOW_H_ */
drivers/net/ena/meson.build +1 -0
index 2b18d7add7..244775bf16 100644
@@ -10,6 +10,7 @@ endif
 sources = files(
         'ena_ethdev.c',
         'ena_rss.c',
+        'ena_flow.c',
         'base/ena_com.c',
         'base/ena_eth_com.c',
 )
Signature · 1 line
2.17.1
#13 lore raw

PATCH v3 12/13 net/ena/base: remove x86 Tx LLQ write barrier

In reply to Shai Brandes

ena_com_write_bounce_buffer_to_dev() issues a wmb() before copying each LLQ entry from the bounce buffer to the write-combining (WC) LLQ memory region. It was intended to ensure the bounce buffer is fully written before the copy reads it. That is never needed: a CPU always observes its own prior stores, on every architecture. wmb() also orders stores against later stores, not against later loads, so it could not provide that guarantee anyway.

The barrier is needed on ARM for a different reason: it orders one LLQ entry's stores to the device ahead of the next entry's. The copy uses relaxed stores, which on ARM may reach the device partially and out of order while the burst is still being written. The barrier in the doorbell write cannot prevent this, as it only orders the entries against the doorbell, not against each other. With the barrier removed, c8gn at 32 queues fails with IPP_REASS_ERROR_PRE_VALID_DB ("Data Out of Window") before the doorbell is written.

On x86 the barrier is redundant. WC stores are weakly ordered there too, so it never ordered entries against each other. The entries reach the device before the doorbell because of the memory type, not a fence:
each entry is written as complete 64-byte WC lines, and on Intel the UC doorbell write flushes pending WC buffers, while on AMD each 64-byte WC line is flushed once it is fully written. The per-entry SFENCE made the CPU wait for the previous entry to reach the device before copying the next one, defeating the purpose of write combining.

Introduce arm_wmb(), a write barrier on ARM and a no-op elsewhere, and use it in place of wmb() before the bounce buffer copy.

---
 doc/guides/rel_notes/release_26_11.rst |  2 ++
 drivers/net/ena/base/ena_eth_com.c     | 23 ++++++++++++++++++++---
 drivers/net/ena/base/ena_plat_dpdk.h   |  8 ++++++++
 3 files changed, 30 insertions(+), 3 deletions(-)
doc/guides/rel_notes/release_26_11.rst +2 -0
index a34b81c9b6..9b8e5ccc90 100644
@@ -136,6 +136,8 @@ New Features
 * **Updated Amazon ENA (Elastic Network Adapter) ethernet driver.**
 
   * Added Rx flow steering support using the generic flow API.
+  * Restrict the Tx LLQ write barrier to ARM, where it is required for correct entry ordering,
+    and remove it on x86, where it is redundant and limits throughput.
 
 * **Updated Broadcom bnxt driver.**
 
drivers/net/ena/base/ena_eth_com.c +20 -3
index ea0fb374db..5dbb432acc 100644
@@ -132,10 +132,27 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
 			    io_sq->qid, io_sq->llq_runtime.entries_in_tx_burst_left);
 	}
 
-	/* Make sure everything was written into the bounce buffer before
-	 * writing the bounce buffer to the device
+	/* Ensure the previous LLQ entry reaches the device before this one.
+	 *
+	 * The original wmb() was intended to ensure the bounce buffer is
+	 * fully written before it is copied to the device. This is not
+	 * required: a CPU always observes its own prior stores, on every
+	 * architecture. Moreover, wmb() orders stores against later stores,
+	 * not against later loads, so it could not provide this guarantee.
+	 *
+	 * The copy below uses relaxed stores to the WC LLQ region: plain
+	 * stores with no barrier, which the CPU may send to the device in any
+	 * order. On ARM, this means an entry may reach the device partially
+	 * and out of order before the doorbell is written. In addition, the
+	 * barrier in the doorbell write cannot prevent this, as it only orders
+	 * the entries against the doorbell, not against each other.
+	 *
+	 * On x86, this barrier is not needed. Each entry is written as complete
+	 * 64-byte WC lines, all of which reach the device before the
+	 * doorbell: on Intel, the UC doorbell write flushes pending WC
+	 * buffers; on AMD, each line is flushed once it is fully written.
 	 */
-	wmb();
+	arm_wmb();
 
 	/* The line is completed. Copy it to dev */
 	ENA_MEMCPY_TO_DEVICE_64(io_sq->desc_addr.pbuf_dev_addr + dst_offset,
drivers/net/ena/base/ena_plat_dpdk.h +8 -0
index 4a6d53d0a2..12f1643a85 100644
@@ -73,6 +73,14 @@ typedef RTE_ATOMIC(int32_t) ena_atomic32_t;
 #define rmb rte_rmb
 #define mb rte_mb
 #define mmiowb rte_io_wmb
+
+/* Write memory barrier for ARM architectures - covers 32 and 64 bit ARM */
+#if defined(RTE_ARCH_ARM)
+#define arm_wmb rte_wmb
+#else
+static inline void arm_wmb(void) { }
+#endif
+
 #define __iomem
 
 #ifndef READ_ONCE
Signature · 1 line
2.17.1
#14 lore raw

PATCH v3 13/13 net/ena: upgrade driver version to 2.15.0

In reply to Shai Brandes

Upgrade driver version to 2.15.0

---
 drivers/net/ena/ena_ethdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ena/ena_ethdev.c +1 -1
index 3eee5e2545..435c2af477 100644
@@ -23,7 +23,7 @@
 #include <ena_eth_io_defs.h>
 
 #define DRV_MODULE_VER_MAJOR	2
-#define DRV_MODULE_VER_MINOR	14
+#define DRV_MODULE_VER_MINOR	15
 #define DRV_MODULE_VER_SUBMINOR	0
 
 #define __MERGE_64B_H_L(h, l) (((uint64_t)h << 32) | l)
Signature · 1 line
2.17.1
#15 lore raw

RE: [PATCH v3 13/13] net/ena: upgrade driver version to 2.15.0

Recheck-request: iol-unit-arm64-testing

It seems that the failure is environmental. Rechecking may fail again as I see other patches also fail on that test suite today.

Quoted 29 lines

-----Original Message-----
From: Brandes, Shai <[email protected]>
Sent: Sunday, October 18, 2026 12:54 PM
To: [email protected]
Cc: [email protected]; Brandes, Shai <[email protected]>
Subject: [PATCH v3 13/13] net/ena: upgrade driver version to 2.15.0

Upgrade driver version to 2.15.0

---
 drivers/net/ena/ena_ethdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ena/ena_ethdev.c +1 -2
index 3eee5e2545..435c2af477 100644
@@ -23,7 +23,7 @@
 #include <ena_eth_io_defs.h>
 
 #define DRV_MODULE_VER_MAJOR	2
-#define DRV_MODULE_VER_MINOR	14
+#define DRV_MODULE_VER_MINOR	15
 #define DRV_MODULE_VER_SUBMINOR	0
 
 #define __MERGE_64B_H_L(h, l) (((uint64_t)h << 32) | l)
--

2.17.1

#16 lore raw
In reply to Shai Brandes
Quoted 9 lines · On Sun, 18 Oct 2026 12:45:41 +0300 Shai Brandes <[email protected]> wrote:

Hello all,
This series upgrades HAL and fixes two PHC correctness issues,
an LLQ feature version not communicated to the device, and
a failed LLQ configuration zeroing the negotiated tx_max_header_size. Additionally it adds n-tuple Rx flow steering support through the rte_flow API. Review and comments are welcome

Best regards,
Shai Brandes

I am disappointed that you did not address the AI identified problems in last version.

Review of [PATCH v3 00/13] net/ena: 2.15.0 (bundle 2204)

Applied to main at 9a45341f18 (26.11-rc1); every commit built with -Dwerror=true (gcc, x86-64).

Series level
------------

There is no changelog. Against the previous posting, v3 only rebases, keeps ena_com_execute_admin_command() exported in 01, and fixes a typo in 11. None of the earlier review comments are addressed; they are repeated below.

Error: patch 04 still breaks the build.

Info: the stable fixes (02, 03, 06, 10) sit behind refactors, and 06 and 10 depend on context from 01, 05 and 09. Put the fixes first so they backport without rework.

[PATCH v3 01/13] net/ena: avoid using un-needed admin response buffers
----------------------------------------------------------------------

Warning: undocumented behaviour change. Besides the move, the missing-interrupt fallback in ena_com_wait_and_process_admin_cq_interrupts() changes from

	admin_queue->polling = true;

to

	ena_com_set_admin_polling_mode(admin_queue->ena_dev, true);

which also writes ENA_REGS_ADMIN_INTR_MASK to the device. Say so in the commit message, or split the wait path rework into its own patch.

[PATCH v3 03/13] net/ena/base: fix missing barriers in PHC timestamp read
------------------------------------------------------------------------

Warning: wrong Fixes tag. The req_id poll loop without a barrier comes from f73f53f7dc7a (v23.11); a14be4dd8693 (v25.11) only added the statistics block. As tagged, 23.11 and 24.11 will not pick this up. Use:

Fixes f73f53f7dc7a ("net/ena: upgrade HAL")

[PATCH v3 04/13] net/ena/base: rename bounce buffer references
-------------------------------------------------------------

Error: build break. The member is renamed in ena_com.h but ena_eth_com.c still uses the old name until patch 05:

ena_eth_com.c:160: error: 'struct ena_com_llq_pkt_ctrl' has no member named 'curr_bounce_buf'

Move the ena_eth_com.c renames (curr_bounce_buf, plus write_header_to_bounce and close_bounce_buffer, which 05 also renames without mentioning it) into this patch. 05 is then only the ena_com_sq_is_llq() helper, matching its subject.

[PATCH v3 08/13] net/ena/base: deduplicate meta caching config flag
------------------------------------------------------------------

Info: removing the field leaves two consecutive blank lines in struct ena_com_io_sq after mem_queue_type. Drop one.

[PATCH v3 09/13] net/ena/base: split LLQ info into datapath and config
---------------------------------------------------------------------

Warning: this is not "No functional change". The burst limit divisor changes:

- llq_default_cfg->llq_ring_entry_size_value;
+ llq_info->common.desc_list_entry_size;

They differ when the device does not support the default entry size and the fallback above picks another one. With a 128 byte default and a 256 byte fallback, the old code allows twice as many entries per burst as the device accepts. That is a real bug, present since the LIMIT_TX_BURST support went in. Split it out:

net/ena/base: fix Tx burst limit with fallback entry size

Fixes b68309be44c0 ("net/ena/base: update communication layer

for the ENAv2")
Cc: [email protected]

and keep 09 a pure refactor.

Info: continuation lines of the descs_num_before_header assignments are not indented:

		llq_info->common.descs_num_before_header =
		llq_default_cfg->llq_num_decs_before_header;

Indent the second line one more tab, or keep it on one line.

[PATCH v3 11/13] net/ena: support flow API for n-tuple Rx steering
-----------------------------------------------------------------

Warning: an item without spec is rejected for IPV4, IPV6, TCP and UDP ("IPv4 item requires spec"). In rte_flow a NULL spec means "match any packet of this protocol". testpmd passes spec == NULL for items given without fields, so the obvious rule

flow create 0 ingress pattern eth / ipv4 / tcp dst is 80 / end
actions queue index 1 / end

fails. Treat NULL spec as protocol presence with zero masks, e.g.:

	case RTE_FLOW_ITEM_TYPE_IPV4:
		...
		has_ipv4 = true;
		if (spec == NULL)
			break;
		if (mask == NULL)
			mask = &rte_flow_item_ipv4_mask;

Same for IPV6, TCP and UDP.

Warning: secondary process. All other admin commands (MTU, RSS, stats) go through ENA_PROXY because only the primary owns the admin queue. The flow ops call ena_com_flow_steering_*() directly, so rte_flow from a secondary submits admin commands from the wrong process. Proxy them, or simply refuse in ena_flow_ops_get():

	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
		return -E_RTE_SECONDARY;

Warning: features/ena.ini adds the [rte_flow items] and [rte_flow actions] tables but not "Flow API = Y" under [Features].

Info:
- ena_infos_get(): the two "&= ~" lines are no-ops (ENA never sets RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP or RTE_ETH_DEV_FLOW_OPS_THREAD_SAFE) and dev_infos_get should not write dev->data. Drop them and the comments.
- ena_flow_create() parses the pattern twice, once inside ena_flow_validate(). Split the attr/started checks into a helper and call ena_flow_parse() once.
- adapter->flow_rule_count duplicates ena_dev->flow_steering.active_rules_cnt. Use the base counter.
- ena_flow_ops_get() logs WARNING when steering is unsupported. testpmd calls rte_flow_flush() on port close, so this fires on every close. Use DEBUG or no log.
- ena_flow_query() only returns ENOTSUP; leave .query NULL and ethdev returns ENOSYS.
- ena_com_flow_steering_remove_rule() and _remove_all_rules() pass a response buffer they never read. Use ena_com_execute_admin_command_no_resp() from patch 01.
- ena_com_flow_steering_destroy() leaves dangling pointers. End it with memset(flow_steering, 0, sizeof(*flow_steering)) like ena_com_rss_destroy().

[PATCH v3 12/13] net/ena/base: remove x86 Tx LLQ write barrier
-------------------------------------------------------------

Warning: arm_wmb() is a no-op on every non-ARM architecture, not just x86. ppc64le, riscv and loongarch are weakly ordered and the driver still builds there. The argument for dropping the barrier (UC doorbell store flushes WC buffers) is x86 specific, so make the test x86 specific:

  #if defined(RTE_ARCH_X86)
  #define ena_llq_wmb() do { } while (0)
  #else
  #define ena_llq_wmb() rte_wmb()
  #endif

(rte_io_wmb() everywhere is the other option, if Graviton testing shows dmb oshst is enough; on x86 it is a compiler barrier.)

Info: the new comment in ena_com_write_bounce_buffer_to_dev() is 20 lines, half of it history of the old wmb(). History belongs in the commit message; keep the comment to what the barrier orders and why x86 does not need it.

#17 lore raw

I missed your earlier review comments, and I apologize for the oversight.
Regarding the AI review, I assumed the result from the initial patchset, which passed cleanly (https://mails.dpdk.org/archives/test-report/2026-October/1060187.html), would still apply, since the code logic has not changed between versions. However, the latest run does report new issues that also need to be addressed.
I will address all of the points raised and aim to send a v4 before the code freeze tomorrow.

Sorry again,
Shai

Quoted 210 lines

-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Monday, October 19, 2026 7:34 PM
To: Brandes, Shai <[email protected]>
Cc: [email protected]
Subject: RE: [EXTERNAL] [PATCH v3 00/13] ENA release 2.15.0

CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.

Quoted 5 lines · On Sun, 18 Oct 2026 12:45:41 +0300 Shai Brandes <[email protected]> wrote:

Hello all,
This series upgrades HAL and fixes two PHC correctness issues, an LLQ feature version not communicated to the device, and a failed LLQ configuration zeroing the negotiated tx_max_header_size. Additionally it adds n-tuple Rx flow steering support through the rte_flow

API.

Quoted 4 lines

Review and comments are welcome

Best regards,
Shai Brandes

I am disappointed that you did not address the AI identified problems in last version.

Review of [PATCH v3 00/13] net/ena: 2.15.0 (bundle 2204)

Applied to main at 9a45341f18 (26.11-rc1); every commit built with - Dwerror=true (gcc, x86-64).

Series level
------------

There is no changelog. Against the previous posting, v3 only rebases, keeps ena_com_execute_admin_command() exported in 01, and fixes a typo in 11. None of the earlier review comments are addressed; they are repeated below.

Error: patch 04 still breaks the build.

Info: the stable fixes (02, 03, 06, 10) sit behind refactors, and 06 and 10 depend on context from 01, 05 and 09. Put the fixes first so they backport without rework.

[PATCH v3 01/13] net/ena: avoid using un-needed admin response buffers
----------------------------------------------------------------------

Warning: undocumented behaviour change. Besides the move, the missing- interrupt fallback in ena_com_wait_and_process_admin_cq_interrupts() changes from

        admin_queue->polling = true;

to

        ena_com_set_admin_polling_mode(admin_queue->ena_dev, true);

which also writes ENA_REGS_ADMIN_INTR_MASK to the device. Say so in the commit message, or split the wait path rework into its own patch.

[PATCH v3 03/13] net/ena/base: fix missing barriers in PHC timestamp read
------------------------------------------------------------------------

Warning: wrong Fixes tag. The req_id poll loop without a barrier comes from f73f53f7dc7a (v23.11); a14be4dd8693 (v25.11) only added the statistics block. As tagged, 23.11 and 24.11 will not pick this up. Use:

Fixes f73f53f7dc7a ("net/ena: upgrade HAL")

[PATCH v3 04/13] net/ena/base: rename bounce buffer references
-------------------------------------------------------------

Error: build break. The member is renamed in ena_com.h but ena_eth_com.c still uses the old name until patch 05:

ena_eth_com.c:160: error: 'struct ena_com_llq_pkt_ctrl' has no member named 'curr_bounce_buf'

Move the ena_eth_com.c renames (curr_bounce_buf, plus write_header_to_bounce and close_bounce_buffer, which 05 also renames without mentioning it) into this patch. 05 is then only the ena_com_sq_is_llq() helper, matching its subject.

[PATCH v3 08/13] net/ena/base: deduplicate meta caching config flag
------------------------------------------------------------------

Info: removing the field leaves two consecutive blank lines in struct ena_com_io_sq after mem_queue_type. Drop one.

[PATCH v3 09/13] net/ena/base: split LLQ info into datapath and config
---------------------------------------------------------------------

Warning: this is not "No functional change". The burst limit divisor changes:

(quoted diff) +1 -1
-       llq_default_cfg->llq_ring_entry_size_value;
+       llq_info->common.desc_list_entry_size;

They differ when the device does not support the default entry size and the fallback above picks another one. With a 128 byte default and a 256 byte fallback, the old code allows twice as many entries per burst as the device accepts. That is a real bug, present since the LIMIT_TX_BURST support went in. Split it out:

net/ena/base: fix Tx burst limit with fallback entry size

Fixes b68309be44c0 ("net/ena/base: update communication layer

for the ENAv2")
Cc: [email protected]

and keep 09 a pure refactor.

Info: continuation lines of the descs_num_before_header assignments are not indented:

                llq_info->common.descs_num_before_header =
                llq_default_cfg->llq_num_decs_before_header;

Indent the second line one more tab, or keep it on one line.

[PATCH v3 11/13] net/ena: support flow API for n-tuple Rx steering
-----------------------------------------------------------------

Warning: an item without spec is rejected for IPV4, IPV6, TCP and UDP ("IPv4 item requires spec"). In rte_flow a NULL spec means "match any packet of this protocol". testpmd passes spec == NULL for items given without fields, so the obvious rule

flow create 0 ingress pattern eth / ipv4 / tcp dst is 80 / end
actions queue index 1 / end

fails. Treat NULL spec as protocol presence with zero masks, e.g.:

        case RTE_FLOW_ITEM_TYPE_IPV4:
                ...
                has_ipv4 = true;
                if (spec == NULL)
                        break;
                if (mask == NULL)
                        mask = &rte_flow_item_ipv4_mask;

Same for IPV6, TCP and UDP.

Warning: secondary process. All other admin commands (MTU, RSS, stats) go through ENA_PROXY because only the primary owns the admin queue. The flow ops call ena_com_flow_steering_*() directly, so rte_flow from a secondary submits admin commands from the wrong process. Proxy them, or simply refuse in ena_flow_ops_get():

        if (rte_eal_process_type() != RTE_PROC_PRIMARY)
                return -E_RTE_SECONDARY;

Warning: features/ena.ini adds the [rte_flow items] and [rte_flow actions] tables but not "Flow API = Y" under [Features].

Info:
- ena_infos_get(): the two "&= ~" lines are no-ops (ENA never sets RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP or
RTE_ETH_DEV_FLOW_OPS_THREAD_SAFE)
and dev_infos_get should not write dev->data. Drop them and the comments.
- ena_flow_create() parses the pattern twice, once inside ena_flow_validate(). Split the attr/started checks into a helper and call ena_flow_parse() once.
- adapter->flow_rule_count duplicates ena_dev->flow_steering.active_rules_cnt. Use the base counter.
- ena_flow_ops_get() logs WARNING when steering is unsupported. testpmd calls rte_flow_flush() on port close, so this fires on every close. Use DEBUG or no log.
- ena_flow_query() only returns ENOTSUP; leave .query NULL and ethdev returns ENOSYS.
- ena_com_flow_steering_remove_rule() and _remove_all_rules() pass a response buffer they never read. Use ena_com_execute_admin_command_no_resp() from patch 01.
- ena_com_flow_steering_destroy() leaves dangling pointers. End it with memset(flow_steering, 0, sizeof(*flow_steering)) like ena_com_rss_destroy().

[PATCH v3 12/13] net/ena/base: remove x86 Tx LLQ write barrier
-------------------------------------------------------------

Warning: arm_wmb() is a no-op on every non-ARM architecture, not just x86. ppc64le, riscv and loongarch are weakly ordered and the driver still builds there. The argument for dropping the barrier (UC doorbell store flushes WC buffers) is x86 specific, so make the test x86 specific:

  #if defined(RTE_ARCH_X86)
  #define ena_llq_wmb() do { } while (0)
  #else
  #define ena_llq_wmb() rte_wmb()
  #endif

(rte_io_wmb() everywhere is the other option, if Graviton testing shows dmb oshst is enough; on x86 it is a compiler barrier.)

Info: the new comment in ena_com_write_bounce_buffer_to_dev() is 20 lines, half of it history of the old wmb(). History belongs in the commit message; keep the comment to what the barrier orders and why x86 does not need it.