Skip to content

Conversation

@ovsrobot
Copy link
Owner

@ovsrobot ovsrobot commented Oct 28, 2025

Auto-submission for "http://patchwork.dpdk.org/project/dpdk/list/?series=36484"

Summary by Sourcery

Enable multi-queue operation and RSS on the r8169 driver by adding configurable RX/TX queue numbers, descriptor format abstraction, and RSS key/RETA management APIs, while refactoring and consolidating descriptor and hardware-specific logic.

New Features:

  • Introduce multi-queue RX/TX support with configurable queue numbers
  • Add RSS support including key initialization, indirection table (RETA) update/query and hash configuration
  • Support multiple RX descriptor formats (types 1, 3, and 4) for newer hardware revisions

Enhancements:

  • Refactor descriptor handling into generic helper functions for mapping, marking and option extraction
  • Simplify extensive mcfg switch-case logic into concise conditional blocks
  • Unify checksum and error checks through inline functions

Documentation:

  • Update driver feature documentation to advertise RSS hash, RSS key update and RETA update support

Summary by CodeRabbit

Release Notes

  • New Features

    • Added RSS (Receive Side Scaling) support for improved network performance and load distribution
    • Added multi-queue support for transmit and receive operations on RTL8169/RTL8125 devices
    • Enhanced device capability reporting for RSS configuration and queue management
  • Documentation

    • Updated driver documentation to reflect RSS and multi-queue features

Howard Wang added 3 commits October 28, 2025 04:56
8126 and 8127 support 4 RX queues and 2 TX queues.

Signed-off-by: Howard Wang <howard_wang@realsil.com.cn>
Signed-off-by: 0-day Robot <robot@bytheb.org>
Signed-off-by: Howard Wang <howard_wang@realsil.com.cn>
Signed-off-by: 0-day Robot <robot@bytheb.org>
Signed-off-by: Howard Wang <howard_wang@realsil.com.cn>
Signed-off-by: 0-day Robot <robot@bytheb.org>
@coderabbitai
Copy link

coderabbitai bot commented Oct 28, 2025

Walkthrough

The r8169 driver is extended to support Receive Side Scaling (RSS) multi-queue operation, featuring multiple RX descriptor format variants (v1/v3/v4), RSS key and indirection table management, and per-queue state tracking for both TX and RX paths. Hardware capability detection and device information reporting now expose RSS and queue capabilities to the network layer.

Changes

Cohort / File(s) Summary
Documentation and Maintenance
.mailmap, MAINTAINERS, doc/guides/nics/features/r8169.ini, doc/guides/nics/r8169.rst
Added Javen Xu as maintainer and contributor. Documented RSS and multi-queue support as new features in the r8169 device capabilities.
Register and Constant Definitions
drivers/net/r8169/r8169_compat.h
Extended RX status bit definitions with versioned variants (V3, V4) and added CFG9346_EEM_MASK constant for enhanced register field coverage.
Driver Operations and Device Info
drivers/net/r8169/r8169_ethdev.c
Exposed RSS-related driver operations (reta_update, reta_query, rss_hash_update, rss_hash_conf_get), populated device info with RSS capabilities (hash_key_size, reta_size, flow_type_rss_offloads), adjusted link speed selection, and updated queue capability reporting based on hardware support.
Header Definitions and Data Structures
drivers/net/r8169/r8169_ethdev.h
Introduced RSS configuration enums and macros (RTL_RSS_OFFLOAD_ALL, RTL_RSS_CTRL_OFFLOAD_ALL, key/table size constants), added RX descriptor structure variants (rtl_rx_desc, rtl_rx_descv3, rtl_rx_descv4), expanded struct rtl_hw with multi-queue fields (EnableRss, rss_key[], rss_indir_tbl[]), and updated rtl_get_rx_port_offloads signature to accept hardware context.
Hardware Configuration
drivers/net/r8169/r8169_hw.c, drivers/net/r8169/r8169_hw.h
Implemented RSS configuration functions (rtl8125_set_rss_hash_opt, rtl8125_store_reta, rtl8125_store_rss_key, rtl8125_config_rss) and RX descriptor type selection (rtl8125_set_rx_desc_type). Refactored switch-case logic into range-based conditions for cleaner chipset handling.
PHY Management
drivers/net/r8169/r8169_phy.c
Consolidated chipset-specific branching logic by replacing explicit CFG_METHOD switch cases with range-based if conditions across multiple functions, reducing code duplication while maintaining behavioral equivalence.
RX/TX Queue Implementation
drivers/net/r8169/r8169_rxtx.c
Restructured RX and TX paths to support multi-queue operation with per-queue descriptor management, added helpers for multiple descriptor formats (rtl_mark_as_last_descriptor_v*, rtl_map_to_asic, rtl_set_desc_dma_addr), implemented per-queue RSS/VMQ configuration (rtl_init_rss, rtl8125_set_rx_q_num, rtl8125_set_tx_q_num), updated descriptor access patterns with format-aware helpers (rtl_rx_desc_opts1, rtl_rx_desc_opts2, rtl_get_rx_desc_hash), and modified rtl_clear_rdu_func signature to accept queue_id parameter.

Sequence Diagrams

sequenceDiagram
    participant App as Application
    participant Driver as r8169 Driver
    participant HW as Hardware
    
    App->>Driver: Enable RX with multi-queue
    Driver->>Driver: rtl_rx_init()
    
    rect rgb(200, 220, 255)
    note over Driver: Multi-queue setup
    Driver->>Driver: rtl_init_rss(hw, nb_rx_queues)
    Driver->>HW: Configure RSS key (rtl8125_store_rss_key)
    Driver->>HW: Configure RETA (rtl8125_store_reta)
    Driver->>HW: Set RX queue number (rtl8125_set_rx_q_num)
    end
    
    loop Per Queue
        Driver->>Driver: Allocate RX ring (multi-desc format)
        Driver->>HW: Initialize per-queue descriptor pointers
    end
    
    Driver->>App: Ready for RX
    
    rect rgb(200, 255, 220)
    note over HW: Per-packet processing
    HW->>HW: Calculate RSS hash
    HW->>HW: Select queue via indirection table
    end
    
    HW->>Driver: Packet received on selected queue
    Driver->>Driver: Extract RSS hash (rtl_get_rx_desc_hash)
    Driver->>Driver: Populate mbuf hash field
    Driver->>App: Deliver packet to application
Loading
sequenceDiagram
    participant Init as Initialization
    participant HW as r8169_hw.c
    participant Ethdev as r8169_ethdev.c
    
    Init->>Ethdev: Query device capabilities
    Ethdev->>Ethdev: rtl_dev_infos_get()
    
    rect rgb(220, 200, 255)
    note over Ethdev: RSS capability reporting
    Ethdev->>Ethdev: Set hash_key_size = RTL_RSS_KEY_SIZE
    Ethdev->>Ethdev: Set reta_size = RTL_MAX_INDIRECTION_TABLE_ENTRIES
    Ethdev->>Ethdev: Set flow_type_rss_offloads = RTL_RSS_CTRL_OFFLOAD_ALL
    end
    
    Ethdev->>Init: Device info with RSS capabilities
    
    Init->>Ethdev: Configure RSS parameters
    Ethdev->>Ethdev: rss_hash_conf_get() / rss_hash_update()
    Ethdev->>HW: Invoke rtl8125_config_rss()
    
    rect rgb(220, 255, 200)
    note over HW: Hardware configuration
    HW->>HW: rtl8125_set_rss_hash_opt()
    HW->>HW: rtl8125_store_rss_key()
    HW->>HW: rtl8125_store_reta()
    end
    
    HW->>Ethdev: Configuration complete
    Ethdev->>Init: Ready for operation
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Key areas requiring focused attention:

  • drivers/net/r8169/r8169_rxtx.c: Complete restructuring of RX/TX paths with multiple descriptor format abstractions, per-queue state management, and RSS integration—high logic density and numerous helper functions introduced.
  • drivers/net/r8169/r8169_ethdev.c: New RSS driver operations and device info population requiring verification of hardware register mapping and offload capability flags.
  • drivers/net/r8169/r8169_hw.c: RSS configuration orchestration and RX descriptor type selection logic—verify correctness of hardware register writes and state sequencing.
  • rtl_clear_rdu_func signature change: Impacts all call sites; verify queue_id parameter is correctly threaded throughout the codebase.
  • Descriptor format dispatch logic: Ensure rtl_hw.HwSuppRxDescType is set correctly per chipset and all descriptor-access helpers route to appropriate format handlers.
  • Per-queue descriptor length handling: Validate hw->RxDescLength is initialized per chipset and used consistently in all descriptor allocation and access paths.

