Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@ Jason He <jason.he@broadcom.com>
Jason Wang <jasowang@redhat.com>
Jasper Tran O'Leary <jtranoleary@google.com>
Jasvinder Singh <jasvinder.singh@intel.com>
Javen Xu <javen_xu@realsil.com.cn>
Jay Ding <jay.ding@broadcom.com>
Jay Jayatheerthan <jay.jayatheerthan@intel.com>
Jay Rolette <rolette@infiniteio.com>
Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,7 @@ Realtek r8169
M: Howard Wang <howard_wang@realsil.com.cn>
M: Chunhao Lin <hau@realtek.com>
M: Xing Wang <xing_wang@realsil.com.cn>
M: Javen Xu <javen_xu@realsil.com.cn>
F: drivers/net/r8169/
F: doc/guides/nics/r8169.rst
F: doc/guides/nics/features/r8169.ini
Expand Down
3 changes: 3 additions & 0 deletions doc/guides/nics/features/r8169.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Scattered Rx = Y
TSO = Y
Promiscuous mode = Y
Allmulticast mode = Y
RSS hash = Y
RSS key update = Y
RSS reta update = Y
Flow control = Y
L3 checksum offload = Y
L4 checksum offload = Y
Expand Down
2 changes: 2 additions & 0 deletions doc/guides/nics/r8169.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ Features of the R8169 PMD are:

* Checksum offload
* Jumbo frames supported
* RSS (Receive Side Scaling)
* Multiple queues for TX and RX
10 changes: 10 additions & 0 deletions drivers/net/r8169/r8169_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,15 @@ enum RTL_register_content {
RxRUNT = (1UL << 20),
RxCRC = (1UL << 19),

RxRWT_V3 = (1 << 18),
RxRES_V3 = (1 << 20),
RxRUNT_V3 = (1 << 19),
RxCRC_V3 = (1 << 17),

RxRES_V4 = (1 << 22),
RxRUNT_V4 = (1 << 21),
RxCRC_V4 = (1 << 20),

/* ChipCmd bits */
StopReq = 0x80,
CmdReset = 0x10,
Expand All @@ -301,6 +310,7 @@ enum RTL_register_content {
RxBufEmpty = 0x01,

/* Cfg9346 bits */
Cfg9346_EEM_MASK = 0xC0,
Cfg9346_Lock = 0x00,
Cfg9346_Unlock = 0xC0,
Cfg9346_EEDO = (1UL << 0),
Expand Down
212 changes: 191 additions & 21 deletions drivers/net/r8169/r8169_ethdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,16 @@ static int rtl_allmulticast_disable(struct rte_eth_dev *dev);
static int rtl_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
static int rtl_fw_version_get(struct rte_eth_dev *dev, char *fw_version,
size_t fw_size);

static int rtl_reta_update(struct rte_eth_dev *dev,
struct rte_eth_rss_reta_entry64 *reta_conf,
uint16_t reta_size);
static int rtl_reta_query(struct rte_eth_dev *dev,
struct rte_eth_rss_reta_entry64 *reta_conf,
uint16_t reta_size);
static int rtl_rss_hash_update(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
static int rtl_rss_hash_conf_get(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
/*
* The set of PCI devices this driver supports
*/
Expand Down Expand Up @@ -108,6 +117,11 @@ static const struct eth_dev_ops rtl_eth_dev_ops = {
.tx_queue_release = rtl_tx_queue_release,
.tx_done_cleanup = rtl_tx_done_cleanup,
.txq_info_get = rtl_txq_info_get,

.reta_update = rtl_reta_update,
.reta_query = rtl_reta_query,
.rss_hash_update = rtl_rss_hash_update,
.rss_hash_conf_get = rtl_rss_hash_conf_get,
};

static int
Expand Down Expand Up @@ -150,26 +164,19 @@ _rtl_setup_link(struct rte_eth_dev *dev)

/* Setup link speed and duplex */
if (*link_speeds == RTE_ETH_LINK_SPEED_AUTONEG) {
switch (hw->mcfg) {
case CFG_METHOD_48:
case CFG_METHOD_49:
case CFG_METHOD_50:
case CFG_METHOD_51:
case CFG_METHOD_52:
case CFG_METHOD_53:
case CFG_METHOD_54:
case CFG_METHOD_55:
case CFG_METHOD_56:
case CFG_METHOD_57:
case CFG_METHOD_58:
switch (hw->chipset_name) {
case RTL8125A:
case RTL8125B:
case RTL8168KB:
case RTL8125BP:
case RTL8125D:
case RTL8125CP:
speed_mode = SPEED_2500;
break;
case CFG_METHOD_69:
case CFG_METHOD_70:
case CFG_METHOD_71:
case RTL8126A:
speed_mode = SPEED_5000;
break;
case CFG_METHOD_91:
case RTL8127:
speed_mode = SPEED_10000;
break;
default:
Expand Down Expand Up @@ -408,8 +415,13 @@ rtl_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
dev_info->max_rx_pktlen = JUMBO_FRAME_9K;
dev_info->max_mac_addrs = 1;

dev_info->max_rx_queues = 1;
dev_info->max_tx_queues = 1;
if (hw->mcfg >= CFG_METHOD_69) {
dev_info->max_rx_queues = 4;
dev_info->max_tx_queues = 2;
} else {
dev_info->max_rx_queues = 1;
dev_info->max_tx_queues = 1;
}

dev_info->default_rxconf = (struct rte_eth_rxconf) {
.rx_free_thresh = RTL_RX_FREE_THRESH,
Expand Down Expand Up @@ -445,10 +457,14 @@ rtl_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
dev_info->min_mtu = RTE_ETHER_MIN_MTU;
dev_info->max_mtu = dev_info->max_rx_pktlen - RTL_ETH_OVERHEAD;

dev_info->rx_offload_capa = (rtl_get_rx_port_offloads() |
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;

Comment on lines +460 to +467
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.

return 0;
}

Expand Down Expand Up @@ -535,7 +551,7 @@ rtl_sw_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)

static int
rtl_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats,
struct eth_queue_stats *qstats __rte_unused)
struct eth_queue_stats *qstats __rte_unused)
{
struct rtl_adapter *adapter = RTL_DEV_PRIVATE(dev);
struct rtl_hw *hw = &adapter->hw;
Expand Down Expand Up @@ -709,6 +725,160 @@ rtl_fw_version_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size)
return 0;
}

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;
}
Comment on lines +728 to +768
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;
 }


static int
rtl_reta_query(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;
u16 idx, shift;
int i;

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++) {
idx = i / RTE_ETH_RETA_GROUP_SIZE;
shift = i % RTE_ETH_RETA_GROUP_SIZE;

if (reta_conf[idx].mask & (1ULL << shift))
reta_conf[idx].reta[shift] = hw->rss_indir_tbl[i];
}

return 0;
}

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;
}
Comment on lines +797 to +836
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.


static int
rtl_rss_hash_conf_get(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;
u64 rss_hf = 0;
u32 rss_ctrl_8125;

if (!hw->EnableRss) {
rss_conf->rss_hf = rss_hf;
return 0;
}

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_ctrl_8125 = RTL_R32(hw, RSS_CTRL_8125);

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

rss_conf->rss_hf = rss_hf;

return 0;
}

static int
rtl_dev_init(struct rte_eth_dev *dev)
{
Expand Down
Loading