Support to check pcie error and invoke aer driver to recover pcie. Signed-off-by: Jiawen Wu --- 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 #include +#include #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, ®s->uncor_status); + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®s->uncor_mask); + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, ®s->uncor_severity); + pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, ®s->cor_status); + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®s->cor_mask); + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®s->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 #include #include +#include #include #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