Poem

🐰 A fuzzy tale of queues so deep,
Where RSS keys and RTAs leap,
From v1 through v4 descriptors bright,
The r8169 now scales just right,
Multi-queue dreams at last take flight! 🚀

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.53% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "net/r8169: support multiq and code refactor" accurately reflects the primary objectives of this changeset. The PR introduces comprehensive multi-queue support for both RX and TX paths (evident in the extensive changes to r8169_rxtx.c, r8169_ethdev.c, and related files), implements RSS/RETA handling capabilities, and performs significant code refactoring throughout the codebase (particularly in r8169_phy.c where switch-case blocks are consolidated into range-based conditions). The title is concise, avoids unnecessary noise, and clearly identifies both main aspects of the change: multi-queue functionality and code refactoring. A maintainer reviewing PR history would immediately understand that this submission adds multi-queue driver support while improving code organization.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch series_36484

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai
Copy link

sourcery-ai bot commented Oct 28, 2025

Reviewer's Guide

This PR refactors the r8169 PMD to support multiple Tx/Rx queues with Receive Side Scaling (RSS), restructures descriptor handling across hardware versions, improves per-queue doorbell and no-close logic, and collapses chipset-specific switch statements into more maintainable range-based checks.

Sequence diagram for RX packet processing with multi-queue and RSS

sequenceDiagram
    participant HW as "rtl_hw"
    participant RXQ as "rtl_rx_queue"
    participant DEV as "rte_eth_dev"
    participant APP as "Application"
    APP->>DEV: Request RX packets
    DEV->>RXQ: Call rtl_recv_pkts()
    RXQ->>HW: Get RX descriptor type and length
    RXQ->>RXQ: For each RX descriptor
    RXQ->>HW: Check RSS enabled
    RXQ->>RXQ: Extract RSS hash if enabled
    RXQ->>DEV: Return mbuf with RSS hash
    DEV->>APP: Deliver packets with RSS hash
Loading

Sequence diagram for TX queue doorbell with per-queue registers

sequenceDiagram
    participant HW as "rtl_hw"
    participant TXQ as "rtl_tx_queue"
    participant DEV as "rte_eth_dev"
    participant APP as "Application"
    APP->>DEV: Send packet
    DEV->>TXQ: Enqueue packet
    TXQ->>HW: Update sw_tail_ptr_reg for this queue
    HW->>TXQ: Acknowledge doorbell
    TXQ->>DEV: Confirm TX completion
    DEV->>APP: Notify TX done
Loading

Class diagram for updated RX descriptor types and queue structures

classDiagram
    class rtl_rx_desc {
        +u32 opts1
        +u32 opts2
        +u64 addr
    }
    class rtl_rx_descv3 {
        +RxDescDDWord1_rsv1
        +RxDescDDWord1_rsv2
        +RxDescNormalDDWord2_RSSResult
        +RxDescNormalDDWord2_HeaderBufferLen
        +RxDescNormalDDWord2_HeaderInfo
        +addr_TimeStampLow
        +addr_TimeStampHigh
        +RxDescNormalDDWord4_opts2
        +RxDescNormalDDWord4_opts1
    }
    class rtl_rx_descv4 {
        +addr_RSSInfo
        +addr_RSSResult
        +RxDescNormalDDWord2_opts2
        +RxDescNormalDDWord2_opts1
    }
    class rtl_hw {
        +u8 EnableRss
        +u8 HwSuppRxDescType
        +u16 RxDescLength
        +u8 rss_key[RTL_RSS_KEY_SIZE]
        +u8 rss_indir_tbl[RTL_MAX_INDIRECTION_TABLE_ENTRIES]
    }
    class rtl_rx_queue {
        +struct rtl_rx_desc* hw_ring
        +struct rtl_rx_entry* sw_ring
        +struct rtl_hw* hw
        +uint16_t nb_rx_desc
        +struct rte_mempool* mb_pool
        +uint16_t queue_id
        +uint16_t port_id
        +uint16_t rx_tail
        +struct rte_mbuf* pkt_first_seg
        +struct rte_mbuf* pkt_last_seg
    }
    rtl_hw "1" -- "*" rtl_rx_queue : has
    rtl_rx_queue "1" -- "*" rtl_rx_desc : uses
    rtl_rx_queue "1" -- "*" rtl_rx_descv3 : uses
    rtl_rx_queue "1" -- "*" rtl_rx_descv4 : uses
Loading

Class diagram for updated TX queue structure and doorbell logic

classDiagram
    class rtl_tx_queue {
        +struct rtl_tx_desc* hw_ring
        +struct rtl_tx_entry* sw_ring
        +struct rtl_hw* hw
        +uint16_t nb_tx_desc
        +uint16_t queue_id
        +uint16_t port_id
        +uint16_t tx_free_thresh
        +uint16_t tx_free
        +uint16_t hw_clo_ptr_reg
        +uint16_t sw_tail_ptr_reg
        +uint32_t NextHwDesCloPtr
        +uint32_t BeginHwDesCloPtr
    }
    class rtl_hw {
        +u8 HwSuppTxNoCloseVer
        +u8 EnableTxNoClose
        +u32 MaxTxDescPtrMask
    }
    rtl_hw "1" -- "*" rtl_tx_queue : has
Loading

File-Level Changes

Change Details Files
Multi-queue initialization and management
  • Define QUEUE_NUM_LIMIT and per-queue descriptor offset arrays
  • Loop over nb_rx_queues/nb_tx_queues to reserve DMA zones, write descriptor start addresses, allocate mbufs, and mark queue states
  • Update stop/free routines to iterate over all Rx and Tx queues
drivers/net/r8169/r8169_rxtx.c
drivers/net/r8169/r8169_ethdev.c
drivers/net/r8169/r8169_ethdev.h
doc/guides/nics/features/r8169.ini
RSS and indirection table support
  • Extend struct rtl_hw with rss_key and rss_indir_tbl arrays
  • Implement rss initialization and configuration APIs (rtl_init_rss, rtl8125_config_rss, store_reta, store_rss_key)
  • Expose reta_update/query and rss_hash_update/conf_get in eth_dev ops
  • Adjust dev_info to advertise hash key size, reta size, and RSS offloads
drivers/net/r8169/r8169_rxtx.c
drivers/net/r8169/r8169_ethdev.c
drivers/net/r8169/r8169_ethdev.h
drivers/net/r8169/r8169_hw.h
doc/guides/nics/features/r8169.ini
Descriptor type abstraction and unified Rx path
  • Define new Rx descriptor layouts (rtl_rx_descv3/v4) and enum type
  • Add rtl_get_rxdesc, rtl_map_to_asic, rtl_mark_as_last_descriptor, and opts/extractor helpers
  • Replace manual descriptor field accesses with the new abstraction and unify csum, error and hash extraction logic
