* [PATCH net-next v5 00/11] Wangxun improvement and new support
@ 2026-03-17 7:38 Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting Jiawen Wu
` (10 more replies)
0 siblings, 11 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Implement power management function for txgbe. Clean up the same code in
the two drivers, to make more use of lib functions.
Add Tx timeout process and pci_error_handlers ops, to recover the devices.
v5:
- Add patch 10/11 to handle Tx hang check with pause frame.
- Clear WX_STATE_DISABLED bit in wx_resume().
v4: https://lore.kernel.org/all/20260306063211.20536-1-jiawenwu@trustnetic.com
- Add an initial patch to remove netdev->ethtool->wol_enabled setting.
v3: https://lore.kernel.org/all/20260303030331.24076-1-jiawenwu@trustnetic.com
- Detail the commit log for improving ngbe reset flow.
- Correct the process of stopping the work queue.
v2: https://lore.kernel.org/all/20260227073450.23680-1-jiawenwu@trustnetic.com
- Split NCSI changes from the WOL patch.
- Properly return and handle error codes.
- Fix the typos.
- Remove the check for PCIe errors and subsequent error handling, because
aer_recover_queue() does not want to be called by the ethernet driver.
The discussion link:
https://lore.kernel.org/linux-acpi/001c01dc9740$c7722540$56566fc0$@trustnetic.com/T/
v1: https://lore.kernel.org/all/20260203075759.5852-1-jiawenwu@trustnetic.com
Jiawen Wu (11):
net: ngbe: remove netdev->ethtool->wol_enabled setting
net: ngbe: move the WOL functions to libwx
net: ngbe: remove redundant macros
net: ngbe: improve the reset flow
net: wangxun: move reusable PCI driver ops functions into libwx
net: txgbe: add power management support
net: wangxun: move ethtool_ops.set_channels into libwx
net: wangxun: delete service_timer before cancel service_work
net: wangxun: add Tx timeout process
net: wangxun: improve flow control setting
net: wangxun: implement pci_error_handlers ops
drivers/net/ethernet/wangxun/libwx/Makefile | 2 +-
drivers/net/ethernet/wangxun/libwx/wx_err.c | 228 ++++++++++++++++++
drivers/net/ethernet/wangxun/libwx/wx_err.h | 16 ++
.../net/ethernet/wangxun/libwx/wx_ethtool.c | 39 ++-
.../net/ethernet/wangxun/libwx/wx_ethtool.h | 4 +
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 56 ++++-
drivers/net/ethernet/wangxun/libwx/wx_lib.c | 141 ++++++++++-
drivers/net/ethernet/wangxun/libwx/wx_lib.h | 4 +
drivers/net/ethernet/wangxun/libwx/wx_type.h | 32 ++-
.../net/ethernet/wangxun/libwx/wx_vf_common.c | 1 +
.../net/ethernet/wangxun/ngbe/ngbe_ethtool.c | 52 +---
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 202 ++++++++--------
drivers/net/ethernet/wangxun/ngbe/ngbe_type.h | 19 +-
.../ethernet/wangxun/txgbe/txgbe_ethtool.c | 17 +-
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 78 +++---
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 3 +-
16 files changed, 657 insertions(+), 237 deletions(-)
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_err.c
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_err.h
--
2.48.1
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-17 9:46 ` Breno Leitao
2026-03-18 19:59 ` Joe Damato
2026-03-17 7:38 ` [PATCH net-next v5 02/11] net: ngbe: move the WOL functions to libwx Jiawen Wu
` (9 subsequent siblings)
10 siblings, 2 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
netdev->ethtool->wol_enabled is set in ethtool core code, so remove the
redundant setting in ngbe_set_wol().
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
index fc04040957bf..40779fee0fdf 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
@@ -37,9 +37,8 @@ static int ngbe_set_wol(struct net_device *netdev,
wx->wol = 0;
if (wol->wolopts & WAKE_MAGIC)
wx->wol = WX_PSR_WKUP_CTL_MAG;
- netdev->ethtool->wol_enabled = !!(wx->wol);
wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
- device_set_wakeup_enable(&pdev->dev, netdev->ethtool->wol_enabled);
+ device_set_wakeup_enable(&pdev->dev, !!(wx->wol));
return 0;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 02/11] net: ngbe: move the WOL functions to libwx
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 03/11] net: ngbe: remove redundant macros Jiawen Wu
` (8 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Remove duplicate-defined register macros, move the WOL implementation to
the library module. So that the WOL functions can be reused in txgbe
later.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
.../net/ethernet/wangxun/libwx/wx_ethtool.c | 33 +++++++++++++++++
.../net/ethernet/wangxun/libwx/wx_ethtool.h | 4 +++
.../net/ethernet/wangxun/ngbe/ngbe_ethtool.c | 35 ++-----------------
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 12 +++----
drivers/net/ethernet/wangxun/ngbe/ngbe_type.h | 14 --------
5 files changed, 45 insertions(+), 53 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index f362e51c73ee..2de1170db8c7 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -262,6 +262,39 @@ int wx_set_link_ksettings(struct net_device *netdev,
}
EXPORT_SYMBOL(wx_set_link_ksettings);
+void wx_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ if (!wx->wol_hw_supported)
+ return;
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = 0;
+ if (wx->wol & WX_PSR_WKUP_CTL_MAG)
+ wol->wolopts |= WAKE_MAGIC;
+}
+EXPORT_SYMBOL(wx_get_wol);
+
+int wx_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct wx *wx = netdev_priv(netdev);
+ struct pci_dev *pdev = wx->pdev;
+
+ if (!wx->wol_hw_supported)
+ return -EOPNOTSUPP;
+
+ wx->wol = 0;
+ if (wol->wolopts & WAKE_MAGIC)
+ wx->wol = WX_PSR_WKUP_CTL_MAG;
+ wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
+ device_set_wakeup_enable(&pdev->dev, !!(wx->wol));
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_set_wol);
+
void wx_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.h b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.h
index 727093970462..5b187d1587b1 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.h
@@ -18,6 +18,10 @@ int wx_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd);
int wx_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd);
+void wx_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol);
+int wx_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol);
void wx_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause);
int wx_set_pauseparam(struct net_device *netdev,
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
index 40779fee0fdf..2b6356622a13 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
@@ -12,37 +12,6 @@
#include "ngbe_ethtool.h"
#include "ngbe_type.h"
-static void ngbe_get_wol(struct net_device *netdev,
- struct ethtool_wolinfo *wol)
-{
- struct wx *wx = netdev_priv(netdev);
-
- if (!wx->wol_hw_supported)
- return;
- wol->supported = WAKE_MAGIC;
- wol->wolopts = 0;
- if (wx->wol & WX_PSR_WKUP_CTL_MAG)
- wol->wolopts |= WAKE_MAGIC;
-}
-
-static int ngbe_set_wol(struct net_device *netdev,
- struct ethtool_wolinfo *wol)
-{
- struct wx *wx = netdev_priv(netdev);
- struct pci_dev *pdev = wx->pdev;
-
- if (!wx->wol_hw_supported)
- return -EOPNOTSUPP;
-
- wx->wol = 0;
- if (wol->wolopts & WAKE_MAGIC)
- wx->wol = WX_PSR_WKUP_CTL_MAG;
- wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
- device_set_wakeup_enable(&pdev->dev, !!(wx->wol));
-
- return 0;
-}
-
static int ngbe_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@@ -121,8 +90,8 @@ static const struct ethtool_ops ngbe_ethtool_ops = {
.get_link_ksettings = wx_get_link_ksettings,
.set_link_ksettings = wx_set_link_ksettings,
.nway_reset = wx_nway_reset,
- .get_wol = ngbe_get_wol,
- .set_wol = ngbe_set_wol,
+ .get_wol = wx_get_wol,
+ .set_wol = wx_set_wol,
.get_sset_count = wx_get_sset_count,
.get_strings = wx_get_strings,
.get_ethtool_stats = wx_get_ethtool_stats,
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index 58488e138beb..e28ddf684a06 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -58,14 +58,14 @@ static void ngbe_init_type_code(struct wx *wx)
wx->mac.type = wx_mac_em;
type_mask = (u16)(wx->subsystem_device_id & NGBE_OEM_MASK);
ncsi_mask = wx->subsystem_device_id & NGBE_NCSI_MASK;
- wol_mask = wx->subsystem_device_id & NGBE_WOL_MASK;
+ wol_mask = wx->subsystem_device_id & WX_WOL_MASK;
val = rd32(wx, WX_CFG_PORT_ST);
wx->mac_type = (val & BIT(7)) >> 7 ?
em_mac_type_rgmii :
em_mac_type_mdi;
- wx->wol_hw_supported = (wol_mask == NGBE_WOL_SUP) ? 1 : 0;
+ wx->wol_hw_supported = (wol_mask == WX_WOL_SUP) ? 1 : 0;
wx->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK ||
type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0;
@@ -520,9 +520,9 @@ static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
if (wufc) {
wx_set_rx_mode(netdev);
wx_configure_rx(wx);
- wr32(wx, NGBE_PSR_WKUP_CTL, wufc);
+ wr32(wx, WX_PSR_WKUP_CTL, wufc);
} else {
- wr32(wx, NGBE_PSR_WKUP_CTL, 0);
+ wr32(wx, WX_PSR_WKUP_CTL, 0);
}
pci_wake_from_d3(pdev, !!wufc);
*enable_wake = !!wufc;
@@ -742,10 +742,10 @@ static int ngbe_probe(struct pci_dev *pdev,
wx->wol = 0;
if (wx->wol_hw_supported)
- wx->wol = NGBE_PSR_WKUP_CTL_MAG;
+ wx->wol = WX_PSR_WKUP_CTL_MAG;
netdev->ethtool->wol_enabled = !!(wx->wol);
- wr32(wx, NGBE_PSR_WKUP_CTL, wx->wol);
+ wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
device_set_wakeup_enable(&pdev->dev, wx->wol);
/* Save off EEPROM version number and Option Rom version which
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
index 3b2ca7f47e33..f1957fa0add4 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
@@ -39,8 +39,6 @@
#define NGBE_NCSI_SUP 0x8000
#define NGBE_NCSI_MASK 0x8000
-#define NGBE_WOL_SUP 0x4000
-#define NGBE_WOL_MASK 0x4000
/**************** EM Registers ****************************/
/* chip control Registers */
@@ -93,18 +91,6 @@
#define NGBE_CFG_LAN_SPEED 0x14440
#define NGBE_CFG_PORT_ST 0x14404
-/* Wake up registers */
-#define NGBE_PSR_WKUP_CTL 0x15B80
-/* Wake Up Filter Control Bit */
-#define NGBE_PSR_WKUP_CTL_LNKC BIT(0) /* Link Status Change Wakeup Enable*/
-#define NGBE_PSR_WKUP_CTL_MAG BIT(1) /* Magic Packet Wakeup Enable */
-#define NGBE_PSR_WKUP_CTL_EX BIT(2) /* Directed Exact Wakeup Enable */
-#define NGBE_PSR_WKUP_CTL_MC BIT(3) /* Directed Multicast Wakeup Enable*/
-#define NGBE_PSR_WKUP_CTL_BC BIT(4) /* Broadcast Wakeup Enable */
-#define NGBE_PSR_WKUP_CTL_ARP BIT(5) /* ARP Request Packet Wakeup Enable*/
-#define NGBE_PSR_WKUP_CTL_IPV4 BIT(6) /* Directed IPv4 Pkt Wakeup Enable */
-#define NGBE_PSR_WKUP_CTL_IPV6 BIT(7) /* Directed IPv6 Pkt Wakeup Enable */
-
#define NGBE_FW_EEPROM_CHECKSUM_CMD 0xE9
#define NGBE_FW_NVM_DATA_OFFSET 3
#define NGBE_FW_CMD_DEFAULT_CHECKSUM 0xFF /* checksum always 0xFF */
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 03/11] net: ngbe: remove redundant macros
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 02/11] net: ngbe: move the WOL functions to libwx Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 04/11] net: ngbe: improve the reset flow Jiawen Wu
` (7 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
NGBE_NCSI_SUP and NGBE_NCSI_MASK are duplicate-defined, they can be
replaced by the macros defined in libwx. Just remove them.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Joe Damato <joe@dama.to>
---
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 4 ++--
drivers/net/ethernet/wangxun/ngbe/ngbe_type.h | 3 ---
2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index e28ddf684a06..8c9d505721b1 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -57,7 +57,7 @@ static void ngbe_init_type_code(struct wx *wx)
wx->mac.type = wx_mac_em;
type_mask = (u16)(wx->subsystem_device_id & NGBE_OEM_MASK);
- ncsi_mask = wx->subsystem_device_id & NGBE_NCSI_MASK;
+ ncsi_mask = wx->subsystem_device_id & WX_NCSI_MASK;
wol_mask = wx->subsystem_device_id & WX_WOL_MASK;
val = rd32(wx, WX_CFG_PORT_ST);
@@ -66,7 +66,7 @@ static void ngbe_init_type_code(struct wx *wx)
em_mac_type_mdi;
wx->wol_hw_supported = (wol_mask == WX_WOL_SUP) ? 1 : 0;
- wx->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK ||
+ wx->ncsi_enabled = (ncsi_mask == WX_NCSI_SUP ||
type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0;
switch (type_mask) {
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
index f1957fa0add4..7077a0da4c98 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
@@ -37,9 +37,6 @@
#define NGBE_OEM_MASK 0x00FF
-#define NGBE_NCSI_SUP 0x8000
-#define NGBE_NCSI_MASK 0x8000
-
/**************** EM Registers ****************************/
/* chip control Registers */
#define NGBE_MIS_PRB_CTL 0x10010
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 04/11] net: ngbe: improve the reset flow
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
` (2 preceding siblings ...)
2026-03-17 7:38 ` [PATCH net-next v5 03/11] net: ngbe: remove redundant macros Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-19 11:25 ` Paolo Abeni
2026-03-17 7:38 ` [PATCH net-next v5 05/11] net: wangxun: move reusable PCI driver ops functions into libwx Jiawen Wu
` (6 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Implement wx->do_reset() for ngbe driver, and improve the specific reset
flow. Add ngbe_reset_hw() in ngbe_reset(), to make the device connected
to the external PHY (i.e. wx->mac_type != em_mac_type_mdi) do proper LAN
reset, at all times device reset is required.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Joe Damato <joe@dama.to>
---
.../net/ethernet/wangxun/ngbe/ngbe_ethtool.c | 1 -
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 49 +++++++++++++++++--
drivers/net/ethernet/wangxun/ngbe/ngbe_type.h | 1 +
3 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
index 2b6356622a13..b86980c2418f 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
@@ -60,7 +60,6 @@ static int ngbe_set_ringparam(struct net_device *netdev,
wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
kvfree(temp_ring);
- wx_configure(wx);
ngbe_up(wx);
clear_reset:
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index 8c9d505721b1..f25a5fcab319 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -133,6 +133,7 @@ static int ngbe_sw_init(struct wx *wx)
wx->mbx.size = WX_VXMAILBOX_SIZE;
wx->setup_tc = ngbe_setup_tc;
+ wx->do_reset = ngbe_do_reset;
set_bit(0, &wx->fwd_bitmask);
return 0;
@@ -383,6 +384,12 @@ static void ngbe_disable_device(struct wx *wx)
static void ngbe_reset(struct wx *wx)
{
+ int err;
+
+ err = ngbe_reset_hw(wx);
+ if (err)
+ wx_err(wx, "Hardware Error: %d\n", err);
+
wx_flush_sw_mac_table(wx);
wx_mac_set_default_filter(wx, wx->mac.addr);
if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
@@ -398,7 +405,7 @@ void ngbe_down(struct wx *wx)
wx_clean_all_rx_rings(wx);
}
-void ngbe_up(struct wx *wx)
+static void ngbe_up_complete(struct wx *wx)
{
wx_configure_vectors(wx);
@@ -463,7 +470,7 @@ static int ngbe_open(struct net_device *netdev)
wx_ptp_init(wx);
- ngbe_up(wx);
+ ngbe_up_complete(wx);
return 0;
err_dis_phy:
@@ -502,6 +509,12 @@ static int ngbe_close(struct net_device *netdev)
return 0;
}
+void ngbe_up(struct wx *wx)
+{
+ wx_configure(wx);
+ ngbe_up_complete(wx);
+}
+
static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
{
struct wx *wx = pci_get_drvdata(pdev);
@@ -563,6 +576,8 @@ int ngbe_setup_tc(struct net_device *dev, u8 tc)
*/
if (netif_running(dev))
ngbe_close(dev);
+ else
+ ngbe_reset(wx);
wx_clear_interrupt_scheme(wx);
@@ -579,6 +594,34 @@ int ngbe_setup_tc(struct net_device *dev, u8 tc)
return 0;
}
+static void ngbe_reinit_locked(struct wx *wx)
+{
+ int err = 0;
+
+ netif_trans_update(wx->netdev);
+
+ err = wx_set_state_reset(wx);
+ if (err) {
+ wx_err(wx, "wait device reset timeout\n");
+ return;
+ }
+
+ ngbe_down(wx);
+ ngbe_up(wx);
+
+ clear_bit(WX_STATE_RESETTING, wx->state);
+}
+
+void ngbe_do_reset(struct net_device *netdev)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ if (netif_running(netdev))
+ ngbe_reinit_locked(wx);
+ else
+ ngbe_reset(wx);
+}
+
static const struct net_device_ops ngbe_netdev_ops = {
.ndo_open = ngbe_open,
.ndo_stop = ngbe_close,
@@ -858,7 +901,7 @@ static int ngbe_resume(struct pci_dev *pdev)
pci_set_master(pdev);
device_wakeup_disable(&pdev->dev);
- ngbe_reset_hw(wx);
+ ngbe_reset(wx);
rtnl_lock();
err = wx_init_interrupt_scheme(wx);
if (!err && netif_running(netdev))
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
index 7077a0da4c98..4f648f272c08 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
@@ -125,5 +125,6 @@ extern char ngbe_driver_name[];
void ngbe_down(struct wx *wx);
void ngbe_up(struct wx *wx);
int ngbe_setup_tc(struct net_device *dev, u8 tc);
+void ngbe_do_reset(struct net_device *netdev);
#endif /* _NGBE_TYPE_H_ */
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 05/11] net: wangxun: move reusable PCI driver ops functions into libwx
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
` (3 preceding siblings ...)
2026-03-17 7:38 ` [PATCH net-next v5 04/11] net: ngbe: improve the reset flow Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 06/11] net: txgbe: add power management support Jiawen Wu
` (5 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Add function pointer wx->close_suspend() and adjust wx->do_reset(), so
that PCI driver ops such as .shutdown can be called in libwx.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
.../net/ethernet/wangxun/libwx/wx_ethtool.c | 2 +-
drivers/net/ethernet/wangxun/libwx/wx_lib.c | 89 +++++++++++++-
drivers/net/ethernet/wangxun/libwx/wx_lib.h | 3 +
drivers/net/ethernet/wangxun/libwx/wx_type.h | 3 +-
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 113 ++++--------------
drivers/net/ethernet/wangxun/ngbe/ngbe_type.h | 3 +-
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 17 +--
.../net/ethernet/wangxun/txgbe/txgbe_type.h | 3 +-
8 files changed, 126 insertions(+), 107 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index 2de1170db8c7..2fda1f6130c0 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -395,7 +395,7 @@ static void wx_update_rsc(struct wx *wx)
/* reset the device to apply the new RSC setting */
if (need_reset && wx->do_reset)
- wx->do_reset(netdev);
+ wx->do_reset(netdev, true);
}
int wx_set_coalesce(struct net_device *netdev,
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 746623fa59b4..c65240ca3c28 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -3109,7 +3109,7 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features)
netdev->features = features;
if (changed & NETIF_F_HW_VLAN_CTAG_RX && wx->do_reset)
- wx->do_reset(netdev);
+ wx->do_reset(netdev, true);
else if (changed & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER))
wx_set_rx_mode(netdev);
@@ -3159,7 +3159,7 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features)
out:
if (need_reset && wx->do_reset)
- wx->do_reset(netdev);
+ wx->do_reset(netdev, true);
return 0;
}
@@ -3342,5 +3342,90 @@ void wx_service_timer(struct timer_list *t)
}
EXPORT_SYMBOL(wx_service_timer);
+static void wx_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
+{
+ struct wx *wx = pci_get_drvdata(pdev);
+ struct net_device *netdev;
+ u32 wufc = wx->wol;
+
+ netdev = wx->netdev;
+ rtnl_lock();
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ wx->close_suspend(wx);
+
+ wx_clear_interrupt_scheme(wx);
+ rtnl_unlock();
+
+ if (wufc) {
+ wx_set_rx_mode(netdev);
+ wx_configure_rx(wx);
+ wr32(wx, WX_PSR_WKUP_CTL, wufc);
+ } else {
+ wr32(wx, WX_PSR_WKUP_CTL, 0);
+ }
+ pci_wake_from_d3(pdev, !!wufc);
+ *enable_wake = !!wufc;
+ wx_control_hw(wx, false);
+
+ pci_disable_device(pdev);
+}
+
+int wx_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ bool wake;
+
+ wx_dev_shutdown(pdev, &wake);
+ device_set_wakeup_enable(&pdev->dev, wake);
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_suspend);
+
+int wx_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev;
+ struct wx *wx;
+ u32 err;
+
+ wx = pci_get_drvdata(pdev);
+ netdev = wx->netdev;
+
+ err = pci_enable_device_mem(pdev);
+ if (err) {
+ wx_err(wx, "Cannot enable PCI device from suspend\n");
+ return err;
+ }
+ pci_set_master(pdev);
+ device_wakeup_disable(&pdev->dev);
+
+ wx->do_reset(netdev, false);
+ rtnl_lock();
+
+ err = wx_init_interrupt_scheme(wx);
+ if (!err && netif_running(netdev))
+ err = netdev->netdev_ops->ndo_open(netdev);
+ if (!err)
+ netif_device_attach(netdev);
+ rtnl_unlock();
+
+ return err;
+}
+EXPORT_SYMBOL(wx_resume);
+
+void wx_shutdown(struct pci_dev *pdev)
+{
+ bool wake;
+
+ wx_dev_shutdown(pdev, &wake);
+
+ if (system_state == SYSTEM_POWER_OFF) {
+ pci_wake_from_d3(pdev, wake);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
+}
+EXPORT_SYMBOL(wx_shutdown);
+
MODULE_DESCRIPTION("Common library for Wangxun(R) Ethernet drivers.");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_lib.h
index aed6ea8cf0d6..42461723a400 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.h
@@ -41,5 +41,8 @@ void wx_set_ring(struct wx *wx, u32 new_tx_count,
void wx_service_event_schedule(struct wx *wx);
void wx_service_event_complete(struct wx *wx);
void wx_service_timer(struct timer_list *t);
+int wx_suspend(struct pci_dev *pdev, pm_message_t state);
+int wx_resume(struct pci_dev *pdev);
+void wx_shutdown(struct pci_dev *pdev);
#endif /* _WX_LIB_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 29e5c5470c94..e013f05d2cfe 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -1372,7 +1372,8 @@ struct wx {
void (*atr)(struct wx_ring *ring, struct wx_tx_buffer *first, u8 ptype);
void (*configure_fdir)(struct wx *wx);
int (*setup_tc)(struct net_device *netdev, u8 tc);
- void (*do_reset)(struct net_device *netdev);
+ void (*do_reset)(struct net_device *netdev, bool reinit);
+ void (*close_suspend)(struct wx *wx);
int (*ptp_setup_sdp)(struct wx *wx);
void (*set_num_queues)(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index f25a5fcab319..4dd7de79431c 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -134,6 +134,7 @@ static int ngbe_sw_init(struct wx *wx)
wx->mbx.size = WX_VXMAILBOX_SIZE;
wx->setup_tc = ngbe_setup_tc;
wx->do_reset = ngbe_do_reset;
+ wx->close_suspend = ngbe_close_suspend;
set_bit(0, &wx->fwd_bitmask);
return 0;
@@ -483,6 +484,16 @@ static int ngbe_open(struct net_device *netdev)
return err;
}
+void ngbe_close_suspend(struct wx *wx)
+{
+ wx_ptp_suspend(wx);
+ ngbe_down(wx);
+ wx_free_irq(wx);
+ wx_free_isb_resources(wx);
+ wx_free_resources(wx);
+ phylink_disconnect_phy(wx->phylink);
+}
+
/**
* ngbe_close - Disables a network interface
* @netdev: network interface device structure
@@ -499,11 +510,10 @@ static int ngbe_close(struct net_device *netdev)
struct wx *wx = netdev_priv(netdev);
wx_ptp_stop(wx);
- ngbe_down(wx);
- wx_free_irq(wx);
- wx_free_isb_resources(wx);
- wx_free_resources(wx);
- phylink_disconnect_phy(wx->phylink);
+
+ if (netif_device_present(netdev))
+ ngbe_close_suspend(wx);
+
wx_control_hw(wx, false);
return 0;
@@ -515,50 +525,6 @@ void ngbe_up(struct wx *wx)
ngbe_up_complete(wx);
}
-static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
-{
- struct wx *wx = pci_get_drvdata(pdev);
- struct net_device *netdev;
- u32 wufc = wx->wol;
-
- netdev = wx->netdev;
- rtnl_lock();
- netif_device_detach(netdev);
-
- if (netif_running(netdev))
- ngbe_close(netdev);
- wx_clear_interrupt_scheme(wx);
- rtnl_unlock();
-
- if (wufc) {
- wx_set_rx_mode(netdev);
- wx_configure_rx(wx);
- wr32(wx, WX_PSR_WKUP_CTL, wufc);
- } else {
- wr32(wx, WX_PSR_WKUP_CTL, 0);
- }
- pci_wake_from_d3(pdev, !!wufc);
- *enable_wake = !!wufc;
- wx_control_hw(wx, false);
-
- pci_disable_device(pdev);
-}
-
-static void ngbe_shutdown(struct pci_dev *pdev)
-{
- struct wx *wx = pci_get_drvdata(pdev);
- bool wake;
-
- wake = !!wx->wol;
-
- ngbe_dev_shutdown(pdev, &wake);
-
- if (system_state == SYSTEM_POWER_OFF) {
- pci_wake_from_d3(pdev, wake);
- pci_set_power_state(pdev, PCI_D3hot);
- }
-}
-
/**
* ngbe_setup_tc - routine to configure net_device for multiple traffic
* classes.
@@ -612,11 +578,11 @@ static void ngbe_reinit_locked(struct wx *wx)
clear_bit(WX_STATE_RESETTING, wx->state);
}
-void ngbe_do_reset(struct net_device *netdev)
+void ngbe_do_reset(struct net_device *netdev, bool reinit)
{
struct wx *wx = netdev_priv(netdev);
- if (netif_running(netdev))
+ if (netif_running(netdev) && reinit)
ngbe_reinit_locked(wx);
else
ngbe_reset(wx);
@@ -874,53 +840,14 @@ static void ngbe_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static int ngbe_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- bool wake;
-
- ngbe_dev_shutdown(pdev, &wake);
- device_set_wakeup_enable(&pdev->dev, wake);
-
- return 0;
-}
-
-static int ngbe_resume(struct pci_dev *pdev)
-{
- struct net_device *netdev;
- struct wx *wx;
- u32 err;
-
- wx = pci_get_drvdata(pdev);
- netdev = wx->netdev;
-
- err = pci_enable_device_mem(pdev);
- if (err) {
- wx_err(wx, "Cannot enable PCI device from suspend\n");
- return err;
- }
- pci_set_master(pdev);
- device_wakeup_disable(&pdev->dev);
-
- ngbe_reset(wx);
- rtnl_lock();
- err = wx_init_interrupt_scheme(wx);
- if (!err && netif_running(netdev))
- err = ngbe_open(netdev);
- if (!err)
- netif_device_attach(netdev);
- rtnl_unlock();
-
- return 0;
-}
-
static struct pci_driver ngbe_driver = {
.name = ngbe_driver_name,
.id_table = ngbe_pci_tbl,
.probe = ngbe_probe,
.remove = ngbe_remove,
- .suspend = ngbe_suspend,
- .resume = ngbe_resume,
- .shutdown = ngbe_shutdown,
+ .suspend = wx_suspend,
+ .resume = wx_resume,
+ .shutdown = wx_shutdown,
.sriov_configure = wx_pci_sriov_configure,
};
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
index 4f648f272c08..eb5c92edae06 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
@@ -125,6 +125,7 @@ extern char ngbe_driver_name[];
void ngbe_down(struct wx *wx);
void ngbe_up(struct wx *wx);
int ngbe_setup_tc(struct net_device *dev, u8 tc);
-void ngbe_do_reset(struct net_device *netdev);
+void ngbe_do_reset(struct net_device *netdev, bool reinit);
+void ngbe_close_suspend(struct wx *wx);
#endif /* _NGBE_TYPE_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 0de051450a82..30f66507809b 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -412,6 +412,7 @@ static int txgbe_sw_init(struct wx *wx)
wx->setup_tc = txgbe_setup_tc;
wx->do_reset = txgbe_do_reset;
+ wx->close_suspend = txgbe_close_suspend;
set_bit(0, &wx->fwd_bitmask);
switch (wx->mac.type) {
@@ -500,10 +501,12 @@ static int txgbe_open(struct net_device *netdev)
* This function should contain the necessary work common to both suspending
* and closing of the device.
*/
-static void txgbe_close_suspend(struct wx *wx)
+void txgbe_close_suspend(struct wx *wx)
{
wx_ptp_suspend(wx);
- txgbe_disable_device(wx);
+ txgbe_down(wx);
+ wx_free_irq(wx);
+ txgbe_free_misc_irq(wx->priv);
wx_free_resources(wx);
}
@@ -523,10 +526,8 @@ static int txgbe_close(struct net_device *netdev)
struct wx *wx = netdev_priv(netdev);
wx_ptp_stop(wx);
- txgbe_down(wx);
- wx_free_irq(wx);
- txgbe_free_misc_irq(wx->priv);
- wx_free_resources(wx);
+ if (netif_device_present(netdev))
+ txgbe_close_suspend(wx);
txgbe_fdir_filter_exit(wx);
wx_control_hw(wx, false);
@@ -614,11 +615,11 @@ static void txgbe_reinit_locked(struct wx *wx)
clear_bit(WX_STATE_RESETTING, wx->state);
}
-void txgbe_do_reset(struct net_device *netdev)
+void txgbe_do_reset(struct net_device *netdev, bool reinit)
{
struct wx *wx = netdev_priv(netdev);
- if (netif_running(netdev))
+ if (netif_running(netdev) && reinit)
txgbe_reinit_locked(wx);
else
txgbe_reset(wx);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 82433e9cb0e3..e9360e935682 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -313,7 +313,8 @@ extern char txgbe_driver_name[];
void txgbe_down(struct wx *wx);
void txgbe_up(struct wx *wx);
int txgbe_setup_tc(struct net_device *dev, u8 tc);
-void txgbe_do_reset(struct net_device *netdev);
+void txgbe_do_reset(struct net_device *netdev, bool reinit);
+void txgbe_close_suspend(struct wx *wx);
#define TXGBE_LINK_SPEED_UNKNOWN 0
#define TXGBE_LINK_SPEED_10GB_FULL 4
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 06/11] net: txgbe: add power management support
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
` (4 preceding siblings ...)
2026-03-17 7:38 ` [PATCH net-next v5 05/11] net: wangxun: move reusable PCI driver ops functions into libwx Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 07/11] net: wangxun: move ethtool_ops.set_channels into libwx Jiawen Wu
` (4 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Support .suspend and .resume and Wake-on-LAN.
Implement ethtool ops .get_wol and .set_wol to support Wake-on-LAN
function. WOL requires hardware board support which is identified by
subsystem device ID. Magic packets are checked by firmware, and
currently only WAKE_MAGIC is supported.
And WOL related operations are added to txgbe_shutdown(), it matches the
implementation of wx_shutdown(). So change to call wx_shutdown()
directly in txgbe driver.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Joe Damato <joe@dama.to>
---
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 3 +-
.../ethernet/wangxun/txgbe/txgbe_ethtool.c | 2 +
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 49 +++++++------------
3 files changed, 21 insertions(+), 33 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index bee9e245e792..150a063daafd 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -1313,8 +1313,7 @@ void wx_disable_rx(struct wx *wx)
rxctrl &= ~WX_RDB_PB_CTL_RXEN;
wr32(wx, WX_RDB_PB_CTL, rxctrl);
- if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
- ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) {
+ if (!(wx->ncsi_enabled || wx->wol_hw_supported)) {
/* disable mac receiver */
wr32m(wx, WX_MAC_RX_CFG,
WX_MAC_RX_CFG_RE, 0);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
index 9157b8275be1..c92eb71e0c15 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
@@ -575,6 +575,8 @@ static const struct ethtool_ops txgbe_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_link_ksettings = txgbe_get_link_ksettings,
.set_link_ksettings = wx_set_link_ksettings,
+ .get_wol = wx_get_wol,
+ .set_wol = wx_set_wol,
.get_sset_count = wx_get_sset_count,
.get_strings = wx_get_strings,
.get_ethtool_stats = wx_get_ethtool_stats,
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 30f66507809b..ddc7cea9d7c2 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -245,8 +245,7 @@ static void txgbe_disable_device(struct wx *wx)
wx_set_all_vfs(wx);
}
- if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
- ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) {
+ if (!(wx->ncsi_enabled || wx->wol_hw_supported)) {
/* disable mac transmiter */
wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
}
@@ -303,6 +302,7 @@ void txgbe_up(struct wx *wx)
static void txgbe_init_type_code(struct wx *wx)
{
u8 device_type = wx->subsystem_device_id & 0xF0;
+ u16 wol_mask, ncsi_mask;
switch (wx->device_id) {
case TXGBE_DEV_ID_SP1000:
@@ -347,6 +347,11 @@ static void txgbe_init_type_code(struct wx *wx)
wx->media_type = wx_media_unknown;
break;
}
+
+ wol_mask = wx->subsystem_device_id & WX_WOL_MASK;
+ ncsi_mask = wx->subsystem_device_id & WX_NCSI_MASK;
+ wx->wol_hw_supported = (wol_mask == WX_WOL_SUP) ? 1 : 0;
+ wx->ncsi_enabled = (ncsi_mask == WX_NCSI_SUP) ? 1 : 0;
}
/**
@@ -534,34 +539,6 @@ static int txgbe_close(struct net_device *netdev)
return 0;
}
-static void txgbe_dev_shutdown(struct pci_dev *pdev)
-{
- struct wx *wx = pci_get_drvdata(pdev);
- struct net_device *netdev;
-
- netdev = wx->netdev;
- netif_device_detach(netdev);
-
- rtnl_lock();
- if (netif_running(netdev))
- txgbe_close_suspend(wx);
- rtnl_unlock();
-
- wx_control_hw(wx, false);
-
- pci_disable_device(pdev);
-}
-
-static void txgbe_shutdown(struct pci_dev *pdev)
-{
- txgbe_dev_shutdown(pdev);
-
- if (system_state == SYSTEM_POWER_OFF) {
- pci_wake_from_d3(pdev, false);
- pci_set_power_state(pdev, PCI_D3hot);
- }
-}
-
/**
* txgbe_setup_tc - routine to configure net_device for multiple traffic
* classes.
@@ -824,6 +801,14 @@ static int txgbe_probe(struct pci_dev *pdev,
eth_hw_addr_set(netdev, wx->mac.perm_addr);
wx_mac_set_default_filter(wx, wx->mac.perm_addr);
+ wx->wol = 0;
+ if (wx->wol_hw_supported)
+ wx->wol = WX_PSR_WKUP_CTL_MAG;
+
+ netdev->ethtool->wol_enabled = !!(wx->wol);
+ wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
+ device_set_wakeup_enable(&pdev->dev, wx->wol);
+
txgbe_init_service(wx);
err = wx_init_interrupt_scheme(wx);
@@ -975,7 +960,9 @@ static struct pci_driver txgbe_driver = {
.id_table = txgbe_pci_tbl,
.probe = txgbe_probe,
.remove = txgbe_remove,
- .shutdown = txgbe_shutdown,
+ .suspend = wx_suspend,
+ .resume = wx_resume,
+ .shutdown = wx_shutdown,
.sriov_configure = wx_pci_sriov_configure,
};
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 07/11] net: wangxun: move ethtool_ops.set_channels into libwx
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
` (5 preceding siblings ...)
2026-03-17 7:38 ` [PATCH net-next v5 06/11] net: txgbe: add power management support Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 08/11] net: wangxun: delete service_timer before cancel service_work Jiawen Wu
` (3 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Since function ops wx->setup_tc() is set in txgbe and ngbe,
ethtool_ops.set_channels can be implemented in libwx to reduce
duplicated code.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/libwx/wx_ethtool.c | 2 +-
drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c | 15 +--------------
.../net/ethernet/wangxun/txgbe/txgbe_ethtool.c | 15 +--------------
3 files changed, 3 insertions(+), 29 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index 2fda1f6130c0..9ab7dce956e3 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -555,7 +555,7 @@ int wx_set_channels(struct net_device *dev,
wx->ring_feature[RING_F_RSS].limit = count;
- return 0;
+ return wx->setup_tc(dev, netdev_get_num_tc(dev));
}
EXPORT_SYMBOL(wx_set_channels);
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
index b86980c2418f..c37d108a85a1 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
@@ -67,19 +67,6 @@ static int ngbe_set_ringparam(struct net_device *netdev,
return err;
}
-static int ngbe_set_channels(struct net_device *dev,
- struct ethtool_channels *ch)
-{
- int err;
-
- err = wx_set_channels(dev, ch);
- if (err < 0)
- return err;
-
- /* use setup TC to update any traffic class queue mapping */
- return ngbe_setup_tc(dev, netdev_get_num_tc(dev));
-}
-
static const struct ethtool_ops ngbe_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ |
@@ -103,7 +90,7 @@ static const struct ethtool_ops ngbe_ethtool_ops = {
.get_coalesce = wx_get_coalesce,
.set_coalesce = wx_set_coalesce,
.get_channels = wx_get_channels,
- .set_channels = ngbe_set_channels,
+ .set_channels = wx_set_channels,
.get_rxfh_fields = wx_get_rxfh_fields,
.set_rxfh_fields = wx_set_rxfh_fields,
.get_rxfh_indir_size = wx_rss_indir_size,
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
index c92eb71e0c15..fc5d98f38f66 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
@@ -91,19 +91,6 @@ static int txgbe_set_ringparam(struct net_device *netdev,
return err;
}
-static int txgbe_set_channels(struct net_device *dev,
- struct ethtool_channels *ch)
-{
- int err;
-
- err = wx_set_channels(dev, ch);
- if (err < 0)
- return err;
-
- /* use setup TC to update any traffic class queue mapping */
- return txgbe_setup_tc(dev, netdev_get_num_tc(dev));
-}
-
static int txgbe_get_ethtool_fdir_entry(struct txgbe *txgbe,
struct ethtool_rxnfc *cmd)
{
@@ -589,7 +576,7 @@ static const struct ethtool_ops txgbe_ethtool_ops = {
.get_coalesce = wx_get_coalesce,
.set_coalesce = wx_set_coalesce,
.get_channels = wx_get_channels,
- .set_channels = txgbe_set_channels,
+ .set_channels = wx_set_channels,
.get_rxnfc = txgbe_get_rxnfc,
.set_rxnfc = txgbe_set_rxnfc,
.get_rx_ring_count = txgbe_get_rx_ring_count,
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 08/11] net: wangxun: delete service_timer before cancel service_work
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
` (6 preceding siblings ...)
2026-03-17 7:38 ` [PATCH net-next v5 07/11] net: wangxun: move ethtool_ops.set_channels into libwx Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 09/11] net: wangxun: add Tx timeout process Jiawen Wu
` (2 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
When removing the device, timer_delete_sync(&wx->service_timer) is
called in .ndo_stop() after cancel_work_sync(&wx->service_task). This
may cause new work to be queued after device down. So we should delete
service_timer first.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/libwx/wx_vf_common.c | 1 +
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
index ade2bfe563aa..5565062c7471 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
@@ -48,6 +48,7 @@ void wxvf_remove(struct pci_dev *pdev)
struct wx *wx = pci_get_drvdata(pdev);
struct net_device *netdev;
+ timer_delete_sync(&wx->service_timer);
cancel_work_sync(&wx->service_task);
netdev = wx->netdev;
unregister_netdev(netdev);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index ddc7cea9d7c2..01ceaf270b70 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -936,6 +936,7 @@ static void txgbe_remove(struct pci_dev *pdev)
struct txgbe *txgbe = wx->priv;
struct net_device *netdev;
+ timer_delete_sync(&wx->service_timer);
cancel_work_sync(&wx->service_task);
netdev = wx->netdev;
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 09/11] net: wangxun: add Tx timeout process
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
` (7 preceding siblings ...)
2026-03-17 7:38 ` [PATCH net-next v5 08/11] net: wangxun: delete service_timer before cancel service_work Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-19 11:31 ` Paolo Abeni
2026-03-17 7:38 ` [PATCH net-next v5 10/11] net: wangxun: improve flow control setting Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 11/11] net: wangxun: implement pci_error_handlers ops Jiawen Wu
10 siblings, 1 reply; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Implement .ndo_tx_timeout to handle Tx side timeout event. When Tx
timeout event occur, it will triger driver into reset process.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/libwx/Makefile | 2 +-
drivers/net/ethernet/wangxun/libwx/wx_err.c | 126 ++++++++++++++++++
drivers/net/ethernet/wangxun/libwx/wx_err.h | 14 ++
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 1 +
drivers/net/ethernet/wangxun/libwx/wx_lib.c | 49 +++++++
drivers/net/ethernet/wangxun/libwx/wx_lib.h | 1 +
drivers/net/ethernet/wangxun/libwx/wx_type.h | 12 +-
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 34 ++++-
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 3 +
9 files changed, 239 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_err.c
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_err.h
diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile
index a71b0ad77de3..c8724bb129aa 100644
--- a/drivers/net/ethernet/wangxun/libwx/Makefile
+++ b/drivers/net/ethernet/wangxun/libwx/Makefile
@@ -4,5 +4,5 @@
obj-$(CONFIG_LIBWX) += libwx.o
-libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_ptp.o wx_mbx.o wx_sriov.o
+libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_ptp.o wx_mbx.o wx_sriov.o wx_err.o
libwx-objs += wx_vf.o wx_vf_lib.o wx_vf_common.o
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_err.c b/drivers/net/ethernet/wangxun/libwx/wx_err.c
new file mode 100644
index 000000000000..bb77bdce69d2
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_err.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2026 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+
+#include "wx_type.h"
+#include "wx_lib.h"
+#include "wx_err.h"
+
+static void wx_reset_subtask(struct wx *wx)
+{
+ if (!test_bit(WX_FLAG_NEED_PF_RESET, wx->flags))
+ return;
+
+ if (!netif_running(wx->netdev) ||
+ test_bit(WX_STATE_RESETTING, wx->state))
+ return;
+
+ rtnl_lock();
+
+ wx_warn(wx, "Reset adapter.\n");
+
+ if (test_bit(WX_FLAG_NEED_PF_RESET, wx->flags)) {
+ if (wx->do_reset)
+ wx->do_reset(wx->netdev, true);
+ clear_bit(WX_FLAG_NEED_PF_RESET, wx->flags);
+ }
+
+ rtnl_unlock();
+}
+
+/*
+ * wx_check_tx_hang_subtask - check for hung queues and dropped interrupts
+ * @wx - pointer to the device wx structure
+ *
+ * This function serves two purposes. First it strobes the interrupt lines
+ * in order to make certain interrupts are occurring. Secondly it sets the
+ * bits needed to check for TX hangs. As a result we should immediately
+ * determine if a hang has occurred.
+ */
+static void wx_check_tx_hang_subtask(struct wx *wx)
+{
+ int i;
+
+ /* If we're down or resetting, just bail */
+ if (!netif_running(wx->netdev) ||
+ test_bit(WX_STATE_RESETTING, wx->state))
+ return;
+
+ /* Force detection of hung controller */
+ if (netif_carrier_ok(wx->netdev)) {
+ for (i = 0; i < wx->num_tx_queues; i++)
+ set_bit(WX_TX_DETECT_HANG, wx->tx_ring[i]->state);
+ }
+}
+
+void wx_handle_errors_subtask(struct wx *wx)
+{
+ wx_reset_subtask(wx);
+ wx_check_tx_hang_subtask(wx);
+}
+EXPORT_SYMBOL(wx_handle_errors_subtask);
+
+static void wx_tx_timeout_reset(struct wx *wx)
+{
+ if (!netif_running(wx->netdev))
+ return;
+
+ set_bit(WX_FLAG_NEED_PF_RESET, wx->flags);
+ wx_warn(wx, "initiating reset due to tx timeout\n");
+ wx_service_event_schedule(wx);
+}
+
+void wx_tx_timeout(struct net_device *netdev, unsigned int txqueue)
+{
+ struct wx *wx = netdev_priv(netdev);
+ u32 head, tail;
+ int i;
+
+ for (i = 0; i < wx->num_tx_queues; i++) {
+ struct wx_ring *tx_ring = wx->tx_ring[i];
+
+ if (test_bit(WX_TX_DETECT_HANG, tx_ring->state) &&
+ wx_check_tx_hang(tx_ring))
+ wx_warn(wx, "Real tx hang detected on queue %d\n", i);
+
+ head = rd32(wx, WX_PX_TR_RP(tx_ring->reg_idx));
+ tail = rd32(wx, WX_PX_TR_WP(tx_ring->reg_idx));
+ wx_warn(wx,
+ "tx ring %d next_to_use is %d, next_to_clean is %d\n",
+ i, tx_ring->next_to_use,
+ tx_ring->next_to_clean);
+ wx_warn(wx, "tx ring %d hw rp is 0x%x, wp is 0x%x\n",
+ i, head, tail);
+ }
+
+ wx_tx_timeout_reset(wx);
+}
+EXPORT_SYMBOL(wx_tx_timeout);
+
+void wx_handle_tx_hang(struct wx_ring *tx_ring, unsigned int next)
+{
+ struct wx *wx = netdev_priv(tx_ring->netdev);
+
+ wx_warn(wx, "Detected Tx Unit Hang\n"
+ " Tx Queue <%d>\n"
+ " TDH, TDT <%x>, <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "tx_buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " jiffies <%lx>\n",
+ tx_ring->queue_index,
+ rd32(wx, WX_PX_TR_RP(tx_ring->reg_idx)),
+ rd32(wx, WX_PX_TR_WP(tx_ring->reg_idx)),
+ tx_ring->next_to_use, next,
+ tx_ring->tx_buffer_info[next].time_stamp, jiffies);
+
+ netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+ wx_warn(wx, "tx hang detected on queue %d, resetting adapter\n",
+ tx_ring->queue_index);
+
+ wx_tx_timeout_reset(wx);
+}
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_err.h b/drivers/net/ethernet/wangxun/libwx/wx_err.h
new file mode 100644
index 000000000000..e317e6c8d928
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_err.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * WangXun Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2026 Beijing WangXun Technology Co., Ltd.
+ */
+
+#ifndef _WX_ERR_H_
+#define _WX_ERR_H_
+
+void wx_handle_errors_subtask(struct wx *wx);
+void wx_tx_timeout(struct net_device *netdev, unsigned int txqueue);
+void wx_handle_tx_hang(struct wx_ring *tx_ring, unsigned int next);
+
+#endif /* _WX_ERR_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 150a063daafd..2f71dc24306d 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -1931,6 +1931,7 @@ static void wx_configure_tx_ring(struct wx *wx,
else
ring->atr_sample_rate = 0;
+ bitmap_zero(ring->state, WX_RING_STATE_NBITS);
/* reinitialize tx_buffer_info */
memset(ring->tx_buffer_info, 0,
sizeof(struct wx_tx_buffer) * ring->count);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index c65240ca3c28..5a21478a592b 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -14,6 +14,7 @@
#include "wx_type.h"
#include "wx_lib.h"
+#include "wx_err.h"
#include "wx_ptp.h"
#include "wx_hw.h"
#include "wx_vf_lib.h"
@@ -742,6 +743,48 @@ static struct netdev_queue *wx_txring_txq(const struct wx_ring *ring)
return netdev_get_tx_queue(ring->netdev, ring->queue_index);
}
+static u64 wx_get_tx_pending(struct wx_ring *ring)
+{
+ unsigned int head, tail;
+
+ head = ring->next_to_clean;
+ tail = ring->next_to_use;
+
+ return ((head <= tail) ? tail : tail + ring->count) - head;
+}
+
+bool wx_check_tx_hang(struct wx_ring *ring)
+{
+ u64 tx_done_old = ring->tx_stats.tx_done_old;
+ u64 tx_pending = wx_get_tx_pending(ring);
+ u64 tx_done = ring->stats.packets;
+
+ clear_bit(WX_TX_DETECT_HANG, ring->state);
+
+ /*
+ * Check for a hung queue, but be thorough. This verifies
+ * that a transmit has been completed since the previous
+ * check AND there is at least one packet pending. The
+ * ARMED bit is set to indicate a potential hang. The
+ * bit is cleared if a pause frame is received to remove
+ * false hang detection due to PFC or 802.3x frames. By
+ * requiring this to fail twice we avoid races with
+ * pfc clearing the ARMED bit and conditions where we
+ * run the check_tx_hang logic with a transmit completion
+ * pending but without time to complete it yet.
+ */
+ if (tx_done_old == tx_done && tx_pending)
+ /* make sure it is true for two checks in a row */
+ return test_and_set_bit(WX_HANG_CHECK_ARMED, ring->state);
+
+ /* update completed stats and continue */
+ ring->tx_stats.tx_done_old = tx_done;
+ /* reset the countdown */
+ clear_bit(WX_HANG_CHECK_ARMED, ring->state);
+
+ return false;
+}
+
/**
* wx_clean_tx_irq - Reclaim resources after transmit completes
* @q_vector: structure containing interrupt and ring information
@@ -866,6 +909,12 @@ static bool wx_clean_tx_irq(struct wx_q_vector *q_vector,
netdev_tx_completed_queue(wx_txring_txq(tx_ring),
total_packets, total_bytes);
+ if (test_bit(WX_TX_DETECT_HANG, tx_ring->state) &&
+ wx_check_tx_hang(tx_ring)) {
+ wx_handle_tx_hang(tx_ring, i);
+ return true;
+ }
+
#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) &&
(wx_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD))) {
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_lib.h
index 42461723a400..85f70ea5a64f 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.h
@@ -10,6 +10,7 @@
struct wx_dec_ptype wx_decode_ptype(const u8 ptype);
void wx_alloc_rx_buffers(struct wx_ring *rx_ring, u16 cleaned_count);
u16 wx_desc_unused(struct wx_ring *ring);
+bool wx_check_tx_hang(struct wx_ring *ring);
netdev_tx_t wx_xmit_frame(struct sk_buff *skb,
struct net_device *netdev);
void wx_napi_enable_all(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index e013f05d2cfe..434a582393d7 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -1036,6 +1036,7 @@ struct wx_queue_stats {
struct wx_tx_queue_stats {
u64 restart_queue;
u64 tx_busy;
+ u64 tx_done_old;
};
struct wx_rx_queue_stats {
@@ -1051,6 +1052,12 @@ struct wx_rx_queue_stats {
#define wx_for_each_ring(posm, headm) \
for (posm = (headm).ring; posm; posm = posm->next)
+enum wx_ring_state {
+ WX_TX_DETECT_HANG,
+ WX_HANG_CHECK_ARMED,
+ WX_RING_STATE_NBITS
+};
+
struct wx_ring_container {
struct wx_ring *ring; /* pointer to linked list of rings */
unsigned int total_bytes; /* total bytes processed this int */
@@ -1070,6 +1077,7 @@ struct wx_ring {
struct wx_tx_buffer *tx_buffer_info;
struct wx_rx_buffer *rx_buffer_info;
};
+ DECLARE_BITMAP(state, WX_RING_STATE_NBITS);
u8 __iomem *tail;
dma_addr_t dma; /* phys. address of descriptor ring */
dma_addr_t headwb_dma;
@@ -1254,6 +1262,7 @@ enum wx_pf_flags {
WX_FLAG_NEED_DO_RESET,
WX_FLAG_RX_MERGE_ENABLED,
WX_FLAG_TXHEAD_WB_ENABLED,
+ WX_FLAG_NEED_PF_RESET,
WX_PF_FLAGS_NBITS /* must be last */
};
@@ -1470,7 +1479,8 @@ wr32ptp(struct wx *wx, u32 reg, u32 value)
#define wx_err(wx, fmt, arg...) \
dev_err(&(wx)->pdev->dev, fmt, ##arg)
-
+#define wx_warn(wx, fmt, arg...) \
+ dev_warn(&(wx)->pdev->dev, fmt, ##arg)
#define wx_dbg(wx, fmt, arg...) \
dev_dbg(&(wx)->pdev->dev, fmt, ##arg)
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index 4dd7de79431c..e0f5d3b49db7 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -14,6 +14,7 @@
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
#include "../libwx/wx_lib.h"
+#include "../libwx/wx_err.h"
#include "../libwx/wx_ptp.h"
#include "../libwx/wx_mbx.h"
#include "../libwx/wx_sriov.h"
@@ -140,6 +141,26 @@ static int ngbe_sw_init(struct wx *wx)
return 0;
}
+/**
+ * ngbe_service_task - manages and runs subtasks
+ * @work: pointer to work_struct containing our data
+ **/
+static void ngbe_service_task(struct work_struct *work)
+{
+ struct wx *wx = container_of(work, struct wx, service_task);
+
+ wx_handle_errors_subtask(wx);
+
+ wx_service_event_complete(wx);
+}
+
+static void ngbe_init_service(struct wx *wx)
+{
+ timer_setup(&wx->service_timer, wx_service_timer, 0);
+ INIT_WORK(&wx->service_task, ngbe_service_task);
+ clear_bit(WX_STATE_SERVICE_SCHED, wx->state);
+}
+
/**
* ngbe_irq_enable - Enable default interrupt generation settings
* @wx: board private structure
@@ -370,6 +391,7 @@ static void ngbe_disable_device(struct wx *wx)
wx_napi_disable_all(wx);
netif_tx_stop_all_queues(netdev);
netif_tx_disable(netdev);
+ timer_delete_sync(&wx->service_timer);
if (wx->gpio_ctrl)
ngbe_sfp_modules_txrx_powerctl(wx, false);
wx_irq_disable(wx);
@@ -415,6 +437,7 @@ static void ngbe_up_complete(struct wx *wx)
wx_napi_enable_all(wx);
/* enable transmits */
netif_tx_start_all_queues(wx->netdev);
+ mod_timer(&wx->service_timer, jiffies);
/* clear any pending interrupts, may auto mask */
rd32(wx, WX_PX_IC(0));
@@ -593,6 +616,7 @@ static const struct net_device_ops ngbe_netdev_ops = {
.ndo_stop = ngbe_close,
.ndo_change_mtu = wx_change_mtu,
.ndo_start_xmit = wx_xmit_frame,
+ .ndo_tx_timeout = wx_tx_timeout,
.ndo_set_rx_mode = wx_set_rx_mode,
.ndo_set_features = wx_set_features,
.ndo_fix_features = wx_fix_features,
@@ -779,9 +803,11 @@ static int ngbe_probe(struct pci_dev *pdev,
eth_hw_addr_set(netdev, wx->mac.perm_addr);
wx_mac_set_default_filter(wx, wx->mac.perm_addr);
+ ngbe_init_service(wx);
+
err = wx_init_interrupt_scheme(wx);
if (err)
- goto err_free_mac_table;
+ goto err_cancel_service;
/* phy Interface Configuration */
err = ngbe_mdio_init(wx);
@@ -801,6 +827,9 @@ static int ngbe_probe(struct pci_dev *pdev,
wx_control_hw(wx, false);
err_clear_interrupt_scheme:
wx_clear_interrupt_scheme(wx);
+err_cancel_service:
+ timer_delete_sync(&wx->service_timer);
+ cancel_work_sync(&wx->service_task);
err_free_mac_table:
kfree(wx->rss_key);
kfree(wx->mac_table);
@@ -826,6 +855,9 @@ static void ngbe_remove(struct pci_dev *pdev)
struct wx *wx = pci_get_drvdata(pdev);
struct net_device *netdev;
+ timer_delete_sync(&wx->service_timer);
+ cancel_work_sync(&wx->service_task);
+
netdev = wx->netdev;
wx_disable_sriov(wx);
unregister_netdev(netdev);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 01ceaf270b70..d4f87fbb9565 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -14,6 +14,7 @@
#include "../libwx/wx_type.h"
#include "../libwx/wx_lib.h"
+#include "../libwx/wx_err.h"
#include "../libwx/wx_ptp.h"
#include "../libwx/wx_hw.h"
#include "../libwx/wx_mbx.h"
@@ -128,6 +129,7 @@ static void txgbe_service_task(struct work_struct *work)
{
struct wx *wx = container_of(work, struct wx, service_task);
+ wx_handle_errors_subtask(wx);
txgbe_module_detection_subtask(wx);
txgbe_link_config_subtask(wx);
@@ -640,6 +642,7 @@ static const struct net_device_ops txgbe_netdev_ops = {
.ndo_stop = txgbe_close,
.ndo_change_mtu = wx_change_mtu,
.ndo_start_xmit = wx_xmit_frame,
+ .ndo_tx_timeout = wx_tx_timeout,
.ndo_set_rx_mode = wx_set_rx_mode,
.ndo_set_features = wx_set_features,
.ndo_fix_features = wx_fix_features,
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 10/11] net: wangxun: improve flow control setting
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
` (8 preceding siblings ...)
2026-03-17 7:38 ` [PATCH net-next v5 09/11] net: wangxun: add Tx timeout process Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 11/11] net: wangxun: implement pci_error_handlers ops Jiawen Wu
10 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Save the current mode of flow control, check the pause frame statistics
in watchdog to clear WX_HANG_CHECK_ARMED.
The received pause frames are divided into XON and XOFF to be counted.
And due to the hardware defect of SP devices, XON packets cannot be
trasmitted correctly, so Tx XON pause is disabled by default for those
devices.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
.../net/ethernet/wangxun/libwx/wx_ethtool.c | 2 +-
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 52 +++++++++++++++++--
drivers/net/ethernet/wangxun/libwx/wx_type.h | 16 +++++-
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 3 +-
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 3 +-
5 files changed, 66 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index 9ab7dce956e3..d1356ff5d69b 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -211,7 +211,7 @@ void wx_get_pause_stats(struct net_device *netdev,
hwstats = &wx->stats;
stats->tx_pause_frames = hwstats->lxontxc + hwstats->lxofftxc;
- stats->rx_pause_frames = hwstats->lxonoffrxc;
+ stats->rx_pause_frames = hwstats->lxonrxc + hwstats->lxoffrxc;
}
EXPORT_SYMBOL(wx_get_pause_stats);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 2f71dc24306d..4e0195f7df39 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -2772,6 +2772,15 @@ int wx_fc_enable(struct wx *wx, bool tx_pause, bool rx_pause)
}
}
+ if (rx_pause && tx_pause)
+ wx->fc.mode = wx_fc_full;
+ else if (rx_pause)
+ wx->fc.mode = wx_fc_rx_pause;
+ else if (tx_pause)
+ wx->fc.mode = wx_fc_tx_pause;
+ else
+ wx->fc.mode = wx_fc_none;
+
/* Disable any previous flow control settings */
mflcn_reg = rd32(wx, WX_MAC_RX_FLOW_CTRL);
mflcn_reg &= ~WX_MAC_RX_FLOW_CTRL_RFE;
@@ -2790,7 +2799,9 @@ int wx_fc_enable(struct wx *wx, bool tx_pause, bool rx_pause)
/* Set up and enable Rx high/low water mark thresholds, enable XON. */
if (tx_pause && wx->fc.high_water) {
- fcrtl = (wx->fc.low_water << 10) | WX_RDB_RFCL_XONE;
+ fcrtl = (wx->fc.low_water << 10);
+ if (wx->mac.type != wx_mac_sp)
+ fcrtl |= WX_RDB_RFCL_XONE;
wr32(wx, WX_RDB_RFCL, fcrtl);
fcrth = (wx->fc.high_water << 10) | WX_RDB_RFCH_XOFFE;
} else {
@@ -2831,6 +2842,28 @@ int wx_fc_enable(struct wx *wx, bool tx_pause, bool rx_pause)
}
EXPORT_SYMBOL(wx_fc_enable);
+static void wx_update_xoff_rx_lfc(struct wx *wx)
+{
+ struct wx_hw_stats *hwstats = &wx->stats;
+ u64 data;
+ int i;
+
+ if (wx->fc.mode != wx_fc_full &&
+ wx->fc.mode != wx_fc_rx_pause)
+ return;
+
+ data = rd64(wx, WX_MAC_LXOFFRXC);
+ hwstats->lxoffrxc += data;
+
+ /* refill credits (no tx hang) if we received xoff */
+ if (!data)
+ return;
+
+ for (i = 0; i < wx->num_tx_queues; i++)
+ clear_bit(WX_HANG_CHECK_ARMED,
+ wx->tx_ring[i]->state);
+}
+
/**
* wx_update_stats - Update the board statistics counters.
* @wx: board private structure
@@ -2844,6 +2877,10 @@ void wx_update_stats(struct wx *wx)
u64 restart_queue = 0, tx_busy = 0;
u32 i;
+ if (!netif_running(wx->netdev) ||
+ test_bit(WX_STATE_RESETTING, wx->state))
+ return;
+
/* gather some stats to the wx struct that are per queue */
for (i = 0; i < wx->num_rx_queues; i++) {
struct wx_ring *rx_ring = wx->rx_ring[i];
@@ -2879,6 +2916,8 @@ void wx_update_stats(struct wx *wx)
wx->restart_queue = restart_queue;
wx->tx_busy = tx_busy;
+ wx_update_xoff_rx_lfc(wx);
+
hwstats->gprc += rd32(wx, WX_RDM_PKT_CNT);
hwstats->gptc += rd32(wx, WX_TDM_PKT_CNT);
hwstats->gorc += rd64(wx, WX_RDM_BYTE_CNT_LSB);
@@ -2893,7 +2932,10 @@ void wx_update_stats(struct wx *wx)
hwstats->mptc += rd64(wx, WX_TX_MC_FRAMES_GOOD_L);
hwstats->roc += rd32(wx, WX_RX_OVERSIZE_FRAMES_GOOD);
hwstats->ruc += rd32(wx, WX_RX_UNDERSIZE_FRAMES_GOOD);
- hwstats->lxonoffrxc += rd32(wx, WX_MAC_LXONOFFRXC);
+ if (wx->mac.type >= wx_mac_aml)
+ hwstats->lxonrxc = rd32(wx, WX_MAC_LXONRXC_AML);
+ else
+ hwstats->lxonrxc += rd32(wx, WX_MAC_LXONRXC);
hwstats->lxontxc += rd32(wx, WX_RDB_LXONTXC);
hwstats->lxofftxc += rd32(wx, WX_RDB_LXOFFTXC);
hwstats->o2bgptc += rd32(wx, WX_TDM_OS2BMC_CNT);
@@ -2946,7 +2988,11 @@ void wx_clear_hw_cntrs(struct wx *wx)
rd64(wx, WX_RX_LEN_ERROR_FRAMES_L);
rd32(wx, WX_RDB_LXONTXC);
rd32(wx, WX_RDB_LXOFFTXC);
- rd32(wx, WX_MAC_LXONOFFRXC);
+ if (wx->mac.type >= wx_mac_aml)
+ wr32(wx, WX_MAC_LXONRXC_AML, 0);
+ else
+ rd32(wx, WX_MAC_LXONRXC);
+ rd32(wx, WX_MAC_LXOFFRXC);
}
EXPORT_SYMBOL(wx_clear_hw_cntrs);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 434a582393d7..510fab4b3a0f 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -79,7 +79,9 @@
#define WX_RX_LEN_ERROR_FRAMES_L 0x11978
#define WX_RX_UNDERSIZE_FRAMES_GOOD 0x11938
#define WX_RX_OVERSIZE_FRAMES_GOOD 0x1193C
-#define WX_MAC_LXONOFFRXC 0x11E0C
+#define WX_MAC_LXOFFRXC 0x11988
+#define WX_MAC_LXONRXC 0x11E0C
+#define WX_MAC_LXONRXC_AML 0x11F84
/*********************** Receive DMA registers **************************/
#define WX_RDM_VF_RE(_i) (0x12004 + ((_i) * 4))
@@ -1156,9 +1158,18 @@ enum wx_isb_idx {
WX_ISB_MAX
};
+/* Flow Control Settings */
+enum wx_fc_mode {
+ wx_fc_none = 0,
+ wx_fc_rx_pause,
+ wx_fc_tx_pause,
+ wx_fc_full
+};
+
struct wx_fc_info {
u32 high_water; /* Flow Ctrl High-water */
u32 low_water; /* Flow Ctrl Low-water */
+ enum wx_fc_mode mode; /* Flow Control Mode */
};
/* Statistics counters collected by the MAC */
@@ -1175,7 +1186,8 @@ struct wx_hw_stats {
u64 mptc;
u64 roc;
u64 ruc;
- u64 lxonoffrxc;
+ u64 lxonrxc;
+ u64 lxoffrxc;
u64 lxontxc;
u64 lxofftxc;
u64 o2bgptc;
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index e0f5d3b49db7..07e816720747 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -150,6 +150,7 @@ static void ngbe_service_task(struct work_struct *work)
struct wx *wx = container_of(work, struct wx, service_task);
wx_handle_errors_subtask(wx);
+ wx_update_stats(wx);
wx_service_event_complete(wx);
}
@@ -401,8 +402,6 @@ static void ngbe_disable_device(struct wx *wx)
wr32(wx, WX_PX_TR_CFG(reg_idx), WX_PX_TR_CFG_SWFLSH);
}
-
- wx_update_stats(wx);
}
static void ngbe_reset(struct wx *wx)
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index d4f87fbb9565..e9439e4ebe61 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -132,6 +132,7 @@ static void txgbe_service_task(struct work_struct *work)
wx_handle_errors_subtask(wx);
txgbe_module_detection_subtask(wx);
txgbe_link_config_subtask(wx);
+ wx_update_stats(wx);
wx_service_event_complete(wx);
}
@@ -261,8 +262,6 @@ static void txgbe_disable_device(struct wx *wx)
/* Disable the Tx DMA engine */
wr32m(wx, WX_TDM_CTL, WX_TDM_CTL_TE, 0);
-
- wx_update_stats(wx);
}
void txgbe_down(struct wx *wx)
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next v5 11/11] net: wangxun: implement pci_error_handlers ops
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
` (9 preceding siblings ...)
2026-03-17 7:38 ` [PATCH net-next v5 10/11] net: wangxun: improve flow control setting Jiawen Wu
@ 2026-03-17 7:38 ` Jiawen Wu
10 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-17 7:38 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao, Jiawen Wu
Support AER driver to handle the PCIe errors.
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/libwx/wx_err.c | 102 ++++++++++++++++++
drivers/net/ethernet/wangxun/libwx/wx_err.h | 2 +
drivers/net/ethernet/wangxun/libwx/wx_lib.c | 5 +-
drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 +
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 5 +-
.../net/ethernet/wangxun/txgbe/txgbe_main.c | 5 +-
6 files changed, 117 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_err.c b/drivers/net/ethernet/wangxun/libwx/wx_err.c
index bb77bdce69d2..86b318647a3c 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_err.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_err.c
@@ -3,11 +3,113 @@
#include <linux/netdevice.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include "wx_type.h"
#include "wx_lib.h"
#include "wx_err.h"
+/**
+ * wx_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * Return: pci_ers_result_t.
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t wx_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct wx *wx = pci_get_drvdata(pdev);
+ struct net_device *netdev;
+
+ netdev = wx->netdev;
+ if (!netif_device_present(netdev))
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ rtnl_lock();
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ wx->close_suspend(wx);
+
+ if (state == pci_channel_io_perm_failure) {
+ rtnl_unlock();
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ if (!test_and_set_bit(WX_STATE_DISABLED, wx->state))
+ pci_disable_device(pdev);
+ rtnl_unlock();
+
+ /* Request a slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * wx_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Return: pci_ers_result_t.
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t wx_io_slot_reset(struct pci_dev *pdev)
+{
+ struct wx *wx = pci_get_drvdata(pdev);
+ pci_ers_result_t result;
+
+ if (pci_enable_device_mem(pdev)) {
+ wx_err(wx, "Cannot re-enable PCI device after reset.\n");
+ result = PCI_ERS_RESULT_DISCONNECT;
+ } else {
+ /* make all bar access done before reset. */
+ smp_mb__before_atomic();
+ clear_bit(WX_STATE_DISABLED, wx->state);
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+ pci_save_state(pdev);
+ pci_wake_from_d3(pdev, false);
+
+ wx->do_reset(wx->netdev, false);
+ result = PCI_ERS_RESULT_RECOVERED;
+ }
+
+ pci_aer_clear_nonfatal_status(pdev);
+
+ return result;
+}
+
+/**
+ * wx_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void wx_io_resume(struct pci_dev *pdev)
+{
+ struct wx *wx = pci_get_drvdata(pdev);
+ struct net_device *netdev;
+
+ netdev = wx->netdev;
+ rtnl_lock();
+ if (netif_running(netdev))
+ netdev->netdev_ops->ndo_open(netdev);
+
+ netif_device_attach(netdev);
+ rtnl_unlock();
+}
+
+const struct pci_error_handlers wx_err_handler = {
+ .error_detected = wx_io_error_detected,
+ .slot_reset = wx_io_slot_reset,
+ .resume = wx_io_resume,
+};
+EXPORT_SYMBOL(wx_err_handler);
+
static void wx_reset_subtask(struct wx *wx)
{
if (!test_bit(WX_FLAG_NEED_PF_RESET, wx->flags))
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_err.h b/drivers/net/ethernet/wangxun/libwx/wx_err.h
index e317e6c8d928..8b1a7863b5b1 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_err.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_err.h
@@ -7,6 +7,8 @@
#ifndef _WX_ERR_H_
#define _WX_ERR_H_
+extern const struct pci_error_handlers wx_err_handler;
+
void wx_handle_errors_subtask(struct wx *wx);
void wx_tx_timeout(struct net_device *netdev, unsigned int txqueue);
void wx_handle_tx_hang(struct wx_ring *tx_ring, unsigned int next);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 5a21478a592b..fdf14c21cd5e 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -3418,7 +3418,8 @@ static void wx_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
*enable_wake = !!wufc;
wx_control_hw(wx, false);
- pci_disable_device(pdev);
+ if (!test_and_set_bit(WX_STATE_DISABLED, wx->state))
+ pci_disable_device(pdev);
}
int wx_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -3446,6 +3447,8 @@ int wx_resume(struct pci_dev *pdev)
wx_err(wx, "Cannot enable PCI device from suspend\n");
return err;
}
+
+ clear_bit(WX_STATE_DISABLED, wx->state);
pci_set_master(pdev);
device_wakeup_disable(&pdev->dev);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 510fab4b3a0f..117cebbb9a67 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -1208,6 +1208,7 @@ enum wx_state {
WX_STATE_PTP_RUNNING,
WX_STATE_PTP_TX_IN_PROGRESS,
WX_STATE_SERVICE_SCHED,
+ WX_STATE_DISABLED,
WX_STATE_NBITS /* must be last */
};
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index 07e816720747..a382671d4c6d 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -818,6 +818,7 @@ static int ngbe_probe(struct pci_dev *pdev,
goto err_register;
pci_set_drvdata(pdev, wx);
+ pci_save_state(pdev);
return 0;
@@ -868,7 +869,8 @@ static void ngbe_remove(struct pci_dev *pdev)
kfree(wx->mac_table);
wx_clear_interrupt_scheme(wx);
- pci_disable_device(pdev);
+ if (!test_and_set_bit(WX_STATE_DISABLED, wx->state))
+ pci_disable_device(pdev);
}
static struct pci_driver ngbe_driver = {
@@ -880,6 +882,7 @@ static struct pci_driver ngbe_driver = {
.resume = wx_resume,
.shutdown = wx_shutdown,
.sriov_configure = wx_pci_sriov_configure,
+ .err_handler = &wx_err_handler,
};
module_pci_driver(ngbe_driver);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index e9439e4ebe61..4f0af47260a9 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -885,6 +885,7 @@ static int txgbe_probe(struct pci_dev *pdev,
goto err_remove_phy;
pci_set_drvdata(pdev, wx);
+ pci_save_state(pdev);
netif_tx_stop_all_queues(netdev);
@@ -955,7 +956,8 @@ static void txgbe_remove(struct pci_dev *pdev)
kfree(wx->mac_table);
wx_clear_interrupt_scheme(wx);
- pci_disable_device(pdev);
+ if (!test_and_set_bit(WX_STATE_DISABLED, wx->state))
+ pci_disable_device(pdev);
}
static struct pci_driver txgbe_driver = {
@@ -967,6 +969,7 @@ static struct pci_driver txgbe_driver = {
.resume = wx_resume,
.shutdown = wx_shutdown,
.sriov_configure = wx_pci_sriov_configure,
+ .err_handler = &wx_err_handler,
};
module_pci_driver(txgbe_driver);
--
2.48.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting
2026-03-17 7:38 ` [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting Jiawen Wu
@ 2026-03-17 9:46 ` Breno Leitao
2026-03-18 19:59 ` Joe Damato
1 sibling, 0 replies; 17+ messages in thread
From: Breno Leitao @ 2026-03-17 9:46 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal
On Tue, Mar 17, 2026 at 03:38:17PM +0800, Jiawen Wu wrote:
> netdev->ethtool->wol_enabled is set in ethtool core code, so remove the
> redundant setting in ngbe_set_wol().
>
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Breno Leitao <leitao@debian.org>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting
2026-03-17 7:38 ` [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting Jiawen Wu
2026-03-17 9:46 ` Breno Leitao
@ 2026-03-18 19:59 ` Joe Damato
1 sibling, 0 replies; 17+ messages in thread
From: Joe Damato @ 2026-03-18 19:59 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Simon Horman, Jacob Keller, Kees Cook, Michal Kubiak,
Larysa Zaremba, Abdun Nihaal, Breno Leitao
On Tue, Mar 17, 2026 at 03:38:17PM +0800, Jiawen Wu wrote:
> netdev->ethtool->wol_enabled is set in ethtool core code, so remove the
> redundant setting in ngbe_set_wol().
>
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> ---
> drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 04/11] net: ngbe: improve the reset flow
2026-03-17 7:38 ` [PATCH net-next v5 04/11] net: ngbe: improve the reset flow Jiawen Wu
@ 2026-03-19 11:25 ` Paolo Abeni
2026-03-24 6:40 ` Jiawen Wu
0 siblings, 1 reply; 17+ messages in thread
From: Paolo Abeni @ 2026-03-19 11:25 UTC (permalink / raw)
To: Jiawen Wu, netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Richard Cochran, Russell King, Simon Horman,
Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao
On 3/17/26 8:38 AM, Jiawen Wu wrote:
> @@ -383,6 +384,12 @@ static void ngbe_disable_device(struct wx *wx)
>
> static void ngbe_reset(struct wx *wx)
> {
> + int err;
> +
> + err = ngbe_reset_hw(wx);
> + if (err)
> + wx_err(wx, "Hardware Error: %d\n", err);
AI review says:
"""
Andrew Lunn suggested in v1 review that ngbe_reset() should return int
to propagate error codes to callers, rather than just logging errors
and continuing. While the response mentioned hardware errors are
handled in another work queue, should the callers (ngbe_down,
ngbe_setup_tc, ngbe_do_reset, ngbe_resume) be able to detect and
handle reset failures?
Reference:
https://lore.kernel.org/netdev/4ddc6f7d-ee6f-48a9-857f-a10448815675@lunn.ch/
"""
There are a few problems with the workqueue approach:
- AFAICS the workqueue is scheduled on xmit timeouts, which are
apparenly not directly related to ngbe_reset_hw() failures
- the worker try to reset again the H/W and unconditionally clears the
error status, even if such reset fails.
- ngbe_reset_hw() is supposed to stop interrupt generation; if it fails,
it looks like that the sequence:
ngbe_down(wx);
// ngbe_reset()
ngbe_up()
can have very bad consequences (like ring reconf with IRQ enabled).
I think explicitly propagating and handling the failure here is needed.
/P
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH net-next v5 09/11] net: wangxun: add Tx timeout process
2026-03-17 7:38 ` [PATCH net-next v5 09/11] net: wangxun: add Tx timeout process Jiawen Wu
@ 2026-03-19 11:31 ` Paolo Abeni
0 siblings, 0 replies; 17+ messages in thread
From: Paolo Abeni @ 2026-03-19 11:31 UTC (permalink / raw)
To: Jiawen Wu, netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Richard Cochran, Russell King, Simon Horman,
Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao
On 3/17/26 8:38 AM, Jiawen Wu wrote:
> +bool wx_check_tx_hang(struct wx_ring *ring)
> +{
> + u64 tx_done_old = ring->tx_stats.tx_done_old;
> + u64 tx_pending = wx_get_tx_pending(ring);
> + u64 tx_done = ring->stats.packets;
> +
> + clear_bit(WX_TX_DETECT_HANG, ring->state);
> +
> + /*
> + * Check for a hung queue, but be thorough. This verifies
> + * that a transmit has been completed since the previous
> + * check AND there is at least one packet pending. The
> + * ARMED bit is set to indicate a potential hang. The
> + * bit is cleared if a pause frame is received to remove
AFAICS this is handled in patch 11, at slot reset time, which IIRC is
quite separate from pause frame reception.
I think this comment need to be update to reflect the current behavior.
Also you should explicitly mention in the commit message that the actual
implementation of this part will with a later patch.
/P
^ permalink raw reply [flat|nested] 17+ messages in thread
* RE: [PATCH net-next v5 04/11] net: ngbe: improve the reset flow
2026-03-19 11:25 ` Paolo Abeni
@ 2026-03-24 6:40 ` Jiawen Wu
0 siblings, 0 replies; 17+ messages in thread
From: Jiawen Wu @ 2026-03-24 6:40 UTC (permalink / raw)
To: 'Paolo Abeni', netdev, netdev
Cc: 'Mengyuan Lou', 'Andrew Lunn',
'David S. Miller', 'Eric Dumazet',
'Jakub Kicinski', 'Richard Cochran',
'Russell King', 'Simon Horman',
'Jacob Keller', 'Kees Cook',
'Michal Kubiak', 'Joe Damato',
'Larysa Zaremba', 'Abdun Nihaal',
'Breno Leitao', 'Mengyuan Lou',
'Andrew Lunn', 'David S. Miller',
'Eric Dumazet', 'Jakub Kicinski',
'Richard Cochran', 'Russell King',
'Simon Horman', 'Jacob Keller',
'Kees Cook', 'Michal Kubiak',
'Joe Damato', 'Larysa Zaremba',
'Abdun Nihaal', 'Breno Leitao'
On Thu, Mar 19, 2026 7:26 PM, Paolo Abeni wrote:
> On 3/17/26 8:38 AM, Jiawen Wu wrote:
> > @@ -383,6 +384,12 @@ static void ngbe_disable_device(struct wx *wx)
> >
> > static void ngbe_reset(struct wx *wx)
> > {
> > + int err;
> > +
> > + err = ngbe_reset_hw(wx);
> > + if (err)
> > + wx_err(wx, "Hardware Error: %d\n", err);
>
> AI review says:
>
> """
> Andrew Lunn suggested in v1 review that ngbe_reset() should return int
> to propagate error codes to callers, rather than just logging errors
> and continuing. While the response mentioned hardware errors are
> handled in another work queue, should the callers (ngbe_down,
> ngbe_setup_tc, ngbe_do_reset, ngbe_resume) be able to detect and
> handle reset failures?
>
> Reference:
> https://lore.kernel.org/netdev/4ddc6f7d-ee6f-48a9-857f-a10448815675@lunn.ch/
> """
>
> There are a few problems with the workqueue approach:
> - AFAICS the workqueue is scheduled on xmit timeouts, which are
> apparenly not directly related to ngbe_reset_hw() failures
> - the worker try to reset again the H/W and unconditionally clears the
> error status, even if such reset fails.
> - ngbe_reset_hw() is supposed to stop interrupt generation; if it fails,
> it looks like that the sequence:
>
> ngbe_down(wx);
> // ngbe_reset()
> ngbe_up()
>
> can have very bad consequences (like ring reconf with IRQ enabled).
>
> I think explicitly propagating and handling the failure here is needed.
To be clear, when ngbe_reset_hw() fails, the hardware is already in a PCIe
error state. In patch set v1, this error will be detected in watchdog, and
do PCIe recovery. But it was removed in v2, so the sequence seems weird.
In the current flow, I'll fix it to return int.
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-03-24 6:41 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-17 7:38 [PATCH net-next v5 00/11] Wangxun improvement and new support Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 01/11] net: ngbe: remove netdev->ethtool->wol_enabled setting Jiawen Wu
2026-03-17 9:46 ` Breno Leitao
2026-03-18 19:59 ` Joe Damato
2026-03-17 7:38 ` [PATCH net-next v5 02/11] net: ngbe: move the WOL functions to libwx Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 03/11] net: ngbe: remove redundant macros Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 04/11] net: ngbe: improve the reset flow Jiawen Wu
2026-03-19 11:25 ` Paolo Abeni
2026-03-24 6:40 ` Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 05/11] net: wangxun: move reusable PCI driver ops functions into libwx Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 06/11] net: txgbe: add power management support Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 07/11] net: wangxun: move ethtool_ops.set_channels into libwx Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 08/11] net: wangxun: delete service_timer before cancel service_work Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 09/11] net: wangxun: add Tx timeout process Jiawen Wu
2026-03-19 11:31 ` Paolo Abeni
2026-03-17 7:38 ` [PATCH net-next v5 10/11] net: wangxun: improve flow control setting Jiawen Wu
2026-03-17 7:38 ` [PATCH net-next v5 11/11] net: wangxun: implement pci_error_handlers ops Jiawen Wu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox