git: 56c45700f2ae - main - ena: Fix misconfiguration when requesting regular LLQ

From: Arthur Kiyanovski <akiyano_at_FreeBSD.org>
Date: Tue, 29 Apr 2025 17:15:13 UTC
The branch main has been updated by akiyano:

URL: https://cgit.FreeBSD.org/src/commit/?id=56c45700f2ae15755358f2da8266247613c564df

commit 56c45700f2ae15755358f2da8266247613c564df
Author:     David Arinzon <darinzon@amazon.com>
AuthorDate: 2025-04-22 10:54:18 +0000
Commit:     Arthur Kiyanovski <akiyano@FreeBSD.org>
CommitDate: 2025-04-29 17:00:06 +0000

    ena: Fix misconfiguration when requesting regular LLQ
    
    Patch 0a33c047a443 introduced new values to
    hw.ena.force_large_llq_header. The default value of 2 means no
    preference, while 0 and 1 act as the previous false and true
    respectively, which allowed forcefully setting regular or large LLQ.
    
    There are 2 ways to force the driver to select regular LLQ:
    
    1. Setting hw.ena.force_large_llq_header = 0 via sysctl.
    2. Turning on ena express, which makes the recommendation by the FW to
       be regular LLQ.
    
    When the device supports large LLQ but the driver is forced to
    regular LLQ, llq_config->llq_ring_entry_size_value is never initialized
    and since it is a variable allocated on the stack, it stays garbage.
    
    Since this variable is involved in calculating max_entries_in_tx_burst,
    it could cause the maximum burst size to be zero. This causes the driver
    to ignore the real maximum burst size of the device, leading to driver
    resets in devices that have a maximum burst size (Nitro v4 and on. see
    [1] for more information).
    
    In case the garbage value is 0, the calculation of
    max_entries_in_tx_burst divides by 0 and causes kernel panic.
    
    The patch modifies the logic to take into account all use-cases and
    ensure that the relevant fields are properly initialized.
    
    [1]: https://docs.aws.amazon.com/ec2/latest/instancetypes/ec2-nitro-instances.html
    
    Fixes: 0a33c047a443 ("ena: Support LLQ entry size recommendation from device")
    Approved by: cperciva (mentor)
    MFC after: 3 days
    Sponsored by: Amazon, Inc.
    Differential Revision: https://reviews.freebsd.org/D50040
---
 sys/dev/ena/ena.c | 41 ++++++++++++++++++++++++++++++-----------
 1 file changed, 30 insertions(+), 11 deletions(-)

diff --git a/sys/dev/ena/ena.c b/sys/dev/ena/ena.c
index f0b6cec1bb61..af158b5aea1d 100644
--- a/sys/dev/ena/ena.c
+++ b/sys/dev/ena/ena.c
@@ -2759,22 +2759,41 @@ static inline void
 ena_set_llq_configurations(struct ena_llq_configurations *llq_config,
     struct ena_admin_feature_llq_desc *llq, struct ena_adapter *adapter)
 {
+	bool use_large_llq;
+
 	llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
 	llq_config->llq_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
 	llq_config->llq_num_decs_before_header =
 	    ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
-	if ((llq->entry_size_ctrl_supported & ENA_ADMIN_LIST_ENTRY_SIZE_256B) != 0) {
-		if ((ena_force_large_llq_header == ENA_LLQ_HEADER_SIZE_POLICY_LARGE) ||
-		    (ena_force_large_llq_header == ENA_LLQ_HEADER_SIZE_POLICY_DEFAULT &&
-		    llq->entry_size_recommended == ENA_ADMIN_LIST_ENTRY_SIZE_256B)) {
-			llq_config->llq_ring_entry_size =
-			    ENA_ADMIN_LIST_ENTRY_SIZE_256B;
-			llq_config->llq_ring_entry_size_value = 256;
-			adapter->llq_policy = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
-		}
+
+	switch (ena_force_large_llq_header)
+	{
+	case ENA_LLQ_HEADER_SIZE_POLICY_REGULAR:
+		use_large_llq = false;
+		break;
+	case ENA_LLQ_HEADER_SIZE_POLICY_LARGE:
+		use_large_llq = true;
+		break;
+	case ENA_LLQ_HEADER_SIZE_POLICY_DEFAULT:
+		use_large_llq =
+		    (llq->entry_size_recommended == ENA_ADMIN_LIST_ENTRY_SIZE_256B);
+		break;
+	default:
+		use_large_llq = false;
+		ena_log(adapter->pdev, WARN,
+		    "force_large_llq_header should have values [0-2]\n");
+		break;
+	}
+
+	if (!(llq->entry_size_ctrl_supported & ENA_ADMIN_LIST_ENTRY_SIZE_256B))
+		use_large_llq = false;
+
+	if (use_large_llq) {
+		llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
+		llq_config->llq_ring_entry_size_value = 256;
+		adapter->llq_policy = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
 	} else {
-		llq_config->llq_ring_entry_size =
-		    ENA_ADMIN_LIST_ENTRY_SIZE_128B;
+		llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
 		llq_config->llq_ring_entry_size_value = 128;
 		adapter->llq_policy = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
 	}