* [RFC Patch net-next v1 0/9] r8169: add RSS support for RTL8127
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
From: Javen Xu <javen_xu@realsil.com.cn>
This series patch adds RSS support for RTL8127 in the r8169 driver.
Currently, without RSS support, a single CPU core handles all incoming
traffic. Under heavy loads, this single core becomes a bottleneck, causing
high softirq usage and leading to unstable and degraded network throughput.
As a result, we add rss support for RTL8127. This RFC patch is just for
discussing. And we do some experiments on AMD platform. Below is the
result.
Platform: AMD Ryzen Embedded R2514 with Radeon Graphics(4 Cores/8 Threads)
Arch: x86_64
Test command:
Server: iperf3 -s
Client: iperf3 -c 192.168.2.1 -P 20 -t 3600
Monitor: mpstat -P ALL 1
Before this patch (Without RSS):
Throughput: Unstable, fluctuating between 3.76 Gbits/sec and
8.2 Gbits/sec.
CPU Usage: A single CPU core is fully occupied with softirq reaching
up to 96%.
After this patch (With RSS enabled):
Throughput: Stable at 9.42 Gbits/sec.
CPU Usage: The traffic load is evenly distributed across multiple CPU
cores. The maximum softirq on a single core dropped to 63%.
Patch summary:
Patch 1: Adds necessary macro and register definitions for RSS.
Patch 2-4: Support NAPI and multi RX/TX queues.
Patch 5-6: Support MSI-X and enables it specifically for RTL8127.
Patch 7: Enables RSS for RTL8127.
Patch 8-9: Adds ethtool support to configure the number of RX queues.
Javen Xu (9):
r8169: add some register definitions
r8169: add napi and irq support
r8169: add support for multi tx queues
r8169: add support for multi rx queues
r8169: add support for msix
r8169: enable msix for RTL8127
r8169: add support and enable rss
r8169: move struct ethtool_ops
r8169: add support for ethtool
drivers/net/ethernet/realtek/r8169_main.c | 1437 ++++++++++++++++++---
1 file changed, 1238 insertions(+), 199 deletions(-)
--
2.43.0
^ permalink raw reply
* [RFC Patch net-next v1 1/9] r8169: add some register definitions
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
To support rss, this patch adds some macro definitions and register
definitions.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 75 +++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 791277e750ba..0fbec27e4a0d 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -77,6 +77,23 @@
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
#define R8169_TX_STOP_THRS (MAX_SKB_FRAGS + 1)
#define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS)
+#define R8169_MAX_RX_QUEUES 8
+#define R8169_MAX_TX_QUEUES 1
+#define R8169_MAX_MSIX_VEC 32
+#define R8127_MAX_TX_QUEUES 1
+#define R8127_MAX_RX_QUEUES 8
+#define R8127_MAX_IRQ 32
+#define R8127_MIN_IRQ 30
+#define RTL8127_RSS_KEY_SIZE 40
+#define RSS_CPU_NUM_OFFSET 16
+#define RSS_MASK_BITS_OFFSET 8
+#define RTL8127_MAX_INDIRECTION_TABLE_ENTRIES 128
+#define RXS_8125B_RSS_UDP_V4 BIT(27)
+#define RXS_8125_RSS_IPV4_V4 BIT(28)
+#define RXS_8125_RSS_IPV6_V4 BIT(29)
+#define RXS_8125_RSS_TCP_V4 BIT(30)
+#define RTL8127_RXS_RSS_L3_TYPE_MASK_V4 (RXS_8125_RSS_IPV4_V4 | RXS_8125_RSS_IPV6_V4)
+#define RTL8127_RXS_RSS_L4_TYPE_MASK_V4 (RXS_8125_RSS_TCP_V4 | RXS_8125B_RSS_UDP_V4)
#define OCP_STD_PHY_BASE 0xa400
@@ -435,6 +452,8 @@ enum rtl8125_registers {
#define INT_CFG0_CLKREQEN BIT(3)
IntrMask_8125 = 0x38,
IntrStatus_8125 = 0x3c,
+ IntrMask1_8125 = 0x800,
+ IntrStatus1_8125 = 0x802,
INT_CFG1_8125 = 0x7a,
LEDSEL2 = 0x84,
LEDSEL1 = 0x86,
@@ -444,6 +463,36 @@ enum rtl8125_registers {
RSS_CTRL_8125 = 0x4500,
Q_NUM_CTRL_8125 = 0x4800,
EEE_TXIDLE_TIMER_8125 = 0x6048,
+ TNPDS_Q1_LOW = 0x2100,
+ RDSAR_Q1_LOW = 0x4000,
+ IMR_V2_SET_REG_8125 = 0x0d0c,
+ IMR_V2_CLEAR_REG_8125 = 0x0d00,
+ IMR_V4_L2_CLEAR_REG_8125 = 0x0d10,
+ ISR_V2_8125 = 0x0d04,
+ ISR_V4_L2_8125 = 0x0d14,
+};
+
+enum rtl8127_msix_id {
+ MSIX_ID_V4_LINKCHG = 29,
+};
+
+enum rtl8127_rss_register_content {
+ RSS_CTRL_TCP_IPV4_SUPP = (1 << 0),
+ RSS_CTRL_IPV4_SUPP = (1 << 1),
+ RSS_CTRL_TCP_IPV6_SUPP = (1 << 2),
+ RSS_CTRL_IPV6_SUPP = (1 << 3),
+ RSS_CTRL_IPV6_EXT_SUPP = (1 << 4),
+ RSS_CTRL_TCP_IPV6_EXT_SUPP = (1 << 5),
+ RSS_CTRL_UDP_IPV4_SUPP = (1 << 11),
+ RSS_CTRL_UDP_IPV6_SUPP = (1 << 12),
+ RSS_CTRL_UDP_IPV6_EXT_SUPP = (1 << 13),
+ RSS_INDIRECTION_TBL_8125_V2 = 0x4700,
+ RSS_KEY_8125 = 0x4600,
+};
+
+enum rtl8127_rss_flag {
+ RTL_8125_RSS_FLAG_HASH_UDP_IPV4 = (1 << 0),
+ RTL_8125_RSS_FLAG_HASH_UDP_IPV6 = (1 << 1),
};
#define LEDSEL_MASK_8125 0x23f
@@ -474,6 +523,10 @@ enum rtl_register_content {
RxRUNT = (1 << 20),
RxCRC = (1 << 19),
+ RxRES_RSS = (1 << 22),
+ RxRUNT_RSS = (1 << 21),
+ RxCRC_RSS = (1 << 20),
+
/* ChipCmdBits */
StopReq = 0x80,
CmdReset = 0x10,
@@ -576,6 +629,9 @@ enum rtl_register_content {
/* magic enable v2 */
MagicPacket_v2 = (1 << 16), /* Wake up when receives a Magic Packet */
+ ISRIMR_V6_LINKCHG = (1 << 29),
+ ISRIMR_V6_TOK_Q0 = (1 << 8),
+ ISRIMR_V6_ROK_Q0 = (1 << 0),
};
enum rtl_desc_bit {
@@ -633,6 +689,11 @@ enum rtl_rx_desc_bit {
#define RxProtoIP (PID1 | PID0)
#define RxProtoMask RxProtoIP
+ RxUDPT_v4 = (1 << 19),
+ RxTCPT_v4 = (1 << 18),
+ RxUDPF_v4 = (1 << 16), /* UDP/IP checksum failed */
+ RxTCPF_v4 = (1 << 15), /* TCP/IP checksum failed */
+
IPFail = (1 << 16), /* IP checksum failed */
UDPFail = (1 << 15), /* UDP/IP checksum failed */
TCPFail = (1 << 14), /* TCP/IP checksum failed */
@@ -659,6 +720,11 @@ struct RxDesc {
__le64 addr;
};
+enum features {
+ RTL_FEATURE_MSI = (1 << 1),
+ RTL_FEATURE_MSIX = (1 << 2),
+};
+
struct ring_info {
struct sk_buff *skb;
u32 len;
@@ -728,6 +794,13 @@ enum rtl_dash_type {
RTL_DASH_25_BP,
};
+enum rx_desc_ring_type {
+ RX_DESC_RING_TYPE_UNKNOWN = 0,
+ RX_DESC_RING_TYPE_DEAFULT,
+ RX_DESC_RING_TYPE_RSS,
+ RX_DESC_RING_TYPE_MAX
+};
+
struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev;
@@ -763,6 +836,8 @@ struct rtl8169_private {
unsigned aspm_manageable:1;
unsigned dash_enabled:1;
bool sfp_mode:1;
+ bool rss_support:1;
+ bool rss_enable:1;
dma_addr_t counters_phys_addr;
struct rtl8169_counters *counters;
struct rtl8169_tc_offsets tc_offset;
--
2.43.0
^ permalink raw reply related
* [RFC Patch net-next v1 5/9] r8169: add support for msix
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch add support for msix. But we still use MSI here. And we force
nvecs to 1. We will modify it in rss patch.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 162 ++++++++++++++++++++--
1 file changed, 151 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 52e690eba644..7d493342ab4b 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -1764,26 +1764,40 @@ static u32 rtl_get_events(struct rtl8169_private *tp)
static void rtl_ack_events(struct rtl8169_private *tp, u32 bits)
{
- if (rtl_is_8125(tp))
+ if (rtl_is_8125(tp)) {
RTL_W32(tp, IntrStatus_8125, bits);
- else
+ if (tp->features & RTL_FEATURE_MSIX) {
+ RTL_W32(tp, ISR_V2_8125, 0xffffffff);
+ RTL_W32(tp, ISR_V4_L2_8125, 0xffffffff);
+ }
+ } else {
RTL_W16(tp, IntrStatus, bits);
+ }
}
static void rtl_irq_disable(struct rtl8169_private *tp)
{
- if (rtl_is_8125(tp))
+ if (rtl_is_8125(tp)) {
RTL_W32(tp, IntrMask_8125, 0);
- else
+ if (tp->features & RTL_FEATURE_MSIX) {
+ RTL_W32(tp, IMR_V2_CLEAR_REG_8125, 0xffffffff);
+ RTL_W32(tp, IMR_V4_L2_CLEAR_REG_8125, 0xffffffff);
+ }
+ } else {
RTL_W16(tp, IntrMask, 0);
+ }
}
static void rtl_irq_enable(struct rtl8169_private *tp)
{
- if (rtl_is_8125(tp))
- RTL_W32(tp, IntrMask_8125, tp->irq_mask);
- else
+ if (rtl_is_8125(tp)) {
+ if (tp->features & RTL_FEATURE_MSIX)
+ RTL_W32(tp, IMR_V2_SET_REG_8125, tp->irq_mask);
+ else
+ RTL_W32(tp, IntrMask_8125, tp->irq_mask);
+ } else {
RTL_W16(tp, IntrMask, tp->irq_mask);
+ }
}
static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
@@ -2894,6 +2908,10 @@ static void rtl_software_parameter_initialize(struct rtl8169_private *tp)
tp->InitRxDescType = RX_DESC_RING_TYPE_DEAFULT;
tp->HwCurrIsrVer = tp->HwSuppIsrVer;
+ /* This just force nvecs, and will be remove in the following patch*/
+ tp->min_irq_nvecs = 1;
+ tp->max_irq_nvecs = 1;
+
rtl_setup_mqs_reg(tp);
rtl_set_ring_size(tp, NUM_RX_DESC, NUM_TX_DESC);
}
@@ -5321,6 +5339,44 @@ static void rtl8169_free_irq(struct rtl8169_private *tp)
}
}
+static void rtl8169_disable_hw_interrupt_msix(struct rtl8169_private *tp, int message_id)
+{
+ RTL_W32(tp, IMR_V2_CLEAR_REG_8125, BIT(message_id));
+}
+
+static void rtl8169_clear_hw_isr(struct rtl8169_private *tp, int message_id)
+{
+ RTL_W32(tp, ISR_V2_8125, BIT(message_id));
+}
+
+static void rtl8169_enable_hw_interrupt_msix(struct rtl8169_private *tp, int message_id)
+{
+ RTL_W32(tp, IMR_V2_SET_REG_8125, BIT(message_id));
+}
+
+static irqreturn_t rtl8169_interrupt_msix(int irq, void *dev_instance)
+{
+ struct rtl8169_napi *napi = dev_instance;
+ struct rtl8169_private *tp = napi->priv;
+ int message_id = napi->index;
+
+ rtl8169_disable_hw_interrupt_msix(tp, message_id);
+
+ rtl8169_clear_hw_isr(tp, message_id);
+
+ if (message_id == MSIX_ID_V4_LINKCHG) {
+ phy_mac_interrupt(tp->phydev);
+ rtl8169_enable_hw_interrupt_msix(tp, message_id);
+ return IRQ_HANDLED;
+ }
+
+ tp->recheck_desc_ownbit = true;
+
+ napi_schedule(&napi->napi);
+
+ return IRQ_HANDLED;
+}
+
static int rtl8169_request_irq(struct rtl8169_private *tp)
{
struct net_device *dev = tp->dev;
@@ -5331,10 +5387,14 @@ static int rtl8169_request_irq(struct rtl8169_private *tp)
for (int i = 0; i < tp->irq_nvecs; i++) {
irq = &tp->irq_tbl[i];
+ if (tp->features & RTL_FEATURE_MSIX && tp->HwCurrIsrVer > 1)
+ irq->handler = rtl8169_interrupt_msix;
+ else
+ irq->handler = rtl8169_interrupt;
napi = &tp->r8169napi[i];
snprintf(irq->name, len, "%s-%d", dev->name, i);
- rc = pci_request_irq(tp->pci_dev, i, rtl8169_interrupt, NULL, napi, irq->name);
+ rc = pci_request_irq(tp->pci_dev, i, irq->handler, NULL, napi, irq->name);
if (rc)
break;
@@ -5786,10 +5846,18 @@ static const struct net_device_ops rtl_netdev_ops = {
static void rtl_set_irq_mask(struct rtl8169_private *tp)
{
- tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
+ if (tp->features & RTL_FEATURE_MSIX) {
+ tp->irq_mask = ISRIMR_V6_LINKCHG;
+ for (int i = 0; i < tp->num_tx_rings; i++)
+ tp->irq_mask |= ISRIMR_V6_TOK_Q0 << i;
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ tp->irq_mask |= ISRIMR_V6_ROK_Q0 << i;
+ } else {
+ tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
- tp->irq_mask |= SYSErr | RxFIFOOver;
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ tp->irq_mask |= SYSErr | RxFIFOOver;
+ }
}
static int rtl_alloc_irq(struct rtl8169_private *tp)
@@ -5817,6 +5885,18 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
if (nvecs < 0)
nvecs = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ tp->features &= ~(RTL_FEATURE_MSIX | RTL_FEATURE_MSI);
+
+ if (nvecs > 0) {
+ tp->irq_nvecs = nvecs;
+ tp->irq = pci_irq_vector(pdev, 0);
+ if (nvecs > 1)
+ tp->features |= RTL_FEATURE_MSIX;
+ else if (pci_dev_msi_enabled(pdev))
+ tp->features |= RTL_FEATURE_MSI;
+ return 0;
+ }
+
tp->irq = pdev->irq;
tp->irq_nvecs = 1;
@@ -6087,6 +6167,52 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp)
return false;
}
+static int rtl8169_poll_msix_rx(struct napi_struct *napi, int budget)
+{
+ struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi, napi);
+ struct rtl8169_private *tp = r8169_napi->priv;
+ struct net_device *dev = tp->dev;
+ const int message_id = r8169_napi->index;
+ int work_done = 0;
+
+ if (message_id < tp->num_rx_rings)
+ work_done += rtl_rx(dev, tp, &tp->rx_ring[message_id], budget);
+
+ if (work_done < budget && napi_complete_done(napi, work_done))
+ rtl8169_enable_hw_interrupt_msix(tp, message_id);
+
+ return work_done;
+}
+
+static int rtl8169_poll_msix_tx(struct napi_struct *napi, int budget)
+{
+ struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi, napi);
+ struct rtl8169_private *tp = r8169_napi->priv;
+ struct net_device *dev = tp->dev;
+ unsigned int work_done = 0;
+ const int message_id = r8169_napi->index;
+ int tx_ring_idx = message_id - 8;
+
+ if (tx_ring_idx >= 0 && tx_ring_idx < tp->num_tx_rings)
+ work_done += rtl_tx(dev, tp, &tp->tx_ring[tx_ring_idx], budget);
+
+ if (work_done < budget && napi_complete_done(napi, work_done))
+ rtl8169_enable_hw_interrupt_msix(tp, message_id);
+
+ return work_done;
+}
+
+static int rtl8169_poll_msix_other(struct napi_struct *napi, int budget)
+{
+ struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi, napi);
+ struct rtl8169_private *tp = r8169_napi->priv;
+ const int message_id = r8169_napi->index;
+
+ napi_complete_done(napi, budget);
+ rtl8169_enable_hw_interrupt_msix(tp, message_id);
+
+ return 1;
+}
static void r8169_init_napi(struct rtl8169_private *tp)
{
@@ -6095,6 +6221,20 @@ static void r8169_init_napi(struct rtl8169_private *tp)
int (*poll)(struct napi_struct *napi, int budget);
poll = rtl8169_poll;
+ if (tp->features & RTL_FEATURE_MSIX) {
+ switch (tp->HwCurrIsrVer) {
+ case 6:
+ if (i < R8127_MAX_RX_QUEUES)
+ poll = rtl8169_poll_msix_rx;
+ else if (i > 7 && i < 16)
+ poll = rtl8169_poll_msix_tx;
+ else
+ poll = rtl8169_poll_msix_other;
+ break;
+ default:
+ break;
+ }
+ }
netif_napi_add(tp->dev, &r8169napi->napi, poll);
r8169napi->priv = tp;
r8169napi->index = i;
--
2.43.0
^ permalink raw reply related
* [RFC Patch net-next v1 9/9] r8169: add support for ethtool
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch add support for changing rx queues by ethtool. We can set rx
1, 2, 4, 8 by ethtool -L eth1 rx num.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 68 +++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 6b574fc336d6..57087abe7d88 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -6518,6 +6518,72 @@ static void r8169_init_napi(struct rtl8169_private *tp)
}
}
+static void rtl8169_get_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ ch->max_rx = tp->HwSuppNumRxQueues ? tp->HwSuppNumRxQueues : 1;
+ ch->max_tx = tp->HwSuppNumTxQueues ? tp->HwSuppNumTxQueues : 1;
+ ch->max_other = 0;
+ ch->max_combined = 0;
+
+ ch->rx_count = tp->num_rx_rings;
+ ch->tx_count = tp->num_tx_rings;
+ ch->other_count = 0;
+ ch->combined_count = 0;
+}
+
+static int rtl8169_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ bool if_running = netif_running(dev);
+ int i;
+
+ if (!tp->rss_support && (ch->rx_count > 1 || ch->tx_count > 1)) {
+ netdev_warn(dev, "This chip does not support multiple channels/RSS.\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (ch->rx_count == 0 || ch->tx_count == 0)
+ return -EINVAL;
+ if (ch->rx_count > tp->HwSuppNumRxQueues ||
+ ch->tx_count > tp->HwSuppNumTxQueues)
+ return -EINVAL;
+ if (ch->other_count || ch->combined_count)
+ return -EINVAL;
+
+ if (ch->rx_count == tp->num_rx_rings &&
+ ch->tx_count == tp->num_tx_rings)
+ return 0;
+
+ if (if_running)
+ rtl8169_close(dev);
+
+ tp->num_rx_rings = ch->rx_count;
+ tp->num_tx_rings = ch->tx_count;
+
+ tp->rss_enable = (tp->num_rx_rings > 1 && tp->rss_support);
+
+ for (i = 0; i < tp->HwSuppIndirTblEntries; i++) {
+ if (tp->rss_enable)
+ tp->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
+ else
+ tp->rss_indir_tbl[i] = 0;
+ }
+
+ if (tp->rss_enable)
+ tp->InitRxDescType = RX_DESC_RING_TYPE_RSS;
+ else
+ tp->InitRxDescType = RX_DESC_RING_TYPE_DEAFULT;
+
+ if (if_running)
+ return rtl_open(dev);
+
+ return 0;
+}
+
static const struct ethtool_ops rtl8169_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES,
@@ -6536,6 +6602,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.nway_reset = phy_ethtool_nway_reset,
.get_eee = rtl8169_get_eee,
.set_eee = rtl8169_set_eee,
+ .get_channels = rtl8169_get_channels,
+ .set_channels = rtl8169_set_channels,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = rtl8169_set_link_ksettings,
.get_ringparam = rtl8169_get_ringparam,
--
2.43.0
^ permalink raw reply related
* [RFC Patch net-next v1 8/9] r8169: move struct ethtool_ops
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch move struct ethtool_ops, no changes. Prepare for next patch.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 56 +++++++++++------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index b3f15e6fd5e9..6b574fc336d6 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -2587,34 +2587,6 @@ static int rtl8169_set_link_ksettings(struct net_device *ndev,
return 0;
}
-static const struct ethtool_ops rtl8169_ethtool_ops = {
- .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
- ETHTOOL_COALESCE_MAX_FRAMES,
- .get_drvinfo = rtl8169_get_drvinfo,
- .get_regs_len = rtl8169_get_regs_len,
- .get_link = ethtool_op_get_link,
- .get_coalesce = rtl_get_coalesce,
- .set_coalesce = rtl_set_coalesce,
- .get_regs = rtl8169_get_regs,
- .get_wol = rtl8169_get_wol,
- .set_wol = rtl8169_set_wol,
- .get_strings = rtl8169_get_strings,
- .get_sset_count = rtl8169_get_sset_count,
- .get_ethtool_stats = rtl8169_get_ethtool_stats,
- .get_ts_info = ethtool_op_get_ts_info,
- .nway_reset = phy_ethtool_nway_reset,
- .get_eee = rtl8169_get_eee,
- .set_eee = rtl8169_set_eee,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = rtl8169_set_link_ksettings,
- .get_ringparam = rtl8169_get_ringparam,
- .get_pause_stats = rtl8169_get_pause_stats,
- .get_pauseparam = rtl8169_get_pauseparam,
- .set_pauseparam = rtl8169_set_pauseparam,
- .get_eth_mac_stats = rtl8169_get_eth_mac_stats,
- .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
-};
-
static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool gmii)
{
/* Chips combining a 1Gbps MAC with a 100Mbps PHY */
@@ -6546,6 +6518,34 @@ static void r8169_init_napi(struct rtl8169_private *tp)
}
}
+static const struct ethtool_ops rtl8169_ethtool_ops = {
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
+ ETHTOOL_COALESCE_MAX_FRAMES,
+ .get_drvinfo = rtl8169_get_drvinfo,
+ .get_regs_len = rtl8169_get_regs_len,
+ .get_link = ethtool_op_get_link,
+ .get_coalesce = rtl_get_coalesce,
+ .set_coalesce = rtl_set_coalesce,
+ .get_regs = rtl8169_get_regs,
+ .get_wol = rtl8169_get_wol,
+ .set_wol = rtl8169_set_wol,
+ .get_strings = rtl8169_get_strings,
+ .get_sset_count = rtl8169_get_sset_count,
+ .get_ethtool_stats = rtl8169_get_ethtool_stats,
+ .get_ts_info = ethtool_op_get_ts_info,
+ .nway_reset = phy_ethtool_nway_reset,
+ .get_eee = rtl8169_get_eee,
+ .set_eee = rtl8169_set_eee,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = rtl8169_set_link_ksettings,
+ .get_ringparam = rtl8169_get_ringparam,
+ .get_pause_stats = rtl8169_get_pause_stats,
+ .get_pauseparam = rtl8169_get_pauseparam,
+ .set_pauseparam = rtl8169_set_pauseparam,
+ .get_eth_mac_stats = rtl8169_get_eth_mac_stats,
+ .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
+};
+
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct rtl_chip_info *chip;
--
2.43.0
^ permalink raw reply related
* [RFC Patch net-next v1 2/9] r8169: add napi and irq support
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
Multi tx queues and rx queues require multi irq support. Each irq pairs
with one napi.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 205 ++++++++++++++++++++--
1 file changed, 187 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 0fbec27e4a0d..d1f3a208bd1b 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -794,6 +794,19 @@ enum rtl_dash_type {
RTL_DASH_25_BP,
};
+struct rtl8169_napi {
+ struct napi_struct napi;
+ void *priv;
+ int index;
+};
+
+struct rtl8169_irq {
+ irq_handler_t handler;
+ unsigned int vector;
+ u8 requested;
+ char name[IFNAMSIZ + 10];
+};
+
enum rx_desc_ring_type {
RX_DESC_RING_TYPE_UNKNOWN = 0,
RX_DESC_RING_TYPE_DEAFULT,
@@ -818,9 +831,20 @@ struct rtl8169_private {
dma_addr_t RxPhyAddr;
struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
+ struct rtl8169_irq irq_tbl[R8169_MAX_MSIX_VEC];
+ struct rtl8169_napi r8169napi[R8169_MAX_MSIX_VEC];
+ u16 isr_reg[R8169_MAX_MSIX_VEC];
+ u16 imr_reg[R8169_MAX_MSIX_VEC];
+ unsigned int num_tx_rings;
+ unsigned int num_rx_rings;
u16 cp_cmd;
u16 tx_lpi_timer;
u32 irq_mask;
+ u8 min_irq_nvecs;
+ u8 max_irq_nvecs;
+ u8 HwSuppIsrVer;
+ u8 HwCurrIsrVer;
+ u8 irq_nvecs;
int irq;
struct clk *clk;
@@ -2755,6 +2779,45 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
}
+static void rtl_setup_mqs_reg(struct rtl8169_private *tp)
+{
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_52) {
+ tp->isr_reg[0] = IntrStatus;
+ tp->imr_reg[0] = IntrMask;
+ } else {
+ tp->isr_reg[0] = IntrStatus_8125;
+ tp->imr_reg[0] = IntrMask_8125;
+ }
+
+ for (int i = 1; i < tp->max_irq_nvecs; i++)
+ tp->isr_reg[i] = (u16)(IntrStatus1_8125 + (i - 1) * 4);
+
+ for (int i = 1; i < tp->max_irq_nvecs; i++)
+ tp->imr_reg[i] = (u16)(IntrMask1_8125 + (i - 1) * 4);
+}
+
+static void rtl_software_parameter_initialize(struct rtl8169_private *tp)
+{
+ tp->num_rx_rings = 1;
+ tp->num_tx_rings = 1;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_80:
+ tp->min_irq_nvecs = R8127_MIN_IRQ;
+ tp->max_irq_nvecs = R8127_MAX_IRQ;
+ tp->HwSuppIsrVer = 6;
+ break;
+ default:
+ tp->min_irq_nvecs = 1;
+ tp->max_irq_nvecs = 1;
+ tp->HwSuppIsrVer = 1;
+ break;
+ }
+ tp->HwCurrIsrVer = tp->HwSuppIsrVer;
+
+ rtl_setup_mqs_reg(tp);
+}
+
static void rtl_request_firmware(struct rtl8169_private *tp)
{
struct rtl_fw *rtl_fw;
@@ -4294,6 +4357,7 @@ static int rtl8169_rx_fill(struct rtl8169_private *tp)
return 0;
}
+
static int rtl8169_init_ring(struct rtl8169_private *tp)
{
rtl8169_init_ring_indexes(tp);
@@ -4313,6 +4377,7 @@ static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int entry)
DMA_TO_DEVICE);
memset(desc, 0, sizeof(*desc));
memset(tx_skb, 0, sizeof(*tx_skb));
+
}
static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
@@ -4341,9 +4406,21 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp)
netdev_reset_queue(tp->dev);
}
+static void rtl8169_napi_disable(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->irq_nvecs; i++)
+ napi_disable(&tp->r8169napi[i].napi);
+}
+
+static void rtl8169_napi_enable(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->irq_nvecs; i++)
+ napi_enable(&tp->r8169napi[i].napi);
+}
+
static void rtl8169_cleanup(struct rtl8169_private *tp)
{
- napi_disable(&tp->napi);
+ rtl8169_napi_disable(tp);
/* Give a racing hard_start_xmit a few cycles to complete. */
synchronize_net();
@@ -4389,7 +4466,8 @@ static void rtl_reset_work(struct rtl8169_private *tp)
for (i = 0; i < NUM_RX_DESC; i++)
rtl8169_mark_to_asic(tp->RxDescArray + i);
- napi_enable(&tp->napi);
+ rtl8169_napi_enable(tp);
+
rtl_hw_start(tp);
}
@@ -4895,7 +4973,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
goto release_descriptor;
}
- skb = napi_alloc_skb(&tp->napi, pkt_size);
+ skb = napi_alloc_skb(&tp->r8169napi[0].napi, pkt_size);
if (unlikely(!skb)) {
dev->stats.rx_dropped++;
goto release_descriptor;
@@ -4919,7 +4997,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
if (skb->pkt_type == PACKET_MULTICAST)
dev->stats.multicast++;
- napi_gro_receive(&tp->napi, skb);
+ napi_gro_receive(&tp->r8169napi[0].napi, skb);
dev_sw_netstats_rx_add(dev, pkt_size);
release_descriptor:
@@ -4931,7 +5009,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
{
- struct rtl8169_private *tp = dev_instance;
+ struct rtl8169_napi *napi = dev_instance;
+ struct rtl8169_private *tp = napi->priv;
u32 status = rtl_get_events(tp);
if ((status & 0xffff) == 0xffff || !(status & tp->irq_mask))
@@ -4948,13 +5027,53 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
phy_mac_interrupt(tp->phydev);
rtl_irq_disable(tp);
- napi_schedule(&tp->napi);
+ napi_schedule(&napi->napi);
out:
rtl_ack_events(tp, status);
return IRQ_HANDLED;
}
+static void rtl8169_free_irq(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->irq_nvecs; i++) {
+ struct rtl8169_irq *irq = &tp->irq_tbl[i];
+ struct rtl8169_napi *napi = &tp->r8169napi[i];
+
+ if (irq->requested) {
+ irq->requested = 0;
+ pci_free_irq(tp->pci_dev, i, napi);
+ }
+ }
+}
+
+static int rtl8169_request_irq(struct rtl8169_private *tp)
+{
+ struct net_device *dev = tp->dev;
+ int rc = 0;
+ struct rtl8169_irq *irq;
+ struct rtl8169_napi *napi;
+ const int len = sizeof(tp->irq_tbl[0].name);
+
+ for (int i = 0; i < tp->irq_nvecs; i++) {
+ irq = &tp->irq_tbl[i];
+
+ napi = &tp->r8169napi[i];
+ snprintf(irq->name, len, "%s-%d", dev->name, i);
+ rc = pci_request_irq(tp->pci_dev, i, rtl8169_interrupt, NULL, napi, irq->name);
+
+ if (rc)
+ break;
+
+ irq->vector = pci_irq_vector(tp->pci_dev, i);
+ irq->requested = 1;
+ }
+
+ if (rc)
+ rtl8169_free_irq(tp);
+ return rc;
+}
+
static void rtl_task(struct work_struct *work)
{
struct rtl8169_private *tp =
@@ -4989,9 +5108,10 @@ static void rtl_task(struct work_struct *work)
static int rtl8169_poll(struct napi_struct *napi, int budget)
{
- struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
+ struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi, napi);
+ struct rtl8169_private *tp = r8169_napi->priv;
struct net_device *dev = tp->dev;
- int work_done;
+ int work_done = 0;
rtl_tx(dev, tp, budget);
@@ -5110,7 +5230,7 @@ static void rtl8169_up(struct rtl8169_private *tp)
phy_init_hw(tp->phydev);
phy_resume(tp->phydev);
rtl8169_init_phy(tp);
- napi_enable(&tp->napi);
+ rtl8169_napi_enable(tp);
enable_work(&tp->wk.work);
rtl_reset_work(tp);
@@ -5125,10 +5245,12 @@ static int rtl8169_close(struct net_device *dev)
pm_runtime_get_sync(&pdev->dev);
netif_stop_queue(dev);
+
rtl8169_down(tp);
rtl8169_rx_clear(tp);
- free_irq(tp->irq, tp);
+
+ rtl8169_free_irq(tp);
phy_disconnect(tp->phydev);
@@ -5183,14 +5305,14 @@ static int rtl_open(struct net_device *dev)
rtl_request_firmware(tp);
irqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED;
- retval = request_irq(tp->irq, rtl8169_interrupt, irqflags, dev->name, tp);
+
+ retval = rtl8169_request_irq(tp);
if (retval < 0)
goto err_release_fw_2;
retval = r8169_phy_connect(tp);
if (retval)
goto err_free_irq;
-
rtl8169_up(tp);
rtl8169_init_counter_offsets(tp);
netif_start_queue(dev);
@@ -5200,7 +5322,7 @@ static int rtl_open(struct net_device *dev)
return retval;
err_free_irq:
- free_irq(tp->irq, tp);
+ rtl8169_free_irq(tp);
err_release_fw_2:
rtl_release_firmware(tp);
rtl8169_rx_clear(tp);
@@ -5265,7 +5387,7 @@ static int rtl8169_runtime_resume(struct device *dev)
rtl_rar_set(tp, tp->dev->dev_addr);
__rtl8169_set_wol(tp, tp->saved_wolopts);
- if (tp->TxDescArray)
+ if (netif_running(tp->dev))
rtl8169_up(tp);
netif_device_attach(tp->dev);
@@ -5303,7 +5425,7 @@ static int rtl8169_runtime_suspend(struct device *device)
{
struct rtl8169_private *tp = dev_get_drvdata(device);
- if (!tp->TxDescArray) {
+ if (!netif_running(tp->dev)) {
netif_device_detach(tp->dev);
return 0;
}
@@ -5403,7 +5525,9 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp)
static int rtl_alloc_irq(struct rtl8169_private *tp)
{
+ struct pci_dev *pdev = tp->pci_dev;
unsigned int flags;
+ int nvecs = 1;
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
@@ -5419,7 +5543,15 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
break;
}
- return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags);
+ nvecs = pci_alloc_irq_vectors(pdev, tp->min_irq_nvecs, tp->max_irq_nvecs, flags);
+
+ if (nvecs < 0)
+ nvecs = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+
+ tp->irq = pdev->irq;
+ tp->irq_nvecs = 1;
+
+ return nvecs;
}
static void rtl_read_mac_address(struct rtl8169_private *tp,
@@ -5614,6 +5746,18 @@ static void rtl_hw_initialize(struct rtl8169_private *tp)
}
}
+static int rtl8169_set_real_num_queue(struct rtl8169_private *tp)
+{
+ int retval;
+
+ retval = netif_set_real_num_tx_queues(tp->dev, tp->num_tx_rings);
+ if (retval < 0)
+ return retval;
+
+ retval = netif_set_real_num_rx_queues(tp->dev, tp->num_rx_rings);
+ return retval;
+}
+
static int rtl_jumbo_max(struct rtl8169_private *tp)
{
/* Non-GBit versions don't support jumbo frames */
@@ -5674,6 +5818,20 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp)
return false;
}
+
+static void r8169_init_napi(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->irq_nvecs; i++) {
+ struct rtl8169_napi *r8169napi = &tp->r8169napi[i];
+ int (*poll)(struct napi_struct *napi, int budget);
+
+ poll = rtl8169_poll;
+ netif_napi_add(tp->dev, &r8169napi->napi, poll);
+ r8169napi->priv = tp;
+ r8169napi->index = i;
+ }
+}
+
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct rtl_chip_info *chip;
@@ -5778,11 +5936,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl_hw_reset(tp);
+ rtl_software_parameter_initialize(tp);
+
rc = rtl_alloc_irq(tp);
if (rc < 0)
return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n");
- tp->irq = pci_irq_vector(pdev, 0);
INIT_WORK(&tp->wk.work, rtl_task);
disable_work(&tp->wk.work);
@@ -5791,7 +5950,13 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->ethtool_ops = &rtl8169_ethtool_ops;
- netif_napi_add(dev, &tp->napi, rtl8169_poll);
+ if (!tp->rss_support) {
+ netif_napi_add(dev, &tp->r8169napi[0].napi, rtl8169_poll);
+ tp->r8169napi[0].priv = tp;
+ tp->r8169napi[0].index = 0;
+ } else {
+ r8169_init_napi(tp);
+ }
dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
@@ -5853,6 +6018,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (jumbo_max)
dev->max_mtu = jumbo_max;
+ rc = rtl8169_set_real_num_queue(tp);
+ if (rc < 0)
+ return dev_err_probe(&pdev->dev, rc, "set tx/rx num failure\n");
+
rtl_set_irq_mask(tp);
tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters),
--
2.43.0
^ permalink raw reply related
* [RFC Patch net-next v1 4/9] r8169: add support for multi rx queues
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch supports for multi rx queues. But we set rx queue num 1 here.
We will add support for rx queue num 8 in rss patch.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 272 +++++++++++++++++-----
1 file changed, 212 insertions(+), 60 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 05f0cb532a31..52e690eba644 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -73,7 +73,6 @@
#define R8169_RX_BUF_SIZE (SZ_16K - 1)
#define NUM_TX_DESC 256 /* Number of Tx descriptor registers */
#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
-#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
#define R8169_TX_STOP_THRS (MAX_SKB_FRAGS + 1)
#define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS)
#define R8169_MAX_RX_QUEUES 8
@@ -793,6 +792,19 @@ enum rtl_dash_type {
RTL_DASH_25_BP,
};
+struct rtl8169_rx_ring {
+ u32 index; /* Rx queue index */
+ u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
+ u32 dirty_rx; /* Index into the Rx descriptor buffer for recycling. */
+ u32 num_rx_desc; /* num of Rx desc */
+ struct RxDesc *RxDescArray; /* array of Rx Desc*/
+ u32 RxDescAllocSize; /* memory size per descs of ring */
+ dma_addr_t RxDescPhyAddr[NUM_RX_DESC]; /* Rx data buffer physical dma address */
+ dma_addr_t RxPhyAddr; /* Rx desc physical address */
+ struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
+ u16 rdsar_reg; /* Receive Descriptor Start Address */
+};
+
struct rtl8169_tx_ring {
u32 index; /* Tx queue index */
u32 cur_tx; /* Index into the Tx descriptor buffer of next Tx pkt. */
@@ -833,12 +845,9 @@ struct rtl8169_private {
struct napi_struct napi;
enum mac_version mac_version;
enum rtl_dash_type dash_type;
- u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
- struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
- dma_addr_t RxPhyAddr;
- struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
struct rtl8169_irq irq_tbl[R8169_MAX_MSIX_VEC];
struct rtl8169_napi r8169napi[R8169_MAX_MSIX_VEC];
+ struct rtl8169_rx_ring rx_ring[R8169_MAX_RX_QUEUES];
struct rtl8169_tx_ring tx_ring[R8169_MAX_TX_QUEUES];
u16 isr_reg[R8169_MAX_MSIX_VEC];
u16 imr_reg[R8169_MAX_MSIX_VEC];
@@ -848,11 +857,13 @@ struct rtl8169_private {
u16 tx_lpi_timer;
u32 irq_mask;
u16 HwSuppNumTxQueues;
+ u16 HwSuppNumRxQueues;
u8 min_irq_nvecs;
u8 max_irq_nvecs;
u8 HwSuppIsrVer;
u8 HwCurrIsrVer;
u8 irq_nvecs;
+ u8 InitRxDescType;
u8 recheck_desc_ownbit;
unsigned int features;
int irq;
@@ -2728,6 +2739,15 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
}
}
+static void rtl8169_rx_desc_init(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ memset(ring->RxDescArray, 0x0, ring->RxDescAllocSize);
+ }
+}
+
static void rtl8169_tx_desc_init(struct rtl8169_private *tp)
{
for (int i = 0; i < tp->num_tx_rings; i++) {
@@ -2750,6 +2770,14 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
ring->index = i;
netdev_tx_reset_queue(netdev_get_tx_queue(dev, i));
}
+
+ for (int i = 0; i < tp->HwSuppNumRxQueues; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ ring->dirty_rx = 0;
+ ring->cur_rx = 0;
+ ring->index = i;
+ }
}
static void rtl_jumbo_config(struct rtl8169_private *tp)
@@ -2810,6 +2838,9 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
static void rtl_set_ring_size(struct rtl8169_private *tp, u32 rx_num, u32 tx_num)
{
+ for (int i = 0; i < tp->HwSuppNumRxQueues; i++)
+ tp->rx_ring[i].num_rx_desc = rx_num;
+
for (int i = 0; i < tp->HwSuppNumTxQueues; i++)
tp->tx_ring[i].num_tx_desc = tx_num;
}
@@ -2820,6 +2851,10 @@ static void rtl_setup_mqs_reg(struct rtl8169_private *tp)
for (int i = 1; i < tp->HwSuppNumTxQueues; i++)
tp->tx_ring[i].tdsar_reg = (u16)(TNPDS_Q1_LOW + (i - 1) * 8);
+ tp->rx_ring[0].rdsar_reg = RxDescAddrLow;
+ for (int i = 1; i < tp->HwSuppNumRxQueues; i++)
+ tp->rx_ring[i].rdsar_reg = (u16)(RDSAR_Q1_LOW + (i - 1) * 8);
+
if (tp->mac_version <= RTL_GIGA_MAC_VER_52) {
tp->isr_reg[0] = IntrStatus;
tp->imr_reg[0] = IntrMask;
@@ -2845,15 +2880,18 @@ static void rtl_software_parameter_initialize(struct rtl8169_private *tp)
tp->min_irq_nvecs = R8127_MIN_IRQ;
tp->max_irq_nvecs = R8127_MAX_IRQ;
tp->HwSuppNumTxQueues = R8127_MAX_TX_QUEUES;
+ tp->HwSuppNumRxQueues = R8127_MAX_RX_QUEUES;
tp->HwSuppIsrVer = 6;
break;
default:
tp->min_irq_nvecs = 1;
tp->max_irq_nvecs = 1;
tp->HwSuppNumTxQueues = 1;
+ tp->HwSuppNumRxQueues = 1;
tp->HwSuppIsrVer = 1;
break;
}
+ tp->InitRxDescType = RX_DESC_RING_TYPE_DEAFULT;
tp->HwCurrIsrVer = tp->HwSuppIsrVer;
rtl_setup_mqs_reg(tp);
@@ -2989,14 +3027,18 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
* register to be written before TxDescAddrLow to work.
* Switching from MMIO to I/O access fixes the issue as well.
*/
- RTL_W32(tp, RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
- RTL_W32(tp, RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
for (int i = 0; i < tp->num_tx_rings; i++) {
struct rtl8169_tx_ring *ring = &tp->tx_ring[i];
RTL_W32(tp, ring->tdsar_reg, ((u64)ring->TxPhyAddr & DMA_BIT_MASK(32)));
RTL_W32(tp, ring->tdsar_reg + 4, ((u64)ring->TxPhyAddr >> 32));
}
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ RTL_W32(tp, ring->rdsar_reg, ((u64)ring->RxPhyAddr) & DMA_BIT_MASK(32));
+ RTL_W32(tp, ring->rdsar_reg + 4, ((u64)ring->RxPhyAddr >> 32));
+ }
}
static void rtl8169_set_magic_reg(struct rtl8169_private *tp)
@@ -4332,7 +4374,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static void rtl8169_mark_to_asic(struct RxDesc *desc)
+static void rtl8169_mark_to_asic_default(struct RxDesc *desc)
{
u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
@@ -4342,13 +4384,19 @@ static void rtl8169_mark_to_asic(struct RxDesc *desc)
WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
}
+static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc *desc)
+{
+ rtl8169_mark_to_asic_default(desc);
+}
+
static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
- struct RxDesc *desc)
+ struct rtl8169_rx_ring *ring, unsigned int index)
{
struct device *d = tp_to_dev(tp);
int node = dev_to_node(d);
dma_addr_t mapping;
struct page *data;
+ struct RxDesc *desc = ring->RxDescArray + index;
data = alloc_pages_node(node, GFP_KERNEL, get_order(R8169_RX_BUF_SIZE));
if (!data)
@@ -4361,44 +4409,56 @@ static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
return NULL;
}
+ ring->RxDescPhyAddr[index] = mapping;
desc->addr = cpu_to_le64(mapping);
- rtl8169_mark_to_asic(desc);
+ rtl8169_mark_to_asic(tp, desc);
return data;
}
-static void rtl8169_rx_clear(struct rtl8169_private *tp)
+static void rtl8169_rx_clear(struct rtl8169_private *tp, struct rtl8169_rx_ring *ring)
{
int i;
- for (i = 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) {
+ for (i = 0; i < NUM_RX_DESC && ring->Rx_databuff[i]; i++) {
dma_unmap_page(tp_to_dev(tp),
- le64_to_cpu(tp->RxDescArray[i].addr),
+ ring->RxDescPhyAddr[i],
R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
- __free_pages(tp->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
- tp->Rx_databuff[i] = NULL;
- tp->RxDescArray[i].addr = 0;
- tp->RxDescArray[i].opts1 = 0;
+ __free_pages(ring->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
+ ring->Rx_databuff[i] = NULL;
+ ring->RxDescPhyAddr[i] = 0;
+ ring->RxDescArray[i].addr = 0;
+ ring->RxDescArray[i].opts1 = 0;
}
}
-static int rtl8169_rx_fill(struct rtl8169_private *tp)
+static void rtl8169_mark_as_last_descriptor_default(struct RxDesc *desc)
+{
+ desc->opts1 |= cpu_to_le32(RingEnd);
+}
+
+static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, struct RxDesc *desc)
+{
+ rtl8169_mark_as_last_descriptor_default(desc);
+}
+
+static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_ring *ring)
{
int i;
for (i = 0; i < NUM_RX_DESC; i++) {
struct page *data;
- data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
+ data = rtl8169_alloc_rx_data(tp, ring, i);
if (!data) {
- rtl8169_rx_clear(tp);
+ rtl8169_rx_clear(tp, ring);
return -ENOMEM;
}
- tp->Rx_databuff[i] = data;
+ ring->Rx_databuff[i] = data;
}
/* mark as last descriptor in the ring */
- tp->RxDescArray[NUM_RX_DESC - 1].opts1 |= cpu_to_le32(RingEnd);
+ rtl8169_mark_as_last_descriptor(tp, &ring->RxDescArray[NUM_RX_DESC - 1]);
return 0;
}
@@ -4438,6 +4498,40 @@ static void rtl8169_free_tx_desc(struct rtl8169_private *tp)
}
}
+static int rtl8169_alloc_rx_desc(struct rtl8169_private *tp)
+{
+ struct rtl8169_rx_ring *ring;
+ struct pci_dev *pdev = tp->pci_dev;
+
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ ring = &tp->rx_ring[i];
+ ring->RxDescAllocSize = (ring->num_rx_desc + 1) * sizeof(struct RxDesc);
+ ring->RxDescArray = dma_alloc_coherent(&pdev->dev,
+ ring->RxDescAllocSize,
+ &ring->RxPhyAddr,
+ GFP_KERNEL);
+ if (!ring->RxDescArray)
+ return -1;
+ }
+ return 0;
+}
+
+static void rtl8169_free_rx_desc(struct rtl8169_private *tp)
+{
+ struct rtl8169_rx_ring *ring;
+ struct pci_dev *pdev = tp->pci_dev;
+
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ ring = &tp->rx_ring[i];
+ if (ring->RxDescArray) {
+ dma_free_coherent(&pdev->dev,
+ ring->RxDescAllocSize,
+ ring->RxDescArray,
+ ring->RxPhyAddr);
+ ring->RxDescArray = NULL;
+ }
+ }
+}
static int rtl8169_init_ring(struct rtl8169_private *tp)
{
@@ -4445,6 +4539,7 @@ static int rtl8169_init_ring(struct rtl8169_private *tp)
rtl8169_init_ring_indexes(tp);
rtl8169_tx_desc_init(tp);
+ rtl8169_rx_desc_init(tp);
for (int i = 0; i < tp->num_tx_rings; i++) {
struct rtl8169_tx_ring *ring = &tp->tx_ring[i];
@@ -4452,9 +4547,14 @@ static int rtl8169_init_ring(struct rtl8169_private *tp)
memset(ring->tx_skb, 0x0, sizeof(ring->tx_skb));
}
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+ memset(ring->Rx_databuff, 0, sizeof(ring->Rx_databuff));
+ retval = rtl8169_rx_fill(tp, ring);
+ }
- return rtl8169_rx_fill(tp);
+ return retval;
}
static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp,
@@ -4549,16 +4649,23 @@ static void rtl8169_cleanup(struct rtl8169_private *tp)
rtl8169_init_ring_indexes(tp);
}
-static void rtl_reset_work(struct rtl8169_private *tp)
+static void rtl8169_rx_desc_reset(struct rtl8169_private *tp)
{
- int i;
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ for (int j = 0; j < ring->num_rx_desc; j++)
+ rtl8169_mark_to_asic(tp, ring->RxDescArray + j);
+ }
+}
+static void rtl_reset_work(struct rtl8169_private *tp)
+{
netif_stop_queue(tp->dev);
rtl8169_cleanup(tp);
- for (i = 0; i < NUM_RX_DESC; i++)
- rtl8169_mark_to_asic(tp->RxDescArray + i);
+ rtl8169_rx_desc_reset(tp);
rtl8169_napi_enable(tp);
@@ -5033,9 +5140,11 @@ static inline int rtl8169_fragmented_frame(u32 status)
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
}
-static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
+static inline void rtl8169_rx_csum_default(struct rtl8169_private *tp,
+ struct sk_buff *skb,
+ struct RxDesc *desc)
{
- u32 status = opts1 & (RxProtoMask | RxCSFailMask);
+ u32 status = le32_to_cpu(desc->opts1) & (RxProtoMask | RxCSFailMask);
if (status == RxProtoTCP || status == RxProtoUDP)
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -5043,22 +5152,67 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
skb_checksum_none_assert(skb);
}
-static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget)
+static inline void rtl8169_rx_csum(struct rtl8169_private *tp,
+ struct sk_buff *skb,
+ struct RxDesc *desc)
+{
+ rtl8169_rx_csum_default(tp, skb, desc);
+}
+
+static u32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxDesc *desc)
+{
+ return READ_ONCE(desc->opts1);
+}
+
+static int rtl8169_check_rx_desc_error(struct net_device *dev,
+ struct rtl8169_private *tp,
+ u32 status)
+{
+ int ret = 0;
+
+ if (unlikely(status & RxRES)) {
+ if (status & (RxRWT | RxRUNT))
+ dev->stats.rx_length_errors++;
+ if (status & RxCRC)
+ dev->stats.rx_crc_errors++;
+ ret = -1;
+ }
+ return ret;
+}
+
+static inline void rtl8169_set_desc_dma_addr(struct rtl8169_private *tp,
+ struct RxDesc *desc,
+ dma_addr_t mapping)
+{
+ desc->addr = cpu_to_le64(mapping);
+}
+
+static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
+ struct rtl8169_rx_ring *ring, int budget)
{
struct device *d = tp_to_dev(tp);
int count;
- for (count = 0; count < budget; count++, tp->cur_rx++) {
- unsigned int pkt_size, entry = tp->cur_rx % NUM_RX_DESC;
- struct RxDesc *desc = tp->RxDescArray + entry;
+ for (count = 0; count < budget; count++, ring->cur_rx++) {
+ unsigned int pkt_size, entry = ring->cur_rx % ring->num_rx_desc;
+ struct RxDesc *desc = ring->RxDescArray + entry;
struct sk_buff *skb;
const void *rx_buf;
dma_addr_t addr;
u32 status;
- status = le32_to_cpu(READ_ONCE(desc->opts1));
- if (status & DescOwn)
- break;
+ status = le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc));
+
+ if (status & DescOwn) {
+ if (!tp->recheck_desc_ownbit)
+ break;
+
+ tp->recheck_desc_ownbit = false;
+ rtl8169_desc_quirk(tp);
+ status = le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc));
+ if (status & DescOwn)
+ break;
+ }
/* This barrier is needed to keep us from reading
* any other fields out of the Rx descriptor until
@@ -5066,20 +5220,15 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
*/
dma_rmb();
- if (unlikely(status & RxRES)) {
+ if (rtl8169_check_rx_desc_error(dev, tp, status) < 0) {
if (net_ratelimit())
netdev_warn(dev, "Rx ERROR. status = %08x\n",
status);
+
dev->stats.rx_errors++;
- if (status & (RxRWT | RxRUNT))
- dev->stats.rx_length_errors++;
- if (status & RxCRC)
- dev->stats.rx_crc_errors++;
if (!(dev->features & NETIF_F_RXALL))
goto release_descriptor;
- else if (status & RxRWT || !(status & (RxRUNT | RxCRC)))
- goto release_descriptor;
}
pkt_size = status & GENMASK(13, 0);
@@ -5095,14 +5244,14 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
goto release_descriptor;
}
- skb = napi_alloc_skb(&tp->r8169napi[0].napi, pkt_size);
+ skb = napi_alloc_skb(&tp->r8169napi[ring->index].napi, pkt_size);
if (unlikely(!skb)) {
dev->stats.rx_dropped++;
goto release_descriptor;
}
- addr = le64_to_cpu(desc->addr);
- rx_buf = page_address(tp->Rx_databuff[entry]);
+ addr = ring->RxDescPhyAddr[entry];
+ rx_buf = page_address(ring->Rx_databuff[entry]);
dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
prefetch(rx_buf);
@@ -5111,7 +5260,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
skb->len = pkt_size;
dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
- rtl8169_rx_csum(skb, status);
+ rtl8169_rx_csum(tp, skb, desc);
skb->protocol = eth_type_trans(skb, dev);
rtl8169_rx_vlan_tag(desc, skb);
@@ -5119,11 +5268,13 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
if (skb->pkt_type == PACKET_MULTICAST)
dev->stats.multicast++;
- napi_gro_receive(&tp->r8169napi[0].napi, skb);
+ napi_gro_receive(&tp->r8169napi[ring->index].napi, skb);
dev_sw_netstats_rx_add(dev, pkt_size);
release_descriptor:
- rtl8169_mark_to_asic(desc);
+ rtl8169_set_desc_dma_addr(tp, desc, ring->RxDescPhyAddr[entry]);
+ dma_wmb();
+ rtl8169_mark_to_asic(tp, desc);
}
return count;
@@ -5239,7 +5390,8 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
for (int i = 0; i < tp->num_tx_rings; i++)
rtl_tx(dev, tp, &tp->tx_ring[i], budget);
- work_done = rtl_rx(dev, tp, budget);
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ work_done += rtl_rx(dev, tp, &tp->rx_ring[i], budget);
if (work_done < budget && napi_complete_done(napi, work_done))
rtl_irq_enable(tp);
@@ -5371,16 +5523,16 @@ static int rtl8169_close(struct net_device *dev)
netif_stop_queue(dev);
rtl8169_down(tp);
- rtl8169_rx_clear(tp);
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
rtl8169_free_irq(tp);
phy_disconnect(tp->phydev);
- dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
- tp->RxPhyAddr);
- tp->RxDescArray = NULL;
+ rtl8169_free_rx_desc(tp);
+
rtl8169_free_tx_desc(tp);
pm_runtime_put_sync(&pdev->dev);
@@ -5411,11 +5563,12 @@ static int rtl_open(struct net_device *dev)
* dma_alloc_coherent provides more.
*/
- tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
- &tp->RxPhyAddr, GFP_KERNEL);
if (rtl8169_alloc_tx_desc(tp) < 0)
goto err_free_tx_0;
+ if (rtl8169_alloc_rx_desc(tp) < 0)
+ goto err_free_rx_1;
+
retval = rtl8169_init_ring(tp);
if (retval < 0)
goto err_free_rx_1;
@@ -5444,11 +5597,10 @@ static int rtl_open(struct net_device *dev)
rtl8169_free_irq(tp);
err_release_fw_2:
rtl_release_firmware(tp);
- rtl8169_rx_clear(tp);
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
err_free_rx_1:
- dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
- tp->RxPhyAddr);
- tp->RxDescArray = NULL;
+ rtl8169_free_rx_desc(tp);
err_free_tx_0:
rtl8169_free_tx_desc(tp);
goto out;
--
2.43.0
^ permalink raw reply related
* [RFC Patch net-next v1 7/9] r8169: add support and enable rss
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch adds support and enable rss for RTL8127. We remove the
setting nvecs 1 to support multi queue and rss.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 340 ++++++++++++++++++++--
1 file changed, 321 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 622ee8905a05..b3f15e6fd5e9 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -718,6 +718,21 @@ struct RxDesc {
__le64 addr;
};
+struct RxDescRss {
+ union {
+ __le64 addr;
+ struct {
+ __le32 RSSInfo;
+ __le32 RSSResult;
+ } RxDescRSSDWord;
+ };
+
+ struct {
+ __le32 opts2;
+ __le32 opts1;
+ } RxDescOpts;
+};
+
enum features {
RTL_FEATURE_MSI = (1 << 1),
RTL_FEATURE_MSIX = (1 << 2),
@@ -853,9 +868,13 @@ struct rtl8169_private {
u16 imr_reg[R8169_MAX_MSIX_VEC];
unsigned int num_tx_rings;
unsigned int num_rx_rings;
+ u32 rss_flags;
u16 cp_cmd;
u16 tx_lpi_timer;
u32 irq_mask;
+ u8 rss_key[RTL8127_RSS_KEY_SIZE];
+ u8 rss_indir_tbl[RTL8127_MAX_INDIRECTION_TABLE_ENTRIES];
+ u8 HwSuppIndirTblEntries;
u16 HwSuppNumTxQueues;
u16 HwSuppNumRxQueues;
u8 min_irq_nvecs;
@@ -1698,6 +1717,13 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp)
}
}
+static bool rtl_check_rss_support(struct rtl8169_private *tp)
+{
+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
+ return true;
+ return false;
+}
+
static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
@@ -2001,9 +2027,20 @@ static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb)
TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00;
}
-static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
+static void rtl8169_rx_vlan_tag(struct rtl8169_private *tp,
+ struct RxDesc *desc,
+ struct sk_buff *skb)
{
- u32 opts2 = le32_to_cpu(desc->opts2);
+ u32 opts2;
+
+ switch (tp->InitRxDescType) {
+ case RX_DESC_RING_TYPE_RSS:
+ opts2 = le32_to_cpu(((struct RxDescRss *)desc)->RxDescOpts.opts2);
+ break;
+ default:
+ opts2 = le32_to_cpu(desc->opts2);
+ break;
+ }
if (opts2 & RxVlanTag)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff));
@@ -2884,6 +2921,14 @@ static void rtl_setup_mqs_reg(struct rtl8169_private *tp)
tp->imr_reg[i] = (u16)(IntrMask1_8125 + (i - 1) * 4);
}
+static void rtl8169_init_rss(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->HwSuppIndirTblEntries; i++)
+ tp->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
+
+ netdev_rss_key_fill(tp->rss_key, RTL8127_RSS_KEY_SIZE);
+}
+
static void rtl_software_parameter_initialize(struct rtl8169_private *tp)
{
tp->num_rx_rings = 1;
@@ -2895,6 +2940,7 @@ static void rtl_software_parameter_initialize(struct rtl8169_private *tp)
tp->max_irq_nvecs = R8127_MAX_IRQ;
tp->HwSuppNumTxQueues = R8127_MAX_TX_QUEUES;
tp->HwSuppNumRxQueues = R8127_MAX_RX_QUEUES;
+ tp->HwSuppIndirTblEntries = RTL8127_MAX_INDIRECTION_TABLE_ENTRIES;
tp->HwSuppIsrVer = 6;
break;
default:
@@ -2908,10 +2954,6 @@ static void rtl_software_parameter_initialize(struct rtl8169_private *tp)
tp->InitRxDescType = RX_DESC_RING_TYPE_DEAFULT;
tp->HwCurrIsrVer = tp->HwSuppIsrVer;
- /* This just force nvecs, and will be remove in the following patch*/
- tp->min_irq_nvecs = 1;
- tp->max_irq_nvecs = 1;
-
rtl_setup_mqs_reg(tp);
rtl_set_ring_size(tp, NUM_RX_DESC, NUM_TX_DESC);
}
@@ -3038,6 +3080,76 @@ static void rtl_set_rx_max_size(struct rtl8169_private *tp)
RTL_W16(tp, RxMaxSize, R8169_RX_BUF_SIZE + 1);
}
+static void rtl8169_store_rss_key(struct rtl8169_private *tp)
+{
+ const u16 rss_key_reg = RSS_KEY_8125;
+ u32 i, rss_key_size = sizeof(tp->rss_key);
+ u32 *rss_key = (u32 *)tp->rss_key;
+
+ /* Write redirection table to HW */
+ for (i = 0; i < rss_key_size; i += 4)
+ RTL_W32(tp, rss_key_reg + i, *rss_key++);
+}
+
+static void rtl8169_store_reta(struct rtl8169_private *tp)
+{
+ u16 indir_tbl_reg = RSS_INDIRECTION_TBL_8125_V2;
+ u32 i, reta_entries = tp->HwSuppIndirTblEntries;
+ u32 reta = 0;
+ u8 *indir_tbl = tp->rss_indir_tbl;
+
+ /* Write redirection table to HW */
+ for (i = 0; i < reta_entries; i++) {
+ reta |= indir_tbl[i] << (i & 0x3) * 8;
+ if ((i & 3) == 3) {
+ RTL_W32(tp, indir_tbl_reg, reta);
+ indir_tbl_reg += 4;
+ reta = 0;
+ }
+ }
+}
+
+static int rtl8169_set_rss_hash_opt(struct rtl8169_private *tp)
+{
+ u32 rss_flags = tp->rss_flags;
+ u32 hash_mask_len;
+ u32 rss_ctrl;
+
+ rss_ctrl = ilog2(tp->num_rx_rings);
+ rss_ctrl &= (BIT(0) | BIT(1) | BIT(2));
+ rss_ctrl <<= RSS_CPU_NUM_OFFSET;
+
+ /* Perform hash on these packet types */
+ rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
+ | RSS_CTRL_IPV4_SUPP
+ | RSS_CTRL_IPV6_SUPP
+ | RSS_CTRL_IPV6_EXT_SUPP
+ | RSS_CTRL_TCP_IPV6_SUPP
+ | RSS_CTRL_TCP_IPV6_EXT_SUPP;
+
+ if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
+ rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP;
+
+ if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
+ rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP |
+ RSS_CTRL_UDP_IPV6_EXT_SUPP;
+
+ hash_mask_len = ilog2(tp->HwSuppIndirTblEntries);
+ hash_mask_len &= (BIT(0) | BIT(1) | BIT(2));
+ rss_ctrl |= hash_mask_len << RSS_MASK_BITS_OFFSET;
+
+ RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
+
+ return 0;
+}
+
+static void rtl_set_rss_config(struct rtl8169_private *tp)
+{
+ rtl8169_set_rss_hash_opt(tp);
+ rtl8169_store_reta(tp);
+ rtl8169_store_rss_key(tp);
+}
+
static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
{
/*
@@ -4102,6 +4214,29 @@ DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond)
return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13);
}
+static void rtl8125_set_tx_q_num(struct rtl8169_private *tp)
+{
+ u16 mac_ocp_data;
+
+ mac_ocp_data = r8168_mac_ocp_read(tp, 0xe63e);
+ mac_ocp_data &= ~(BIT(11) | BIT(10));
+ mac_ocp_data |= ((ilog2(tp->num_tx_rings) & 0x03) << 10);
+ r8168_mac_ocp_write(tp, 0xe63e, mac_ocp_data);
+}
+
+static void rtl8125_set_rx_q_num(struct rtl8169_private *tp)
+{
+ u16 q_ctrl;
+ u16 rx_q_num;
+
+ rx_q_num = (u16)ilog2(tp->num_rx_rings);
+ rx_q_num &= (BIT(0) | BIT(1) | BIT(2));
+ rx_q_num <<= 2;
+ q_ctrl = RTL_R16(tp, Q_NUM_CTRL_8125);
+ q_ctrl &= ~(BIT(2) | BIT(3) | BIT(4));
+ q_ctrl |= rx_q_num;
+ RTL_W16(tp, Q_NUM_CTRL_8125, q_ctrl);
+}
static void rtl8125_hw_set_interrupt_type(struct rtl8169_private *tp)
{
@@ -4142,6 +4277,13 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
tp->mac_version == RTL_GIGA_MAC_VER_80)
RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
+ /* enable rx descriptor type v4 and set queue num for rss*/
+ if (tp->rss_enable) {
+ rtl8125_set_rx_q_num(tp);
+ rtl8125_set_tx_q_num(tp);
+ RTL_W8(tp, 0xd8, RTL_R8(tp, 0xd8) | 0x02);
+ }
+
if (tp->mac_version == RTL_GIGA_MAC_VER_80)
r8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00);
else if (tp->mac_version == RTL_GIGA_MAC_VER_70)
@@ -4378,6 +4520,12 @@ static void rtl_hw_start(struct rtl8169_private *tp)
rtl_hw_aspm_clkreq_enable(tp, true);
rtl_set_rx_max_size(tp);
rtl_set_rx_tx_desc_registers(tp);
+ if (rtl_is_8125(tp)) {
+ if (tp->rss_enable)
+ rtl_set_rss_config(tp);
+ else
+ RTL_W32(tp, RSS_CTRL_8125, 0x00);
+ }
rtl_lock_config_regs(tp);
rtl_jumbo_config(tp);
@@ -4405,6 +4553,16 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+static void rtl8169_mark_to_asic_rss(struct RxDescRss *descrss)
+{
+ u32 eor = le32_to_cpu(descrss->RxDescOpts.opts1) & RingEnd;
+
+ descrss->RxDescOpts.opts2 = 0;
+ /* Force memory writes to complete before releasing descriptor */
+ dma_wmb();
+ WRITE_ONCE(descrss->RxDescOpts.opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
+}
+
static void rtl8169_mark_to_asic_default(struct RxDesc *desc)
{
u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
@@ -4417,7 +4575,14 @@ static void rtl8169_mark_to_asic_default(struct RxDesc *desc)
static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc *desc)
{
- rtl8169_mark_to_asic_default(desc);
+ switch (tp->InitRxDescType) {
+ case RX_DESC_RING_TYPE_RSS:
+ rtl8169_mark_to_asic_rss((struct RxDescRss *)desc);
+ break;
+ default:
+ rtl8169_mark_to_asic_default(desc);
+ break;
+ }
}
static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
@@ -4441,7 +4606,13 @@ static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
}
ring->RxDescPhyAddr[index] = mapping;
- desc->addr = cpu_to_le64(mapping);
+ if (tp->InitRxDescType == RX_DESC_RING_TYPE_RSS) {
+ struct RxDescRss *descrss = (struct RxDescRss *)(ring->RxDescArray) + index;
+
+ descrss->addr = cpu_to_le64(mapping);
+ } else {
+ desc->addr = cpu_to_le64(mapping);
+ }
rtl8169_mark_to_asic(tp, desc);
return data;
@@ -4468,9 +4639,21 @@ static void rtl8169_mark_as_last_descriptor_default(struct RxDesc *desc)
desc->opts1 |= cpu_to_le32(RingEnd);
}
+static void rtl8169_mark_as_last_descriptor_rss(struct RxDescRss *descrss)
+{
+ descrss->RxDescOpts.opts1 |= cpu_to_le32(RingEnd);
+}
+
static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, struct RxDesc *desc)
{
- rtl8169_mark_as_last_descriptor_default(desc);
+ switch (tp->InitRxDescType) {
+ case RX_DESC_RING_TYPE_RSS:
+ rtl8169_mark_as_last_descriptor_rss((struct RxDescRss *)desc);
+ break;
+ default:
+ rtl8169_mark_as_last_descriptor_default(desc);
+ break;
+ }
}
static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_ring *ring)
@@ -5171,6 +5354,28 @@ static inline int rtl8169_fragmented_frame(u32 status)
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
}
+static inline void rtl8169_rx_hash(struct rtl8169_private *tp,
+ struct RxDescRss *desc,
+ struct sk_buff *skb)
+{
+ u32 rss_header_info;
+ u32 hash_val;
+
+ if (!(tp->dev->features & NETIF_F_RXHASH))
+ return;
+
+ rss_header_info = le32_to_cpu(desc->RxDescRSSDWord.RSSInfo);
+
+ if (!(rss_header_info & RTL8127_RXS_RSS_L3_TYPE_MASK_V4))
+ return;
+
+ hash_val = le32_to_cpu(desc->RxDescRSSDWord.RSSResult);
+
+ skb_set_hash(skb, hash_val,
+ (RTL8127_RXS_RSS_L4_TYPE_MASK_V4 & rss_header_info) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
+}
+
static inline void rtl8169_rx_csum_default(struct rtl8169_private *tp,
struct sk_buff *skb,
struct RxDesc *desc)
@@ -5183,16 +5388,41 @@ static inline void rtl8169_rx_csum_default(struct rtl8169_private *tp,
skb_checksum_none_assert(skb);
}
+static inline void rtl8169_rx_csum_rss(struct rtl8169_private *tp,
+ struct sk_buff *skb,
+ struct RxDescRss *descrss)
+{
+ u32 opts1 = le32_to_cpu(descrss->RxDescOpts.opts1);
+
+ if (((opts1 & RxTCPT_v4) && !(opts1 & RxTCPF_v4)) ||
+ ((opts1 & RxUDPT_v4) && !(opts1 & RxUDPF_v4)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb_checksum_none_assert(skb);
+}
+
static inline void rtl8169_rx_csum(struct rtl8169_private *tp,
struct sk_buff *skb,
struct RxDesc *desc)
{
- rtl8169_rx_csum_default(tp, skb, desc);
+ switch (tp->InitRxDescType) {
+ case RX_DESC_RING_TYPE_RSS:
+ rtl8169_rx_csum_rss(tp, skb, (struct RxDescRss *)desc);
+ break;
+ default:
+ rtl8169_rx_csum_default(tp, skb, desc);
+ break;
+ }
}
static u32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxDesc *desc)
{
- return READ_ONCE(desc->opts1);
+ switch (tp->InitRxDescType) {
+ case RX_DESC_RING_TYPE_RSS:
+ return READ_ONCE(((struct RxDescRss *)desc)->RxDescOpts.opts1);
+ default:
+ return READ_ONCE(desc->opts1);
+ }
}
static int rtl8169_check_rx_desc_error(struct net_device *dev,
@@ -5201,12 +5431,25 @@ static int rtl8169_check_rx_desc_error(struct net_device *dev,
{
int ret = 0;
- if (unlikely(status & RxRES)) {
- if (status & (RxRWT | RxRUNT))
- dev->stats.rx_length_errors++;
- if (status & RxCRC)
- dev->stats.rx_crc_errors++;
- ret = -1;
+ switch (tp->InitRxDescType) {
+ case RX_DESC_RING_TYPE_RSS:
+ if (unlikely(status & RxRES_RSS)) {
+ if (status & RxRUNT_RSS)
+ dev->stats.rx_length_errors++;
+ if (status & RxCRC_RSS)
+ dev->stats.rx_crc_errors++;
+ ret = -1;
+ }
+ break;
+ default:
+ if (unlikely(status & RxRES)) {
+ if (status & (RxRWT | RxRUNT))
+ dev->stats.rx_length_errors++;
+ if (status & RxCRC)
+ dev->stats.rx_crc_errors++;
+ ret = -1;
+ }
+ break;
}
return ret;
}
@@ -5215,7 +5458,14 @@ static inline void rtl8169_set_desc_dma_addr(struct rtl8169_private *tp,
struct RxDesc *desc,
dma_addr_t mapping)
{
- desc->addr = cpu_to_le64(mapping);
+ switch (tp->InitRxDescType) {
+ case RX_DESC_RING_TYPE_RSS:
+ ((struct RxDescRss *)desc)->addr = cpu_to_le64(mapping);
+ break;
+ default:
+ desc->addr = cpu_to_le64(mapping);
+ break;
+ }
}
static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
@@ -5291,10 +5541,13 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
skb->len = pkt_size;
dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
+ if (tp->rss_enable)
+ rtl8169_rx_hash(tp, (struct RxDescRss *)desc, skb);
+
rtl8169_rx_csum(tp, skb, desc);
skb->protocol = eth_type_trans(skb, dev);
- rtl8169_rx_vlan_tag(desc, skb);
+ rtl8169_rx_vlan_tag(tp, desc, skb);
if (skb->pkt_type == PACKET_MULTICAST)
dev->stats.multicast++;
@@ -5873,6 +6126,45 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp)
}
}
+static void rtl8169_double_check_rss_support(struct rtl8169_private *tp)
+{
+ if (tp->HwCurrIsrVer > 1) {
+ if (!(tp->features & RTL_FEATURE_MSIX) || tp->irq_nvecs < tp->min_irq_nvecs)
+ tp->HwCurrIsrVer = 1;
+ }
+
+ if (tp->rss_support && tp->HwCurrIsrVer > 1) {
+ u8 rss_queue_num = netif_get_num_default_rss_queues();
+
+ tp->num_rx_rings = min(rss_queue_num, tp->HwSuppNumRxQueues);
+ if (!(tp->num_rx_rings >= 2 && tp->irq_nvecs >= tp->min_irq_nvecs))
+ tp->num_rx_rings = 1;
+ }
+
+ if (tp->num_rx_rings >= 2) {
+ tp->rss_enable = 1;
+ tp->InitRxDescType = RX_DESC_RING_TYPE_RSS;
+ } else {
+ tp->rss_enable = 0;
+ if (tp->irq_nvecs > 1) {
+ pci_free_irq_vectors(tp->pci_dev);
+
+ tp->irq_nvecs = pci_alloc_irq_vectors(tp->pci_dev, 1, 1, PCI_IRQ_ALL_TYPES);
+
+ if (tp->irq_nvecs > 0) {
+ tp->irq = pci_irq_vector(tp->pci_dev, 0);
+ } else {
+ tp->irq = tp->pci_dev->irq;
+ tp->irq_nvecs = 1;
+ }
+
+ tp->features &= ~RTL_FEATURE_MSIX;
+ if (pci_dev_msi_enabled(tp->pci_dev))
+ tp->features |= RTL_FEATURE_MSI;
+ }
+ }
+}
+
static int rtl_alloc_irq(struct rtl8169_private *tp)
{
struct pci_dev *pdev = tp->pci_dev;
@@ -6346,6 +6638,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->dash_type = rtl_get_dash_type(tp);
tp->dash_enabled = rtl_dash_is_enabled(tp);
+ tp->rss_support = rtl_check_rss_support(tp);
tp->cp_cmd = RTL_R16(tp, CPlusCmd) & CPCMD_MASK;
@@ -6367,6 +6660,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc < 0)
return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n");
+ rtl8169_double_check_rss_support(tp);
+
+ if (tp->rss_support)
+ rtl8169_init_rss(tp);
INIT_WORK(&tp->wk.work, rtl_task);
disable_work(&tp->wk.work);
@@ -6388,6 +6685,11 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+ if (tp->rss_support) {
+ dev->hw_features |= NETIF_F_RXHASH;
+ dev->features |= NETIF_F_RXHASH;
+ }
+
/*
* Pretend we are using VLANs; This bypasses a nasty bug where
* Interrupts stop flowing on high load on 8110SCd controllers.
--
2.43.0
^ permalink raw reply related
* [RFC Patch net-next v1 3/9] r8169: add support for multi tx queues
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch support for multi tx queues. But we still use one tx queue
here. More support will be available in rss support patch.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 278 ++++++++++++++++------
1 file changed, 199 insertions(+), 79 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index d1f3a208bd1b..05f0cb532a31 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -73,7 +73,6 @@
#define R8169_RX_BUF_SIZE (SZ_16K - 1)
#define NUM_TX_DESC 256 /* Number of Tx descriptor registers */
#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
-#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
#define R8169_TX_STOP_THRS (MAX_SKB_FRAGS + 1)
#define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS)
@@ -794,6 +793,18 @@ enum rtl_dash_type {
RTL_DASH_25_BP,
};
+struct rtl8169_tx_ring {
+ u32 index; /* Tx queue index */
+ u32 cur_tx; /* Index into the Tx descriptor buffer of next Tx pkt. */
+ u32 dirty_tx; /* Index into the Tx descriptor buffer for recycling. */
+ u32 num_tx_desc; /* num of Tx desc */
+ struct TxDesc *TxDescArray; /* array of Rx Desc*/
+ u32 TxDescAllocSize; /* memory size per descs of ring */
+ dma_addr_t TxPhyAddr; /* Tx desc physical address */
+ struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
+ u16 tdsar_reg; /* Transmit Descriptor Start Address */
+};
+
struct rtl8169_napi {
struct napi_struct napi;
void *priv;
@@ -823,16 +834,12 @@ struct rtl8169_private {
enum mac_version mac_version;
enum rtl_dash_type dash_type;
u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
- u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
- u32 dirty_tx;
- struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */
struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
- dma_addr_t TxPhyAddr;
dma_addr_t RxPhyAddr;
struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
- struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
struct rtl8169_irq irq_tbl[R8169_MAX_MSIX_VEC];
struct rtl8169_napi r8169napi[R8169_MAX_MSIX_VEC];
+ struct rtl8169_tx_ring tx_ring[R8169_MAX_TX_QUEUES];
u16 isr_reg[R8169_MAX_MSIX_VEC];
u16 imr_reg[R8169_MAX_MSIX_VEC];
unsigned int num_tx_rings;
@@ -840,11 +847,14 @@ struct rtl8169_private {
u16 cp_cmd;
u16 tx_lpi_timer;
u32 irq_mask;
+ u16 HwSuppNumTxQueues;
u8 min_irq_nvecs;
u8 max_irq_nvecs;
u8 HwSuppIsrVer;
u8 HwCurrIsrVer;
u8 irq_nvecs;
+ u8 recheck_desc_ownbit;
+ unsigned int features;
int irq;
struct clk *clk;
@@ -2718,9 +2728,28 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
}
}
+static void rtl8169_tx_desc_init(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->num_tx_rings; i++) {
+ struct rtl8169_tx_ring *ring = &tp->tx_ring[i];
+
+ memset(ring->TxDescArray, 0x0, ring->TxDescAllocSize);
+ ring->TxDescArray[ring->num_tx_desc - 1].opts1 = cpu_to_le32(RingEnd);
+ }
+}
+
static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
{
- tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
+ struct net_device *dev = tp->dev;
+
+ for (int i = 0; i < tp->HwSuppNumTxQueues; i++) {
+ struct rtl8169_tx_ring *ring = &tp->tx_ring[i];
+
+ ring->dirty_tx = 0;
+ ring->cur_tx = 0;
+ ring->index = i;
+ netdev_tx_reset_queue(netdev_get_tx_queue(dev, i));
+ }
}
static void rtl_jumbo_config(struct rtl8169_private *tp)
@@ -2779,8 +2808,18 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
}
+static void rtl_set_ring_size(struct rtl8169_private *tp, u32 rx_num, u32 tx_num)
+{
+ for (int i = 0; i < tp->HwSuppNumTxQueues; i++)
+ tp->tx_ring[i].num_tx_desc = tx_num;
+}
+
static void rtl_setup_mqs_reg(struct rtl8169_private *tp)
{
+ tp->tx_ring[0].tdsar_reg = TxDescStartAddrLow;
+ for (int i = 1; i < tp->HwSuppNumTxQueues; i++)
+ tp->tx_ring[i].tdsar_reg = (u16)(TNPDS_Q1_LOW + (i - 1) * 8);
+
if (tp->mac_version <= RTL_GIGA_MAC_VER_52) {
tp->isr_reg[0] = IntrStatus;
tp->imr_reg[0] = IntrMask;
@@ -2805,17 +2844,20 @@ static void rtl_software_parameter_initialize(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_80:
tp->min_irq_nvecs = R8127_MIN_IRQ;
tp->max_irq_nvecs = R8127_MAX_IRQ;
+ tp->HwSuppNumTxQueues = R8127_MAX_TX_QUEUES;
tp->HwSuppIsrVer = 6;
break;
default:
tp->min_irq_nvecs = 1;
tp->max_irq_nvecs = 1;
+ tp->HwSuppNumTxQueues = 1;
tp->HwSuppIsrVer = 1;
break;
}
tp->HwCurrIsrVer = tp->HwSuppIsrVer;
rtl_setup_mqs_reg(tp);
+ rtl_set_ring_size(tp, NUM_RX_DESC, NUM_TX_DESC);
}
static void rtl_request_firmware(struct rtl8169_private *tp)
@@ -2947,10 +2989,14 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
* register to be written before TxDescAddrLow to work.
* Switching from MMIO to I/O access fixes the issue as well.
*/
- RTL_W32(tp, TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
- RTL_W32(tp, TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
RTL_W32(tp, RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
RTL_W32(tp, RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
+ for (int i = 0; i < tp->num_tx_rings; i++) {
+ struct rtl8169_tx_ring *ring = &tp->tx_ring[i];
+
+ RTL_W32(tp, ring->tdsar_reg, ((u64)ring->TxPhyAddr & DMA_BIT_MASK(32)));
+ RTL_W32(tp, ring->tdsar_reg + 4, ((u64)ring->TxPhyAddr >> 32));
+ }
}
static void rtl8169_set_magic_reg(struct rtl8169_private *tp)
@@ -4357,43 +4403,85 @@ static int rtl8169_rx_fill(struct rtl8169_private *tp)
return 0;
}
+static int rtl8169_alloc_tx_desc(struct rtl8169_private *tp)
+{
+ struct rtl8169_tx_ring *ring;
+ struct pci_dev *pdev = tp->pci_dev;
+
+ for (int i = 0; i < tp->num_tx_rings; i++) {
+ ring = &tp->tx_ring[i];
+ ring->TxDescAllocSize = (ring->num_tx_desc + 1) * sizeof(struct TxDesc);
+ ring->TxDescArray = dma_alloc_coherent(&pdev->dev,
+ ring->TxDescAllocSize,
+ &ring->TxPhyAddr,
+ GFP_KERNEL);
+ if (!ring->TxDescArray)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void rtl8169_free_tx_desc(struct rtl8169_private *tp)
+{
+ struct rtl8169_tx_ring *ring;
+ struct pci_dev *pdev = tp->pci_dev;
+
+ for (int i = 0; i < tp->num_tx_rings; i++) {
+ ring = &tp->tx_ring[i];
+ if (ring->TxDescArray) {
+ dma_free_coherent(&pdev->dev,
+ ring->TxDescAllocSize,
+ ring->TxDescArray,
+ ring->TxPhyAddr);
+ ring->TxDescArray = NULL;
+ }
+ }
+}
+
static int rtl8169_init_ring(struct rtl8169_private *tp)
{
+ int retval = 0;
+
rtl8169_init_ring_indexes(tp);
+ rtl8169_tx_desc_init(tp);
+
+ for (int i = 0; i < tp->num_tx_rings; i++) {
+ struct rtl8169_tx_ring *ring = &tp->tx_ring[i];
+
+ memset(ring->tx_skb, 0x0, sizeof(ring->tx_skb));
+ }
+
- memset(tp->tx_skb, 0, sizeof(tp->tx_skb));
- memset(tp->Rx_databuff, 0, sizeof(tp->Rx_databuff));
return rtl8169_rx_fill(tp);
}
-static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int entry)
+static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp,
+ struct ring_info *tx_skb,
+ struct TxDesc *desc)
{
- struct ring_info *tx_skb = tp->tx_skb + entry;
- struct TxDesc *desc = tp->TxDescArray + entry;
+ dma_unmap_single(tp_to_dev(tp), le64_to_cpu(desc->addr), tx_skb->len, DMA_TO_DEVICE);
- dma_unmap_single(tp_to_dev(tp), le64_to_cpu(desc->addr), tx_skb->len,
- DMA_TO_DEVICE);
memset(desc, 0, sizeof(*desc));
memset(tx_skb, 0, sizeof(*tx_skb));
}
-static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
- unsigned int n)
+static void rtl8169_tx_clear_range(struct rtl8169_private *tp, struct rtl8169_tx_ring *ring,
+ u32 start, unsigned int n)
{
unsigned int i;
for (i = 0; i < n; i++) {
- unsigned int entry = (start + i) % NUM_TX_DESC;
- struct ring_info *tx_skb = tp->tx_skb + entry;
+ unsigned int entry = (start + i) % ring->num_tx_desc;
+ struct ring_info *tx_skb = ring->tx_skb + entry;
unsigned int len = tx_skb->len;
if (len) {
struct sk_buff *skb = tx_skb->skb;
- rtl8169_unmap_tx_skb(tp, entry);
+ rtl8169_unmap_tx_skb(tp, tx_skb, ring->TxDescArray + entry);
if (skb)
dev_consume_skb_any(skb);
}
@@ -4402,7 +4490,13 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
static void rtl8169_tx_clear(struct rtl8169_private *tp)
{
- rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
+ for (int i = 0; i < tp->num_tx_rings; i++) {
+ struct rtl8169_tx_ring *ring = &tp->tx_ring[i];
+
+ rtl8169_tx_clear_range(tp, ring, ring->dirty_tx, ring->num_tx_desc);
+ ring->cur_tx = 0;
+ ring->dirty_tx = 0;
+ }
netdev_reset_queue(tp->dev);
}
@@ -4478,10 +4572,15 @@ static void rtl8169_tx_timeout(struct net_device *dev, unsigned int txqueue)
rtl_schedule_task(tp, RTL_FLAG_TASK_TX_TIMEOUT);
}
-static int rtl8169_tx_map(struct rtl8169_private *tp, const u32 *opts, u32 len,
- void *addr, unsigned int entry, bool desc_own)
+static int rtl8169_tx_map(struct rtl8169_private *tp,
+ struct rtl8169_tx_ring *ring,
+ const u32 *opts,
+ u32 len,
+ void *addr,
+ unsigned int entry,
+ bool desc_own)
{
- struct TxDesc *txd = tp->TxDescArray + entry;
+ struct TxDesc *txd = ring->TxDescArray + entry;
struct device *d = tp_to_dev(tp);
dma_addr_t mapping;
u32 opts1;
@@ -4505,13 +4604,16 @@ static int rtl8169_tx_map(struct rtl8169_private *tp, const u32 *opts, u32 len,
opts1 |= DescOwn;
txd->opts1 = cpu_to_le32(opts1);
- tp->tx_skb[entry].len = len;
+ ring->tx_skb[entry].len = len;
return 0;
}
-static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
- const u32 *opts, unsigned int entry)
+static int rtl8169_xmit_frags(struct rtl8169_private *tp,
+ struct rtl8169_tx_ring *ring,
+ struct sk_buff *skb,
+ const u32 *opts,
+ unsigned int entry)
{
struct skb_shared_info *info = skb_shinfo(skb);
unsigned int cur_frag;
@@ -4523,14 +4625,14 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
entry = (entry + 1) % NUM_TX_DESC;
- if (unlikely(rtl8169_tx_map(tp, opts, len, addr, entry, true)))
+ if (unlikely(rtl8169_tx_map(tp, ring, opts, len, addr, entry, true)))
goto err_out;
}
return 0;
err_out:
- rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
+ rtl8169_tx_clear_range(tp, ring, ring->cur_tx + 1, cur_frag);
return -EIO;
}
@@ -4684,9 +4786,9 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
return true;
}
-static unsigned int rtl_tx_slots_avail(struct rtl8169_private *tp)
+static unsigned int rtl_tx_slots_avail(struct rtl8169_tx_ring *ring)
{
- return READ_ONCE(tp->dirty_tx) + NUM_TX_DESC - READ_ONCE(tp->cur_tx);
+ return READ_ONCE(ring->dirty_tx) + NUM_TX_DESC - READ_ONCE(ring->cur_tx);
}
/* Versions RTL8102e and from RTL8168c onwards support csum_v2 */
@@ -4701,10 +4803,10 @@ static bool rtl_chip_supports_csum_v2(struct rtl8169_private *tp)
}
}
-static void rtl8169_doorbell(struct rtl8169_private *tp)
+static void rtl8169_doorbell(struct rtl8169_private *tp, struct rtl8169_tx_ring *ring)
{
if (rtl_is_8125(tp))
- RTL_W16(tp, TxPoll_8125, BIT(0));
+ RTL_W16(tp, TxPoll_8125, BIT(ring->index));
else
RTL_W8(tp, TxPoll, NPQ);
}
@@ -4713,16 +4815,18 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- unsigned int entry = tp->cur_tx % NUM_TX_DESC;
struct TxDesc *txd_first, *txd_last;
bool stop_queue, door_bell;
unsigned int frags;
u32 opts[2];
+ const u16 queue_mapping = skb_get_queue_mapping(skb);
+ struct rtl8169_tx_ring *ring = &tp->tx_ring[queue_mapping];
+ unsigned int entry = ring->cur_tx % ring->num_tx_desc;
- if (unlikely(!rtl_tx_slots_avail(tp))) {
+ if (unlikely(!rtl_tx_slots_avail(ring))) {
if (net_ratelimit())
netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
- netif_stop_queue(dev);
+ netif_stop_subqueue(dev, queue_mapping);
return NETDEV_TX_BUSY;
}
@@ -4734,47 +4838,49 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
else if (!rtl8169_tso_csum_v2(tp, skb, opts))
goto err_dma_0;
- if (unlikely(rtl8169_tx_map(tp, opts, skb_headlen(skb), skb->data,
+ if (unlikely(rtl8169_tx_map(tp, ring, opts, skb_headlen(skb), skb->data,
entry, false)))
goto err_dma_0;
- txd_first = tp->TxDescArray + entry;
+ txd_first = ring->TxDescArray + entry;
frags = skb_shinfo(skb)->nr_frags;
if (frags) {
- if (rtl8169_xmit_frags(tp, skb, opts, entry))
+ if (rtl8169_xmit_frags(tp, ring, skb, opts, entry))
goto err_dma_1;
entry = (entry + frags) % NUM_TX_DESC;
}
- txd_last = tp->TxDescArray + entry;
+ txd_last = ring->TxDescArray + entry;
txd_last->opts1 |= cpu_to_le32(LastFrag);
- tp->tx_skb[entry].skb = skb;
+ ring->tx_skb[entry].skb = skb;
skb_tx_timestamp(skb);
/* Force memory writes to complete before releasing descriptor */
dma_wmb();
- door_bell = __netdev_sent_queue(dev, skb->len, netdev_xmit_more());
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_mapping);
+
+ door_bell = __netdev_tx_sent_queue(txq, skb->len, netdev_xmit_more());
txd_first->opts1 |= cpu_to_le32(DescOwn | FirstFrag);
/* rtl_tx needs to see descriptor changes before updated tp->cur_tx */
smp_wmb();
- WRITE_ONCE(tp->cur_tx, tp->cur_tx + frags + 1);
+ WRITE_ONCE(ring->cur_tx, ring->cur_tx + frags + 1);
- stop_queue = !netif_subqueue_maybe_stop(dev, 0, rtl_tx_slots_avail(tp),
+ stop_queue = !netif_subqueue_maybe_stop(dev, 0, rtl_tx_slots_avail(ring),
R8169_TX_STOP_THRS,
R8169_TX_START_THRS);
if (door_bell || stop_queue)
- rtl8169_doorbell(tp);
+ rtl8169_doorbell(tp, ring);
return NETDEV_TX_OK;
err_dma_1:
- rtl8169_unmap_tx_skb(tp, entry);
+ rtl8169_unmap_tx_skb(tp, ring->tx_skb + entry, txd_first);
err_dma_0:
dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
@@ -4859,24 +4965,38 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
}
-static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
- int budget)
+static void rtl8169_desc_quirk(struct rtl8169_private *tp)
+{
+ RTL_R8(tp, tp->imr_reg[0]);
+}
+
+static int rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
+ struct rtl8169_tx_ring *ring, int budget)
{
unsigned int dirty_tx, bytes_compl = 0, pkts_compl = 0;
struct sk_buff *skb;
+ u32 status;
+ unsigned int count = 0;
+
+ dirty_tx = ring->dirty_tx;
+
+ while (READ_ONCE(ring->cur_tx) != dirty_tx) {
+ unsigned int entry = dirty_tx % ring->num_tx_desc;
+ struct ring_info *tx_skb = ring->tx_skb + entry;
+
+ status = le32_to_cpu(READ_ONCE(ring->TxDescArray[entry].opts1));
+ if (status & DescOwn) {
+ if (!tp->recheck_desc_ownbit)
+ break;
+ tp->recheck_desc_ownbit = false;
+ rtl8169_desc_quirk(tp);
+ status = le32_to_cpu(READ_ONCE(ring->TxDescArray[entry].opts1));
+ if (status & DescOwn)
+ break;
+ }
- dirty_tx = tp->dirty_tx;
-
- while (READ_ONCE(tp->cur_tx) != dirty_tx) {
- unsigned int entry = dirty_tx % NUM_TX_DESC;
- u32 status;
-
- status = le32_to_cpu(READ_ONCE(tp->TxDescArray[entry].opts1));
- if (status & DescOwn)
- break;
-
- skb = tp->tx_skb[entry].skb;
- rtl8169_unmap_tx_skb(tp, entry);
+ skb = tx_skb->skb;
+ rtl8169_unmap_tx_skb(tp, tx_skb, ring->TxDescArray + entry);
if (skb) {
pkts_compl++;
@@ -4886,12 +5006,13 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
dirty_tx++;
}
- if (tp->dirty_tx != dirty_tx) {
+ if (ring->dirty_tx != dirty_tx) {
+ count = dirty_tx - ring->dirty_tx;
dev_sw_netstats_tx_add(dev, pkts_compl, bytes_compl);
- WRITE_ONCE(tp->dirty_tx, dirty_tx);
+ WRITE_ONCE(ring->dirty_tx, dirty_tx);
netif_subqueue_completed_wake(dev, 0, pkts_compl, bytes_compl,
- rtl_tx_slots_avail(tp),
+ rtl_tx_slots_avail(ring),
R8169_TX_START_THRS);
/*
* 8168 hack: TxPoll requests are lost when the Tx packets are
@@ -4901,9 +5022,10 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
* If skb is NULL then we come here again once a tx irq is
* triggered after the last fragment is marked transmitted.
*/
- if (READ_ONCE(tp->cur_tx) != dirty_tx && skb)
- rtl8169_doorbell(tp);
+ if (READ_ONCE(ring->cur_tx) != dirty_tx && skb)
+ rtl8169_doorbell(tp, ring);
}
+ return count;
}
static inline int rtl8169_fragmented_frame(u32 status)
@@ -5027,6 +5149,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
phy_mac_interrupt(tp->phydev);
rtl_irq_disable(tp);
+ tp->recheck_desc_ownbit = true;
napi_schedule(&napi->napi);
out:
rtl_ack_events(tp, status);
@@ -5113,7 +5236,8 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
struct net_device *dev = tp->dev;
int work_done = 0;
- rtl_tx(dev, tp, budget);
+ for (int i = 0; i < tp->num_tx_rings; i++)
+ rtl_tx(dev, tp, &tp->tx_ring[i], budget);
work_done = rtl_rx(dev, tp, budget);
@@ -5256,10 +5380,8 @@ static int rtl8169_close(struct net_device *dev)
dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
tp->RxPhyAddr);
- dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
- tp->TxPhyAddr);
- tp->TxDescArray = NULL;
tp->RxDescArray = NULL;
+ rtl8169_free_tx_desc(tp);
pm_runtime_put_sync(&pdev->dev);
@@ -5288,20 +5410,17 @@ static int rtl_open(struct net_device *dev)
* Rx and Tx descriptors needs 256 bytes alignment.
* dma_alloc_coherent provides more.
*/
- tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
- &tp->TxPhyAddr, GFP_KERNEL);
- if (!tp->TxDescArray)
- goto out;
tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
&tp->RxPhyAddr, GFP_KERNEL);
- if (!tp->RxDescArray)
+ if (rtl8169_alloc_tx_desc(tp) < 0)
goto err_free_tx_0;
retval = rtl8169_init_ring(tp);
if (retval < 0)
goto err_free_rx_1;
+
rtl_request_firmware(tp);
irqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED;
@@ -5331,9 +5450,7 @@ static int rtl_open(struct net_device *dev)
tp->RxPhyAddr);
tp->RxDescArray = NULL;
err_free_tx_0:
- dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
- tp->TxPhyAddr);
- tp->TxDescArray = NULL;
+ rtl8169_free_tx_desc(tp);
goto out;
}
@@ -5842,7 +5959,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
u32 txconfig;
u32 xid;
- dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp));
+ dev = devm_alloc_etherdev_mqs(&pdev->dev, sizeof(*tp),
+ R8169_MAX_TX_QUEUES,
+ R8169_MAX_RX_QUEUES);
+
if (!dev)
return -ENOMEM;
--
2.43.0
^ permalink raw reply related
* [RFC Patch net-next v1 6/9] r8169: enable msix for RTL8127
From: javen @ 2026-04-20 2:19 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260420021957.1756-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch enables msix for RTL8127.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
drivers/net/ethernet/realtek/r8169_main.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 7d493342ab4b..622ee8905a05 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -4102,6 +4102,16 @@ DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond)
return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13);
}
+
+static void rtl8125_hw_set_interrupt_type(struct rtl8169_private *tp)
+{
+ u8 tmp;
+
+ tmp = RTL_R8(tp, INT_CFG0_8125);
+ tmp |= INT_CFG0_ENABLE_8125;
+ RTL_W8(tp, INT_CFG0_8125, tmp);
+}
+
static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
{
rtl_pcie_state_l2l3_disable(tp);
@@ -4110,6 +4120,9 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
RTL_W32(tp, RSS_CTRL_8125, 0);
RTL_W16(tp, Q_NUM_CTRL_8125, 0);
+ if (tp->features & RTL_FEATURE_MSIX)
+ rtl8125_hw_set_interrupt_type(tp);
+
/* disable UPS */
r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2] net: dsa: realtek: rtl8365mb: fix mode mask calculation
From: Luiz Angelo Daros de Luca @ 2026-04-20 2:24 UTC (permalink / raw)
To: Mieczyslaw Nalewaj, Alvin Šipraga; +Cc: netdev@vger.kernel.org
In-Reply-To: <400a6387-a444-4576-af6d-26be5410bce3@yahoo.com>
> The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting
> the 4-bit mask (0xF) by only (_extint % 2) bits instead of
> (_extint % 2) * 4. This caused the mask to overlap with the adjacent
> nibble when configuring odd-numbered external interfaces, selecting
> the wrong bits entirely.
>
> Align the shift calculation with the existing ...MODE_OFFSET macro.
>
> Fixes: 4af2950c50c8 ("net: dsa: realtek-smi: add rtl8365mb subdriver for RTL8365MB-VC")
> Signed-off-by: Abdulkader Alrezej <alrazj.abdulkader@gmail.com>
> Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
> Reviewed-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
This bug specifically affected ext1 (Port 6) for all digital interface
modes except DISABLED (0x0) and RGMII (0x1).
The error caused the mask for ext1 to overlap with the adjacent nibble
of ext0. Since ext0 is currently unused by all supported devices in
this family, the incorrect mask was zeroing bits that were already
expected to be zero, masking the failure.
However, for ext1, the incorrect shift left the effective mask with
only a single bit (bit 4) instead of the full 4-bit nibble (bits 4-7).
This meant the driver could only successfully write values 0x0 or 0x1.
Any mode requiring bits [7:5] (such as MII, RMII, or HSGMII) would
have been effectively written as 0x0 or 0x1, breaking those
configurations.
The original chip for this driver, RTL8365MB-VC, does utilize ext1,
but as the driver currently only implements RGMII mode, the hardware
result remained coincidentally correct:
Before patch: (0x0001 << 4) & 0x001E = 0x0010
After patch: (0x0001 << 4) & 0x00F0 = 0x0010
Tests on my device, TP-Link Archer C5v4, show no problem before and no
regressions, as ext1/port6 is not connected on that specific hardware.
Backporting note: There is no strict need to backport this fix to
stable trees, as only the RGMII mode was actually implemented and it
happened to work despite the logical error.
Regards,
Luiz
^ permalink raw reply
* Re: [RFC PATCH 2/2] kernel/module: Decouple klp and ftrace from load_module
From: Masami Hiramatsu @ 2026-04-20 2:27 UTC (permalink / raw)
To: Petr Mladek
Cc: Petr Pavlu, Song Chen, rafael, lenb, mturquette, sboyd,
viresh.kumar, agk, snitzer, mpatocka, bmarzins, song, yukuai,
linan122, jason.wessel, danielt, dianders, horms, davem, edumazet,
kuba, pabeni, paulmck, frederic, mcgrof, da.gomez, samitolvanen,
atomlin, jpoimboe, jikos, mbenes, joe.lawrence, rostedt, mhiramat,
mark.rutland, mathieu.desnoyers, linux-modules, linux-kernel,
linux-trace-kernel, linux-acpi, linux-clk, linux-pm,
live-patching, dm-devel, linux-raid, kgdb-bugreport, netdev
In-Reply-To: <aeD2_FrFL6E3dbAC@pathway.suse.cz>
On Thu, 16 Apr 2026 16:49:32 +0200
Petr Mladek <pmladek@suse.com> wrote:
> On Thu 2026-04-16 13:18:30, Petr Pavlu wrote:
> > On 4/15/26 8:43 AM, Song Chen wrote:
> > > On 4/14/26 22:33, Petr Pavlu wrote:
> > >> On 4/13/26 10:07 AM, chensong_2000@189.cn wrote:
> > >>> diff --git a/include/linux/module.h b/include/linux/module.h
> > >>> index 14f391b186c6..0bdd56f9defd 100644
> > >>> --- a/include/linux/module.h
> > >>> +++ b/include/linux/module.h
> > >>> @@ -308,6 +308,14 @@ enum module_state {
> > >>> MODULE_STATE_COMING, /* Full formed, running module_init. */
> > >>> MODULE_STATE_GOING, /* Going away. */
> > >>> MODULE_STATE_UNFORMED, /* Still setting it up. */
> > >>> + MODULE_STATE_FORMED,
> > >>
> > >> I don't see a reason to add a new module state. Why is it necessary and
> > >> how does it fit with the existing states?
> > >>
> > > because once notifier fails in state MODULE_STATE_UNFORMED (now only ftrace has someting to do in this state), notifier chain will roll back by calling blocking_notifier_call_chain_robust, i'm afraid MODULE_STATE_GOING is going to jeopardise the notifers which don't handle it appropriately, like:
> > >
> > > case MODULE_STATE_COMING:
> > > kmalloc();
> > > case MODULE_STATE_GOING:
> > > kfree();
> >
> > My understanding is that the current module "state machine" operates as
> > follows. Transitions marked with an asterisk (*) are announced via the
> > module notifier.
> >
> > ---> UNFORMED --*> COMING --*> LIVE --*> GOING -.
> > ^ | ^ |
> > | '---------------------* |
> > '---------------------------------------'
> >
> > The new code aims to replace the current ftrace_module_init() call in
> > load_module(). To achieve this, it adds a notification for the UNFORMED
> > state (only when loading a module) and introduces a new FORMED state for
> > rollback. FORMED is purely a fake state because it never appears in
> > module::state. The new structure is as follows:
> >
> > ,--*> (FORMED)
> > |
> > --*> UNFORMED --*> COMING --*> LIVE --*> GOING -.
> > ^ | ^ |
> > | '---------------------* |
> > '---------------------------------------'
> >
> > I'm afraid this is quite complex and inconsistent. Unless it can be kept
> > simple, we would be just replacing one special handling with a different
> > complexity, which is not worth it.
>
> > >>
> > >>> + if (err)
> > >>> + goto ddebug_cleanup;
> > >>> /* Finally it's fully formed, ready to start executing. */
> > >>> err = complete_formation(mod, info);
> > >>> - if (err)
> > >>> + if (err) {
> > >>> + blocking_notifier_call_chain_reverse(&module_notify_list,
> > >>> + MODULE_STATE_FORMED, mod);
> > >>> goto ddebug_cleanup;
> > >>> + }
> > >>> - err = prepare_coming_module(mod);
> > >>> + err = prepare_module_state_transaction(mod,
> > >>> + MODULE_STATE_COMING, MODULE_STATE_GOING);
> > >>> if (err)
> > >>> goto bug_cleanup;
> > >>> @@ -3522,7 +3519,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
> > >>> destroy_params(mod->kp, mod->num_kp);
> > >>> blocking_notifier_call_chain(&module_notify_list,
> > >>> MODULE_STATE_GOING, mod);
> > >>
> > >> My understanding is that all notifier chains for MODULE_STATE_GOING
> > >> should be reversed.
> > > yes, all, from lowest priority notifier to highest.
> > > I will resend patch 1 which was failed due to my proxy setting.
> >
> > What I meant here is that the call:
> >
> > blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, mod);
> >
> > should be replaced with:
> >
> > blocking_notifier_call_chain_reverse(&module_notify_list, MODULE_STATE_GOING, mod);
> >
> > >
> > >>
> > >>> - klp_module_going(mod);
> > >>> bug_cleanup:
> > >>> mod->state = MODULE_STATE_GOING;
> > >>> /* module_bug_cleanup needs module_mutex protection */
> > >>
> > >> The patch removes the klp_module_going() cleanup call in load_module().
> > >> Similarly, the ftrace_release_mod() call under the ddebug_cleanup label
> > >> should be removed and appropriately replaced with a cleanup via
> > >> a notifier.
> > >>
> > > err = prepare_module_state_transaction(mod,
> > > MODULE_STATE_UNFORMED, MODULE_STATE_FORMED);
> > > if (err)
> > > goto ddebug_cleanup;
> > >
> > > ftrace will be cleanup in blocking_notifier_call_chain_robust rolling back.
> > >
> > > err = prepare_module_state_transaction(mod,
> > > MODULE_STATE_COMING, MODULE_STATE_GOING);
> > >
> > > each notifier including ftrace and klp will be cleanup in blocking_notifier_call_chain_robust rolling back.
> > >
> > > if all notifiers are successful in MODULE_STATE_COMING, they all will be clean up in
> > > coming_cleanup:
> > > mod->state = MODULE_STATE_GOING;
> > > destroy_params(mod->kp, mod->num_kp);
> > > blocking_notifier_call_chain(&module_notify_list,
> > > MODULE_STATE_GOING, mod);
> > >
> > > if something wrong underneath.
> >
> > My point is that the patch leaves a call to ftrace_release_mod() in
> > load_module(), which I expected to be handled via a notifier.
>
> I think that I have got it. The ftrace code needs two notifiers when
> the module is being loaded and two when it is going.
>
> This is why Sond added the new state. But I think that we would
> need two new states to call:
>
> + ftrace_module_init() in MODULE_STATE_UNFORMED
> + ftrace_module_enable() in MODULE_STATE_FORMED
>
> and
>
> + ftrace_free_mem() in MODULE_STATE_PRE_GOING
> + ftrace_free_mem() in MODULE_STATE_GOING
>
>
> By using the ascii art:
>
> -*> UNFORMED -*> FORMED -> COMING -*> LIVE -*> PRE_GOING -*> GOING -.
> | | | ^ ^ ^
> | | '----------------' | |
> | '--------------------------------------' |
> '------------------------------------------------------'
>
>
> But I think that this is not worth it.
Agree.
If this needs to be ordered so strictly, why we will use a "single"
module notifier chain for this complex situation?
I think the notifier call chain is just for notice a single signal,
instead of sending several different signals, especially if there is
any dependency among the callbacks.
If notification callbacks need to be ordered, they are currently
sorted by representing priority numerically, but this is quite
fragile for updating. It has to look up other registered priorities
and adjust the order among dependencies each time. For this reason,
this mechanism is not suitable for global ordering. (It's like line
numbers in BASIC.)
It is probably only useful for representing dependencies between
two components maintained by the same maintainer.
I'm against a general-purpose system that makes everything modular.
It unnecessarily complicates things. If there are processes that
require strict ordering, especially processes that must be performed
before each stage as part of the framework, they should be called
directly from the framework, not via notification callbacks.
This makes it simpler and more robust to maintain.
Only the framework's end users should utilize notification callbacks.
Thank you,
>
> Best Regards,
> Petr
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* [PATCH v1] net: liquidio: resolve VF pci_dev on demand for FLR requests
From: Yuho Choi @ 2026-04-20 2:33 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni, netdev
Cc: Andrew Lunn, Eric Dumazet, Kory Maincent, Vadim Fedorenko,
Marco Crivellari, linux-kernel, Myeonghun Pak, Ijae Kim,
Taegyu Kim, Yuho Choi
The PF SR-IOV enable path caches VF pci_dev pointers in
dpiring_to_vfpcidev_lut[] by iterating with pci_get_device(). Those
entries do not own a reference, because the iterator drops the previous
device reference on each step. The cached pointer is then dereferenced
later when handling OCTEON_VF_FLR_REQUEST.
This can leave stale VF pci_dev pointers in the lookup table and makes
the FLR path rely on a PCI device object whose lifetime is not pinned.
Drop the long-lived lookup table and resolve the VF pci_dev only when an
FLR request arrives. Use the PF's SR-IOV metadata to derive the VF's
bus/devfn, get a referenced pci_dev for immediate use, issue the FLR,
and then drop the reference.
Fixes: ca6139ffc67ee ("liquidio CN23XX: sysfs VF config support")
Fixes: 8c978d059224 ("liquidio CN23XX: Mailbox support")
Co-developed-by: Myeonghun Pak <mhun512@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Co-developed-by: Taegyu Kim <tmk5904@psu.edu>
Signed-off-by: Taegyu Kim <tmk5904@psu.edu>
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
---
.../net/ethernet/cavium/liquidio/lio_main.c | 27 ----------------
.../ethernet/cavium/liquidio/octeon_device.h | 3 --
.../ethernet/cavium/liquidio/octeon_mailbox.c | 31 ++++++++++++++++++-
3 files changed, 30 insertions(+), 31 deletions(-)
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index c1a3df2252549..32dd9b25760e3 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -3781,9 +3781,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
static int octeon_enable_sriov(struct octeon_device *oct)
{
unsigned int num_vfs_alloced = oct->sriov_info.num_vfs_alloced;
- struct pci_dev *vfdev;
int err;
- u32 u;
if (OCTEON_CN23XX_PF(oct) && num_vfs_alloced) {
err = pci_enable_sriov(oct->pci_dev,
@@ -3796,23 +3794,6 @@ static int octeon_enable_sriov(struct octeon_device *oct)
return err;
}
oct->sriov_info.sriov_enabled = 1;
-
- /* init lookup table that maps DPI ring number to VF pci_dev
- * struct pointer
- */
- u = 0;
- vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
- OCTEON_CN23XX_VF_VID, NULL);
- while (vfdev) {
- if (vfdev->is_virtfn &&
- (vfdev->physfn == oct->pci_dev)) {
- oct->sriov_info.dpiring_to_vfpcidev_lut[u] =
- vfdev;
- u += oct->sriov_info.rings_per_vf;
- }
- vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
- OCTEON_CN23XX_VF_VID, vfdev);
- }
}
return num_vfs_alloced;
@@ -3820,8 +3801,6 @@ static int octeon_enable_sriov(struct octeon_device *oct)
static int lio_pci_sriov_disable(struct octeon_device *oct)
{
- int u;
-
if (pci_vfs_assigned(oct->pci_dev)) {
dev_err(&oct->pci_dev->dev, "VFs are still assigned to VMs.\n");
return -EPERM;
@@ -3829,12 +3808,6 @@ static int lio_pci_sriov_disable(struct octeon_device *oct)
pci_disable_sriov(oct->pci_dev);
- u = 0;
- while (u < MAX_POSSIBLE_VFS) {
- oct->sriov_info.dpiring_to_vfpcidev_lut[u] = NULL;
- u += oct->sriov_info.rings_per_vf;
- }
-
oct->sriov_info.num_vfs_alloced = 0;
dev_info(&oct->pci_dev->dev, "oct->pf_num:%d disabled VFs\n",
oct->pf_num);
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
index 19344b21f8fb9..858a0fff2cc0b 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
@@ -390,9 +390,6 @@ struct octeon_sriov_info {
struct lio_trusted_vf trusted_vf;
- /*lookup table that maps DPI ring number to VF pci_dev struct pointer*/
- struct pci_dev *dpiring_to_vfpcidev_lut[MAX_POSSIBLE_VFS];
-
u64 vf_macaddr[MAX_POSSIBLE_VFS];
u16 vf_vlantci[MAX_POSSIBLE_VFS];
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
index ad685f5d0a136..b967c7928b4a7 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
@@ -26,6 +26,29 @@
#include "octeon_mailbox.h"
#include "cn23xx_pf_device.h"
+static struct pci_dev *lio_vf_pci_dev_by_qno(struct octeon_device *oct, u32 q_no)
+{
+ int vfidx, bus, devfn;
+
+ if (!oct->sriov_info.rings_per_vf)
+ return NULL;
+
+ if (q_no % oct->sriov_info.rings_per_vf)
+ return NULL;
+
+ vfidx = q_no / oct->sriov_info.rings_per_vf;
+ if (vfidx >= oct->sriov_info.num_vfs_alloced)
+ return NULL;
+
+ bus = pci_iov_virtfn_bus(oct->pci_dev, vfidx);
+ devfn = pci_iov_virtfn_devfn(oct->pci_dev, vfidx);
+ if (bus < 0 || devfn < 0)
+ return NULL;
+
+ return pci_get_domain_bus_and_slot(pci_domain_nr(oct->pci_dev->bus),
+ bus, devfn);
+}
+
/**
* octeon_mbox_read:
* @mbox: Pointer mailbox
@@ -237,6 +260,7 @@ static int octeon_mbox_process_cmd(struct octeon_mbox *mbox,
struct octeon_mbox_cmd *mbox_cmd)
{
struct octeon_device *oct = mbox->oct_dev;
+ struct pci_dev *vfdev;
switch (mbox_cmd->msg.s.cmd) {
case OCTEON_VF_ACTIVE:
@@ -260,7 +284,12 @@ static int octeon_mbox_process_cmd(struct octeon_mbox *mbox,
dev_info(&oct->pci_dev->dev,
"got a request for FLR from VF that owns DPI ring %u\n",
mbox->q_no);
- pcie_flr(oct->sriov_info.dpiring_to_vfpcidev_lut[mbox->q_no]);
+ vfdev = lio_vf_pci_dev_by_qno(oct, mbox->q_no);
+ if (!vfdev)
+ break;
+
+ pcie_flr(vfdev);
+ pci_dev_put(vfdev);
break;
case OCTEON_PF_CHANGED_VF_MACADDR:
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH v2 net 0/11] octeontx2-af: npc: cn20k: MCAM fixes
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth
This series tightens Marvell OcteonTX2 AF NPC support for CN20K
silicon around MCAM key typing, optional debugfs setup, defrag
allocation rollback, x2 versus x4 KEX profiles and default-rule
allocation, logical MCAM clear and configuration, default-rule index
bookkeeping and explicit teardown, and NIXLF reserved-slot lookup when
default rules are missing.
Patches 1 through 3 focus on AF error handling: propagate
npc_mcam_idx_2_key_type() failures through cn20k MCAM enable, config,
copy, and read paths; treat cn20k NPC debugfs files as optional so
probe does not fail when debugfs is unavailable; and fix defrag MCAM
allocation rollback so allocation errno is not overwritten by subbank
index resolution.
Patches 4 and 5 align default-rule and flow-install behaviour with the
loaded mkex profile: prefer x4 default entries when the profile is x4,
and reject x4 flow keys when the profile is strictly x2.
Patches 6 through 8 refine cn20k MCAM programming: clear entries by
logical index and resolved key width, fix bank and CFG sequencing in
npc_cn20k_config_mcam_entry(), and read action metadata from the
correct bank in npc_cn20k_read_mcam_entry().
Patches 9 through 11 complete default-rule lifecycle handling:
initialize all default-rule index outputs up front, tear down default
MCAM rules explicitly (coordinated with npc_mcam_free_all_entries()),
and reject USHRT_MAX sentinel indices in npc_get_nixlf_mcam_index()
for cn20k.
Ratheesh Kannoth (11):
octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
octeontx2-af: npc: cn20k: Drop debugfs_create_file() error checks in
init
octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc
rollback
octeontx2-af: npc: cn20k: Make default entries as x4.
octeontx2-af: npc: cn20k: Reject request for x4 entries in x2
profile.
octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width
octeontx2-af: npc: cn20k: Fix bank value.
octeontx2-af: npc: cn20k: Fix MCAM actions read
octeontx2-af: npc: cn20k: Initialize default-rule index outputs up
front
octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on
free
octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
--
v1 -> v2: Addressed simon comments. Added more patch fixes to this series.
https://lore.kernel.org/netdev/20260418162013.GG280379@horms.kernel.org/
2.43.0
^ permalink raw reply
* [PATCH v2 net 04/11] octeontx2-af: npc: cn20k: Make default entries as x4.
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
X4 profile users won't alloc x2 entries. Allocating x2 entries
would cause under utilized subbanks(X2). Avoid this in X4 kex
profile, all allocations will be from x4 subbank.
Fixes: 09d3b7a1403f ("octeontx2-af: npc: cn20k: Allocate default MCAM indexes")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 26 ++++++++--
.../marvell/octeontx2/nic/otx2_flows.c | 48 +++++++++++++------
2 files changed, 56 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 7f897ce0d17d..108998b6d832 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -3592,9 +3592,10 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
struct npc_defrag_node *v,
int cnt, u16 *save)
{
+ u16 new_midx, old_midx, vidx, target_pf;
struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct rvu_npc_mcam_rule *rule, *tmp;
int i, vidx_cnt, rc, sb_off;
- u16 new_midx, old_midx, vidx;
struct npc_subbank *sb;
bool deleted;
u16 pcifunc;
@@ -3713,8 +3714,21 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
mcam->entry2pfvf_map[new_midx] = pcifunc;
/* Counter is not preserved */
mcam->entry2cntr_map[new_midx] = new_midx;
+
+ target_pf = mcam->entry2target_pffunc[old_midx];
+ mcam->entry2target_pffunc[new_midx] = target_pf;
+ mcam->entry2target_pffunc[old_midx] = 0;
+
npc_mcam_set_bit(mcam, new_midx);
+ list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
+ if (rule->entry != old_midx)
+ continue;
+
+ rule->entry = new_midx;
+ break;
+ }
+
/* Mark as invalid */
v->vidx[vidx_cnt - i - 1] = -1;
save[cnt - i - 1] = -1;
@@ -4277,10 +4291,16 @@ int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc)
pfvf = rvu_get_pfvf(rvu, pcifunc);
pfvf->hw_prio = NPC_DFT_RULE_PRIO;
+ if (npc_priv.kw == NPC_MCAM_KEY_X4) {
+ req.kw_type = NPC_MCAM_KEY_X4;
+ req.ref_entry = eidx & (npc_priv.bank_depth - 1);
+ } else {
+ req.kw_type = NPC_MCAM_KEY_X2;
+ req.ref_entry = eidx;
+ }
+
req.contig = false;
req.ref_prio = NPC_MCAM_HIGHER_PRIO;
- req.ref_entry = eidx;
- req.kw_type = NPC_MCAM_KEY_X2;
req.count = cnt;
req.hdr.pcifunc = pcifunc;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
index 38cc539d724d..5dd0591fed99 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
@@ -37,14 +37,13 @@ static void otx2_clear_ntuple_flow_info(struct otx2_nic *pfvf, struct otx2_flow_
flow_cfg->max_flows = 0;
}
-static int otx2_mcam_pfl_info_get(struct otx2_nic *pfvf, bool *is_x2,
- u16 *x4_slots)
+static int otx2_mcam_pfl_info_get(struct otx2_nic *pfvf, u16 *x4_slots, u8 *kw_type)
{
struct npc_get_pfl_info_rsp *rsp;
struct msg_req *req;
static struct {
bool is_set;
- bool is_x2;
+ u8 kw_type;
u16 x4_slots;
} pfl_info;
@@ -53,8 +52,8 @@ static int otx2_mcam_pfl_info_get(struct otx2_nic *pfvf, bool *is_x2,
*/
mutex_lock(&pfvf->mbox.lock);
if (pfl_info.is_set) {
- *is_x2 = pfl_info.is_x2;
*x4_slots = pfl_info.x4_slots;
+ *kw_type = pfl_info.kw_type;
mutex_unlock(&pfvf->mbox.lock);
return 0;
}
@@ -79,16 +78,16 @@ static int otx2_mcam_pfl_info_get(struct otx2_nic *pfvf, bool *is_x2,
return -EFAULT;
}
- *is_x2 = (rsp->kw_type == NPC_MCAM_KEY_X2);
- if (*is_x2)
- *x4_slots = 0;
+ pfl_info.kw_type = rsp->kw_type;
+ if (rsp->kw_type == NPC_MCAM_KEY_X2)
+ pfl_info.x4_slots = 0;
else
- *x4_slots = rsp->x4_slots;
-
- pfl_info.is_x2 = *is_x2;
- pfl_info.x4_slots = *x4_slots;
+ pfl_info.x4_slots = rsp->x4_slots;
pfl_info.is_set = true;
+ *x4_slots = pfl_info.x4_slots;
+ *kw_type = pfl_info.kw_type;
+
mutex_unlock(&pfvf->mbox.lock);
return 0;
}
@@ -164,6 +163,7 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
u16 dft_idx = 0, x4_slots = 0;
int ent, allocated = 0, ref;
bool is_x2 = false;
+ u8 kw_type = 0;
int rc;
/* Free current ones and allocate new ones with requested count */
@@ -182,12 +182,14 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
}
if (is_cn20k(pfvf->pdev)) {
- rc = otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots);
+ rc = otx2_mcam_pfl_info_get(pfvf, &x4_slots, &kw_type);
if (rc) {
netdev_err(pfvf->netdev, "Error to retrieve profile info\n");
return rc;
}
+ is_x2 = kw_type == NPC_MCAM_KEY_X2;
+
rc = otx2_get_dft_rl_idx(pfvf, &dft_idx);
if (rc) {
netdev_err(pfvf->netdev,
@@ -289,6 +291,8 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
struct npc_mcam_alloc_entry_rsp *rsp;
int vf_vlan_max_flows, count;
int rc, ref, prio, ent;
+ u8 kw_type = 0;
+ u16 x4_slots;
u16 dft_idx;
ref = 0;
@@ -315,6 +319,16 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
if (!flow_cfg->def_ent)
return -ENOMEM;
+ kw_type = NPC_MCAM_KEY_X2;
+ if (is_cn20k(pfvf->pdev)) {
+ rc = otx2_mcam_pfl_info_get(pfvf, &x4_slots, &kw_type);
+ if (rc) {
+ netdev_err(pfvf->netdev,
+ "Error to get pfl info\n");
+ return rc;
+ }
+ }
+
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&pfvf->mbox);
@@ -324,6 +338,10 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
}
req->kw_type = NPC_MCAM_KEY_X2;
+ if (is_cn20k(pfvf->pdev) && kw_type == NPC_MCAM_KEY_X4) {
+ req->kw_type = NPC_MCAM_KEY_X4;
+ ref &= (x4_slots - 1);
+ }
req->contig = false;
req->count = count;
req->ref_prio = prio;
@@ -1174,15 +1192,14 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
#ifdef CONFIG_DCB
int vlan_prio, qidx, pfc_rule = 0;
#endif
+ bool modify = false, is_x2;
int err, vf = 0, off, sz;
- bool modify = false;
u8 kw_type = 0;
u8 *src, *dst;
u16 x4_slots;
- bool is_x2;
if (is_cn20k(pfvf->pdev)) {
- err = otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots);
+ err = otx2_mcam_pfl_info_get(pfvf, &x4_slots, &kw_type);
if (err) {
netdev_err(pfvf->netdev,
"Error to retrieve NPC profile info, pcifunc=%#x\n",
@@ -1190,6 +1207,7 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
return -EFAULT;
}
+ is_x2 = kw_type == NPC_MCAM_KEY_X2;
if (!is_x2) {
err = otx2_prepare_flow_request(&flow->flow_spec,
&treq);
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 01/11] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth, Suman Ghosh, Dan Carpenter
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
npc_mcam_idx_2_key_type() can fail; callers used to ignore it and still
used kw_type when enabling, configuring, copying, and reading MCAM
entries. That could program or decode hardware with an undefined key
type.
Return -EINVAL when key-type lookup fails. Return -EINVAL from
npc_cn20k_copy_mcam_entry() when src and dest key types differ instead
of failing silently.
Change npc_cn20k_{enable,config,copy,read}_mcam_entry() to return int on
success or error. Thread those errors through the cn20k MCAM write and
read mbox handlers, the cn20k baseline steer read path, NPC defrag
move (disable/copy/enable with dev_err and -EFAULT), and the DMAC
update path in rvu_npc_fs.c.
Make npc_copy_mcam_entry() return int so the cn20k branch can return
npc_cn20k_copy_mcam_entry() without a void/int mismatch, and fail
NPC_MCAM_SHIFT_ENTRY when copy fails.
Cc: Suman Ghosh <sumang@marvell.com>
Cc: Dan Carpenter <error27@gmail.com>
Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
Link: https://lore.kernel.org/netdev/adiQJvuKlEhq2ILx@stanley.mountain/
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 107 ++++++++++++------
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 20 ++--
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 13 ++-
.../marvell/octeontx2/af/rvu_npc_fs.c | 12 +-
4 files changed, 100 insertions(+), 52 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 7291fdb89b03..18d70f4527d1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -798,7 +798,7 @@ void npc_cn20k_load_mkex_profile(struct rvu *rvu, int blkaddr,
iounmap(mkex_prfl_addr);
}
-void
+int
npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
int index, bool enable)
{
@@ -808,7 +808,9 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
u64 cfg, hw_prio;
u8 kw_type;
- npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+ if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+ return -EINVAL;
+
if (kw_type == NPC_MCAM_KEY_X2) {
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
@@ -819,7 +821,7 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
rvu_write64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
cfg);
- return;
+ return 0;
}
/* For NPC_CN20K_MCAM_KEY_X4 keys, both the banks
@@ -836,6 +838,8 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
cfg);
}
+
+ return 0;
}
void
@@ -1042,9 +1046,9 @@ npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx,
}
}
-void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
- u8 intf, struct cn20k_mcam_entry *entry,
- bool enable, u8 hw_prio, u8 req_kw_type)
+int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
+ u8 intf, struct cn20k_mcam_entry *entry,
+ bool enable, u8 hw_prio, u8 req_kw_type)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
int mcam_idx = index % mcam->banksize;
@@ -1052,10 +1056,13 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
int kw = 0;
u8 kw_type;
+ if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+ return -EINVAL;
+
/* Disable before mcam entry update */
- npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false);
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false))
+ return -EINVAL;
- npc_mcam_idx_2_key_type(rvu, index, &kw_type);
/* CAM1 takes the comparison value and
* CAM0 specifies match for a bit in key being '0' or '1' or 'dontcare'.
* CAM1<n> = 0 & CAM0<n> = 1 => match if key<n> = 0
@@ -1120,9 +1127,11 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
/* PF installing VF rule */
npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank,
kw_type, enable, hw_prio);
+
+ return 0;
}
-void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
+int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
u64 cfg, sreg, dreg, soff, doff;
@@ -1132,10 +1141,15 @@ void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
dbank = npc_get_bank(mcam, dest);
sbank = npc_get_bank(mcam, src);
- npc_mcam_idx_2_key_type(rvu, src, &src_kwtype);
- npc_mcam_idx_2_key_type(rvu, dest, &dest_kwtype);
+
+ if (npc_mcam_idx_2_key_type(rvu, src, &src_kwtype))
+ return -EINVAL;
+
+ if (npc_mcam_idx_2_key_type(rvu, dest, &dest_kwtype))
+ return -EINVAL;
+
if (src_kwtype != dest_kwtype)
- return;
+ return -EINVAL;
src &= (mcam->banksize - 1);
dest &= (mcam->banksize - 1);
@@ -1170,6 +1184,8 @@ void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
if (src_kwtype == NPC_MCAM_KEY_X2)
break;
}
+
+ return 0;
}
static void npc_cn20k_fill_entryword(struct cn20k_mcam_entry *entry, int idx,
@@ -1179,16 +1195,17 @@ static void npc_cn20k_fill_entryword(struct cn20k_mcam_entry *entry, int idx,
entry->kw_mask[idx] = cam1 ^ cam0;
}
-void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
- struct cn20k_mcam_entry *entry,
- u8 *intf, u8 *ena, u8 *hw_prio)
+int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
+ struct cn20k_mcam_entry *entry,
+ u8 *intf, u8 *ena, u8 *hw_prio)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
u64 cam0, cam1, bank_cfg, cfg;
int kw = 0, bank;
u8 kw_type;
- npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+ if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+ return -EINVAL;
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
@@ -1298,6 +1315,8 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 1));
entry->vtag_action = cfg;
+
+ return 0;
}
int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
@@ -1335,11 +1354,10 @@ int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
if (is_pffunc_af(req->hdr.pcifunc))
nix_intf = req->intf;
- npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf,
- &req->entry_data, req->enable_entry,
- req->hw_prio, req->req_kw_type);
+ rc = npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf,
+ &req->entry_data, req->enable_entry,
+ req->hw_prio, req->req_kw_type);
- rc = 0;
exit:
mutex_unlock(&mcam->lock);
return rc;
@@ -1361,11 +1379,13 @@ int rvu_mbox_handler_npc_cn20k_mcam_read_entry(struct rvu *rvu,
mutex_lock(&mcam->lock);
rc = npc_mcam_verify_entry(mcam, pcifunc, req->entry);
- if (!rc)
- npc_cn20k_read_mcam_entry(rvu, blkaddr, req->entry,
- &rsp->entry_data, &rsp->intf,
- &rsp->enable, &rsp->hw_prio);
+ if (rc)
+ goto fail;
+ rc = npc_cn20k_read_mcam_entry(rvu, blkaddr, req->entry,
+ &rsp->entry_data, &rsp->intf,
+ &rsp->enable, &rsp->hw_prio);
+fail:
mutex_unlock(&mcam->lock);
return rc;
}
@@ -1415,9 +1435,9 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu,
else
nix_intf = pfvf->nix_rx_intf;
- npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf,
- &req->entry_data, req->enable_entry,
- req->hw_prio, req->req_kw_type);
+ rc = npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf,
+ &req->entry_data, req->enable_entry,
+ req->hw_prio, req->req_kw_type);
mutex_unlock(&mcam->lock);
@@ -1480,9 +1500,9 @@ int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu,
read_entry:
/* Read the mcam entry */
- npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
- &rsp->entry, &intf,
- &enable, &hw_prio);
+ rc = npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
+ &rsp->entry, &intf,
+ &enable, &hw_prio);
mutex_unlock(&mcam->lock);
out:
return rc;
@@ -3607,9 +3627,30 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(midx,
bank));
- npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false);
- npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx);
- npc_cn20k_enable_mcam_entry(rvu, blkaddr, new_midx, true);
+ /* If bug happened during copy/enable mcam, then there is a bug in allocation
+ * algorithm itself. There is no point in rewinding and returning, as it
+ * will face further issue. Return error after printing error
+ */
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false)) {
+ dev_err(rvu->dev,
+ "%s: Error happened while disabling old_mid=%u\n",
+ __func__, old_midx);
+ return -EFAULT;
+ }
+
+ if (npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx)) {
+ dev_err(rvu->dev,
+ "%s: Error happened to while copying old_midx=%u new_midx=%u\n",
+ __func__, old_midx, new_midx);
+ return -EFAULT;
+ }
+
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, new_midx, true)) {
+ dev_err(rvu->dev,
+ "%s: Error happened while enabling new_mid=%u\n",
+ __func__, new_midx);
+ return -EFAULT;
+ }
midx = new_midx % mcam->banksize;
bank = new_midx / mcam->banksize;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 815d0b257a7e..8f3eea9cfb1d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -320,16 +320,16 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc);
int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
u16 *mcast, u16 *promisc, u16 *ucast);
-void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
- u8 intf, struct cn20k_mcam_entry *entry,
- bool enable, u8 hw_prio, u8 req_kw_type);
-void npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
- int index, bool enable);
-void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
- u16 src, u16 dest);
-void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
- struct cn20k_mcam_entry *entry, u8 *intf,
- u8 *ena, u8 *hw_prio);
+int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
+ u8 intf, struct cn20k_mcam_entry *entry,
+ bool enable, u8 hw_prio, u8 req_kw_type);
+int npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
+ int index, bool enable);
+int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
+ u16 src, u16 dest);
+int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
+ struct cn20k_mcam_entry *entry, u8 *intf,
+ u8 *ena, u8 *hw_prio);
void npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr,
int bank, int index);
int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index c2ca5ed1d028..762fafd4ccb7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -241,7 +241,8 @@ void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
if (index < 0 || index >= mcam->banksize * mcam->banks)
return;
- return npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
+ npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
+ return;
}
index &= (mcam->banksize - 1);
@@ -589,8 +590,8 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
NPC_AF_MCAMEX_BANKX_CFG(src, sbank)) & 1;
}
-static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
- int blkaddr, u16 src, u16 dest)
+static int npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, u16 src, u16 dest)
{
int dbank = npc_get_bank(mcam, dest);
int sbank = npc_get_bank(mcam, src);
@@ -630,6 +631,7 @@ static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
NPC_AF_MCAMEX_BANKX_CFG(src, sbank));
rvu_write64(rvu, blkaddr,
NPC_AF_MCAMEX_BANKX_CFG(dest, dbank), cfg);
+ return 0;
}
u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
@@ -3266,7 +3268,10 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu *rvu,
npc_enable_mcam_entry(rvu, mcam, blkaddr, new_entry, false);
/* Copy rule from old entry to new entry */
- npc_copy_mcam_entry(rvu, mcam, blkaddr, old_entry, new_entry);
+ if (npc_copy_mcam_entry(rvu, mcam, blkaddr, old_entry, new_entry)) {
+ rc = NPC_MCAM_INVALID_REQ;
+ break;
+ }
/* Copy counter mapping, if any */
cntr = mcam->entry2cntr_map[old_entry];
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
index b45798d9fdab..bd1488fe1611 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -1980,13 +1980,15 @@ static int npc_update_dmac_value(struct rvu *rvu, int npcblkaddr,
ether_addr_copy(rule->packet.dmac, pfvf->mac_addr);
- if (is_cn20k(rvu->pdev))
- npc_cn20k_read_mcam_entry(rvu, npcblkaddr, rule->entry,
- cn20k_entry, &intf,
- &enable, &hw_prio);
- else
+ if (is_cn20k(rvu->pdev)) {
+ if (npc_cn20k_read_mcam_entry(rvu, npcblkaddr, rule->entry,
+ cn20k_entry, &intf,
+ &enable, &hw_prio))
+ return -EINVAL;
+ } else {
npc_read_mcam_entry(rvu, mcam, npcblkaddr, rule->entry,
entry, &intf, &enable);
+ }
npc_update_entry(rvu, NPC_DMAC, &mdata,
ether_addr_to_u64(pfvf->mac_addr), 0,
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 03/11] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth, Dan Carpenter
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
npc_defrag_alloc_free_slots() allocates MCAM indexes in up to two passes
on bank0 then bank1. On failure it rolls back by freeing entries already
placed in save[].
__npc_subbank_alloc() can return a negative errno while only part of the
indexes are valid. The rollback loop used rc for
npc_mcam_idx_2_subbank_idx() as well, so a successful lookup stored zero
in rc and a later __npc_subbank_free() failure could still end with
return 0 when the allocation path had also left rc at zero
(for example shortfall after zero return values from the alloc helpers).
Jump to the rollback path immediately when either __npc_subbank_alloc()
call fails, preserving its errno. If both calls succeed but the total
allocated count is still less than cnt, set rc to -ENOSPC before rollback.
Use a separate err variable for npc_mcam_idx_2_subbank_idx() so a
successful lookup no longer clears a non-zero rc from the allocation
phase.
Cc: Dan Carpenter <error27@gmail.com>
Fixes: 645c6e3c1999 ("octeontx2-af: npc: cn20k: virtual index support")
Link: https://lore.kernel.org/netdev/adjNJEpILRZATB2N@stanley.mountain/
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../net/ethernet/marvell/octeontx2/af/cn20k/npc.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 18d70f4527d1..7f897ce0d17d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -3502,7 +3502,7 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
{
int alloc_cnt1, alloc_cnt2;
struct npc_subbank *sb;
- int rc, sb_off, i;
+ int rc, sb_off, i, err;
bool deleted;
sb = &npc_priv.sb[f->idx];
@@ -3516,6 +3516,9 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
NPC_MCAM_LOWER_PRIO,
false, cnt, save, cnt, true,
&alloc_cnt1);
+ if (rc)
+ goto fail_free_alloc;
+
if (alloc_cnt1 < cnt) {
rc = __npc_subbank_alloc(rvu, sb,
NPC_MCAM_KEY_X2, sb->b1b,
@@ -3525,21 +3528,25 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
save + alloc_cnt1,
cnt - alloc_cnt1,
true, &alloc_cnt2);
+ if (rc)
+ goto fail_free_alloc;
}
if (alloc_cnt1 + alloc_cnt2 != cnt) {
dev_err(rvu->dev,
"%s: Failed to alloc cnt=%u alloc_cnt1=%u alloc_cnt2=%u\n",
__func__, cnt, alloc_cnt1, alloc_cnt2);
+ rc = -ENOSPC;
goto fail_free_alloc;
}
+
return 0;
fail_free_alloc:
for (i = 0; i < alloc_cnt1 + alloc_cnt2; i++) {
- rc = npc_mcam_idx_2_subbank_idx(rvu, save[i],
- &sb, &sb_off);
- if (rc) {
+ err = npc_mcam_idx_2_subbank_idx(rvu, save[i],
+ &sb, &sb_off);
+ if (err) {
dev_err(rvu->dev,
"%s: Error to find subbank for mcam idx=%u\n",
__func__, save[i]);
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 05/11] octeontx2-af: npc: cn20k: Reject request for x4 entries in x2 profile.
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
Flow install mbox can alloc x2/x4 npc mcam entry based on
the flow entry size. If global kex profile is x2, x4 entries
won't work. Return error upon request for x4 entry in
x2 profile.
Fixes: 9000cada7aa9 ("octeontx2-af: npc: cn20k: Allocate MCAM entry for flow installation")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../net/ethernet/marvell/octeontx2/af/cn20k/npc.c | 10 ++++++++--
.../net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c | 12 +++++++++++-
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 108998b6d832..705fe7a877e6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -4330,11 +4330,17 @@ int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc)
* as NPC_DFT_RULE_PRIO - 1 (higher hw priority)
*/
req.contig = false;
- req.kw_type = NPC_MCAM_KEY_X2;
req.count = cnt;
req.hdr.pcifunc = pcifunc;
req.ref_prio = NPC_MCAM_LOWER_PRIO;
- req.ref_entry = eidx + 1;
+ if (npc_priv.kw == NPC_MCAM_KEY_X4) {
+ req.kw_type = NPC_MCAM_KEY_X4;
+ req.ref_entry = (eidx + 1) & (npc_priv.bank_depth - 1);
+ } else {
+ req.kw_type = NPC_MCAM_KEY_X2;
+ req.ref_entry = eidx + 1;
+ }
+
ret = rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &req, &rsp);
if (ret) {
dev_err(rvu->dev,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
index bd1488fe1611..d8945823e202 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -1663,9 +1663,11 @@ rvu_npc_alloc_entry_for_flow_install(struct rvu *rvu,
{
struct npc_mcam_alloc_entry_req entry_req;
struct npc_mcam_alloc_entry_rsp entry_rsp;
+ struct npc_get_pfl_info_rsp rsp = { 0 };
struct npc_get_num_kws_req kws_req;
struct npc_get_num_kws_rsp kws_rsp;
int off, kw_bits, rc;
+ struct msg_req req;
u8 *src, *dst;
if (!is_cn20k(rvu->pdev)) {
@@ -1689,8 +1691,16 @@ rvu_npc_alloc_entry_for_flow_install(struct rvu *rvu,
kw_bits = kws_rsp.kws * 64;
*kw_type = NPC_MCAM_KEY_X2;
- if (kw_bits > 256)
+ if (kw_bits > 256) {
+ rvu_mbox_handler_npc_get_pfl_info(rvu, &req, &rsp);
+ if (rsp.kw_type == NPC_MCAM_KEY_X2) {
+ dev_err(rvu->dev,
+ "Only X2 entries are supported in X2 profile\n");
+ return -EOPNOTSUPP;
+ }
+
*kw_type = NPC_MCAM_KEY_X4;
+ }
memset(&entry_req, 0, sizeof(entry_req));
memset(&entry_rsp, 0, sizeof(entry_rsp));
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 02/11] octeontx2-af: npc: cn20k: Drop debugfs_create_file() error checks in init
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth, Dan Carpenter, Simon Horman
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
debugfs is not intended to be checked for allocation failures the way
other kernel APIs are: callers should not fail probe or subsystem init
because a debugfs node could not be created, including when debugfs is
disabled in Kconfig. Replacing NULL checks with IS_ERR() checks is
similarly wrong for optional debugfs.
Remove dentry checks and -EFAULT returns from npc_cn20k_debugfs_init().
https://staticthinking.wordpress.com/2023/07/24/debugfs-functions-are-not-supposed-to-be-checked/
Cc: Dan Carpenter <error27@gmail.com>
Fixes: 528530dff56b ("octeontx2-af: npc: cn20k: add debugfs support")
Link: https://lore.kernel.org/netdev/adjNGPWKMOk3KgWL@stanley.mountain/
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../marvell/octeontx2/af/cn20k/debugfs.c | 33 ++++++-------------
1 file changed, 10 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
index 3debf2fae1a4..6f13296303cb 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
@@ -249,34 +249,21 @@ DEFINE_SHOW_ATTRIBUTE(npc_defrag);
int npc_cn20k_debugfs_init(struct rvu *rvu)
{
struct npc_priv_t *npc_priv = npc_priv_get();
- struct dentry *npc_dentry;
- npc_dentry = debugfs_create_file("mcam_layout", 0444, rvu->rvu_dbg.npc,
- npc_priv, &npc_mcam_layout_fops);
+ debugfs_create_file("mcam_layout", 0444, rvu->rvu_dbg.npc,
+ npc_priv, &npc_mcam_layout_fops);
- if (!npc_dentry)
- return -EFAULT;
+ debugfs_create_file("mcam_default", 0444, rvu->rvu_dbg.npc,
+ rvu, &npc_mcam_default_fops);
- npc_dentry = debugfs_create_file("mcam_default", 0444, rvu->rvu_dbg.npc,
- rvu, &npc_mcam_default_fops);
+ debugfs_create_file("vidx2idx", 0444, rvu->rvu_dbg.npc,
+ npc_priv, &npc_vidx2idx_map_fops);
- if (!npc_dentry)
- return -EFAULT;
+ debugfs_create_file("idx2vidx", 0444, rvu->rvu_dbg.npc,
+ npc_priv, &npc_idx2vidx_map_fops);
- npc_dentry = debugfs_create_file("vidx2idx", 0444, rvu->rvu_dbg.npc,
- npc_priv, &npc_vidx2idx_map_fops);
- if (!npc_dentry)
- return -EFAULT;
-
- npc_dentry = debugfs_create_file("idx2vidx", 0444, rvu->rvu_dbg.npc,
- npc_priv, &npc_idx2vidx_map_fops);
- if (!npc_dentry)
- return -EFAULT;
-
- npc_dentry = debugfs_create_file("defrag", 0444, rvu->rvu_dbg.npc,
- npc_priv, &npc_defrag_fops);
- if (!npc_dentry)
- return -EFAULT;
+ debugfs_create_file("defrag", 0444, rvu->rvu_dbg.npc,
+ npc_priv, &npc_defrag_fops);
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 06/11] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth, Suman Ghosh
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
Replace the old four-argument CN20K MCAM clear with a per-bank static
helper and npc_cn20k_clear_mcam_entry() that takes a logical MCAM index,
resolves the key width via npc_mcam_idx_2_key_type(), and clears either
one bank (X2) or every bank (X4).
Call it from npc_clear_mcam_entry() on cn20k and log when key-type lookup
fails. Use the per-bank helper from npc_cn20k_config_mcam_entry() for
pre-program clears.
For loopback VFs, use the promisc MCAM index as ucast_idx when copying
RSS action for promisc, matching cn20k default-rule layout.
Cc: Suman Ghosh <sumang@marvell.com>
Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 36 ++++++++++++++++---
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 3 +-
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 17 +++++++--
3 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 705fe7a877e6..7bfd39fe0f5e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -842,8 +842,8 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
return 0;
}
-void
-npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int bank, int index)
+static void
+npc_clear_x2_entry(struct rvu *rvu, int blkaddr, int bank, int index)
{
rvu_write64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 1),
@@ -877,6 +877,32 @@ npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int bank, int index)
NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, bank), 0);
}
+int
+npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int mcam_idx)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int bank = npc_get_bank(mcam, mcam_idx);
+ u8 kw_type, index;
+
+ if (npc_mcam_idx_2_key_type(rvu, mcam_idx, &kw_type))
+ return -EINVAL;
+
+ index = mcam_idx & (mcam->banksize - 1);
+
+ if (kw_type == NPC_MCAM_KEY_X2) {
+ npc_clear_x2_entry(rvu, blkaddr, bank, index);
+ return 0;
+ }
+
+ /* For NPC_MCAM_KEY_X4 keys, both the banks
+ * need to be programmed with the same value.
+ */
+ for (bank = 0; bank < mcam->banks_per_entry; bank++)
+ npc_clear_x2_entry(rvu, blkaddr, bank, index);
+
+ return 0;
+}
+
static void npc_cn20k_get_keyword(struct cn20k_mcam_entry *entry, int idx,
u64 *cam0, u64 *cam1)
{
@@ -1071,7 +1097,7 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
*/
if (kw_type == NPC_MCAM_KEY_X2) {
/* Clear mcam entry to avoid writes being suppressed by NPC */
- npc_cn20k_clear_mcam_entry(rvu, blkaddr, bank, mcam_idx);
+ npc_clear_x2_entry(rvu, blkaddr, bank, mcam_idx);
npc_cn20k_config_kw_x2(rvu, mcam, blkaddr,
mcam_idx, intf, entry,
bank, kw_type, kw, req_kw_type);
@@ -1096,8 +1122,8 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
}
/* Clear mcam entry to avoid writes being suppressed by NPC */
- npc_cn20k_clear_mcam_entry(rvu, blkaddr, 0, mcam_idx);
- npc_cn20k_clear_mcam_entry(rvu, blkaddr, 1, mcam_idx);
+ npc_clear_x2_entry(rvu, blkaddr, 0, mcam_idx);
+ npc_clear_x2_entry(rvu, blkaddr, 1, mcam_idx);
npc_cn20k_config_kw_x4(rvu, mcam, blkaddr,
mcam_idx, intf, entry,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 8f3eea9cfb1d..2f761b97f91b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -330,8 +330,7 @@ int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
struct cn20k_mcam_entry *entry, u8 *intf,
u8 *ena, u8 *hw_prio);
-void npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr,
- int bank, int index);
+int npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int index);
int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type);
u16 npc_cn20k_vidx2idx(u16 index);
u16 npc_cn20k_idx2vidx(u16 idx);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 762fafd4ccb7..0a2191fda614 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -259,6 +259,13 @@ static void npc_clear_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int bank = npc_get_bank(mcam, index);
int actbank = bank;
+ if (is_cn20k(rvu->pdev)) {
+ if (npc_cn20k_clear_mcam_entry(rvu, blkaddr, index))
+ dev_err(rvu->dev, "%s Failed to enable mcam %u\n",
+ __func__, index);
+ return;
+ }
+
index &= (mcam->banksize - 1);
for (; bank < (actbank + mcam->banks_per_entry); bank++) {
rvu_write64(rvu, blkaddr,
@@ -753,9 +760,15 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
/* If the corresponding PF's ucast action is RSS,
* use the same action for promisc also
+ * Please note that for lbk(s) "index" and "ucast_idx"
+ * will be same.
*/
- ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
- nixlf, NIXLF_UCAST_ENTRY);
+ if (is_lbk_vf(rvu, pcifunc))
+ ucast_idx = index;
+ else
+ ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_UCAST_ENTRY);
+
if (is_mcam_entry_enabled(rvu, mcam, blkaddr, ucast_idx))
*(u64 *)&action = npc_get_mcam_action(rvu, mcam,
blkaddr, ucast_idx);
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 07/11] octeontx2-af: npc: cn20k: Fix bank value.
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth, Suman Ghosh
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
or X4 keys its loop reused the bank parameter as the loop counter,
so bank no longer reflected the caller's bank after the loop and
the control flow was hard to follow.
Program NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT directly in
npc_cn20k_config_mcam_entry(): one CFG write for X2 using the computed
bank, and one CFG write per bank inside the X4 action loop. Enable the
entry at the end with npc_cn20k_enable_mcam_entry(..., true) instead of
embedding the enable bit in bank_cfg via the removed helper.
Cc: Suman Ghosh <sumang@marvell.com>
Fixes: 4e527f1e5c15 ("octeontx2-af: npc: cn20k: Add new mailboxes for CN20K silicon")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 92 ++++++++-----------
1 file changed, 37 insertions(+), 55 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 7bfd39fe0f5e..4b37d471f118 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -1044,34 +1044,6 @@ static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam,
kw, req_kw_type);
}
-static void
-npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx,
- int bank, u8 kw_type, bool enable, u8 hw_prio)
-{
- struct npc_mcam *mcam = &rvu->hw->mcam;
- u64 bank_cfg;
-
- bank_cfg = (u64)hw_prio << 24;
- if (enable)
- bank_cfg |= 0x1;
-
- if (kw_type == NPC_MCAM_KEY_X2) {
- rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
- bank_cfg);
- return;
- }
-
- /* For NPC_MCAM_KEY_X4 keys, both the banks
- * need to be programmed with the same value.
- */
- for (bank = 0; bank < mcam->banks_per_entry; bank++) {
- rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
- bank_cfg);
- }
-}
-
int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
u8 intf, struct cn20k_mcam_entry *entry,
bool enable, u8 hw_prio, u8 req_kw_type)
@@ -1079,6 +1051,7 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
struct npc_mcam *mcam = &rvu->hw->mcam;
int mcam_idx = index % mcam->banksize;
int bank = index / mcam->banksize;
+ u64 bank_cfg = (u64)hw_prio << 24;
int kw = 0;
u8 kw_type;
@@ -1118,41 +1091,50 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
bank, 1),
entry->vtag_action);
- goto set_cfg;
- }
- /* Clear mcam entry to avoid writes being suppressed by NPC */
- npc_clear_x2_entry(rvu, blkaddr, 0, mcam_idx);
- npc_clear_x2_entry(rvu, blkaddr, 1, mcam_idx);
-
- npc_cn20k_config_kw_x4(rvu, mcam, blkaddr,
- mcam_idx, intf, entry,
- kw_type, req_kw_type);
- for (bank = 0; bank < mcam->banks_per_entry; bank++) {
- /* Set 'action' */
+ /* Set HW priority */
rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
- bank, 0),
- entry->action);
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
+ bank_cfg);
- /* Set TAG 'action' */
- rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
- bank, 1),
- entry->vtag_action);
+ } else {
+ /* Clear mcam entry to avoid writes being suppressed by NPC */
+ npc_clear_x2_entry(rvu, blkaddr, 0, mcam_idx);
+ npc_clear_x2_entry(rvu, blkaddr, 1, mcam_idx);
- /* Set 'action2' for inline receive */
- rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
- bank, 2),
- entry->action2);
+ npc_cn20k_config_kw_x4(rvu, mcam, blkaddr,
+ mcam_idx, intf, entry,
+ kw_type, req_kw_type);
+ for (bank = 0; bank < mcam->banks_per_entry; bank++) {
+ /* Set 'action' */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 0),
+ entry->action);
+
+ /* Set TAG 'action' */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 1),
+ entry->vtag_action);
+
+ /* Set 'action2' for inline receive */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 2),
+ entry->action2);
+
+ /* Set HW priority */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
+ bank_cfg);
+ }
}
-set_cfg:
/* TODO: */
/* PF installing VF rule */
- npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank,
- kw_type, enable, hw_prio);
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable))
+ return -EINVAL;
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 08/11] octeontx2-af: npc: cn20k: Fix MCAM actions read
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth, Suman Ghosh
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
npc_cn20k_read_mcam_entry() always reloaded action and vtag_action from
bank 0 after programming the CAM words. Use the bank returned by
npc_get_bank() for the ACTION reads as well, and read those registers
once up front so both X2 and X4 paths share the same metadata.
Return directly from the X2 keyword path now that the action fields are
already populated.
Cc: Suman Ghosh <sumang@marvell.com>
Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 22 ++++++++-----------
1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 4b37d471f118..752dbcede90f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -1218,6 +1218,14 @@ int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0));
+ entry->action = cfg;
+
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 1));
+ entry->vtag_action = cfg;
+
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index,
bank, 1)) & 3;
@@ -1267,7 +1275,7 @@ int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
bank,
0));
npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1);
- goto read_action;
+ return 0;
}
for (bank = 0; bank < mcam->banks_per_entry; bank++, kw = kw + 4) {
@@ -1312,18 +1320,6 @@ int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1);
}
-read_action:
- /* 'action' is set to same value for both bank '0' and '1'.
- * Hence, reading bank '0' should be enough.
- */
- cfg = rvu_read64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 0));
- entry->action = cfg;
-
- cfg = rvu_read64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 1));
- entry->vtag_action = cfg;
-
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 09/11] octeontx2-af: npc: cn20k: Initialize default-rule index outputs up front
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
npc_cn20k_dft_rules_idx_get() wrote USHRT_MAX into individual outputs
only on some error paths (lbk promisc lookup, VF ucast lookup, and the
PF rule walk), which could leave other caller slots stale across
retries.
Set every non-NULL bcast/mcast/promisc/ucast pointer to USHRT_MAX once
at entry, then drop the duplicate assignments on failure. Successful
lookups still overwrite the relevant slot before returning.
Fixes: 09d3b7a1403f ("octeontx2-af: npc: cn20k: Allocate default MCAM indexes")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 752dbcede90f..0714734c6af7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -4001,6 +4001,13 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
void *val;
int i, j;
+ for (i = 0; i < ARRAY_SIZE(ptr); i++) {
+ if (!ptr[i])
+ continue;
+
+ *ptr[i] = USHRT_MAX;
+ }
+
if (!npc_priv.init_done)
return 0;
@@ -4016,7 +4023,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID],
pcifunc);
- *ptr[0] = USHRT_MAX;
return -ESRCH;
}
@@ -4036,7 +4042,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID],
pcifunc);
- *ptr[3] = USHRT_MAX;
return -ESRCH;
}
@@ -4056,7 +4061,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
__func__,
npc_dft_rule_name[i], pcifunc);
- *ptr[j] = USHRT_MAX;
continue;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 10/11] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
npc_cn20k_dft_rules_free() used the NPC MCAM mbox "free all" path, which
does not match how cn20k tracks default-rule MCAM slots indexes.
Resolve the default-rule indices, then for each valid slot clear the
bitmap entry, drop the PF/VF map, disable the MCAM line, clear the
target function, and npc_cn20k_idx_free(). Remove any
matching software mcam_rules nodes. On hard failure from idx_free, WARN
and stop so the box stays up for analysis.
In npc_mcam_free_all_entries(), prefetch the same default-rule indices
and, on cn20k, skip bitmap clear and idx_free when the scanned entry is
one of those reserved defaults (they are released by
npc_cn20k_dft_rules_free). Still disable the entry and tear down counter
mapping for every matching index.
Fixes: 09d3b7a1403f ("octeontx2-af: npc: cn20k: Allocate default MCAM indexes")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 51 ++++++++++++----
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 59 +++++++++++++------
2 files changed, 82 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 0714734c6af7..cb2fc21e0583 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -4163,11 +4163,11 @@ static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
{
- struct npc_mcam_free_entry_req free_req = { 0 };
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ u16 ptr[4] = {[0 ... 3] = USHRT_MAX};
+ struct rvu_npc_mcam_rule *rule, *tmp;
unsigned long index;
- struct msg_rsp rsp;
- u16 ptr[4];
- int rc, i;
+ int blkaddr, rc, i;
void *map;
if (!npc_priv.init_done)
@@ -4225,14 +4225,43 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
}
free_rules:
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+ for (int i = 0; i < 4; i++) {
+ if (ptr[i] == USHRT_MAX)
+ continue;
- free_req.hdr.pcifunc = pcifunc;
- free_req.all = 1;
- rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
- if (rc)
- dev_err(rvu->dev,
- "%s: Error deleting default entries (pcifunc=%#x\n",
- __func__, pcifunc);
+ mutex_lock(&mcam->lock);
+ npc_mcam_clear_bit(mcam, ptr[i]);
+ mcam->entry2pfvf_map[ptr[i]] = NPC_MCAM_INVALID_MAP;
+ npc_cn20k_enable_mcam_entry(rvu, blkaddr, ptr[i], false);
+ mcam->entry2target_pffunc[ptr[i]] = 0x0;
+ mutex_unlock(&mcam->lock);
+
+ rc = npc_cn20k_idx_free(rvu, &ptr[i], 1);
+ if (rc) {
+ /* Non recoverable error. Let us WARN and return. Keep system alive to
+ * enable debugging
+ */
+ WARN(1, "%s Error deleting default entries (pcifunc=%#x) mcam_idx=%u\n",
+ __func__, pcifunc, ptr[i]);
+ return;
+ }
+ }
+
+ mutex_lock(&mcam->lock);
+ list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
+ for (int i = 0; i < 4; i++) {
+ if (ptr[i] != rule->entry)
+ continue;
+
+ list_del(&rule->list);
+ kfree(rule);
+ break;
+ }
+ }
+ mutex_unlock(&mcam->lock);
}
int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 0a2191fda614..b2a9c8d0075b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -2519,33 +2519,58 @@ void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index)
static void npc_mcam_free_all_entries(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, u16 pcifunc)
{
+ u16 dft_idxs[NPC_DFT_RULE_MAX_ID];
+ bool cn20k_dft_rl;
u16 index, cntr;
int rc;
+ npc_cn20k_dft_rules_idx_get(rvu, pcifunc,
+ &dft_idxs[NPC_DFT_RULE_BCAST_ID],
+ &dft_idxs[NPC_DFT_RULE_MCAST_ID],
+ &dft_idxs[NPC_DFT_RULE_PROMISC_ID],
+ &dft_idxs[NPC_DFT_RULE_UCAST_ID]);
+
/* Scan all MCAM entries and free the ones mapped to 'pcifunc' */
for (index = 0; index < mcam->bmap_entries; index++) {
- if (mcam->entry2pfvf_map[index] == pcifunc) {
+ if (mcam->entry2pfvf_map[index] != pcifunc)
+ continue;
+
+ cn20k_dft_rl = false;
+
+ if (is_cn20k(rvu->pdev)) {
+ if (dft_idxs[NPC_DFT_RULE_BCAST_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_MCAST_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_PROMISC_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_UCAST_ID] == index) {
+ cn20k_dft_rl = true;
+ }
+ }
+
+ /* Disable the entry */
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
+
+ if (!cn20k_dft_rl) {
mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP;
/* Free the entry in bitmap */
npc_mcam_clear_bit(mcam, index);
- /* Disable the entry */
- npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
-
- /* Update entry2counter mapping */
- cntr = mcam->entry2cntr_map[index];
- if (cntr != NPC_MCAM_INVALID_MAP)
- npc_unmap_mcam_entry_and_cntr(rvu, mcam,
- blkaddr, index,
- cntr);
mcam->entry2target_pffunc[index] = 0x0;
- if (is_cn20k(rvu->pdev)) {
- rc = npc_cn20k_idx_free(rvu, &index, 1);
- if (rc)
- dev_err(rvu->dev,
- "Failed to free mcam idx=%u pcifunc=%#x\n",
- index, pcifunc);
- }
}
+
+ /* Update entry2counter mapping */
+ cntr = mcam->entry2cntr_map[index];
+ if (cntr != NPC_MCAM_INVALID_MAP)
+ npc_unmap_mcam_entry_and_cntr(rvu, mcam,
+ blkaddr, index,
+ cntr);
+
+ if (!is_cn20k(rvu->pdev) || cn20k_dft_rl)
+ continue;
+
+ rc = npc_cn20k_idx_free(rvu, &index, 1);
+ if (rc)
+ dev_err(rvu->dev,
+ "Failed to free mcam idx=%u pcifunc=%#x\n",
+ index, pcifunc);
}
}
--
2.43.0
^ permalink raw reply related
* [PATCH v2 net 11/11] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices
From: Ratheesh Kannoth @ 2026-04-20 2:34 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
dan.carpenter, Ratheesh Kannoth, Suman Ghosh
In-Reply-To: <20260420023442.3295891-1-rkannoth@marvell.com>
npc_get_nixlf_mcam_index() returned USHRT_MAX from npc_cn20k_dft_rules_idx_get()
for broadcast, multicast, promiscuous, and unicast default-rule slots when no
rule was installed. Callers could use that sentinel as a real MCAM index.
Return -EINVAL from the cn20k cases when the reserved entry is still USHRT_MAX.
Teach rvu_npc_update_flowkey_alg_idx() to handle negative indices and skip RSS
action updates when the lookup fails. Add range checks to cn20k NPC MCAM helpers
so bogus indices are rejected before touching hardware.
Cc: Suman Ghosh <sumang@marvell.com>
Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 12 ++++++++++
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 23 ++++++++++++-------
2 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index cb2fc21e0583..59d22511b742 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -808,6 +808,9 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
u64 cfg, hw_prio;
u8 kw_type;
+ if (index < 0 || index >= mcam->total_entries)
+ return -EINVAL;
+
if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
return -EINVAL;
@@ -1055,6 +1058,9 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
int kw = 0;
u8 kw_type;
+ if (index < 0 || index >= mcam->total_entries)
+ return -EINVAL;
+
if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
return -EINVAL;
@@ -1147,6 +1153,9 @@ int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
int bank, i, sb, db;
int dbank, sbank;
+ if (src >= mcam->total_entries || dest >= mcam->total_entries)
+ return -EINVAL;
+
dbank = npc_get_bank(mcam, dest);
sbank = npc_get_bank(mcam, src);
@@ -1212,6 +1221,9 @@ int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
int kw = 0, bank;
u8 kw_type;
+ if (index >= mcam->total_entries)
+ return -EINVAL;
+
if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
return -EINVAL;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index b2a9c8d0075b..be79a51b4b48 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -165,12 +165,20 @@ int npc_get_nixlf_mcam_index(struct npc_mcam *mcam,
switch (type) {
case NIXLF_BCAST_ENTRY:
+ if (bcast == USHRT_MAX)
+ return -EINVAL;
return bcast;
case NIXLF_ALLMULTI_ENTRY:
+ if (mcast == USHRT_MAX)
+ return -EINVAL;
return mcast;
case NIXLF_PROMISC_ENTRY:
+ if (promisc == USHRT_MAX)
+ return -EINVAL;
return promisc;
case NIXLF_UCAST_ENTRY:
+ if (ucast == USHRT_MAX)
+ return -EINVAL;
return ucast;
default:
return -EINVAL;
@@ -238,9 +246,6 @@ void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int actbank = bank;
if (is_cn20k(rvu->pdev)) {
- if (index < 0 || index >= mcam->banksize * mcam->banks)
- return;
-
npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
return;
}
@@ -1128,7 +1133,7 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
index = mcam_index;
}
- if (index >= mcam->total_entries)
+ if (index < 0 || index >= mcam->total_entries)
return;
bank = npc_get_bank(mcam, index);
@@ -1173,16 +1178,18 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
/* If PF's promiscuous entry is enabled,
* Set RSS action for that entry as well
*/
- npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
- blkaddr, alg_idx);
+ if (index >= 0)
+ npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
+ blkaddr, alg_idx);
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_ALLMULTI_ENTRY);
/* If PF's allmulti entry is enabled,
* Set RSS action for that entry as well
*/
- npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
- blkaddr, alg_idx);
+ if (index >= 0)
+ npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
+ blkaddr, alg_idx);
}
}
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox