Commit 5528e0d7 authored by David S. Miller's avatar David S. Miller
Browse files


Jeff Kirsher says:

====================
1GbE Intel Wired LAN Driver Updates 2020-01-06

This series contains updates to igc to add basic support for
timestamping.

Vinicius adds basic support for timestamping and enables ptp4l/phc2sys
to work with i225 devices.  Initially, adds the ability to read and
adjust the PHC clock.  Patches 2 & 3 enable and retrieve hardware
timestamps.  Patch 4 implements the ethtool ioctl that ptp4l uses to
check what timestamping methods are supported.  Lastly, added support to
do timestamping using the "Start of Packet" signal from the PHY, which
is now supported in i225 devices.

While i225 does support multiple PTP domains, with multiple timestamping
registers, we currently only support one PTP domain and use only one of
the timestamping registers for implementation purposes.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1b935183 a299df35
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -8,4 +8,4 @@
obj-$(CONFIG_IGC) += igc.o

igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o \
igc_ethtool.o
igc_ethtool.o igc_ptp.o
+45 −0
Original line number Diff line number Diff line
@@ -10,6 +10,9 @@
#include <linux/vmalloc.h>
#include <linux/ethtool.h>
#include <linux/sctp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>
#include <linux/net_tstamp.h>

#include "igc_hw.h"

@@ -45,11 +48,15 @@ extern char igc_driver_version[];
#define IGC_REGS_LEN			740
#define IGC_RETA_SIZE			128

/* flags controlling PTP/1588 function */
#define IGC_PTP_ENABLED		BIT(0)

/* Interrupt defines */
#define IGC_START_ITR			648 /* ~6000 ints/sec */
#define IGC_FLAG_HAS_MSI		BIT(0)
#define IGC_FLAG_QUEUE_PAIRS		BIT(3)
#define IGC_FLAG_DMAC			BIT(4)
#define IGC_FLAG_PTP			BIT(8)
#define IGC_FLAG_NEED_LINK_UPDATE	BIT(9)
#define IGC_FLAG_MEDIA_RESET		BIT(10)
#define IGC_FLAG_MAS_ENABLE		BIT(12)
@@ -100,6 +107,20 @@ extern char igc_driver_version[];
#define AUTO_ALL_MODES		0
#define IGC_RX_HDR_LEN			IGC_RXBUFFER_256

/* Transmit and receive latency (for PTP timestamps) */
/* FIXME: These values were estimated using the ones that i210 has as
 * basis, they seem to provide good numbers with ptp4l/phc2sys, but we
 * need to confirm them.
 */
#define IGC_I225_TX_LATENCY_10		9542
#define IGC_I225_TX_LATENCY_100		1024
#define IGC_I225_TX_LATENCY_1000	178
#define IGC_I225_TX_LATENCY_2500	64
#define IGC_I225_RX_LATENCY_10		20662
#define IGC_I225_RX_LATENCY_100		2213
#define IGC_I225_RX_LATENCY_1000	448
#define IGC_I225_RX_LATENCY_2500	160

/* RX and TX descriptor control thresholds.
 * PTHRESH - MAC will consider prefetch if it has fewer than this number of
 *           descriptors available in its onboard memory.
@@ -432,6 +453,20 @@ struct igc_adapter {

	unsigned long link_check_timeout;
	struct igc_info ei;

	struct ptp_clock *ptp_clock;
	struct ptp_clock_info ptp_caps;
	struct work_struct ptp_tx_work;
	struct sk_buff *ptp_tx_skb;
	struct hwtstamp_config tstamp_config;
	unsigned long ptp_tx_start;
	unsigned long last_rx_ptp_check;
	unsigned long last_rx_timestamp;
	unsigned int ptp_flags;
	/* System time value lock */
	spinlock_t tmreg_lock;
	struct cyclecounter cc;
	struct timecounter tc;
};

