* [PATCH iwl-next] ixgbe: use ktime_get_real_ns() in ixgbe_ptp_reset()
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Jacob Keller, Marcin Szycik
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
Replace ktime_to_ns(ktime_get_real()) with the direct equivalent
ktime_get_real_ns() in ixgbe_ptp_reset(). Using the combined helper
avoids the unnecessary intermediate ktime_t variable and makes the
intent clearer.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Marcin Szycik <marcin.szycik@linux.intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index 6885d23..a7d1635 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -1347,7 +1347,7 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
spin_lock_irqsave(&adapter->tmreg_lock, flags);
timecounter_init(&adapter->hw_tc, &adapter->hw_cc,
- ktime_to_ns(ktime_get_real()));
+ ktime_get_real_ns());
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
adapter->last_overflow_check = jiffies;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: call ixgbe_setup_fc() before fc_enable() after NVM update
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
From: Radoslaw Tyl <radoslawx.tyl@intel.com>
During an NVM update the PHY reset clears the Technology Ability Field
(IEEE 802.3 clause 37 register 7.10) back to hardware defaults. When
the driver subsequently calls only hw->mac.ops.fc_enable() the SRRCTL
register is recalculated from the stale autonegotiated capability bits,
which the MDD (Malicious Driver Detect) logic treats as an invalid
change and halts traffic on the PF.
Fix by calling ixgbe_setup_fc() immediately before fc_enable() in
ixgbe_watchdog_update_link() so that flow-control autoneg and the
PHY registers are re-programmed in the correct order after any reset.
Signed-off-by: Radoslaw Tyl <radoslawx.tyl@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 52f0cdc..db954e9 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -8041,6 +8041,12 @@ static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter)
pfc_en |= !!(adapter->ixgbe_ieee_pfc->pfc_en);
if (link_up && !((adapter->flags & IXGBE_FLAG_DCB_ENABLED) && pfc_en)) {
+ if (hw->mac.ops.setup_fc) {
+ int err = hw->mac.ops.setup_fc(hw);
+
+ if (err)
+ e_warn(drv, "setup_fc failed: %d\n", err);
+ }
hw->mac.ops.fc_enable(hw);
ixgbe_set_rx_drop_en(adapter);
}
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: replace GFP_ATOMIC with GFP_KERNEL in ixgbe_fcoe_ddp_setup()
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
From: Sebastian Basierski <sebastianx.basierski@intel.com>
ixgbe_fcoe_ddp_setup() is always called from process context (FCoE
offload setup paths) and never from an atomic context. Using
GFP_ATOMIC is therefore unnecessarily restrictive and wastes memory
allocator headroom that is reserved for genuine atomic callers.
Replace the dma_pool_alloc() flag with GFP_KERNEL.
Signed-off-by: Sebastian Basierski <sebastianx.basierski@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index 011fda9..7fa0971 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -193,7 +193,7 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
}
/* alloc the udl from per cpu ddp pool */
- ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp);
+ ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_KERNEL, &ddp->udp);
if (!ddp->udl) {
e_err(drv, "failed allocated ddp context\n");
goto out_noddp_unmap;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: fix cls_u32 nexthdr path returning success when no entry installed
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Marcin Szycik
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
ixgbe_configure_clsu32() returns 0 (success) after the nexthdr loop
even when ixgbe_clsu32_build_input() fails for every candidate entry
and no jump-table slot is actually programmed. Callers that test the
return value would then falsely believe the filter was installed.
The variable 'err' already tracks the last ixgbe_clsu32_build_input()
return value; if the loop completes with a successful break, err is 0.
If all attempts failed, err holds the last failure code. Change the
unconditional 'return 0' to 'return err' so errors are propagated
correctly.
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Marcin Szycik <marcin.szycik@linux.intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index db954e9..8ac80ff 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -10311,7 +10311,7 @@ static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
kfree(jump);
}
}
- return 0;
+ return err;
}
input = kzalloc_obj(*input);
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: use int instead of u32 for error code variables
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
The variables used to store return values of kernel and driver functions
throughout the ixgbe driver are declared as u32 in several places. Such
functions return negative errno values on error (e.g. -EIO, -EFAULT),
which are sign-extended negative integers. Storing them in an unsigned
u32 silently wraps the value: -EIO (0xFFFFFFF7) stored in u32 becomes a
large positive number, so any "if (status)" truthiness check still works
by accident, but comparisons against specific negative error codes or
propagation up the call stack would produce wrong results.
In the Linux kernel, u32 is reserved for fixed-width quantities used in
hardware interfaces or protocol structures. Using it for generic error
codes misleads reviewers into thinking the value is hardware-constrained.
Change all such local variables from u32 to int driver-wide: one in
ixgbe_main.c (ixgbe_resume), three in ixgbe_phy.c
(ixgbe_identify_phy_generic, ixgbe_tn_check_overtemp,
ixgbe_set_copper_phy_power), and six in ixgbe_x550.c
(ixgbe_check_link_t_X550em, ixgbe_get_lasi_ext_t_x550em,
ixgbe_enable_lasi_ext_t_x550em, ixgbe_handle_lasi_ext_t_x550em,
ixgbe_ext_phy_t_x550em_get_link, ixgbe_setup_internal_phy_t_x550em).
No functional change.
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 6 +++---
drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 12 ++++++------
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 210c7b9..703451d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7518,6 +7518,6 @@ static int ixgbe_resume(struct device *dev_d)
struct pci_dev *pdev = to_pci_dev(dev_d);
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
- u32 err;
+ int err;
adapter->hw.hw_addr = adapter->io_addr;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index a1b2c3d..b4c5d6e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -264,5 +264,5 @@ int ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
{
- u32 status = -EFAULT;
+ int status = -EFAULT;
u32 phy_addr;
if (!hw->phy.phy_semaphore_mask) {
@@ -2812,6 +2812,6 @@ bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
{
u16 phy_data = 0;
- u32 status;
+ int status;
if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
return false;
@@ -2833,5 +2833,5 @@ int ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on)
{
- u32 status;
+ int status;
u16 reg;
/* Bail if we don't have copper phy */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index c1d2e3f..d4e5f6a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -1912,6 +1912,6 @@ static int ixgbe_check_link_t_X550em(struct ixgbe_hw *hw,
bool link_up_wait_to_complete)
{
- u32 status;
+ int status;
u16 i, autoneg_status;
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
@@ -2331,6 +2331,6 @@ static int ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc,
bool *is_overtemp)
{
- u32 status;
+ int status;
u16 reg;
*is_overtemp = false;
@@ -2419,6 +2419,6 @@ static int ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
{
bool lsc, overtemp;
- u32 status;
+ int status;
u16 reg;
/* Clear interrupt flags */
@@ -2512,7 +2512,7 @@ static int ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw,
{
struct ixgbe_phy_info *phy = &hw->phy;
bool lsc;
- u32 status;
+ int status;
status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc, is_overtemp);
if (status)
@@ -2608,5 +2608,5 @@ static int ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up)
{
- u32 ret;
+ int ret;
u16 autoneg_status;
*link_up = false;
@@ -2642,7 +2642,7 @@ static int ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
{
ixgbe_link_speed force_speed;
bool link_up;
- u32 status;
+ int status;
u16 speed;
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: fix integer overflow and wrong bit position in ixgbe_validate_rtr()
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
Two bugs in the same loop in ixgbe_validate_rtr():
1. When extracting 3-bit traffic class values from the IXGBE_RTRUP2TC
register the shifted value was assigned directly to a u8, silently
truncating any bits above bit 7. Mask with IXGBE_RTRUP2TC_UP_MASK
before the assignment so only the intended 3 bits are kept.
2. When clearing an out-of-bounds entry the mask was always shifted by
the fixed constant IXGBE_RTRUP2TC_UP_SHIFT (== 3), regardless of
which loop iteration was being processed. This means only the entry
at bit position 3 was ever cleared; entries at bit positions 0, 6, 9,
..., 21 were left unreset. Use i * IXGBE_RTRUP2TC_UP_SHIFT to target
the correct field for each iteration.
Also replace the hardcoded 0x7 literal with the IXGBE_RTRUP2TC_UP_MASK
constant for consistency with other parts of the driver.
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 9aec66c..53b82a5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -9798,11 +9798,12 @@ static void ixgbe_validate_rtr(struct ixgbe_adapter *adapter, u8 tc)
rsave = reg;
for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
- u8 up2tc = reg >> (i * IXGBE_RTRUP2TC_UP_SHIFT);
+ u8 up2tc = IXGBE_RTRUP2TC_UP_MASK &
+ (reg >> (i * IXGBE_RTRUP2TC_UP_SHIFT));
/* If up2tc is out of bounds default to zero */
if (up2tc > tc)
- reg &= ~(0x7 << IXGBE_RTRUP2TC_UP_SHIFT);
+ reg &= ~(IXGBE_RTRUP2TC_UP_MASK << (i * IXGBE_RTRUP2TC_UP_SHIFT));
}
if (reg != rsave)
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: fix ITR value overflow in adaptive interrupt throttling
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
ixgbe_update_itr() packs a mode flag (IXGBE_ITR_ADAPTIVE_LATENCY, bit 7)
and a usecs delay (bits [6:0]) into an unsigned int, then stores it in
ring_container->itr which is u8. Values above 0xFF wrap, corrupting both
the delay and the mode-flag on the next readback.
Separate the mode bits from the usecs sub-field; clamp only the latter to
[0, IXGBE_ITR_ADAPTIVE_LATENCY - 1] via min_t(unsigned int, ...) so
overflow cannot bleed into bit 7. Add a WARN_ONCE() when the raw usecs
value exceeds U8_MAX so out-of-range ITR computations are visible in
dmesg during development and testing.
Fixes: b4ded8327fea ("ixgbe: Update adaptive ITR algorithm")
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 1885fe8..4d53bd63 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2901,8 +2901,12 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
if ((itr & IXGBE_ITR_ADAPTIVE_LATENCY) && itr < ring_container->itr)
itr = ring_container->itr - IXGBE_ITR_ADAPTIVE_MIN_INC;
clear_counts:
- /* write back value */
- ring_container->itr = itr;
+ WARN_ONCE((itr & ~IXGBE_ITR_ADAPTIVE_LATENCY) > U8_MAX,
+ "ITR value %u exceeds U8_MAX, clamping\n", itr);
+
+ ring_container->itr = (itr & IXGBE_ITR_ADAPTIVE_LATENCY) |
+ min_t(unsigned int, itr & ~IXGBE_ITR_ADAPTIVE_LATENCY,
+ IXGBE_ITR_ADAPTIVE_LATENCY - 1);
/* next update should occur within next jiffy */
ring_container->next_update = next_update + 1;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next] ixgbe: extend 5 s SWFW semaphore timeout to all X550EM variants
From: Aleksandr Loktionov @ 2026-03-27 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260327073046.134085-1-aleksandr.loktionov@intel.com>
From: Marta Plantykow <marta.a.plantykow@intel.com>
The 5-second SWFW semaphore timeout added for X550 (ixgbe_mac_X550)
also applies to X550EM devices (e.g. X550EM_a, X550EM_x) since they
share the same FW and the same SR-dump-driven worst-case latency of
~3.2 s / module-update latency of ~4.5 s. Change the mac-type
comparison from '== ixgbe_mac_X550' to a range check that covers
all three X550-family enum values (ixgbe_mac_X550, ixgbe_mac_X550EM_x,
ixgbe_mac_x550em_a) without inadvertently capturing later entries such
as ixgbe_mac_e610 which share the same swfw-sync function but have
not been validated against this exact timing requirement.
Signed-off-by: Marta Plantykow <marta.a.plantykow@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index 85047ef..298958d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -577,7 +577,8 @@ int ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
swmask |= swi2c_mask;
fwmask |= swi2c_mask << 2;
- if (hw->mac.type == ixgbe_mac_X550)
+ if (hw->mac.type >= ixgbe_mac_X550 &&
+ hw->mac.type <= ixgbe_mac_x550em_a)
timeout = 1000;
for (i = 0; i < timeout; i++) {
--
2.52.0
^ permalink raw reply related
* [PATCH net v3] mptcp: fix soft lockup in mptcp_recvmsg()
From: Li Xiasong @ 2026-03-27 7:55 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: netdev, mptcp, linux-kernel, yuehaibing, zhangchangzhong,
weiyongjun1
syzbot reported a soft lockup in mptcp_recvmsg() [0].
When receiving data with MSG_PEEK | MSG_WAITALL flags, the skb is not
removed from the sk_receive_queue. This causes sk_wait_data() to always
find available data and never perform actual waiting, leading to a soft
lockup.
Fix this by adding a 'last' parameter to track the last peeked skb.
This allows sk_wait_data() to make informed waiting decisions and prevent
infinite loops when MSG_PEEK is used.
[0]:
watchdog: BUG: soft lockup - CPU#2 stuck for 156s! [server:1963]
Modules linked in:
CPU: 2 UID: 0 PID: 1963 Comm: server Not tainted 6.19.0-rc8 #61 PREEMPT(none)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
RIP: 0010:sk_wait_data+0x15/0x190
Code: 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 41 56 41 55 41 54 49 89 f4 55 48 89 d5 53 48 89 fb <48> 83 ec 30 65 48 8b 05 17 a4 6b 01 48 89 44 24 28 31 c0 65 48 8b
RSP: 0018:ffffc90000603ca0 EFLAGS: 00000246
RAX: 0000000000000000 RBX: ffff888102bf0800 RCX: 0000000000000001
RDX: 0000000000000000 RSI: ffffc90000603d18 RDI: ffff888102bf0800
RBP: 0000000000000000 R08: 0000000000000002 R09: 0000000000000101
R10: 0000000000000000 R11: 0000000000000075 R12: ffffc90000603d18
R13: ffff888102bf0800 R14: ffff888102bf0800 R15: 0000000000000000
FS: 00007f6e38b8c4c0(0000) GS:ffff8881b877e000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055aa7bff1680 CR3: 0000000105cbe000 CR4: 00000000000006f0
Call Trace:
<TASK>
mptcp_recvmsg+0x547/0x8c0 net/mptcp/protocol.c:2329
inet_recvmsg+0x11f/0x130 net/ipv4/af_inet.c:891
sock_recvmsg+0x94/0xc0 net/socket.c:1100
__sys_recvfrom+0xb2/0x130 net/socket.c:2256
__x64_sys_recvfrom+0x1f/0x30 net/socket.c:2267
do_syscall_64+0x59/0x2d0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x76/0x7e arch/x86/entry/entry_64.S:131
RIP: 0033:0x7f6e386a4a1d
Code: 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 8d 05 f1 de 2c 00 41 89 ca 8b 00 85 c0 75 20 45 31 c9 45 31 c0 b8 2d 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 6b f3 c3 66 0f 1f 84 00 00 00 00 00 41 56 41
RSP: 002b:00007ffc3c4bb078 EFLAGS: 00000246 ORIG_RAX: 000000000000002d
RAX: ffffffffffffffda RBX: 000000000000861e RCX: 00007f6e386a4a1d
RDX: 00000000000003ff RSI: 00007ffc3c4bb150 RDI: 0000000000000004
RBP: 00007ffc3c4bb570 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000103 R11: 0000000000000246 R12: 00005605dbc00be0
R13: 00007ffc3c4bb650 R14: 0000000000000000 R15: 0000000000000000
</TASK>
Fixes: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption")
Signed-off-by: Li Xiasong <lixiasong1@huawei.com>
---
v2->v3:
Thanks to Matthieu Baerts for the review.
- Initialize last to NULL.
- Only update 'last' when MSG_PEEK is set, avoiding dangling pointer.
v1->v2:
Thanks to Matthieu Baerts for the suggestion and review.
- Move 'last' variable definition into the while loop in mptcp_recvmsg() to
narrow its scope.
- In __mptcp_recvmsg_mskq(), assign 'last' right after 'copied' is updated,
regardless of MSG_PEEK flag.
https://lore.kernel.org/netdev/20260324085131.4187473-1-lixiasong1@huawei.com/
v1:
https://lore.kernel.org/netdev/20260302052651.1466983-1-lixiasong1@huawei.com/
---
net/mptcp/protocol.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index cf1852b99963..60f6e6a189b7 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -2006,7 +2006,7 @@ static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
size_t len, int flags, int copied_total,
struct scm_timestamping_internal *tss,
- int *cmsg_flags)
+ int *cmsg_flags, struct sk_buff **last)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct sk_buff *skb, *tmp;
@@ -2058,6 +2058,8 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
}
mptcp_eat_recv_skb(sk, skb);
+ } else {
+ *last = skb;
}
if (copied >= len)
@@ -2288,10 +2290,12 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
cmsg_flags = MPTCP_CMSG_INQ;
while (copied < len) {
+ struct sk_buff *last = NULL;
int err, bytes_read;
bytes_read = __mptcp_recvmsg_mskq(sk, msg, len - copied, flags,
- copied, &tss, &cmsg_flags);
+ copied, &tss, &cmsg_flags,
+ &last);
if (unlikely(bytes_read < 0)) {
if (!copied)
copied = bytes_read;
@@ -2343,7 +2347,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
pr_debug("block timeout %ld\n", timeo);
mptcp_cleanup_rbuf(msk, copied);
- err = sk_wait_data(sk, &timeo, NULL);
+ err = sk_wait_data(sk, &timeo, last);
if (err < 0) {
err = copied ? : err;
goto out_err;
--
2.34.1
^ permalink raw reply related
* Re: [PATCH net-next v4 00/10] selftests: drivers: bash support for remote traffic generators
From: Ioana Ciornei @ 2026-03-27 7:32 UTC (permalink / raw)
To: Jakub Kicinski
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, linux-kernel, petrm, willemb, linux-kselftest
In-Reply-To: <20260326120342.6429fbdc@kernel.org>
On Thu, Mar 26, 2026 at 12:03:42PM -0700, Jakub Kicinski wrote:
> On Thu, 26 Mar 2026 15:28:18 +0200 Ioana Ciornei wrote:
> > This patch set aims to add the necessary support so that bash written
> > selftests are also able to easily run with a remote traffic generator
> > system, either be it in another netns or one accessible through ssh.
> >
> > This patch set is a result of the discussion from v1:
> > https://lore.kernel.org/all/20260303084330.340b6459@kernel.org/
> > Even though the python infrastructure is already established, some
> > things are easier in bash and it would be a shame to leave behind the
> > bash tests that we already have.
>
> I think this introduces a bunch of regressions, eg:
>
> https://netdev-ctrl.bots.linux.dev/logs/vmksft/forwarding/results/575622/4-local-termination-sh/stdout
>
> https://netdev-ctrl.bots.linux.dev/logs/vmksft/netdevsim/results/575802/18-netcons-resume-sh/stdout
I cannot reproduce this unfortunately. For example, local_termination.sh
gives me the following result with the exact patches that I submitted.
Any idea on what might be the difference?
root@localhost:~/ksft-net-drv# ./run_kselftest.sh -t net/forwarding:local_termination.sh
[71318.022491] kselftest: Running tests in net/forwarding
TAP version 13
1..1
# timeout set to 0
# selftests: net/forwarding: local_termination.sh
# TEST: veth1: Unicast IPv4 to primary MAC address [ OK ]
# TEST: veth1: Unicast IPv4 to macvlan MAC address [ OK ]
# TEST: veth1: Unicast IPv4 to unknown MAC address [ OK ]
# TEST: veth1: Unicast IPv4 to unknown MAC address, promisc [ OK ]
# TEST: veth1: Unicast IPv4 to unknown MAC address, allmulti [ OK ]
# TEST: veth1: Multicast IPv4 to joined group [ OK ]
# TEST: veth1: Multicast IPv4 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: veth1: Multicast IPv4 to unknown group, promisc [ OK ]
# TEST: veth1: Multicast IPv4 to unknown group, allmulti [ OK ]
# TEST: veth1: Multicast IPv6 to joined group [ OK ]
# TEST: veth1: Multicast IPv6 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: veth1: Multicast IPv6 to unknown group, promisc [ OK ]
# TEST: veth1: Multicast IPv6 to unknown group, allmulti [ OK ]
# TEST: veth1: Link-local STP BPDU [ OK ]
# TEST: veth1: Link-local LLDP [ OK ]
# TEST: veth1: 1588v2 over L2 transport, Sync [ OK ]
# TEST: veth1: 1588v2 over L2 transport, Follow-Up [ OK ]
# TEST: veth1: 1588v2 over L2 transport, Peer Delay Request [ OK ]
# TEST: veth1: 1588v2 over IPv4, Sync [ OK ]
# TEST: veth1: 1588v2 over IPv4, Follow-Up [ OK ]
# TEST: veth1: 1588v2 over IPv4, Peer Delay Request [ OK ]
# TEST: veth1: 1588v2 over IPv6, Sync [ OK ]
# TEST: veth1: 1588v2 over IPv6, Follow-Up [ OK ]
# TEST: veth1: 1588v2 over IPv6, Peer Delay Request [ OK ]
# TEST: vlan_filtering=0 bridge: Unicast IPv4 to primary MAC address [ OK ]
# TEST: vlan_filtering=0 bridge: Unicast IPv4 to macvlan MAC address [ OK ]
# TEST: vlan_filtering=0 bridge: Unicast IPv4 to unknown MAC address [ OK ]
# TEST: vlan_filtering=0 bridge: Unicast IPv4 to unknown MAC address, promisc [ OK ]
# TEST: vlan_filtering=0 bridge: Unicast IPv4 to unknown MAC address, allmulti [ OK ]
# TEST: vlan_filtering=0 bridge: Multicast IPv4 to joined group [ OK ]
# TEST: vlan_filtering=0 bridge: Multicast IPv4 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: vlan_filtering=0 bridge: Multicast IPv4 to unknown group, promisc [ OK ]
# TEST: vlan_filtering=0 bridge: Multicast IPv4 to unknown group, allmulti [ OK ]
# TEST: vlan_filtering=0 bridge: Multicast IPv6 to joined group [ OK ]
# TEST: vlan_filtering=0 bridge: Multicast IPv6 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: vlan_filtering=0 bridge: Multicast IPv6 to unknown group, promisc [ OK ]
# TEST: vlan_filtering=0 bridge: Multicast IPv6 to unknown group, allmulti [ OK ]
# TEST: vlan_filtering=0 bridge: Link-local STP BPDU [ OK ]
# TEST: vlan_filtering=1 bridge: Unicast IPv4 to primary MAC address [ OK ]
# TEST: vlan_filtering=1 bridge: Unicast IPv4 to macvlan MAC address [ OK ]
# TEST: vlan_filtering=1 bridge: Unicast IPv4 to unknown MAC address [ OK ]
# TEST: vlan_filtering=1 bridge: Unicast IPv4 to unknown MAC address, promisc [ OK ]
# TEST: vlan_filtering=1 bridge: Unicast IPv4 to unknown MAC address, allmulti [ OK ]
# TEST: vlan_filtering=1 bridge: Multicast IPv4 to joined group [ OK ]
# TEST: vlan_filtering=1 bridge: Multicast IPv4 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: vlan_filtering=1 bridge: Multicast IPv4 to unknown group, promisc [ OK ]
# TEST: vlan_filtering=1 bridge: Multicast IPv4 to unknown group, allmulti [ OK ]
# TEST: vlan_filtering=1 bridge: Multicast IPv6 to joined group [ OK ]
# TEST: vlan_filtering=1 bridge: Multicast IPv6 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: vlan_filtering=1 bridge: Multicast IPv6 to unknown group, promisc [ OK ]
# TEST: vlan_filtering=1 bridge: Multicast IPv6 to unknown group, allmulti [ OK ]
# TEST: vlan_filtering=1 bridge: Link-local STP BPDU [ OK ]
# TEST: VLAN upper: Unicast IPv4 to primary MAC address [ OK ]
# TEST: VLAN upper: Unicast IPv4 to macvlan MAC address [ OK ]
# TEST: VLAN upper: Unicast IPv4 to unknown MAC address [ OK ]
# TEST: VLAN upper: Unicast IPv4 to unknown MAC address, promisc [ OK ]
# TEST: VLAN upper: Unicast IPv4 to unknown MAC address, allmulti [ OK ]
# TEST: VLAN upper: Multicast IPv4 to joined group [ OK ]
# TEST: VLAN upper: Multicast IPv4 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN upper: Multicast IPv4 to unknown group, promisc [ OK ]
# TEST: VLAN upper: Multicast IPv4 to unknown group, allmulti [ OK ]
# TEST: VLAN upper: Multicast IPv6 to joined group [ OK ]
# TEST: VLAN upper: Multicast IPv6 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN upper: Multicast IPv6 to unknown group, promisc [ OK ]
# TEST: VLAN upper: Multicast IPv6 to unknown group, allmulti [ OK ]
# TEST: VLAN upper: Link-local STP BPDU [ OK ]
# TEST: VLAN upper: Link-local LLDP [ OK ]
# TEST: VLAN upper: 1588v2 over L2 transport, Sync [ OK ]
# TEST: VLAN upper: 1588v2 over L2 transport, Follow-Up [ OK ]
# TEST: VLAN upper: 1588v2 over L2 transport, Peer Delay Request [ OK ]
# TEST: VLAN upper: 1588v2 over IPv4, Sync [ OK ]
# TEST: VLAN upper: 1588v2 over IPv4, Follow-Up [ OK ]
# TEST: VLAN upper: 1588v2 over IPv4, Peer Delay Request [ OK ]
# TEST: VLAN upper: 1588v2 over IPv6, Sync [ OK ]
# TEST: VLAN upper: 1588v2 over IPv6, Follow-Up [ OK ]
# TEST: VLAN upper: 1588v2 over IPv6, Peer Delay Request [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Unicast IPv4 to primary MAC address [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Unicast IPv4 to macvlan MAC address [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Unicast IPv4 to unknown MAC address [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Unicast IPv4 to unknown MAC address, promisc [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Unicast IPv4 to unknown MAC address, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Multicast IPv4 to joined group [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Multicast IPv4 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN over vlan_filtering=0 bridged port: Multicast IPv4 to unknown group, promisc [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Multicast IPv4 to unknown group, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Multicast IPv6 to joined group [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Multicast IPv6 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN over vlan_filtering=0 bridged port: Multicast IPv6 to unknown group, promisc [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Multicast IPv6 to unknown group, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Link-local STP BPDU [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: Link-local LLDP [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over L2 transport, Sync [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over L2 transport, Follow-Up [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over L2 transport, Peer Delay Request [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over IPv4, Sync [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over IPv4, Follow-Up [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over IPv4, Peer Delay Request [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over IPv6, Sync [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over IPv6, Follow-Up [ OK ]
# TEST: VLAN over vlan_filtering=0 bridged port: 1588v2 over IPv6, Peer Delay Request [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Unicast IPv4 to primary MAC address [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Unicast IPv4 to macvlan MAC address [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Unicast IPv4 to unknown MAC address [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Unicast IPv4 to unknown MAC address, promisc [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Unicast IPv4 to unknown MAC address, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Multicast IPv4 to joined group [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Multicast IPv4 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN over vlan_filtering=1 bridged port: Multicast IPv4 to unknown group, promisc [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Multicast IPv4 to unknown group, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Multicast IPv6 to joined group [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Multicast IPv6 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN over vlan_filtering=1 bridged port: Multicast IPv6 to unknown group, promisc [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Multicast IPv6 to unknown group, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Link-local STP BPDU [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: Link-local LLDP [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over L2 transport, Sync [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over L2 transport, Follow-Up [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over L2 transport, Peer Delay Request [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over IPv4, Sync [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over IPv4, Follow-Up [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over IPv4, Peer Delay Request [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over IPv6, Sync [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over IPv6, Follow-Up [ OK ]
# TEST: VLAN over vlan_filtering=1 bridged port: 1588v2 over IPv6, Peer Delay Request [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Unicast IPv4 to primary MAC address [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Unicast IPv4 to macvlan MAC address [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Unicast IPv4 to unknown MAC address [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Unicast IPv4 to unknown MAC address, promisc [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Unicast IPv4 to unknown MAC address, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Multicast IPv4 to joined group [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Multicast IPv4 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN over vlan_filtering=0 bridge: Multicast IPv4 to unknown group, promisc [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Multicast IPv4 to unknown group, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Multicast IPv6 to joined group [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Multicast IPv6 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN over vlan_filtering=0 bridge: Multicast IPv6 to unknown group, promisc [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Multicast IPv6 to unknown group, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=0 bridge: Link-local STP BPDU [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Unicast IPv4 to primary MAC address [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Unicast IPv4 to macvlan MAC address [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Unicast IPv4 to unknown MAC address [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Unicast IPv4 to unknown MAC address, promisc [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Unicast IPv4 to unknown MAC address, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Multicast IPv4 to joined group [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Multicast IPv4 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN over vlan_filtering=1 bridge: Multicast IPv4 to unknown group, promisc [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Multicast IPv4 to unknown group, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Multicast IPv6 to joined group [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Multicast IPv6 to unknown group [XFAIL]
# reception succeeded, but should have failed
# TEST: VLAN over vlan_filtering=1 bridge: Multicast IPv6 to unknown group, promisc [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Multicast IPv6 to unknown group, allmulti [ OK ]
# TEST: VLAN over vlan_filtering=1 bridge: Link-local STP BPDU [ OK ]
ok 1 selftests: net/forwarding: local_termination.sh
root@localhost:~/ksft-net-drv# cat VERSION
v7.0-rc3-1494-g8122e23405fc
root@localhost:~/git/linux# git log --oneline -11
8122e23405fc (HEAD -> 2026-03-04-net-selftests) selftests: drivers: hw: add test for the ethtool standard counters
120c98910361 selftests: drivers: hw: update ethtool_rmon to work with a single local interface
67eea516922b selftests: drivers: hw: move to KTAP output
4dc0de1901c8 selftests: drivers: hw: replace counter upper limit with UINT32_MAX in rmon test
adf6caeb2d0b selftests: drivers: hw: test rmon counters only on first interface
1ef526c90f90 selftests: drivers: hw: cleanup shellcheck warnings in the rmon test
a5a27ccb4231 selftests: net: update some helpers to use run_on
ca2fe56c8938 selftests: net: extend lib.sh to parse drivers/net/net.config
dc88ab221117 selftests: net: add helpers for running a command on other targets
8bc9c8a32701 selftests: forwarding: extend ethtool_std_stats_get with pause statistics
b08a76290c4e Merge branch 'net-dpaa2-mac-export-standard-statistics'
^ permalink raw reply
* [PATCH net V2 0/2] Correct BD length masks and BQL accounting for multi-BD TX packets
From: Suraj Gupta @ 2026-03-27 7:32 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Michal Simek, Sean Anderson, Daniel Borkmann, Ariane Keller,
netdev, linux-arm-kernel, linux-kernel
This patch series fixes two issues in the Xilinx AXI Ethernet driver:
1. Corrects the BD length masks to match the AXIDMA IP spec.
2. Fixes BQL accounting for multi-BD TX packets.
---
Changes in V2:
- Define BD length masks with GENMASK(25, 0) per PG021.
- Credit BQL using skb->len on packet completion instead of summing
per-BD actual lengths from descriptor status.
---
Suraj Gupta (2):
net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets
drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 9 ++++-----
2 files changed, 6 insertions(+), 7 deletions(-)
--
2.49.1
^ permalink raw reply
* [PATCH net V2 1/2] net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
From: Suraj Gupta @ 2026-03-27 7:32 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Michal Simek, Sean Anderson, Daniel Borkmann, Ariane Keller,
netdev, linux-arm-kernel, linux-kernel
In-Reply-To: <20260327073238.134948-1-suraj.gupta2@amd.com>
The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
product guide (PG021) specifies the buffer length field as bits 25:0
(26 bits). Update both masks to match the IP documentation.
In practice this had no functional impact, since Ethernet frames are
far smaller than 2^23 bytes and the extra bits were always zero, but
the masks should still reflect the hardware specification.
Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 5ff742103beb..fcd3aaef27fc 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -105,7 +105,7 @@
#define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
#define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
+#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
#define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
@@ -130,7 +130,7 @@
#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
+#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
#define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
#define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
#define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
--
2.49.1
^ permalink raw reply related
* [PATCH net V2 2/2] net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets
From: Suraj Gupta @ 2026-03-27 7:32 UTC (permalink / raw)
To: Radhey Shyam Pandey, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Michal Simek, Sean Anderson, Daniel Borkmann, Ariane Keller,
netdev, linux-arm-kernel, linux-kernel
In-Reply-To: <20260327073238.134948-1-suraj.gupta2@amd.com>
When a TX packet spans multiple buffer descriptors (scatter-gather),
axienet_free_tx_chain sums the per-BD actual length from descriptor
status into a caller-provided accumulator. That sum is reset on each
NAPI poll. If the BDs for a single packet complete across different
polls, the earlier bytes are lost and never credited to BQL. This
causes BQL to think bytes are permanently in-flight, eventually
stalling the TX queue.
The SKB pointer is stored only on the last BD of a packet. When that
BD completes, use skb->len for the byte count instead of summing
per-BD status lengths. This matches netdev_sent_queue(), which debits
skb->len, and naturally survives across polls because no partial
packet contributes to the accumulator.
Fixes: c900e49d58eb ("net: xilinx: axienet: Implement BQL")
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
---
drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index b06e4c37ff61..263c4b67fd5a 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -770,8 +770,8 @@ static int axienet_device_reset(struct net_device *ndev)
* @first_bd: Index of first descriptor to clean up
* @nr_bds: Max number of descriptors to clean up
* @force: Whether to clean descriptors even if not complete
- * @sizep: Pointer to a u32 filled with the total sum of all bytes
- * in all cleaned-up descriptors. Ignored if NULL.
+ * @sizep: Pointer to a u32 accumulating the total byte count of
+ * completed packets (using skb->len). Ignored if NULL.
* @budget: NAPI budget (use 0 when not called from NAPI poll)
*
* Would either be called after a successful transmit operation, or after
@@ -805,6 +805,8 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
DMA_TO_DEVICE);
if (cur_p->skb && (status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
+ if (sizep)
+ *sizep += cur_p->skb->len;
napi_consume_skb(cur_p->skb, budget);
packets++;
}
@@ -818,9 +820,6 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
wmb();
cur_p->cntrl = 0;
cur_p->status = 0;
-
- if (sizep)
- *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
}
if (!force) {
--
2.49.1
^ permalink raw reply related
* Re: [PATCH net-next 1/2] devlink: unify devlink_shd_get_priv() into devlink_priv()
From: Przemek Kitszel @ 2026-03-27 7:42 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Jiri Pirko, netdev, Tony Nguyen, intel-wired-lan,
Aleksandr Loktionov, edumazet, horms, pabeni, davem,
Michal Schmidt
In-Reply-To: <20260326143808.1fd69825@kernel.org>
On 3/26/26 22:38, Jakub Kicinski wrote:
> On Wed, 25 Mar 2026 07:26:52 +0100 Przemek Kitszel wrote:
>> Current API makes it possible to access shared devlink instance's priv
>> data:
>>
>> void *devlink_shd_get_priv(struct devlink *devlink);
>>
>> but it is easy to forget (especially during rebase from "before shared
>> devlinks" era) and call:
>>
>> void *devlink_priv(struct devlink *devlink);
>>
>> which even has the same signature, so it's hard to catch the error.
>
> The implicit conversion may make things hard to reason about.
hmm...
now we have simple devlink code with a possibility of hard to detect bug
in drivers, plus hypothetical drivers code that we will need to reason
about. I would replace that for:
"complex devlink code", which will be harder to review, but then without
bugs and with hypothetical drivers code that would not require reasoning
at all (one API call == no decision, and no checking for correctness
later, when someone will be hunting an unrelated bug)
Anyway, I have used "hypothetical drivers code" twice, so maybe it will
be best to forgo this patch. I will just call correct functions in ice,
and we will wait for other users with priv data on shd devlink to see
if they struggle.
The priv_to_devlink issue that Alex pointed out will remain unresolved,
although it's easy to just keep the devlink pointer in priv (as I will
do in ice).
Thank you.
> Are you sure you actually mean that it's "easy to forget" or
> it's easier for OOT transition?
I have literally forgot to change (written from scratch for upstream)
code, in the part that was rebased conflict-free. I guess, I was the
only person that were in need of devlink-shared, with code ready to
rebase over Jiri's work. And I'm done, so there is not much relevance
now for this point.
>
> If we are worried about misuse we should instead add an accessor
> for "individual" (better name welcome) instance and WARN_ON()
> when devlink_priv() is used in the shared setup.
that would require the same amount of code as this patch (curr ver)
has, only with WARN_ON() instead proper value (IOW: we detect what
developer wanted, and give them big warning instead)
I'm not interested :)
>
> Or add a third argument to devlink_priv() which will pass the size
> of the LHS ptr, and warn on attempts to access priv of the wrong
> size?
this could incidentally match sizeof(devlink_shd) :P
^ permalink raw reply
* [PATCH iwl-net] ice: fix PTP timestamping broken by SyncE code on E825C
From: Petr Oros @ 2026-03-27 7:46 UTC (permalink / raw)
To: netdev
Cc: stable, Petr Oros, Tony Nguyen, Przemek Kitszel, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran, Arkadiusz Kubalewski, Grzegorz Nitka,
Aleksandr Loktionov, Ivan Vecera, intel-wired-lan, linux-kernel
The E825C SyncE support added in commit ad1df4f2d591 ("ice: dpll:
Support E825-C SyncE and dynamic pin discovery") introduced a SyncE
reconfiguration block in ice_ptp_link_change() that prevents
ice_ptp_port_phy_restart() from being called in several error paths.
Without the PHY restart, PTP timestamps stop working after any link
change event.
There are three ways the PHY restart gets blocked:
1. When DPLL initialization fails (e.g. missing ACPI firmware node
properties), ICE_FLAG_DPLL is not set and the function returns early
before reaching the PHY restart.
2. When ice_tspll_bypass_mux_active_e825c() fails to read the CGU
register, WARN_ON_ONCE fires and the function returns early.
3. When ice_tspll_cfg_synce_ethdiv_e825c() fails to configure the
clock divider for an active pin, same early return.
SyncE and PTP are independent features. SyncE reconfiguration failures
must not prevent the PTP PHY restart that is essential for timestamp
recovery after link changes.
Fix by making the entire SyncE block conditional on ICE_FLAG_DPLL
without an early return, and replacing the WARN_ON_ONCE + return error
handling inside the loop with dev_err_once + break. The function always
proceeds to ice_ptp_port_phy_restart() regardless of SyncE errors.
Fixes: ad1df4f2d591 ("ice: dpll: Support E825-C SyncE and dynamic pin discovery")
Signed-off-by: Petr Oros <poros@redhat.com>
---
drivers/net/ethernet/intel/ice/ice_ptp.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 094e96219f4565..60bc47099432a2 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -1296,12 +1296,10 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
if (pf->hw.reset_ongoing)
return;
- if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) {
+ if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 &&
+ test_bit(ICE_FLAG_DPLL, pf->flags)) {
int pin, err;
- if (!test_bit(ICE_FLAG_DPLL, pf->flags))
- return;
-
mutex_lock(&pf->dplls.lock);
for (pin = 0; pin < ICE_SYNCE_CLK_NUM; pin++) {
enum ice_synce_clk clk_pin;
@@ -1314,15 +1312,19 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
port_num,
&active,
clk_pin);
- if (WARN_ON_ONCE(err)) {
- mutex_unlock(&pf->dplls.lock);
- return;
+ if (err) {
+ dev_err_once(ice_pf_to_dev(pf),
+ "Failed to read SyncE bypass mux for pin %d, err %d\n",
+ pin, err);
+ break;
}
err = ice_tspll_cfg_synce_ethdiv_e825c(hw, clk_pin);
- if (active && WARN_ON_ONCE(err)) {
- mutex_unlock(&pf->dplls.lock);
- return;
+ if (active && err) {
+ dev_err_once(ice_pf_to_dev(pf),
+ "Failed to configure SyncE ETH divider for pin %d, err %d\n",
+ pin, err);
+ break;
}
}
mutex_unlock(&pf->dplls.lock);
--
2.52.0
^ permalink raw reply related
* RE: [Intel-wired-lan] [PATCH v4 net-next 7/8] ice: add Tx reference clock index handling to AN restart command
From: Loktionov, Aleksandr @ 2026-03-27 7:58 UTC (permalink / raw)
To: Nitka, Grzegorz, netdev@vger.kernel.org
Cc: Vecera, Ivan, vadim.fedorenko@linux.dev, kuba@kernel.org,
jiri@resnulli.us, edumazet@google.com, Kitszel, Przemyslaw,
richardcochran@gmail.com, donald.hunter@gmail.com,
linux-kernel@vger.kernel.org, Kubalewski, Arkadiusz,
andrew+netdev@lunn.ch, intel-wired-lan@lists.osuosl.org,
horms@kernel.org, Prathosh.Satish@microchip.com,
Nguyen, Anthony L, pabeni@redhat.com, davem@davemloft.net
In-Reply-To: <20260326162832.3135857-8-grzegorz.nitka@intel.com>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of Grzegorz Nitka
> Sent: Thursday, March 26, 2026 5:29 PM
> To: netdev@vger.kernel.org
> Cc: Vecera, Ivan <ivecera@redhat.com>; vadim.fedorenko@linux.dev;
> kuba@kernel.org; jiri@resnulli.us; edumazet@google.com; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>; richardcochran@gmail.com;
> donald.hunter@gmail.com; linux-kernel@vger.kernel.org; Kubalewski,
> Arkadiusz <arkadiusz.kubalewski@intel.com>; andrew+netdev@lunn.ch;
> intel-wired-lan@lists.osuosl.org; horms@kernel.org;
> Prathosh.Satish@microchip.com; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; pabeni@redhat.com; davem@davemloft.net
> Subject: [Intel-wired-lan] [PATCH v4 net-next 7/8] ice: add Tx
> reference clock index handling to AN restart command
>
> Extend the Restart Auto-Negotiation (AN) AdminQ command with a new
> parameter allowing software to specify the Tx reference clock index to
> be used during link restart.
>
> This patch:
> - adds REFCLK field definitions to ice_aqc_restart_an
> - updates ice_aq_set_link_restart_an() to take a new refclk parameter
> and properly encode it into the command
> - keeps legacy behavior by passing REFCLK_NOCHANGE where appropriate
>
> This prepares the driver for configurations requiring dynamic
> selection of the Tx reference clock as part of the AN flow.
>
> Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
> Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
> ---
> drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 ++
> drivers/net/ethernet/intel/ice/ice_common.c | 5 ++++-
> drivers/net/ethernet/intel/ice/ice_common.h | 2 +-
> drivers/net/ethernet/intel/ice/ice_lib.c | 3 ++-
> 4 files changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> index 859e9c66f3e7..a24a0613d887 100644
> --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> @@ -1169,6 +1169,8 @@ struct ice_aqc_restart_an {
> u8 cmd_flags;
> #define ICE_AQC_RESTART_AN_LINK_RESTART BIT(1)
> #define ICE_AQC_RESTART_AN_LINK_ENABLE BIT(2)
> +#define ICE_AQC_RESTART_AN_REFCLK_M GENMASK(4, 3)
> +#define ICE_AQC_RESTART_AN_REFCLK_NOCHANGE 0
> u8 reserved2[13];
> };
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.c
> b/drivers/net/ethernet/intel/ice/ice_common.c
> index ce11fea122d0..de88aec9137c 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.c
> +++ b/drivers/net/ethernet/intel/ice/ice_common.c
> @@ -4126,12 +4126,13 @@ int ice_get_link_status(struct ice_port_info
> *pi, bool *link_up)
> * @pi: pointer to the port information structure
> * @ena_link: if true: enable link, if false: disable link
> * @cd: pointer to command details structure or NULL
> + * @refclk: the new TX reference clock, 0 if no change
> *
> * Sets up the link and restarts the Auto-Negotiation over the link.
> */
> int
> ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
> - struct ice_sq_cd *cd)
> + struct ice_sq_cd *cd, u8 refclk)
> {
> struct ice_aqc_restart_an *cmd;
> struct libie_aq_desc desc;
> @@ -4147,6 +4148,8 @@ ice_aq_set_link_restart_an(struct ice_port_info
> *pi, bool ena_link,
> else
> cmd->cmd_flags &= ~ICE_AQC_RESTART_AN_LINK_ENABLE;
>
> + cmd->cmd_flags |= FIELD_PREP(ICE_AQC_RESTART_AN_REFCLK_M,
> refclk);
> +
> return ice_aq_send_cmd(pi->hw, &desc, NULL, 0, cd); }
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.h
> b/drivers/net/ethernet/intel/ice/ice_common.h
> index e700ac0dc347..9f5344212195 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.h
> +++ b/drivers/net/ethernet/intel/ice/ice_common.h
> @@ -215,7 +215,7 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct
> ice_aqc_set_phy_cfg_data *cfg,
> enum ice_fec_mode fec);
> int
> ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
> - struct ice_sq_cd *cd);
> + struct ice_sq_cd *cd, u8 refclk);
> int
> ice_aq_set_mac_cfg(struct ice_hw *hw, u16 max_frame_size, struct
> ice_sq_cd *cd); int diff --git
> a/drivers/net/ethernet/intel/ice/ice_lib.c
> b/drivers/net/ethernet/intel/ice/ice_lib.c
> index 689c6025ea82..c2c7f186bcc7 100644
> --- a/drivers/net/ethernet/intel/ice/ice_lib.c
> +++ b/drivers/net/ethernet/intel/ice/ice_lib.c
> @@ -3769,7 +3769,8 @@ int ice_set_link(struct ice_vsi *vsi, bool ena)
> if (vsi->type != ICE_VSI_PF)
> return -EINVAL;
>
> - status = ice_aq_set_link_restart_an(pi, ena, NULL);
> + status = ice_aq_set_link_restart_an(pi, ena, NULL,
> +
> ICE_AQC_RESTART_AN_REFCLK_NOCHANGE);
>
> /* if link is owned by manageability, FW will return
> LIBIE_AQ_RC_EMODE.
> * this is not a fatal error, so print a warning message and
> return
> --
> 2.39.3
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
^ permalink raw reply
* [PATCH net-next v2 01/13] net: renesas: rswitch: improve port change mode functions
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
For ETHA and GWCA ports every mode change from operational to
configuration and vice-versa requires to change the mode to
"disable" first. This was done by calling the function twice.
Let the change_mode functione take care of this requiered step
in a single call.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch_main.c | 39 +++++++++++++----------------
1 file changed, 18 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/renesas/rswitch_main.c b/drivers/net/ethernet/renesas/rswitch_main.c
index 6fe964816322..f6d1e610e7fa 100644
--- a/drivers/net/ethernet/renesas/rswitch_main.c
+++ b/drivers/net/ethernet/renesas/rswitch_main.c
@@ -176,14 +176,19 @@ static int rswitch_gwca_change_mode(struct rswitch_private *priv,
if (!rswitch_agent_clock_is_enabled(priv->addr, priv->gwca.index))
rswitch_agent_clock_ctrl(priv->addr, priv->gwca.index, 1);
- iowrite32(mode, priv->addr + GWMC);
+ iowrite32(GWMC_OPC_DISABLE, priv->addr + GWMC);
- ret = rswitch_reg_wait(priv->addr, GWMS, GWMS_OPS_MASK, mode);
+ ret = rswitch_reg_wait(priv->addr, GWMS, GWMS_OPS_MASK, GWMC_OPC_DISABLE);
- if (mode == GWMC_OPC_DISABLE)
+ if (mode == GWMC_OPC_DISABLE) {
rswitch_agent_clock_ctrl(priv->addr, priv->gwca.index, 0);
- return ret;
+ return ret;
+ }
+
+ iowrite32(mode, priv->addr + GWMC);
+
+ return rswitch_reg_wait(priv->addr, GWMS, GWMS_OPS_MASK, mode);
}
static int rswitch_gwca_mcast_table_reset(struct rswitch_private *priv)
@@ -682,9 +687,6 @@ static int rswitch_gwca_hw_init(struct rswitch_private *priv)
unsigned int i;
int err;
- err = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE);
- if (err < 0)
- return err;
err = rswitch_gwca_change_mode(priv, GWMC_OPC_CONFIG);
if (err < 0)
return err;
@@ -717,9 +719,6 @@ static int rswitch_gwca_hw_init(struct rswitch_private *priv)
return err;
}
- err = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE);
- if (err < 0)
- return err;
return rswitch_gwca_change_mode(priv, GWMC_OPC_OPERATION);
}
@@ -727,9 +726,6 @@ static int rswitch_gwca_hw_deinit(struct rswitch_private *priv)
{
int err;
- err = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE);
- if (err < 0)
- return err;
err = rswitch_gwca_change_mode(priv, GWMC_OPC_RESET);
if (err < 0)
return err;
@@ -1116,14 +1112,18 @@ static int rswitch_etha_change_mode(struct rswitch_etha *etha,
if (!rswitch_agent_clock_is_enabled(etha->coma_addr, etha->index))
rswitch_agent_clock_ctrl(etha->coma_addr, etha->index, 1);
- iowrite32(mode, etha->addr + EAMC);
-
- ret = rswitch_reg_wait(etha->addr, EAMS, EAMS_OPS_MASK, mode);
+ iowrite32(EAMC_OPC_DISABLE, etha->addr + EAMC);
+ ret = rswitch_reg_wait(etha->addr, EAMS, EAMS_OPS_MASK, EAMC_OPC_DISABLE);
- if (mode == EAMC_OPC_DISABLE)
+ if (mode == EAMC_OPC_DISABLE) {
rswitch_agent_clock_ctrl(etha->coma_addr, etha->index, 0);
- return ret;
+ return ret;
+ }
+
+ iowrite32(mode, etha->addr + EAMC);
+
+ return rswitch_reg_wait(etha->addr, EAMS, EAMS_OPS_MASK, mode);
}
static void rswitch_etha_read_mac_address(struct rswitch_etha *etha)
@@ -1203,9 +1203,6 @@ static int rswitch_etha_hw_init(struct rswitch_etha *etha, const u8 *mac)
{
int err;
- err = rswitch_etha_change_mode(etha, EAMC_OPC_DISABLE);
- if (err < 0)
- return err;
err = rswitch_etha_change_mode(etha, EAMC_OPC_CONFIG);
if (err < 0)
return err;
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 02/13] net: renesas: rswitch: use device instead of net_device
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
In upcomming changes for adding vlan support struct net_device
will not be available in all cases, therefore use struct device
instead.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch_main.c | 34 ++++++++++++++---------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/renesas/rswitch_main.c b/drivers/net/ethernet/renesas/rswitch_main.c
index f6d1e610e7fa..f10e188bc0bd 100644
--- a/drivers/net/ethernet/renesas/rswitch_main.c
+++ b/drivers/net/ethernet/renesas/rswitch_main.c
@@ -302,13 +302,13 @@ static int rswitch_gwca_queue_alloc_rx_buf(struct rswitch_gwca_queue *gq,
return -ENOMEM;
}
-static void rswitch_gwca_queue_free(struct net_device *ndev,
+static void rswitch_gwca_queue_free(struct device *dev,
struct rswitch_gwca_queue *gq)
{
unsigned int i;
if (!gq->dir_tx) {
- dma_free_coherent(ndev->dev.parent,
+ dma_free_coherent(dev,
sizeof(struct rswitch_ext_ts_desc) *
(gq->ring_size + 1), gq->rx_ring, gq->ring_dma);
gq->rx_ring = NULL;
@@ -318,7 +318,7 @@ static void rswitch_gwca_queue_free(struct net_device *ndev,
kfree(gq->rx_bufs);
gq->rx_bufs = NULL;
} else {
- dma_free_coherent(ndev->dev.parent,
+ dma_free_coherent(dev,
sizeof(struct rswitch_ext_desc) *
(gq->ring_size + 1), gq->tx_ring, gq->ring_dma);
gq->tx_ring = NULL;
@@ -357,7 +357,7 @@ static int rswitch_gwca_queue_alloc(struct net_device *ndev,
if (rswitch_gwca_queue_alloc_rx_buf(gq, 0, gq->ring_size) < 0)
goto out;
- gq->rx_ring = dma_alloc_coherent(ndev->dev.parent,
+ gq->rx_ring = dma_alloc_coherent(&priv->pdev->dev,
sizeof(struct rswitch_ext_ts_desc) *
(gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL);
} else {
@@ -367,7 +367,7 @@ static int rswitch_gwca_queue_alloc(struct net_device *ndev,
gq->unmap_addrs = kzalloc_objs(*gq->unmap_addrs, gq->ring_size);
if (!gq->unmap_addrs)
goto out;
- gq->tx_ring = dma_alloc_coherent(ndev->dev.parent,
+ gq->tx_ring = dma_alloc_coherent(&priv->pdev->dev,
sizeof(struct rswitch_ext_desc) *
(gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL);
}
@@ -385,7 +385,7 @@ static int rswitch_gwca_queue_alloc(struct net_device *ndev,
return 0;
out:
- rswitch_gwca_queue_free(ndev, gq);
+ rswitch_gwca_queue_free(&priv->pdev->dev, gq);
return -ENOMEM;
}
@@ -467,12 +467,11 @@ static void rswitch_gwca_ts_queue_fill(struct rswitch_private *priv,
}
}
-static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev,
+static int rswitch_gwca_queue_ext_ts_fill(struct device *dev,
struct rswitch_gwca_queue *gq,
unsigned int start_index,
unsigned int num)
{
- struct rswitch_device *rdev = netdev_priv(ndev);
struct rswitch_ext_ts_desc *desc;
unsigned int i, index;
dma_addr_t dma_addr;
@@ -481,18 +480,17 @@ static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev,
index = (i + start_index) % gq->ring_size;
desc = &gq->rx_ring[index];
if (!gq->dir_tx) {
- dma_addr = dma_map_single(ndev->dev.parent,
+ dma_addr = dma_map_single(dev,
gq->rx_bufs[index] + RSWITCH_HEADROOM,
RSWITCH_MAP_BUF_SIZE,
DMA_FROM_DEVICE);
- if (dma_mapping_error(ndev->dev.parent, dma_addr))
+ if (dma_mapping_error(dev, dma_addr))
goto err;
desc->desc.info_ds = cpu_to_le16(RSWITCH_DESC_BUF_SIZE);
rswitch_desc_set_dptr(&desc->desc, dma_addr);
dma_wmb();
desc->desc.die_dt = DT_FEMPTY | DIE;
- desc->info1 = cpu_to_le64(INFO1_SPN(rdev->etha->index));
} else {
desc->desc.die_dt = DT_EEMPTY | DIE;
}
@@ -506,7 +504,7 @@ static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev,
index = (i + start_index) % gq->ring_size;
desc = &gq->rx_ring[index];
dma_addr = rswitch_desc_get_dptr(&desc->desc);
- dma_unmap_single(ndev->dev.parent, dma_addr,
+ dma_unmap_single(dev, dma_addr,
RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE);
}
}
@@ -514,7 +512,7 @@ static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev,
return -ENOMEM;
}
-static int rswitch_gwca_queue_ext_ts_format(struct net_device *ndev,
+static int rswitch_gwca_queue_ext_ts_format(struct device *dev,
struct rswitch_private *priv,
struct rswitch_gwca_queue *gq)
{
@@ -524,7 +522,7 @@ static int rswitch_gwca_queue_ext_ts_format(struct net_device *ndev,
int err;
memset(gq->rx_ring, 0, ring_size);
- err = rswitch_gwca_queue_ext_ts_fill(ndev, gq, 0, gq->ring_size);
+ err = rswitch_gwca_queue_ext_ts_fill(dev, gq, 0, gq->ring_size);
if (err < 0)
return err;
@@ -636,7 +634,7 @@ static void rswitch_txdmac_free(struct net_device *ndev)
{
struct rswitch_device *rdev = netdev_priv(ndev);
- rswitch_gwca_queue_free(ndev, rdev->tx_queue);
+ rswitch_gwca_queue_free(ndev->dev.parent, rdev->tx_queue);
rswitch_gwca_put(rdev->priv, rdev->tx_queue);
}
@@ -670,7 +668,7 @@ static void rswitch_rxdmac_free(struct net_device *ndev)
{
struct rswitch_device *rdev = netdev_priv(ndev);
- rswitch_gwca_queue_free(ndev, rdev->rx_queue);
+ rswitch_gwca_queue_free(ndev->dev.parent, rdev->rx_queue);
rswitch_gwca_put(rdev->priv, rdev->rx_queue);
}
@@ -679,7 +677,7 @@ static int rswitch_rxdmac_init(struct rswitch_private *priv, unsigned int index)
struct rswitch_device *rdev = priv->rdev[index];
struct net_device *ndev = rdev->ndev;
- return rswitch_gwca_queue_ext_ts_format(ndev, priv, rdev->rx_queue);
+ return rswitch_gwca_queue_ext_ts_format(ndev->dev.parent, priv, rdev->rx_queue);
}
static int rswitch_gwca_hw_init(struct rswitch_private *priv)
@@ -870,7 +868,7 @@ static bool rswitch_rx(struct net_device *ndev, int *quota)
ret = rswitch_gwca_queue_alloc_rx_buf(gq, gq->dirty, num);
if (ret < 0)
goto err;
- ret = rswitch_gwca_queue_ext_ts_fill(ndev, gq, gq->dirty, num);
+ ret = rswitch_gwca_queue_ext_ts_fill(ndev->dev.parent, gq, gq->dirty, num);
if (ret < 0)
goto err;
gq->dirty = rswitch_next_queue_index(gq, false, num);
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 03/13] net: renesas: rswitch: fix FWPC2 register access macros
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
Fix typo in macro name and remove duplicate macro definition.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch.h | 3 +--
drivers/net/ethernet/renesas/rswitch_l2.c | 2 +-
drivers/net/ethernet/renesas/rswitch_main.c | 2 +-
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h
index aa605304fed0..340524d995ac 100644
--- a/drivers/net/ethernet/renesas/rswitch.h
+++ b/drivers/net/ethernet/renesas/rswitch.h
@@ -826,8 +826,7 @@ enum rswitch_gwca_mode {
#define FWPC1_DDE BIT(0)
#define FWPC2(i) (FWPC20 + (i) * 0x10)
-#define FWCP2_LTWFW GENMASK(16 + (RSWITCH_NUM_AGENTS - 1), 16)
-#define FWCP2_LTWFW_MASK GENMASK(16 + (RSWITCH_NUM_AGENTS - 1), 16)
+#define FWPC2_LTWFW GENMASK(16 + (RSWITCH_NUM_AGENTS - 1), 16)
#define FWPBFC(i) (FWPBFC0 + (i) * 0x10)
#define FWPBFC_PBDV GENMASK(RSWITCH_NUM_AGENTS - 1, 0)
diff --git a/drivers/net/ethernet/renesas/rswitch_l2.c b/drivers/net/ethernet/renesas/rswitch_l2.c
index 9433cd8adced..709524c8a5c4 100644
--- a/drivers/net/ethernet/renesas/rswitch_l2.c
+++ b/drivers/net/ethernet/renesas/rswitch_l2.c
@@ -82,7 +82,7 @@ static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv)
*
* Do not allow L2 forwarding to self for hw port.
*/
- iowrite32(FIELD_PREP(FWCP2_LTWFW_MASK, fwd_mask | BIT(rdev->port)),
+ iowrite32(FIELD_PREP(FWPC2_LTWFW, fwd_mask | BIT(rdev->port)),
priv->addr + FWPC2(rdev->port));
}
diff --git a/drivers/net/ethernet/renesas/rswitch_main.c b/drivers/net/ethernet/renesas/rswitch_main.c
index f10e188bc0bd..d404bc41bd1e 100644
--- a/drivers/net/ethernet/renesas/rswitch_main.c
+++ b/drivers/net/ethernet/renesas/rswitch_main.c
@@ -129,7 +129,7 @@ static int rswitch_fwd_init(struct rswitch_private *priv)
iowrite32(FIELD_PREP(FWCP1_LTHFW, all_ports_mask),
priv->addr + FWPC1(i));
/* Disallow L2 forwarding */
- iowrite32(FIELD_PREP(FWCP2_LTWFW, all_ports_mask),
+ iowrite32(FIELD_PREP(FWPC2_LTWFW, all_ports_mask),
priv->addr + FWPC2(i));
/* Disallow port based forwarding */
iowrite32(0, priv->addr + FWPBFC(i));
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 04/13] net: renesas: rswitch: add register definitions for vlan support
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
Add missing register and bit definitions for vlan support.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch.h | 156 ++++++++++++++++++++++++++++++++-
1 file changed, 152 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h
index 340524d995ac..15d3fa48b0e3 100644
--- a/drivers/net/ethernet/renesas/rswitch.h
+++ b/drivers/net/ethernet/renesas/rswitch.h
@@ -7,8 +7,10 @@
#ifndef __RSWITCH_H__
#define __RSWITCH_H__
+#include <linux/if_vlan.h>
#include <linux/platform_device.h>
#include <linux/phy.h>
+#include <net/switchdev.h>
#include "rcar_gen4_ptp.h"
@@ -221,7 +223,7 @@ enum rswitch_reg {
FWMACTL1 = FWRO + 0x4634,
FWMACTL2 = FWRO + 0x4638,
FWMACTL3 = FWRO + 0x463c,
- FWMACTL4 = FWRO + 0x4640,
+ FWMACTL40 = FWRO + 0x4640,
FWMACTL5 = FWRO + 0x4650,
FWMACTLR = FWRO + 0x4654,
FWMACTIM = FWRO + 0x4660,
@@ -249,7 +251,7 @@ enum rswitch_reg {
FWVLANTL0 = FWRO + 0x4910,
FWVLANTL1 = FWRO + 0x4914,
FWVLANTL2 = FWRO + 0x4918,
- FWVLANTL3 = FWRO + 0x4920,
+ FWVLANTL30 = FWRO + 0x4920,
FWVLANTL4 = FWRO + 0x4930,
FWVLANTLR = FWRO + 0x4934,
FWVLANTIM = FWRO + 0x4940,
@@ -508,7 +510,7 @@ enum rswitch_reg {
EACTDQMLM = TARO + 0x010c,
EAVCC = TARO + 0x0130,
EAVTC = TARO + 0x0134,
- EATTFC = TARO + 0x0138,
+ EARTFC = TARO + 0x0138,
EACAEC = TARO + 0x0200,
EACC = TARO + 0x0204,
EACAIVC0 = TARO + 0x0220,
@@ -729,6 +731,41 @@ enum rswitch_etha_mode {
#define EAMS_OPS_MASK EAMC_OPC_OPERATION
+/* bit field definitions for EAVCC and GWVCC */
+#define VEM GENMASK(18, 16)
+#define VIM BIT(0)
+
+/* bit field definitions for EAVTC and GWVTC */
+#define STD BIT(31)
+#define STP GENMASK(30, 28)
+#define STV GENMASK(27, 16)
+#define CTD BIT(15)
+#define CTP GENMASK(14, 12)
+#define CTV GENMASK(11, 0)
+
+/* bit field definitions for EARTFC and GWTTCF */
+#define UT BIT(8)
+#define SCRT BIT(7)
+#define SCT BIT(6)
+#define CRT BIT(5)
+#define CT BIT(4)
+#define CSRT BIT(3)
+#define CST BIT(2)
+#define RT BIT(1)
+#define NT BIT(0)
+
+/* bit field definitions for EARDQDC and GWRDQDC */
+#define DQD GENMASK(10, 0)
+#define DES_RAM_DP 0x400
+
+enum vlan_egress_mode {
+ NO_VLAN,
+ C_TAG_VLAN,
+ HW_C_TAG_VLAN,
+ SC_TAG_VLAN,
+ HW_SC_TAG_VLAN,
+};
+
#define EAVCC_VEM_SC_TAG (0x3 << 16)
#define MPIC_PIS GENMASK(2, 0)
@@ -806,6 +843,22 @@ enum rswitch_gwca_mode {
#define CABPPFLC_INIT_VALUE 0x00800080
/* MFWD */
+#define FWGC_SVM GENMASK(1, 0)
+
+enum switch_vlan_mode {
+ NO_VLAN_MODE,
+ C_TAG,
+ SC_TAG,
+};
+
+/* FWCEPRC2 */
+#define FDMACSLFEF BIT(19)
+#define FDMACUFEF BIT(3)
+
+/* FWCEPTC */
+#define EPCS GENMASK(17, 16)
+#define EPCSD GENMASK(6, 0)
+
#define FWPC0(i) (FWPC00 + (i) * 0x10)
#define FWPC0_LTHTA BIT(0)
#define FWPC0_IP4UE BIT(3)
@@ -816,10 +869,13 @@ enum rswitch_gwca_mode {
#define FWPC0_IPDSA BIT(12)
#define FWPC0_IPHLA BIT(18)
#define FWPC0_MACDSA BIT(20)
+#define FWPC0_MACRUDA BIT(21)
#define FWPC0_MACSSA BIT(23)
#define FWPC0_MACHLA BIT(26)
#define FWPC0_MACHMA BIT(27)
#define FWPC0_VLANSA BIT(28)
+#define FWPC0_VLANRU BIT(29)
+#define FWPC0_VLANRUS BIT(30)
#define FWPC1(i) (FWPC10 + (i) * 0x10)
#define FWCP1_LTHFW GENMASK(16 + (RSWITCH_NUM_AGENTS - 1), 16)
@@ -847,6 +903,98 @@ enum rswitch_gwca_mode {
#define FWMACAGC_MACAGOG BIT(28)
#define FWMACAGC_MACDESOG BIT(29)
+//FWMACTL0
+#define FWMACTL0_ED BIT(16)
+#define FWMACTL0_HLD BIT(10)
+#define FWMACTL0_DE BIT(9)
+#define FWMACTL0_SL BIT(8)
+
+//FWMACTL3
+#define FWMACTL3_DSLV GENMASK(16 + RSWITCH_NUM_AGENTS - 1, 16)
+#define FWMACTL3_SSLV GENMASK(RSWITCH_NUM_AGENTS - 1, 0)
+
+//FWMACTL4
+#define FWMACTL4(i) (FWMACTL40 + (i) * 4)
+#define FWMACTL4_CSDL GENMASK(6, 0)
+
+//FWMACTL5
+#define FWMACTL5_CME BIT(21)
+#define FWMACTL5_EME BIT(20)
+#define FWMACTL5_IPU BIT(19)
+#define FWMACTL5_IPV GENMASK(18, 16)
+#define FWMACTL5_DV GENMASK(6, 0)
+
+//FWMACTLR
+#define FWMACTLR_L BIT(31)
+#define FWMACTLR_LCN GENMASK(25, 16)
+#define FWMACTLR_LO BIT(3)
+#define FWMACTLR_LEF BIT(2)
+#define FWMACTLR_LSF BIT(1)
+#define FWMACTLR_LF BIT(0)
+
+// FWVLANTEC
+#define VLANTMUE GENMASK(28, 16)
+
+// FWVLANTL0
+#define VLANED BIT(16)
+#define VLANHLDL BIT(10)
+#define VLANSLL BIT(8)
+
+// FWVLANTL1
+#define VLANVIDL GENMASK(11, 0)
+
+// FWVLANTL2
+#define VLANSLVL GENMASK(6, 0)
+
+// FWVLANTL3
+#define FWVLANTL3(i) (FWVLANTL30 + (i) * 4)
+#define VLANCSDL GENMASK(6, 0)
+
+// FWVLANTL4
+#define VLANCMEL BIT(21)
+#define VLANEMEL BIT(20)
+#define VLANIPUL BIT(19)
+#define VLANIPVL GENMASK(18, 16)
+#define VLANDVL GENMASK(6, 0)
+
+// FWVLANTLR
+#define VLANTL BIT(31)
+#define VLANLO BIT(3)
+#define VLANLEF BIT(2)
+#define VLANLSF BIT(1)
+#define VLANLF BIT(0)
+
+// FWVLANTIM
+#define VLANTR BIT(1)
+#define VLANTIOG BIT(0)
+
+// FWVLANTEM
+#define VLANTUEN GENMASK(28, 16)
+#define VLANTEN GENAMSK(12, 0)
+
+// FWVLANTS
+#define VLANVIDS GENMASK(11, 0)
+
+// FWVLANTSR0
+#define VLANTS BIT(31)
+#define VLANHLDS BIT(10)
+#define VLANSLS BIT(8)
+#define VLANSNF BIT(1)
+#define VLANSEF BIT(0)
+
+// FWVLANTSR1
+#define VLANSLVS GENMASK(6, 0)
+
+// FWVLANTSR2
+#define FWVLANTSR2(i) (FWVLANTSR20 + (i) * 4)
+
+// FWVLANTSR3
+#define VLANCMES BIT(21)
+#define VLANEMES BIT(20)
+#define VLANIPUS BIT(19)
+#define VLANIPVS GENMASK(18, 16)
+#define VLANDVS GENMASK(6, 0)
+
#define RSW_AGEING_CLK_PER_US 0x140
#define RSW_AGEING_TIME 300
@@ -904,7 +1052,7 @@ enum DIE_DT {
#define INFO1_DV(port_vector) ((u64)(port_vector) << 48ULL)
/* For reception */
-#define INFO1_SPN(port) ((u64)(port) << 36ULL)
+#define SPN GENMASK_U64(38, 36)
/* For timestamp descriptor in dptrl (Byte 4 to 7) */
#define TS_DESC_TSUN(dptrl) ((dptrl) & GENMASK(7, 0))
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 05/13] net: renesas: rswitch: add exception path for packets with unknown dst MAC
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
Packets with unknown MAC address cannot be handled by the HW forwarding.
These need to be forwarded, via an exception path, to the network driver.
Creates a queue for the exeption path. Packets received with unknown
src/dst address need to be passed to the CPU. The received packet does not
have the correct source port information, this is derived from the
descriptor and added to the new queue. The received packet is added to the
new queue and sent to the CPU for MAC learning. The CPU will broadcast the
received packet, to all ports. This is how the HW learns the new MAC
address.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch.h | 1 +
drivers/net/ethernet/renesas/rswitch_main.c | 80 ++++++++++++++++++++++++++---
2 files changed, 74 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h
index 15d3fa48b0e3..bf123b564ed1 100644
--- a/drivers/net/ethernet/renesas/rswitch.h
+++ b/drivers/net/ethernet/renesas/rswitch.h
@@ -1148,6 +1148,7 @@ struct rswitch_gwca {
struct rswitch_gwca_queue *queues;
int num_queues;
struct rswitch_gwca_queue ts_queue;
+ struct rswitch_gwca_queue *l2_shared_rx_queue;
DECLARE_BITMAP(used, RSWITCH_MAX_NUM_QUEUES);
u32 tx_irq_bits[RSWITCH_NUM_IRQ_REGS];
u32 rx_irq_bits[RSWITCH_NUM_IRQ_REGS];
diff --git a/drivers/net/ethernet/renesas/rswitch_main.c b/drivers/net/ethernet/renesas/rswitch_main.c
index d404bc41bd1e..f8ceb7f66903 100644
--- a/drivers/net/ethernet/renesas/rswitch_main.c
+++ b/drivers/net/ethernet/renesas/rswitch_main.c
@@ -680,6 +680,34 @@ static int rswitch_rxdmac_init(struct rswitch_private *priv, unsigned int index)
return rswitch_gwca_queue_ext_ts_format(ndev->dev.parent, priv, rdev->rx_queue);
}
+static int rswitch_shared_rx_queue_alloc(struct rswitch_private *priv)
+{
+ struct rswitch_gwca *gwca = &priv->gwca;
+ struct device *dev = &priv->pdev->dev;
+
+ int err;
+
+ gwca->l2_shared_rx_queue = rswitch_gwca_get(priv);
+ if (!gwca->l2_shared_rx_queue)
+ return -EBUSY;
+
+ err = rswitch_gwca_queue_alloc(NULL, priv, gwca->l2_shared_rx_queue, false, RX_RING_SIZE);
+ if (err < 0) {
+ rswitch_gwca_put(priv, gwca->l2_shared_rx_queue);
+ return err;
+ }
+
+ return rswitch_gwca_queue_ext_ts_format(dev, priv, gwca->l2_shared_rx_queue);
+}
+
+static void rswitch_shared_rx_queue_free(struct rswitch_private *priv)
+{
+ struct rswitch_gwca *gwca = &priv->gwca;
+
+ rswitch_gwca_queue_free(&priv->pdev->dev, gwca->l2_shared_rx_queue);
+ rswitch_gwca_put(priv, gwca->l2_shared_rx_queue);
+}
+
static int rswitch_gwca_hw_init(struct rswitch_private *priv)
{
unsigned int i;
@@ -717,6 +745,12 @@ static int rswitch_gwca_hw_init(struct rswitch_private *priv)
return err;
}
+ err = rswitch_shared_rx_queue_alloc(priv);
+ if (err < 0) {
+ rswitch_shared_rx_queue_free(priv);
+ return err;
+ }
+
return rswitch_gwca_change_mode(priv, GWMC_OPC_OPERATION);
}
@@ -940,6 +974,7 @@ static int rswitch_poll(struct napi_struct *napi, int budget)
rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true);
rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true);
}
+ rswitch_enadis_data_irq(priv, priv->gwca.l2_shared_rx_queue->index, true);
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -952,15 +987,31 @@ static int rswitch_poll(struct napi_struct *napi, int budget)
return 0;
}
-static void rswitch_queue_interrupt(struct net_device *ndev)
+static void rswitch_queue_interrupt(struct rswitch_private *priv, struct rswitch_gwca_queue *gq)
{
- struct rswitch_device *rdev = netdev_priv(ndev);
+ struct rswitch_ext_ts_desc *desc;
+ struct rswitch_device *rdev;
+ struct net_device *ndev;
+ u32 spn;
+
+ if (gq->index == priv->gwca.l2_shared_rx_queue->index) {
+ desc = &gq->rx_ring[gq->cur];
+ spn = FIELD_GET(SPN, desc->info1);
+ ndev = priv->rdev[spn]->ndev;
+ rdev = netdev_priv(ndev);
+ gq->ndev = ndev;
+ rdev->rx_queue = gq;
+ } else {
+ rdev = netdev_priv(gq->ndev);
+ }
+
if (napi_schedule_prep(&rdev->napi)) {
- spin_lock(&rdev->priv->lock);
- rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false);
- rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false);
- spin_unlock(&rdev->priv->lock);
+ spin_lock(&priv->lock);
+ rswitch_enadis_data_irq(priv, rdev->tx_queue->index, false);
+ rswitch_enadis_data_irq(priv, rdev->rx_queue->index, false);
+ rswitch_enadis_data_irq(priv, priv->gwca.l2_shared_rx_queue->index, false);
+ spin_unlock(&priv->lock);
__napi_schedule(&rdev->napi);
}
}
@@ -978,7 +1029,7 @@ static irqreturn_t rswitch_data_irq(struct rswitch_private *priv, u32 *dis)
continue;
rswitch_ack_data_irq(priv, gq->index);
- rswitch_queue_interrupt(gq->ndev);
+ rswitch_queue_interrupt(priv, gq);
}
return IRQ_HANDLED;
@@ -1513,6 +1564,14 @@ static int rswitch_serdes_set_params(struct rswitch_device *rdev)
return phy_set_speed(rdev->serdes, rdev->etha->speed);
}
+static void rswitch_etha_set_exception_path(struct rswitch_private *priv)
+{
+ iowrite32(FDMACUFEF, priv->addr + FWCEPRC2);
+ iowrite32(FIELD_PREP(EPCSD, priv->gwca.l2_shared_rx_queue->index) |
+ FIELD_PREP(EPCSD, priv->gwca.l2_shared_rx_queue->index),
+ priv->addr + FWCEPTC);
+}
+
static int rswitch_ether_port_init_one(struct rswitch_device *rdev)
{
int err;
@@ -1566,6 +1625,8 @@ static int rswitch_ether_port_init_all(struct rswitch_private *priv)
unsigned int i;
int err;
+ rswitch_etha_set_exception_path(priv);
+
rswitch_for_each_enabled_port(priv, i) {
err = rswitch_ether_port_init_one(priv->rdev[i]);
if (err)
@@ -1616,6 +1677,7 @@ static int rswitch_open(struct net_device *ndev)
bitmap_set(rdev->priv->opened_ports, rdev->port, 1);
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, true);
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, true);
+ rswitch_enadis_data_irq(rdev->priv, rdev->priv->gwca.l2_shared_rx_queue->index, true);
spin_unlock_irqrestore(&rdev->priv->lock, flags);
phy_start(ndev->phydev);
@@ -1642,6 +1704,7 @@ static int rswitch_stop(struct net_device *ndev)
spin_lock_irqsave(&rdev->priv->lock, flags);
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false);
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false);
+ rswitch_enadis_data_irq(rdev->priv, rdev->priv->gwca.l2_shared_rx_queue->index, false);
bitmap_clear(rdev->priv->opened_ports, rdev->port, 1);
spin_unlock_irqrestore(&rdev->priv->lock, flags);
@@ -2166,6 +2229,9 @@ static int renesas_eth_sw_probe(struct platform_device *pdev)
priv->gwca.index = AGENT_INDEX_GWCA;
priv->gwca.num_queues = min(RSWITCH_NUM_PORTS * NUM_QUEUES_PER_NDEV,
RSWITCH_MAX_NUM_QUEUES);
+ /* One extra queue for L2 switch reception */
+ priv->gwca.num_queues = min(priv->gwca.num_queues + 1,
+ RSWITCH_MAX_NUM_QUEUES);
priv->gwca.queues = devm_kcalloc(&pdev->dev, priv->gwca.num_queues,
sizeof(*priv->gwca.queues), GFP_KERNEL);
if (!priv->gwca.queues)
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 06/13] net: renesas: rswitch: add forwarding rules for gwca
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
Add rules to forward packets from the Ethernet ports to the CPU port (GWCA)
using L2 forwarding instead of port forwarding.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch_l2.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/net/ethernet/renesas/rswitch_l2.c b/drivers/net/ethernet/renesas/rswitch_l2.c
index 709524c8a5c4..cabf1f92ad0c 100644
--- a/drivers/net/ethernet/renesas/rswitch_l2.c
+++ b/drivers/net/ethernet/renesas/rswitch_l2.c
@@ -93,10 +93,32 @@ static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv)
}
}
+static void rswitch_update_l2_hw_forwarding_gwca(struct rswitch_private *priv)
+{
+ struct rswitch_device *rdev;
+ u32 fwpc0_set, fwpc0_clr, fwpc2_set, fwpc2_clr;
+
+ fwpc0_clr = FWPC0_MACSSA | FWPC0_MACDSA | FWPC0_MACRUDA;
+ fwpc0_set = fwpc0_clr;
+ fwpc2_clr = FIELD_PREP(FWPC2_LTWFW, BIT(AGENT_INDEX_GWCA));
+ fwpc2_set = fwpc2_clr;
+
+ (priv->offload_brdev) ? (fwpc0_clr = 0, fwpc2_set = 0)
+ : (fwpc0_set = 0, fwpc2_set = 0);
+
+ rswitch_modify(priv->addr, FWPC0(AGENT_INDEX_GWCA), fwpc0_clr, fwpc0_set);
+
+ rswitch_for_all_ports(priv, rdev) {
+ rswitch_modify(priv->addr, FWPC2(rdev->etha->index),
+ fwpc2_clr, fwpc2_set);
+ }
+}
+
void rswitch_update_l2_offload(struct rswitch_private *priv)
{
rswitch_update_l2_hw_learning(priv);
rswitch_update_l2_hw_forwarding(priv);
+ rswitch_update_l2_hw_forwarding_gwca(priv);
}
static void rswitch_update_offload_brdev(struct rswitch_private *priv)
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 07/13] net: renesas: rswitch: make helper functions available to whole driver
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
These functions will be needed in L2 and vlan handling. Remove static
declaration and add function prototype to rswitch.h.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch.h | 6 ++++--
drivers/net/ethernet/renesas/rswitch_main.c | 12 ++++++------
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h
index bf123b564ed1..ff2a84057f01 100644
--- a/drivers/net/ethernet/renesas/rswitch.h
+++ b/drivers/net/ethernet/renesas/rswitch.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Renesas Ethernet Switch device driver
*
- * Copyright (C) 2022-2025 Renesas Electronics Corporation
+ * Copyright (C) 2022-2026 Renesas Electronics Corporation
*/
#ifndef __RSWITCH_H__
@@ -1218,5 +1218,7 @@ struct rswitch_private {
bool is_rdev(const struct net_device *ndev);
void rswitch_modify(void __iomem *addr, enum rswitch_reg reg, u32 clear, u32 set);
-
+int rswitch_reg_wait(void __iomem *addr, u32 offs, u32 mask, u32 expected);
+int rswitch_gwca_change_mode(struct rswitch_private *priv, enum rswitch_gwca_mode mode);
+int rswitch_etha_change_mode(struct rswitch_etha *etha, enum rswitch_etha_mode mode);
#endif /* #ifndef __RSWITCH_H__ */
diff --git a/drivers/net/ethernet/renesas/rswitch_main.c b/drivers/net/ethernet/renesas/rswitch_main.c
index f8ceb7f66903..b16f7aca4a69 100644
--- a/drivers/net/ethernet/renesas/rswitch_main.c
+++ b/drivers/net/ethernet/renesas/rswitch_main.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Renesas Ethernet Switch device driver
*
- * Copyright (C) 2022-2025 Renesas Electronics Corporation
+ * Copyright (C) 2022-2026 Renesas Electronics Corporation
*/
#include <linux/clk.h>
@@ -32,7 +32,7 @@
#define RSWITCH_GPTP_OFFSET_S4 0x00018000
-static int rswitch_reg_wait(void __iomem *addr, u32 offs, u32 mask, u32 expected)
+int rswitch_reg_wait(void __iomem *addr, u32 offs, u32 mask, u32 expected)
{
u32 val;
@@ -168,8 +168,8 @@ static int rswitch_fwd_init(struct rswitch_private *priv)
}
/* Gateway CPU agent block (GWCA) */
-static int rswitch_gwca_change_mode(struct rswitch_private *priv,
- enum rswitch_gwca_mode mode)
+int rswitch_gwca_change_mode(struct rswitch_private *priv,
+ enum rswitch_gwca_mode mode)
{
int ret;
@@ -1153,8 +1153,8 @@ static int rswitch_gwca_ts_request_irqs(struct rswitch_private *priv)
}
/* Ethernet TSN Agent block (ETHA) and Ethernet MAC IP block (RMAC) */
-static int rswitch_etha_change_mode(struct rswitch_etha *etha,
- enum rswitch_etha_mode mode)
+int rswitch_etha_change_mode(struct rswitch_etha *etha,
+ enum rswitch_etha_mode mode)
{
int ret;
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 08/13] net: renesas: rswitch: add basic vlan init to rswitch_fwd_init
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
Add basic vlan related register initialization.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch_main.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/renesas/rswitch_main.c b/drivers/net/ethernet/renesas/rswitch_main.c
index b16f7aca4a69..ac87175b918e 100644
--- a/drivers/net/ethernet/renesas/rswitch_main.c
+++ b/drivers/net/ethernet/renesas/rswitch_main.c
@@ -120,6 +120,7 @@ static int rswitch_fwd_init(struct rswitch_private *priv)
u32 all_ports_mask = GENMASK(RSWITCH_NUM_AGENTS - 1, 0);
unsigned int i;
u32 reg_val;
+ int ret;
/* Start with empty configuration */
for (i = 0; i < RSWITCH_NUM_AGENTS; i++) {
@@ -154,17 +155,27 @@ static int rswitch_fwd_init(struct rswitch_private *priv)
}
/* For GWCA port, allow direct descriptor forwarding */
- rswitch_modify(priv->addr, FWPC1(priv->gwca.index), FWPC1_DDE, FWPC1_DDE);
+ rswitch_modify(priv->addr, FWPC1(priv->gwca.index), 0, FWPC1_DDE);
/* Initialize hardware L2 forwarding table */
- /* Allow entire table to be used for "unsecure" entries */
+ /* Allow entire table to be used for "un-secure" entries */
rswitch_modify(priv->addr, FWMACHEC, 0, FWMACHEC_MACHMUE_MASK);
/* Initialize MAC hash table */
iowrite32(FWMACTIM_MACTIOG, priv->addr + FWMACTIM);
- return rswitch_reg_wait(priv->addr, FWMACTIM, FWMACTIM_MACTIOG, 0);
+ ret = rswitch_reg_wait(priv->addr, FWMACTIM, FWMACTIM_MACTIOG, 0);
+ if (ret)
+ return ret;
+
+ /* Allow entire VLAN table to be used for "un-secure" entries */
+ iowrite32(VLANTMUE, priv->addr + FWVLANTEC);
+
+ /* Initialize VLAN table */
+ iowrite32(VLANTIOG, priv->addr + FWVLANTIM);
+
+ return rswitch_reg_wait(priv->addr, FWVLANTIM, VLANTIOG, 0);
}
/* Gateway CPU agent block (GWCA) */
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 09/13] net: renesas: rswitch: update port HW init
From: Michael Dege @ 2026-03-27 8:27 UTC (permalink / raw)
To: Yoshihiro Shimoda, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-renesas-soc, linux-kernel, Michael Dege
In-Reply-To: <20260327-rswitch_add_vlans-v2-0-d7f4358ca57a@renesas.com>
Certain Ethernet and cpu port settings need to be updated for vlan
support.
Signed-off-by: Michael Dege <michael.dege@renesas.com>
---
drivers/net/ethernet/renesas/rswitch.h | 4 ----
drivers/net/ethernet/renesas/rswitch_main.c | 15 ++++++++++++---
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h
index ff2a84057f01..42c8bbafa27d 100644
--- a/drivers/net/ethernet/renesas/rswitch.h
+++ b/drivers/net/ethernet/renesas/rswitch.h
@@ -766,8 +766,6 @@ enum vlan_egress_mode {
HW_SC_TAG_VLAN,
};
-#define EAVCC_VEM_SC_TAG (0x3 << 16)
-
#define MPIC_PIS GENMASK(2, 0)
#define MPIC_PIS_GMII 2
#define MPIC_PIS_XGMII 4
@@ -806,8 +804,6 @@ enum rswitch_gwca_mode {
#define GWMTIRM_MTIOG BIT(0)
#define GWMTIRM_MTR BIT(1)
-#define GWVCC_VEM_SC_TAG (0x3 << 16)
-
#define GWARIRM_ARIOG BIT(0)
#define GWARIRM_ARR BIT(1)
diff --git a/drivers/net/ethernet/renesas/rswitch_main.c b/drivers/net/ethernet/renesas/rswitch_main.c
index ac87175b918e..d1be588fb625 100644
--- a/drivers/net/ethernet/renesas/rswitch_main.c
+++ b/drivers/net/ethernet/renesas/rswitch_main.c
@@ -735,8 +735,11 @@ static int rswitch_gwca_hw_init(struct rswitch_private *priv)
if (err < 0)
return err;
- iowrite32(GWVCC_VEM_SC_TAG, priv->addr + GWVCC);
- iowrite32(0, priv->addr + GWTTFC);
+ iowrite32(0, priv->addr + GWIRC);
+ iowrite32(FIELD_PREP(DQD, DES_RAM_DP), priv->addr + GWRDQDC0);
+ /* Drop frames with unknown tags */
+ iowrite32(UT, priv->addr + GWTTFC);
+
iowrite32(lower_32_bits(priv->gwca.linkfix_table_dma), priv->addr + GWDCBAC1);
iowrite32(upper_32_bits(priv->gwca.linkfix_table_dma), priv->addr + GWDCBAC0);
iowrite32(lower_32_bits(priv->gwca.ts_queue.ring_dma), priv->addr + GWTDCAC10);
@@ -878,6 +881,7 @@ static bool rswitch_rx(struct net_device *ndev, int *quota)
limit = boguscnt;
desc = &gq->rx_ring[gq->cur];
+
while ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY) {
dma_rmb();
skb = rswitch_rx_handle_desc(ndev, gq, desc);
@@ -1267,7 +1271,12 @@ static int rswitch_etha_hw_init(struct rswitch_etha *etha, const u8 *mac)
if (err < 0)
return err;
- iowrite32(EAVCC_VEM_SC_TAG, etha->addr + EAVCC);
+ iowrite32(0, etha->addr + EAIRC);
+ iowrite32(FIELD_PREP(DQD, DES_RAM_DP), etha->addr + EATDQDC0);
+
+ /* Drop frames with unknown tags */
+ iowrite32(UT, etha->addr + EARTFC);
+
rswitch_rmac_setting(etha, mac);
rswitch_etha_enable_mii(etha);
--
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