Commit 3a6a4eda authored by Jacob Keller's avatar Jacob Keller Committed by Jeff Kirsher

ixgbe: Hardware Timestamping + PTP Hardware Clock (PHC)

This patch enables hardware timestamping for use with PTP software by
extracting a ns counter from an arbitrary fixed point cycles counter.
The hardware generates SYSTIME registers using the DMA tick which
changes based on the current link speed. These SYSTIME registers are
converted to ns using the cyclecounter and timecounter structures
provided by the kernel. Using the SO_TIMESTAMPING api, software can
enable and access timestamps for PTP packets.

The SO_TIMESTAMPING API has space for 3 different kinds of timestamps,
SYS, RAW, and SOF. SYS hardware timestamps are hardware ns values that
are then scaled to the software clock. RAW hardware timestamps are the
direct raw value of the ns counter. SOF software timestamps are the
software timestamp calculated as close as possible to the software
transmit, but are not offloaded to the hardware. This patch only
supports the RAW hardware timestamps due to inefficiency of the SYS
design.

This patch also enables the PHC subsystem features for atomically
adjusting the cycle register, and adjusting the clock frequency in
parts per billion. This frequency adjustment works by slightly
adjusting the value added to the cycle registers each DMA tick. This
causes the hardware registers to overflow rapidly (approximately once
every 34 seconds, when at 10gig link). To solve this, the timecounter
structure is used, along with a timer set for every 25 seconds. This
allows for detecting register overflow and converting the cycle
counter registers into ns values needed for providing useful
timestamps to the network stack.

Only the basic required clock functions are supported at this time,
although the hardware supports some ancillary features and these could
easily be enabled in the future.

