From: Simon Horman <horms@kernel.org>
To: jiawenwu@trustnetic.com
Cc: Simon Horman <horms@kernel.org>,
netdev@vger.kernel.org, mengyuanlou@net-swift.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, richardcochran@gmail.com,
linux@armlinux.org.uk, aleksandr.loktionov@intel.com,
jacob.e.keller@intel.com, michal.swiatkowski@linux.intel.com,
kees@kernel.org, larysa.zaremba@intel.com, leitao@debian.org,
joe@dama.to, u.kleine-koenig@baylibre.com,
weirongguang@kylinos.cn, fabio.baltieri@gmail.com
Subject: Re: [PATCH net-next v11 5/5] net: wangxun: add pcie error handler
Date: Thu, 23 Jul 2026 10:16:39 +0100 [thread overview]
Message-ID: <20260723091639.574355-2-horms@kernel.org> (raw)
In-Reply-To: <20260716073822.24356-6-jiawenwu@trustnetic.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260716073822.24356-2-jiawenwu@trustnetic.com?part=5
---
Subject: net: wangxun: add pcie error handler
This patch wires up pci_error_handlers callbacks (error_detected,
slot_reset, resume) for the ngbe and txgbe drivers, adds a
WX_FLAG_NEED_PCIE_RECOVERY flag plus a down_suspend op, and routes
ndo_tx_timeout through a check that inspects config space and defers
to the AER path when the device looks disconnected.
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_err.c b/drivers/net/ethernet/wangxun/libwx/wx_err.c
> index ee27f96735dc..0cb99e456a1c 100644
> --- a/drivers/net/ethernet/wangxun/libwx/wx_err.c
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_err.c
> @@ -4,11 +4,120 @@
>
> #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;
> +
> + if (!wx)
> + return PCI_ERS_RESULT_DISCONNECT;
> +
> + netdev = wx->netdev;
> + if (!netif_device_present(netdev))
> + return PCI_ERS_RESULT_DISCONNECT;
> +
> + if (state == pci_channel_io_perm_failure)
> + return PCI_ERS_RESULT_DISCONNECT;
[High]
Should the pci_channel_io_perm_failure branch perform teardown before
returning? In this branch the device is guaranteed gone forever, yet no
netif_device_detach(), wx_soft_quiesce(), or pci_disable_device() runs.
The service_timer keeps firing every couple of seconds and
wx_check_hang_subtask()/wx_update_stats() will keep doing MMIO reads
against the disconnected device. On arm64 an MMIO to a disconnected
device raises a synchronous external abort. TX queues are also still up
and will keep taking skbs through ndo_start_xmit until remove() runs.
Compare with ixgbe_io_error_detected() in
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c, which performs
rtnl_lock/netif_device_detach/ixgbe_close_suspend before the
perm_failure check. Would applying the same ordering here work?
> +
> + rtnl_lock();
> + netif_device_detach(netdev);
> + set_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags);
> + wx_soft_quiesce(wx);
> +
> + 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);
> +
> + if (pci_enable_device_mem(pdev)) {
> + wx_err(wx, "Cannot re-enable PCI device after reset.\n");
> + return PCI_ERS_RESULT_DISCONNECT;
> + }
[Medium, Low]
When pci_enable_device_mem() fails here, does wx_io_slot_reset() need to
unwind the state set up by wx_io_error_detected()? WX_STATE_DISABLED,
WX_STATE_DOWN (via wx_soft_quiesce), and WX_FLAG_NEED_PCIE_RECOVERY all
remain latched because the clear_bit() calls further down are never
reached.
If remove() runs later, ngbe_close()/txgbe_close() reach
ngbe_down()/txgbe_down() and call ngbe_disable_device()/
txgbe_disable_device(), which do:
if (test_and_set_bit(WX_STATE_DOWN, wx->state))
return;
so the queue/ring disable MMIO sequence is skipped. Similarly
ngbe_reset()/txgbe_reset() early-return on WX_FLAG_NEED_PCIE_RECOVERY,
so wx_flush_sw_mac_table() and related MAC cleanup is skipped. Is that
intended?
Separately, wx_err(wx, ...) here expands to
dev_err(&(wx)->pdev->dev, ...) and dereferences wx unconditionally,
while wx_io_error_detected() explicitly guards with
if (!wx) return PCI_ERS_RESULT_DISCONNECT. Should the three callbacks
be consistent — either the guard in error_detected is dead code, or
slot_reset and resume are missing an intended check?
> +
> + /* make all memory operations done before clearing the flag */
> + smp_mb__before_atomic();
> + clear_bit(WX_STATE_DISABLED, wx->state);
> + clear_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags);
> + pci_set_master(pdev);
> + pci_restore_state(pdev);
> + pci_wake_from_d3(pdev, false);
> +
> + rtnl_lock();
> + if (netif_running(wx->netdev) && wx->down_suspend)
> + wx->down_suspend(wx);
> + if (wx->do_reset)
> + wx->do_reset(wx->netdev, false);
> + rtnl_unlock();
> +
> + return PCI_ERS_RESULT_RECOVERED;
> +}
> +
> +/**
> + * 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;
> + int err;
> +
> + netdev = wx->netdev;
> + rtnl_lock();
> + if (netif_running(netdev)) {
> + err = netdev->netdev_ops->ndo_open(netdev);
> + if (err) {
> + wx_err(wx, "Failed to open netdev after reset\n");
> + goto out;
> + }
> + }
> + netif_device_attach(netdev);
> +out:
> + rtnl_unlock();
> +}
[High]
When ndo_open() fails in wx_io_resume(), the "out" path drops the rtnl
and returns without calling netif_device_attach(), without clearing
WX_STATE_DOWN, and without clearing WX_STATE_RES_FREED.
Because wx_io_error_detected() only cleared __LINK_STATE_PRESENT via
netif_device_detach(), __LINK_STATE_START is still set, so
netif_running() continues to return true. WX_STATE_DOWN and
WX_STATE_RES_FREED (set earlier in the AER cycle by wx_soft_quiesce()
and down_suspend()) are only cleared inside ngbe_up_complete() /
txgbe_up_complete(), which are only reached if ndo_open() runs to
completion.
If open fails partway (wx_setup_resources, request_irq,
phylink_connect_phy, ...), the netdev is left detached but "running"
with WX_STATE_DOWN and WX_STATE_RES_FREED latched. A subsequent
userspace "ip link set eth0 down" then hits the new short-circuit
early in ngbe_close()/txgbe_close():
if (test_bit(WX_STATE_RES_FREED, wx->state))
goto out;
...
out:
wx_control_hw(wx, false);
Since ->resume returns void, there is no way to inform the AER core.
Is there a recovery path other than unbind/rebind if ndo_open() fails
here?
> +
> +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);
> +
[ ... ]
> @@ -139,6 +251,33 @@ void wx_check_hang_subtask(struct wx *wx)
> }
> EXPORT_SYMBOL(wx_check_hang_subtask);
>
> +static bool wx_check_pcie_error(struct wx *wx)
> +{
> + u16 vid, pci_cmd;
> +
> + pci_read_config_word(wx->pdev, PCI_VENDOR_ID, &vid);
> + pci_read_config_word(wx->pdev, PCI_COMMAND, &pci_cmd);
> +
> + /* PCIe link loss or memory space can't access */
> + if (vid == U16_MAX || !(pci_cmd & PCI_COMMAND_MEMORY))
> + return true;
> +
> + return false;
> +}
> +
> +static void wx_tx_timeout_recovery(struct wx *wx)
> +{
> + /*
> + * When a PCIe hardware error occurs, the driver should initiate a PCIe
> + * recovery mechanism. However, this recovery flow relies on the AER
> + * driver for current kernel policy. Therefore, a self-contained
> + * recovery mechanism is not implemented yet.
> + */
> + set_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags);
> + wx_err(wx, "PCIe error detected during tx timeout\n");
> + queue_work(wx->reset_wq, &wx->reset_task);
> +}
[Medium]
What happens on a platform where AER never fires (AER disabled at boot,
firmware masks the event, or CONFIG_PCIEAER=n)?
wx_tx_timeout_recovery() only sets WX_FLAG_NEED_PCIE_RECOVERY and
queues reset_task. WX_FLAG_NEED_PCIE_RECOVERY is only cleared in
wx_io_slot_reset(), so without AER the flag latches.
wx_reset_task() then does:
rtnl_lock();
if (test_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags))
wx_soft_quiesce(wx); /* sets WX_STATE_DOWN */
if (test_bit(WX_STATE_DOWN, wx->state) ||
test_bit(WX_STATE_RESETTING, wx->state))
goto out; /* always taken now */
wx_pf_reset_subtask(wx); /* checks a different flag */
and ngbe_reset()/txgbe_reset() early-return on
WX_FLAG_NEED_PCIE_RECOVERY, so any future reset is a silent no-op. Is
there an intended fallback recovery when AER is unavailable, or is the
interface expected to stay unusable until reboot? The comment
acknowledges "a self-contained recovery mechanism is not implemented
yet" — should this be gated on IS_ENABLED(CONFIG_PCIEAER) or similar?
> +
> static void wx_tx_timeout_reset(struct wx *wx)
> {
> if (test_bit(WX_STATE_DOWN, wx->state))
> @@ -153,7 +292,10 @@ void wx_tx_timeout(struct net_device *netdev, unsigned int __always_unused txque
> {
> struct wx *wx = netdev_priv(netdev);
>
> - wx_tx_timeout_reset(wx);
> + if (wx_check_pcie_error(wx))
> + wx_tx_timeout_recovery(wx);
> + else
> + wx_tx_timeout_reset(wx);
> }
> EXPORT_SYMBOL(wx_tx_timeout);
[ ... ]
next prev parent reply other threads:[~2026-07-23 9:22 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-16 7:38 [PATCH net-next v11 0/5] net: wangxun: timeout and error Jiawen Wu
2026-07-16 7:38 ` [PATCH net-next v11 1/5] net: ngbe: implement libwx reset ops Jiawen Wu
2026-07-16 7:38 ` [PATCH net-next v11 2/5] net: wangxun: add Tx timeout process Jiawen Wu
2026-07-16 7:38 ` [PATCH net-next v11 3/5] net: wangxun: add reinit parameter to wx->do_reset callback Jiawen Wu
2026-07-16 7:38 ` [PATCH net-next v11 4/5] net: wangxun: implement soft quiesce for PCIe error recovery Jiawen Wu
2026-07-16 7:38 ` [PATCH net-next v11 5/5] net: wangxun: add pcie error handler Jiawen Wu
2026-07-23 9:16 ` Simon Horman [this message]
2026-07-23 9:37 ` Simon Horman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260723091639.574355-2-horms@kernel.org \
--to=horms@kernel.org \
--cc=aleksandr.loktionov@intel.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fabio.baltieri@gmail.com \
--cc=jacob.e.keller@intel.com \
--cc=jiawenwu@trustnetic.com \
--cc=joe@dama.to \
--cc=kees@kernel.org \
--cc=kuba@kernel.org \
--cc=larysa.zaremba@intel.com \
--cc=leitao@debian.org \
--cc=linux@armlinux.org.uk \
--cc=mengyuanlou@net-swift.com \
--cc=michal.swiatkowski@linux.intel.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=richardcochran@gmail.com \
--cc=u.kleine-koenig@baylibre.com \
--cc=weirongguang@kylinos.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox