mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
Merge branch 'net-wangxun-timeout-and-error'
Jiawen Wu says: ==================== net: wangxun: timeout and error It is about adding the Tx timeout process and pci_error_handlers. When a PCIe error occurs, the txgbe device is able to recover on platform that support AER interrupt. And for Tx timeout, the txgbe driver can recover the device by reset process. For ngbe devices, due to the absence of the current function, it cannot br fully recovered once there is a PCIe error or Tx timeout. Its function will be completed in the future. ==================== Link: https://patch.msgid.link/20260803064334.21876-1-jiawenwu@trustnetic.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
417c619e7d
|
|
@ -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
|
||||
|
|
|
|||
332
drivers/net/ethernet/wangxun/libwx/wx_err.c
Normal file
332
drivers/net/ethernet/wangxun/libwx/wx_err.c
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2015 - 2026 Beijing WangXun Technology Co., Ltd. */
|
||||
/* Copyright (c) 1999 - 2026 Intel Corporation. */
|
||||
|
||||
#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;
|
||||
|
||||
rtnl_lock();
|
||||
netif_device_detach(netdev);
|
||||
set_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags);
|
||||
wx_soft_quiesce(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);
|
||||
|
||||
if (pci_enable_device_mem(pdev)) {
|
||||
wx_err(wx, "Cannot re-enable PCI device after reset.\n");
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_pf_reset_subtask(struct wx *wx)
|
||||
{
|
||||
if (!test_and_clear_bit(WX_FLAG_NEED_DO_RESET, wx->flags))
|
||||
return;
|
||||
|
||||
wx_warn(wx, "Reset adapter.\n");
|
||||
if (wx->do_reset)
|
||||
wx->do_reset(wx->netdev, true);
|
||||
}
|
||||
|
||||
static void wx_reset_task(struct work_struct *work)
|
||||
{
|
||||
struct wx *wx = container_of(work, struct wx, reset_task);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
/* If the device has been detached (e.g., due to AER error handling),
|
||||
* abort the reset task to prevent operating on a dead or unmanaged
|
||||
* hardware.
|
||||
*/
|
||||
if (!netif_device_present(wx->netdev))
|
||||
goto out;
|
||||
|
||||
if (test_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags)) {
|
||||
/* Double check: Verify if the PCIe error is still present. */
|
||||
if (wx_check_pcie_error(wx))
|
||||
wx_soft_quiesce(wx);
|
||||
else
|
||||
clear_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_bit(WX_STATE_DOWN, wx->state) ||
|
||||
test_bit(WX_STATE_RESETTING, wx->state))
|
||||
goto out;
|
||||
|
||||
wx_pf_reset_subtask(wx);
|
||||
|
||||
out:
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
void wx_check_err_subtask(struct wx *wx)
|
||||
{
|
||||
if (test_bit(WX_FLAG_NEED_DO_RESET, wx->flags))
|
||||
queue_work(wx->reset_wq, &wx->reset_task);
|
||||
}
|
||||
EXPORT_SYMBOL(wx_check_err_subtask);
|
||||
|
||||
int wx_init_err_task(struct wx *wx)
|
||||
{
|
||||
wx->reset_wq = alloc_workqueue("%s_reset_wq_%x", WQ_UNBOUND | WQ_HIGHPRI,
|
||||
1, wx->driver_name, pci_dev_id(wx->pdev));
|
||||
if (!wx->reset_wq) {
|
||||
wx_err(wx, "Failed to create wx_reset_wq workqueue\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_WORK(&wx->reset_task, wx_reset_task);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(wx_init_err_task);
|
||||
|
||||
static bool wx_ring_tx_pending(struct wx *wx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < wx->num_tx_queues; i++) {
|
||||
struct wx_ring *tx_ring = wx->tx_ring[i];
|
||||
|
||||
if (tx_ring->next_to_use != tx_ring->next_to_clean)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool wx_vf_tx_pending(struct wx *wx)
|
||||
{
|
||||
struct wx_ring_feature *vmdq = &wx->ring_feature[RING_F_VMDQ];
|
||||
u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
|
||||
u32 i, j;
|
||||
|
||||
if (!wx->num_vfs)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < wx->num_vfs; i++) {
|
||||
for (j = 0; j < q_per_pool; j++) {
|
||||
u32 h, t;
|
||||
|
||||
h = rd32(wx, WX_PX_TR_RP_PV(q_per_pool, i, j));
|
||||
t = rd32(wx, WX_PX_TR_WP_PV(q_per_pool, i, j));
|
||||
|
||||
if (h != t)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wx_watchdog_flush_tx(struct wx *wx)
|
||||
{
|
||||
if (!netif_running(wx->netdev))
|
||||
return;
|
||||
if (netif_carrier_ok(wx->netdev))
|
||||
return;
|
||||
|
||||
if (wx_ring_tx_pending(wx) || wx_vf_tx_pending(wx)) {
|
||||
/* We've lost link, so the controller stops DMA,
|
||||
* but we've got queued Tx work that's never going
|
||||
* to get done, so reset controller to flush Tx.
|
||||
* (Do the reset outside of interrupt context).
|
||||
*/
|
||||
wx_warn(wx, "initiating reset due to lost link with pending Tx work\n");
|
||||
set_bit(WX_FLAG_NEED_DO_RESET, wx->flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void wx_detect_tx_hang(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_check_hang_subtask(struct wx *wx)
|
||||
{
|
||||
if (test_bit(WX_STATE_DOWN, wx->state) ||
|
||||
test_bit(WX_STATE_RESETTING, wx->state))
|
||||
return;
|
||||
|
||||
wx_watchdog_flush_tx(wx);
|
||||
wx_detect_tx_hang(wx);
|
||||
}
|
||||
EXPORT_SYMBOL(wx_check_hang_subtask);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void wx_tx_timeout_reset(struct wx *wx)
|
||||
{
|
||||
if (test_bit(WX_STATE_DOWN, wx->state))
|
||||
return;
|
||||
|
||||
set_bit(WX_FLAG_NEED_DO_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 __always_unused txqueue)
|
||||
{
|
||||
struct wx *wx = netdev_priv(netdev);
|
||||
|
||||
if (wx_check_pcie_error(wx))
|
||||
wx_tx_timeout_recovery(wx);
|
||||
else
|
||||
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: Queue %d, TDH %x, TDT %x, ntu %x, ntc %x, ntc.time_stamp %lx, 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_tx_timeout_reset(wx);
|
||||
}
|
||||
18
drivers/net/ethernet/wangxun/libwx/wx_err.h
Normal file
18
drivers/net/ethernet/wangxun/libwx/wx_err.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* 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_
|
||||
|
||||
extern const struct pci_error_handlers wx_err_handler;
|
||||
|
||||
void wx_check_err_subtask(struct wx *wx);
|
||||
int wx_init_err_task(struct wx *wx);
|
||||
void wx_check_hang_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_ */
|
||||
|
|
@ -397,7 +397,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,
|
||||
|
|
|
|||
|
|
@ -1932,6 +1932,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);
|
||||
|
|
@ -2851,16 +2852,26 @@ EXPORT_SYMBOL(wx_fc_enable);
|
|||
static void wx_update_xoff_rx_lfc(struct wx *wx)
|
||||
{
|
||||
struct wx_hw_stats *hwstats = &wx->stats;
|
||||
u64 data;
|
||||
int i;
|
||||
|
||||
if (wx->fc.mode != wx_fc_full &&
|
||||
wx->fc.mode != wx_fc_rx_pause)
|
||||
return;
|
||||
|
||||
if (wx->mac.type >= wx_mac_aml)
|
||||
hwstats->lxoffrxc += rd32_wrap(wx, WX_MAC_LXOFFRXC_AML,
|
||||
&wx->last_stats.lxoffrxc);
|
||||
data = rd32_wrap(wx, WX_MAC_LXOFFRXC_AML,
|
||||
&wx->last_stats.lxoffrxc);
|
||||
else
|
||||
hwstats->lxoffrxc += rd64(wx, WX_MAC_LXOFFRXC);
|
||||
data = rd64(wx, WX_MAC_LXOFFRXC);
|
||||
hwstats->lxoffrxc += data;
|
||||
|
||||
/* refill credits (no tx hang) if we received xoff */
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < wx->num_tx_queues; i++)
|
||||
clear_bit(WX_HANG_CHECK_ARMED, wx->tx_ring[i]->state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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,37 @@ static struct netdev_queue *wx_txring_txq(const struct wx_ring *ring)
|
|||
return netdev_get_tx_queue(ring->netdev, ring->queue_index);
|
||||
}
|
||||
|
||||
static u32 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;
|
||||
}
|
||||
|
||||
static bool wx_check_tx_hang(struct wx_ring *ring)
|
||||
{
|
||||
u32 tx_done_old = ring->tx_stats.tx_done_old;
|
||||
u32 tx_pending = wx_get_tx_pending(ring);
|
||||
u32 tx_done = ring->stats.packets;
|
||||
|
||||
if (!test_and_clear_bit(WX_TX_DETECT_HANG, ring->state))
|
||||
return false;
|
||||
|
||||
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 +898,11 @@ 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 (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))) {
|
||||
|
|
@ -3114,7 +3151,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);
|
||||
|
||||
|
|
@ -3164,7 +3201,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;
|
||||
}
|
||||
|
|
@ -3373,5 +3410,23 @@ void wx_service_timer(struct timer_list *t)
|
|||
}
|
||||
EXPORT_SYMBOL(wx_service_timer);
|
||||
|
||||
void wx_soft_quiesce(struct wx *wx)
|
||||
{
|
||||
if (!netif_running(wx->netdev) ||
|
||||
test_and_set_bit(WX_STATE_DOWN, wx->state))
|
||||
return;
|
||||
|
||||
pci_clear_master(wx->pdev);
|
||||
netif_tx_stop_all_queues(wx->netdev);
|
||||
netif_carrier_off(wx->netdev);
|
||||
netif_tx_disable(wx->netdev);
|
||||
wx_napi_disable_all(wx);
|
||||
wx_ptp_quiesce(wx);
|
||||
|
||||
clear_bit(WX_FLAG_NEED_DO_RESET, wx->flags);
|
||||
timer_delete_sync(&wx->service_timer);
|
||||
}
|
||||
EXPORT_SYMBOL(wx_soft_quiesce);
|
||||
|
||||
MODULE_DESCRIPTION("Common library for Wangxun(R) Ethernet drivers.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -41,5 +41,6 @@ int 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);
|
||||
void wx_soft_quiesce(struct wx *wx);
|
||||
|
||||
#endif /* _WX_LIB_H_ */
|
||||
|
|
|
|||
|
|
@ -321,6 +321,9 @@ static long wx_ptp_do_aux_work(struct ptp_clock_info *ptp)
|
|||
struct wx *wx = container_of(ptp, struct wx, ptp_caps);
|
||||
int ts_done;
|
||||
|
||||
if (!test_bit(WX_STATE_PTP_RUNNING, wx->state))
|
||||
return HZ;
|
||||
|
||||
ts_done = wx_ptp_tx_hwtstamp_work(wx);
|
||||
|
||||
wx_ptp_overflow_check(wx);
|
||||
|
|
@ -842,6 +845,30 @@ void wx_ptp_stop(struct wx *wx)
|
|||
}
|
||||
EXPORT_SYMBOL(wx_ptp_stop);
|
||||
|
||||
void wx_ptp_quiesce(struct wx *wx)
|
||||
{
|
||||
if (!test_and_clear_bit(WX_STATE_PTP_RUNNING, wx->state))
|
||||
return;
|
||||
|
||||
clear_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags);
|
||||
|
||||
if (wx->ptp_clock)
|
||||
ptp_cancel_worker_sync(wx->ptp_clock);
|
||||
|
||||
if (wx->ptp_tx_skb) {
|
||||
dev_kfree_skb_any(wx->ptp_tx_skb);
|
||||
wx->ptp_tx_skb = NULL;
|
||||
}
|
||||
clear_bit_unlock(WX_STATE_PTP_TX_IN_PROGRESS, wx->state);
|
||||
|
||||
if (wx->ptp_clock) {
|
||||
ptp_clock_unregister(wx->ptp_clock);
|
||||
wx->ptp_clock = NULL;
|
||||
dev_info(&wx->pdev->dev, "removed PHC on %s\n", wx->netdev->name);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(wx_ptp_quiesce);
|
||||
|
||||
/**
|
||||
* wx_ptp_rx_hwtstamp - utility function which checks for RX time stamp
|
||||
* @wx: pointer to wx struct
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ void wx_ptp_reset(struct wx *wx);
|
|||
void wx_ptp_init(struct wx *wx);
|
||||
void wx_ptp_suspend(struct wx *wx);
|
||||
void wx_ptp_stop(struct wx *wx);
|
||||
void wx_ptp_quiesce(struct wx *wx);
|
||||
void wx_ptp_rx_hwtstamp(struct wx *wx, struct sk_buff *skb);
|
||||
int wx_hwtstamp_get(struct net_device *dev,
|
||||
struct kernel_hwtstamp_config *cfg);
|
||||
|
|
|
|||
|
|
@ -450,6 +450,11 @@ enum WX_MSCA_CMD_value {
|
|||
#define WX_PX_TR_CFG_THRE_SHIFT 8
|
||||
#define WX_PX_TR_CFG_HEAD_WB BIT(27)
|
||||
|
||||
#define WX_PX_TR_RP_PV(q_per_pool, vf_number, vf_q_index) \
|
||||
(WX_PX_TR_RP((q_per_pool) * (vf_number) + (vf_q_index)))
|
||||
#define WX_PX_TR_WP_PV(q_per_pool, vf_number, vf_q_index) \
|
||||
(WX_PX_TR_WP((q_per_pool) * (vf_number) + (vf_q_index)))
|
||||
|
||||
/* Receive DMA Registers */
|
||||
#define WX_PX_RR_BAL(_i) (0x01000 + ((_i) * 0x40))
|
||||
#define WX_PX_RR_BAH(_i) (0x01004 + ((_i) * 0x40))
|
||||
|
|
@ -1040,6 +1045,7 @@ struct wx_queue_stats {
|
|||
struct wx_tx_queue_stats {
|
||||
u64 restart_queue;
|
||||
u64 tx_busy;
|
||||
u32 tx_done_old;
|
||||
};
|
||||
|
||||
struct wx_rx_queue_stats {
|
||||
|
|
@ -1055,6 +1061,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 */
|
||||
|
|
@ -1074,6 +1086,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;
|
||||
|
|
@ -1209,6 +1222,8 @@ enum wx_state {
|
|||
WX_STATE_PTP_RUNNING,
|
||||
WX_STATE_PTP_TX_IN_PROGRESS,
|
||||
WX_STATE_SERVICE_SCHED,
|
||||
WX_STATE_DISABLED,
|
||||
WX_STATE_RES_FREED,
|
||||
WX_STATE_NBITS /* must be last */
|
||||
};
|
||||
|
||||
|
|
@ -1275,6 +1290,7 @@ enum wx_pf_flags {
|
|||
WX_FLAG_NEED_DO_RESET,
|
||||
WX_FLAG_RX_MERGE_ENABLED,
|
||||
WX_FLAG_TXHEAD_WB_ENABLED,
|
||||
WX_FLAG_NEED_PCIE_RECOVERY,
|
||||
WX_PF_FLAGS_NBITS /* must be last */
|
||||
};
|
||||
|
||||
|
|
@ -1395,7 +1411,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 (*down_suspend)(struct wx *wx);
|
||||
int (*ptp_setup_sdp)(struct wx *wx);
|
||||
void (*set_num_queues)(struct wx *wx);
|
||||
|
||||
|
|
@ -1423,6 +1440,8 @@ struct wx {
|
|||
|
||||
struct timer_list service_timer;
|
||||
struct work_struct service_task;
|
||||
struct work_struct reset_task;
|
||||
struct workqueue_struct *reset_wq;
|
||||
struct mutex reset_lock; /* mutex for reset */
|
||||
};
|
||||
|
||||
|
|
@ -1505,7 +1524,8 @@ rd32_wrap(struct wx *wx, u32 reg, u32 *last)
|
|||
|
||||
#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)
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,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:
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -46,6 +47,20 @@ static const struct pci_device_id ngbe_pci_tbl[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static void ngbe_down_suspend(struct wx *wx)
|
||||
{
|
||||
if (test_and_set_bit(WX_STATE_RES_FREED, wx->state))
|
||||
return;
|
||||
|
||||
phylink_stop(wx->phylink);
|
||||
phylink_disconnect_phy(wx->phylink);
|
||||
wx_clean_all_tx_rings(wx);
|
||||
wx_clean_all_rx_rings(wx);
|
||||
wx_free_irq(wx);
|
||||
wx_free_isb_resources(wx);
|
||||
wx_free_resources(wx);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_init_type_code - Initialize the shared code
|
||||
* @wx: pointer to hardware structure
|
||||
|
|
@ -133,6 +148,8 @@ 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->down_suspend = ngbe_down_suspend;
|
||||
set_bit(0, &wx->fwd_bitmask);
|
||||
|
||||
return 0;
|
||||
|
|
@ -147,6 +164,8 @@ static void ngbe_service_task(struct work_struct *work)
|
|||
struct wx *wx = container_of(work, struct wx, service_task);
|
||||
|
||||
wx_update_stats(wx);
|
||||
wx_check_hang_subtask(wx);
|
||||
wx_check_err_subtask(wx);
|
||||
|
||||
wx_service_event_complete(wx);
|
||||
}
|
||||
|
|
@ -392,6 +411,7 @@ static void ngbe_disable_device(struct wx *wx)
|
|||
netif_tx_stop_all_queues(netdev);
|
||||
netif_tx_disable(netdev);
|
||||
|
||||
clear_bit(WX_FLAG_NEED_DO_RESET, wx->flags);
|
||||
timer_delete_sync(&wx->service_timer);
|
||||
cancel_work_sync(&wx->service_task);
|
||||
|
||||
|
|
@ -408,6 +428,9 @@ static void ngbe_disable_device(struct wx *wx)
|
|||
|
||||
static void ngbe_reset(struct wx *wx)
|
||||
{
|
||||
if (test_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags))
|
||||
return;
|
||||
|
||||
wx_flush_sw_mac_table(wx);
|
||||
wx_mac_set_default_filter(wx, wx->mac.addr);
|
||||
if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
|
||||
|
|
@ -423,13 +446,14 @@ 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);
|
||||
|
||||
/* make sure to complete pre-operations */
|
||||
smp_mb__before_atomic();
|
||||
clear_bit(WX_STATE_DOWN, wx->state);
|
||||
clear_bit(WX_STATE_RES_FREED, wx->state);
|
||||
wx_napi_enable_all(wx);
|
||||
/* enable transmits */
|
||||
netif_tx_start_all_queues(wx->netdev);
|
||||
|
|
@ -490,7 +514,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:
|
||||
|
|
@ -503,6 +527,12 @@ static int ngbe_open(struct net_device *netdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
void ngbe_up(struct wx *wx)
|
||||
{
|
||||
wx_configure(wx);
|
||||
ngbe_up_complete(wx);
|
||||
}
|
||||
|
||||
/**
|
||||
* ngbe_close - Disables a network interface
|
||||
* @netdev: network interface device structure
|
||||
|
|
@ -518,12 +548,16 @@ static int ngbe_close(struct net_device *netdev)
|
|||
{
|
||||
struct wx *wx = netdev_priv(netdev);
|
||||
|
||||
if (test_bit(WX_STATE_RES_FREED, wx->state))
|
||||
goto out;
|
||||
|
||||
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);
|
||||
out:
|
||||
wx_control_hw(wx, false);
|
||||
|
||||
return 0;
|
||||
|
|
@ -555,7 +589,8 @@ static void ngbe_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);
|
||||
}
|
||||
|
||||
static void ngbe_shutdown(struct pci_dev *pdev)
|
||||
|
|
@ -590,6 +625,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);
|
||||
|
||||
|
|
@ -606,11 +643,36 @@ int ngbe_setup_tc(struct net_device *dev, u8 tc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ngbe_reinit_locked(struct wx *wx)
|
||||
{
|
||||
netif_trans_update(wx->netdev);
|
||||
|
||||
mutex_lock(&wx->reset_lock);
|
||||
set_bit(WX_STATE_RESETTING, wx->state);
|
||||
|
||||
ngbe_down(wx);
|
||||
ngbe_up(wx);
|
||||
|
||||
clear_bit(WX_STATE_RESETTING, wx->state);
|
||||
mutex_unlock(&wx->reset_lock);
|
||||
}
|
||||
|
||||
void ngbe_do_reset(struct net_device *netdev, bool reinit)
|
||||
{
|
||||
struct wx *wx = netdev_priv(netdev);
|
||||
|
||||
if (netif_running(netdev) && reinit)
|
||||
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,
|
||||
.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,
|
||||
|
|
@ -796,6 +858,10 @@ 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);
|
||||
|
||||
err = wx_init_err_task(wx);
|
||||
if (err)
|
||||
goto err_free_mac_table;
|
||||
|
||||
ngbe_init_service(wx);
|
||||
|
||||
err = wx_init_interrupt_scheme(wx);
|
||||
|
|
@ -812,6 +878,7 @@ static int ngbe_probe(struct pci_dev *pdev,
|
|||
goto err_register;
|
||||
|
||||
pci_set_drvdata(pdev, wx);
|
||||
pci_save_state(pdev);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -823,6 +890,8 @@ static int ngbe_probe(struct pci_dev *pdev,
|
|||
err_cancel_service:
|
||||
timer_delete_sync(&wx->service_timer);
|
||||
cancel_work_sync(&wx->service_task);
|
||||
cancel_work_sync(&wx->reset_task);
|
||||
destroy_workqueue(wx->reset_wq);
|
||||
err_free_mac_table:
|
||||
kfree(wx->rss_key);
|
||||
kfree(wx->mac_table);
|
||||
|
|
@ -854,6 +923,8 @@ static void ngbe_remove(struct pci_dev *pdev)
|
|||
|
||||
timer_shutdown_sync(&wx->service_timer);
|
||||
cancel_work_sync(&wx->service_task);
|
||||
cancel_work_sync(&wx->reset_task);
|
||||
destroy_workqueue(wx->reset_wq);
|
||||
|
||||
phylink_destroy(wx->phylink);
|
||||
pci_release_selected_regions(pdev,
|
||||
|
|
@ -863,7 +934,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 int ngbe_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
|
@ -890,6 +962,7 @@ static int ngbe_resume(struct pci_dev *pdev)
|
|||
wx_err(wx, "Cannot enable PCI device from suspend\n");
|
||||
return err;
|
||||
}
|
||||
clear_bit(WX_STATE_DISABLED, wx->state);
|
||||
pci_set_master(pdev);
|
||||
device_wakeup_disable(&pdev->dev);
|
||||
|
||||
|
|
@ -914,6 +987,7 @@ static struct pci_driver ngbe_driver = {
|
|||
.resume = ngbe_resume,
|
||||
.shutdown = ngbe_shutdown,
|
||||
.sriov_configure = wx_pci_sriov_configure,
|
||||
.err_handler = &wx_err_handler,
|
||||
};
|
||||
|
||||
module_pci_driver(ngbe_driver);
|
||||
|
|
|
|||
|
|
@ -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, bool reinit);
|
||||
|
||||
#endif /* _NGBE_TYPE_H_ */
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -93,12 +94,24 @@ static void txgbe_module_detection_subtask(struct wx *wx)
|
|||
{
|
||||
int err;
|
||||
|
||||
if (test_bit(WX_STATE_DOWN, wx->state) ||
|
||||
test_bit(WX_STATE_RESETTING, wx->state))
|
||||
return;
|
||||
|
||||
if (!test_and_clear_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags))
|
||||
return;
|
||||
|
||||
/* wait for SFF module ready */
|
||||
msleep(200);
|
||||
|
||||
/* Re-check state to avoid racing with down/reset paths.
|
||||
* Module identification is deferred to the next up event,
|
||||
* so it is safe to bail out here.
|
||||
*/
|
||||
if (test_bit(WX_STATE_DOWN, wx->state) ||
|
||||
test_bit(WX_STATE_RESETTING, wx->state))
|
||||
return;
|
||||
|
||||
err = txgbe_identify_module(wx);
|
||||
if (err == -ENODEV)
|
||||
set_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags);
|
||||
|
|
@ -106,6 +119,10 @@ static void txgbe_module_detection_subtask(struct wx *wx)
|
|||
|
||||
static void txgbe_link_config_subtask(struct wx *wx)
|
||||
{
|
||||
if (test_bit(WX_STATE_DOWN, wx->state) ||
|
||||
test_bit(WX_STATE_RESETTING, wx->state))
|
||||
return;
|
||||
|
||||
if (!test_and_clear_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags))
|
||||
return;
|
||||
|
||||
|
|
@ -123,6 +140,8 @@ static void txgbe_service_task(struct work_struct *work)
|
|||
txgbe_module_detection_subtask(wx);
|
||||
txgbe_link_config_subtask(wx);
|
||||
wx_update_stats(wx);
|
||||
wx_check_hang_subtask(wx);
|
||||
wx_check_err_subtask(wx);
|
||||
|
||||
wx_service_event_complete(wx);
|
||||
}
|
||||
|
|
@ -144,6 +163,7 @@ static void txgbe_up_complete(struct wx *wx)
|
|||
/* make sure to complete pre-operations */
|
||||
smp_mb__before_atomic();
|
||||
clear_bit(WX_STATE_DOWN, wx->state);
|
||||
clear_bit(WX_STATE_RES_FREED, wx->state);
|
||||
wx_napi_enable_all(wx);
|
||||
|
||||
switch (wx->mac.type) {
|
||||
|
|
@ -187,6 +207,9 @@ static void txgbe_reset(struct wx *wx)
|
|||
u8 old_addr[ETH_ALEN];
|
||||
int err;
|
||||
|
||||
if (test_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags))
|
||||
return;
|
||||
|
||||
err = txgbe_reset_hw(wx);
|
||||
if (err != 0)
|
||||
wx_err(wx, "Hardware Error: %d\n", err);
|
||||
|
|
@ -224,6 +247,7 @@ static void txgbe_disable_device(struct wx *wx)
|
|||
wx_irq_disable(wx);
|
||||
wx_napi_disable_all(wx);
|
||||
|
||||
clear_bit(WX_FLAG_NEED_DO_RESET, wx->flags);
|
||||
timer_delete_sync(&wx->service_timer);
|
||||
cancel_work_sync(&wx->service_task);
|
||||
|
||||
|
|
@ -292,6 +316,20 @@ void txgbe_up(struct wx *wx)
|
|||
txgbe_up_complete(wx);
|
||||
}
|
||||
|
||||
static void txgbe_down_suspend(struct wx *wx)
|
||||
{
|
||||
if (test_and_set_bit(WX_STATE_RES_FREED, wx->state))
|
||||
return;
|
||||
|
||||
phylink_stop(wx->phylink);
|
||||
wx_clean_all_tx_rings(wx);
|
||||
wx_clean_all_rx_rings(wx);
|
||||
wx_free_irq(wx);
|
||||
txgbe_free_misc_irq(wx->priv);
|
||||
wx_free_resources(wx);
|
||||
txgbe_fdir_filter_exit(wx);
|
||||
}
|
||||
|
||||
/**
|
||||
* txgbe_init_type_code - Initialize the shared code
|
||||
* @wx: pointer to hardware structure
|
||||
|
|
@ -408,6 +446,7 @@ static int txgbe_sw_init(struct wx *wx)
|
|||
|
||||
wx->setup_tc = txgbe_setup_tc;
|
||||
wx->do_reset = txgbe_do_reset;
|
||||
wx->down_suspend = txgbe_down_suspend;
|
||||
set_bit(0, &wx->fwd_bitmask);
|
||||
|
||||
switch (wx->mac.type) {
|
||||
|
|
@ -518,12 +557,16 @@ static int txgbe_close(struct net_device *netdev)
|
|||
{
|
||||
struct wx *wx = netdev_priv(netdev);
|
||||
|
||||
if (test_bit(WX_STATE_RES_FREED, wx->state))
|
||||
goto out;
|
||||
|
||||
wx_ptp_stop(wx);
|
||||
txgbe_down(wx);
|
||||
wx_free_irq(wx);
|
||||
txgbe_free_misc_irq(wx->priv);
|
||||
wx_free_resources(wx);
|
||||
txgbe_fdir_filter_exit(wx);
|
||||
out:
|
||||
wx_control_hw(wx, false);
|
||||
|
||||
return 0;
|
||||
|
|
@ -544,7 +587,8 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev)
|
|||
|
||||
wx_control_hw(wx, false);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
if (!test_and_set_bit(WX_STATE_DISABLED, wx->state))
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static void txgbe_shutdown(struct pci_dev *pdev)
|
||||
|
|
@ -606,11 +650,11 @@ static void txgbe_reinit_locked(struct wx *wx)
|
|||
mutex_unlock(&wx->reset_lock);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -654,6 +698,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,
|
||||
|
|
@ -814,6 +859,10 @@ 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);
|
||||
|
||||
err = wx_init_err_task(wx);
|
||||
if (err)
|
||||
goto err_free_mac_table;
|
||||
|
||||
txgbe_init_service(wx);
|
||||
|
||||
err = wx_init_interrupt_scheme(wx);
|
||||
|
|
@ -889,6 +938,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);
|
||||
|
||||
|
|
@ -916,6 +966,8 @@ static int txgbe_probe(struct pci_dev *pdev,
|
|||
err_cancel_service:
|
||||
timer_delete_sync(&wx->service_timer);
|
||||
cancel_work_sync(&wx->service_task);
|
||||
cancel_work_sync(&wx->reset_task);
|
||||
destroy_workqueue(wx->reset_wq);
|
||||
err_free_mac_table:
|
||||
kfree(wx->rss_key);
|
||||
kfree(wx->mac_table);
|
||||
|
|
@ -949,6 +1001,8 @@ static void txgbe_remove(struct pci_dev *pdev)
|
|||
|
||||
timer_shutdown_sync(&wx->service_timer);
|
||||
cancel_work_sync(&wx->service_task);
|
||||
cancel_work_sync(&wx->reset_task);
|
||||
destroy_workqueue(wx->reset_wq);
|
||||
|
||||
txgbe_remove_phy(txgbe);
|
||||
wx_free_isb_resources(wx);
|
||||
|
|
@ -960,7 +1014,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 = {
|
||||
|
|
@ -970,6 +1025,7 @@ static struct pci_driver txgbe_driver = {
|
|||
.remove = txgbe_remove,
|
||||
.shutdown = txgbe_shutdown,
|
||||
.sriov_configure = wx_pci_sriov_configure,
|
||||
.err_handler = &wx_err_handler,
|
||||
};
|
||||
|
||||
module_pci_driver(txgbe_driver);
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ 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);
|
||||
|
||||
#define DECLARE_PHY_INTERFACE_MASK_ZERO(name) \
|
||||
unsigned long name[PHY_INTERFACE_MODE_MAX] = { 0, }
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user