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

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

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
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -220,6 +220,17 @@ config IXGBE_DCB

	  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
	tristate "Intel(R) 82599 Virtual Function Ethernet support"
	depends on PCI_MSI
+2 −0
Original line number Diff line number Diff line
@@ -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_dcb_82599.o ixgbe_dcb_nl.o

ixgbe-$(CONFIG_IXGBE_PTP) += ixgbe_ptp.o

ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o
+32 −0
Original line number Diff line number Diff line
@@ -36,6 +36,12 @@
#include <linux/aer.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_common.h"
#include "ixgbe_dcb.h"
@@ -96,6 +102,7 @@
#define IXGBE_TX_FLAGS_FCOE		(u32)(1 << 5)
#define IXGBE_TX_FLAGS_FSO		(u32)(1 << 6)
#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_PRIO_MASK	0xe0000000
#define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT  29
@@ -458,6 +465,7 @@ struct ixgbe_adapter {
#define IXGBE_FLAG2_FDIR_REQUIRES_REINIT        (u32)(1 << 7)
#define IXGBE_FLAG2_RSS_FIELD_IPV4_UDP		(u32)(1 << 8)
#define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP		(u32)(1 << 9)
#define IXGBE_FLAG2_OVERFLOW_CHECK_ENABLED	(u32)(1 << 10)

	/* Tx fast path data */
	int num_tx_queues;
@@ -545,6 +553,17 @@ struct ixgbe_adapter {
	u32 interrupt_event;
	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 */
	DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
	unsigned int num_vfs;
@@ -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);
}

#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_ */
+52 −1
Original line number Diff line number Diff line
@@ -789,6 +789,13 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
		total_bytes += tx_buffer->bytecount;
		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 */
		dev_kfree_skb_any(tx_buffer->skb);

@@ -1389,6 +1396,11 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,

	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)) {
		u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan);
		__vlan_hwaccel_put_tag(skb, vid);
@@ -5387,6 +5399,11 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
		flow_rx = false;
		break;
	}

#ifdef CONFIG_IXGBE_PTP
	ixgbe_ptp_start_cyclecounter(adapter);
#endif

	e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
	       (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
	       "10 Gbps" :
@@ -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)
		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");
	netif_carrier_off(netdev);
}
@@ -5723,6 +5744,9 @@ static void ixgbe_service_task(struct work_struct *work)
	ixgbe_watchdog_subtask(adapter);
	ixgbe_fdir_reinit_subtask(adapter);
	ixgbe_check_hang_subtask(adapter);
#ifdef CONFIG_IXGBE_PTP
	ixgbe_ptp_overflow_check(adapter);
#endif

	ixgbe_service_event_complete(adapter);
}
@@ -5873,6 +5897,11 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
	if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN)
		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 */
#ifdef IXGBE_FCOE
	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,
		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
	/*
	 * Use the l2switch_enable flag - would be false if the DMA
@@ -6415,8 +6451,15 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
{
	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);
	}
}

/**
 * ixgbe_add_sanmac_netdev - Add the SAN MAC address to the corresponding
@@ -7202,6 +7245,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,

	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 */
	hw->eeprom.ops.read(hw, 0x2e, &adapter->eeprom_verh);
	hw->eeprom.ops.read(hw, 0x2d, &adapter->eeprom_verl);
@@ -7330,6 +7377,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
	set_bit(__IXGBE_DOWN, &adapter->state);
	cancel_work_sync(&adapter->service_task);

#ifdef CONFIG_IXGBE_PTP
	ixgbe_ptp_stop(adapter);
#endif

#ifdef CONFIG_IXGBE_DCA
	if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
		adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED;
+732 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading