diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igb')
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_82575.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_main.c | 66 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ptp.c | 42 |
5 files changed, 83 insertions, 33 deletions
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index ee443985581f..4a50870e0fa7 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -257,6 +257,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) } /* 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); if (ret_val) return ret_val; diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index bf9bf9056d0c..06ffb2bc713e 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -563,6 +563,7 @@ struct igb_adapter { struct cyclecounter cc; struct timecounter tc; u32 tx_hwtstamp_timeouts; + u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; bool pps_sys_wrap_on; @@ -666,7 +667,7 @@ void igb_setup_tctl(struct igb_adapter *); void igb_setup_rctl(struct igb_adapter *); netdev_tx_t igb_xmit_frame_ring(struct sk_buff *, struct igb_ring *); 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); void igb_set_ethtool_ops(struct net_device *); void igb_power_up_link(struct igb_adapter *); @@ -676,6 +677,7 @@ void igb_ptp_stop(struct igb_adapter *adapter); void igb_ptp_reset(struct igb_adapter *adapter); void igb_ptp_suspend(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_pktstamp(struct igb_q_vector *q_vector, void *va, struct sk_buff *skb); diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 0efb62db6efd..d06a8db514d4 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -90,6 +90,7 @@ static const struct igb_stats igb_gstrings_stats[] = { IGB_STAT("os2bmc_tx_by_host", stats.o2bspc), IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc), IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), + IGB_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), }; @@ -2315,7 +2316,7 @@ static void igb_get_ethtool_stats(struct net_device *netdev, char *p; spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, net_stats); + igb_update_stats(adapter); for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { p = (char *)adapter + igb_gstrings_stats[i].stat_offset; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 1cf74aa4ebd9..ec62410b035a 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -191,10 +191,7 @@ static int igb_disable_sriov(struct pci_dev *dev); static int igb_pci_disable_sriov(struct pci_dev *dev); #endif -#ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP static int igb_suspend(struct device *); -#endif static int igb_resume(struct device *); static int igb_runtime_suspend(struct device *dev); static int igb_runtime_resume(struct device *dev); @@ -204,7 +201,6 @@ static const struct dev_pm_ops igb_pm_ops = { SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume, igb_runtime_idle) }; -#endif static void igb_shutdown(struct pci_dev *); static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs); #ifdef CONFIG_IGB_DCA @@ -1822,7 +1818,7 @@ void igb_down(struct igb_adapter *adapter) /* record the stats before reset*/ spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); spin_unlock(&adapter->stats64_lock); adapter->link_speed = 0; @@ -4690,7 +4686,7 @@ no_wait: } spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); spin_unlock(&adapter->stats64_lock); for (i = 0; i < adapter->num_tx_queues; i++) { @@ -4726,6 +4722,7 @@ no_wait: igb_spoof_check(adapter); igb_ptp_rx_hang(adapter); + igb_ptp_tx_hang(adapter); /* Check LVMMC register on i350/i354 only */ 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) return __igb_maybe_stop_tx(tx_ring, size); } -static void igb_tx_map(struct igb_ring *tx_ring, - struct igb_tx_buffer *first, - const u8 hdr_len) +static int igb_tx_map(struct igb_ring *tx_ring, + struct igb_tx_buffer *first, + const u8 hdr_len) { struct sk_buff *skb = first->skb; struct igb_tx_buffer *tx_buffer; @@ -5314,7 +5311,7 @@ static void igb_tx_map(struct igb_ring *tx_ring, */ mmiowb(); } - return; + return 0; dma_error: dev_err(tx_ring->dev, "TX DMA map failed\n"); @@ -5345,6 +5342,8 @@ dma_error: tx_buffer->skb = NULL; tx_ring->next_to_use = i; + + return -1; } 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; if (adapter->hw.mac.type == e1000_82576) 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, else if (!tso) 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; out_drop: dev_kfree_skb_any(first->skb); 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; } @@ -5487,7 +5499,7 @@ static void igb_get_stats64(struct net_device *netdev, struct igb_adapter *adapter = netdev_priv(netdev); spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); memcpy(stats, &adapter->stats64, sizeof(*stats)); spin_unlock(&adapter->stats64_lock); } @@ -5536,9 +5548,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) * igb_update_stats - Update the board statistics counters * @adapter: board private structure **/ -void igb_update_stats(struct igb_adapter *adapter, - struct rtnl_link_stats64 *net_stats) +void igb_update_stats(struct igb_adapter *adapter) { + struct rtnl_link_stats64 *net_stats = &adapter->stats64; struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; u32 reg, mpc; @@ -6457,8 +6469,8 @@ static void igb_set_default_mac_filter(struct igb_adapter *adapter) igb_rar_set_index(adapter, 0); } -int igb_add_mac_filter(struct igb_adapter *adapter, const u8 *addr, - const u8 queue) +static int igb_add_mac_filter(struct igb_adapter *adapter, const u8 *addr, + const u8 queue) { struct e1000_hw *hw = &adapter->hw; int rar_entries = hw->mac.rar_entry_count - @@ -6487,8 +6499,8 @@ int igb_add_mac_filter(struct igb_adapter *adapter, const u8 *addr, return -ENOSPC; } -int igb_del_mac_filter(struct igb_adapter *adapter, const u8 *addr, - const u8 queue) +static int igb_del_mac_filter(struct igb_adapter *adapter, const u8 *addr, + const u8 queue) { struct e1000_hw *hw = &adapter->hw; int rar_entries = hw->mac.rar_entry_count - @@ -6540,8 +6552,8 @@ static int igb_uc_unsync(struct net_device *netdev, const unsigned char *addr) return 0; } -int igb_set_vf_mac_filter(struct igb_adapter *adapter, const int vf, - const u32 info, const u8 *addr) +static int igb_set_vf_mac_filter(struct igb_adapter *adapter, const int vf, + const u32 info, const u8 *addr) { struct pci_dev *pdev = adapter->pdev; struct vf_data_storage *vf_data = &adapter->vf_data[vf]; @@ -8015,9 +8027,7 @@ static void igb_deliver_wake_packet(struct net_device *netdev) netif_rx(skb); } -#ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP -static int igb_suspend(struct device *dev) +static int __maybe_unused igb_suspend(struct device *dev) { int retval; bool wake; @@ -8036,9 +8046,8 @@ static int igb_suspend(struct device *dev) 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 net_device *netdev = pci_get_drvdata(pdev); @@ -8092,7 +8101,7 @@ static int igb_resume(struct device *dev) 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 net_device *netdev = pci_get_drvdata(pdev); @@ -8104,7 +8113,7 @@ static int igb_runtime_idle(struct device *dev) 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); int retval; @@ -8124,11 +8133,10 @@ static int igb_runtime_suspend(struct device *dev) return 0; } -static int igb_runtime_resume(struct device *dev) +static int __maybe_unused igb_runtime_resume(struct device *dev) { return igb_resume(dev); } -#endif /* CONFIG_PM */ static void igb_shutdown(struct pci_dev *pdev) { diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 7a3fd4d74592..841c2a083349 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -712,6 +712,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 * @adapter: Board private structure. * @@ -721,6 +750,7 @@ void igb_ptp_rx_hang(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 skb_shared_hwtstamps shhwtstamps; u64 regval; @@ -748,10 +778,17 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) shhwtstamps.hwtstamp = ktime_add_ns(shhwtstamps.hwtstamp, adjust); - skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); - dev_kfree_skb_any(adapter->ptp_tx_skb); + /* Clear the lock early before calling skb_tstamp_tx so that + * 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; 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); } /** @@ -941,6 +978,7 @@ static int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter, is_l4 = true; break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: /* 82576 cannot timestamp all packets, which it needs to do to * support both V1 Sync and Delay_Req messages |