lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260203075759.5852-8-jiawenwu@trustnetic.com>
Date: Tue,  3 Feb 2026 15:57:59 +0800
From: Jiawen Wu <jiawenwu@...stnetic.com>
To: netdev@...r.kernel.org,
	Andrew Lunn <andrew+netdev@...n.ch>,
	"David S. Miller" <davem@...emloft.net>,
	Eric Dumazet <edumazet@...gle.com>,
	Jakub Kicinski <kuba@...nel.org>,
	Paolo Abeni <pabeni@...hat.com>,
	Simon Horman <horms@...nel.org>
Cc: Mengyuan Lou <mengyuanlou@...-swift.com>,
	Jiawen Wu <jiawenwu@...stnetic.com>
Subject: [PATCH net-next v1 7/7] net: wangxun: add pcie error handler

Support to check pcie error and invoke aer driver to recover pcie.

Signed-off-by: Jiawen Wu <jiawenwu@...stnetic.com>
---
 drivers/net/ethernet/wangxun/libwx/wx_err.c   | 235 +++++++++++++++++-
 drivers/net/ethernet/wangxun/libwx/wx_err.h   |   3 +
 drivers/net/ethernet/wangxun/libwx/wx_hw.c    |  56 ++++-
 drivers/net/ethernet/wangxun/libwx/wx_hw.h    |   2 +
 drivers/net/ethernet/wangxun/libwx/wx_lib.c   |   3 +-
 drivers/net/ethernet/wangxun/libwx/wx_type.h  |  11 +
 drivers/net/ethernet/wangxun/ngbe/ngbe_main.c |  14 +-
 drivers/net/ethernet/wangxun/ngbe/ngbe_type.h |   2 +
 .../net/ethernet/wangxun/txgbe/txgbe_irq.c    |   7 +
 .../net/ethernet/wangxun/txgbe/txgbe_main.c   |  13 +-
 .../net/ethernet/wangxun/txgbe/txgbe_type.h   |   5 +-
 11 files changed, 339 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/wangxun/libwx/wx_err.c b/drivers/net/ethernet/wangxun/libwx/wx_err.c
index bb77bdce69d2..36eb06bd1798 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_err.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_err.c
@@ -3,10 +3,228 @@
 
 #include <linux/netdevice.h>
 #include <linux/pci.h>
+#include <linux/aer.h>
 
 #include "wx_type.h"
 #include "wx_lib.h"
 #include "wx_err.h"
