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

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
...@@ -2044,6 +2044,7 @@ const struct e1000_info e1000_82574_info = { ...@@ -2044,6 +2044,7 @@ const struct e1000_info e1000_82574_info = {
| FLAG_HAS_MSIX | FLAG_HAS_MSIX
| FLAG_HAS_JUMBO_FRAMES | FLAG_HAS_JUMBO_FRAMES
| FLAG_HAS_WOL | FLAG_HAS_WOL
| FLAG_HAS_HW_TIMESTAMP
| FLAG_APME_IN_CTRL3 | FLAG_APME_IN_CTRL3
| FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT | FLAG_HAS_AMT
...@@ -2065,6 +2066,7 @@ const struct e1000_info e1000_82583_info = { ...@@ -2065,6 +2066,7 @@ const struct e1000_info e1000_82583_info = {
.mac = e1000_82583, .mac = e1000_82583,
.flags = FLAG_HAS_HW_VLAN_FILTER .flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_WOL | FLAG_HAS_WOL
| FLAG_HAS_HW_TIMESTAMP
| FLAG_APME_IN_CTRL3 | FLAG_APME_IN_CTRL3
| FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT | FLAG_HAS_AMT
......
...@@ -107,6 +107,7 @@ ...@@ -107,6 +107,7 @@
#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ #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_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_CE 0x01000000
#define E1000_RXDEXT_STATERR_SE 0x02000000 #define E1000_RXDEXT_STATERR_SE 0x02000000
#define E1000_RXDEXT_STATERR_SEQ 0x04000000 #define E1000_RXDEXT_STATERR_SEQ 0x04000000
...@@ -318,6 +319,7 @@ ...@@ -318,6 +319,7 @@
#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ #define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ #define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ #define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
/* Transmit Control */ /* Transmit Control */
#define E1000_TCTL_EN 0x00000002 /* enable Tx */ #define E1000_TCTL_EN 0x00000002 /* enable Tx */
...@@ -536,6 +538,18 @@ ...@@ -536,6 +538,18 @@
#define E1000_RXCW_C 0x20000000 /* Receive config */ #define E1000_RXCW_C 0x20000000 /* Receive config */
#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ #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 */ /* PCI Express Control */
#define E1000_GCR_RXD_NO_SNOOP 0x00000001 #define E1000_GCR_RXD_NO_SNOOP 0x00000001
#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 #define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002
......
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
#include "hw.h" #include "hw.h"
...@@ -353,6 +355,7 @@ struct e1000_adapter { ...@@ -353,6 +355,7 @@ struct e1000_adapter {
u64 gorc_old; u64 gorc_old;
u32 alloc_rx_buff_failed; u32 alloc_rx_buff_failed;
u32 rx_dma_failed; u32 rx_dma_failed;
u32 rx_hwtstamp_cleared;
unsigned int rx_ps_pages; unsigned int rx_ps_pages;
u16 rx_ps_bsize0; u16 rx_ps_bsize0;
...@@ -402,6 +405,14 @@ struct e1000_adapter { ...@@ -402,6 +405,14 @@ struct e1000_adapter {
u16 tx_ring_count; u16 tx_ring_count;
u16 rx_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 { struct e1000_info {
...@@ -416,6 +427,38 @@ struct e1000_info { ...@@ -416,6 +427,38 @@ struct e1000_info {
const struct e1000_nvm_operations *nvm_ops; 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 */ /* hardware capability, feature, and workaround flags */
#define FLAG_HAS_AMT (1 << 0) #define FLAG_HAS_AMT (1 << 0)
#define FLAG_HAS_FLASH (1 << 1) #define FLAG_HAS_FLASH (1 << 1)
...@@ -431,7 +474,7 @@ struct e1000_info { ...@@ -431,7 +474,7 @@ struct e1000_info {
#define FLAG_HAS_SMART_POWER_DOWN (1 << 11) #define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
#define FLAG_IS_QUAD_PORT_A (1 << 12) #define FLAG_IS_QUAD_PORT_A (1 << 12)
#define FLAG_IS_QUAD_PORT (1 << 13) #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_WUC (1 << 15)
#define FLAG_APME_IN_CTRL3 (1 << 16) #define FLAG_APME_IN_CTRL3 (1 << 16)
#define FLAG_APME_CHECK_PORT_B (1 << 17) #define FLAG_APME_CHECK_PORT_B (1 << 17)
...@@ -463,6 +506,7 @@ struct e1000_info { ...@@ -463,6 +506,7 @@ struct e1000_info {
#define FLAG2_NO_DISABLE_RX (1 << 10) #define FLAG2_NO_DISABLE_RX (1 << 10)
#define FLAG2_PCIM2PCI_ARBITER_WA (1 << 11) #define FLAG2_PCIM2PCI_ARBITER_WA (1 << 11)
#define FLAG2_DFLT_CRC_STRIPPING (1 << 12) #define FLAG2_DFLT_CRC_STRIPPING (1 << 12)
#define FLAG2_CHECK_RX_HWTSTAMP (1 << 13)
#define E1000_RX_DESC_PS(R, i) \ #define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
......
...@@ -108,6 +108,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { ...@@ -108,6 +108,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
E1000_STAT("dropped_smbus", stats.mgpdc), E1000_STAT("dropped_smbus", stats.mgpdc),
E1000_STAT("rx_dma_failed", rx_dma_failed), E1000_STAT("rx_dma_failed", rx_dma_failed),
E1000_STAT("tx_dma_failed", tx_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) #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) ...@@ -2182,6 +2183,28 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
return 0; 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 = { static const struct ethtool_ops e1000_ethtool_ops = {
.get_settings = e1000_get_settings, .get_settings = e1000_get_settings,
.set_settings = e1000_set_settings, .set_settings = e1000_set_settings,
...@@ -2209,7 +2232,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { ...@@ -2209,7 +2232,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_coalesce = e1000_get_coalesce, .get_coalesce = e1000_get_coalesce,
.set_coalesce = e1000_set_coalesce, .set_coalesce = e1000_set_coalesce,
.get_rxnfc = e1000_get_rxnfc, .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, .get_eee = e1000e_get_eee,
.set_eee = e1000e_set_eee, .set_eee = e1000e_set_eee,
}; };
......
...@@ -60,6 +60,7 @@ enum e1e_registers { ...@@ -60,6 +60,7 @@ enum e1e_registers {
E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */ E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */ E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */
E1000_IVAR = 0x000E4, /* Interrupt Vector Allocation - RW */ E1000_IVAR = 0x000E4, /* Interrupt Vector Allocation - RW */
E1000_FEXTNVM7 = 0x000E4, /* Future Extended NVM 7 - RW */
E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */ E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2)) #define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
E1000_LPIC = 0x000FC, /* Low Power Idle Control - RW */ E1000_LPIC = 0x000FC, /* Low Power Idle Control - RW */
...@@ -241,6 +242,15 @@ enum e1e_registers { ...@@ -241,6 +242,15 @@ enum e1e_registers {
#define E1000_PCH_RAICC(_n) (E1000_PCH_RAICC_BASE + ((_n) * 4)) #define E1000_PCH_RAICC(_n) (E1000_PCH_RAICC_BASE + ((_n) * 4))
#define E1000_CRC_OFFSET E1000_PCH_RAICC_BASE #define E1000_CRC_OFFSET E1000_PCH_RAICC_BASE
E1000_HICR = 0x08F00, /* Host Interface Control */ 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 #define E1000_MAX_PHY_ADDR 4
......
...@@ -4601,6 +4601,7 @@ const struct e1000_info e1000_pch2_info = { ...@@ -4601,6 +4601,7 @@ const struct e1000_info e1000_pch2_info = {
.mac = e1000_pch2lan, .mac = e1000_pch2lan,
.flags = FLAG_IS_ICH .flags = FLAG_IS_ICH
| FLAG_HAS_WOL | FLAG_HAS_WOL
| FLAG_HAS_HW_TIMESTAMP
| FLAG_HAS_CTRLEXT_ON_LOAD | FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT | FLAG_HAS_AMT
| FLAG_HAS_FLASH | FLAG_HAS_FLASH
...@@ -4620,6 +4621,7 @@ const struct e1000_info e1000_pch_lpt_info = { ...@@ -4620,6 +4621,7 @@ const struct e1000_info e1000_pch_lpt_info = {
.mac = e1000_pch_lpt, .mac = e1000_pch_lpt,
.flags = FLAG_IS_ICH .flags = FLAG_IS_ICH
| FLAG_HAS_WOL | FLAG_HAS_WOL
| FLAG_HAS_HW_TIMESTAMP
| FLAG_HAS_CTRLEXT_ON_LOAD | FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT | FLAG_HAS_AMT
| FLAG_HAS_FLASH | FLAG_HAS_FLASH
......
This diff is collapsed.
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