diff options
author | Stuart Hodgson <smhodgson@solarflare.com> | 2012-09-03 06:09:36 -0400 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-09-18 21:54:12 -0400 |
commit | 7c236c43b838221e17220bcb39e8e8d8c7123713 (patch) | |
tree | 4ef6fa19edafeddf8280c5086624ae430125be91 | |
parent | 576eda8b08e00cbb0cf29ba777c2cb461c98cbbc (diff) |
sfc: Add support for IEEE-1588 PTP
Add PTP IEEE-1588 support and make accesible via the PHC subsystem.
This work is based on prior code by Andrew Jackson
Signed-off-by: Stuart Hodgson <smhodgson@solarflare.com>
[bwh:
- Add byte order conversion in efx_ptp_send_times()
- Simplify conversion of PPS event times
- Add the built-in vs module check to CONFIG_SFC_PTP dependencies]
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r-- | drivers/net/ethernet/sfc/Kconfig | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ethtool.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi_pcol.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 19 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 36 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ptp.c | 1483 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/siena.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/tx.c | 6 |
11 files changed, 1562 insertions, 1 deletions
diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig index fb3cbc27063c..25906c1d1b15 100644 --- a/drivers/net/ethernet/sfc/Kconfig +++ b/drivers/net/ethernet/sfc/Kconfig | |||
@@ -34,3 +34,10 @@ config SFC_SRIOV | |||
34 | This enables support for the SFC9000 I/O Virtualization | 34 | This enables support for the SFC9000 I/O Virtualization |
35 | features, allowing accelerated network performance in | 35 | features, allowing accelerated network performance in |
36 | virtualized environments. | 36 | virtualized environments. |
37 | config SFC_PTP | ||
38 | bool "Solarflare SFC9000-family PTP support" | ||
39 | depends on SFC && PTP_1588_CLOCK && !(SFC=y && PTP_1588_CLOCK=m) | ||
40 | default y | ||
41 | ---help--- | ||
42 | This enables support for the Precision Time Protocol (PTP) | ||
43 | on SFC9000-family NICs | ||
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile index ea1f8db57318..e11f2ecf69d9 100644 --- a/drivers/net/ethernet/sfc/Makefile +++ b/drivers/net/ethernet/sfc/Makefile | |||
@@ -5,5 +5,6 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \ | |||
5 | mcdi.o mcdi_phy.o mcdi_mon.o | 5 | mcdi.o mcdi_phy.o mcdi_mon.o |
6 | sfc-$(CONFIG_SFC_MTD) += mtd.o | 6 | sfc-$(CONFIG_SFC_MTD) += mtd.o |
7 | sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o | 7 | sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o |
8 | sfc-$(CONFIG_SFC_PTP) += ptp.o | ||
8 | 9 | ||
9 | obj-$(CONFIG_SFC) += sfc.o | 10 | obj-$(CONFIG_SFC) += sfc.o |
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 8b79a6413fe4..96bd980e828d 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -1779,6 +1779,9 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) | |||
1779 | struct efx_nic *efx = netdev_priv(net_dev); | 1779 | struct efx_nic *efx = netdev_priv(net_dev); |
1780 | struct mii_ioctl_data *data = if_mii(ifr); | 1780 | struct mii_ioctl_data *data = if_mii(ifr); |
1781 | 1781 | ||
1782 | if (cmd == SIOCSHWTSTAMP) | ||
1783 | return efx_ptp_ioctl(efx, ifr, cmd); | ||
1784 | |||
1782 | /* Convert phy_id from older PRTAD/DEVAD format */ | 1785 | /* Convert phy_id from older PRTAD/DEVAD format */ |
1783 | if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && | 1786 | if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && |
1784 | (data->phy_id & 0xfc00) == 0x0400) | 1787 | (data->phy_id & 0xfc00) == 0x0400) |
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index f8e7e204981f..9df556c01b8e 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c | |||
@@ -1174,6 +1174,7 @@ const struct ethtool_ops efx_ethtool_ops = { | |||
1174 | .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, | 1174 | .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, |
1175 | .get_rxfh_indir = efx_ethtool_get_rxfh_indir, | 1175 | .get_rxfh_indir = efx_ethtool_get_rxfh_indir, |
1176 | .set_rxfh_indir = efx_ethtool_set_rxfh_indir, | 1176 | .set_rxfh_indir = efx_ethtool_set_rxfh_indir, |
1177 | .get_ts_info = efx_ptp_get_ts_info, | ||
1177 | .get_module_info = efx_ethtool_get_module_info, | 1178 | .get_module_info = efx_ethtool_get_module_info, |
1178 | .get_module_eeprom = efx_ethtool_get_module_eeprom, | 1179 | .get_module_eeprom = efx_ethtool_get_module_eeprom, |
1179 | }; | 1180 | }; |
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 2707e86def9e..294df4bca4a6 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c | |||
@@ -578,6 +578,11 @@ void efx_mcdi_process_event(struct efx_channel *channel, | |||
578 | case MCDI_EVENT_CODE_FLR: | 578 | case MCDI_EVENT_CODE_FLR: |
579 | efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF)); | 579 | efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF)); |
580 | break; | 580 | break; |
581 | case MCDI_EVENT_CODE_PTP_RX: | ||
582 | case MCDI_EVENT_CODE_PTP_FAULT: | ||
583 | case MCDI_EVENT_CODE_PTP_PPS: | ||
584 | efx_ptp_event(efx, event); | ||
585 | break; | ||
581 | 586 | ||
582 | default: | 587 | default: |
583 | netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n", | 588 | netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n", |
diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h index 50389326bec8..9d426d0457bd 100644 --- a/drivers/net/ethernet/sfc/mcdi_pcol.h +++ b/drivers/net/ethernet/sfc/mcdi_pcol.h | |||
@@ -289,6 +289,7 @@ | |||
289 | #define MCDI_EVENT_CODE_TX_FLUSH 0xc /* enum */ | 289 | #define MCDI_EVENT_CODE_TX_FLUSH 0xc /* enum */ |
290 | #define MCDI_EVENT_CODE_PTP_RX 0xd /* enum */ | 290 | #define MCDI_EVENT_CODE_PTP_RX 0xd /* enum */ |
291 | #define MCDI_EVENT_CODE_PTP_FAULT 0xe /* enum */ | 291 | #define MCDI_EVENT_CODE_PTP_FAULT 0xe /* enum */ |
292 | #define MCDI_EVENT_CODE_PTP_PPS 0xf /* enum */ | ||
292 | #define MCDI_EVENT_CMDDONE_DATA_OFST 0 | 293 | #define MCDI_EVENT_CMDDONE_DATA_OFST 0 |
293 | #define MCDI_EVENT_CMDDONE_DATA_LBN 0 | 294 | #define MCDI_EVENT_CMDDONE_DATA_LBN 0 |
294 | #define MCDI_EVENT_CMDDONE_DATA_WIDTH 32 | 295 | #define MCDI_EVENT_CMDDONE_DATA_WIDTH 32 |
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 0f0926e68963..797dbed25d94 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h | |||
@@ -56,7 +56,8 @@ | |||
56 | #define EFX_MAX_CHANNELS 32U | 56 | #define EFX_MAX_CHANNELS 32U |
57 | #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS | 57 | #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS |
58 | #define EFX_EXTRA_CHANNEL_IOV 0 | 58 | #define EFX_EXTRA_CHANNEL_IOV 0 |
59 | #define EFX_MAX_EXTRA_CHANNELS 1U | 59 | #define EFX_EXTRA_CHANNEL_PTP 1 |
60 | #define EFX_MAX_EXTRA_CHANNELS 2U | ||
60 | 61 | ||
61 | /* Checksum generation is a per-queue option in hardware, so each | 62 | /* Checksum generation is a per-queue option in hardware, so each |
62 | * queue visible to the networking core is backed by two hardware TX | 63 | * queue visible to the networking core is backed by two hardware TX |
@@ -68,6 +69,9 @@ | |||
68 | #define EFX_TXQ_TYPES 4 | 69 | #define EFX_TXQ_TYPES 4 |
69 | #define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS) | 70 | #define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS) |
70 | 71 | ||
72 | /* Forward declare Precision Time Protocol (PTP) support structure. */ | ||
73 | struct efx_ptp_data; | ||
74 | |||
71 | struct efx_self_tests; | 75 | struct efx_self_tests; |
72 | 76 | ||
73 | /** | 77 | /** |
@@ -736,6 +740,7 @@ struct vfdi_status; | |||
736 | * %local_addr_list. Protected by %local_lock. | 740 | * %local_addr_list. Protected by %local_lock. |
737 | * @local_lock: Mutex protecting %local_addr_list and %local_page_list. | 741 | * @local_lock: Mutex protecting %local_addr_list and %local_page_list. |
738 | * @peer_work: Work item to broadcast peer addresses to VMs. | 742 | * @peer_work: Work item to broadcast peer addresses to VMs. |
743 | * @ptp_data: PTP state data | ||
739 | * @monitor_work: Hardware monitor workitem | 744 | * @monitor_work: Hardware monitor workitem |
740 | * @biu_lock: BIU (bus interface unit) lock | 745 | * @biu_lock: BIU (bus interface unit) lock |
741 | * @last_irq_cpu: Last CPU to handle a possible test interrupt. This | 746 | * @last_irq_cpu: Last CPU to handle a possible test interrupt. This |
@@ -863,6 +868,10 @@ struct efx_nic { | |||
863 | struct work_struct peer_work; | 868 | struct work_struct peer_work; |
864 | #endif | 869 | #endif |
865 | 870 | ||
871 | #ifdef CONFIG_SFC_PTP | ||
872 | struct efx_ptp_data *ptp_data; | ||
873 | #endif | ||
874 | |||
866 | /* The following fields may be written more often */ | 875 | /* The following fields may be written more often */ |
867 | 876 | ||
868 | struct delayed_work monitor_work ____cacheline_aligned_in_smp; | 877 | struct delayed_work monitor_work ____cacheline_aligned_in_smp; |
@@ -1125,5 +1134,13 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr) | |||
1125 | #define EFX_MAX_FRAME_LEN(mtu) \ | 1134 | #define EFX_MAX_FRAME_LEN(mtu) \ |
1126 | ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */ + 7) & ~7) + 16) | 1135 | ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */ + 7) & ~7) + 16) |
1127 | 1136 | ||
1137 | static inline bool efx_xmit_with_hwtstamp(struct sk_buff *skb) | ||
1138 | { | ||
1139 | return skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP; | ||
1140 | } | ||
1141 | static inline void efx_xmit_hwtstamp_pending(struct sk_buff *skb) | ||
1142 | { | ||
1143 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; | ||
1144 | } | ||
1128 | 1145 | ||
1129 | #endif /* EFX_NET_DRIVER_H */ | 1146 | #endif /* EFX_NET_DRIVER_H */ |
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index bab5cd9f5740..438cef11f727 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #ifndef EFX_NIC_H | 11 | #ifndef EFX_NIC_H |
12 | #define EFX_NIC_H | 12 | #define EFX_NIC_H |
13 | 13 | ||
14 | #include <linux/net_tstamp.h> | ||
14 | #include <linux/i2c-algo-bit.h> | 15 | #include <linux/i2c-algo-bit.h> |
15 | #include "net_driver.h" | 16 | #include "net_driver.h" |
16 | #include "efx.h" | 17 | #include "efx.h" |
@@ -250,6 +251,41 @@ extern int efx_sriov_get_vf_config(struct net_device *dev, int vf, | |||
250 | extern int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf, | 251 | extern int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf, |
251 | bool spoofchk); | 252 | bool spoofchk); |
252 | 253 | ||
254 | struct ethtool_ts_info; | ||
255 | #ifdef CONFIG_SFC_PTP | ||
256 | extern void efx_ptp_probe(struct efx_nic *efx); | ||
257 | extern int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd); | ||
258 | extern int efx_ptp_get_ts_info(struct net_device *net_dev, | ||
259 | struct ethtool_ts_info *ts_info); | ||
260 | extern bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); | ||
261 | extern int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); | ||
262 | extern void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev); | ||
263 | #else | ||
264 | static inline void efx_ptp_probe(struct efx_nic *efx) {} | ||
265 | static inline int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd) | ||
266 | { | ||
267 | return -EOPNOTSUPP; | ||
268 | } | ||
269 | static inline int efx_ptp_get_ts_info(struct net_device *net_dev, | ||
270 | struct ethtool_ts_info *ts_info) | ||
271 | { | ||
272 | ts_info->so_timestamping = (SOF_TIMESTAMPING_SOFTWARE | | ||
273 | SOF_TIMESTAMPING_RX_SOFTWARE); | ||
274 | ts_info->phc_index = -1; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | static inline bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb) | ||
279 | { | ||
280 | return false; | ||
281 | } | ||
282 | static inline int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb) | ||
283 | { | ||
284 | return NETDEV_TX_OK; | ||
285 | } | ||
286 | static inline void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev) {} | ||
287 | #endif | ||
288 | |||
253 | extern const struct efx_nic_type falcon_a1_nic_type; | 289 | extern const struct efx_nic_type falcon_a1_nic_type; |
254 | extern const struct efx_nic_type falcon_b0_nic_type; | 290 | extern const struct efx_nic_type falcon_b0_nic_type; |
255 | extern const struct efx_nic_type siena_a0_nic_type; | 291 | extern const struct efx_nic_type siena_a0_nic_type; |
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c new file mode 100644 index 000000000000..2b07a4eae07e --- /dev/null +++ b/drivers/net/ethernet/sfc/ptp.c | |||
@@ -0,0 +1,1483 @@ | |||
1 | /**************************************************************************** | ||
2 | * Driver for Solarflare Solarstorm network controllers and boards | ||
3 | * Copyright 2011 Solarflare Communications Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published | ||
7 | * by the Free Software Foundation, incorporated herein by reference. | ||
8 | */ | ||
9 | |||
10 | /* Theory of operation: | ||
11 | * | ||
12 | * PTP support is assisted by firmware running on the MC, which provides | ||
13 | * the hardware timestamping capabilities. Both transmitted and received | ||
14 | * PTP event packets are queued onto internal queues for subsequent processing; | ||
15 | * this is because the MC operations are relatively long and would block | ||
16 | * block NAPI/interrupt operation. | ||
17 | * | ||
18 | * Receive event processing: | ||
19 | * The event contains the packet's UUID and sequence number, together | ||
20 | * with the hardware timestamp. The PTP receive packet queue is searched | ||
21 | * for this UUID/sequence number and, if found, put on a pending queue. | ||
22 | * Packets not matching are delivered without timestamps (MCDI events will | ||
23 | * always arrive after the actual packet). | ||
24 | * It is important for the operation of the PTP protocol that the ordering | ||
25 | * of packets between the event and general port is maintained. | ||
26 | * | ||
27 | * Work queue processing: | ||
28 | * If work waiting, synchronise host/hardware time | ||
29 | * | ||
30 | * Transmit: send packet through MC, which returns the transmission time | ||
31 | * that is converted to an appropriate timestamp. | ||
32 | * | ||
33 | * Receive: the packet's reception time is converted to an appropriate | ||
34 | * timestamp. | ||
35 | */ | ||
36 | #include <linux/ip.h> | ||
37 | #include <linux/udp.h> | ||
38 | #include <linux/time.h> | ||
39 | #include <linux/ktime.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/net_tstamp.h> | ||
42 | #include <linux/pps_kernel.h> | ||
43 | #include <linux/ptp_clock_kernel.h> | ||
44 | #include "net_driver.h" | ||
45 | #include "efx.h" | ||
46 | #include "mcdi.h" | ||
47 | #include "mcdi_pcol.h" | ||
48 | #include "io.h" | ||
49 | #include "regs.h" | ||
50 | #include "nic.h" | ||
51 | |||
52 | /* Maximum number of events expected to make up a PTP event */ | ||
53 | #define MAX_EVENT_FRAGS 3 | ||
54 | |||
55 | /* Maximum delay, ms, to begin synchronisation */ | ||
56 | #define MAX_SYNCHRONISE_WAIT_MS 2 | ||
57 | |||
58 | /* How long, at most, to spend synchronising */ | ||
59 | #define SYNCHRONISE_PERIOD_NS 250000 | ||
60 | |||
61 | /* How often to update the shared memory time */ | ||
62 | #define SYNCHRONISATION_GRANULARITY_NS 200 | ||
63 | |||
64 | /* Minimum permitted length of a (corrected) synchronisation time */ | ||
65 | #define MIN_SYNCHRONISATION_NS 120 | ||
66 | |||
67 | /* Maximum permitted length of a (corrected) synchronisation time */ | ||
68 | #define MAX_SYNCHRONISATION_NS 1000 | ||
69 | |||
70 | /* How many (MC) receive events that can be queued */ | ||
71 | #define MAX_RECEIVE_EVENTS 8 | ||
72 | |||
73 | /* Length of (modified) moving average. */ | ||
74 | #define AVERAGE_LENGTH 16 | ||
75 | |||
76 | /* How long an unmatched event or packet can be held */ | ||
77 | #define PKT_EVENT_LIFETIME_MS 10 | ||
78 | |||
79 | /* Offsets into PTP packet for identification. These offsets are from the | ||
80 | * start of the IP header, not the MAC header. Note that neither PTP V1 nor | ||
81 | * PTP V2 permit the use of IPV4 options. | ||
82 | */ | ||
83 | #define PTP_DPORT_OFFSET 22 | ||
84 | |||
85 | #define PTP_V1_VERSION_LENGTH 2 | ||
86 | #define PTP_V1_VERSION_OFFSET 28 | ||
87 | |||
88 | #define PTP_V1_UUID_LENGTH 6 | ||
89 | #define PTP_V1_UUID_OFFSET 50 | ||
90 | |||
91 | #define PTP_V1_SEQUENCE_LENGTH 2 | ||
92 | #define PTP_V1_SEQUENCE_OFFSET 58 | ||
93 | |||
94 | /* The minimum length of a PTP V1 packet for offsets, etc. to be valid: | ||
95 | * includes IP header. | ||
96 | */ | ||
97 | #define PTP_V1_MIN_LENGTH 64 | ||
98 | |||
99 | #define PTP_V2_VERSION_LENGTH 1 | ||
100 | #define PTP_V2_VERSION_OFFSET 29 | ||
101 | |||
102 | /* Although PTP V2 UUIDs are comprised a ClockIdentity (8) and PortNumber (2), | ||
103 | * the MC only captures the last six bytes of the clock identity. These values | ||
104 | * reflect those, not the ones used in the standard. The standard permits | ||
105 | * mapping of V1 UUIDs to V2 UUIDs with these same values. | ||
106 | */ | ||
107 | #define PTP_V2_MC_UUID_LENGTH 6 | ||
108 | #define PTP_V2_MC_UUID_OFFSET 50 | ||
109 | |||
110 | #define PTP_V2_SEQUENCE_LENGTH 2 | ||
111 | #define PTP_V2_SEQUENCE_OFFSET 58 | ||
112 | |||
113 | /* The minimum length of a PTP V2 packet for offsets, etc. to be valid: | ||
114 | * includes IP header. | ||
115 | */ | ||
116 | #define PTP_V2_MIN_LENGTH 63 | ||
117 | |||
118 | #define PTP_MIN_LENGTH 63 | ||
119 | |||
120 | #define PTP_ADDRESS 0xe0000181 /* 224.0.1.129 */ | ||
121 | #define PTP_EVENT_PORT 319 | ||
122 | #define PTP_GENERAL_PORT 320 | ||
123 | |||
124 | /* Annoyingly the format of the version numbers are different between | ||
125 | * versions 1 and 2 so it isn't possible to simply look for 1 or 2. | ||
126 | */ | ||
127 | #define PTP_VERSION_V1 1 | ||
128 | |||
129 | #define PTP_VERSION_V2 2 | ||
130 | #define PTP_VERSION_V2_MASK 0x0f | ||
131 | |||
132 | enum ptp_packet_state { | ||
133 | PTP_PACKET_STATE_UNMATCHED = 0, | ||
134 | PTP_PACKET_STATE_MATCHED, | ||
135 | PTP_PACKET_STATE_TIMED_OUT, | ||
136 | PTP_PACKET_STATE_MATCH_UNWANTED | ||
137 | }; | ||
138 | |||
139 | /* NIC synchronised with single word of time only comprising | ||
140 | * partial seconds and full nanoseconds: 10^9 ~ 2^30 so 2 bits for seconds. | ||
141 | */ | ||
142 | #define MC_NANOSECOND_BITS 30 | ||
143 | #define MC_NANOSECOND_MASK ((1 << MC_NANOSECOND_BITS) - 1) | ||
144 | #define MC_SECOND_MASK ((1 << (32 - MC_NANOSECOND_BITS)) - 1) | ||
145 | |||
146 | /* Maximum parts-per-billion adjustment that is acceptable */ | ||
147 | #define MAX_PPB 1000000 | ||
148 | |||
149 | /* Number of bits required to hold the above */ | ||
150 | #define MAX_PPB_BITS 20 | ||
151 | |||
152 | /* Number of extra bits allowed when calculating fractional ns. | ||
153 | * EXTRA_BITS + MC_CMD_PTP_IN_ADJUST_BITS + MAX_PPB_BITS should | ||
154 | * be less than 63. | ||
155 | */ | ||
156 | #define PPB_EXTRA_BITS 2 | ||
157 | |||
158 | /* Precalculate scale word to avoid long long division at runtime */ | ||
159 | #define PPB_SCALE_WORD ((1LL << (PPB_EXTRA_BITS + MC_CMD_PTP_IN_ADJUST_BITS +\ | ||
160 | MAX_PPB_BITS)) / 1000000000LL) | ||
161 | |||
162 | #define PTP_SYNC_ATTEMPTS 4 | ||
163 | |||
164 | /** | ||
165 | * struct efx_ptp_match - Matching structure, stored in sk_buff's cb area. | ||
166 | * @words: UUID and (partial) sequence number | ||
167 | * @expiry: Time after which the packet should be delivered irrespective of | ||
168 | * event arrival. | ||
169 | * @state: The state of the packet - whether it is ready for processing or | ||
170 | * whether that is of no interest. | ||
171 | */ | ||
172 | struct efx_ptp_match { | ||
173 | u32 words[DIV_ROUND_UP(PTP_V1_UUID_LENGTH, 4)]; | ||
174 | unsigned long expiry; | ||
175 | enum ptp_packet_state state; | ||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * struct efx_ptp_event_rx - A PTP receive event (from MC) | ||
180 | * @seq0: First part of (PTP) UUID | ||
181 | * @seq1: Second part of (PTP) UUID and sequence number | ||
182 | * @hwtimestamp: Event timestamp | ||
183 | */ | ||
184 | struct efx_ptp_event_rx { | ||
185 | struct list_head link; | ||
186 | u32 seq0; | ||
187 | u32 seq1; | ||
188 | ktime_t hwtimestamp; | ||
189 | unsigned long expiry; | ||
190 | }; | ||
191 | |||
192 | /** | ||
193 | * struct efx_ptp_timeset - Synchronisation between host and MC | ||
194 | * @host_start: Host time immediately before hardware timestamp taken | ||
195 | * @seconds: Hardware timestamp, seconds | ||
196 | * @nanoseconds: Hardware timestamp, nanoseconds | ||
197 | * @host_end: Host time immediately after hardware timestamp taken | ||
198 | * @waitns: Number of nanoseconds between hardware timestamp being read and | ||
199 | * host end time being seen | ||
200 | * @window: Difference of host_end and host_start | ||
201 | * @valid: Whether this timeset is valid | ||
202 | */ | ||
203 | struct efx_ptp_timeset { | ||
204 | u32 host_start; | ||
205 | u32 seconds; | ||
206 | u32 nanoseconds; | ||
207 | u32 host_end; | ||
208 | u32 waitns; | ||
209 | u32 window; /* Derived: end - start, allowing for wrap */ | ||
210 | }; | ||
211 | |||
212 | /** | ||
213 | * struct efx_ptp_data - Precision Time Protocol (PTP) state | ||
214 | * @channel: The PTP channel | ||
215 | * @rxq: Receive queue (awaiting timestamps) | ||
216 | * @txq: Transmit queue | ||
217 | * @evt_list: List of MC receive events awaiting packets | ||
218 | * @evt_free_list: List of free events | ||
219 | * @evt_lock: Lock for manipulating evt_list and evt_free_list | ||
220 | * @rx_evts: Instantiated events (on evt_list and evt_free_list) | ||
221 | * @workwq: Work queue for processing pending PTP operations | ||
222 | * @work: Work task | ||
223 | * @reset_required: A serious error has occurred and the PTP task needs to be | ||
224 | * reset (disable, enable). | ||
225 | * @rxfilter_event: Receive filter when operating | ||
226 | * @rxfilter_general: Receive filter when operating | ||
227 | * @config: Current timestamp configuration | ||
228 | * @enabled: PTP operation enabled | ||
229 | * @mode: Mode in which PTP operating (PTP version) | ||
230 | * @evt_frags: Partly assembled PTP events | ||
231 | * @evt_frag_idx: Current fragment number | ||
232 | * @evt_code: Last event code | ||
233 | * @start: Address at which MC indicates ready for synchronisation | ||
234 | * @host_time_pps: Host time at last PPS | ||
235 | * @last_sync_ns: Last number of nanoseconds between readings when synchronising | ||
236 | * @base_sync_ns: Number of nanoseconds for last synchronisation. | ||
237 | * @base_sync_valid: Whether base_sync_time is valid. | ||
238 | * @current_adjfreq: Current ppb adjustment. | ||
239 | * @phc_clock: Pointer to registered phc device | ||
240 | * @phc_clock_info: Registration structure for phc device | ||
241 | * @pps_work: pps work task for handling pps events | ||
242 | * @pps_workwq: pps work queue | ||
243 | * @nic_ts_enabled: Flag indicating if NIC generated TS events are handled | ||
244 | * @txbuf: Buffer for use when transmitting (PTP) packets to MC (avoids | ||
245 | * allocations in main data path). | ||
246 | * @debug_ptp_dir: PTP debugfs directory | ||
247 | * @missed_rx_sync: Number of packets received without syncrhonisation. | ||
248 | * @good_syncs: Number of successful synchronisations. | ||
249 | * @no_time_syncs: Number of synchronisations with no good times. | ||
250 | * @bad_sync_durations: Number of synchronisations with bad durations. | ||
251 | * @bad_syncs: Number of failed synchronisations. | ||
252 | * @last_sync_time: Number of nanoseconds for last synchronisation. | ||
253 | * @sync_timeouts: Number of synchronisation timeouts | ||
254 | * @fast_syncs: Number of synchronisations requiring short delay | ||
255 | * @min_sync_delta: Minimum time between event and synchronisation | ||
256 | * @max_sync_delta: Maximum time between event and synchronisation | ||
257 | * @average_sync_delta: Average time between event and synchronisation. | ||
258 | * Modified moving average. | ||
259 | * @last_sync_delta: Last time between event and synchronisation | ||
260 | * @mc_stats: Context value for MC statistics | ||
261 | * @timeset: Last set of synchronisation statistics. | ||
262 | */ | ||
263 | struct efx_ptp_data { | ||
264 | struct efx_channel *channel; | ||
265 | struct sk_buff_head rxq; | ||
266 | struct sk_buff_head txq; | ||
267 | struct list_head evt_list; | ||
268 | struct list_head evt_free_list; | ||
269 | spinlock_t evt_lock; | ||
270 | struct efx_ptp_event_rx rx_evts[MAX_RECEIVE_EVENTS]; | ||
271 | struct workqueue_struct *workwq; | ||
272 | struct work_struct work; | ||
273 | bool reset_required; | ||
274 | u32 rxfilter_event; | ||
275 | u32 rxfilter_general; | ||
276 | bool rxfilter_installed; | ||
277 | struct hwtstamp_config config; | ||
278 | bool enabled; | ||
279 | unsigned int mode; | ||
280 | efx_qword_t evt_frags[MAX_EVENT_FRAGS]; | ||
281 | int evt_frag_idx; | ||
282 | int evt_code; | ||
283 | struct efx_buffer start; | ||
284 | struct pps_event_time host_time_pps; | ||
285 | unsigned last_sync_ns; | ||
286 | unsigned base_sync_ns; | ||
287 | bool base_sync_valid; | ||
288 | s64 current_adjfreq; | ||
289 | struct ptp_clock *phc_clock; | ||
290 | struct ptp_clock_info phc_clock_info; | ||
291 | struct work_struct pps_work; | ||
292 | struct workqueue_struct *pps_workwq; | ||
293 | bool nic_ts_enabled; | ||
294 | u8 txbuf[ALIGN(MC_CMD_PTP_IN_TRANSMIT_LEN( | ||
295 | MC_CMD_PTP_IN_TRANSMIT_PACKET_MAXNUM), 4)]; | ||
296 | struct efx_ptp_timeset | ||
297 | timeset[MC_CMD_PTP_OUT_SYNCHRONIZE_TIMESET_MAXNUM]; | ||
298 | }; | ||
299 | |||
300 | static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta); | ||
301 | static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta); | ||
302 | static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts); | ||
303 | static int efx_phc_settime(struct ptp_clock_info *ptp, | ||
304 | const struct timespec *e_ts); | ||
305 | static int efx_phc_enable(struct ptp_clock_info *ptp, | ||
306 | struct ptp_clock_request *request, int on); | ||
307 | |||
308 | /* Enable MCDI PTP support. */ | ||
309 | static int efx_ptp_enable(struct efx_nic *efx) | ||
310 | { | ||
311 | u8 inbuf[MC_CMD_PTP_IN_ENABLE_LEN]; | ||
312 | |||
313 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ENABLE); | ||
314 | MCDI_SET_DWORD(inbuf, PTP_IN_ENABLE_QUEUE, | ||
315 | efx->ptp_data->channel->channel); | ||
316 | MCDI_SET_DWORD(inbuf, PTP_IN_ENABLE_MODE, efx->ptp_data->mode); | ||
317 | |||
318 | return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), | ||
319 | NULL, 0, NULL); | ||
320 | } | ||
321 | |||
322 | /* Disable MCDI PTP support. | ||
323 | * | ||
324 | * Note that this function should never rely on the presence of ptp_data - | ||
325 | * may be called before that exists. | ||
326 | */ | ||
327 | static int efx_ptp_disable(struct efx_nic *efx) | ||
328 | { | ||
329 | u8 inbuf[MC_CMD_PTP_IN_DISABLE_LEN]; | ||
330 | |||
331 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_DISABLE); | ||
332 | return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), | ||
333 | NULL, 0, NULL); | ||
334 | } | ||
335 | |||
336 | static void efx_ptp_deliver_rx_queue(struct sk_buff_head *q) | ||
337 | { | ||
338 | struct sk_buff *skb; | ||
339 | |||
340 | while ((skb = skb_dequeue(q))) { | ||
341 | local_bh_disable(); | ||
342 | netif_receive_skb(skb); | ||
343 | local_bh_enable(); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static void efx_ptp_handle_no_channel(struct efx_nic *efx) | ||
348 | { | ||
349 | netif_err(efx, drv, efx->net_dev, | ||
350 | "ERROR: PTP requires MSI-X and 1 additional interrupt" | ||
351 | "vector. PTP disabled\n"); | ||
352 | } | ||
353 | |||
354 | /* Repeatedly send the host time to the MC which will capture the hardware | ||
355 | * time. | ||
356 | */ | ||
357 | static void efx_ptp_send_times(struct efx_nic *efx, | ||
358 | struct pps_event_time *last_time) | ||
359 | { | ||
360 | struct pps_event_time now; | ||
361 | struct timespec limit; | ||
362 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
363 | struct timespec start; | ||
364 | int *mc_running = ptp->start.addr; | ||
365 | |||
366 | pps_get_ts(&now); | ||
367 | start = now.ts_real; | ||
368 | limit = now.ts_real; | ||
369 | timespec_add_ns(&limit, SYNCHRONISE_PERIOD_NS); | ||
370 | |||
371 | /* Write host time for specified period or until MC is done */ | ||
372 | while ((timespec_compare(&now.ts_real, &limit) < 0) && | ||
373 | ACCESS_ONCE(*mc_running)) { | ||
374 | struct timespec update_time; | ||
375 | unsigned int host_time; | ||
376 | |||
377 | /* Don't update continuously to avoid saturating the PCIe bus */ | ||
378 | update_time = now.ts_real; | ||
379 | timespec_add_ns(&update_time, SYNCHRONISATION_GRANULARITY_NS); | ||
380 | do { | ||
381 | pps_get_ts(&now); | ||
382 | } while ((timespec_compare(&now.ts_real, &update_time) < 0) && | ||
383 | ACCESS_ONCE(*mc_running)); | ||
384 | |||
385 | /* Synchronise NIC with single word of time only */ | ||
386 | host_time = (now.ts_real.tv_sec << MC_NANOSECOND_BITS | | ||
387 | now.ts_real.tv_nsec); | ||
388 | /* Update host time in NIC memory */ | ||
389 | _efx_writed(efx, cpu_to_le32(host_time), | ||
390 | FR_CZ_MC_TREG_SMEM + MC_SMEM_P0_PTP_TIME_OFST); | ||
391 | } | ||
392 | *last_time = now; | ||
393 | } | ||
394 | |||
395 | /* Read a timeset from the MC's results and partial process. */ | ||
396 | static void efx_ptp_read_timeset(u8 *data, struct efx_ptp_timeset *timeset) | ||
397 | { | ||
398 | unsigned start_ns, end_ns; | ||
399 | |||
400 | timeset->host_start = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_HOSTSTART); | ||
401 | timeset->seconds = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_SECONDS); | ||
402 | timeset->nanoseconds = MCDI_DWORD(data, | ||
403 | PTP_OUT_SYNCHRONIZE_NANOSECONDS); | ||
404 | timeset->host_end = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_HOSTEND), | ||
405 | timeset->waitns = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_WAITNS); | ||
406 | |||
407 | /* Ignore seconds */ | ||
408 | start_ns = timeset->host_start & MC_NANOSECOND_MASK; | ||
409 | end_ns = timeset->host_end & MC_NANOSECOND_MASK; | ||
410 | /* Allow for rollover */ | ||
411 | if (end_ns < start_ns) | ||
412 | end_ns += NSEC_PER_SEC; | ||
413 | /* Determine duration of operation */ | ||
414 | timeset->window = end_ns - start_ns; | ||
415 | } | ||
416 | |||
417 | /* Process times received from MC. | ||
418 | * | ||
419 | * Extract times from returned results, and establish the minimum value | ||
420 | * seen. The minimum value represents the "best" possible time and events | ||
421 | * too much greater than this are rejected - the machine is, perhaps, too | ||
422 | * busy. A number of readings are taken so that, hopefully, at least one good | ||
423 | * synchronisation will be seen in the results. | ||
424 | */ | ||
425 | static int efx_ptp_process_times(struct efx_nic *efx, u8 *synch_buf, | ||
426 | size_t response_length, | ||
427 | const struct pps_event_time *last_time) | ||
428 | { | ||
429 | unsigned number_readings = (response_length / | ||
430 | MC_CMD_PTP_OUT_SYNCHRONIZE_TIMESET_LEN); | ||
431 | unsigned i; | ||
432 | unsigned min; | ||
433 | unsigned min_set = 0; | ||
434 | unsigned total; | ||
435 | unsigned ngood = 0; | ||
436 | unsigned last_good = 0; | ||
437 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
438 | bool min_valid = false; | ||
439 | u32 last_sec; | ||
440 | u32 start_sec; | ||
441 | struct timespec delta; | ||
442 | |||
443 | if (number_readings == 0) | ||
444 | return -EAGAIN; | ||
445 | |||
446 | /* Find minimum value in this set of results, discarding clearly | ||
447 | * erroneous results. | ||
448 | */ | ||
449 | for (i = 0; i < number_readings; i++) { | ||
450 | efx_ptp_read_timeset(synch_buf, &ptp->timeset[i]); | ||
451 | synch_buf += MC_CMD_PTP_OUT_SYNCHRONIZE_TIMESET_LEN; | ||
452 | if (ptp->timeset[i].window > SYNCHRONISATION_GRANULARITY_NS) { | ||
453 | if (min_valid) { | ||
454 | if (ptp->timeset[i].window < min_set) | ||
455 | min_set = ptp->timeset[i].window; | ||
456 | } else { | ||
457 | min_valid = true; | ||
458 | min_set = ptp->timeset[i].window; | ||
459 | } | ||
460 | } | ||
461 | } | ||
462 | |||
463 | if (min_valid) { | ||
464 | if (ptp->base_sync_valid && (min_set > ptp->base_sync_ns)) | ||
465 | min = ptp->base_sync_ns; | ||
466 | else | ||
467 | min = min_set; | ||
468 | } else { | ||
469 | min = SYNCHRONISATION_GRANULARITY_NS; | ||
470 | } | ||
471 | |||
472 | /* Discard excessively long synchronise durations. The MC times | ||
473 | * when it finishes reading the host time so the corrected window | ||
474 | * time should be fairly constant for a given platform. | ||
475 | */ | ||
476 | total = 0; | ||
477 | for (i = 0; i < number_readings; i++) | ||
478 | if (ptp->timeset[i].window > ptp->timeset[i].waitns) { | ||
479 | unsigned win; | ||
480 | |||
481 | win = ptp->timeset[i].window - ptp->timeset[i].waitns; | ||
482 | if (win >= MIN_SYNCHRONISATION_NS && | ||
483 | win < MAX_SYNCHRONISATION_NS) { | ||
484 | total += ptp->timeset[i].window; | ||
485 | ngood++; | ||
486 | last_good = i; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | if (ngood == 0) { | ||
491 | netif_warn(efx, drv, efx->net_dev, | ||
492 | "PTP no suitable synchronisations %dns %dns\n", | ||
493 | ptp->base_sync_ns, min_set); | ||
494 | return -EAGAIN; | ||
495 | } | ||
496 | |||
497 | /* Average minimum this synchronisation */ | ||
498 | ptp->last_sync_ns = DIV_ROUND_UP(total, ngood); | ||
499 | if (!ptp->base_sync_valid || (ptp->last_sync_ns < ptp->base_sync_ns)) { | ||
500 | ptp->base_sync_valid = true; | ||
501 | ptp->base_sync_ns = ptp->last_sync_ns; | ||
502 | } | ||
503 | |||
504 | /* Calculate delay from actual PPS to last_time */ | ||
505 | delta.tv_nsec = | ||
506 | ptp->timeset[last_good].nanoseconds + | ||
507 | last_time->ts_real.tv_nsec - | ||
508 | (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK); | ||
509 | |||
510 | /* It is possible that the seconds rolled over between taking | ||
511 | * the start reading and the last value written by the host. The | ||
512 | * timescales are such that a gap of more than one second is never | ||
513 | * expected. | ||
514 | */ | ||
515 | start_sec = ptp->timeset[last_good].host_start >> MC_NANOSECOND_BITS; | ||
516 | last_sec = last_time->ts_real.tv_sec & MC_SECOND_MASK; | ||
517 | if (start_sec != last_sec) { | ||
518 | if (((start_sec + 1) & MC_SECOND_MASK) != last_sec) { | ||
519 | netif_warn(efx, hw, efx->net_dev, | ||
520 | "PTP bad synchronisation seconds\n"); | ||
521 | return -EAGAIN; | ||
522 | } else { | ||
523 | delta.tv_sec = 1; | ||
524 | } | ||
525 | } else { | ||
526 | delta.tv_sec = 0; | ||
527 | } | ||
528 | |||
529 | ptp->host_time_pps = *last_time; | ||
530 | pps_sub_ts(&ptp->host_time_pps, delta); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* Synchronize times between the host and the MC */ | ||
536 | static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings) | ||
537 | { | ||
538 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
539 | u8 synch_buf[MC_CMD_PTP_OUT_SYNCHRONIZE_LENMAX]; | ||
540 | size_t response_length; | ||
541 | int rc; | ||
542 | unsigned long timeout; | ||
543 | struct pps_event_time last_time = {}; | ||
544 | unsigned int loops = 0; | ||
545 | int *start = ptp->start.addr; | ||
546 | |||
547 | MCDI_SET_DWORD(synch_buf, PTP_IN_OP, MC_CMD_PTP_OP_SYNCHRONIZE); | ||
548 | MCDI_SET_DWORD(synch_buf, PTP_IN_SYNCHRONIZE_NUMTIMESETS, | ||
549 | num_readings); | ||
550 | MCDI_SET_DWORD(synch_buf, PTP_IN_SYNCHRONIZE_START_ADDR_LO, | ||
551 | (u32)ptp->start.dma_addr); | ||
552 | MCDI_SET_DWORD(synch_buf, PTP_IN_SYNCHRONIZE_START_ADDR_HI, | ||
553 | (u32)((u64)ptp->start.dma_addr >> 32)); | ||
554 | |||
555 | /* Clear flag that signals MC ready */ | ||
556 | ACCESS_ONCE(*start) = 0; | ||
557 | efx_mcdi_rpc_start(efx, MC_CMD_PTP, synch_buf, | ||
558 | MC_CMD_PTP_IN_SYNCHRONIZE_LEN); | ||
559 | |||
560 | /* Wait for start from MCDI (or timeout) */ | ||
561 | timeout = jiffies + msecs_to_jiffies(MAX_SYNCHRONISE_WAIT_MS); | ||
562 | while (!ACCESS_ONCE(*start) && (time_before(jiffies, timeout))) { | ||
563 | udelay(20); /* Usually start MCDI execution quickly */ | ||
564 | loops++; | ||
565 | } | ||
566 | |||
567 | if (ACCESS_ONCE(*start)) | ||
568 | efx_ptp_send_times(efx, &last_time); | ||
569 | |||
570 | /* Collect results */ | ||
571 | rc = efx_mcdi_rpc_finish(efx, MC_CMD_PTP, | ||
572 | MC_CMD_PTP_IN_SYNCHRONIZE_LEN, | ||
573 | synch_buf, sizeof(synch_buf), | ||
574 | &response_length); | ||
575 | if (rc == 0) | ||
576 | rc = efx_ptp_process_times(efx, synch_buf, response_length, | ||
577 | &last_time); | ||
578 | |||
579 | return rc; | ||
580 | } | ||
581 | |||
582 | /* Transmit a PTP packet, via the MCDI interface, to the wire. */ | ||
583 | static int efx_ptp_xmit_skb(struct efx_nic *efx, struct sk_buff *skb) | ||
584 | { | ||
585 | u8 *txbuf = efx->ptp_data->txbuf; | ||
586 | struct skb_shared_hwtstamps timestamps; | ||
587 | int rc = -EIO; | ||
588 | /* MCDI driver requires word aligned lengths */ | ||
589 | size_t len = ALIGN(MC_CMD_PTP_IN_TRANSMIT_LEN(skb->len), 4); | ||
590 | u8 txtime[MC_CMD_PTP_OUT_TRANSMIT_LEN]; | ||
591 | |||
592 | MCDI_SET_DWORD(txbuf, PTP_IN_OP, MC_CMD_PTP_OP_TRANSMIT); | ||
593 | MCDI_SET_DWORD(txbuf, PTP_IN_TRANSMIT_LENGTH, skb->len); | ||
594 | if (skb_shinfo(skb)->nr_frags != 0) { | ||
595 | rc = skb_linearize(skb); | ||
596 | if (rc != 0) | ||
597 | goto fail; | ||
598 | } | ||
599 | |||
600 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
601 | rc = skb_checksum_help(skb); | ||
602 | if (rc != 0) | ||
603 | goto fail; | ||
604 | } | ||
605 | skb_copy_from_linear_data(skb, | ||
606 | &txbuf[MC_CMD_PTP_IN_TRANSMIT_PACKET_OFST], | ||
607 | len); | ||
608 | rc = efx_mcdi_rpc(efx, MC_CMD_PTP, txbuf, len, txtime, | ||
609 | sizeof(txtime), &len); | ||
610 | if (rc != 0) | ||
611 | goto fail; | ||
612 | |||
613 | memset(×tamps, 0, sizeof(timestamps)); | ||
614 | timestamps.hwtstamp = ktime_set( | ||
615 | MCDI_DWORD(txtime, PTP_OUT_TRANSMIT_SECONDS), | ||
616 | MCDI_DWORD(txtime, PTP_OUT_TRANSMIT_NANOSECONDS)); | ||
617 | |||
618 | skb_tstamp_tx(skb, ×tamps); | ||
619 | |||
620 | rc = 0; | ||
621 | |||
622 | fail: | ||
623 | dev_kfree_skb(skb); | ||
624 | |||
625 | return rc; | ||
626 | } | ||
627 | |||
628 | static void efx_ptp_drop_time_expired_events(struct efx_nic *efx) | ||
629 | { | ||
630 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
631 | struct list_head *cursor; | ||
632 | struct list_head *next; | ||
633 | |||
634 | /* Drop time-expired events */ | ||
635 | spin_lock_bh(&ptp->evt_lock); | ||
636 | if (!list_empty(&ptp->evt_list)) { | ||
637 | list_for_each_safe(cursor, next, &ptp->evt_list) { | ||
638 | struct efx_ptp_event_rx *evt; | ||
639 | |||
640 | evt = list_entry(cursor, struct efx_ptp_event_rx, | ||
641 | link); | ||
642 | if (time_after(jiffies, evt->expiry)) { | ||
643 | list_del(&evt->link); | ||
644 | list_add(&evt->link, &ptp->evt_free_list); | ||
645 | netif_warn(efx, hw, efx->net_dev, | ||
646 | "PTP rx event dropped\n"); | ||
647 | } | ||
648 | } | ||
649 | } | ||
650 | spin_unlock_bh(&ptp->evt_lock); | ||
651 | } | ||
652 | |||
653 | static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx, | ||
654 | struct sk_buff *skb) | ||
655 | { | ||
656 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
657 | bool evts_waiting; | ||
658 | struct list_head *cursor; | ||
659 | struct list_head *next; | ||
660 | struct efx_ptp_match *match; | ||
661 | enum ptp_packet_state rc = PTP_PACKET_STATE_UNMATCHED; | ||
662 | |||
663 | spin_lock_bh(&ptp->evt_lock); | ||
664 | evts_waiting = !list_empty(&ptp->evt_list); | ||
665 | spin_unlock_bh(&ptp->evt_lock); | ||
666 | |||
667 | if (!evts_waiting) | ||
668 | return PTP_PACKET_STATE_UNMATCHED; | ||
669 | |||
670 | match = (struct efx_ptp_match *)skb->cb; | ||
671 | /* Look for a matching timestamp in the event queue */ | ||
672 | spin_lock_bh(&ptp->evt_lock); | ||
673 | list_for_each_safe(cursor, next, &ptp->evt_list) { | ||
674 | struct efx_ptp_event_rx *evt; | ||
675 | |||
676 | evt = list_entry(cursor, struct efx_ptp_event_rx, link); | ||
677 | if ((evt->seq0 == match->words[0]) && | ||
678 | (evt->seq1 == match->words[1])) { | ||
679 | struct skb_shared_hwtstamps *timestamps; | ||
680 | |||
681 | /* Match - add in hardware timestamp */ | ||
682 | timestamps = skb_hwtstamps(skb); | ||
683 | timestamps->hwtstamp = evt->hwtimestamp; | ||
684 | |||
685 | match->state = PTP_PACKET_STATE_MATCHED; | ||
686 | rc = PTP_PACKET_STATE_MATCHED; | ||
687 | list_del(&evt->link); | ||
688 | list_add(&evt->link, &ptp->evt_free_list); | ||
689 | break; | ||
690 | } | ||
691 | } | ||
692 | spin_unlock_bh(&ptp->evt_lock); | ||
693 | |||
694 | return rc; | ||
695 | } | ||
696 | |||
697 | /* Process any queued receive events and corresponding packets | ||
698 | * | ||
699 | * q is returned with all the packets that are ready for delivery. | ||
700 | * true is returned if at least one of those packets requires | ||
701 | * synchronisation. | ||
702 | */ | ||
703 | static bool efx_ptp_process_events(struct efx_nic *efx, struct sk_buff_head *q) | ||
704 | { | ||
705 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
706 | bool rc = false; | ||
707 | struct sk_buff *skb; | ||
708 | |||
709 | while ((skb = skb_dequeue(&ptp->rxq))) { | ||
710 | struct efx_ptp_match *match; | ||
711 | |||
712 | match = (struct efx_ptp_match *)skb->cb; | ||
713 | if (match->state == PTP_PACKET_STATE_MATCH_UNWANTED) { | ||
714 | __skb_queue_tail(q, skb); | ||
715 | } else if (efx_ptp_match_rx(efx, skb) == | ||
716 | PTP_PACKET_STATE_MATCHED) { | ||
717 | rc = true; | ||
718 | __skb_queue_tail(q, skb); | ||
719 | } else if (time_after(jiffies, match->expiry)) { | ||
720 | match->state = PTP_PACKET_STATE_TIMED_OUT; | ||
721 | netif_warn(efx, rx_err, efx->net_dev, | ||
722 | "PTP packet - no timestamp seen\n"); | ||
723 | __skb_queue_tail(q, skb); | ||
724 | } else { | ||
725 | /* Replace unprocessed entry and stop */ | ||
726 | skb_queue_head(&ptp->rxq, skb); | ||
727 | break; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | return rc; | ||
732 | } | ||
733 | |||
734 | /* Complete processing of a received packet */ | ||
735 | static inline void efx_ptp_process_rx(struct efx_nic *efx, struct sk_buff *skb) | ||
736 | { | ||
737 | local_bh_disable(); | ||
738 | netif_receive_skb(skb); | ||
739 | local_bh_enable(); | ||
740 | } | ||
741 | |||
742 | static int efx_ptp_start(struct efx_nic *efx) | ||
743 | { | ||
744 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
745 | struct efx_filter_spec rxfilter; | ||
746 | int rc; | ||
747 | |||
748 | ptp->reset_required = false; | ||
749 | |||
750 | /* Must filter on both event and general ports to ensure | ||
751 | * that there is no packet re-ordering. | ||
752 | */ | ||
753 | efx_filter_init_rx(&rxfilter, EFX_FILTER_PRI_REQUIRED, 0, | ||
754 | efx_rx_queue_index( | ||
755 | efx_channel_get_rx_queue(ptp->channel))); | ||
756 | rc = efx_filter_set_ipv4_local(&rxfilter, IPPROTO_UDP, | ||
757 | htonl(PTP_ADDRESS), | ||
758 | htons(PTP_EVENT_PORT)); | ||
759 | if (rc != 0) | ||
760 | return rc; | ||
761 | |||
762 | rc = efx_filter_insert_filter(efx, &rxfilter, true); | ||
763 | if (rc < 0) | ||
764 | return rc; | ||
765 | ptp->rxfilter_event = rc; | ||
766 | |||
767 | efx_filter_init_rx(&rxfilter, EFX_FILTER_PRI_REQUIRED, 0, | ||
768 | efx_rx_queue_index( | ||
769 | efx_channel_get_rx_queue(ptp->channel))); | ||
770 | rc = efx_filter_set_ipv4_local(&rxfilter, IPPROTO_UDP, | ||
771 | htonl(PTP_ADDRESS), | ||
772 | htons(PTP_GENERAL_PORT)); | ||
773 | if (rc != 0) | ||
774 | goto fail; | ||
775 | |||
776 | rc = efx_filter_insert_filter(efx, &rxfilter, true); | ||
777 | if (rc < 0) | ||
778 | goto fail; | ||
779 | ptp->rxfilter_general = rc; | ||
780 | |||
781 | rc = efx_ptp_enable(efx); | ||
782 | if (rc != 0) | ||
783 | goto fail2; | ||
784 | |||
785 | ptp->evt_frag_idx = 0; | ||
786 | ptp->current_adjfreq = 0; | ||
787 | ptp->rxfilter_installed = true; | ||
788 | |||
789 | return 0; | ||
790 | |||
791 | fail2: | ||
792 | efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, | ||
793 | ptp->rxfilter_general); | ||
794 | fail: | ||
795 | efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, | ||
796 | ptp->rxfilter_event); | ||
797 | |||
798 | return rc; | ||
799 | } | ||
800 | |||
801 | static int efx_ptp_stop(struct efx_nic *efx) | ||
802 | { | ||
803 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
804 | int rc = efx_ptp_disable(efx); | ||
805 | struct list_head *cursor; | ||
806 | struct list_head *next; | ||
807 | |||
808 | if (ptp->rxfilter_installed) { | ||
809 | efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, | ||
810 | ptp->rxfilter_general); | ||
811 | efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, | ||
812 | ptp->rxfilter_event); | ||
813 | ptp->rxfilter_installed = false; | ||
814 | } | ||
815 | |||
816 | /* Make sure RX packets are really delivered */ | ||
817 | efx_ptp_deliver_rx_queue(&efx->ptp_data->rxq); | ||
818 | skb_queue_purge(&efx->ptp_data->txq); | ||
819 | |||
820 | /* Drop any pending receive events */ | ||
821 | spin_lock_bh(&efx->ptp_data->evt_lock); | ||
822 | list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) { | ||
823 | list_del(cursor); | ||
824 | list_add(cursor, &efx->ptp_data->evt_free_list); | ||
825 | } | ||
826 | spin_unlock_bh(&efx->ptp_data->evt_lock); | ||
827 | |||
828 | return rc; | ||
829 | } | ||
830 | |||
831 | static void efx_ptp_pps_worker(struct work_struct *work) | ||
832 | { | ||
833 | struct efx_ptp_data *ptp = | ||
834 | container_of(work, struct efx_ptp_data, pps_work); | ||
835 | struct efx_nic *efx = ptp->channel->efx; | ||
836 | struct ptp_clock_event ptp_evt; | ||
837 | |||
838 | if (efx_ptp_synchronize(efx, PTP_SYNC_ATTEMPTS)) | ||
839 | return; | ||
840 | |||
841 | ptp_evt.type = PTP_CLOCK_PPSUSR; | ||
842 | ptp_evt.pps_times = ptp->host_time_pps; | ||
843 | ptp_clock_event(ptp->phc_clock, &ptp_evt); | ||
844 | } | ||
845 | |||
846 | /* Process any pending transmissions and timestamp any received packets. | ||
847 | */ | ||
848 | static void efx_ptp_worker(struct work_struct *work) | ||
849 | { | ||
850 | struct efx_ptp_data *ptp_data = | ||
851 | container_of(work, struct efx_ptp_data, work); | ||
852 | struct efx_nic *efx = ptp_data->channel->efx; | ||
853 | struct sk_buff *skb; | ||
854 | struct sk_buff_head tempq; | ||
855 | |||
856 | if (ptp_data->reset_required) { | ||
857 | efx_ptp_stop(efx); | ||
858 | efx_ptp_start(efx); | ||
859 | return; | ||
860 | } | ||
861 | |||
862 | efx_ptp_drop_time_expired_events(efx); | ||
863 | |||
864 | __skb_queue_head_init(&tempq); | ||
865 | if (efx_ptp_process_events(efx, &tempq) || | ||
866 | !skb_queue_empty(&ptp_data->txq)) { | ||
867 | |||
868 | while ((skb = skb_dequeue(&ptp_data->txq))) | ||
869 | efx_ptp_xmit_skb(efx, skb); | ||
870 | } | ||
871 | |||
872 | while ((skb = __skb_dequeue(&tempq))) | ||
873 | efx_ptp_process_rx(efx, skb); | ||
874 | } | ||
875 | |||
876 | /* Initialise PTP channel and state. | ||
877 | * | ||
878 | * Setting core_index to zero causes the queue to be initialised and doesn't | ||
879 | * overlap with 'rxq0' because ptp.c doesn't use skb_record_rx_queue. | ||
880 | */ | ||
881 | static int efx_ptp_probe_channel(struct efx_channel *channel) | ||
882 | { | ||
883 | struct efx_nic *efx = channel->efx; | ||
884 | struct efx_ptp_data *ptp; | ||
885 | int rc = 0; | ||
886 | unsigned int pos; | ||
887 | |||
888 | channel->irq_moderation = 0; | ||
889 | channel->rx_queue.core_index = 0; | ||
890 | |||
891 | ptp = kzalloc(sizeof(struct efx_ptp_data), GFP_KERNEL); | ||
892 | efx->ptp_data = ptp; | ||
893 | if (!efx->ptp_data) | ||
894 | return -ENOMEM; | ||
895 | |||
896 | rc = efx_nic_alloc_buffer(efx, &ptp->start, sizeof(int)); | ||
897 | if (rc != 0) | ||
898 | goto fail1; | ||
899 | |||
900 | ptp->channel = channel; | ||
901 | skb_queue_head_init(&ptp->rxq); | ||
902 | skb_queue_head_init(&ptp->txq); | ||
903 | ptp->workwq = create_singlethread_workqueue("sfc_ptp"); | ||
904 | if (!ptp->workwq) { | ||
905 | rc = -ENOMEM; | ||
906 | goto fail2; | ||
907 | } | ||
908 | |||
909 | INIT_WORK(&ptp->work, efx_ptp_worker); | ||
910 | ptp->config.flags = 0; | ||
911 | ptp->config.tx_type = HWTSTAMP_TX_OFF; | ||
912 | ptp->config.rx_filter = HWTSTAMP_FILTER_NONE; | ||
913 | INIT_LIST_HEAD(&ptp->evt_list); | ||
914 | INIT_LIST_HEAD(&ptp->evt_free_list); | ||
915 | spin_lock_init(&ptp->evt_lock); | ||
916 | for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++) | ||
917 | list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list); | ||
918 | |||
919 | ptp->phc_clock_info.owner = THIS_MODULE; | ||
920 | snprintf(ptp->phc_clock_info.name, | ||
921 | sizeof(ptp->phc_clock_info.name), | ||
922 | "%pm", efx->net_dev->perm_addr); | ||
923 | ptp->phc_clock_info.max_adj = MAX_PPB; | ||
924 | ptp->phc_clock_info.n_alarm = 0; | ||
925 | ptp->phc_clock_info.n_ext_ts = 0; | ||
926 | ptp->phc_clock_info.n_per_out = 0; | ||
927 | ptp->phc_clock_info.pps = 1; | ||
928 | ptp->phc_clock_info.adjfreq = efx_phc_adjfreq; | ||
929 | ptp->phc_clock_info.adjtime = efx_phc_adjtime; | ||
930 | ptp->phc_clock_info.gettime = efx_phc_gettime; | ||
931 | ptp->phc_clock_info.settime = efx_phc_settime; | ||
932 | ptp->phc_clock_info.enable = efx_phc_enable; | ||
933 | |||
934 | ptp->phc_clock = ptp_clock_register(&ptp->phc_clock_info); | ||
935 | if (!ptp->phc_clock) | ||
936 | goto fail3; | ||
937 | |||
938 | INIT_WORK(&ptp->pps_work, efx_ptp_pps_worker); | ||
939 | ptp->pps_workwq = create_singlethread_workqueue("sfc_pps"); | ||
940 | if (!ptp->pps_workwq) { | ||
941 | rc = -ENOMEM; | ||
942 | goto fail4; | ||
943 | } | ||
944 | ptp->nic_ts_enabled = false; | ||
945 | |||
946 | return 0; | ||
947 | fail4: | ||
948 | ptp_clock_unregister(efx->ptp_data->phc_clock); | ||
949 | |||
950 | fail3: | ||
951 | destroy_workqueue(efx->ptp_data->workwq); | ||
952 | |||
953 | fail2: | ||
954 | efx_nic_free_buffer(efx, &ptp->start); | ||
955 | |||
956 | fail1: | ||
957 | kfree(efx->ptp_data); | ||
958 | efx->ptp_data = NULL; | ||
959 | |||
960 | return rc; | ||
961 | } | ||
962 | |||
963 | static void efx_ptp_remove_channel(struct efx_channel *channel) | ||
964 | { | ||
965 | struct efx_nic *efx = channel->efx; | ||
966 | |||
967 | if (!efx->ptp_data) | ||
968 | return; | ||
969 | |||
970 | (void)efx_ptp_disable(channel->efx); | ||
971 | |||
972 | cancel_work_sync(&efx->ptp_data->work); | ||
973 | cancel_work_sync(&efx->ptp_data->pps_work); | ||
974 | |||
975 | skb_queue_purge(&efx->ptp_data->rxq); | ||
976 | skb_queue_purge(&efx->ptp_data->txq); | ||
977 | |||
978 | ptp_clock_unregister(efx->ptp_data->phc_clock); | ||
979 | |||
980 | destroy_workqueue(efx->ptp_data->workwq); | ||
981 | destroy_workqueue(efx->ptp_data->pps_workwq); | ||
982 | |||
983 | efx_nic_free_buffer(efx, &efx->ptp_data->start); | ||
984 | kfree(efx->ptp_data); | ||
985 | } | ||
986 | |||
987 | static void efx_ptp_get_channel_name(struct efx_channel *channel, | ||
988 | char *buf, size_t len) | ||
989 | { | ||
990 | snprintf(buf, len, "%s-ptp", channel->efx->name); | ||
991 | } | ||
992 | |||
993 | /* Determine whether this packet should be processed by the PTP module | ||
994 | * or transmitted conventionally. | ||
995 | */ | ||
996 | bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb) | ||
997 | { | ||
998 | return efx->ptp_data && | ||
999 | efx->ptp_data->enabled && | ||
1000 | skb->len >= PTP_MIN_LENGTH && | ||
1001 | skb->len <= MC_CMD_PTP_IN_TRANSMIT_PACKET_MAXNUM && | ||
1002 | likely(skb->protocol == htons(ETH_P_IP)) && | ||
1003 | ip_hdr(skb)->protocol == IPPROTO_UDP && | ||
1004 | udp_hdr(skb)->dest == htons(PTP_EVENT_PORT); | ||
1005 | } | ||
1006 | |||
1007 | /* Receive a PTP packet. Packets are queued until the arrival of | ||
1008 | * the receive timestamp from the MC - this will probably occur after the | ||
1009 | * packet arrival because of the processing in the MC. | ||
1010 | */ | ||
1011 | static void efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb) | ||
1012 | { | ||
1013 | struct efx_nic *efx = channel->efx; | ||
1014 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
1015 | struct efx_ptp_match *match = (struct efx_ptp_match *)skb->cb; | ||
1016 | u8 *data; | ||
1017 | unsigned int version; | ||
1018 | |||
1019 | match->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS); | ||
1020 | |||
1021 | /* Correct version? */ | ||
1022 | if (ptp->mode == MC_CMD_PTP_MODE_V1) { | ||
1023 | if (skb->len < PTP_V1_MIN_LENGTH) { | ||
1024 | netif_receive_skb(skb); | ||
1025 | return; | ||
1026 | } | ||
1027 | version = ntohs(*(__be16 *)&skb->data[PTP_V1_VERSION_OFFSET]); | ||
1028 | if (version != PTP_VERSION_V1) { | ||
1029 | netif_receive_skb(skb); | ||
1030 | return; | ||
1031 | } | ||
1032 | } else { | ||
1033 | if (skb->len < PTP_V2_MIN_LENGTH) { | ||
1034 | netif_receive_skb(skb); | ||
1035 | return; | ||
1036 | } | ||
1037 | version = skb->data[PTP_V2_VERSION_OFFSET]; | ||
1038 | |||
1039 | BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2); | ||
1040 | BUILD_BUG_ON(PTP_V1_UUID_OFFSET != PTP_V2_MC_UUID_OFFSET); | ||
1041 | BUILD_BUG_ON(PTP_V1_UUID_LENGTH != PTP_V2_MC_UUID_LENGTH); | ||
1042 | BUILD_BUG_ON(PTP_V1_SEQUENCE_OFFSET != PTP_V2_SEQUENCE_OFFSET); | ||
1043 | BUILD_BUG_ON(PTP_V1_SEQUENCE_LENGTH != PTP_V2_SEQUENCE_LENGTH); | ||
1044 | |||
1045 | if ((version & PTP_VERSION_V2_MASK) != PTP_VERSION_V2) { | ||
1046 | netif_receive_skb(skb); | ||
1047 | return; | ||
1048 | } | ||
1049 | } | ||
1050 | |||
1051 | /* Does this packet require timestamping? */ | ||
1052 | if (ntohs(*(__be16 *)&skb->data[PTP_DPORT_OFFSET]) == PTP_EVENT_PORT) { | ||
1053 | struct skb_shared_hwtstamps *timestamps; | ||
1054 | |||
1055 | match->state = PTP_PACKET_STATE_UNMATCHED; | ||
1056 | |||
1057 | /* Clear all timestamps held: filled in later */ | ||
1058 | timestamps = skb_hwtstamps(skb); | ||
1059 | memset(timestamps, 0, sizeof(*timestamps)); | ||
1060 | |||
1061 | /* Extract UUID/Sequence information */ | ||
1062 | data = skb->data + PTP_V1_UUID_OFFSET; | ||
1063 | match->words[0] = (data[0] | | ||
1064 | (data[1] << 8) | | ||
1065 | (data[2] << 16) | | ||
1066 | (data[3] << 24)); | ||
1067 | match->words[1] = (data[4] | | ||
1068 | (data[5] << 8) | | ||
1069 | (skb->data[PTP_V1_SEQUENCE_OFFSET + | ||
1070 | PTP_V1_SEQUENCE_LENGTH - 1] << | ||
1071 | 16)); | ||
1072 | } else { | ||
1073 | match->state = PTP_PACKET_STATE_MATCH_UNWANTED; | ||
1074 | } | ||
1075 | |||
1076 | skb_queue_tail(&ptp->rxq, skb); | ||
1077 | queue_work(ptp->workwq, &ptp->work); | ||
1078 | } | ||
1079 | |||
1080 | /* Transmit a PTP packet. This has to be transmitted by the MC | ||
1081 | * itself, through an MCDI call. MCDI calls aren't permitted | ||
1082 | * in the transmit path so defer the actual transmission to a suitable worker. | ||
1083 | */ | ||
1084 | int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb) | ||
1085 | { | ||
1086 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
1087 | |||
1088 | skb_queue_tail(&ptp->txq, skb); | ||
1089 | |||
1090 | if ((udp_hdr(skb)->dest == htons(PTP_EVENT_PORT)) && | ||
1091 | (skb->len <= MC_CMD_PTP_IN_TRANSMIT_PACKET_MAXNUM)) | ||
1092 | efx_xmit_hwtstamp_pending(skb); | ||
1093 | queue_work(ptp->workwq, &ptp->work); | ||
1094 | |||
1095 | return NETDEV_TX_OK; | ||
1096 | } | ||
1097 | |||
1098 | static int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, | ||
1099 | unsigned int new_mode) | ||
1100 | { | ||
1101 | if ((enable_wanted != efx->ptp_data->enabled) || | ||
1102 | (enable_wanted && (efx->ptp_data->mode != new_mode))) { | ||
1103 | int rc; | ||
1104 | |||
1105 | if (enable_wanted) { | ||
1106 | /* Change of mode requires disable */ | ||
1107 | if (efx->ptp_data->enabled && | ||
1108 | (efx->ptp_data->mode != new_mode)) { | ||
1109 | efx->ptp_data->enabled = false; | ||
1110 | rc = efx_ptp_stop(efx); | ||
1111 | if (rc != 0) | ||
1112 | return rc; | ||
1113 | } | ||
1114 | |||
1115 | /* Set new operating mode and establish | ||
1116 | * baseline synchronisation, which must | ||
1117 | * succeed. | ||
1118 | */ | ||
1119 | efx->ptp_data->mode = new_mode; | ||
1120 | rc = efx_ptp_start(efx); | ||
1121 | if (rc == 0) { | ||
1122 | rc = efx_ptp_synchronize(efx, | ||
1123 | PTP_SYNC_ATTEMPTS * 2); | ||
1124 | if (rc != 0) | ||
1125 | efx_ptp_stop(efx); | ||
1126 | } | ||
1127 | } else { | ||
1128 | rc = efx_ptp_stop(efx); | ||
1129 | } | ||
1130 | |||
1131 | if (rc != 0) | ||
1132 | return rc; | ||
1133 | |||
1134 | efx->ptp_data->enabled = enable_wanted; | ||
1135 | } | ||
1136 | |||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init) | ||
1141 | { | ||
1142 | bool enable_wanted = false; | ||
1143 | unsigned int new_mode; | ||
1144 | int rc; | ||
1145 | |||
1146 | if (init->flags) | ||
1147 | return -EINVAL; | ||
1148 | |||
1149 | if ((init->tx_type != HWTSTAMP_TX_OFF) && | ||
1150 | (init->tx_type != HWTSTAMP_TX_ON)) | ||
1151 | return -ERANGE; | ||
1152 | |||
1153 | new_mode = efx->ptp_data->mode; | ||
1154 | /* Determine whether any PTP HW operations are required */ | ||
1155 | switch (init->rx_filter) { | ||
1156 | case HWTSTAMP_FILTER_NONE: | ||
1157 | break; | ||
1158 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | ||
1159 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | ||
1160 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | ||
1161 | init->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; | ||
1162 | new_mode = MC_CMD_PTP_MODE_V1; | ||
1163 | enable_wanted = true; | ||
1164 | break; | ||
1165 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | ||
1166 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | ||
1167 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | ||
1168 | /* Although these three are accepted only IPV4 packets will be | ||
1169 | * timestamped | ||
1170 | */ | ||
1171 | init->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; | ||
1172 | new_mode = MC_CMD_PTP_MODE_V2; | ||
1173 | enable_wanted = true; | ||
1174 | break; | ||
1175 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | ||
1176 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | ||
1177 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | ||
1178 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | ||
1179 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | ||
1180 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | ||
1181 | /* Non-IP + IPv6 timestamping not supported */ | ||
1182 | return -ERANGE; | ||
1183 | break; | ||
1184 | default: | ||
1185 | return -ERANGE; | ||
1186 | } | ||
1187 | |||
1188 | if (init->tx_type != HWTSTAMP_TX_OFF) | ||
1189 | enable_wanted = true; | ||
1190 | |||
1191 | rc = efx_ptp_change_mode(efx, enable_wanted, new_mode); | ||
1192 | if (rc != 0) | ||
1193 | return rc; | ||
1194 | |||
1195 | efx->ptp_data->config = *init; | ||
1196 | |||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | int | ||
1201 | efx_ptp_get_ts_info(struct net_device *net_dev, struct ethtool_ts_info *ts_info) | ||
1202 | { | ||
1203 | struct efx_nic *efx = netdev_priv(net_dev); | ||
1204 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
1205 | |||
1206 | if (!ptp) | ||
1207 | return -EOPNOTSUPP; | ||
1208 | |||
1209 | ts_info->so_timestamping = (SOF_TIMESTAMPING_TX_HARDWARE | | ||
1210 | SOF_TIMESTAMPING_RX_HARDWARE | | ||
1211 | SOF_TIMESTAMPING_RAW_HARDWARE); | ||
1212 | ts_info->phc_index = ptp_clock_index(ptp->phc_clock); | ||
1213 | ts_info->tx_types = 1 << HWTSTAMP_TX_OFF | 1 << HWTSTAMP_TX_ON; | ||
1214 | ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE | | ||
1215 | 1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT | | ||
1216 | 1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC | | ||
1217 | 1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ | | ||
1218 | 1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT | | ||
1219 | 1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC | | ||
1220 | 1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); | ||
1221 | return 0; | ||
1222 | } | ||
1223 | |||
1224 | int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd) | ||
1225 | { | ||
1226 | struct hwtstamp_config config; | ||
1227 | int rc; | ||
1228 | |||
1229 | /* Not a PTP enabled port */ | ||
1230 | if (!efx->ptp_data) | ||
1231 | return -EOPNOTSUPP; | ||
1232 | |||
1233 | if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) | ||
1234 | return -EFAULT; | ||
1235 | |||
1236 | rc = efx_ptp_ts_init(efx, &config); | ||
1237 | if (rc != 0) | ||
1238 | return rc; | ||
1239 | |||
1240 | return copy_to_user(ifr->ifr_data, &config, sizeof(config)) | ||
1241 | ? -EFAULT : 0; | ||
1242 | } | ||
1243 | |||
1244 | static void ptp_event_failure(struct efx_nic *efx, int expected_frag_len) | ||
1245 | { | ||
1246 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
1247 | |||
1248 | netif_err(efx, hw, efx->net_dev, | ||
1249 | "PTP unexpected event length: got %d expected %d\n", | ||
1250 | ptp->evt_frag_idx, expected_frag_len); | ||
1251 | ptp->reset_required = true; | ||
1252 | queue_work(ptp->workwq, &ptp->work); | ||
1253 | } | ||
1254 | |||
1255 | /* Process a completed receive event. Put it on the event queue and | ||
1256 | * start worker thread. This is required because event and their | ||
1257 | * correspoding packets may come in either order. | ||
1258 | */ | ||
1259 | static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp) | ||
1260 | { | ||
1261 | struct efx_ptp_event_rx *evt = NULL; | ||
1262 | |||
1263 | if (ptp->evt_frag_idx != 3) { | ||
1264 | ptp_event_failure(efx, 3); | ||
1265 | return; | ||
1266 | } | ||
1267 | |||
1268 | spin_lock_bh(&ptp->evt_lock); | ||
1269 | if (!list_empty(&ptp->evt_free_list)) { | ||
1270 | evt = list_first_entry(&ptp->evt_free_list, | ||
1271 | struct efx_ptp_event_rx, link); | ||
1272 | list_del(&evt->link); | ||
1273 | |||
1274 | evt->seq0 = EFX_QWORD_FIELD(ptp->evt_frags[2], MCDI_EVENT_DATA); | ||
1275 | evt->seq1 = (EFX_QWORD_FIELD(ptp->evt_frags[2], | ||
1276 | MCDI_EVENT_SRC) | | ||
1277 | (EFX_QWORD_FIELD(ptp->evt_frags[1], | ||
1278 | MCDI_EVENT_SRC) << 8) | | ||
1279 | (EFX_QWORD_FIELD(ptp->evt_frags[0], | ||
1280 | MCDI_EVENT_SRC) << 16)); | ||
1281 | evt->hwtimestamp = ktime_set( | ||
1282 | EFX_QWORD_FIELD(ptp->evt_frags[0], MCDI_EVENT_DATA), | ||
1283 | EFX_QWORD_FIELD(ptp->evt_frags[1], MCDI_EVENT_DATA)); | ||
1284 | evt->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS); | ||
1285 | list_add_tail(&evt->link, &ptp->evt_list); | ||
1286 | |||
1287 | queue_work(ptp->workwq, &ptp->work); | ||
1288 | } else { | ||
1289 | netif_err(efx, rx_err, efx->net_dev, "No free PTP event"); | ||
1290 | } | ||
1291 | spin_unlock_bh(&ptp->evt_lock); | ||
1292 | } | ||
1293 | |||
1294 | static void ptp_event_fault(struct efx_nic *efx, struct efx_ptp_data *ptp) | ||
1295 | { | ||
1296 | int code = EFX_QWORD_FIELD(ptp->evt_frags[0], MCDI_EVENT_DATA); | ||
1297 | if (ptp->evt_frag_idx != 1) { | ||
1298 | ptp_event_failure(efx, 1); | ||
1299 | return; | ||
1300 | } | ||
1301 | |||
1302 | netif_err(efx, hw, efx->net_dev, "PTP error %d\n", code); | ||
1303 | } | ||
1304 | |||
1305 | static void ptp_event_pps(struct efx_nic *efx, struct efx_ptp_data *ptp) | ||
1306 | { | ||
1307 | if (ptp->nic_ts_enabled) | ||
1308 | queue_work(ptp->pps_workwq, &ptp->pps_work); | ||
1309 | } | ||
1310 | |||
1311 | void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev) | ||
1312 | { | ||
1313 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
1314 | int code = EFX_QWORD_FIELD(*ev, MCDI_EVENT_CODE); | ||
1315 | |||
1316 | if (!ptp->enabled) | ||
1317 | return; | ||
1318 | |||
1319 | if (ptp->evt_frag_idx == 0) { | ||
1320 | ptp->evt_code = code; | ||
1321 | } else if (ptp->evt_code != code) { | ||
1322 | netif_err(efx, hw, efx->net_dev, | ||
1323 | "PTP out of sequence event %d\n", code); | ||
1324 | ptp->evt_frag_idx = 0; | ||
1325 | } | ||
1326 | |||
1327 | ptp->evt_frags[ptp->evt_frag_idx++] = *ev; | ||
1328 | if (!MCDI_EVENT_FIELD(*ev, CONT)) { | ||
1329 | /* Process resulting event */ | ||
1330 | switch (code) { | ||
1331 | case MCDI_EVENT_CODE_PTP_RX: | ||
1332 | ptp_event_rx(efx, ptp); | ||
1333 | break; | ||
1334 | case MCDI_EVENT_CODE_PTP_FAULT: | ||
1335 | ptp_event_fault(efx, ptp); | ||
1336 | break; | ||
1337 | case MCDI_EVENT_CODE_PTP_PPS: | ||
1338 | ptp_event_pps(efx, ptp); | ||
1339 | break; | ||
1340 | default: | ||
1341 | netif_err(efx, hw, efx->net_dev, | ||
1342 | "PTP unknown event %d\n", code); | ||
1343 | break; | ||
1344 | } | ||
1345 | ptp->evt_frag_idx = 0; | ||
1346 | } else if (MAX_EVENT_FRAGS == ptp->evt_frag_idx) { | ||
1347 | netif_err(efx, hw, efx->net_dev, | ||
1348 | "PTP too many event fragments\n"); | ||
1349 | ptp->evt_frag_idx = 0; | ||
1350 | } | ||
1351 | } | ||
1352 | |||
1353 | static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) | ||
1354 | { | ||
1355 | struct efx_ptp_data *ptp_data = container_of(ptp, | ||
1356 | struct efx_ptp_data, | ||
1357 | phc_clock_info); | ||
1358 | struct efx_nic *efx = ptp_data->channel->efx; | ||
1359 | u8 inadj[MC_CMD_PTP_IN_ADJUST_LEN]; | ||
1360 | s64 adjustment_ns; | ||
1361 | int rc; | ||
1362 | |||
1363 | if (delta > MAX_PPB) | ||
1364 | delta = MAX_PPB; | ||
1365 | else if (delta < -MAX_PPB) | ||
1366 | delta = -MAX_PPB; | ||
1367 | |||
1368 | /* Convert ppb to fixed point ns. */ | ||
1369 | adjustment_ns = (((s64)delta * PPB_SCALE_WORD) >> | ||
1370 | (PPB_EXTRA_BITS + MAX_PPB_BITS)); | ||
1371 | |||
1372 | MCDI_SET_DWORD(inadj, PTP_IN_OP, MC_CMD_PTP_OP_ADJUST); | ||
1373 | MCDI_SET_DWORD(inadj, PTP_IN_ADJUST_FREQ_LO, (u32)adjustment_ns); | ||
1374 | MCDI_SET_DWORD(inadj, PTP_IN_ADJUST_FREQ_HI, | ||
1375 | (u32)(adjustment_ns >> 32)); | ||
1376 | MCDI_SET_DWORD(inadj, PTP_IN_ADJUST_SECONDS, 0); | ||
1377 | MCDI_SET_DWORD(inadj, PTP_IN_ADJUST_NANOSECONDS, 0); | ||
1378 | rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inadj, sizeof(inadj), | ||
1379 | NULL, 0, NULL); | ||
1380 | if (rc != 0) | ||
1381 | return rc; | ||
1382 | |||
1383 | ptp_data->current_adjfreq = delta; | ||
1384 | return 0; | ||
1385 | } | ||
1386 | |||
1387 | static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) | ||
1388 | { | ||
1389 | struct efx_ptp_data *ptp_data = container_of(ptp, | ||
1390 | struct efx_ptp_data, | ||
1391 | phc_clock_info); | ||
1392 | struct efx_nic *efx = ptp_data->channel->efx; | ||
1393 | struct timespec delta_ts = ns_to_timespec(delta); | ||
1394 | u8 inbuf[MC_CMD_PTP_IN_ADJUST_LEN]; | ||
1395 | |||
1396 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ADJUST); | ||
1397 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_FREQ_LO, 0); | ||
1398 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_FREQ_HI, 0); | ||
1399 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_SECONDS, (u32)delta_ts.tv_sec); | ||
1400 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_NANOSECONDS, (u32)delta_ts.tv_nsec); | ||
1401 | return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), | ||
1402 | NULL, 0, NULL); | ||
1403 | } | ||
1404 | |||
1405 | static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts) | ||
1406 | { | ||
1407 | struct efx_ptp_data *ptp_data = container_of(ptp, | ||
1408 | struct efx_ptp_data, | ||
1409 | phc_clock_info); | ||
1410 | struct efx_nic *efx = ptp_data->channel->efx; | ||
1411 | u8 inbuf[MC_CMD_PTP_IN_READ_NIC_TIME_LEN]; | ||
1412 | u8 outbuf[MC_CMD_PTP_OUT_READ_NIC_TIME_LEN]; | ||
1413 | int rc; | ||
1414 | |||
1415 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_READ_NIC_TIME); | ||
1416 | |||
1417 | rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), | ||
1418 | outbuf, sizeof(outbuf), NULL); | ||
1419 | if (rc != 0) | ||
1420 | return rc; | ||
1421 | |||
1422 | ts->tv_sec = MCDI_DWORD(outbuf, PTP_OUT_READ_NIC_TIME_SECONDS); | ||
1423 | ts->tv_nsec = MCDI_DWORD(outbuf, PTP_OUT_READ_NIC_TIME_NANOSECONDS); | ||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | static int efx_phc_settime(struct ptp_clock_info *ptp, | ||
1428 | const struct timespec *e_ts) | ||
1429 | { | ||
1430 | /* Get the current NIC time, efx_phc_gettime. | ||
1431 | * Subtract from the desired time to get the offset | ||
1432 | * call efx_phc_adjtime with the offset | ||
1433 | */ | ||
1434 | int rc; | ||
1435 | struct timespec time_now; | ||
1436 | struct timespec delta; | ||
1437 | |||
1438 | rc = efx_phc_gettime(ptp, &time_now); | ||
1439 | if (rc != 0) | ||
1440 | return rc; | ||
1441 | |||
1442 | delta = timespec_sub(*e_ts, time_now); | ||
1443 | |||
1444 | efx_phc_adjtime(ptp, timespec_to_ns(&delta)); | ||
1445 | if (rc != 0) | ||
1446 | return rc; | ||
1447 | |||
1448 | return 0; | ||
1449 | } | ||
1450 | |||
1451 | static int efx_phc_enable(struct ptp_clock_info *ptp, | ||
1452 | struct ptp_clock_request *request, | ||
1453 | int enable) | ||
1454 | { | ||
1455 | struct efx_ptp_data *ptp_data = container_of(ptp, | ||
1456 | struct efx_ptp_data, | ||
1457 | phc_clock_info); | ||
1458 | if (request->type != PTP_CLK_REQ_PPS) | ||
1459 | return -EOPNOTSUPP; | ||
1460 | |||
1461 | ptp_data->nic_ts_enabled = !!enable; | ||
1462 | return 0; | ||
1463 | } | ||
1464 | |||
1465 | static const struct efx_channel_type efx_ptp_channel_type = { | ||
1466 | .handle_no_channel = efx_ptp_handle_no_channel, | ||
1467 | .pre_probe = efx_ptp_probe_channel, | ||
1468 | .post_remove = efx_ptp_remove_channel, | ||
1469 | .get_name = efx_ptp_get_channel_name, | ||
1470 | /* no copy operation; there is no need to reallocate this channel */ | ||
1471 | .receive_skb = efx_ptp_rx, | ||
1472 | .keep_eventq = false, | ||
1473 | }; | ||
1474 | |||
1475 | void efx_ptp_probe(struct efx_nic *efx) | ||
1476 | { | ||
1477 | /* Check whether PTP is implemented on this NIC. The DISABLE | ||
1478 | * operation will succeed if and only if it is implemented. | ||
1479 | */ | ||
1480 | if (efx_ptp_disable(efx) == 0) | ||
1481 | efx->extra_channel_type[EFX_EXTRA_CHANNEL_PTP] = | ||
1482 | &efx_ptp_channel_type; | ||
1483 | } | ||
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 6bafd216e55e..84b41bf08a38 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c | |||
@@ -335,6 +335,7 @@ static int siena_probe_nic(struct efx_nic *efx) | |||
335 | goto fail5; | 335 | goto fail5; |
336 | 336 | ||
337 | efx_sriov_probe(efx); | 337 | efx_sriov_probe(efx); |
338 | efx_ptp_probe(efx); | ||
338 | 339 | ||
339 | return 0; | 340 | return 0; |
340 | 341 | ||
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index ebca75ed78dc..5e090e54298e 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c | |||
@@ -339,6 +339,12 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, | |||
339 | 339 | ||
340 | EFX_WARN_ON_PARANOID(!netif_device_present(net_dev)); | 340 | EFX_WARN_ON_PARANOID(!netif_device_present(net_dev)); |
341 | 341 | ||
342 | /* PTP "event" packet */ | ||
343 | if (unlikely(efx_xmit_with_hwtstamp(skb)) && | ||
344 | unlikely(efx_ptp_is_ptp_tx(efx, skb))) { | ||
345 | return efx_ptp_tx(efx, skb); | ||
346 | } | ||
347 | |||
342 | index = skb_get_queue_mapping(skb); | 348 | index = skb_get_queue_mapping(skb); |
343 | type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; | 349 | type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; |
344 | if (index >= efx->n_tx_channels) { | 350 | if (index >= efx->n_tx_channels) { |