Note that use of this hardware timestamping requires modifying daemon
software to use the SO_TIMESTAMPING API for timestamps, and the
ptp_clock PHC framework for accessing the clock. The timestamps have
no relation to the system time at all, so software must use the posix
clock generated by the PHC framework instead.
Signed-off-by: default avatarJacob E Keller <jacob.e.keller@intel.com>
Tested-by: default avatarStephen Ko <stephen.s.ko@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 44b82dde
...@@ -220,6 +220,17 @@ config IXGBE_DCB ...@@ -220,6 +220,17 @@ config IXGBE_DCB
If unsure, say N. If unsure, say N.
config IXGBE_PTP
bool "PTP Clock Support"
default n
depends on IXGBE && PTP_1588_CLOCK
---help---
Say Y here if you want support for 1588 Timestamping with a
PHC device, using the PTP 1588 Clock support. This is
required to enable timestamping support for the device.
If unsure, say N.
config IXGBEVF config IXGBEVF
tristate "Intel(R) 82599 Virtual Function Ethernet support" tristate "Intel(R) 82599 Virtual Function Ethernet support"
depends on PCI_MSI depends on PCI_MSI
......
...@@ -39,4 +39,6 @@ ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ...@@ -39,4 +39,6 @@ ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \
ixgbe_dcb_82599.o ixgbe_dcb_nl.o ixgbe_dcb_82599.o ixgbe_dcb_nl.o
ixgbe-$(CONFIG_IXGBE_PTP) += ixgbe_ptp.o
ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o
...@@ -36,6 +36,12 @@ ...@@ -36,6 +36,12 @@
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#ifdef CONFIG_IXGBE_PTP
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#endif /* CONFIG_IXGBE_PTP */
#include "ixgbe_type.h" #include "ixgbe_type.h"
#include "ixgbe_common.h" #include "ixgbe_common.h"
#include "ixgbe_dcb.h" #include "ixgbe_dcb.h"
...@@ -96,6 +102,7 @@ ...@@ -96,6 +102,7 @@
#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 5) #define IXGBE_TX_FLAGS_FCOE (u32)(1 << 5)
#define IXGBE_TX_FLAGS_FSO (u32)(1 << 6) #define IXGBE_TX_FLAGS_FSO (u32)(1 << 6)
#define IXGBE_TX_FLAGS_TXSW (u32)(1 << 7) #define IXGBE_TX_FLAGS_TXSW (u32)(1 << 7)
#define IXGBE_TX_FLAGS_TSTAMP (u32)(1 << 8)
#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT 29 #define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT 29
...@@ -458,6 +465,7 @@ struct ixgbe_adapter { ...@@ -458,6 +465,7 @@ struct ixgbe_adapter {
#define IXGBE_FLAG2_FDIR_REQUIRES_REINIT (u32)(1 << 7) #define IXGBE_FLAG2_FDIR_REQUIRES_REINIT (u32)(1 << 7)
#define IXGBE_FLAG2_RSS_FIELD_IPV4_UDP (u32)(1 << 8) #define IXGBE_FLAG2_RSS_FIELD_IPV4_UDP (u32)(1 << 8)
#define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP (u32)(1 << 9) #define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP (u32)(1 << 9)
#define IXGBE_FLAG2_OVERFLOW_CHECK_ENABLED (u32)(1 << 10)
/* Tx fast path data */ /* Tx fast path data */
int num_tx_queues; int num_tx_queues;
...@@ -545,6 +553,17 @@ struct ixgbe_adapter { ...@@ -545,6 +553,17 @@ struct ixgbe_adapter {
u32 interrupt_event; u32 interrupt_event;
u32 led_reg; u32 led_reg;
#ifdef CONFIG_IXGBE_PTP
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
unsigned long last_overflow_check;
spinlock_t tmreg_lock;
struct cyclecounter cc;
struct timecounter tc;
u32 base_incval;
u32 cycle_speed;
#endif /* CONFIG_IXGBE_PTP */
/* SR-IOV */ /* SR-IOV */
DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS); DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
unsigned int num_vfs; unsigned int num_vfs;
...@@ -689,4 +708,17 @@ static inline struct netdev_queue *txring_txq(const struct ixgbe_ring *ring) ...@@ -689,4 +708,17 @@ static inline struct netdev_queue *txring_txq(const struct ixgbe_ring *ring)
return netdev_get_tx_queue(ring->netdev, ring->queue_index); return netdev_get_tx_queue(ring->netdev, ring->queue_index);
} }
#ifdef CONFIG_IXGBE_PTP
extern void ixgbe_ptp_init(struct ixgbe_adapter *adapter);
extern void ixgbe_ptp_stop(struct ixgbe_adapter *adapter);
extern void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
extern void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
struct sk_buff *skb);
extern void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
struct sk_buff *skb);
extern int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
struct ifreq *ifr, int cmd);
extern void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter);
#endif /* CONFIG_IXGBE_PTP */
#endif /* _IXGBE_H_ */ #endif /* _IXGBE_H_ */
...@@ -789,6 +789,13 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, ...@@ -789,6 +789,13 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
total_bytes += tx_buffer->bytecount; total_bytes += tx_buffer->bytecount;
total_packets += tx_buffer->gso_segs; total_packets += tx_buffer->gso_segs;
#ifdef CONFIG_IXGBE_PTP
if (unlikely(tx_buffer->tx_flags &
IXGBE_TX_FLAGS_TSTAMP))
ixgbe_ptp_tx_hwtstamp(q_vector,
tx_buffer->skb);
#endif
/* free the skb */ /* free the skb */
dev_kfree_skb_any(tx_buffer->skb); dev_kfree_skb_any(tx_buffer->skb);
...@@ -1389,6 +1396,11 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring, ...@@ -1389,6 +1396,11 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
ixgbe_rx_checksum(rx_ring, rx_desc, skb); ixgbe_rx_checksum(rx_ring, rx_desc, skb);
#ifdef CONFIG_IXGBE_PTP
if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS))
ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb);
#endif
if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) { if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan); u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan);
__vlan_hwaccel_put_tag(skb, vid); __vlan_hwaccel_put_tag(skb, vid);
...@@ -5387,6 +5399,11 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) ...@@ -5387,6 +5399,11 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
flow_rx = false; flow_rx = false;
break; break;
} }
#ifdef CONFIG_IXGBE_PTP
ixgbe_ptp_start_cyclecounter(adapter);
#endif
e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
(link_speed == IXGBE_LINK_SPEED_10GB_FULL ? (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
"10 Gbps" : "10 Gbps" :
...@@ -5424,6 +5441,10 @@ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *adapter) ...@@ -5424,6 +5441,10 @@ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *adapter)
if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB) if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB)
adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP; adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
#ifdef CONFIG_IXGBE_PTP
ixgbe_ptp_start_cyclecounter(adapter);
#endif
e_info(drv, "NIC Link is Down\n"); e_info(drv, "NIC Link is Down\n");
netif_carrier_off(netdev); netif_carrier_off(netdev);
} }
...@@ -5723,6 +5744,9 @@ static void ixgbe_service_task(struct work_struct *work) ...@@ -5723,6 +5744,9 @@ static void ixgbe_service_task(struct work_struct *work)
ixgbe_watchdog_subtask(adapter); ixgbe_watchdog_subtask(adapter);
ixgbe_fdir_reinit_subtask(adapter); ixgbe_fdir_reinit_subtask(adapter);
ixgbe_check_hang_subtask(adapter); ixgbe_check_hang_subtask(adapter);
#ifdef CONFIG_IXGBE_PTP
ixgbe_ptp_overflow_check(adapter);
#endif
ixgbe_service_event_complete(adapter); ixgbe_service_event_complete(adapter);
} }
...@@ -5873,6 +5897,11 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags) ...@@ -5873,6 +5897,11 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN) if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN)
cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE); cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE);
#ifdef CONFIG_IXGBE_PTP
if (tx_flags & IXGBE_TX_FLAGS_TSTAMP)
cmd_type |= cpu_to_le32(IXGBE_ADVTXD_MAC_TSTAMP);
#endif
/* set segmentation enable bits for TSO/FSO */ /* set segmentation enable bits for TSO/FSO */
#ifdef IXGBE_FCOE #ifdef IXGBE_FCOE
if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FSO)) if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FSO))
...@@ -6263,6 +6292,13 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, ...@@ -6263,6 +6292,13 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
tx_flags |= IXGBE_TX_FLAGS_SW_VLAN; tx_flags |= IXGBE_TX_FLAGS_SW_VLAN;
} }
#ifdef CONFIG_IXGBE_PTP
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
}
#endif
#ifdef CONFIG_PCI_IOV #ifdef CONFIG_PCI_IOV
/* /*
* Use the l2switch_enable flag - would be false if the DMA * Use the l2switch_enable flag - would be false if the DMA
...@@ -6415,7 +6451,14 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) ...@@ -6415,7 +6451,14 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
{ {
struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_adapter *adapter = netdev_priv(netdev);
switch (cmd) {
#ifdef CONFIG_IXGBE_PTP
case SIOCSHWTSTAMP:
return ixgbe_ptp_hwtstamp_ioctl(adapter, req, cmd);
#endif
default:
return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd); return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd);
}
} }
/** /**
...@@ -7202,6 +7245,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ...@@ -7202,6 +7245,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
#ifdef CONFIG_IXGBE_PTP
ixgbe_ptp_init(adapter);
#endif /* CONFIG_IXGBE_PTP*/
/* save off EEPROM version number */ /* save off EEPROM version number */
hw->eeprom.ops.read(hw, 0x2e, &adapter->eeprom_verh); hw->eeprom.ops.read(hw, 0x2e, &adapter->eeprom_verh);
hw->eeprom.ops.read(hw, 0x2d, &adapter->eeprom_verl); hw->eeprom.ops.read(hw, 0x2d, &adapter->eeprom_verl);
...@@ -7330,6 +7377,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) ...@@ -7330,6 +7377,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
set_bit(__IXGBE_DOWN, &adapter->state); set_bit(__IXGBE_DOWN, &adapter->state);
cancel_work_sync(&adapter->service_task); cancel_work_sync(&adapter->service_task);
#ifdef CONFIG_IXGBE_PTP
ixgbe_ptp_stop(adapter);
#endif
#ifdef CONFIG_IXGBE_DCA #ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED;
......
This diff is collapsed.
...@@ -1879,6 +1879,36 @@ enum { ...@@ -1879,6 +1879,36 @@ enum {
#define IXGBE_RXDCTL_RLPML_EN 0x00008000 #define IXGBE_RXDCTL_RLPML_EN 0x00008000
#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */ #define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */
#define IXGBE_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */
#define IXGBE_TSYNCTXCTL_ENABLED 0x00000010 /* Tx timestamping enabled */
#define IXGBE_TSYNCRXCTL_VALID 0x00000001 /* Rx timestamp valid */
#define IXGBE_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
#define IXGBE_TSYNCRXCTL_TYPE_L2_V2 0x00
#define IXGBE_TSYNCRXCTL_TYPE_L4_V1 0x02
#define IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
#define IXGBE_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
#define IXGBE_TSYNCRXCTL_ENABLED 0x00000010 /* Rx Timestamping enabled */
#define IXGBE_RXMTRL_V1_CTRLT_MASK 0x000000FF
#define IXGBE_RXMTRL_V1_SYNC_MSG 0x00
#define IXGBE_RXMTRL_V1_DELAY_REQ_MSG 0x01
#define IXGBE_RXMTRL_V1_FOLLOWUP_MSG 0x02
#define IXGBE_RXMTRL_V1_DELAY_RESP_MSG 0x03
#define IXGBE_RXMTRL_V1_MGMT_MSG 0x04
#define IXGBE_RXMTRL_V2_MSGID_MASK 0x0000FF00
#define IXGBE_RXMTRL_V2_SYNC_MSG 0x0000
#define IXGBE_RXMTRL_V2_DELAY_REQ_MSG 0x0100
#define IXGBE_RXMTRL_V2_PDELAY_REQ_MSG 0x0200
#define IXGBE_RXMTRL_V2_PDELAY_RESP_MSG 0x0300
#define IXGBE_RXMTRL_V2_FOLLOWUP_MSG 0x0800
#define IXGBE_RXMTRL_V2_DELAY_RESP_MSG 0x0900
#define IXGBE_RXMTRL_V2_PDELAY_FOLLOWUP_MSG 0x0A00
#define IXGBE_RXMTRL_V2_ANNOUNCE_MSG 0x0B00
#define IXGBE_RXMTRL_V2_SIGNALING_MSG 0x0C00
#define IXGBE_RXMTRL_V2_MGMT_MSG 0x0D00
#define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */ #define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */
#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/ #define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/
#define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */ #define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */
...@@ -2008,6 +2038,7 @@ enum { ...@@ -2008,6 +2038,7 @@ enum {
#define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */ #define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */
#define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */ #define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */
#define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */ #define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */
#define IXGBE_RXDADV_STAT_TS 0x00010000 /* IEEE 1588 Time Stamp */
/* PSRTYPE bit definitions */ /* PSRTYPE bit definitions */
#define IXGBE_PSRTYPE_TCPHDR 0x00000010 #define IXGBE_PSRTYPE_TCPHDR 0x00000010
...@@ -2285,6 +2316,7 @@ struct ixgbe_adv_tx_context_desc { ...@@ -2285,6 +2316,7 @@ struct ixgbe_adv_tx_context_desc {
/* Adv Transmit Descriptor Config Masks */ /* Adv Transmit Descriptor Config Masks */
#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buf length(bytes) */ #define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buf length(bytes) */
#define IXGBE_ADVTXD_MAC_LINKSEC 0x00040000 /* Insert LinkSec */ #define IXGBE_ADVTXD_MAC_LINKSEC 0x00040000 /* Insert LinkSec */
#define IXGBE_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE 1588 Time Stamp */
#define IXGBE_ADVTXD_IPSEC_SA_INDEX_MASK 0x000003FF /* IPSec SA index */ #define IXGBE_ADVTXD_IPSEC_SA_INDEX_MASK 0x000003FF /* IPSec SA index */
#define IXGBE_ADVTXD_IPSEC_ESP_LEN_MASK 0x000001FF /* IPSec ESP length */ #define IXGBE_ADVTXD_IPSEC_ESP_LEN_MASK 0x000001FF /* IPSec ESP length */
#define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */ #define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */
......
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