diff options
Diffstat (limited to 'drivers/net/ethernet/intel/e1000e')
| -rw-r--r-- | drivers/net/ethernet/intel/e1000e/e1000.h | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/e1000e/ethtool.c | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/e1000e/netdev.c | 51 | 
3 files changed, 36 insertions, 19 deletions
| diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index c7c994eb410e..98e68888abb1 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -268,6 +268,7 @@ struct e1000_adapter {  	u32 tx_fifo_size;  	u32 tx_dma_failed;  	u32 tx_hwtstamp_timeouts; +	u32 tx_hwtstamp_skipped;  	/* Rx */  	bool (*clean_rx)(struct e1000_ring *ring, int *work_done, diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index e23dbd9190d6..003cbd605799 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -105,6 +105,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {  	E1000_STAT("uncorr_ecc_errors", uncorr_errors),  	E1000_STAT("corr_ecc_errors", corr_errors),  	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) @@ -2072,7 +2073,7 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,  	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); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b3679728caac..2dcb5463d9b8 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1183,6 +1183,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)  	struct e1000_hw *hw = &adapter->hw;  	if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) { +		struct sk_buff *skb = adapter->tx_hwtstamp_skb;  		struct skb_shared_hwtstamps shhwtstamps;  		u64 txstmp; @@ -1191,9 +1192,14 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)  		e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp); -		skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps); -		dev_kfree_skb_any(adapter->tx_hwtstamp_skb); +		/* Clear the global tx_hwtstamp_skb pointer and force writes +		 * prior to notifying the stack of a Tx timestamp. +		 */  		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  			      + adapter->tx_timeout_factor * HZ)) {  		dev_kfree_skb_any(adapter->tx_hwtstamp_skb); @@ -3680,6 +3686,7 @@ static int e1000e_config_hwtstamp(struct e1000_adapter *adapter,  		 * Delay Request messages but not both so fall-through to  		 * time stamp all packets.  		 */ +	case HWTSTAMP_FILTER_NTP_ALL:  	case HWTSTAMP_FILTER_ALL:  		is_l2 = true;  		is_l4 = true; @@ -5860,17 +5867,20 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,  			     nr_frags);  	if (count) {  		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && -		    (adapter->flags & FLAG_HAS_HW_TIMESTAMP) && -		    !adapter->tx_hwtstamp_skb) { -			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; -			tx_flags |= E1000_TX_FLAGS_HWTSTAMP; -			adapter->tx_hwtstamp_skb = skb_get(skb); -			adapter->tx_hwtstamp_start = jiffies; -			schedule_work(&adapter->tx_hwtstamp_work); -		} else { -			skb_tx_timestamp(skb); +		    (adapter->flags & FLAG_HAS_HW_TIMESTAMP)) { +			if (!adapter->tx_hwtstamp_skb) { +				skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; +				tx_flags |= E1000_TX_FLAGS_HWTSTAMP; +				adapter->tx_hwtstamp_skb = skb_get(skb); +				adapter->tx_hwtstamp_start = jiffies; +				schedule_work(&adapter->tx_hwtstamp_work); +			} else { +				adapter->tx_hwtstamp_skipped++; +			}  		} +		skb_tx_timestamp(skb); +  		netdev_sent_queue(netdev, skb->len);  		e1000_tx_queue(tx_ring, tx_flags, count);  		/* Make sure there is space in the ring for the next send. */ @@ -6630,12 +6640,17 @@ static int e1000e_pm_thaw(struct device *dev)  static int e1000e_pm_suspend(struct device *dev)  {  	struct pci_dev *pdev = to_pci_dev(dev); +	int rc;  	e1000e_flush_lpic(pdev);  	e1000e_pm_freeze(dev); -	return __e1000_shutdown(pdev, false); +	rc = __e1000_shutdown(pdev, false); +	if (rc) +		e1000e_pm_thaw(dev); + +	return rc;  }  static int e1000e_pm_resume(struct device *dev) @@ -6733,20 +6748,20 @@ static irqreturn_t e1000_intr_msix(int __always_unused irq, void *data)  		vector = 0;  		msix_irq = adapter->msix_entries[vector].vector; -		disable_irq(msix_irq); -		e1000_intr_msix_rx(msix_irq, netdev); +		if (disable_hardirq(msix_irq)) +			e1000_intr_msix_rx(msix_irq, netdev);  		enable_irq(msix_irq);  		vector++;  		msix_irq = adapter->msix_entries[vector].vector; -		disable_irq(msix_irq); -		e1000_intr_msix_tx(msix_irq, netdev); +		if (disable_hardirq(msix_irq)) +			e1000_intr_msix_tx(msix_irq, netdev);  		enable_irq(msix_irq);  		vector++;  		msix_irq = adapter->msix_entries[vector].vector; -		disable_irq(msix_irq); -		e1000_msix_other(msix_irq, netdev); +		if (disable_hardirq(msix_irq)) +			e1000_msix_other(msix_irq, netdev);  		enable_irq(msix_irq);  	} |