/* igc_desc_unused - calculate if we have unused descriptors */
@@ -515,6 +550,16 @@ int igc_add_filter(struct igc_adapter *adapter,
int igc_erase_filter(struct igc_adapter *adapter,
		     struct igc_nfc_filter *input);

void igc_ptp_init(struct igc_adapter *adapter);
void igc_ptp_reset(struct igc_adapter *adapter);
void igc_ptp_stop(struct igc_adapter *adapter);
void igc_ptp_rx_rgtstamp(struct igc_q_vector *q_vector, struct sk_buff *skb);
void igc_ptp_rx_pktstamp(struct igc_q_vector *q_vector, void *va,
			 struct sk_buff *skb);
int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
void igc_ptp_tx_hang(struct igc_adapter *adapter);

#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))

#define IGC_TXD_DCMD	(IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS)
+66 −0
Original line number Diff line number Diff line
@@ -218,6 +218,7 @@
#define IGC_ICR_RXDMT0		BIT(4)	/* Rx desc min. threshold (0) */
#define IGC_ICR_RXO		BIT(6)	/* Rx overrun */
#define IGC_ICR_RXT0		BIT(7)	/* Rx timer intr (ring 0) */
#define IGC_ICR_TS		BIT(19)	/* Time Sync Interrupt */
#define IGC_ICR_DRSTA		BIT(30)	/* Device Reset Asserted */

/* If this bit asserted, the driver should claim the interrupt */
@@ -240,6 +241,7 @@
#define IGC_IMS_DRSTA		IGC_ICR_DRSTA	/* Device Reset Asserted */
#define IGC_IMS_RXT0		IGC_ICR_RXT0	/* Rx timer intr */
#define IGC_IMS_RXDMT0		IGC_ICR_RXDMT0	/* Rx desc min. threshold */
#define IGC_IMS_TS		IGC_ICR_TS	/* Time Sync Interrupt */

#define IGC_QVECTOR_MASK	0x7FFC		/* Q-vector mask */
#define IGC_ITR_VAL_MASK	0x04		/* ITR value mask */
@@ -312,12 +314,21 @@
#define IGC_RCTL_RDMTS_HALF	0x00000000 /* Rx desc min thresh size */
#define IGC_RCTL_BAM		0x00008000 /* broadcast enable */

/* Split Replication Receive Control */
#define IGC_SRRCTL_TIMESTAMP		0x40000000
#define IGC_SRRCTL_TIMER1SEL(timer)	(((timer) & 0x3) << 14)
#define IGC_SRRCTL_TIMER0SEL(timer)	(((timer) & 0x3) << 17)

/* Receive Descriptor bit definitions */
#define IGC_RXD_STAT_EOP	0x02	/* End of Packet */
#define IGC_RXD_STAT_IXSM	0x04	/* Ignore checksum */
#define IGC_RXD_STAT_UDPCS	0x10	/* UDP xsum calculated */
#define IGC_RXD_STAT_TCPCS	0x20	/* TCP xsum calculated */

/* Advanced Receive Descriptor bit definitions */
#define IGC_RXDADV_STAT_TSIP	0x08000 /* timestamp in packet */
#define IGC_RXDADV_STAT_TS	0x10000 /* Pkt was time stamped */

#define IGC_RXDEXT_STATERR_CE		0x01000000
#define IGC_RXDEXT_STATERR_SE		0x02000000
#define IGC_RXDEXT_STATERR_SEQ		0x04000000
@@ -354,6 +365,61 @@

#define I225_RXPBSIZE_DEFAULT	0x000000A2 /* RXPBSIZE default */
#define I225_TXPBSIZE_DEFAULT	0x04000014 /* TXPBSIZE default */
#define IGC_RXPBS_CFG_TS_EN	0x80000000 /* Timestamp in Rx buffer */

/* Time Sync Interrupt Causes */
#define IGC_TSICR_SYS_WRAP	BIT(0) /* SYSTIM Wrap around. */
#define IGC_TSICR_TXTS		BIT(1) /* Transmit Timestamp. */
#define IGC_TSICR_TT0		BIT(3) /* Target Time 0 Trigger. */
#define IGC_TSICR_TT1		BIT(4) /* Target Time 1 Trigger. */
#define IGC_TSICR_AUTT0		BIT(5) /* Auxiliary Timestamp 0 Taken. */
#define IGC_TSICR_AUTT1		BIT(6) /* Auxiliary Timestamp 1 Taken. */

#define IGC_TSICR_INTERRUPTS	IGC_TSICR_TXTS

/* PTP Queue Filter */
#define IGC_ETQF_1588		BIT(30)

#define IGC_FTQF_VF_BP		0x00008000
#define IGC_FTQF_1588_TIME_STAMP	0x08000000
#define IGC_FTQF_MASK			0xF0000000
#define IGC_FTQF_MASK_PROTO_BP	0x10000000

/* Time Sync Receive Control bit definitions */
#define IGC_TSYNCRXCTL_VALID		0x00000001  /* Rx timestamp valid */
#define IGC_TSYNCRXCTL_TYPE_MASK	0x0000000E  /* Rx type mask */
#define IGC_TSYNCRXCTL_TYPE_L2_V2	0x00
#define IGC_TSYNCRXCTL_TYPE_L4_V1	0x02
#define IGC_TSYNCRXCTL_TYPE_L2_L4_V2	0x04
#define IGC_TSYNCRXCTL_TYPE_ALL		0x08
#define IGC_TSYNCRXCTL_TYPE_EVENT_V2	0x0A
#define IGC_TSYNCRXCTL_ENABLED		0x00000010  /* enable Rx timestamping */
#define IGC_TSYNCRXCTL_SYSCFI		0x00000020  /* Sys clock frequency */
#define IGC_TSYNCRXCTL_RXSYNSIG		0x00000400  /* Sample RX tstamp in PHY sop */

/* Time Sync Receive Configuration */
#define IGC_TSYNCRXCFG_PTP_V1_CTRLT_MASK	0x000000FF
#define IGC_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE	0x00
#define IGC_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE	0x01

/* Immediate Interrupt Receive */
#define IGC_IMIR_CLEAR_MASK	0xF001FFFF /* IMIR Reg Clear Mask */
#define IGC_IMIR_PORT_BYPASS	0x20000 /* IMIR Port Bypass Bit */
#define IGC_IMIR_PRIORITY_SHIFT	29 /* IMIR Priority Shift */
#define IGC_IMIREXT_CLEAR_MASK	0x7FFFF /* IMIREXT Reg Clear Mask */

/* Immediate Interrupt Receive Extended */
#define IGC_IMIREXT_CTRL_BP	0x00080000  /* Bypass check of ctrl bits */
#define IGC_IMIREXT_SIZE_BP	0x00001000  /* Packet size bypass */

/* Time Sync Transmit Control bit definitions */
#define IGC_TSYNCTXCTL_VALID			0x00000001  /* Tx timestamp valid */
#define IGC_TSYNCTXCTL_ENABLED			0x00000010  /* enable Tx timestamping */
#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK	0x0000F000  /* max delay */
#define IGC_TSYNCTXCTL_SYNC_COMP_ERR		0x20000000  /* sync err */
#define IGC_TSYNCTXCTL_SYNC_COMP		0x40000000  /* sync complete */
#define IGC_TSYNCTXCTL_START_SYNC		0x80000000  /* initiate sync */
#define IGC_TSYNCTXCTL_TXSYNSIG			0x00000020  /* Sample TX tstamp in PHY sop */

/* Receive Checksum Control */
#define IGC_RXCSUM_CRCOFL	0x00000800   /* CRC32 offload enable */
+34 −0
Original line number Diff line number Diff line
@@ -1600,6 +1600,39 @@ static int igc_set_channels(struct net_device *netdev,
	return 0;
}

static int igc_get_ts_info(struct net_device *dev,
			   struct ethtool_ts_info *info)
{
	struct igc_adapter *adapter = netdev_priv(dev);

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

	switch (adapter->hw.mac.type) {
	case igc_i225:
		info->so_timestamping =
			SOF_TIMESTAMPING_TX_SOFTWARE |
			SOF_TIMESTAMPING_RX_SOFTWARE |
			SOF_TIMESTAMPING_SOFTWARE |
			SOF_TIMESTAMPING_TX_HARDWARE |
			SOF_TIMESTAMPING_RX_HARDWARE |
			SOF_TIMESTAMPING_RAW_HARDWARE;

		info->tx_types =
			BIT(HWTSTAMP_TX_OFF) |
			BIT(HWTSTAMP_TX_ON);

		info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
		info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL);

		return 0;
	default:
		return -EOPNOTSUPP;
	}
}