+#include "wx_hw.h"
+
+/**
+ * wx_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * 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);
+
+	wx->io_err = true;
+	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
+ *
+ * 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);
+
+	wx->io_err = false;
+	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 bool wx_check_pcie_error(struct wx *wx)
+{
+	u16 vid, pci_cmd, devctl2;
+	u32 value;
+
+	pci_read_config_word(wx->pdev, PCI_VENDOR_ID, &vid);
+	wx_warn(wx, "PCI vendor id is 0x%x\n", vid);
+	pci_read_config_word(wx->pdev, PCI_COMMAND, &pci_cmd);
+	wx_warn(wx, "PCI command reg is 0x%x\n", pci_cmd);
+	pcie_capability_read_word(wx->pdev, PCI_EXP_DEVCTL2, &devctl2);
+	wx_warn(wx, "Device Control2 Register: 0x%04x\n", devctl2);
+
+	value = rd32(wx, WX_MIS_PWR);
+	wx_warn(wx, "MIS_PWR value is 0x%08x\n", value);
+	value = rd32(wx, WX_PX_IMS(0));
+	wx_warn(wx, "PX_IMS0 value is 0x%08x\n", value);
+	if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) {
+		value = rd32(wx, WX_PX_IMS(1));
+		wx_warn(wx, "PX_IMS1 value is 0x%08x\n", value);
+	}
+	value = rd32(wx, WX_TDB_TFCS);
+	wx_warn(wx, "Tx flow control Status[TDB_TFCS 0xCE00]: 0x%x\n", value);
+
+	/* PCIe link loss or memory space can't access */
+	if (vid == WX_FAILED_READ_CFG_WORD || !(pci_cmd & 0x2))
+		return true;
+
+	return false;
+}
+
+static void wx_check_error_subtask(struct wx *wx)
+{
+	u32 sm;
+
+	if (test_bit(WX_FLAG_ERROR_CHECK, wx->flags)) {
+		/* get PF semaphore */
+		wr32(wx, WX_MIS_PF_SM, 1);
+		clear_bit(WX_FLAG_ERROR_CHECK, wx->flags);
+	}
+
+	sm = rd32(wx, WX_MIS_PF_SM);
+	/* PCIe memory space access error */
+	if (sm == U32_MAX)
+		goto out;
+
+	/* PCIe error may be occurred in another port */
+	if ((sm == 1 && wx_check_first_lan_up(wx)))
+		goto out;
+
+	return;
+out:
+	set_bit(WX_FLAG_NEED_PCIE_RECOVER, wx->flags);
+	wx_warn(wx, "Set PCIe recover on LAN %d\n", wx->bus.func);
+}
+
+static bool wx_check_recovery_capability(struct pci_dev *dev)
+{
+#if defined(__i386__) || defined(__x86_64__)
+	return true;
+#else
+	/* check upstream bridge is root or PLX bridge,
+	 * or if CPU is kunpeng 920
+	 */
+	if (dev->bus->self->vendor == PCI_VENDOR_ID_PLX ||
+	    dev->bus->self->vendor == PCI_VENDOR_ID_HUAWEI)
+		return true;
+	else
+		return false;
+#endif
+}
+
+static void wx_pcie_do_recovery(struct pci_dev *dev)
+{
+	struct wx *wx = pci_get_drvdata(dev);
+	struct aer_capability_regs *regs = &wx->aer_info;
+	int pos;
+
+	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+	if (!pos)
+		return;
+
+	memset(regs, 0, sizeof(*regs));
+	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &regs->uncor_status);
+	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &regs->uncor_mask);
+	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &regs->uncor_severity);
+	pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &regs->cor_status);
+	pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &regs->cor_mask);
+	pci_read_config_dword(dev, pos + PCI_ERR_CAP, &regs->cap_control);
+
+	aer_recover_queue(pci_domain_nr(dev->bus), dev->bus->number,
+			  dev->devfn, AER_FATAL, regs);
+}
+
+static void wx_pcie_recovery_subtask(struct wx *wx)
+{
+	if (!test_bit(WX_FLAG_NEED_PCIE_RECOVER, wx->flags))
+		return;
+
+	/* release PF semaphore */
+	wr32(wx, WX_MIS_PF_SM, 0);
+
+	if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags)) {
+		wx_warn(wx, "PCIe recovery skipped in SR-IOV mode\n");
+		goto out;
+	}
+
+	if (wx_check_recovery_capability(wx->pdev)) {
+		wx_warn(wx, "Do PCIe recovery\n");
+		wx_pcie_do_recovery(wx->pdev);
+	} else {
+		wx_warn(wx, "This platform can't support PCIe recovery, skip it\n");
+	}
+
+out:
+	clear_bit(WX_FLAG_NEED_PCIE_RECOVER, wx->flags);
+}
 
 static void wx_reset_subtask(struct wx *wx)
 {
@@ -57,11 +275,20 @@ static void wx_check_tx_hang_subtask(struct wx *wx)
 
 void wx_handle_errors_subtask(struct wx *wx)
 {
+	wx_check_error_subtask(wx);
+	wx_pcie_recovery_subtask(wx);
 	wx_reset_subtask(wx);
 	wx_check_tx_hang_subtask(wx);
 }
 EXPORT_SYMBOL(wx_handle_errors_subtask);
 
+void wx_pcie_error_handler(struct wx *wx)
+{
+	set_bit(WX_FLAG_ERROR_CHECK, wx->flags);
+	wx_service_event_schedule(wx);
+}
+EXPORT_SYMBOL(wx_pcie_error_handler);
+
 static void wx_tx_timeout_reset(struct wx *wx)
 {
 	if (!netif_running(wx->netdev))
@@ -75,9 +302,12 @@ static void wx_tx_timeout_reset(struct wx *wx)
 void wx_tx_timeout(struct net_device *netdev, unsigned int txqueue)
 {
 	struct wx *wx = netdev_priv(netdev);
+	bool pcie_error;
 	u32 head, tail;
 	int i;
 
+	pcie_error = wx_check_pcie_error(wx);
+
 	for (i = 0; i < wx->num_tx_queues; i++) {
 		struct wx_ring *tx_ring = wx->tx_ring[i];
 
@@ -95,7 +325,10 @@ void wx_tx_timeout(struct net_device *netdev, unsigned int txqueue)
 			i, head, tail);
 	}
 
-	wx_tx_timeout_reset(wx);
+	if (pcie_error)
+		wx_pcie_error_handler(wx);
+	else
+		wx_tx_timeout_reset(wx);
 }
 EXPORT_SYMBOL(wx_tx_timeout);
 
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_err.h b/drivers/net/ethernet/wangxun/libwx/wx_err.h
index e317e6c8d928..f1d14d622f14 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_err.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_err.h
@@ -7,7 +7,10 @@
 #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_pcie_error_handler(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_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 8e3e02ffb5a4..ec0c8e2ba511 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -10,6 +10,7 @@
 
 #include "wx_type.h"
 #include "wx_lib.h"
+#include "wx_err.h"
 #include "wx_sriov.h"
 #include "wx_vf.h"
 #include "wx_hw.h"
@@ -2308,8 +2309,11 @@ int wx_disable_pcie_master(struct wx *wx)
 	/* Poll for master request bit to clear */
 	status = read_poll_timeout(rd32, val, !val, 100, WX_PCI_MASTER_DISABLE_TIMEOUT,
 				   false, wx, WX_PX_TRANSACTION_PENDING);
-	if (status < 0)
+	if (status < 0) {
 		wx_err(wx, "PCIe transaction pending bit did not clear.\n");
+		if (!wx->io_err)
+			wx_pcie_error_handler(wx);
+	}
 
 	return status;
 }