drivers/net/r8169/r8169_rxtx.c
drivers/net/r8169/r8169_ethdev.h
Hardware config and power-management refactoring
  • Collapse repetitive switch(hw->mcfg) blocks into range-based if/else conditions
  • Simplify OOB mutex, timer interrupt clear, ASPM, UPS disable, DMA aggregation, and PHY power routines
  • Remove duplicated code paths and unify register writes
drivers/net/r8169/r8169_hw.c
Per-queue Tx doorbell and no-close enhancements
  • Move hw_clo_ptr_reg and sw_tail_ptr_reg into rtl_tx_queue
  • Compute per-queue register offsets in rtl_tx_init and tx_queue_setup
  • Update rtl_get_hw_clo_ptr, tx_clean, rtl8125_doorbell, and tx_done_cleanup to use queue-local pointers
drivers/net/r8169/r8169_rxtx.c

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `drivers/net/r8169/r8169_rxtx.c:573-582` </location>
<code_context>
 static void
 rtl_enable_aspm_clkreq_lock(struct rtl_hw *hw, bool enable)
 {
</code_context>

<issue_to_address>
**issue (bug_risk):** Potential for non-uniform RSS key entropy due to memcpy from rte_rand.

If RTL_RSS_KEY_SIZE isn't a multiple of sizeof(u64), the final bytes of rss_key may remain uninitialized. Please ensure all bytes are set, either by handling the tail explicitly or by looping over each byte.
</issue_to_address>

### Comment 2
<location> `drivers/net/r8169/r8169_rxtx.c:481-482` </location>
<code_context>
+	.rss_hash_conf_get    = rtl_rss_hash_conf_get,
 };

 static int
</code_context>

<issue_to_address>
**issue (bug_risk):** Possible memory leak if allocation fails partway through loop.

If allocation fails after some mbufs have been created, the function returns without freeing them. Free any previously allocated mbufs before returning to prevent memory leaks.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
drivers/net/r8169/r8169_rxtx.c (1)

1649-1652: Fix inconsistent atomic access patterns for opts1 and tx_tail.

Both fields are declared atomic (RTE_ATOMIC(u32) opts1 and RTE_ATOMIC(uint32_t) tx_tail) but are accessed inconsistently: opts1 is read via rte_atomic_load_explicit() but written with plain assignment; tx_tail is read atomically but incremented with plain +=. This violates atomic semantics and risks memory ordering violations for descriptor ownership handoff.

Use atomic stores and fetch operations with appropriate memory ordering:

 txd->opts2 = rte_cpu_to_le_32(opts2);
 rte_wmb();
-txd->opts1 = rte_cpu_to_le_32(opts1);
+rte_atomic_store_explicit(&txd->opts1, rte_cpu_to_le_32(opts1),
+                          rte_memory_order_release);

and

-txq->tx_tail += desc_count;
+(void)rte_atomic_fetch_add_explicit(&txq->tx_tail, desc_count,
+                                    rte_memory_order_release);

Alternatively, if the queue is single-threaded per-core, remove RTE_ATOMIC from both field declarations in the struct.

🧹 Nitpick comments (13)
doc/guides/nics/features/r8169.ini (1)

16-18: RSS features marked as universally supported; clarify chipset scope.

Driver enables RSS only for newer methods (e.g., mcfg ≥ 69). Consider noting in docs that RSS/RETA/Key are available on those chipsets to avoid overstating coverage.

drivers/net/r8169/r8169_compat.h (1)

296-304: Use consistent unsigned bit types for RX status bits.

Replace (1 << n) with (1UL << n) (or reuse BIT_n style) to avoid signed-shift surprises and match existing style.

-    RxRWT_V3  = (1 << 18),
-    RxRES_V3  = (1 << 20),
-    RxRUNT_V3 = (1 << 19),
-    RxCRC_V3  = (1 << 17),
+    RxRWT_V3  = (1UL << 18),
+    RxRES_V3  = (1UL << 20),
+    RxRUNT_V3 = (1UL << 19),
+    RxCRC_V3  = (1UL << 17),
@@
-    RxRES_V4  = (1 << 22),
-    RxRUNT_V4 = (1 << 21),
-    RxCRC_V4  = (1 << 20),
+    RxRES_V4  = (1UL << 22),
+    RxRUNT_V4 = (1UL << 21),
+    RxCRC_V4  = (1UL << 20),
drivers/net/r8169/r8169_ethdev.h (4)

35-49: Use unsigned/standard bit macros for RSS_CTRL flags.

Adopt BIT_x or 1U/1UL shifts consistently to avoid sign issues and match existing style.

-    RSS_CTRL_TCP_IPV4_SUPP     = (1 << 0),
+    RSS_CTRL_TCP_IPV4_SUPP     = (1UL << 0),
@@
-    RSS_CTRL_UDP_IPV6_EXT_SUPP = (1 << 13),
-    RSS_QUAD_CPU_EN            = (1 << 16),
-    RSS_HQ_Q_SUP_R             = (1 << 31),
+    RSS_CTRL_UDP_IPV6_EXT_SUPP = (1UL << 13),
+    RSS_QUAD_CPU_EN            = (1UL << 16),
+    RSS_HQ_Q_SUP_R             = (1UL << 31),

136-142: New RSS fields in struct rtl_hw look fine.

Buffers and enable flag are appropriate. Consider zero-initializing rss_indir_tbl to a round‑robin default during init.


158-229: Descriptor structs: consider adding explicit packing/endianness notes.

If HW requires exact layout, annotate with comments or static asserts. Current defs are likely fine on little‑endian x86.


301-306: rtl_get_rxdesc should return a byte pointer (void) to avoid type confusion across descriptor formats.*

Returning struct rtl_rx_desc* can mislead when HW uses v3/v4 layouts.

-static inline struct rtl_rx_desc*
-rtl_get_rxdesc(struct rtl_hw *hw, struct rtl_rx_desc *base, u32 const number)
+static inline void*
+rtl_get_rxdesc(struct rtl_hw *hw, void *base, u32 const number)
 {
-    return (struct rtl_rx_desc *)((u8 *)base + hw->RxDescLength * number);
+    return (void *)((u8 *)base + hw->RxDescLength * number);
 }
drivers/net/r8169/r8169_hw.c (2)

858-877: Validate nb_rx_queues and clarify bit math in rtl8125_set_rss_hash_opt.

  • Guard nb_rx_queues ∈ [1, 4] (HW limit) to avoid undefined settings.
  • Using & (BIT_0|BIT_1|BIT_2) works but & 0x7 is clearer.
 static void
 rtl8125_set_rss_hash_opt(struct rtl_hw *hw, u16 nb_rx_queues)
 {
-    u32 hash_mask_len;
+    u32 hash_mask_len;
     u32 rss_ctrl;
 
+    /* HW supports up to 4 RX queues */
+    if (nb_rx_queues == 0 || nb_rx_queues > 4)
+        nb_rx_queues = 4;
+
     rss_ctrl = rte_log2_u32(nb_rx_queues);
-    rss_ctrl &= (BIT_0 | BIT_1 | BIT_2);
+    rss_ctrl &= 0x7;
     rss_ctrl <<= RSS_CPU_NUM_OFFSET;
@@
     hash_mask_len = rte_log2_u32(RTL_MAX_INDIRECTION_TABLE_ENTRIES);
-    hash_mask_len &= (BIT_0 | BIT_1 | BIT_2);
+    hash_mask_len &= 0x7;
     rss_ctrl |= hash_mask_len << RSS_MASK_BITS_OFFSET;
 
     RTL_W32(hw, RSS_CTRL_8125, rss_ctrl);
 }

1834-1838: EnableRss gating based on mcfg is reasonable.

Consider documenting the threshold (mcfg ≥ 69) as the condition for RSS capability.

drivers/net/r8169/r8169_ethdev.c (2)

770-795: RETA query reads from cached table only.

Consider syncing from HW during init so first query returns actual HW state.


838-880: rss_hash_conf_get: validate key buffer length before copy.

Avoid copying into a too-small buffer.

-    if (rss_conf->rss_key) {
-        rss_conf->rss_key_len = RTL_RSS_KEY_SIZE;
-        memcpy(rss_conf->rss_key, hw->rss_key, RTL_RSS_KEY_SIZE);
-    }
+    rss_conf->rss_key_len = RTL_RSS_KEY_SIZE;
+    if (rss_conf->rss_key) {
+        if (rss_conf->rss_key_len < RTL_RSS_KEY_SIZE)
+            return -EINVAL;
+        memcpy(rss_conf->rss_key, hw->rss_key, RTL_RSS_KEY_SIZE);
+    }
drivers/net/r8169/r8169_rxtx.c (3)

611-618: Potential misprogramming of RX queue number encoding.

rte_log2_u32() rounds up to next power-of-two; with nb_rx_queues not a power-of-two, HW may be programmed for more queues than allocated.

  • Validate nb_rx_queues is a power-of-two when RSS/multiq is on, or adjust programming to reflect the actual number allocated.

629-634: Avoid fixed-size QUEUE_NUM_LIMIT stack array for RX ring regs.

Risk of OOB if nb_rx_queues > 128; compute register per-iteration instead.