static u32 igc_get_priv_flags(struct net_device *netdev)
{
	struct igc_adapter *adapter = netdev_priv(netdev);
@@ -1847,6 +1880,7 @@ static const struct ethtool_ops igc_ethtool_ops = {
	.get_rxfh_indir_size	= igc_get_rxfh_indir_size,
	.get_rxfh		= igc_get_rxfh,
	.set_rxfh		= igc_set_rxfh,
	.get_ts_info		= igc_get_ts_info,
	.get_channels		= igc_get_channels,
	.set_channels		= igc_set_channels,
	.get_priv_flags		= igc_get_priv_flags,
+87 −0
Original line number Diff line number Diff line
@@ -102,6 +102,9 @@ void igc_reset(struct igc_adapter *adapter)
	if (!netif_running(adapter->netdev))
		igc_power_down_link(adapter);

	/* Re-enable PTP, where applicable. */
	igc_ptp_reset(adapter);

	igc_get_phy_info(hw);
}

@@ -984,6 +987,11 @@ static inline int igc_maybe_stop_tx(struct igc_ring *tx_ring, const u16 size)
	return __igc_maybe_stop_tx(tx_ring, size);
}

#define IGC_SET_FLAG(_input, _flag, _result) \
	(((_flag) <= (_result)) ?				\
	 ((u32)((_input) & (_flag)) * ((_result) / (_flag))) :	\
	 ((u32)((_input) & (_flag)) / ((_flag) / (_result))))

static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
{
	/* set type for advanced descriptor with frame checksum insertion */
@@ -991,6 +999,10 @@ static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
		       IGC_ADVTXD_DCMD_DEXT |
		       IGC_ADVTXD_DCMD_IFCS;

	/* set timestamp bit if present */
	cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP,
				 (IGC_ADVTXD_MAC_TSTAMP));

	return cmd_type;
}

@@ -1189,6 +1201,26 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
	first->bytecount = skb->len;
	first->gso_segs = 1;

	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
		struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);

		/* FIXME: add support for retrieving timestamps from
		 * the other timer registers before skipping the
		 * timestamping request.
		 */
		if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON &&
		    !test_and_set_bit_lock(__IGC_PTP_TX_IN_PROGRESS,
					   &adapter->state)) {
			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
			tx_flags |= IGC_TX_FLAGS_TSTAMP;

			adapter->ptp_tx_skb = skb_get(skb);
			adapter->ptp_tx_start = jiffies;
		} else {
			adapter->tx_hwtstamp_skipped++;
		}
	}

	/* record initial flags and protocol */
	first->tx_flags = tx_flags;
	first->protocol = protocol;
@@ -1296,6 +1328,10 @@ static void igc_process_skb_fields(struct igc_ring *rx_ring,

	igc_rx_checksum(rx_ring, rx_desc, skb);

	if (igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TS) &&
	    !igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP))
		igc_ptp_rx_rgtstamp(rx_ring->q_vector, skb);

	skb_record_rx_queue(skb, rx_ring->queue_index);

	skb->protocol = eth_type_trans(skb, rx_ring->netdev);