@@ -2517,6 +2521,7 @@ int wx_sw_init(struct wx *wx)
 	bitmap_zero(wx->state, WX_STATE_NBITS);
 	bitmap_zero(wx->flags, WX_PF_FLAGS_NBITS);
 	wx->misc_irq_domain = false;
+	wx->io_err = false;
 
 	return 0;
 }
@@ -2974,4 +2979,53 @@ void wx_start_hw(struct wx *wx)
 }
 EXPORT_SYMBOL(wx_start_hw);
 
+void wx_set_pci_lan_up(struct wx *wx, bool up)
+{
+	u8 max_lan;
+	u32 reg;
+
+	if (wx->mac.type == wx_mac_em)
+		max_lan = 3;
+	else
+		max_lan = 1;
+
+	if (wx->bus.func > max_lan) {
+		wx_err(wx, "%s: invalid bus lan id %d\n",
+		       __func__, wx->bus.func);
+		return;
+	}
+
+	reg = rd32(wx, WX_MIS_PRB_CTL);
+	if (up)
+		reg |= BIT(max_lan - wx->bus.func);
+	else
+		reg &= ~BIT(max_lan - wx->bus.func);
+	wr32(wx, WX_MIS_PRB_CTL, reg);
+}
+EXPORT_SYMBOL(wx_set_pci_lan_up);
+
+bool wx_check_first_lan_up(struct wx *wx)
+{
+	u8 max_lan, i;
+	u32 reg;
+
+	if (wx->mac.type == wx_mac_em)
+		max_lan = 3;
+	else
+		max_lan = 1;
+
+	/* Check whether the current port is the first (smallest number)
+	 * among the ports up on this board.
+	 */
+	reg = rd32(wx, WX_MIS_PRB_CTL);
+	for (i = 0; i <= max_lan; i++) {
+		if (reg & BIT(max_lan - i))
+			break;
+	}
+	if (i == wx->bus.func)
+		return true;
+
+	return false;
+}
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
index 13857376bbad..1ab30a983b68 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
@@ -59,5 +59,7 @@ int wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);
 int wx_fc_enable(struct wx *wx, bool tx_pause, bool rx_pause);
 void wx_update_stats(struct wx *wx);
 void wx_clear_hw_cntrs(struct wx *wx);
+void wx_set_pci_lan_up(struct wx *wx, bool up);
+bool wx_check_first_lan_up(struct wx *wx);
 
 #endif /* _WX_HW_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 76bda834c59f..cbd391f1c027 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -3421,7 +3421,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..68d06d6619ab 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -11,6 +11,7 @@
 #include <linux/if_vlan.h>
 #include <linux/phylink.h>
 #include <linux/dim.h>
+#include <linux/aer.h>
 #include <net/ip.h>
 
 #define WX_NCSI_SUP                             0x8000
