Refactor several ixgbe driver operations to check whether the
netdev they operate on is enabled. This will allow the system
to get synchronized, for example, during the PCI resets.
Fixes: f7f37e7ff2b9 ("ixgbe: handle close/suspend race with
netif_device_detach/present")
Signed-off-by: Sergey Temerkhanov <[email protected]>
Reviewed-by: Aleksandr Loktionov <[email protected]>
---
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 5 +++
.../net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c | 13 +++++-
.../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 34 +++++++++------
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 29 +++++++++----
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h | 1 +
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 42 +++++++++++++++++--
drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c | 4 +-
7 files changed, 101 insertions(+), 27 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index a5304390f975..bac3b85a1d63 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -955,6 +955,11 @@ extern char ixgbe_driver_name[];
extern char ixgbe_default_device_descr[];
#endif /* IXGBE_FCOE */
+static inline bool ixgbe_netif_running(struct net_device *netdev)
+{
+ return netif_running(netdev) && netif_device_present(netdev);
+}
+
int ixgbe_open(struct net_device *netdev);
int ixgbe_close(struct net_device *netdev);
void ixgbe_up(struct ixgbe_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
index 382d097e4b11..4420d3c32996 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
@@ -277,17 +277,23 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device
*netdev, int priority,
static void ixgbe_dcbnl_devreset(struct net_device *dev)
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(dev);
+ bool running;
+
+ if (!netif_device_present(dev))
+ return;
+
+ running = netif_running(dev);
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
usleep_range(1000, 2000);
- if (netif_running(dev))
+ if (running)
dev->netdev_ops->ndo_stop(dev);
ixgbe_clear_interrupt_scheme(adapter);
ixgbe_init_interrupt_scheme(adapter);
- if (netif_running(dev))
+ if (running)
dev->netdev_ops->ndo_open(dev);
clear_bit(__IXGBE_RESETTING, &adapter->state);
@@ -515,6 +521,9 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
+ if (!netif_device_present(dev))
+ return -ENETDOWN;
+
if (!adapter->ixgbe_ieee_ets) {
adapter->ixgbe_ieee_ets = kmalloc_obj(struct ieee_ets);
if (!adapter->ixgbe_ieee_ets)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 1e1db8435506..f6258d1276e3 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -468,6 +468,9 @@ static int ixgbe_set_link_ksettings(struct net_device
*netdev,
u32 advertised, old;
int err = 0;
+ if (!netif_device_present(netdev))
+ return -ENETDOWN;
+
if ((hw->phy.media_type == ixgbe_media_type_copper) ||
(hw->phy.multispeed_fiber)) {
/*
@@ -578,9 +581,9 @@ static void ixgbe_set_pauseparam_finalize(struct net_device
*netdev,
/* If the thing changed then we'll update and use new autoneg. */
if (memcmp(fc, &hw->fc, sizeof(*fc))) {
hw->fc = *fc;
- if (netif_running(netdev))
+ if (ixgbe_netif_running(netdev))
ixgbe_reinit_locked(adapter);
- else
+ else if (netif_device_present(netdev))
ixgbe_reset(adapter);
}
}
@@ -1268,7 +1271,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
usleep_range(1000, 2000);
- if (!netif_running(adapter->netdev)) {
+ if (!ixgbe_netif_running(adapter->netdev)) {
for (i = 0; i < adapter->num_tx_queues; i++)
adapter->tx_ring[i]->count = new_tx_count;
for (i = 0; i < adapter->num_xdp_queues; i++)
@@ -2251,10 +2254,11 @@ static void ixgbe_diag_test(struct net_device *netdev,
struct ethtool_test *eth_test, u64 *data)
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
- bool if_running = netif_running(netdev);
+ bool if_running = ixgbe_netif_running(netdev);
- if (ixgbe_removed(adapter->hw.hw_addr)) {
- e_err(hw, "Adapter removed - test blocked\n");
+ if (ixgbe_removed(adapter->hw.hw_addr) ||
+ !netif_device_present(netdev)) {
+ e_err(hw, "Adapter removed or detached - test blocked\n");
data[0] = 1;
data[1] = 1;
data[2] = 1;
@@ -2468,7 +2472,7 @@ static int ixgbe_nway_reset(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
- if (netif_running(netdev))
+ if (ixgbe_netif_running(netdev))
ixgbe_reinit_locked(adapter);
return 0;
@@ -2652,7 +2656,8 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
else
/* rx only or mixed */
q_vector->itr = rx_itr_param;
- ixgbe_write_eitr(q_vector);
+ if (netif_device_present(netdev))
+ ixgbe_write_eitr(q_vector);
}
/*
@@ -3696,6 +3701,9 @@ static int ixgbe_set_eee_e610(struct net_device *netdev,
kedata->eee_enabled)
return -EOPNOTSUPP;
+ if (!netif_device_present(netdev))
+ return -ENETDOWN;
+
hw->phy.eee_speeds_advertised = kedata->eee_enabled ?
hw->phy.eee_speeds_supported : 0;
@@ -3711,9 +3719,9 @@ static int ixgbe_set_eee_e610(struct net_device *netdev,
else
adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
- if (netif_running(netdev))
+ if (ixgbe_netif_running(netdev))
ixgbe_reinit_locked(adapter);
- else
+ else if (netif_device_present(netdev))
ixgbe_reset(adapter);
return 0;
@@ -3795,9 +3803,9 @@ static int ixgbe_set_eee(struct net_device *netdev,
struct ethtool_keee *edata)
}
/* reset link */
- if (netif_running(netdev))
+ if (ixgbe_netif_running(netdev))
ixgbe_reinit_locked(adapter);
- else
+ else if (netif_device_present(netdev))
ixgbe_reset(adapter);
return 0;
@@ -3879,7 +3887,7 @@ static int ixgbe_set_priv_flags(struct net_device
*netdev, u32 priv_flags)
adapter->flags2 = flags2;
/* reset interface to repopulate queues */
- if (netif_running(netdev))
+ if (ixgbe_netif_running(netdev))
ixgbe_reinit_locked(adapter);
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index 011fda9c6193..54d8b079ada4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -830,27 +830,34 @@ static void ixgbe_fcoe_ddp_disable(struct ixgbe_adapter
*adapter)
*
* Turns on FCoE offload feature in 82599.
*
- * Returns : 0 indicates success or -EINVAL on failure
+ * Returns: 0 on success or a negative error code on failure
*/
int ixgbe_fcoe_enable(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
struct ixgbe_fcoe *fcoe = &adapter->fcoe;
+ bool running;
+ /* libfcoe calls ndo_fcoe_disable() even when this callback fails. */
atomic_inc(&fcoe->refcnt);
+ if (!netif_device_present(netdev))
+ return -ENETDOWN;
+
if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE))
return -EINVAL;
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
return -EINVAL;
+ running = netif_running(netdev);
+
e_info(drv, "Enabling FCoE offload features.\n");
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
e_warn(probe, "Enabling FCoE on PF will disable legacy VFs\n");
- if (netif_running(netdev))
+ if (running)
netdev->netdev_ops->ndo_stop(netdev);
/* Allocate per CPU memory to track DDP pools */
@@ -864,8 +871,9 @@ int ixgbe_fcoe_enable(struct net_device *netdev)
/* release existing queues and reallocate them */
ixgbe_clear_interrupt_scheme(adapter);
ixgbe_init_interrupt_scheme(adapter);
+ adapter->fcoe.reinit_pending = false;
- if (netif_running(netdev))
+ if (running)
netdev->netdev_ops->ndo_open(netdev);
return 0;
@@ -882,6 +890,7 @@ int ixgbe_fcoe_enable(struct net_device *netdev)
int ixgbe_fcoe_disable(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
+ bool running;
if (!atomic_dec_and_test(&adapter->fcoe.refcnt))
return -EINVAL;
@@ -889,8 +898,10 @@ int ixgbe_fcoe_disable(struct net_device *netdev)
if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
return -EINVAL;
+ running = ixgbe_netif_running(netdev);
+
e_info(drv, "Disabling FCoE offload features.\n");
- if (netif_running(netdev))
+ if (running)
netdev->netdev_ops->ndo_stop(netdev);
/* Free per CPU memory to track DDP pools */
@@ -903,10 +914,14 @@ int ixgbe_fcoe_disable(struct net_device *netdev)
netdev_features_change(netdev);
/* release existing queues and reallocate them */
- ixgbe_clear_interrupt_scheme(adapter);
- ixgbe_init_interrupt_scheme(adapter);
+ if (netif_device_present(netdev)) {
+ ixgbe_clear_interrupt_scheme(adapter);
+ ixgbe_init_interrupt_scheme(adapter);
+ } else {
+ adapter->fcoe.reinit_pending = true;
+ }
- if (netif_running(netdev))
+ if (running)
netdev->netdev_ops->ndo_open(netdev);
return 0;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
index 724f5382329f..81de590268cc 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
@@ -58,6 +58,7 @@ struct ixgbe_fcoe {
dma_addr_t extra_ddp_buffer_dma;
unsigned long mode;
u8 up;
+ bool reinit_pending;
};
#endif /* _IXGBE_FCOE_H */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index a219590b3118..1f23a035a90b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -182,6 +182,7 @@ EXPORT_SYMBOL(ixgbe_xdp_locking_key);
static struct workqueue_struct *ixgbe_wq;
static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev);
+static int ixgbe_rebuild_fcoe_queues(struct ixgbe_adapter *adapter);
static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *);
static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *);
static void ixgbe_watchdog_update_link(struct ixgbe_adapter *);
@@ -7395,7 +7396,7 @@ static int ixgbe_change_mtu(struct net_device *netdev,
int new_mtu)
/* must set new MTU before calling down or up */
WRITE_ONCE(netdev->mtu, new_mtu);
- if (netif_running(netdev))
+ if (ixgbe_netif_running(netdev))
ixgbe_reinit_locked(adapter);
return 0;
@@ -7423,6 +7424,10 @@ int ixgbe_open(struct net_device *netdev)
if (test_bit(__IXGBE_TESTING, &adapter->state))
return -EBUSY;
+ err = ixgbe_rebuild_fcoe_queues(adapter);
+ if (err)
+ return err;
+
netif_carrier_off(netdev);
/* allocate transmit descriptors */
@@ -12345,6 +12350,24 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct
pci_dev *pdev)
return result;
}
+static int ixgbe_rebuild_fcoe_queues(struct ixgbe_adapter *adapter)
+{
+#ifdef IXGBE_FCOE
+ int err;
+
+ if (!adapter->fcoe.reinit_pending)
+ return 0;
+
+ ixgbe_clear_interrupt_scheme(adapter);
+ err = ixgbe_init_interrupt_scheme(adapter);
+ if (err)
+ return err;
+
+ adapter->fcoe.reinit_pending = false;
+#endif
+ return 0;
+}
+
/**
* ixgbe_io_resume - called when traffic can start flowing again.
* @pdev: Pointer to PCI device
@@ -12356,6 +12379,8 @@ static void ixgbe_io_resume(struct pci_dev *pdev)
{
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
+ bool running;
+ int err;
#ifdef CONFIG_PCI_IOV
if (adapter->vferr_refcount) {
@@ -12366,8 +12391,19 @@ static void ixgbe_io_resume(struct pci_dev *pdev)
#endif
rtnl_lock();
- if (netif_running(netdev))
- ixgbe_open(netdev);
+ running = netif_running(netdev);
+ err = ixgbe_rebuild_fcoe_queues(adapter);
+ if (err)
+ e_dev_err("Cannot rebuild queue layout after PCI error
recovery: %d\n",
+ err);
+ if (running && !err) {
+ err = ixgbe_open(netdev);
+ if (err)
+ e_dev_err("Cannot re-open netdev after PCI error
recovery: %d\n",
+ err);
+ }
+ if (err && running)
+ dev_close(netdev);
netif_device_attach(netdev);
rtnl_unlock();
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
index 89f96c463f02..02820982b202 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
@@ -39,7 +39,7 @@ static int ixgbe_xsk_pool_enable(struct ixgbe_adapter
*adapter,
if (err)
return err;
- if_running = netif_running(adapter->netdev) &&
+ if_running = ixgbe_netif_running(adapter->netdev) &&
ixgbe_enabled_xdp_adapter(adapter);
if (if_running)
@@ -71,7 +71,7 @@ static int ixgbe_xsk_pool_disable(struct ixgbe_adapter
*adapter, u16 qid)
if (!pool)
return -EINVAL;
- if_running = netif_running(adapter->netdev) &&
+ if_running = ixgbe_netif_running(adapter->netdev) &&
ixgbe_enabled_xdp_adapter(adapter);
if (if_running)
--
2.53.0