Commit beb0dff1 authored by Jacob Keller's avatar Jacob Keller Committed by Jeff Kirsher

i40e: enable PTP

New feature: Enable PTP support in the i40e driver.

Change-ID: I6a8e799f582705191f9583afb1b9231a8db96cc8
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarMatthew Vick <matthew.vick@intel.com>
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 6ff4ef86
...@@ -243,6 +243,7 @@ config IXGBEVF ...@@ -243,6 +243,7 @@ config IXGBEVF
config I40E config I40E
tristate "Intel(R) Ethernet Controller XL710 Family support" tristate "Intel(R) Ethernet Controller XL710 Family support"
select PTP_1588_CLOCK
depends on PCI depends on PCI
---help--- ---help---
This driver supports Intel(R) Ethernet Controller XL710 Family of This driver supports Intel(R) Ethernet Controller XL710 Family of
......
...@@ -40,4 +40,5 @@ i40e-objs := i40e_main.o \ ...@@ -40,4 +40,5 @@ i40e-objs := i40e_main.o \
i40e_debugfs.o \ i40e_debugfs.o \
i40e_diag.o \ i40e_diag.o \
i40e_txrx.o \ i40e_txrx.o \
i40e_ptp.o \
i40e_virtchnl_pf.o i40e_virtchnl_pf.o
...@@ -50,6 +50,9 @@ ...@@ -50,6 +50,9 @@
#include <net/ip6_checksum.h> #include <net/ip6_checksum.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include "i40e_type.h" #include "i40e_type.h"
#include "i40e_prototype.h" #include "i40e_prototype.h"
#include "i40e_virtchnl.h" #include "i40e_virtchnl.h"
...@@ -242,6 +245,7 @@ struct i40e_pf { ...@@ -242,6 +245,7 @@ struct i40e_pf {
#define I40E_FLAG_DCB_ENABLED (u64)(1 << 20) #define I40E_FLAG_DCB_ENABLED (u64)(1 << 20)
#define I40E_FLAG_FDIR_ENABLED (u64)(1 << 21) #define I40E_FLAG_FDIR_ENABLED (u64)(1 << 21)
#define I40E_FLAG_FDIR_ATR_ENABLED (u64)(1 << 22) #define I40E_FLAG_FDIR_ATR_ENABLED (u64)(1 << 22)
#define I40E_FLAG_PTP (u64)(1 << 25)
#define I40E_FLAG_MFP_ENABLED (u64)(1 << 26) #define I40E_FLAG_MFP_ENABLED (u64)(1 << 26)
#ifdef CONFIG_I40E_VXLAN #ifdef CONFIG_I40E_VXLAN
#define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27) #define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27)
...@@ -302,6 +306,20 @@ struct i40e_pf { ...@@ -302,6 +306,20 @@ struct i40e_pf {
u32 fcoe_hmc_filt_num; u32 fcoe_hmc_filt_num;
u32 fcoe_hmc_cntx_num; u32 fcoe_hmc_cntx_num;
struct i40e_filter_control_settings filter_settings; struct i40e_filter_control_settings filter_settings;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
struct sk_buff *ptp_tx_skb;
struct work_struct ptp_tx_work;
struct hwtstamp_config tstamp_config;
unsigned long ptp_tx_start;
unsigned long last_rx_ptp_check;
spinlock_t tmreg_lock; /* Used to protect the device time registers. */
u64 ptp_base_adj;
u32 tx_hwtstamp_timeouts;
u32 rx_hwtstamp_cleared;
bool ptp_tx;
bool ptp_rx;
}; };
struct i40e_mac_filter { struct i40e_mac_filter {
...@@ -566,4 +584,12 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr, ...@@ -566,4 +584,12 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
bool is_vf, bool is_netdev); bool is_vf, bool is_netdev);
void i40e_vlan_stripping_enable(struct i40e_vsi *vsi); void i40e_vlan_stripping_enable(struct i40e_vsi *vsi);
void i40e_ptp_rx_hang(struct i40e_vsi *vsi);
void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf);
void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index);
void i40e_ptp_set_increment(struct i40e_pf *pf);
int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr);
int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr);
void i40e_ptp_init(struct i40e_pf *pf);
void i40e_ptp_stop(struct i40e_pf *pf);
#endif /* _I40E_H_ */ #endif /* _I40E_H_ */
...@@ -108,6 +108,8 @@ static struct i40e_stats i40e_gstrings_stats[] = { ...@@ -108,6 +108,8 @@ static struct i40e_stats i40e_gstrings_stats[] = {
I40E_PF_STAT("rx_oversize", stats.rx_oversize), I40E_PF_STAT("rx_oversize", stats.rx_oversize),
I40E_PF_STAT("rx_jabber", stats.rx_jabber), I40E_PF_STAT("rx_jabber", stats.rx_jabber),
I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests), I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
I40E_PF_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
}; };
#define I40E_QUEUE_STATS_LEN(n) \ #define I40E_QUEUE_STATS_LEN(n) \
...@@ -748,7 +750,36 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset, ...@@ -748,7 +750,36 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset,
static int i40e_get_ts_info(struct net_device *dev, static int i40e_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info) struct ethtool_ts_info *info)
{ {
return ethtool_op_get_ts_info(dev, info); struct i40e_pf *pf = i40e_netdev_to_pf(dev);
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;
if (pf->ptp_clock)
info->phc_index = ptp_clock_index(pf->ptp_clock);
else
info->phc_index = -1;
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_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
return 0;
} }
static int i40e_link_test(struct net_device *netdev, u64 *data) static int i40e_link_test(struct net_device *netdev, u64 *data)
......
...@@ -1697,6 +1697,27 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -1697,6 +1697,27 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu)
return 0; return 0;
} }
/**
* i40e_ioctl - Access the hwtstamp interface
* @netdev: network interface device structure
* @ifr: interface request data
* @cmd: ioctl command
**/
int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_pf *pf = np->vsi->back;
switch (cmd) {
case SIOCGHWTSTAMP:
return i40e_ptp_get_ts_config(pf, ifr);
case SIOCSHWTSTAMP:
return i40e_ptp_set_ts_config(pf, ifr);
default:
return -EOPNOTSUPP;
}
}
/** /**
* i40e_vlan_stripping_enable - Turn on vlan stripping for the VSI * i40e_vlan_stripping_enable - Turn on vlan stripping for the VSI
* @vsi: the vsi being adjusted * @vsi: the vsi being adjusted
...@@ -2151,6 +2172,7 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) ...@@ -2151,6 +2172,7 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
tx_ctx.qlen = ring->count; tx_ctx.qlen = ring->count;
tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FDIR_ENABLED | tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FDIR_ENABLED |
I40E_FLAG_FDIR_ATR_ENABLED)); I40E_FLAG_FDIR_ATR_ENABLED));
tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP);
/* As part of VSI creation/update, FW allocates certain /* As part of VSI creation/update, FW allocates certain
* Tx arbitration queue sets for each TC enabled for * Tx arbitration queue sets for each TC enabled for
...@@ -2488,6 +2510,7 @@ static void i40e_enable_misc_int_causes(struct i40e_hw *hw) ...@@ -2488,6 +2510,7 @@ static void i40e_enable_misc_int_causes(struct i40e_hw *hw)
I40E_PFINT_ICR0_ENA_GRST_MASK | I40E_PFINT_ICR0_ENA_GRST_MASK |
I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK |
I40E_PFINT_ICR0_ENA_GPIO_MASK | I40E_PFINT_ICR0_ENA_GPIO_MASK |
I40E_PFINT_ICR0_ENA_TIMESYNC_MASK |
I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK | I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK |
I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
I40E_PFINT_ICR0_ENA_VFLR_MASK | I40E_PFINT_ICR0_ENA_VFLR_MASK |
...@@ -2831,6 +2854,18 @@ static irqreturn_t i40e_intr(int irq, void *data) ...@@ -2831,6 +2854,18 @@ static irqreturn_t i40e_intr(int irq, void *data)
dev_info(&pf->pdev->dev, "HMC error interrupt\n"); dev_info(&pf->pdev->dev, "HMC error interrupt\n");
} }
if (icr0 & I40E_PFINT_ICR0_TIMESYNC_MASK) {
u32 prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_0);
if (prttsyn_stat & I40E_PRTTSYN_STAT_0_TXTIME_MASK) {
ena_mask &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
i40e_ptp_tx_hwtstamp(pf);
prttsyn_stat &= ~I40E_PRTTSYN_STAT_0_TXTIME_MASK;
}
wr32(hw, I40E_PRTTSYN_STAT_0, prttsyn_stat);
}
/* If a critical error is pending we have no choice but to reset the /* If a critical error is pending we have no choice but to reset the
* device. * device.
* Report and mask out any remaining unexpected interrupts. * Report and mask out any remaining unexpected interrupts.
...@@ -4304,6 +4339,9 @@ static void i40e_link_event(struct i40e_pf *pf) ...@@ -4304,6 +4339,9 @@ static void i40e_link_event(struct i40e_pf *pf)
if (pf->vf) if (pf->vf)
i40e_vc_notify_link_state(pf); i40e_vc_notify_link_state(pf);
if (pf->flags & I40E_FLAG_PTP)
i40e_ptp_set_increment(pf);
} }
/** /**
...@@ -4385,6 +4423,8 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) ...@@ -4385,6 +4423,8 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf)
for (i = 0; i < I40E_MAX_VEB; i++) for (i = 0; i < I40E_MAX_VEB; i++)
if (pf->veb[i]) if (pf->veb[i])
i40e_update_veb_stats(pf->veb[i]); i40e_update_veb_stats(pf->veb[i]);
i40e_ptp_rx_hang(pf->vsi[pf->lan_vsi]);
} }
/** /**
...@@ -6033,6 +6073,7 @@ static const struct net_device_ops i40e_netdev_ops = { ...@@ -6033,6 +6073,7 @@ static const struct net_device_ops i40e_netdev_ops = {
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = i40e_set_mac, .ndo_set_mac_address = i40e_set_mac,
.ndo_change_mtu = i40e_change_mtu, .ndo_change_mtu = i40e_change_mtu,
.ndo_do_ioctl = i40e_ioctl,
.ndo_tx_timeout = i40e_tx_timeout, .ndo_tx_timeout = i40e_tx_timeout,
.ndo_vlan_rx_add_vid = i40e_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = i40e_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = i40e_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = i40e_vlan_rx_kill_vid,
...@@ -7299,6 +7340,8 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) ...@@ -7299,6 +7340,8 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
~I40E_PRTDCB_MFLCN_RFCE_MASK); ~I40E_PRTDCB_MFLCN_RFCE_MASK);
fc_complete: fc_complete:
i40e_ptp_init(pf);
return ret; return ret;
} }
...@@ -7803,6 +7846,8 @@ static void i40e_remove(struct pci_dev *pdev) ...@@ -7803,6 +7846,8 @@ static void i40e_remove(struct pci_dev *pdev)
i40e_dbg_pf_exit(pf); i40e_dbg_pf_exit(pf);
i40e_ptp_stop(pf);
if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
i40e_free_vfs(pf); i40e_free_vfs(pf);
pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
......
This diff is collapsed.
...@@ -1088,6 +1088,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) ...@@ -1088,6 +1088,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
} }
skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) {
i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status &
I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT);
rx_ring->last_rx_timestamp = jiffies;
}
/* probably a little skewed due to removing CRC */ /* probably a little skewed due to removing CRC */
total_rx_bytes += skb->len; total_rx_bytes += skb->len;
total_rx_packets++; total_rx_packets++;
...@@ -1425,6 +1432,46 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb, ...@@ -1425,6 +1432,46 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
return 1; return 1;
} }
/**
* i40e_tsyn - set up the tsyn context descriptor
* @tx_ring: ptr to the ring to send
* @skb: ptr to the skb we're sending
* @tx_flags: the collected send information
*
* Returns 0 if no Tx timestamp can happen and 1 if the timestamp will happen
**/
static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
u32 tx_flags, u64 *cd_type_cmd_tso_mss)
{
struct i40e_pf *pf;
if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)))
return 0;
/* Tx timestamps cannot be sampled when doing TSO */
if (tx_flags & I40E_TX_FLAGS_TSO)
return 0;
/* only timestamp the outbound packet if the user has requested it and
* we are not already transmitting a packet to be timestamped
*/
pf = i40e_netdev_to_pf(tx_ring->netdev);
if (pf->ptp_tx && !pf->ptp_tx_skb) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
pf->ptp_tx_skb = skb_get(skb);
} else {
return 0;
}
*cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN <<
I40E_TXD_CTX_QW1_CMD_SHIFT;
pf->ptp_tx_start = jiffies;
schedule_work(&pf->ptp_tx_work);
return 1;
}
/** /**
* i40e_tx_enable_csum - Enable Tx checksum offloads * i40e_tx_enable_csum - Enable Tx checksum offloads
* @skb: send buffer * @skb: send buffer
...@@ -1801,6 +1848,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, ...@@ -1801,6 +1848,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
__be16 protocol; __be16 protocol;
u32 td_cmd = 0; u32 td_cmd = 0;
u8 hdr_len = 0; u8 hdr_len = 0;
int tsyn;
int tso; int tso;
if (0 == i40e_xmit_descriptor_count(skb, tx_ring)) if (0 == i40e_xmit_descriptor_count(skb, tx_ring))
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
...@@ -1831,6 +1879,11 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, ...@@ -1831,6 +1879,11 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
tsyn = i40e_tsyn(tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss);
if (tsyn)
tx_flags |= I40E_TX_FLAGS_TSYN;
/* always enable CRC insertion offload */ /* always enable CRC insertion offload */
td_cmd |= I40E_TX_DESC_CMD_ICRC; td_cmd |= I40E_TX_DESC_CMD_ICRC;
......
...@@ -136,6 +136,7 @@ enum i40e_dyn_idx_t { ...@@ -136,6 +136,7 @@ enum i40e_dyn_idx_t {
#define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) #define I40E_TX_FLAGS_IPV6 (u32)(1 << 5)
#define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) #define I40E_TX_FLAGS_FCCRC (u32)(1 << 6)
#define I40E_TX_FLAGS_FSO (u32)(1 << 7) #define I40E_TX_FLAGS_FSO (u32)(1 << 7)
#define I40E_TX_FLAGS_TSYN (u32)(1 << 8)
#define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000
#define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29
...@@ -248,6 +249,8 @@ struct i40e_ring { ...@@ -248,6 +249,8 @@ struct i40e_ring {
u8 atr_sample_rate; u8 atr_sample_rate;
u8 atr_count; u8 atr_count;
unsigned long last_rx_timestamp;
bool ring_active; /* is ring online or not */ bool ring_active; /* is ring online or not */
/* stats structs */ /* stats structs */
......
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