-    u16 desc_start_addr_lo[QUEUE_NUM_LIMIT];
-    desc_start_addr_lo[0] = RxDescAddrLow;
-    for (i = 1; i < nb_rx_queues; i++)
-        desc_start_addr_lo[i] = (u16)(RDSAR_Q1_LOW_8125 + (i - 1) * 8);
+    u16 desc_lo;
...
-    RTL_W32(hw, desc_start_addr_lo[i],
+    desc_lo = (i == 0) ? RxDescAddrLow
+                       : (u16)(RDSAR_Q1_LOW_8125 + (i - 1) * 8);
+    RTL_W32(hw, desc_lo,
             (u64)rxq->hw_ring_phys_addr & DMA_BIT_MASK(32));
-    RTL_W32(hw, desc_start_addr_lo[i] + 4,
+    RTL_W32(hw, desc_lo + 4,
             (u64)rxq->hw_ring_phys_addr >> 32);

Also applies to: 647-651


1394-1401: Same for TX ring regs: drop QUEUE_NUM_LIMIT stack array.

Compute desc register on the fly to avoid OOB and reduce stack.

-    u16 desc_start_addr_lo[QUEUE_NUM_LIMIT];
...
-    desc_start_addr_lo[0] = TxDescStartAddrLow;
-    for (i = 1; i < nb_tx_queues; i++)
-        desc_start_addr_lo[i] = (u16)(TNPDS_Q1_LOW_8125 + (i - 1) * 8);
+    u16 desc_lo;
...
-    RTL_W32(hw, desc_start_addr_lo[i],
+    desc_lo = (i == 0) ? TxDescStartAddrLow
+                       : (u16)(TNPDS_Q1_LOW_8125 + (i - 1) * 8);
+    RTL_W32(hw, desc_lo,
             (u64)txq->hw_ring_phys_addr & DMA_BIT_MASK(32));
-    RTL_W32(hw, desc_start_addr_lo[i] + 4,
+    RTL_W32(hw, desc_lo + 4,
             (u64)txq->hw_ring_phys_addr >> 32);

Also applies to: 1424-1433

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39b54f2 and 158d14f.

📒 Files selected for processing (11)
  • .mailmap (1 hunks)
  • MAINTAINERS (1 hunks)
  • doc/guides/nics/features/r8169.ini (1 hunks)
  • doc/guides/nics/r8169.rst (1 hunks)
  • drivers/net/r8169/r8169_compat.h (2 hunks)
  • drivers/net/r8169/r8169_ethdev.c (7 hunks)
  • drivers/net/r8169/r8169_ethdev.h (5 hunks)
  • drivers/net/r8169/r8169_hw.c (17 hunks)
  • drivers/net/r8169/r8169_hw.h (1 hunks)
  • drivers/net/r8169/r8169_phy.c (8 hunks)
  • drivers/net/r8169/r8169_rxtx.c (28 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
drivers/net/r8169/r8169_hw.h (1)
drivers/net/r8169/r8169_hw.c (2)
  • rtl8125_store_rss_key (893-906)
  • rtl8125_config_rss (908-916)
drivers/net/r8169/r8169_phy.c (1)
drivers/net/r8169/r8169_hw.c (3)
  • rtl_is_8125 (2524-2528)
  • rtl_eri_read (81-85)
  • rtl_eri_write (154-159)
drivers/net/r8169/r8169_hw.c (2)
lib/eal/include/rte_bitops.h (1)
  • rte_log2_u32 (1397-1404)
drivers/net/r8169/r8169_phy.c (6)
  • rtl_mdio_real_read_phy_ocp (75-83)
  • rtl_set_phy_mcu_patch_request (308-349)
  • rtl_mdio_real_write_phy_ocp (122-130)
  • rtl_clear_phy_mcu_patch_request (351-392)
  • rtl_mdio_direct_read_phy_ocp (69-73)
  • rtl_mdio_direct_write_phy_ocp (116-120)
drivers/net/r8169/r8169_ethdev.h (1)
drivers/net/r8169/r8169_rxtx.c (1)
  • rtl_get_rx_port_offloads (312-327)
drivers/net/r8169/r8169_rxtx.c (4)
drivers/net/r8169/r8169_ethdev.h (1)
  • rtl_get_rxdesc (301-305)
lib/eal/include/rte_bitops.h (1)
  • rte_log2_u32 (1397-1404)
lib/mbuf/rte_mbuf.h (3)
  • rte_pktmbuf_data_room_size (919-926)
  • rte_mbuf_raw_alloc (622-636)
  • rte_mbuf_data_iova_default (203-207)
drivers/net/r8169/r8169_hw.c (3)
  • rtl8125_config_rss (908-916)
  • rtl_mac_ocp_read (424-437)
  • rtl_mac_ocp_write (411-422)
drivers/net/r8169/r8169_ethdev.c (2)
drivers/net/r8169/r8169_rxtx.c (2)
  • rtl_get_rx_port_offloads (312-327)
  • rtl_get_tx_port_offloads (1244-1257)
drivers/net/r8169/r8169_hw.c (1)
  • rtl8125_store_rss_key (893-906)
🔇 Additional comments (27)
.mailmap (1)

685-685: Mailmap entry looks good

Sorted correctly and formatted as expected.

MAINTAINERS (1)

1035-1042: Realtek r8169 maintainer addition LGTM

Entry is correctly placed and formatted.

drivers/net/r8169/r8169_hw.h (1)

82-84: RSS helper prototypes OK

Interfaces align with implementations and driver scope.

Please confirm nb_rx_queues is validated at call sites (>=1 and <= device max).

drivers/net/r8169/r8169_phy.c (4)

512-513: Consider symmetry for CFG_METHOD_91 in PMCH set

Power-down avoids clearing PMCH for 91; power-up should likely avoid setting PMCH for 91 too.

Suggested change:

- if (!(hw->mcfg == CFG_METHOD_23 || hw->mcfg == CFG_METHOD_37))
+ if (!(hw->mcfg == CFG_METHOD_23 || hw->mcfg == CFG_METHOD_37 || hw->mcfg == CFG_METHOD_91))
     RTL_W8(hw, PMCH, RTL_R8(hw, PMCH) | BIT_7 | BIT_6);

473-480: Double-check wait/delay coverage for earlier methods

rtl_wait_phy_ups_resume only waits for 29–36 and 8125; mcfg 21–28 will not wait. The 10 ms delay is applied only for 23/27/28.

Please confirm older methods don’t require wait/settling or expand the ranges accordingly.

Also applies to: 501-503


627-646: CFG_METHOD_50 pre-MCU init path

Watchdog clear and setup logic are scoped and consistent with 8125 staging.


558-565: Verify whether CFG_METHOD_37 should be included in the 21–36 branch or requires separate handling.

The gap is real: CFG_METHOD_37 does not fall within either conditional block. However, the codebase shows conflicting patterns. In other functions (e.g., lines 529, 813, 2053, 2076, 2118), CFG_METHOD_37 is grouped with the 21–36 range (e.g., CFG_METHOD_27 && hw->mcfg <= CFG_METHOD_37). Yet in the PMCH register handling just above (lines 553–555), CFG_METHOD_37 is explicitly excluded alongside CFG_METHOD_23 and 91.

This inconsistency requires clarification: either the 0xD0/0xF2 clearing logic should extend the first branch to include 37, or there is hardware-specific reasoning for the exclusion that needs documentation.

doc/guides/nics/r8169.rst (1)

32-35: Docs: add corresponding features matrix entries

Please ensure doc/guides/nics/features/r8169.ini reflects RSS (hash/key/RETA) and multi-queue.

drivers/net/r8169/r8169_compat.h (1)

313-316: Cfg9346_EEM_MASK addition looks good.

Mask matches EEM1|EEM0 bits and is used safely before toggling unlock. LGTM.

If other places rely on equality with Cfg9346_Unlock, ensure they consistently mask with Cfg9346_EEM_MASK.

drivers/net/r8169/r8169_ethdev.h (1)

51-61: Good separation of RTE flags vs HW register flags.

Macros RTL_RSS_OFFLOAD_ALL (RTE flags) vs RTL_RSS_CTRL_OFFLOAD_ALL (HW bits) are clear.

drivers/net/r8169/r8169_hw.c (8)

762-796: Cfg9346 write-gating logic is correct.

Unlock/restore sequence and masks are handled safely. LGTM.


813-824: Timer INT clear path refactor is fine.

Range checks simplify code without changing behavior for 8125 vs non‑8125.


878-892: RETA programming helper looks correct.

Writes 4 entries per dword; matches v2 table layout. LGTM.


893-907: RSS key programming is fine.

Sequential 32‑bit writes across 40‑byte key. LGTM.


918-938: RX descriptor type selection is clear.

mcfg→v3/v4 mapping and register touches look correct.


1492-1552: Chipset name mapping refactor is OK.

Consolidated mapping improves clarity; no behavior concerns.


1872-1885: RX descriptor metadata initialization looks good.

Type and length are set coherently per chipset.


908-917: rtl8125_config_rss() is already being invoked during device start—this recommendation is already implemented.

The function is called during the RX initialization sequence in rtl_dev_start()rtl_rx_init()rtl8125_config_rss() (r8169_rxtx.c:706). When RSS is enabled (hw->EnableRss), it properly configures all RSS defaults: hash options, RETA, and RSS key via its three helper functions.

Likely an incorrect or invalid review comment.

drivers/net/r8169/r8169_ethdev.c (5)

121-125: RSS ops wiring added to eth_dev_ops looks good.

Functions are present and signatures match DPDK API.


167-185: Chipset-based autoneg speed selection is a nice cleanup.

Mapping aligns with capabilities. LGTM.


418-424: Queue capabilities exposure is fine.

4 RX / 2 TX for newer chipsets, 1/1 otherwise. LGTM.


553-563: stats_get signature change (qstats unused) is fine.

No issues; style aligns with other PMDs.


298-346: Rewritten Review Comment

The suggested change is redundant. rtl8125_config_rss is already called within rtl_rx_init at line 706 of drivers/net/r8169/r8169_rxtx.c, after RSS initialization via rtl_init_rss. Since rtl_rx_init is invoked in rtl_dev_start before any subsequent operations, RSS configuration already occurs at the appropriate point in the device startup sequence. Adding the suggested call in rtl_dev_start would cause the function to be invoked twice, which is unnecessary.

Likely an incorrect or invalid review comment.

drivers/net/r8169/r8169_rxtx.c (4)

703-710: RSS enable/disable and VMQ programming look good.

Initialization path cleanly handles both RSS on/off and writes queue count; enabling Rx at the end is correct.

Please confirm RTL8125 expects queue-count programming after cfg9346 is disabled (ordering with other blocks sometimes matters on these chips).

Also applies to: 712-715


409-424: Descriptor helpers are a solid refactor.

Unifying v1/v3/v4 via rtl_set_desc_dma_addr/rtl_mark_to_asic/rtl_map_to_asic reduces duplication and is correct with wmb before ownership.

Also applies to: 458-473, 474-480


719-733: RX fast-path logic looks correct overall.

Good barriers, error recycling, VLAN/CSUM/RSS handling, and prefetching.

Also applies to: 735-749, 751-770, 772-791, 792-811, 812-828, 829-841, 867-887, 889-899, 919-935, 937-944


1689-1696: TX cleanup paths consistent per family.

8125 vs 8168 split is clear; tx_free/head updates are correct with the underflow fix applied.

Also applies to: 1744-1776, 1778-1786

Comment on lines +460 to +467
dev_info->rx_offload_capa = (rtl_get_rx_port_offloads(hw) |
dev_info->rx_queue_offload_capa);
dev_info->tx_offload_capa = rtl_get_tx_port_offloads();

dev_info->hash_key_size = RTL_RSS_KEY_SIZE;
dev_info->reta_size = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
dev_info->flow_type_rss_offloads = RTL_RSS_CTRL_OFFLOAD_ALL;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

flow_type_rss_offloads uses HW register bits; must use RTE RSS flags. Also avoid ORing with uninitialized queue capa.

  • Set dev_info->rx_offload_capa directly from driver capabilities.
  • Use RTL_RSS_OFFLOAD_ALL for flow_type_rss_offloads.
  • Only expose hash_key_size/reta_size when RSS is enabled; else 0.
-    dev_info->rx_offload_capa = (rtl_get_rx_port_offloads(hw) |
-                                 dev_info->rx_queue_offload_capa);
+    dev_info->rx_offload_capa = rtl_get_rx_port_offloads(hw);
@@
-    dev_info->hash_key_size = RTL_RSS_KEY_SIZE;
-    dev_info->reta_size = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
-    dev_info->flow_type_rss_offloads = RTL_RSS_CTRL_OFFLOAD_ALL;
+    if (hw->EnableRss) {
+        dev_info->hash_key_size = RTL_RSS_KEY_SIZE;
+        dev_info->reta_size = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
+        dev_info->flow_type_rss_offloads = RTL_RSS_OFFLOAD_ALL;
+    } else {
+        dev_info->hash_key_size = 0;
+        dev_info->reta_size = 0;
+        dev_info->flow_type_rss_offloads = 0;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dev_info->rx_offload_capa = (rtl_get_rx_port_offloads(hw) |
dev_info->rx_queue_offload_capa);
dev_info->tx_offload_capa = rtl_get_tx_port_offloads();
dev_info->hash_key_size = RTL_RSS_KEY_SIZE;
dev_info->reta_size = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
dev_info->flow_type_rss_offloads = RTL_RSS_CTRL_OFFLOAD_ALL;
dev_info->rx_offload_capa = rtl_get_rx_port_offloads(hw);
dev_info->tx_offload_capa = rtl_get_tx_port_offloads();
if (hw->EnableRss) {
dev_info->hash_key_size = RTL_RSS_KEY_SIZE;
dev_info->reta_size = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
dev_info->flow_type_rss_offloads = RTL_RSS_OFFLOAD_ALL;
} else {
dev_info->hash_key_size = 0;
dev_info->reta_size = 0;
dev_info->flow_type_rss_offloads = 0;
}
🤖 Prompt for AI Agents
In drivers/net/r8169/r8169_ethdev.c around lines 460 to 467, the code currently
ORs rx_offload_capa with an uninitialized rx_queue_offload_capa and assigns
flow_type_rss_offloads from HW register bits; change it to assign
dev_info->rx_offload_capa directly from the driver capability function (do not
OR with dev_info->rx_queue_offload_capa), set dev_info->flow_type_rss_offloads
to RTL_RSS_OFFLOAD_ALL (RTE RSS flags), and only populate
dev_info->hash_key_size and dev_info->reta_size when RSS is enabled (otherwise
set them to 0); leave tx_offload_capa as the driver-provided value.

Comment on lines +728 to +768
static int
rtl_reta_update(struct rte_eth_dev *dev,
struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
{
struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev);
struct rtl_hw *hw = &adapter->hw;
u32 reta;
u16 idx, shift;
u8 mask, rss_indir_tbl;
int i, j;

if (reta_size != RTL_MAX_INDIRECTION_TABLE_ENTRIES) {
PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
"(%d) doesn't match the number hardware can supported "
"(%d)", reta_size, RTL_MAX_INDIRECTION_TABLE_ENTRIES);
return -EINVAL;
}

for (i = 0; i < reta_size; i += 4) {
idx = i / RTE_ETH_RETA_GROUP_SIZE;
shift = i % RTE_ETH_RETA_GROUP_SIZE;
mask = (reta_conf[idx].mask >> shift) & 0xf;

if (!mask)
continue;

for (j = 0, reta = 0; j < 4; j++) {
rss_indir_tbl = (u8)reta_conf[idx].reta[shift + j];
reta |= rss_indir_tbl << (j * 8);

if (!(mask & (1 << j)))
continue;

hw->rss_indir_tbl[i + j] = rss_indir_tbl;
}

RTL_W32(hw, RSS_INDIRECTION_TBL_8125_V2 + i, reta);
}

return 0;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Mask handling bug in RETA update; unmasked entries are overwritten. Validate queue IDs.

Build each 32‑bit RETA word from existing values, and only override masked positions. Also check target queue < nb_rx_queues.

 static int
 rtl_reta_update(struct rte_eth_dev *dev,
                 struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
 {
     struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev);
     struct rtl_hw *hw = &adapter->hw;
-    u32 reta;
-    u16 idx, shift;
-    u8 mask, rss_indir_tbl;
-    int i, j;
+    u32 reta;
+    u16 idx, shift;
+    u8 mask;
+    int i, j;
 
     if (reta_size != RTL_MAX_INDIRECTION_TABLE_ENTRIES) {
@@
-    for (i = 0; i < reta_size; i += 4) {
+    for (i = 0; i < reta_size; i += 4) {
         idx = i / RTE_ETH_RETA_GROUP_SIZE;
         shift = i % RTE_ETH_RETA_GROUP_SIZE;
-        mask = (reta_conf[idx].mask >> shift) & 0xf;
+        mask = (reta_conf[idx].mask >> shift) & 0xF;
 
         if (!mask)
             continue;
 
-        for (j = 0, reta = 0; j < 4; j++) {
-            rss_indir_tbl = (u8)reta_conf[idx].reta[shift + j];
-            reta |= rss_indir_tbl << (j * 8);
-
-            if (!(mask & (1 << j)))
-                continue;
-
-            hw->rss_indir_tbl[i + j] = rss_indir_tbl;
-        }
+        reta = 0;
+        for (j = 0; j < 4; j++) {
+            u8 v = hw->rss_indir_tbl[i + j];
+            if (mask & (1U << j)) {
+                v = (u8)reta_conf[idx].reta[shift + j];
+                if (v >= dev->data->nb_rx_queues)
+                    return -EINVAL;
+                hw->rss_indir_tbl[i + j] = v;
+            }
+            reta |= ((u32)v) << (j * 8);
+        }
 
         RTL_W32(hw, RSS_INDIRECTION_TBL_8125_V2 + i, reta);
     }
 
     return 0;
 }

Comment on lines +797 to +836
static int
rtl_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
{
struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev);
struct rtl_hw *hw = &adapter->hw;
u32 rss_ctrl_8125;

if (!hw->EnableRss || !(rss_conf->rss_hf & RTL_RSS_OFFLOAD_ALL))
return -EINVAL;

if (rss_conf->rss_key)
memcpy(hw->rss_key, rss_conf->rss_key, RTL_RSS_KEY_SIZE);

rtl8125_store_rss_key(hw);

rss_ctrl_8125 = RTL_R32(hw, RSS_CTRL_8125) & ~RTL_RSS_CTRL_OFFLOAD_ALL;

if (rss_conf->rss_hf & RTE_ETH_RSS_IPV4)
rss_ctrl_8125 |= RSS_CTRL_IPV4_SUPP;
if (rss_conf->rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP)
rss_ctrl_8125 |= RSS_CTRL_TCP_IPV4_SUPP;
if (rss_conf->rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP)
rss_ctrl_8125 |= RSS_CTRL_TCP_IPV6_SUPP;
if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6)
rss_ctrl_8125 |= RSS_CTRL_IPV6_SUPP;
if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6_EX)
rss_ctrl_8125 |= RSS_CTRL_IPV6_EXT_SUPP;
if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6_TCP_EX)
rss_ctrl_8125 |= RSS_CTRL_TCP_IPV6_EXT_SUPP;
if (rss_conf->rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP)
rss_ctrl_8125 |= RSS_CTRL_UDP_IPV4_SUPP;
if (rss_conf->rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP)
rss_ctrl_8125 |= RSS_CTRL_UDP_IPV6_SUPP;
if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6_UDP_EX)
rss_ctrl_8125 |= RSS_CTRL_UDP_IPV6_EXT_SUPP;

RTL_W32(hw, RSS_CTRL_8125, rss_ctrl_8125);

return 0;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

rss_hash_update: accept zero mask (disable), validate key length, and reject unsupported bits instead of requiring any supported bit.

Also return -ENOTSUP when RSS not enabled.

 static int
 rtl_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
 {
     struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev);
     struct rtl_hw *hw = &adapter->hw;
     u32 rss_ctrl_8125;
 
-    if (!hw->EnableRss || !(rss_conf->rss_hf & RTL_RSS_OFFLOAD_ALL))
-        return -EINVAL;
+    if (!hw->EnableRss)
+        return -ENOTSUP;
+    /* Only allow supported bits */
+    if (rss_conf->rss_hf & ~RTL_RSS_OFFLOAD_ALL)
+        return -EINVAL;
 
-    if (rss_conf->rss_key)
-        memcpy(hw->rss_key, rss_conf->rss_key, RTL_RSS_KEY_SIZE);
+    if (rss_conf->rss_key) {
+        if (rss_conf->rss_key_len != RTL_RSS_KEY_SIZE)
+            return -EINVAL;
+        memcpy(hw->rss_key, rss_conf->rss_key, RTL_RSS_KEY_SIZE);
+    }
 
     rtl8125_store_rss_key(hw);
 
     rss_ctrl_8125 = RTL_R32(hw, RSS_CTRL_8125) & ~RTL_RSS_CTRL_OFFLOAD_ALL;
@@
-    RTL_W32(hw, RSS_CTRL_8125, rss_ctrl_8125);
+    /* If rss_hf == 0, this clears all offload bits (disable RSS hashing). */
+    RTL_W32(hw, RSS_CTRL_8125, rss_ctrl_8125);
 
     return 0;
 }
🤖 Prompt for AI Agents
In drivers/net/r8169/r8169_ethdev.c around lines 797-836, update
rtl_rss_hash_update to: return -ENOTSUP instead of -EINVAL when hw->EnableRss is
false; allow rss_conf->rss_hf == 0 as a valid call to disable RSS (do not treat
zero as error); if rss_conf->rss_key is non-NULL validate its length equals
RTL_RSS_KEY_SIZE and return -EINVAL (or appropriate error) if it does not;
compute a mask of supported RSS bits and reject any bits in rss_conf->rss_hf
that are unsupported by returning -ENOTSUP (rather than requiring at least one
supported bit), and keep existing logic to set hw->rss_key, call
rtl8125_store_rss_key, compute rss_ctrl_8125 based on supported flags, and write
it with RTL_W32.

Comment on lines +524 to 533
if (hw->mcfg >= CFG_METHOD_21 && hw->mcfg <= CFG_METHOD_24) {
csi_tmp = rtl_eri_read(hw, 0x1AB, 1, ERIAR_ExGMAC);
csi_tmp &= ~(BIT_2 | BIT_3 | BIT_4 | BIT_5 | BIT_6 | BIT_7);
rtl_eri_write(hw, 0x1AB, 1, csi_tmp, ERIAR_ExGMAC);
break;
case CFG_METHOD_25:
case CFG_METHOD_27:
case CFG_METHOD_28:
case CFG_METHOD_29:
case CFG_METHOD_30:
case CFG_METHOD_31:
case CFG_METHOD_32:
case CFG_METHOD_33:
case CFG_METHOD_34:
case CFG_METHOD_35:
case CFG_METHOD_36:
case CFG_METHOD_37:
} else if (hw->mcfg == CFG_METHOD_25 ||
(hw->mcfg >= CFG_METHOD_27 && hw->mcfg <= CFG_METHOD_37)) {
csi_tmp = rtl_eri_read(hw, 0x1AB, 1, ERIAR_ExGMAC);
csi_tmp &= ~(BIT_3 | BIT_6);
rtl_eri_write(hw, 0x1AB, 1, csi_tmp, ERIAR_ExGMAC);
break;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

CFG_METHOD_26 appears unhandled in MCU PME intr masks

Case 26 is not covered by either branch; likely should follow the 25/27–37 path.

If intended to behave like 25/27–37, apply:

-} else if (hw->mcfg == CFG_METHOD_25 ||
-           (hw->mcfg >= CFG_METHOD_27 && hw->mcfg <= CFG_METHOD_37)) {
+} else if (hw->mcfg == CFG_METHOD_25 || hw->mcfg == CFG_METHOD_26 ||
+           (hw->mcfg >= CFG_METHOD_27 && hw->mcfg <= CFG_METHOD_37)) {


---

🏁 Script executed:

```shell
#!/bin/bash
# Search for CFG_METHOD_26 in the driver file and nearby context
rg -n 'CFG_METHOD_26' drivers/net/r8169/r8169_phy.c -B5 -A5

Length of output: 617


🏁 Script executed:

#!/bin/bash
# Search for all CFG_METHOD ranges in the file to understand the pattern
rg -n 'CFG_METHOD_(2[1-9]|3[0-9]|4[0-9])' drivers/net/r8169/r8169_phy.c | head -50

Length of output: 1948


🏁 Script executed:

#!/bin/bash
# Look at the specific code block in question with broader context
sed -n '510,545p' drivers/net/r8169/r8169_phy.c

Length of output: 1076


🏁 Script executed:

#!/bin/bash
# Search for other conditionals handling CFG_METHOD ranges to see the pattern
rg -n 'CFG_METHOD_25|CFG_METHOD_27' drivers/net/r8169/r8169_phy.c -B3 -A3

Length of output: 1962


🏁 Script executed:

#!/bin/bash
# Check if CFG_METHOD_26 is defined in header files
fd -e h | xargs grep -l 'CFG_METHOD' | head -5 | xargs grep 'CFG_METHOD_26'

Length of output: 129


CFG_METHOD_26 is unhandled in MCU PME intr masks block—include in else-if condition

CFG_METHOD_26 is a valid, defined method (confirmed in r8169_compat.h and r8169_hw.h) but falls into neither branch at lines 524–533. The gap between CFG_METHOD_25 (explicit) and CFG_METHOD_27–37 (range) leaves method 26 without MCU PME interrupt mask configuration. Other code patterns (e.g., line 896: hw->mcfg >= CFG_METHOD_25 && hw->mcfg <= CFG_METHOD_36) indicate 26 should be grouped with 25 and 27–37. Apply the proposed fix:

-} else if (hw->mcfg == CFG_METHOD_25 ||
-           (hw->mcfg >= CFG_METHOD_27 && hw->mcfg <= CFG_METHOD_37)) {
+} else if (hw->mcfg == CFG_METHOD_25 || hw->mcfg == CFG_METHOD_26 ||
+           (hw->mcfg >= CFG_METHOD_27 && hw->mcfg <= CFG_METHOD_37)) {
🤖 Prompt for AI Agents
In drivers/net/r8169/r8169_phy.c around lines 524–533, CFG_METHOD_26 is not
covered by the MCU PME interrupt mask branches causing it to miss mask
configuration; update the else-if condition so CFG_METHOD_26 is included (e.g.,
change the condition to group CFG_METHOD_25 through CFG_METHOD_37 or explicitly
include CFG_METHOD_26) so the same rtl_eri_read/modify/write path that clears
the appropriate bits runs for method 26 as well.

Comment on lines +810 to 812
rtl_clear_phy_mcu_patch_request(hw);

rte_delay_ms(2);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Preserve result of rtl_clear_phy_mcu_patch_request

Return value is ignored, possibly masking failure in retval.

Apply:

-        rtl_clear_phy_mcu_patch_request(hw);
+        if (!rtl_clear_phy_mcu_patch_request(hw))
+            retval = FALSE;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rtl_clear_phy_mcu_patch_request(hw);
rte_delay_ms(2);
if (!rtl_clear_phy_mcu_patch_request(hw))
retval = FALSE;
rte_delay_ms(2);
🤖 Prompt for AI Agents
In drivers/net/r8169/r8169_phy.c around lines 810 to 812, the return value of
rtl_clear_phy_mcu_patch_request is ignored which can hide failures; capture its
return (e.g. retval = rtl_clear_phy_mcu_patch_request(hw)), check for an error
(if retval) and handle it appropriately by returning the error or logging and
jumping to cleanup so failures aren’t silently ignored, then keep the
rte_delay_ms(2) only when the call succeeded if that timing depends on success.

Comment on lines 301 to 306
for (i = 0; i < rxq->nb_rx_desc; i++)
rxq->hw_ring[i] = zero_rxd;
memset(rxq->hw_ring, 0, hw->RxDescLength * rxq->nb_rx_desc);

rtl_mark_as_last_descriptor(hw, rtl_get_rxdesc(hw, rxq->hw_ring,
rxq->nb_rx_desc - 1));

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

RX reset zeroing entire ring inside a loop (O(n^2) work).

The loop calls memset over the entire ring on every iteration; wasteful.

Use a single memset:

-    int i;
-    for (i = 0; i < rxq->nb_rx_desc; i++)
-        memset(rxq->hw_ring, 0, hw->RxDescLength * rxq->nb_rx_desc);
+    memset(rxq->hw_ring, 0, hw->RxDescLength * rxq->nb_rx_desc);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In drivers/net/r8169/r8169_rxtx.c around lines 301 to 306, the code currently
calls memset over the entire RX ring inside a for loop causing O(n^2) work;
replace the loop with a single call to memset once that zeroes the whole ring
(use the existing size expression hw->RxDescLength * rxq->nb_rx_desc) and keep
the subsequent rtl_mark_as_last_descriptor call unchanged so only one full-ring
memset is performed.

Comment on lines +506 to 507
rtl_mark_as_last_descriptor(hw, rtl_get_rxdesc(hw, rxq->hw_ring, i));

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

OOB access: last RX descriptor marked at index i (== nb_rx_desc).

After the fill loop, i == nb_rx_desc. Using i indexes past the ring end.

Fix:

-    rtl_mark_as_last_descriptor(hw, rtl_get_rxdesc(hw, rxq->hw_ring, i));
+    rtl_mark_as_last_descriptor(hw, rtl_get_rxdesc(hw, rxq->hw_ring,
+                                                   rxq->nb_rx_desc - 1));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rtl_mark_as_last_descriptor(hw, rtl_get_rxdesc(hw, rxq->hw_ring, i));
rtl_mark_as_last_descriptor(hw, rtl_get_rxdesc(hw, rxq->hw_ring,
rxq->nb_rx_desc - 1));
🤖 Prompt for AI Agents
In drivers/net/r8169/r8169_rxtx.c around lines 506-507, the code calls
rtl_get_rxdesc(hw, rxq->hw_ring, i) after the fill loop where i == nb_rx_desc,
causing an out-of-bounds access; replace the index with the last valid ring slot
by computing the previous index (e.g. last = (i + nb_rx_desc - 1) % nb_rx_desc)
and call rtl_get_rxdesc(..., last) so the last descriptor is marked without
indexing past the ring end.

Comment on lines +596 to +603
for (i = 0; i < RTL_MAX_INDIRECTION_TABLE_ENTRIES; i++)
hw->rss_indir_tbl[i] = i & (nb_rx_queues - 1);

for (i = 0; i < RTL_RSS_KEY_SIZE; i += sizeof(u64)) {
rand = rte_rand();
memcpy(&hw->rss_key[i], &rand, sizeof(u64));
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

RSS indirection uses bitmask; requires power-of-two queues.

Using i & (nb_rx_queues - 1) silently breaks for non-power-of-two.

Either enforce power-of-two or switch to modulo. Modulo keeps behavior general:

-    for (i = 0; i < RTL_MAX_INDIRECTION_TABLE_ENTRIES; i++)
-        hw->rss_indir_tbl[i] = i & (nb_rx_queues - 1);
+    for (i = 0; i < RTL_MAX_INDIRECTION_TABLE_ENTRIES; i++)
+        hw->rss_indir_tbl[i] = i % nb_rx_queues;

Also consider validating queue count when enabling RSS.

🤖 Prompt for AI Agents
In drivers/net/r8169/r8169_rxtx.c around lines 596 to 603 the RSS indirection
table uses a bitmask (i & (nb_rx_queues - 1)), which only works for power-of-two
nb_rx_queues and will produce incorrect mappings for other values; change the
assignment to use modulo (i % nb_rx_queues) to preserve correct distribution for
arbitrary queue counts, and add a validation step where RSS is enabled to either
enforce/require nb_rx_queues be a power-of-two or warn/error if it is not
(preferably allow arbitrary counts by using the modulo change and emit a
debug/warning if nb_rx_queues is not a power-of-two to inform the user).

Comment on lines +1116 to 1125
first_seg->pkt_len -= RTE_ETHER_CRC_LEN;
if (data_len <= RTE_ETHER_CRC_LEN) {
rte_pktmbuf_free_seg(rmb);
first_seg->nb_segs--;
last_seg->data_len = last_seg->data_len -
(RTE_ETHER_CRC_LEN - data_len);
last_seg->next = NULL;
} else {
rmb->data_len = data_len - RTE_ETHER_CRC_LEN;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Possible NULL deref of last_seg when trimming CRC on single-frag frames.

If the packet is a single segment and data_len <= 4, last_seg is NULL.

Guard and treat the current mbuf as last_seg:

-    if (data_len <= RTE_ETHER_CRC_LEN) {
+    if (data_len <= RTE_ETHER_CRC_LEN) {
+        if (last_seg == NULL)
+            last_seg = rmb;
         rte_pktmbuf_free_seg(rmb);
         first_seg->nb_segs--;
         last_seg->data_len = last_seg->data_len -
                              (RTE_ETHER_CRC_LEN - data_len);
         last_seg->next = NULL;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In drivers/net/r8169/r8169_rxtx.c around lines 1116 to 1125, the code can
dereference last_seg when handling CRC trimming on frames where data_len <=
RTE_ETHER_CRC_LEN and the packet is single-segment (last_seg is NULL). Fix by
detecting when last_seg == NULL and treating the current mbuf chain head (e.g.,
first_seg) as last_seg before adjusting data_len and next; i.e., set last_seg =
first_seg when last_seg is NULL, then proceed to decrement last_seg->data_len,
set last_seg->next = NULL and update nb_segs after freeing the tail segment.

Comment on lines 1710 to 1719
if (enable_tx_no_close) {
next_hw_desc_clo_ptr0 = rtl_get_hw_clo_ptr(hw);
hw->NextHwDesCloPtr0 = next_hw_desc_clo_ptr0;
tx_desc_closed = rtl_fast_mod_mask(next_hw_desc_clo_ptr0 -
hw->BeginHwDesCloPtr0, hw->MaxTxDescPtrMask);
txq->NextHwDesCloPtr = rtl_get_hw_clo_ptr(txq);
tx_desc_closed = rtl_fast_mod_mask(txq->NextHwDesCloPtr -
txq->BeginHwDesCloPtr,
hw->MaxTxDescPtrMask);
tx_left = RTE_MIN(((rte_atomic_load_explicit(&txq->tx_tail,
rte_memory_order_relaxed) % nb_tx_desc) - head),
tx_desc_closed);
hw->BeginHwDesCloPtr0 += tx_left;
txq->BeginHwDesCloPtr += tx_left;
} else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

tx_left underflow when EnableTxNoClose is false (8125 paths).

Computing (tail % nb) - head can wrap negative to a huge uint, causing over-free or hangs.

Apply in both functions:

-    } else {
-        tx_left = (rte_atomic_load_explicit(&txq->tx_tail,
-                            rte_memory_order_relaxed) % nb_tx_desc) - head;
-    }
+    } else {
+        uint16_t tail = (uint16_t)(rte_atomic_load_explicit(&txq->tx_tail,
+                                rte_memory_order_relaxed) % nb_tx_desc);
+        tx_left = (tail >= head) ? (tail - head) : (nb_tx_desc - (head - tail));
+    }

Also applies to: 1813-1822

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants