Skip to content

Commit

Permalink
e1000e: add support for IEEE-1588 PTP
Browse files Browse the repository at this point in the history
Add PTP IEEE-1588 support and make accesible via the PHC subsystem.

v2: make e1000e_ptp_clock_info a static const struct per Stephen Hemminger

Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Reviewed-by: Jacob Keller <Jacob.e.keller@intel.com>
Acked-by: Richard Cochran <richardcochran@gmail.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 27, 2013
1 parent 347b520 commit d89777b
Show file tree
Hide file tree
Showing 8 changed files with 417 additions and 3 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ config E1000E
tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
depends on PCI && (!SPARC32 || BROKEN)
select CRC32
select PTP_1588_CLOCK
---help---
This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
ethernet family of adapters. For PCI or PCI-X e1000 adapters,
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/intel/e1000e/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ obj-$(CONFIG_E1000E) += e1000e.o

e1000e-objs := 82571.o ich8lan.o 80003es2lan.o \
mac.o manage.o nvm.o phy.o \
param.o ethtool.o netdev.o
param.o ethtool.o netdev.o ptp.o

11 changes: 11 additions & 0 deletions drivers/net/ethernet/intel/e1000e/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -544,9 +544,20 @@

#define E1000_TSYNCRXCTL_VALID 0x00000001 /* Rx timestamp valid */
#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00
#define E1000_TSYNCRXCTL_TYPE_L4_V1 0x02
#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
#define E1000_TSYNCRXCTL_TYPE_ALL 0x08
#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
#define E1000_TSYNCRXCTL_ENABLED 0x00000010 /* enable Rx timestamping */
#define E1000_TSYNCRXCTL_SYSCFI 0x00000020 /* Sys clock frequency */

#define E1000_RXMTRL_PTP_V1_SYNC_MESSAGE 0x00000000
#define E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE 0x00010000

#define E1000_RXMTRL_PTP_V2_SYNC_MESSAGE 0x00000000
#define E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE 0x01000000

#define E1000_TIMINCA_INCPERIOD_SHIFT 24
#define E1000_TIMINCA_INCVALUE_MASK 0x00FFFFFF

Expand Down
9 changes: 8 additions & 1 deletion drivers/net/ethernet/intel/e1000e/e1000.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
#include <linux/if_vlan.h>
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>

#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_classify.h>
#include "hw.h"

struct e1000_info;
Expand Down Expand Up @@ -413,6 +414,8 @@ struct e1000_adapter {
spinlock_t systim_lock; /* protects SYSTIML/H regsters */
struct cyclecounter cc;
struct timecounter tc;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
};

struct e1000_info {
Expand All @@ -427,6 +430,8 @@ struct e1000_info {
const struct e1000_nvm_operations *nvm_ops;
};

s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);

/* 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
Expand Down Expand Up @@ -704,6 +709,8 @@ extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
extern s32 e1000_check_polarity_igp(struct e1000_hw *hw);
extern bool e1000_check_phy_82574(struct e1000_hw *hw);
extern s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
extern void e1000e_ptp_init(struct e1000_adapter *adapter);
extern void e1000e_ptp_remove(struct e1000_adapter *adapter);

static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
{
Expand Down
12 changes: 12 additions & 0 deletions drivers/net/ethernet/intel/e1000e/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -2209,8 +2209,20 @@ static int e1000e_get_ts_info(struct net_device *netdev,
info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);

info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_ALL));

if (adapter->ptp_clock)
info->phc_index = ptp_clock_index(adapter->ptp_clock);

return 0;
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/intel/e1000e/hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ enum e1e_registers {
E1000_TSYNCRXCTL = 0x0B620, /* Rx Time Sync Control register - RW */
E1000_RXSTMPL = 0x0B624, /* Rx timestamp Low - RO */
E1000_RXSTMPH = 0x0B628, /* Rx timestamp High - RO */
E1000_RXMTRL = 0x0B634, /* Timesync Rx EtherType and Msg Type - RW */
E1000_RXUDP = 0x0B638, /* Timesync Rx UDP Port - RW */
};

#define E1000_MAX_PHY_ADDR 4
Expand Down
107 changes: 106 additions & 1 deletion drivers/net/ethernet/intel/e1000e/netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -3413,7 +3413,7 @@ static void e1000e_setup_rss_hash(struct e1000_adapter *adapter)
* Get attributes for incrementing the System Time Register SYSTIML/H at
* the default base frequency, and set the cyclecounter shift value.
**/
static s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
{
struct e1000_hw *hw = &adapter->hw;
u32 incvalue, incperiod, shift;
Expand Down Expand Up @@ -3485,6 +3485,10 @@ static int e1000e_config_hwtstamp(struct e1000_adapter *adapter)
struct hwtstamp_config *config = &adapter->hwtstamp_config;
u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
u32 rxmtrl = 0;
u16 rxudp = 0;
bool is_l4 = false;
bool is_l2 = false;
u32 regval;
s32 ret_val;

Expand All @@ -3509,7 +3513,69 @@ static int e1000e_config_hwtstamp(struct e1000_adapter *adapter)
case HWTSTAMP_FILTER_NONE:
tsync_rx_ctl = 0;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
rxmtrl = E1000_RXMTRL_PTP_V1_SYNC_MESSAGE;
is_l4 = true;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
rxmtrl = E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE;
is_l4 = true;
break;
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
/* Also time stamps V2 L2 Path Delay Request/Response */
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_V2;
rxmtrl = E1000_RXMTRL_PTP_V2_SYNC_MESSAGE;
is_l2 = true;
break;
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
/* Also time stamps V2 L2 Path Delay Request/Response. */
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_V2;
rxmtrl = E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE;
is_l2 = true;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
/* Hardware cannot filter just V2 L4 Sync messages;
* fall-through to V2 (both L2 and L4) Sync.
*/
case HWTSTAMP_FILTER_PTP_V2_SYNC:
/* Also time stamps V2 Path Delay Request/Response. */
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
rxmtrl = E1000_RXMTRL_PTP_V2_SYNC_MESSAGE;
is_l2 = true;
is_l4 = true;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
/* Hardware cannot filter just V2 L4 Delay Request messages;
* fall-through to V2 (both L2 and L4) Delay Request.
*/
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
/* Also time stamps V2 Path Delay Request/Response. */
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
rxmtrl = E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE;
is_l2 = true;
is_l4 = true;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
/* Hardware cannot filter just V2 L4 or L2 Event messages;
* fall-through to all V2 (both L2 and L4) Events.
*/
case HWTSTAMP_FILTER_PTP_V2_EVENT:
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
is_l2 = true;
is_l4 = true;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
/* For V1, the hardware can only filter Sync messages or
* Delay Request messages but not both so fall-through to
* time stamp all packets.
*/
case HWTSTAMP_FILTER_ALL:
is_l2 = true;
is_l4 = true;
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
config->rx_filter = HWTSTAMP_FILTER_ALL;
break;
Expand Down Expand Up @@ -3541,6 +3607,22 @@ static int e1000e_config_hwtstamp(struct e1000_adapter *adapter)
return -EAGAIN;
}

/* L2: define ethertype filter for time stamped packets */
if (is_l2)
rxmtrl |= ETH_P_1588;

/* define which PTP packets get time stamped */
ew32(RXMTRL, rxmtrl);

/* Filter by destination port */
if (is_l4) {
rxudp = PTP_EV_PORT;
cpu_to_be16s(&rxudp);
}
ew32(RXUDP, rxudp);

e1e_flush();

/* Clear TSYNCRXCTL_VALID & TSYNCTXCTL_VALID bit */
regval = er32(RXSTMPH);
regval = er32(TXSTMPH);
Expand Down Expand Up @@ -5665,6 +5747,24 @@ static int e1000e_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr)

config = adapter->hwtstamp_config;

switch (config.rx_filter) {
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
/* With V2 type filters which specify a Sync or Delay Request,
* Path Delay Request/Response messages are also time stamped
* by hardware so notify the caller the requested packets plus
* some others are time stamped.
*/
config.rx_filter = HWTSTAMP_FILTER_SOME;
break;
default:
break;
}

return copy_to_user(ifr->ifr_data, &config,
sizeof(config)) ? -EFAULT : 0;
}
Expand Down Expand Up @@ -6672,6 +6772,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);

/* init PTP hardware clock */
e1000e_ptp_init(adapter);

e1000_print_device_info(adapter);

if (pci_dev_run_wake(pdev))
Expand Down Expand Up @@ -6720,6 +6823,8 @@ static void e1000_remove(struct pci_dev *pdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
bool down = test_bit(__E1000_DOWN, &adapter->state);

e1000e_ptp_remove(adapter);

/* The timers may be rescheduled, so explicitly disable them
* from being rescheduled.
*/
Expand Down
Loading

0 comments on commit d89777b

Please sign in to comment.