Skip to content

Commit

Permalink
e1000e: add support for hardware timestamping on some devices
Browse files Browse the repository at this point in the history
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: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
  • Loading branch information
Bruce Allan authored and Jeff Kirsher committed Jan 18, 2013
1 parent ffe0b2f commit b67e191
Showing 7 changed files with 462 additions and 8 deletions.
2 changes: 2 additions & 0 deletions drivers/net/ethernet/intel/e1000e/82571.c
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions drivers/net/ethernet/intel/e1000e/defines.h
Original file line number Diff line number Diff line change
@@ -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
46 changes: 45 additions & 1 deletion drivers/net/ethernet/intel/e1000e/e1000.h
Original file line number Diff line number Diff line change
@@ -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]))
25 changes: 24 additions & 1 deletion drivers/net/ethernet/intel/e1000e/ethtool.c
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions drivers/net/ethernet/intel/e1000e/hw.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions drivers/net/ethernet/intel/e1000e/ich8lan.c
Original file line number Diff line number Diff line change
@@ -4601,6 +4601,7 @@ const struct e1000_info e1000_pch2_info = {
.mac = e1000_pch2lan,
.flags = FLAG_IS_ICH
| FLAG_HAS_WOL
| FLAG_HAS_HW_TIMESTAMP
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_FLASH
@@ -4620,6 +4621,7 @@ const struct e1000_info e1000_pch_lpt_info = {
.mac = e1000_pch_lpt,
.flags = FLAG_IS_ICH
| FLAG_HAS_WOL
| FLAG_HAS_HW_TIMESTAMP
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_FLASH
371 changes: 365 additions & 6 deletions drivers/net/ethernet/intel/e1000e/netdev.c

Large diffs are not rendered by default.

0 comments on commit b67e191

Please sign in to comment.