@@ -30,9 +31,11 @@
 
 /* chip control Registers */
 #define WX_MIS_PWR                   0x10000
+#define WX_MIS_PF_SM                 0x10008
 #define WX_MIS_RST                   0x1000C
 #define WX_MIS_RST_LAN_RST(_i)       BIT((_i) + 1)
 #define WX_MIS_RST_SW_RST            BIT(0)
+#define WX_MIS_PRB_CTL               0x10010
 #define WX_MIS_ST                    0x10028
 #define WX_MIS_ST_MNG_INIT_DN        BIT(0)
 #define WX_MIS_SWSM                  0x1002C
@@ -308,6 +311,7 @@
 #define WX_TDM_VLAN_INS_VLANA_DEFAULT BIT(30) /* Always use default VLAN*/
 
 /****************************** TDB ******************************************/
+#define WX_TDB_TFCS                  0x1CE00
 #define WX_TDB_PB_SZ(_i)             (0x1CC00 + ((_i) * 4))
 #define WX_TXPKT_SIZE_MAX            0xA /* Max Tx Packet size */
 
@@ -1196,6 +1200,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 */
 };
 
@@ -1263,6 +1268,8 @@ enum wx_pf_flags {
 	WX_FLAG_RX_MERGE_ENABLED,
 	WX_FLAG_TXHEAD_WB_ENABLED,
 	WX_FLAG_NEED_PF_RESET,
+	WX_FLAG_ERROR_CHECK,
+	WX_FLAG_NEED_PCIE_RECOVER,
 	WX_PF_FLAGS_NBITS               /* must be last */
 };
 
@@ -1358,6 +1365,8 @@ struct wx {
 #define WX_RSS_KEY_SIZE     40  /* size of RSS Hash Key in bytes */
 	u32 *rss_key;
 	u32 wol;
+	bool io_err;
+	struct aer_capability_regs aer_info;
 
 	u16 bd_number;
 	bool default_up;
@@ -1415,6 +1424,8 @@ struct wx {
 #define WX_INTR_ALL (~0ULL)
 #define WX_INTR_Q(i) BIT((i))
 
+#define WX_FAILED_READ_CFG_WORD  0xffffU
+
 /* register operations */
 #define wr32(a, reg, value)	writel((value), ((a)->hw_addr + (reg)))
 #define rd32(a, reg)		readl((a)->hw_addr + (reg))
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index 3171a98d81a6..653a98d9835b 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -234,6 +234,12 @@ static irqreturn_t __ngbe_msix_misc(struct wx *wx, u32 eicr)
 	if (eicr & NGBE_PX_MISC_IC_VF_MBOX)
 		wx_msg_task(wx);
 
+	if (eicr & NGBE_PX_MISC_PCIE_REQ_ERR) {
+		wx_warn(wx, "PCIe Request Error founded on Lan %d\n",
+			wx->bus.func);
+		wx_pcie_error_handler(wx);
+	}
+
 	if (unlikely(eicr & NGBE_PX_MISC_IC_TIMESYNC))
 		wx_ptp_check_pps_event(wx);
 
@@ -392,6 +398,7 @@ static void ngbe_disable_device(struct wx *wx)
 	netif_tx_stop_all_queues(netdev);
 	netif_tx_disable(netdev);
 	timer_delete_sync(&wx->service_timer);
+	wx_set_pci_lan_up(wx, false);
 	if (wx->gpio_ctrl)
 		ngbe_sfp_modules_txrx_powerctl(wx, false);
 	wx_irq_disable(wx);
@@ -439,6 +446,8 @@ static void ngbe_up_complete(struct wx *wx)
 	netif_tx_start_all_queues(wx->netdev);
 	mod_timer(&wx->service_timer, jiffies);
 
+	wx_set_pci_lan_up(wx, true);
+
 	/* clear any pending interrupts, may auto mask */
 	rd32(wx, WX_PX_IC(0));
 	rd32(wx, WX_PX_MISC_IC);
@@ -819,6 +828,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 +878,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 +891,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/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
index eb5c92edae06..69ee8f1f74f0 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
@@ -70,12 +70,14 @@
 #define NGBE_PX_MISC_IEN_INT_ERR		BIT(20)
 #define NGBE_PX_MISC_IC_VF_MBOX			BIT(23)
 #define NGBE_PX_MISC_IEN_GPIO			BIT(26)
+#define NGBE_PX_MISC_PCIE_REQ_ERR		BIT(27)
 #define NGBE_PX_MISC_IEN_MASK ( \
 				NGBE_PX_MISC_IEN_DEV_RST | \
 				NGBE_PX_MISC_IEN_TIMESYNC | \
 				NGBE_PX_MISC_IEN_ETH_LK | \
 				NGBE_PX_MISC_IEN_INT_ERR | \
 				NGBE_PX_MISC_IC_VF_MBOX | \
+				NGBE_PX_MISC_PCIE_REQ_ERR | \
 				NGBE_PX_MISC_IEN_GPIO)
 
 /* Extended Interrupt Cause Read */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c
index aa14958d439a..c832100bcb61 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c
@@ -6,6 +6,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_sriov.h"
@@ -178,6 +179,12 @@ static irqreturn_t txgbe_misc_irq_thread_fn(int irq, void *data)
 		handle_nested_irq(sub_irq);
 		nhandled++;
 	}