@@ -1415,6 +1451,12 @@ static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
	if (unlikely(!skb))
		return NULL;

	if (unlikely(igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP))) {
		igc_ptp_rx_pktstamp(rx_ring->q_vector, va, skb);
		va += IGC_TS_HDR_LEN;
		size -= IGC_TS_HDR_LEN;
	}

	/* Determine available headroom for copy */
	headlen = size;
	if (headlen > IGC_RX_HDR_LEN)
@@ -3635,6 +3677,22 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter,
					IGC_MAC_STATE_QUEUE_STEERING | flags);
}

static void igc_tsync_interrupt(struct igc_adapter *adapter)
{
	struct igc_hw *hw = &adapter->hw;
	u32 tsicr = rd32(IGC_TSICR);
	u32 ack = 0;

	if (tsicr & IGC_TSICR_TXTS) {
		/* retrieve hardware timestamp */
		schedule_work(&adapter->ptp_tx_work);
		ack |= IGC_TSICR_TXTS;
	}

	/* acknowledge the interrupts */
	wr32(IGC_TSICR, ack);
}

/**
 * igc_msix_other - msix other interrupt handler
 * @irq: interrupt number
@@ -3662,6 +3720,9 @@ static irqreturn_t igc_msix_other(int irq, void *data)
			mod_timer(&adapter->watchdog_timer, jiffies + 1);
	}

	if (icr & IGC_ICR_TS)
		igc_tsync_interrupt(adapter);

	wr32(IGC_EIMS, adapter->eims_other);

	return IRQ_HANDLED;
@@ -3991,6 +4052,8 @@ static void igc_watchdog_task(struct work_struct *work)
		wr32(IGC_ICS, IGC_ICS_RXDMT0);
	}

	igc_ptp_tx_hang(adapter);

	/* Reset the timer */
	if (!test_bit(__IGC_DOWN, &adapter->state)) {
		if (adapter->flags & IGC_FLAG_NEED_LINK_UPDATE)
@@ -4277,6 +4340,24 @@ static int igc_close(struct net_device *netdev)
	return 0;
}

/**
 * igc_ioctl - Access the hwtstamp interface
 * @netdev: network interface device structure
 * @ifreq: interface request data
 * @cmd: ioctl command
 **/
static int igc_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
	switch (cmd) {
	case SIOCGHWTSTAMP:
		return igc_ptp_get_ts_config(netdev, ifr);
	case SIOCSHWTSTAMP:
		return igc_ptp_set_ts_config(netdev, ifr);
	default:
		return -EOPNOTSUPP;
	}
}

static const struct net_device_ops igc_netdev_ops = {
	.ndo_open		= igc_open,
	.ndo_stop		= igc_close,
@@ -4288,6 +4369,7 @@ static const struct net_device_ops igc_netdev_ops = {
	.ndo_fix_features	= igc_fix_features,
	.ndo_set_features	= igc_set_features,
	.ndo_features_check	= igc_features_check,
	.ndo_do_ioctl		= igc_ioctl,
};

/* PCIe configuration access */
@@ -4588,6 +4670,9 @@ static int igc_probe(struct pci_dev *pdev,
	 /* carrier off reporting is important to ethtool even BEFORE open */
	netif_carrier_off(netdev);

	/* do hw tstamp init after resetting */
	igc_ptp_init(adapter);

	/* Check if Media Autosense is enabled */
	adapter->ei = *ei;

@@ -4629,6 +4714,8 @@ static void igc_remove(struct pci_dev *pdev)
	struct net_device *netdev = pci_get_drvdata(pdev);
	struct igc_adapter *adapter = netdev_priv(netdev);

	igc_ptp_stop(adapter);

	set_bit(__IGC_DOWN, &adapter->state);

	del_timer_sync(&adapter->watchdog_timer);
Loading