Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b67e1913 authored by Bruce Allan's avatar Bruce Allan Committed by Jeff Kirsher
Browse files

e1000e: add support for hardware timestamping on some devices



On 82574, 82583, 82579, I217 and I218 add support for hardware time
stamping of all or no Rx packets and Tx packets which have the
SKBTX_HW_TSTAMP flag set.  Update the .get_ts_info ethtool operation to
report the supported time stamping modes, and enable and disable hardware
time stamping with the SIOCSHWTSTAMP ioctl.

Signed-off-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Tested-by: default avatarJeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent ffe0b2ff
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2044,6 +2044,7 @@ const struct e1000_info e1000_82574_info = {
				  | FLAG_HAS_MSIX
				  | FLAG_HAS_JUMBO_FRAMES
				  | FLAG_HAS_WOL
				  | FLAG_HAS_HW_TIMESTAMP
				  | FLAG_APME_IN_CTRL3
				  | FLAG_HAS_SMART_POWER_DOWN
				  | FLAG_HAS_AMT
@@ -2065,6 +2066,7 @@ const struct e1000_info e1000_82583_info = {
	.mac			= e1000_82583,
	.flags			= FLAG_HAS_HW_VLAN_FILTER
				  | FLAG_HAS_WOL
				  | FLAG_HAS_HW_TIMESTAMP
				  | FLAG_APME_IN_CTRL3
				  | FLAG_HAS_SMART_POWER_DOWN
				  | FLAG_HAS_AMT
+14 −0
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@
#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */

#define E1000_RXDEXT_STATERR_TST   0x00000100	/* Time Stamp taken */
#define E1000_RXDEXT_STATERR_CE    0x01000000
#define E1000_RXDEXT_STATERR_SE    0x02000000
#define E1000_RXDEXT_STATERR_SEQ   0x04000000
@@ -318,6 +319,7 @@
#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
#define E1000_TXD_EXTCMD_TSTAMP	0x00000010 /* IEEE1588 Timestamp packet */

/* Transmit Control */
#define E1000_TCTL_EN     0x00000002    /* enable Tx */
@@ -536,6 +538,18 @@
#define E1000_RXCW_C          0x20000000        /* Receive config */
#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */

#define E1000_TSYNCTXCTL_VALID		0x00000001 /* Tx timestamp valid */
#define E1000_TSYNCRXCTL_TYPE_ALL	0x08
#define E1000_TSYNCTXCTL_ENABLED	0x00000010 /* enable Tx timestamping */

#define E1000_TSYNCRXCTL_VALID		0x00000001 /* Rx timestamp valid */
#define E1000_TSYNCRXCTL_TYPE_MASK	0x0000000E /* Rx type mask */
#define E1000_TSYNCRXCTL_ENABLED	0x00000010 /* enable Rx timestamping */
#define E1000_TSYNCRXCTL_SYSCFI		0x00000020 /* Sys clock frequency */

#define E1000_TIMINCA_INCPERIOD_SHIFT	24
#define E1000_TIMINCA_INCVALUE_MASK	0x00FFFFFF

/* PCI Express Control */
#define E1000_GCR_RXD_NO_SNOOP          0x00000001
#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+45 −1
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@
#include <linux/pci-aspm.h>
#include <linux/crc32.h>
#include <linux/if_vlan.h>
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>

#include "hw.h"

@@ -353,6 +355,7 @@ struct e1000_adapter {
	u64 gorc_old;
	u32 alloc_rx_buff_failed;
	u32 rx_dma_failed;
	u32 rx_hwtstamp_cleared;

	unsigned int rx_ps_pages;
	u16 rx_ps_bsize0;
@@ -402,6 +405,14 @@ struct e1000_adapter {

	u16 tx_ring_count;
	u16 rx_ring_count;

	struct hwtstamp_config hwtstamp_config;
	struct delayed_work systim_overflow_work;
	struct sk_buff *tx_hwtstamp_skb;
	struct work_struct tx_hwtstamp_work;
	spinlock_t systim_lock;	/* protects SYSTIML/H regsters */
	struct cyclecounter cc;
	struct timecounter tc;
};

struct e1000_info {
@@ -416,6 +427,38 @@ struct e1000_info {
	const struct e1000_nvm_operations *nvm_ops;
};

/* The system time is maintained by a 64-bit counter comprised of the 32-bit
 * SYSTIMH and SYSTIML registers.  How the counter increments (and therefore
 * its resolution) is based on the contents of the TIMINCA register - it
 * increments every incperiod (bits 31:24) clock ticks by incvalue (bits 23:0).
 * For the best accuracy, the incperiod should be as small as possible.  The
 * incvalue is scaled by a factor as large as possible (while still fitting
 * in bits 23:0) so that relatively small clock corrections can be made.
 *
 * As a result, a shift of INCVALUE_SHIFT_n is used to fit a value of
 * INCVALUE_n into the TIMINCA register allowing 32+8+(24-INCVALUE_SHIFT_n)
 * bits to count nanoseconds leaving the rest for fractional nonseconds.
 */
#define INCVALUE_96MHz		125
#define INCVALUE_SHIFT_96MHz	17
#define INCPERIOD_SHIFT_96MHz	2
#define INCPERIOD_96MHz		(12 >> INCPERIOD_SHIFT_96MHz)

#define INCVALUE_25MHz		40
#define INCVALUE_SHIFT_25MHz	18
#define INCPERIOD_25MHz		1

/* Another drawback of scaling the incvalue by a large factor is the
 * 64-bit SYSTIM register overflows more quickly.  This is dealt with
 * by simply reading the clock before it overflows.
 *
 * Clock	ns bits	Overflows after
 * ~~~~~~	~~~~~~~	~~~~~~~~~~~~~~~
 * 96MHz	47-bit	2^(47-INCPERIOD_SHIFT_96MHz) / 10^9 / 3600 = 9.77 hrs
 * 25MHz	46-bit	2^46 / 10^9 / 3600 = 19.55 hours
 */
#define E1000_SYSTIM_OVERFLOW_PERIOD	(HZ * 60 * 60 * 4)

/* hardware capability, feature, and workaround flags */
#define FLAG_HAS_AMT                      (1 << 0)
#define FLAG_HAS_FLASH                    (1 << 1)
@@ -431,7 +474,7 @@ struct e1000_info {
#define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
#define FLAG_IS_QUAD_PORT_A               (1 << 12)
#define FLAG_IS_QUAD_PORT                 (1 << 13)
/* reserved bit14 */
#define FLAG_HAS_HW_TIMESTAMP             (1 << 14)
#define FLAG_APME_IN_WUC                  (1 << 15)
#define FLAG_APME_IN_CTRL3                (1 << 16)
#define FLAG_APME_CHECK_PORT_B            (1 << 17)
@@ -463,6 +506,7 @@ struct e1000_info {
#define FLAG2_NO_DISABLE_RX               (1 << 10)
#define FLAG2_PCIM2PCI_ARBITER_WA         (1 << 11)
#define FLAG2_DFLT_CRC_STRIPPING          (1 << 12)
#define FLAG2_CHECK_RX_HWTSTAMP           (1 << 13)

#define E1000_RX_DESC_PS(R, i)	    \
	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
+24 −1
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
	E1000_STAT("dropped_smbus", stats.mgpdc),
	E1000_STAT("rx_dma_failed", rx_dma_failed),
	E1000_STAT("tx_dma_failed", tx_dma_failed),
	E1000_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
};

#define E1000_GLOBAL_STATS_LEN	ARRAY_SIZE(e1000_gstrings_stats)
@@ -2182,6 +2183,28 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
	return 0;
}

static int e1000e_get_ts_info(struct net_device *netdev,
			      struct ethtool_ts_info *info)
{
	struct e1000_adapter *adapter = netdev_priv(netdev);

	ethtool_op_get_ts_info(netdev, info);

	if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
		return 0;

	info->so_timestamping |= (SOF_TIMESTAMPING_TX_HARDWARE |
				  SOF_TIMESTAMPING_RX_HARDWARE |
				  SOF_TIMESTAMPING_RAW_HARDWARE);

	info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);

	info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
			    (1 << HWTSTAMP_FILTER_ALL));

	return 0;
}

static const struct ethtool_ops e1000_ethtool_ops = {
	.get_settings		= e1000_get_settings,
	.set_settings		= e1000_set_settings,
@@ -2209,7 +2232,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
	.get_coalesce		= e1000_get_coalesce,
	.set_coalesce		= e1000_set_coalesce,
	.get_rxnfc		= e1000_get_rxnfc,
	.get_ts_info		= ethtool_op_get_ts_info,
	.get_ts_info		= e1000e_get_ts_info,
	.get_eee		= e1000e_get_eee,
	.set_eee		= e1000e_set_eee,
};
+10 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ enum e1e_registers {
	E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
	E1000_IAM      = 0x000E0, /* Interrupt Acknowledge Auto Mask */
	E1000_IVAR     = 0x000E4, /* Interrupt Vector Allocation - RW */
	E1000_FEXTNVM7  = 0x000E4, /* Future Extended NVM 7 - RW */
	E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
	E1000_LPIC     = 0x000FC, /* Low Power Idle Control - RW */
@@ -241,6 +242,15 @@ enum e1e_registers {
#define E1000_PCH_RAICC(_n)	(E1000_PCH_RAICC_BASE + ((_n) * 4))
#define E1000_CRC_OFFSET	E1000_PCH_RAICC_BASE
	E1000_HICR      = 0x08F00, /* Host Interface Control */
	E1000_SYSTIML   = 0x0B600, /* System time register Low - RO */
	E1000_SYSTIMH   = 0x0B604, /* System time register High - RO */
	E1000_TIMINCA   = 0x0B608, /* Increment attributes register - RW */
	E1000_TSYNCTXCTL = 0x0B614, /* Tx Time Sync Control register - RW */
	E1000_TXSTMPL   = 0x0B618, /* Tx timestamp value Low - RO */
	E1000_TXSTMPH   = 0x0B61C, /* Tx timestamp value High - RO */
	E1000_TSYNCRXCTL = 0x0B620, /* Rx Time Sync Control register - RW */
	E1000_RXSTMPL   = 0x0B624, /* Rx timestamp Low - RO */
	E1000_RXSTMPH   = 0x0B628, /* Rx timestamp High - RO */
};

#define E1000_MAX_PHY_ADDR		4
Loading