+	if (eicr & TXGBE_PX_MISC_PCIE_REQ_ERR) {
+		wx_warn(wx, "PCIe Request Error founded on Lan %d\n",
+			wx->bus.func);
+		wx_pcie_error_handler(wx);
+		nhandled++;
+	}
 	if (unlikely(eicr & TXGBE_PX_MISC_IC_TIMESYNC)) {
 		wx_ptp_check_pps_event(wx);
 		nhandled++;
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 8d2302c62ebf..48d418574ee8 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -182,6 +182,8 @@ static void txgbe_up_complete(struct wx *wx)
 	netif_tx_start_all_queues(netdev);
 	mod_timer(&wx->service_timer, jiffies);
 
+	wx_set_pci_lan_up(wx, true);
+
 	/* Set PF Reset Done bit so PF/VF Mail Ops can work */
 	wr32m(wx, WX_CFG_PORT_CTL, WX_CFG_PORT_CTL_PFRSTD,
 	      WX_CFG_PORT_CTL_PFRSTD);
@@ -231,11 +233,7 @@ static void txgbe_disable_device(struct wx *wx)
 
 	timer_delete_sync(&wx->service_timer);
 
-	if (wx->bus.func < 2)
-		wr32m(wx, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN_UP(wx->bus.func), 0);
-	else
-		wx_err(wx, "%s: invalid bus lan id %d\n",
-		       __func__, wx->bus.func);
+	wx_set_pci_lan_up(wx, false);
 
 	if (wx->num_vfs) {
 		/* Clear EITR Select mapping */
@@ -886,6 +884,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 +954,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 +967,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);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index e9360e935682..74ac762a8c34 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -54,8 +54,7 @@
 /* chip control Registers */
 #define TXGBE_MIS_RST                           0x1000C
 #define TXGBE_MIS_RST_MAC_RST(_i)               BIT(20 - (_i) * 3)
-#define TXGBE_MIS_PRB_CTL                       0x10010
-#define TXGBE_MIS_PRB_CTL_LAN_UP(_i)            BIT(1 - (_i))
+
 /* FMGR Registers */
 #define TXGBE_SPI_ILDR_STATUS                   0x10120
 #define TXGBE_SPI_ILDR_STATUS_PERST             BIT(0) /* PCIE_PERST is done */
@@ -89,10 +88,12 @@
 #define TXGBE_PX_MISC_INT_ERR                   BIT(20)
 #define TXGBE_PX_MISC_IC_VF_MBOX                BIT(23)
 #define TXGBE_PX_MISC_GPIO                      BIT(26)
+#define TXGBE_PX_MISC_PCIE_REQ_ERR              BIT(27)
 #define TXGBE_PX_MISC_IEN_MASK                            \
 	(TXGBE_PX_MISC_ETH_LKDN | TXGBE_PX_MISC_DEV_RST | \
 	 TXGBE_PX_MISC_ETH_EVENT | TXGBE_PX_MISC_ETH_LK | \
 	 TXGBE_PX_MISC_ETH_AN | TXGBE_PX_MISC_INT_ERR | \
+	 TXGBE_PX_MISC_PCIE_REQ_ERR | \
 	 TXGBE_PX_MISC_IC_VF_MBOX | TXGBE_PX_MISC_IC_TIMESYNC)
 
 /* Port cfg registers */
-- 
2.48.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