* [PATCH net-next v3 1/9] net: ngbe: move the WOL functions to libwx
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
2026-03-03 8:40 ` Russell King (Oracle)
2026-03-03 3:03 ` [PATCH net-next v3 2/9] net: ngbe: remove redundant macros Jiawen Wu
` (7 subsequent siblings)
8 siblings, 1 reply; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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 | 34 ++++++++++++++++++
.../net/ethernet/wangxun/libwx/wx_ethtool.h | 4 +++
.../net/ethernet/wangxun/ngbe/ngbe_ethtool.c | 36 ++-----------------
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 12 +++----
drivers/net/ethernet/wangxun/ngbe/ngbe_type.h | 14 --------
5 files changed, 46 insertions(+), 54 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index f362e51c73ee..9e940ea9cb8b 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -262,6 +262,40 @@ 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;
+ netdev->ethtool->wol_enabled = !!(wx->wol);
+ wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
+ device_set_wakeup_enable(&pdev->dev, netdev->ethtool->wol_enabled);
+
+ 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 fc04040957bf..2b6356622a13 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
@@ -12,38 +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;
- netdev->ethtool->wol_enabled = !!(wx->wol);
- wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
- device_set_wakeup_enable(&pdev->dev, netdev->ethtool->wol_enabled);
-
- return 0;
-}
-
static int ngbe_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@@ -122,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] 11+ messages in thread* Re: [PATCH net-next v3 1/9] net: ngbe: move the WOL functions to libwx
2026-03-03 3:03 ` [PATCH net-next v3 1/9] net: ngbe: move the WOL functions to libwx Jiawen Wu
@ 2026-03-03 8:40 ` Russell King (Oracle)
0 siblings, 0 replies; 11+ messages in thread
From: Russell King (Oracle) @ 2026-03-03 8:40 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Simon Horman,
Jacob Keller, Kees Cook, Michal Kubiak, Joe Damato,
Larysa Zaremba, Abdun Nihaal, Breno Leitao
On Tue, Mar 03, 2026 at 11:03:23AM +0800, Jiawen Wu wrote:
> +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;
> + netdev->ethtool->wol_enabled = !!(wx->wol);
Please see net/ethtool/ioctl.c::ethtool_set_wol() and
net/ethtool/wol.c::ethnl_set_wol(). Both of these call your set_wol()
method, and then if it was successful, sets
netdev->ethtool->wol_enabled as appropriate. So whatever you do here
will be overwritten by core code.
Maybe an initial patch to remove this prior to moving the code would
be a good idea?
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH net-next v3 2/9] net: ngbe: remove redundant macros
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 1/9] net: ngbe: move the WOL functions to libwx Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 3/9] net: ngbe: improve the reset flow Jiawen Wu
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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] 11+ messages in thread* [PATCH net-next v3 3/9] net: ngbe: improve the reset flow
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 1/9] net: ngbe: move the WOL functions to libwx Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 2/9] net: ngbe: remove redundant macros Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 4/9] net: wangxun: move reusable PCI driver ops functions into libwx Jiawen Wu
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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] 11+ messages in thread* [PATCH net-next v3 4/9] net: wangxun: move reusable PCI driver ops functions into libwx
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
` (2 preceding siblings ...)
2026-03-03 3:03 ` [PATCH net-next v3 3/9] net: ngbe: improve the reset flow Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 5/9] net: txgbe: add power management support Jiawen Wu
` (4 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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 9e940ea9cb8b..9fd8cbe62f0c 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -396,7 +396,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] 11+ messages in thread* [PATCH net-next v3 5/9] net: txgbe: add power management support
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
` (3 preceding siblings ...)
2026-03-03 3:03 ` [PATCH net-next v3 4/9] net: wangxun: move reusable PCI driver ops functions into libwx Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 6/9] net: wangxun: move ethtool_ops.set_channels into libwx Jiawen Wu
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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] 11+ messages in thread* [PATCH net-next v3 6/9] net: wangxun: move ethtool_ops.set_channels into libwx
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
` (4 preceding siblings ...)
2026-03-03 3:03 ` [PATCH net-next v3 5/9] net: txgbe: add power management support Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 7/9] net: wangxun: delete service_timer before cancel service_work Jiawen Wu
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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 9fd8cbe62f0c..27221e259aad 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -556,7 +556,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] 11+ messages in thread* [PATCH net-next v3 7/9] net: wangxun: delete service_timer before cancel service_work
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
` (5 preceding siblings ...)
2026-03-03 3:03 ` [PATCH net-next v3 6/9] net: wangxun: move ethtool_ops.set_channels into libwx Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 8/9] net: wangxun: add Tx timeout process Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 9/9] net: wangxun: implement pci_error_handlers ops Jiawen Wu
8 siblings, 0 replies; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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] 11+ messages in thread* [PATCH net-next v3 8/9] net: wangxun: add Tx timeout process
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
` (6 preceding siblings ...)
2026-03-03 3:03 ` [PATCH net-next v3 7/9] net: wangxun: delete service_timer before cancel service_work Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
2026-03-03 3:03 ` [PATCH net-next v3 9/9] net: wangxun: implement pci_error_handlers ops Jiawen Wu
8 siblings, 0 replies; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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] 11+ messages in thread* [PATCH net-next v3 9/9] net: wangxun: implement pci_error_handlers ops
2026-03-03 3:03 [PATCH net-next v3 0/9] Wangxun improvement and new support Jiawen Wu
` (7 preceding siblings ...)
2026-03-03 3:03 ` [PATCH net-next v3 8/9] net: wangxun: add Tx timeout process Jiawen Wu
@ 2026-03-03 3:03 ` Jiawen Wu
8 siblings, 0 replies; 11+ messages in thread
From: Jiawen Wu @ 2026-03-03 3:03 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 | 3 +-
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, 115 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..1cd73b424d7f 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)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 434a582393d7..142b166117fa 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -1196,6 +1196,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 e0f5d3b49db7..18bd627f63db 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -819,6 +819,7 @@ static int ngbe_probe(struct pci_dev *pdev,
goto err_register;
pci_set_drvdata(pdev, wx);
+ pci_save_state(pdev);
return 0;
@@ -869,7 +870,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 = {
@@ -881,6 +883,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 d4f87fbb9565..c9fdad7f0df2 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -886,6 +886,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);
@@ -956,7 +957,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 = {
@@ -968,6 +970,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] 11+ messages in thread