diff options
author | Jacob Keller <jacob.e.keller@intel.com> | 2014-01-11 00:43:19 -0500 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2014-01-10 19:33:39 -0500 |
commit | beb0dff1251db5214889ea8a122049ec3ae25e41 (patch) | |
tree | 533fa180ac63edd74b2346dec1ee05fb78f0cf8b /drivers | |
parent | 6ff4ef86be2043b24e89dd9b1e4b4e92fc7fc0fd (diff) |
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: Matthew Vick <matthew.vick@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/intel/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e.h | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 33 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 47 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_ptp.c | 662 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_txrx.c | 53 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_txrx.h | 3 |
8 files changed, 824 insertions, 2 deletions
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 9fb2eb8cf152..333bb54d0bdf 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig | |||
@@ -243,6 +243,7 @@ config IXGBEVF | |||
243 | 243 | ||
244 | config I40E | 244 | config I40E |
245 | tristate "Intel(R) Ethernet Controller XL710 Family support" | 245 | tristate "Intel(R) Ethernet Controller XL710 Family support" |
246 | select PTP_1588_CLOCK | ||
246 | depends on PCI | 247 | depends on PCI |
247 | ---help--- | 248 | ---help--- |
248 | This driver supports Intel(R) Ethernet Controller XL710 Family of | 249 | This driver supports Intel(R) Ethernet Controller XL710 Family of |
diff --git a/drivers/net/ethernet/intel/i40e/Makefile b/drivers/net/ethernet/intel/i40e/Makefile index 6ec1a795f184..e4d2e27078a7 100644 --- a/drivers/net/ethernet/intel/i40e/Makefile +++ b/drivers/net/ethernet/intel/i40e/Makefile | |||
@@ -40,4 +40,5 @@ i40e-objs := i40e_main.o \ | |||
40 | i40e_debugfs.o \ | 40 | i40e_debugfs.o \ |
41 | i40e_diag.o \ | 41 | i40e_diag.o \ |
42 | i40e_txrx.o \ | 42 | i40e_txrx.o \ |
43 | i40e_ptp.o \ | ||
43 | i40e_virtchnl_pf.o | 44 | i40e_virtchnl_pf.o |
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 7dab660a8e50..c05984d72cfb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h | |||
@@ -50,6 +50,9 @@ | |||
50 | #include <net/ip6_checksum.h> | 50 | #include <net/ip6_checksum.h> |
51 | #include <linux/ethtool.h> | 51 | #include <linux/ethtool.h> |
52 | #include <linux/if_vlan.h> | 52 | #include <linux/if_vlan.h> |
53 | #include <linux/clocksource.h> | ||
54 | #include <linux/net_tstamp.h> | ||
55 | #include <linux/ptp_clock_kernel.h> | ||
53 | #include "i40e_type.h" | 56 | #include "i40e_type.h" |
54 | #include "i40e_prototype.h" | 57 | #include "i40e_prototype.h" |
55 | #include "i40e_virtchnl.h" | 58 | #include "i40e_virtchnl.h" |
@@ -242,6 +245,7 @@ struct i40e_pf { | |||
242 | #define I40E_FLAG_DCB_ENABLED (u64)(1 << 20) | 245 | #define I40E_FLAG_DCB_ENABLED (u64)(1 << 20) |
243 | #define I40E_FLAG_FDIR_ENABLED (u64)(1 << 21) | 246 | #define I40E_FLAG_FDIR_ENABLED (u64)(1 << 21) |
244 | #define I40E_FLAG_FDIR_ATR_ENABLED (u64)(1 << 22) | 247 | #define I40E_FLAG_FDIR_ATR_ENABLED (u64)(1 << 22) |
248 | #define I40E_FLAG_PTP (u64)(1 << 25) | ||
245 | #define I40E_FLAG_MFP_ENABLED (u64)(1 << 26) | 249 | #define I40E_FLAG_MFP_ENABLED (u64)(1 << 26) |
246 | #ifdef CONFIG_I40E_VXLAN | 250 | #ifdef CONFIG_I40E_VXLAN |
247 | #define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27) | 251 | #define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27) |
@@ -302,6 +306,20 @@ struct i40e_pf { | |||
302 | u32 fcoe_hmc_filt_num; | 306 | u32 fcoe_hmc_filt_num; |
303 | u32 fcoe_hmc_cntx_num; | 307 | u32 fcoe_hmc_cntx_num; |
304 | struct i40e_filter_control_settings filter_settings; | 308 | struct i40e_filter_control_settings filter_settings; |
309 | |||
310 | struct ptp_clock *ptp_clock; | ||
311 | struct ptp_clock_info ptp_caps; | ||
312 | struct sk_buff *ptp_tx_skb; | ||
313 | struct work_struct ptp_tx_work; | ||
314 | struct hwtstamp_config tstamp_config; | ||
315 | unsigned long ptp_tx_start; | ||
316 | unsigned long last_rx_ptp_check; | ||
317 | spinlock_t tmreg_lock; /* Used to protect the device time registers. */ | ||
318 | u64 ptp_base_adj; | ||
319 | u32 tx_hwtstamp_timeouts; | ||
320 | u32 rx_hwtstamp_cleared; | ||
321 | bool ptp_tx; | ||
322 | bool ptp_rx; | ||
305 | }; | 323 | }; |
306 | 324 | ||
307 | struct i40e_mac_filter { | 325 | struct i40e_mac_filter { |
@@ -566,4 +584,12 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr, | |||
566 | bool is_vf, bool is_netdev); | 584 | bool is_vf, bool is_netdev); |
567 | void i40e_vlan_stripping_enable(struct i40e_vsi *vsi); | 585 | void i40e_vlan_stripping_enable(struct i40e_vsi *vsi); |
568 | 586 | ||
587 | void i40e_ptp_rx_hang(struct i40e_vsi *vsi); | ||
588 | void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf); | ||
589 | void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index); | ||
590 | void i40e_ptp_set_increment(struct i40e_pf *pf); | ||
591 | int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr); | ||
592 | int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr); | ||
593 | void i40e_ptp_init(struct i40e_pf *pf); | ||
594 | void i40e_ptp_stop(struct i40e_pf *pf); | ||
569 | #endif /* _I40E_H_ */ | 595 | #endif /* _I40E_H_ */ |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 342a6e13ac8b..7b87d5115816 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c | |||
@@ -108,6 +108,8 @@ static struct i40e_stats i40e_gstrings_stats[] = { | |||
108 | I40E_PF_STAT("rx_oversize", stats.rx_oversize), | 108 | I40E_PF_STAT("rx_oversize", stats.rx_oversize), |
109 | I40E_PF_STAT("rx_jabber", stats.rx_jabber), | 109 | I40E_PF_STAT("rx_jabber", stats.rx_jabber), |
110 | I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests), | 110 | I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests), |
111 | I40E_PF_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), | ||
112 | I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), | ||
111 | }; | 113 | }; |
112 | 114 | ||
113 | #define I40E_QUEUE_STATS_LEN(n) \ | 115 | #define I40E_QUEUE_STATS_LEN(n) \ |
@@ -748,7 +750,36 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset, | |||
748 | static int i40e_get_ts_info(struct net_device *dev, | 750 | static int i40e_get_ts_info(struct net_device *dev, |
749 | struct ethtool_ts_info *info) | 751 | struct ethtool_ts_info *info) |
750 | { | 752 | { |
751 | return ethtool_op_get_ts_info(dev, info); | 753 | struct i40e_pf *pf = i40e_netdev_to_pf(dev); |
754 | |||
755 | info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | | ||
756 | SOF_TIMESTAMPING_RX_SOFTWARE | | ||
757 | SOF_TIMESTAMPING_SOFTWARE | | ||
758 | SOF_TIMESTAMPING_TX_HARDWARE | | ||
759 | SOF_TIMESTAMPING_RX_HARDWARE | | ||
760 | SOF_TIMESTAMPING_RAW_HARDWARE; | ||
761 | |||
762 | if (pf->ptp_clock) | ||
763 | info->phc_index = ptp_clock_index(pf->ptp_clock); | ||
764 | else | ||
765 | info->phc_index = -1; | ||
766 | |||
767 | info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); | ||
768 | |||
769 | info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | | ||
770 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | | ||
771 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | | ||
772 | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | | ||
773 | (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | | ||
774 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | | ||
775 | (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | | ||
776 | (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | | ||
777 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | | ||
778 | (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | | ||
779 | (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | | ||
780 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); | ||
781 | |||
782 | return 0; | ||
752 | } | 783 | } |
753 | 784 | ||
754 | static int i40e_link_test(struct net_device *netdev, u64 *data) | 785 | static int i40e_link_test(struct net_device *netdev, u64 *data) |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 182ed1893b1f..b4e4da5ca7bb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c | |||
@@ -1698,6 +1698,27 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu) | |||
1698 | } | 1698 | } |
1699 | 1699 | ||
1700 | /** | 1700 | /** |
1701 | * i40e_ioctl - Access the hwtstamp interface | ||
1702 | * @netdev: network interface device structure | ||
1703 | * @ifr: interface request data | ||
1704 | * @cmd: ioctl command | ||
1705 | **/ | ||
1706 | int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) | ||
1707 | { | ||
1708 | struct i40e_netdev_priv *np = netdev_priv(netdev); | ||
1709 | struct i40e_pf *pf = np->vsi->back; | ||
1710 | |||
1711 | switch (cmd) { | ||
1712 | case SIOCGHWTSTAMP: | ||
1713 | return i40e_ptp_get_ts_config(pf, ifr); | ||
1714 | case SIOCSHWTSTAMP: | ||
1715 | return i40e_ptp_set_ts_config(pf, ifr); | ||
1716 | default: | ||
1717 | return -EOPNOTSUPP; | ||
1718 | } | ||
1719 | } | ||
1720 | |||
1721 | /** | ||
1701 | * i40e_vlan_stripping_enable - Turn on vlan stripping for the VSI | 1722 | * i40e_vlan_stripping_enable - Turn on vlan stripping for the VSI |
1702 | * @vsi: the vsi being adjusted | 1723 | * @vsi: the vsi being adjusted |
1703 | **/ | 1724 | **/ |
@@ -2150,7 +2171,8 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) | |||
2150 | tx_ctx.base = (ring->dma / 128); | 2171 | tx_ctx.base = (ring->dma / 128); |
2151 | tx_ctx.qlen = ring->count; | 2172 | tx_ctx.qlen = ring->count; |
2152 | tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FDIR_ENABLED | | 2173 | tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FDIR_ENABLED | |
2153 | I40E_FLAG_FDIR_ATR_ENABLED)); | 2174 | I40E_FLAG_FDIR_ATR_ENABLED)); |
2175 | tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP); | ||
2154 | 2176 | ||
2155 | /* As part of VSI creation/update, FW allocates certain | 2177 | /* As part of VSI creation/update, FW allocates certain |
2156 | * Tx arbitration queue sets for each TC enabled for | 2178 | * 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 | I40E_PFINT_ICR0_ENA_GRST_MASK | | 2510 | I40E_PFINT_ICR0_ENA_GRST_MASK | |
2489 | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK | | 2511 | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK | |
2490 | I40E_PFINT_ICR0_ENA_GPIO_MASK | | 2512 | I40E_PFINT_ICR0_ENA_GPIO_MASK | |
2513 | I40E_PFINT_ICR0_ENA_TIMESYNC_MASK | | ||
2491 | I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK | | 2514 | I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK | |
2492 | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | | 2515 | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | |
2493 | I40E_PFINT_ICR0_ENA_VFLR_MASK | | 2516 | I40E_PFINT_ICR0_ENA_VFLR_MASK | |
@@ -2831,6 +2854,18 @@ static irqreturn_t i40e_intr(int irq, void *data) | |||
2831 | dev_info(&pf->pdev->dev, "HMC error interrupt\n"); | 2854 | dev_info(&pf->pdev->dev, "HMC error interrupt\n"); |
2832 | } | 2855 | } |
2833 | 2856 | ||
2857 | if (icr0 & I40E_PFINT_ICR0_TIMESYNC_MASK) { | ||
2858 | u32 prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_0); | ||
2859 | |||
2860 | if (prttsyn_stat & I40E_PRTTSYN_STAT_0_TXTIME_MASK) { | ||
2861 | ena_mask &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; | ||
2862 | i40e_ptp_tx_hwtstamp(pf); | ||
2863 | prttsyn_stat &= ~I40E_PRTTSYN_STAT_0_TXTIME_MASK; | ||
2864 | } | ||
2865 | |||
2866 | wr32(hw, I40E_PRTTSYN_STAT_0, prttsyn_stat); | ||
2867 | } | ||
2868 | |||
2834 | /* If a critical error is pending we have no choice but to reset the | 2869 | /* If a critical error is pending we have no choice but to reset the |
2835 | * device. | 2870 | * device. |
2836 | * Report and mask out any remaining unexpected interrupts. | 2871 | * Report and mask out any remaining unexpected interrupts. |
@@ -4304,6 +4339,9 @@ static void i40e_link_event(struct i40e_pf *pf) | |||
4304 | 4339 | ||
4305 | if (pf->vf) | 4340 | if (pf->vf) |
4306 | i40e_vc_notify_link_state(pf); | 4341 | i40e_vc_notify_link_state(pf); |
4342 | |||
4343 | if (pf->flags & I40E_FLAG_PTP) | ||
4344 | i40e_ptp_set_increment(pf); | ||
4307 | } | 4345 | } |
4308 | 4346 | ||
4309 | /** | 4347 | /** |
@@ -4385,6 +4423,8 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) | |||
4385 | for (i = 0; i < I40E_MAX_VEB; i++) | 4423 | for (i = 0; i < I40E_MAX_VEB; i++) |
4386 | if (pf->veb[i]) | 4424 | if (pf->veb[i]) |
4387 | i40e_update_veb_stats(pf->veb[i]); | 4425 | i40e_update_veb_stats(pf->veb[i]); |
4426 | |||
4427 | i40e_ptp_rx_hang(pf->vsi[pf->lan_vsi]); | ||
4388 | } | 4428 | } |
4389 | 4429 | ||
4390 | /** | 4430 | /** |
@@ -6033,6 +6073,7 @@ static const struct net_device_ops i40e_netdev_ops = { | |||
6033 | .ndo_validate_addr = eth_validate_addr, | 6073 | .ndo_validate_addr = eth_validate_addr, |
6034 | .ndo_set_mac_address = i40e_set_mac, | 6074 | .ndo_set_mac_address = i40e_set_mac, |
6035 | .ndo_change_mtu = i40e_change_mtu, | 6075 | .ndo_change_mtu = i40e_change_mtu, |
6076 | .ndo_do_ioctl = i40e_ioctl, | ||
6036 | .ndo_tx_timeout = i40e_tx_timeout, | 6077 | .ndo_tx_timeout = i40e_tx_timeout, |
6037 | .ndo_vlan_rx_add_vid = i40e_vlan_rx_add_vid, | 6078 | .ndo_vlan_rx_add_vid = i40e_vlan_rx_add_vid, |
6038 | .ndo_vlan_rx_kill_vid = i40e_vlan_rx_kill_vid, | 6079 | .ndo_vlan_rx_kill_vid = i40e_vlan_rx_kill_vid, |
@@ -7299,6 +7340,8 @@ no_autoneg: | |||
7299 | ~I40E_PRTDCB_MFLCN_RFCE_MASK); | 7340 | ~I40E_PRTDCB_MFLCN_RFCE_MASK); |
7300 | 7341 | ||
7301 | fc_complete: | 7342 | fc_complete: |
7343 | i40e_ptp_init(pf); | ||
7344 | |||
7302 | return ret; | 7345 | return ret; |
7303 | } | 7346 | } |
7304 | 7347 | ||
@@ -7803,6 +7846,8 @@ static void i40e_remove(struct pci_dev *pdev) | |||
7803 | 7846 | ||
7804 | i40e_dbg_pf_exit(pf); | 7847 | i40e_dbg_pf_exit(pf); |
7805 | 7848 | ||
7849 | i40e_ptp_stop(pf); | ||
7850 | |||
7806 | if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { | 7851 | if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { |
7807 | i40e_free_vfs(pf); | 7852 | i40e_free_vfs(pf); |
7808 | pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; | 7853 | pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c new file mode 100644 index 000000000000..e33ec6c842b7 --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c | |||
@@ -0,0 +1,662 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * Intel Ethernet Controller XL710 Family Linux Driver | ||
4 | * Copyright(c) 2013 - 2014 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
23 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | * | ||
25 | ******************************************************************************/ | ||
26 | |||
27 | #include "i40e.h" | ||
28 | #include <linux/export.h> | ||
29 | #include <linux/ptp_classify.h> | ||
30 | |||
31 | /* The XL710 timesync is very much like Intel's 82599 design when it comes to | ||
32 | * the fundamental clock design. However, the clock operations are much simpler | ||
33 | * in the XL710 because the device supports a full 64 bits of nanoseconds. | ||
34 | * Because the field is so wide, we can forgo the cycle counter and just | ||
35 | * operate with the nanosecond field directly without fear of overflow. | ||
36 | * | ||
37 | * Much like the 82599, the update period is dependent upon the link speed: | ||
38 | * At 40Gb link or no link, the period is 1.6ns. | ||
39 | * At 10Gb link, the period is multiplied by 2. (3.2ns) | ||
40 | * At 1Gb link, the period is multiplied by 20. (32ns) | ||
41 | * 1588 functionality is not supported at 100Mbps. | ||
42 | */ | ||
43 | #define I40E_PTP_40GB_INCVAL 0x0199999999ULL | ||
44 | #define I40E_PTP_10GB_INCVAL 0x0333333333ULL | ||
45 | #define I40E_PTP_1GB_INCVAL 0x2000000000ULL | ||
46 | |||
47 | #define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 (0x1 << \ | ||
48 | I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) | ||
49 | #define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (0x2 << \ | ||
50 | I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) | ||
51 | #define I40E_PTP_TX_TIMEOUT (HZ * 15) | ||
52 | |||
53 | /** | ||
54 | * i40e_ptp_read - Read the PHC time from the device | ||
55 | * @pf: Board private structure | ||
56 | * @ts: timespec structure to hold the current time value | ||
57 | * | ||
58 | * This function reads the PRTTSYN_TIME registers and stores them in a | ||
59 | * timespec. However, since the registers are 64 bits of nanoseconds, we must | ||
60 | * convert the result to a timespec before we can return. | ||
61 | **/ | ||
62 | static void i40e_ptp_read(struct i40e_pf *pf, struct timespec *ts) | ||
63 | { | ||
64 | struct i40e_hw *hw = &pf->hw; | ||
65 | u32 hi, lo; | ||
66 | u64 ns; | ||
67 | |||
68 | /* The timer latches on the lowest register read. */ | ||
69 | lo = rd32(hw, I40E_PRTTSYN_TIME_L); | ||
70 | hi = rd32(hw, I40E_PRTTSYN_TIME_H); | ||
71 | |||
72 | ns = (((u64)hi) << 32) | lo; | ||
73 | |||
74 | *ts = ns_to_timespec(ns); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * i40e_ptp_write - Write the PHC time to the device | ||
79 | * @pf: Board private structure | ||
80 | * @ts: timespec structure that holds the new time value | ||
81 | * | ||
82 | * This function writes the PRTTSYN_TIME registers with the user value. Since | ||
83 | * we receive a timespec from the stack, we must convert that timespec into | ||
84 | * nanoseconds before programming the registers. | ||
85 | **/ | ||
86 | static void i40e_ptp_write(struct i40e_pf *pf, const struct timespec *ts) | ||
87 | { | ||
88 | struct i40e_hw *hw = &pf->hw; | ||
89 | u64 ns = timespec_to_ns(ts); | ||
90 | |||
91 | /* The timer will not update until the high register is written, so | ||
92 | * write the low register first. | ||
93 | */ | ||
94 | wr32(hw, I40E_PRTTSYN_TIME_L, ns & 0xFFFFFFFF); | ||
95 | wr32(hw, I40E_PRTTSYN_TIME_H, ns >> 32); | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * i40e_ptp_convert_to_hwtstamp - Convert device clock to system time | ||
100 | * @hwtstamps: Timestamp structure to update | ||
101 | * @timestamp: Timestamp from the hardware | ||
102 | * | ||
103 | * We need to convert the NIC clock value into a hwtstamp which can be used by | ||
104 | * the upper level timestamping functions. Since the timestamp is simply a 64- | ||
105 | * bit nanosecond value, we can call ns_to_ktime directly to handle this. | ||
106 | **/ | ||
107 | static void i40e_ptp_convert_to_hwtstamp(struct skb_shared_hwtstamps *hwtstamps, | ||
108 | u64 timestamp) | ||
109 | { | ||
110 | memset(hwtstamps, 0, sizeof(*hwtstamps)); | ||
111 | |||
112 | hwtstamps->hwtstamp = ns_to_ktime(timestamp); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * i40e_ptp_adjfreq - Adjust the PHC frequency | ||
117 | * @ptp: The PTP clock structure | ||
118 | * @ppb: Parts per billion adjustment from the base | ||
119 | * | ||
120 | * Adjust the frequency of the PHC by the indicated parts per billion from the | ||
121 | * base frequency. | ||
122 | **/ | ||
123 | static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) | ||
124 | { | ||
125 | struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); | ||
126 | struct i40e_hw *hw = &pf->hw; | ||
127 | u64 adj, freq, diff; | ||
128 | int neg_adj = 0; | ||
129 | |||
130 | if (ppb < 0) { | ||
131 | neg_adj = 1; | ||
132 | ppb = -ppb; | ||
133 | } | ||
134 | |||
135 | smp_mb(); /* Force any pending update before accessing. */ | ||
136 | adj = ACCESS_ONCE(pf->ptp_base_adj); | ||
137 | |||
138 | freq = adj; | ||
139 | freq *= ppb; | ||
140 | diff = div_u64(freq, 1000000000ULL); | ||
141 | |||
142 | if (neg_adj) | ||
143 | adj -= diff; | ||
144 | else | ||
145 | adj += diff; | ||
146 | |||
147 | wr32(hw, I40E_PRTTSYN_INC_L, adj & 0xFFFFFFFF); | ||
148 | wr32(hw, I40E_PRTTSYN_INC_H, adj >> 32); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * i40e_ptp_adjtime - Adjust the PHC time | ||
155 | * @ptp: The PTP clock structure | ||
156 | * @delta: Offset in nanoseconds to adjust the PHC time by | ||
157 | * | ||
158 | * Adjust the frequency of the PHC by the indicated parts per billion from the | ||
159 | * base frequency. | ||
160 | **/ | ||
161 | static int i40e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) | ||
162 | { | ||
163 | struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); | ||
164 | struct timespec now, then = ns_to_timespec(delta); | ||
165 | unsigned long flags; | ||
166 | |||
167 | spin_lock_irqsave(&pf->tmreg_lock, flags); | ||
168 | |||
169 | i40e_ptp_read(pf, &now); | ||
170 | now = timespec_add(now, then); | ||
171 | i40e_ptp_write(pf, (const struct timespec *)&now); | ||
172 | |||
173 | spin_unlock_irqrestore(&pf->tmreg_lock, flags); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * i40e_ptp_gettime - Get the time of the PHC | ||
180 | * @ptp: The PTP clock structure | ||
181 | * @ts: timespec structure to hold the current time value | ||
182 | * | ||
183 | * Read the device clock and return the correct value on ns, after converting it | ||
184 | * into a timespec struct. | ||
185 | **/ | ||
186 | static int i40e_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) | ||
187 | { | ||
188 | struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); | ||
189 | unsigned long flags; | ||
190 | |||
191 | spin_lock_irqsave(&pf->tmreg_lock, flags); | ||
192 | i40e_ptp_read(pf, ts); | ||
193 | spin_unlock_irqrestore(&pf->tmreg_lock, flags); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * i40e_ptp_settime - Set the time of the PHC | ||
200 | * @ptp: The PTP clock structure | ||
201 | * @ts: timespec structure that holds the new time value | ||
202 | * | ||
203 | * Set the device clock to the user input value. The conversion from timespec | ||
204 | * to ns happens in the write function. | ||
205 | **/ | ||
206 | static int i40e_ptp_settime(struct ptp_clock_info *ptp, | ||
207 | const struct timespec *ts) | ||
208 | { | ||
209 | struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); | ||
210 | unsigned long flags; | ||
211 | |||
212 | spin_lock_irqsave(&pf->tmreg_lock, flags); | ||
213 | i40e_ptp_write(pf, ts); | ||
214 | spin_unlock_irqrestore(&pf->tmreg_lock, flags); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * i40e_ptp_tx_work | ||
221 | * @work: pointer to work struct | ||
222 | * | ||
223 | * This work function polls the PRTTSYN_STAT_0.TXTIME bit to determine when a | ||
224 | * Tx timestamp event has occurred, in order to pass the Tx timestamp value up | ||
225 | * the stack in the skb. | ||
226 | */ | ||
227 | static void i40e_ptp_tx_work(struct work_struct *work) | ||
228 | { | ||
229 | struct i40e_pf *pf = container_of(work, struct i40e_pf, | ||
230 | ptp_tx_work); | ||
231 | struct i40e_hw *hw = &pf->hw; | ||
232 | u32 prttsyn_stat_0; | ||
233 | |||
234 | if (!pf->ptp_tx_skb) | ||
235 | return; | ||
236 | |||
237 | if (time_is_before_jiffies(pf->ptp_tx_start + | ||
238 | I40E_PTP_TX_TIMEOUT)) { | ||
239 | dev_kfree_skb_any(pf->ptp_tx_skb); | ||
240 | pf->ptp_tx_skb = NULL; | ||
241 | pf->tx_hwtstamp_timeouts++; | ||
242 | dev_warn(&pf->pdev->dev, "clearing Tx timestamp hang"); | ||
243 | return; | ||
244 | } | ||
245 | |||
246 | prttsyn_stat_0 = rd32(hw, I40E_PRTTSYN_STAT_0); | ||
247 | if (prttsyn_stat_0 & I40E_PRTTSYN_STAT_0_TXTIME_MASK) | ||
248 | i40e_ptp_tx_hwtstamp(pf); | ||
249 | else | ||
250 | schedule_work(&pf->ptp_tx_work); | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem | ||
255 | * @ptp: The PTP clock structure | ||
256 | * @rq: The requested feature to change | ||
257 | * @on: Enable/disable flag | ||
258 | * | ||
259 | * The XL710 does not support any of the ancillary features of the PHC | ||
260 | * subsystem, so this function may just return. | ||
261 | **/ | ||
262 | static int i40e_ptp_enable(struct ptp_clock_info *ptp, | ||
263 | struct ptp_clock_request *rq, int on) | ||
264 | { | ||
265 | return -EOPNOTSUPP; | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung | ||
270 | * @vsi: The VSI with the rings relevant to 1588 | ||
271 | * | ||
272 | * This watchdog task is scheduled to detect error case where hardware has | ||
273 | * dropped an Rx packet that was timestamped when the ring is full. The | ||
274 | * particular error is rare but leaves the device in a state unable to timestamp | ||
275 | * any future packets. | ||
276 | **/ | ||
277 | void i40e_ptp_rx_hang(struct i40e_vsi *vsi) | ||
278 | { | ||
279 | struct i40e_pf *pf = vsi->back; | ||
280 | struct i40e_hw *hw = &pf->hw; | ||
281 | struct i40e_ring *rx_ring; | ||
282 | unsigned long rx_event; | ||
283 | u32 prttsyn_stat; | ||
284 | int n; | ||
285 | |||
286 | if (pf->flags & I40E_FLAG_PTP) | ||
287 | return; | ||
288 | |||
289 | prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); | ||
290 | |||
291 | /* Unless all four receive timestamp registers are latched, we are not | ||
292 | * concerned about a possible PTP Rx hang, so just update the timeout | ||
293 | * counter and exit. | ||
294 | */ | ||
295 | if (!(prttsyn_stat & ((I40E_PRTTSYN_STAT_1_RXT0_MASK << | ||
296 | I40E_PRTTSYN_STAT_1_RXT0_SHIFT) | | ||
297 | (I40E_PRTTSYN_STAT_1_RXT1_MASK << | ||
298 | I40E_PRTTSYN_STAT_1_RXT1_SHIFT) | | ||
299 | (I40E_PRTTSYN_STAT_1_RXT2_MASK << | ||
300 | I40E_PRTTSYN_STAT_1_RXT2_SHIFT) | | ||
301 | (I40E_PRTTSYN_STAT_1_RXT3_MASK << | ||
302 | I40E_PRTTSYN_STAT_1_RXT3_SHIFT)))) { | ||
303 | pf->last_rx_ptp_check = jiffies; | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | /* Determine the most recent watchdog or rx_timestamp event. */ | ||
308 | rx_event = pf->last_rx_ptp_check; | ||
309 | for (n = 0; n < vsi->num_queue_pairs; n++) { | ||
310 | rx_ring = vsi->rx_rings[n]; | ||
311 | if (time_after(rx_ring->last_rx_timestamp, rx_event)) | ||
312 | rx_event = rx_ring->last_rx_timestamp; | ||
313 | } | ||
314 | |||
315 | /* Only need to read the high RXSTMP register to clear the lock */ | ||
316 | if (time_is_before_jiffies(rx_event + 5 * HZ)) { | ||
317 | rd32(hw, I40E_PRTTSYN_RXTIME_H(0)); | ||
318 | rd32(hw, I40E_PRTTSYN_RXTIME_H(1)); | ||
319 | rd32(hw, I40E_PRTTSYN_RXTIME_H(2)); | ||
320 | rd32(hw, I40E_PRTTSYN_RXTIME_H(3)); | ||
321 | pf->last_rx_ptp_check = jiffies; | ||
322 | pf->rx_hwtstamp_cleared++; | ||
323 | dev_warn(&vsi->back->pdev->dev, | ||
324 | "%s: clearing Rx timestamp hang", | ||
325 | __func__); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * i40e_ptp_tx_hwtstamp - Utility function which returns the Tx timestamp | ||
331 | * @pf: Board private structure | ||
332 | * | ||
333 | * Read the value of the Tx timestamp from the registers, convert it into a | ||
334 | * value consumable by the stack, and store that result into the shhwtstamps | ||
335 | * struct before returning it up the stack. | ||
336 | **/ | ||
337 | void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) | ||
338 | { | ||
339 | struct skb_shared_hwtstamps shhwtstamps; | ||
340 | struct i40e_hw *hw = &pf->hw; | ||
341 | u32 hi, lo; | ||
342 | u64 ns; | ||
343 | |||
344 | lo = rd32(hw, I40E_PRTTSYN_TXTIME_L); | ||
345 | hi = rd32(hw, I40E_PRTTSYN_TXTIME_H); | ||
346 | |||
347 | ns = (((u64)hi) << 32) | lo; | ||
348 | |||
349 | i40e_ptp_convert_to_hwtstamp(&shhwtstamps, ns); | ||
350 | skb_tstamp_tx(pf->ptp_tx_skb, &shhwtstamps); | ||
351 | dev_kfree_skb_any(pf->ptp_tx_skb); | ||
352 | pf->ptp_tx_skb = NULL; | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * i40e_ptp_rx_hwtstamp - Utility function which checks for an Rx timestamp | ||
357 | * @pf: Board private structure | ||
358 | * @skb: Particular skb to send timestamp with | ||
359 | * @index: Index into the receive timestamp registers for the timestamp | ||
360 | * | ||
361 | * The XL710 receives a notification in the receive descriptor with an offset | ||
362 | * into the set of RXTIME registers where the timestamp is for that skb. This | ||
363 | * function goes and fetches the receive timestamp from that offset, if a valid | ||
364 | * one exists. The RXTIME registers are in ns, so we must convert the result | ||
365 | * first. | ||
366 | **/ | ||
367 | void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) | ||
368 | { | ||
369 | u32 prttsyn_stat, hi, lo; | ||
370 | struct i40e_hw *hw; | ||
371 | u64 ns; | ||
372 | |||
373 | /* Since we cannot turn off the Rx timestamp logic if the device is | ||
374 | * doing Tx timestamping, check if Rx timestamping is configured. | ||
375 | */ | ||
376 | if (!pf->ptp_rx) | ||
377 | return; | ||
378 | |||
379 | hw = &pf->hw; | ||
380 | |||
381 | prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); | ||
382 | |||
383 | if (!(prttsyn_stat & (1 << index))) | ||
384 | return; | ||
385 | |||
386 | lo = rd32(hw, I40E_PRTTSYN_RXTIME_L(index)); | ||
387 | hi = rd32(hw, I40E_PRTTSYN_RXTIME_H(index)); | ||
388 | |||
389 | ns = (((u64)hi) << 32) | lo; | ||
390 | |||
391 | i40e_ptp_convert_to_hwtstamp(skb_hwtstamps(skb), ns); | ||
392 | } | ||
393 | |||
394 | /** | ||
395 | * i40e_ptp_set_increment - Utility function to update clock increment rate | ||
396 | * @pf: Board private structure | ||
397 | * | ||
398 | * During a link change, the DMA frequency that drives the 1588 logic will | ||
399 | * change. In order to keep the PRTTSYN_TIME registers in units of nanoseconds, | ||
400 | * we must update the increment value per clock tick. | ||
401 | **/ | ||
402 | void i40e_ptp_set_increment(struct i40e_pf *pf) | ||
403 | { | ||
404 | struct i40e_link_status *hw_link_info; | ||
405 | struct i40e_hw *hw = &pf->hw; | ||
406 | u64 incval; | ||
407 | |||
408 | hw_link_info = &hw->phy.link_info; | ||
409 | |||
410 | i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); | ||
411 | |||
412 | switch (hw_link_info->link_speed) { | ||
413 | case I40E_LINK_SPEED_10GB: | ||
414 | incval = I40E_PTP_10GB_INCVAL; | ||
415 | break; | ||
416 | case I40E_LINK_SPEED_1GB: | ||
417 | incval = I40E_PTP_1GB_INCVAL; | ||
418 | break; | ||
419 | case I40E_LINK_SPEED_100MB: | ||
420 | dev_warn(&pf->pdev->dev, | ||
421 | "%s: 1588 functionality is not supported at 100 Mbps. Stopping the PHC.\n", | ||
422 | __func__); | ||
423 | incval = 0; | ||
424 | break; | ||
425 | case I40E_LINK_SPEED_40GB: | ||
426 | default: | ||
427 | incval = I40E_PTP_40GB_INCVAL; | ||
428 | break; | ||
429 | } | ||
430 | |||
431 | /* Write the new increment value into the increment register. The | ||
432 | * hardware will not update the clock until both registers have been | ||
433 | * written. | ||
434 | */ | ||
435 | wr32(hw, I40E_PRTTSYN_INC_L, incval & 0xFFFFFFFF); | ||
436 | wr32(hw, I40E_PRTTSYN_INC_H, incval >> 32); | ||
437 | |||
438 | /* Update the base adjustement value. */ | ||
439 | ACCESS_ONCE(pf->ptp_base_adj) = incval; | ||
440 | smp_mb(); /* Force the above update. */ | ||
441 | } | ||
442 | |||
443 | /** | ||
444 | * i40e_ptp_get_ts_config - ioctl interface to read the HW timestamping | ||
445 | * @pf: Board private structure | ||
446 | * @ifreq: ioctl data | ||
447 | * | ||
448 | * Obtain the current hardware timestamping settigs as requested. To do this, | ||
449 | * keep a shadow copy of the timestamp settings rather than attempting to | ||
450 | * deconstruct it from the registers. | ||
451 | **/ | ||
452 | int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr) | ||
453 | { | ||
454 | struct hwtstamp_config *config = &pf->tstamp_config; | ||
455 | |||
456 | return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? | ||
457 | -EFAULT : 0; | ||
458 | } | ||
459 | |||
460 | /** | ||
461 | * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping | ||
462 | * @pf: Board private structure | ||
463 | * @ifreq: ioctl data | ||
464 | * | ||
465 | * Respond to the user filter requests and make the appropriate hardware | ||
466 | * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping | ||
467 | * logic, so keep track in software of whether to indicate these timestamps | ||
468 | * or not. | ||
469 | * | ||
470 | * It is permissible to "upgrade" the user request to a broader filter, as long | ||
471 | * as the user receives the timestamps they care about and the user is notified | ||
472 | * the filter has been broadened. | ||
473 | **/ | ||
474 | int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) | ||
475 | { | ||
476 | struct i40e_hw *hw = &pf->hw; | ||
477 | struct hwtstamp_config *config = &pf->tstamp_config; | ||
478 | u32 pf_id, tsyntype, regval; | ||
479 | |||
480 | if (copy_from_user(config, ifr->ifr_data, sizeof(*config))) | ||
481 | return -EFAULT; | ||
482 | |||
483 | /* Reserved for future extensions. */ | ||
484 | if (config->flags) | ||
485 | return -EINVAL; | ||
486 | |||
487 | /* Confirm that 1588 is supported on this PF. */ | ||
488 | pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >> | ||
489 | I40E_PRTTSYN_CTL0_PF_ID_SHIFT; | ||
490 | if (hw->pf_id != pf_id) | ||
491 | return -EINVAL; | ||
492 | |||
493 | switch (config->tx_type) { | ||
494 | case HWTSTAMP_TX_OFF: | ||
495 | pf->ptp_tx = false; | ||
496 | break; | ||
497 | case HWTSTAMP_TX_ON: | ||
498 | pf->ptp_tx = true; | ||
499 | break; | ||
500 | default: | ||
501 | return -ERANGE; | ||
502 | } | ||
503 | |||
504 | switch (config->rx_filter) { | ||
505 | case HWTSTAMP_FILTER_NONE: | ||
506 | pf->ptp_rx = false; | ||
507 | tsyntype = 0; | ||
508 | break; | ||
509 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | ||
510 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | ||
511 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | ||
512 | pf->ptp_rx = true; | ||
513 | tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK | | ||
514 | I40E_PRTTSYN_CTL1_TSYNTYPE_V1 | | ||
515 | I40E_PRTTSYN_CTL1_UDP_ENA_MASK; | ||
516 | config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; | ||
517 | break; | ||
518 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | ||
519 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | ||
520 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | ||
521 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | ||
522 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | ||
523 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | ||
524 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | ||
525 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | ||
526 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | ||
527 | pf->ptp_rx = true; | ||
528 | tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK | | ||
529 | I40E_PRTTSYN_CTL1_TSYNTYPE_V2 | | ||
530 | I40E_PRTTSYN_CTL1_UDP_ENA_MASK; | ||
531 | config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; | ||
532 | break; | ||
533 | case HWTSTAMP_FILTER_ALL: | ||
534 | default: | ||
535 | return -ERANGE; | ||
536 | } | ||
537 | |||
538 | /* Clear out all 1588-related registers to clear and unlatch them. */ | ||
539 | rd32(hw, I40E_PRTTSYN_STAT_0); | ||
540 | rd32(hw, I40E_PRTTSYN_TXTIME_H); | ||
541 | rd32(hw, I40E_PRTTSYN_RXTIME_H(0)); | ||
542 | rd32(hw, I40E_PRTTSYN_RXTIME_H(1)); | ||
543 | rd32(hw, I40E_PRTTSYN_RXTIME_H(2)); | ||
544 | rd32(hw, I40E_PRTTSYN_RXTIME_H(3)); | ||
545 | |||
546 | /* Enable/disable the Tx timestamp interrupt based on user input. */ | ||
547 | regval = rd32(hw, I40E_PRTTSYN_CTL0); | ||
548 | if (pf->ptp_tx) | ||
549 | regval |= I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK; | ||
550 | else | ||
551 | regval &= ~I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK; | ||
552 | wr32(hw, I40E_PRTTSYN_CTL0, regval); | ||
553 | |||
554 | regval = rd32(hw, I40E_PFINT_ICR0_ENA); | ||
555 | if (pf->ptp_tx) | ||
556 | regval |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; | ||
557 | else | ||
558 | regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; | ||
559 | wr32(hw, I40E_PFINT_ICR0_ENA, regval); | ||
560 | |||
561 | /* There is no simple on/off switch for Rx. To "disable" Rx support, | ||
562 | * ignore any received timestamps, rather than turn off the clock. | ||
563 | */ | ||
564 | if (pf->ptp_rx) { | ||
565 | regval = rd32(hw, I40E_PRTTSYN_CTL1); | ||
566 | /* clear everything but the enable bit */ | ||
567 | regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK; | ||
568 | /* now enable bits for desired Rx timestamps */ | ||
569 | regval |= tsyntype; | ||
570 | wr32(hw, I40E_PRTTSYN_CTL1, regval); | ||
571 | } | ||
572 | |||
573 | return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? | ||
574 | -EFAULT : 0; | ||
575 | } | ||
576 | |||
577 | /** | ||
578 | * i40e_ptp_init - Initialize the 1588 support and register the PHC | ||
579 | * @pf: Board private structure | ||
580 | * | ||
581 | * This function registers the device clock as a PHC. If it is successful, it | ||
582 | * starts the clock in the hardware. | ||
583 | **/ | ||
584 | void i40e_ptp_init(struct i40e_pf *pf) | ||
585 | { | ||
586 | struct i40e_hw *hw = &pf->hw; | ||
587 | struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; | ||
588 | |||
589 | strncpy(pf->ptp_caps.name, "i40e", sizeof(pf->ptp_caps.name)); | ||
590 | pf->ptp_caps.owner = THIS_MODULE; | ||
591 | pf->ptp_caps.max_adj = 999999999; | ||
592 | pf->ptp_caps.n_ext_ts = 0; | ||
593 | pf->ptp_caps.pps = 0; | ||
594 | pf->ptp_caps.adjfreq = i40e_ptp_adjfreq; | ||
595 | pf->ptp_caps.adjtime = i40e_ptp_adjtime; | ||
596 | pf->ptp_caps.gettime = i40e_ptp_gettime; | ||
597 | pf->ptp_caps.settime = i40e_ptp_settime; | ||
598 | pf->ptp_caps.enable = i40e_ptp_enable; | ||
599 | |||
600 | /* Attempt to register the clock before enabling the hardware. */ | ||
601 | pf->ptp_clock = ptp_clock_register(&pf->ptp_caps, &pf->pdev->dev); | ||
602 | if (IS_ERR(pf->ptp_clock)) { | ||
603 | pf->ptp_clock = NULL; | ||
604 | dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n", | ||
605 | __func__); | ||
606 | } else { | ||
607 | struct timespec ts; | ||
608 | u32 regval; | ||
609 | |||
610 | spin_lock_init(&pf->tmreg_lock); | ||
611 | INIT_WORK(&pf->ptp_tx_work, i40e_ptp_tx_work); | ||
612 | |||
613 | dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__, | ||
614 | netdev->name); | ||
615 | pf->flags |= I40E_FLAG_PTP; | ||
616 | |||
617 | /* Ensure the clocks are running. */ | ||
618 | regval = rd32(hw, I40E_PRTTSYN_CTL0); | ||
619 | regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK; | ||
620 | wr32(hw, I40E_PRTTSYN_CTL0, regval); | ||
621 | regval = rd32(hw, I40E_PRTTSYN_CTL1); | ||
622 | regval |= I40E_PRTTSYN_CTL1_TSYNENA_MASK; | ||
623 | wr32(hw, I40E_PRTTSYN_CTL1, regval); | ||
624 | |||
625 | /* Set the increment value per clock tick. */ | ||
626 | i40e_ptp_set_increment(pf); | ||
627 | |||
628 | /* reset the tstamp_config */ | ||
629 | memset(&pf->tstamp_config, 0, sizeof(pf->tstamp_config)); | ||
630 | |||
631 | /* Set the clock value. */ | ||
632 | ts = ktime_to_timespec(ktime_get_real()); | ||
633 | i40e_ptp_settime(&pf->ptp_caps, &ts); | ||
634 | } | ||
635 | } | ||
636 | |||
637 | /** | ||
638 | * i40e_ptp_stop - Disable the driver/hardware support and unregister the PHC | ||
639 | * @pf: Board private structure | ||
640 | * | ||
641 | * This function handles the cleanup work required from the initialization by | ||
642 | * clearing out the important information and unregistering the PHC. | ||
643 | **/ | ||
644 | void i40e_ptp_stop(struct i40e_pf *pf) | ||
645 | { | ||
646 | pf->flags &= ~I40E_FLAG_PTP; | ||
647 | pf->ptp_tx = false; | ||
648 | pf->ptp_rx = false; | ||
649 | |||
650 | cancel_work_sync(&pf->ptp_tx_work); | ||
651 | if (pf->ptp_tx_skb) { | ||
652 | dev_kfree_skb_any(pf->ptp_tx_skb); | ||
653 | pf->ptp_tx_skb = NULL; | ||
654 | } | ||
655 | |||
656 | if (pf->ptp_clock) { | ||
657 | ptp_clock_unregister(pf->ptp_clock); | ||
658 | pf->ptp_clock = NULL; | ||
659 | dev_info(&pf->pdev->dev, "%s: removed PHC on %s\n", __func__, | ||
660 | pf->vsi[pf->lan_vsi]->netdev->name); | ||
661 | } | ||
662 | } | ||
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 946d8b1d9a4d..a089ac19cfe9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c | |||
@@ -1088,6 +1088,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) | |||
1088 | } | 1088 | } |
1089 | 1089 | ||
1090 | skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); | 1090 | skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); |
1091 | if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) { | ||
1092 | i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status & | ||
1093 | I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >> | ||
1094 | I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT); | ||
1095 | rx_ring->last_rx_timestamp = jiffies; | ||
1096 | } | ||
1097 | |||
1091 | /* probably a little skewed due to removing CRC */ | 1098 | /* probably a little skewed due to removing CRC */ |
1092 | total_rx_bytes += skb->len; | 1099 | total_rx_bytes += skb->len; |
1093 | total_rx_packets++; | 1100 | total_rx_packets++; |
@@ -1426,6 +1433,46 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb, | |||
1426 | } | 1433 | } |
1427 | 1434 | ||
1428 | /** | 1435 | /** |
1436 | * i40e_tsyn - set up the tsyn context descriptor | ||
1437 | * @tx_ring: ptr to the ring to send | ||
1438 | * @skb: ptr to the skb we're sending | ||
1439 | * @tx_flags: the collected send information | ||
1440 | * | ||
1441 | * Returns 0 if no Tx timestamp can happen and 1 if the timestamp will happen | ||
1442 | **/ | ||
1443 | static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, | ||
1444 | u32 tx_flags, u64 *cd_type_cmd_tso_mss) | ||
1445 | { | ||
1446 | struct i40e_pf *pf; | ||
1447 | |||
1448 | if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) | ||
1449 | return 0; | ||
1450 | |||
1451 | /* Tx timestamps cannot be sampled when doing TSO */ | ||
1452 | if (tx_flags & I40E_TX_FLAGS_TSO) | ||
1453 | return 0; | ||
1454 | |||
1455 | /* only timestamp the outbound packet if the user has requested it and | ||
1456 | * we are not already transmitting a packet to be timestamped | ||
1457 | */ | ||
1458 | pf = i40e_netdev_to_pf(tx_ring->netdev); | ||
1459 | if (pf->ptp_tx && !pf->ptp_tx_skb) { | ||
1460 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; | ||
1461 | pf->ptp_tx_skb = skb_get(skb); | ||
1462 | } else { | ||
1463 | return 0; | ||
1464 | } | ||
1465 | |||
1466 | *cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN << | ||
1467 | I40E_TXD_CTX_QW1_CMD_SHIFT; | ||
1468 | |||
1469 | pf->ptp_tx_start = jiffies; | ||
1470 | schedule_work(&pf->ptp_tx_work); | ||
1471 | |||
1472 | return 1; | ||
1473 | } | ||
1474 | |||
1475 | /** | ||
1429 | * i40e_tx_enable_csum - Enable Tx checksum offloads | 1476 | * i40e_tx_enable_csum - Enable Tx checksum offloads |
1430 | * @skb: send buffer | 1477 | * @skb: send buffer |
1431 | * @tx_flags: Tx flags currently set | 1478 | * @tx_flags: Tx flags currently set |
@@ -1801,6 +1848,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, | |||
1801 | __be16 protocol; | 1848 | __be16 protocol; |
1802 | u32 td_cmd = 0; | 1849 | u32 td_cmd = 0; |
1803 | u8 hdr_len = 0; | 1850 | u8 hdr_len = 0; |
1851 | int tsyn; | ||
1804 | int tso; | 1852 | int tso; |
1805 | if (0 == i40e_xmit_descriptor_count(skb, tx_ring)) | 1853 | if (0 == i40e_xmit_descriptor_count(skb, tx_ring)) |
1806 | return NETDEV_TX_BUSY; | 1854 | return NETDEV_TX_BUSY; |
@@ -1831,6 +1879,11 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, | |||
1831 | 1879 | ||
1832 | skb_tx_timestamp(skb); | 1880 | skb_tx_timestamp(skb); |
1833 | 1881 | ||
1882 | tsyn = i40e_tsyn(tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss); | ||
1883 | |||
1884 | if (tsyn) | ||
1885 | tx_flags |= I40E_TX_FLAGS_TSYN; | ||
1886 | |||
1834 | /* always enable CRC insertion offload */ | 1887 | /* always enable CRC insertion offload */ |
1835 | td_cmd |= I40E_TX_DESC_CMD_ICRC; | 1888 | td_cmd |= I40E_TX_DESC_CMD_ICRC; |
1836 | 1889 | ||
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 93b8642d77cd..d5349698e513 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h | |||
@@ -136,6 +136,7 @@ enum i40e_dyn_idx_t { | |||
136 | #define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) | 136 | #define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) |
137 | #define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) | 137 | #define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) |
138 | #define I40E_TX_FLAGS_FSO (u32)(1 << 7) | 138 | #define I40E_TX_FLAGS_FSO (u32)(1 << 7) |
139 | #define I40E_TX_FLAGS_TSYN (u32)(1 << 8) | ||
139 | #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 | 140 | #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 |
140 | #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 | 141 | #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 |
141 | #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 | 142 | #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 |
@@ -248,6 +249,8 @@ struct i40e_ring { | |||
248 | u8 atr_sample_rate; | 249 | u8 atr_sample_rate; |
249 | u8 atr_count; | 250 | u8 atr_count; |
250 | 251 | ||
252 | unsigned long last_rx_timestamp; | ||
253 | |||
251 | bool ring_active; /* is ring online or not */ | 254 | bool ring_active; /* is ring online or not */ |
252 | 255 | ||
253 | /* stats structs */ | 256 | /* stats structs */ |