Commit 25f41150 authored by David S. Miller's avatar David S. Miller

Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue

Jeff Kirsher says:

====================
1GbE Intel Wired LAN Driver Updates 2017-06-06

This series contains updates and fixes to e1000e and igb.

Matwey V Kornilov fixes an issue where igb_get_phy_id_82575() relies on
the fact that page 0 is already selected, but this is not the case after
igb_read_phy_reg_gs40g()/igb_write_phy_reg_gs40g() were removed in a
previous commit.  This leads to initialization failure and some devices
not working.  To fix the issue, explicitly select page 0 before first
access to PHY registers.

Arnd Bergmann modifies the driver to avoid a "defined but not used"
warning by removing #ifdefs and using __maybe_unused annotation instead
for new power management functions.

Jake provides most of the changes in the series, all around PTP and
timestamp fixes/updates.  Resolved several race conditions based on
the hardware can only handle one transmit timestamp at a time, so
fix the locking logic, as well as create a statistic for "skipped"
timestamps to help administrators identify issues.

Benjamin Poirier provides 2 changes, first to igb to remove the
second argument to igb_update_stats() since it always passes the
same two arguments.  So instead of having to pass the second argument,
just update the function to the necessary information from the adapter
structure.  Second modifies the e1000e_get_stats64() call to
dev_get_stats() to avoid ethtool garbage being reported.

Konstantin Khlebnikov modifies e1000e to use disable_hardirq(), instead
of disable_irq() for MSIx vectors in e1000_netpoll().
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d15e5cc fd8e597b
...@@ -268,6 +268,7 @@ struct e1000_adapter { ...@@ -268,6 +268,7 @@ struct e1000_adapter {
u32 tx_fifo_size; u32 tx_fifo_size;
u32 tx_dma_failed; u32 tx_dma_failed;
u32 tx_hwtstamp_timeouts; u32 tx_hwtstamp_timeouts;
u32 tx_hwtstamp_skipped;
/* Rx */ /* Rx */
bool (*clean_rx)(struct e1000_ring *ring, int *work_done, bool (*clean_rx)(struct e1000_ring *ring, int *work_done,
......
...@@ -105,6 +105,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { ...@@ -105,6 +105,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
E1000_STAT("uncorr_ecc_errors", uncorr_errors), E1000_STAT("uncorr_ecc_errors", uncorr_errors),
E1000_STAT("corr_ecc_errors", corr_errors), E1000_STAT("corr_ecc_errors", corr_errors),
E1000_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), E1000_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
E1000_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
}; };
#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
...@@ -2072,7 +2073,7 @@ static void e1000_get_ethtool_stats(struct net_device *netdev, ...@@ -2072,7 +2073,7 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
pm_runtime_get_sync(netdev->dev.parent); pm_runtime_get_sync(netdev->dev.parent);
e1000e_get_stats64(netdev, &net_stats); dev_get_stats(netdev, &net_stats);
pm_runtime_put_sync(netdev->dev.parent); pm_runtime_put_sync(netdev->dev.parent);
......
...@@ -1183,6 +1183,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) ...@@ -1183,6 +1183,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) { if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
struct sk_buff *skb = adapter->tx_hwtstamp_skb;
struct skb_shared_hwtstamps shhwtstamps; struct skb_shared_hwtstamps shhwtstamps;
u64 txstmp; u64 txstmp;
...@@ -1191,9 +1192,14 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) ...@@ -1191,9 +1192,14 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp); e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp);
skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps); /* Clear the global tx_hwtstamp_skb pointer and force writes
dev_kfree_skb_any(adapter->tx_hwtstamp_skb); * prior to notifying the stack of a Tx timestamp.
*/
adapter->tx_hwtstamp_skb = NULL; adapter->tx_hwtstamp_skb = NULL;
wmb(); /* force write prior to skb_tstamp_tx */
skb_tstamp_tx(skb, &shhwtstamps);
dev_kfree_skb_any(skb);
} else if (time_after(jiffies, adapter->tx_hwtstamp_start } else if (time_after(jiffies, adapter->tx_hwtstamp_start
+ adapter->tx_timeout_factor * HZ)) { + adapter->tx_timeout_factor * HZ)) {
dev_kfree_skb_any(adapter->tx_hwtstamp_skb); dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
...@@ -5861,13 +5867,16 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, ...@@ -5861,13 +5867,16 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
nr_frags); nr_frags);
if (count) { if (count) {
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
(adapter->flags & FLAG_HAS_HW_TIMESTAMP) && (adapter->flags & FLAG_HAS_HW_TIMESTAMP)) {
!adapter->tx_hwtstamp_skb) { if (!adapter->tx_hwtstamp_skb) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= E1000_TX_FLAGS_HWTSTAMP; tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
adapter->tx_hwtstamp_skb = skb_get(skb); adapter->tx_hwtstamp_skb = skb_get(skb);
adapter->tx_hwtstamp_start = jiffies; adapter->tx_hwtstamp_start = jiffies;
schedule_work(&adapter->tx_hwtstamp_work); schedule_work(&adapter->tx_hwtstamp_work);
} else {
adapter->tx_hwtstamp_skipped++;
}
} }
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
...@@ -6734,20 +6743,20 @@ static irqreturn_t e1000_intr_msix(int __always_unused irq, void *data) ...@@ -6734,20 +6743,20 @@ static irqreturn_t e1000_intr_msix(int __always_unused irq, void *data)
vector = 0; vector = 0;
msix_irq = adapter->msix_entries[vector].vector; msix_irq = adapter->msix_entries[vector].vector;
disable_irq(msix_irq); if (disable_hardirq(msix_irq))
e1000_intr_msix_rx(msix_irq, netdev); e1000_intr_msix_rx(msix_irq, netdev);
enable_irq(msix_irq); enable_irq(msix_irq);
vector++; vector++;
msix_irq = adapter->msix_entries[vector].vector; msix_irq = adapter->msix_entries[vector].vector;
disable_irq(msix_irq); if (disable_hardirq(msix_irq))
e1000_intr_msix_tx(msix_irq, netdev); e1000_intr_msix_tx(msix_irq, netdev);
enable_irq(msix_irq); enable_irq(msix_irq);
vector++; vector++;
msix_irq = adapter->msix_entries[vector].vector; msix_irq = adapter->msix_entries[vector].vector;
disable_irq(msix_irq); if (disable_hardirq(msix_irq))
e1000_msix_other(msix_irq, netdev); e1000_msix_other(msix_irq, netdev);
enable_irq(msix_irq); enable_irq(msix_irq);
} }
......
...@@ -257,6 +257,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) ...@@ -257,6 +257,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
} }
/* Set phy->phy_addr and phy->id. */ /* Set phy->phy_addr and phy->id. */
igb_write_phy_reg_82580(hw, I347AT4_PAGE_SELECT, 0);
ret_val = igb_get_phy_id_82575(hw); ret_val = igb_get_phy_id_82575(hw);
if (ret_val) if (ret_val)
return ret_val; return ret_val;
......
...@@ -563,6 +563,7 @@ struct igb_adapter { ...@@ -563,6 +563,7 @@ struct igb_adapter {
struct cyclecounter cc; struct cyclecounter cc;
struct timecounter tc; struct timecounter tc;
u32 tx_hwtstamp_timeouts; u32 tx_hwtstamp_timeouts;
u32 tx_hwtstamp_skipped;
u32 rx_hwtstamp_cleared; u32 rx_hwtstamp_cleared;
bool pps_sys_wrap_on; bool pps_sys_wrap_on;
...@@ -666,7 +667,7 @@ void igb_setup_tctl(struct igb_adapter *); ...@@ -666,7 +667,7 @@ void igb_setup_tctl(struct igb_adapter *);
void igb_setup_rctl(struct igb_adapter *); void igb_setup_rctl(struct igb_adapter *);
netdev_tx_t igb_xmit_frame_ring(struct sk_buff *, struct igb_ring *); netdev_tx_t igb_xmit_frame_ring(struct sk_buff *, struct igb_ring *);
void igb_alloc_rx_buffers(struct igb_ring *, u16); void igb_alloc_rx_buffers(struct igb_ring *, u16);
void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *); void igb_update_stats(struct igb_adapter *);
bool igb_has_link(struct igb_adapter *adapter); bool igb_has_link(struct igb_adapter *adapter);
void igb_set_ethtool_ops(struct net_device *); void igb_set_ethtool_ops(struct net_device *);
void igb_power_up_link(struct igb_adapter *); void igb_power_up_link(struct igb_adapter *);
...@@ -676,6 +677,7 @@ void igb_ptp_stop(struct igb_adapter *adapter); ...@@ -676,6 +677,7 @@ void igb_ptp_stop(struct igb_adapter *adapter);
void igb_ptp_reset(struct igb_adapter *adapter); void igb_ptp_reset(struct igb_adapter *adapter);
void igb_ptp_suspend(struct igb_adapter *adapter); void igb_ptp_suspend(struct igb_adapter *adapter);
void igb_ptp_rx_hang(struct igb_adapter *adapter); void igb_ptp_rx_hang(struct igb_adapter *adapter);
void igb_ptp_tx_hang(struct igb_adapter *adapter);
void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb); void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb);
void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va, void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va,
struct sk_buff *skb); struct sk_buff *skb);
......
...@@ -90,6 +90,7 @@ static const struct igb_stats igb_gstrings_stats[] = { ...@@ -90,6 +90,7 @@ static const struct igb_stats igb_gstrings_stats[] = {
IGB_STAT("os2bmc_tx_by_host", stats.o2bspc), IGB_STAT("os2bmc_tx_by_host", stats.o2bspc),
IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc), IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc),
IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
IGB_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
}; };
...@@ -2315,7 +2316,7 @@ static void igb_get_ethtool_stats(struct net_device *netdev, ...@@ -2315,7 +2316,7 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
char *p; char *p;
spin_lock(&adapter->stats64_lock); spin_lock(&adapter->stats64_lock);
igb_update_stats(adapter, net_stats); igb_update_stats(adapter);
for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
p = (char *)adapter + igb_gstrings_stats[i].stat_offset; p = (char *)adapter + igb_gstrings_stats[i].stat_offset;
......
...@@ -191,10 +191,7 @@ static int igb_disable_sriov(struct pci_dev *dev); ...@@ -191,10 +191,7 @@ static int igb_disable_sriov(struct pci_dev *dev);
static int igb_pci_disable_sriov(struct pci_dev *dev); static int igb_pci_disable_sriov(struct pci_dev *dev);
#endif #endif
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int igb_suspend(struct device *); static int igb_suspend(struct device *);
#endif
static int igb_resume(struct device *); static int igb_resume(struct device *);
static int igb_runtime_suspend(struct device *dev); static int igb_runtime_suspend(struct device *dev);
static int igb_runtime_resume(struct device *dev); static int igb_runtime_resume(struct device *dev);
...@@ -204,7 +201,6 @@ static const struct dev_pm_ops igb_pm_ops = { ...@@ -204,7 +201,6 @@ static const struct dev_pm_ops igb_pm_ops = {
SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume, SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume,
igb_runtime_idle) igb_runtime_idle)
}; };
#endif
static void igb_shutdown(struct pci_dev *); static void igb_shutdown(struct pci_dev *);
static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs); static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
#ifdef CONFIG_IGB_DCA #ifdef CONFIG_IGB_DCA
...@@ -1822,7 +1818,7 @@ void igb_down(struct igb_adapter *adapter) ...@@ -1822,7 +1818,7 @@ void igb_down(struct igb_adapter *adapter)
/* record the stats before reset*/ /* record the stats before reset*/
spin_lock(&adapter->stats64_lock); spin_lock(&adapter->stats64_lock);
igb_update_stats(adapter, &adapter->stats64); igb_update_stats(adapter);
spin_unlock(&adapter->stats64_lock); spin_unlock(&adapter->stats64_lock);
adapter->link_speed = 0; adapter->link_speed = 0;
...@@ -4690,7 +4686,7 @@ static void igb_watchdog_task(struct work_struct *work) ...@@ -4690,7 +4686,7 @@ static void igb_watchdog_task(struct work_struct *work)
} }
spin_lock(&adapter->stats64_lock); spin_lock(&adapter->stats64_lock);
igb_update_stats(adapter, &adapter->stats64); igb_update_stats(adapter);
spin_unlock(&adapter->stats64_lock); spin_unlock(&adapter->stats64_lock);
for (i = 0; i < adapter->num_tx_queues; i++) { for (i = 0; i < adapter->num_tx_queues; i++) {
...@@ -4726,6 +4722,7 @@ static void igb_watchdog_task(struct work_struct *work) ...@@ -4726,6 +4722,7 @@ static void igb_watchdog_task(struct work_struct *work)
igb_spoof_check(adapter); igb_spoof_check(adapter);
igb_ptp_rx_hang(adapter); igb_ptp_rx_hang(adapter);
igb_ptp_tx_hang(adapter);
/* Check LVMMC register on i350/i354 only */ /* Check LVMMC register on i350/i354 only */
if ((adapter->hw.mac.type == e1000_i350) || if ((adapter->hw.mac.type == e1000_i350) ||
...@@ -5201,9 +5198,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size) ...@@ -5201,9 +5198,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
return __igb_maybe_stop_tx(tx_ring, size); return __igb_maybe_stop_tx(tx_ring, size);
} }
static void igb_tx_map(struct igb_ring *tx_ring, static int igb_tx_map(struct igb_ring *tx_ring,
struct igb_tx_buffer *first, struct igb_tx_buffer *first,
const u8 hdr_len) const u8 hdr_len)
{ {
struct sk_buff *skb = first->skb; struct sk_buff *skb = first->skb;
struct igb_tx_buffer *tx_buffer; struct igb_tx_buffer *tx_buffer;
...@@ -5314,7 +5311,7 @@ static void igb_tx_map(struct igb_ring *tx_ring, ...@@ -5314,7 +5311,7 @@ static void igb_tx_map(struct igb_ring *tx_ring,
*/ */
mmiowb(); mmiowb();
} }
return; return 0;
dma_error: dma_error:
dev_err(tx_ring->dev, "TX DMA map failed\n"); dev_err(tx_ring->dev, "TX DMA map failed\n");
...@@ -5345,6 +5342,8 @@ static void igb_tx_map(struct igb_ring *tx_ring, ...@@ -5345,6 +5342,8 @@ static void igb_tx_map(struct igb_ring *tx_ring,
tx_buffer->skb = NULL; tx_buffer->skb = NULL;
tx_ring->next_to_use = i; tx_ring->next_to_use = i;
return -1;
} }
netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
...@@ -5390,6 +5389,8 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, ...@@ -5390,6 +5389,8 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
adapter->ptp_tx_start = jiffies; adapter->ptp_tx_start = jiffies;
if (adapter->hw.mac.type == e1000_82576) if (adapter->hw.mac.type == e1000_82576)
schedule_work(&adapter->ptp_tx_work); schedule_work(&adapter->ptp_tx_work);
} else {
adapter->tx_hwtstamp_skipped++;
} }
} }
...@@ -5410,13 +5411,24 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, ...@@ -5410,13 +5411,24 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
else if (!tso) else if (!tso)
igb_tx_csum(tx_ring, first); igb_tx_csum(tx_ring, first);
igb_tx_map(tx_ring, first, hdr_len); if (igb_tx_map(tx_ring, first, hdr_len))
goto cleanup_tx_tstamp;
return NETDEV_TX_OK; return NETDEV_TX_OK;
out_drop: out_drop:
dev_kfree_skb_any(first->skb); dev_kfree_skb_any(first->skb);
first->skb = NULL; first->skb = NULL;
cleanup_tx_tstamp:
if (unlikely(tx_flags & IGB_TX_FLAGS_TSTAMP)) {
struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
if (adapter->hw.mac.type == e1000_82576)
cancel_work_sync(&adapter->ptp_tx_work);
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
}
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
...@@ -5487,7 +5499,7 @@ static void igb_get_stats64(struct net_device *netdev, ...@@ -5487,7 +5499,7 @@ static void igb_get_stats64(struct net_device *netdev,
struct igb_adapter *adapter = netdev_priv(netdev); struct igb_adapter *adapter = netdev_priv(netdev);
spin_lock(&adapter->stats64_lock); spin_lock(&adapter->stats64_lock);
igb_update_stats(adapter, &adapter->stats64); igb_update_stats(adapter);
memcpy(stats, &adapter->stats64, sizeof(*stats)); memcpy(stats, &adapter->stats64, sizeof(*stats));
spin_unlock(&adapter->stats64_lock); spin_unlock(&adapter->stats64_lock);
} }
...@@ -5536,9 +5548,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -5536,9 +5548,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
* igb_update_stats - Update the board statistics counters * igb_update_stats - Update the board statistics counters
* @adapter: board private structure * @adapter: board private structure
**/ **/
void igb_update_stats(struct igb_adapter *adapter, void igb_update_stats(struct igb_adapter *adapter)
struct rtnl_link_stats64 *net_stats)
{ {
struct rtnl_link_stats64 *net_stats = &adapter->stats64;
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev; struct pci_dev *pdev = adapter->pdev;
u32 reg, mpc; u32 reg, mpc;
...@@ -8015,9 +8027,7 @@ static void igb_deliver_wake_packet(struct net_device *netdev) ...@@ -8015,9 +8027,7 @@ static void igb_deliver_wake_packet(struct net_device *netdev)
netif_rx(skb); netif_rx(skb);
} }
#ifdef CONFIG_PM static int __maybe_unused igb_suspend(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int igb_suspend(struct device *dev)
{ {
int retval; int retval;
bool wake; bool wake;
...@@ -8036,9 +8046,8 @@ static int igb_suspend(struct device *dev) ...@@ -8036,9 +8046,8 @@ static int igb_suspend(struct device *dev)
return 0; return 0;
} }
#endif /* CONFIG_PM_SLEEP */
static int igb_resume(struct device *dev) static int __maybe_unused igb_resume(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev); struct net_device *netdev = pci_get_drvdata(pdev);
...@@ -8092,7 +8101,7 @@ static int igb_resume(struct device *dev) ...@@ -8092,7 +8101,7 @@ static int igb_resume(struct device *dev)
return err; return err;
} }
static int igb_runtime_idle(struct device *dev) static int __maybe_unused igb_runtime_idle(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev); struct net_device *netdev = pci_get_drvdata(pdev);
...@@ -8104,7 +8113,7 @@ static int igb_runtime_idle(struct device *dev) ...@@ -8104,7 +8113,7 @@ static int igb_runtime_idle(struct device *dev)
return -EBUSY; return -EBUSY;
} }
static int igb_runtime_suspend(struct device *dev) static int __maybe_unused igb_runtime_suspend(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
int retval; int retval;
...@@ -8124,11 +8133,10 @@ static int igb_runtime_suspend(struct device *dev) ...@@ -8124,11 +8133,10 @@ static int igb_runtime_suspend(struct device *dev)
return 0; return 0;
} }
static int igb_runtime_resume(struct device *dev) static int __maybe_unused igb_runtime_resume(struct device *dev)
{ {
return igb_resume(dev); return igb_resume(dev);
} }
#endif /* CONFIG_PM */
static void igb_shutdown(struct pci_dev *pdev) static void igb_shutdown(struct pci_dev *pdev)
{ {
......
...@@ -711,6 +711,35 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) ...@@ -711,6 +711,35 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
} }
} }
/**
* igb_ptp_tx_hang - detect error case where Tx timestamp never finishes
* @adapter: private network adapter structure
*/
void igb_ptp_tx_hang(struct igb_adapter *adapter)
{
bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
IGB_PTP_TX_TIMEOUT);
if (!adapter->ptp_tx_skb)
return;
if (!test_bit(__IGB_PTP_TX_IN_PROGRESS, &adapter->state))
return;
/* If we haven't received a timestamp within the timeout, it is
* reasonable to assume that it will never occur, so we can unlock the
* timestamp bit when this occurs.
*/
if (timeout) {
cancel_work_sync(&adapter->ptp_tx_work);
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
adapter->tx_hwtstamp_timeouts++;
dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n");
}
}
/** /**
* igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
* @adapter: Board private structure. * @adapter: Board private structure.
...@@ -721,6 +750,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) ...@@ -721,6 +750,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
**/ **/
static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
{ {
struct sk_buff *skb = adapter->ptp_tx_skb;
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
struct skb_shared_hwtstamps shhwtstamps; struct skb_shared_hwtstamps shhwtstamps;
u64 regval; u64 regval;
...@@ -748,10 +778,17 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) ...@@ -748,10 +778,17 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
shhwtstamps.hwtstamp = shhwtstamps.hwtstamp =
ktime_add_ns(shhwtstamps.hwtstamp, adjust); ktime_add_ns(shhwtstamps.hwtstamp, adjust);
skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); /* Clear the lock early before calling skb_tstamp_tx so that
dev_kfree_skb_any(adapter->ptp_tx_skb); * applications are not woken up before the lock bit is clear. We use
* a copy of the skb pointer to ensure other threads can't change it
* while we're notifying the stack.
*/
adapter->ptp_tx_skb = NULL; adapter->ptp_tx_skb = NULL;
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
/* Notify the stack and free the skb after we've unlocked */
skb_tstamp_tx(skb, &shhwtstamps);
dev_kfree_skb_any(skb);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment