aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurence Evans <levans@solarflare.com>2012-11-15 05:56:07 -0500
committerBen Hutchings <bhutchings@solarflare.com>2013-03-07 15:21:55 -0500
commitc939a316459783e5cd6c6bd9dc90ea11b18ecd7f (patch)
treef479a818957b2dbfe86eef6b827c8b7e0a98e0fd
parent4a74dc65e3ad825a66dfbcb256f98c550f96445b (diff)
sfc: PTP changes to support improved UUID filtering mode
There is a long-standing problem with the packet-timestamp matching in the driver. When a PTP packet is received by the MC, the FPGA timestamps the packet and the MC sends the timestamp and 6 bytes of the UUID to the driver. The driver then matches the timestamp against received packets using the same 6 bytes of UUID. The problem comes from the choice of which 6 bytes to use. The PTP spec is slightly contradictory and misleading in one of the two places where the UUIDs are discussed. From section 7.2.2.2 of the spec, a PTPD2 UUID can be either a EUI-64 or a EUI-64 constructed from a EUI-48. The typical ethernet based implementation uses a EUI-64 constructed from a EUI-48. This works by taking the first 3 bytes of the MAC address of the NIC being used for PTP (the OUI), then inserting 0xFF, 0xFE, then taking the last 3 bytes of the MAC address giving MAC[0], MAC[1], MAC[2], 0xFF, 0xFE, MAC[3], MAC[4], MAC[5] The current MC firmware and driver discard the first two bytes of this UUID and packets are matched against timestamps using bytes 2 to 7 so there is a small risk that in a deployment of Solarflare PTP NICs used with other vendors NICs, that a PTP packet could be matched against the wrong timestamp. This applies to all other organisations whose third byte of the OUI is 0x53. It's a long list but I notice that it includes Cisco. The necessary modifications to use bytes 0-2 and 5-7 of the UUID to match against are quite small but introduce incompatibility between older version of the firmware and driver. When PTP is enabled via SO_TIMESTAMPING specifying PTP V2, the driver will try to enable PTP in the firmware using the enhanced mode (above). If the firmware returns an error, the driver will enable PTP in the firmware using the old mode. [bwh: Fix some style errors; remove private ioctl bits] Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r--drivers/net/ethernet/sfc/mcdi_pcol.h1
-rw-r--r--drivers/net/ethernet/sfc/ptp.c61
2 files changed, 46 insertions, 16 deletions
diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h
index 9d426d0457bd..c5c9747861ba 100644
--- a/drivers/net/ethernet/sfc/mcdi_pcol.h
+++ b/drivers/net/ethernet/sfc/mcdi_pcol.h
@@ -553,6 +553,7 @@
553#define MC_CMD_PTP_MODE_V1_VLAN 0x1 /* enum */ 553#define MC_CMD_PTP_MODE_V1_VLAN 0x1 /* enum */
554#define MC_CMD_PTP_MODE_V2 0x2 /* enum */ 554#define MC_CMD_PTP_MODE_V2 0x2 /* enum */
555#define MC_CMD_PTP_MODE_V2_VLAN 0x3 /* enum */ 555#define MC_CMD_PTP_MODE_V2_VLAN 0x3 /* enum */
556#define MC_CMD_PTP_MODE_V2_ENHANCED 0x4 /* enum */
556 557
557/* MC_CMD_PTP_IN_DISABLE msgrequest */ 558/* MC_CMD_PTP_IN_DISABLE msgrequest */
558#define MC_CMD_PTP_IN_DISABLE_LEN 8 559#define MC_CMD_PTP_IN_DISABLE_LEN 8
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index faf4baf36861..2b40cbd6667b 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -99,6 +99,9 @@
99#define PTP_V2_VERSION_LENGTH 1 99#define PTP_V2_VERSION_LENGTH 1
100#define PTP_V2_VERSION_OFFSET 29 100#define PTP_V2_VERSION_OFFSET 29
101 101
102#define PTP_V2_UUID_LENGTH 8
103#define PTP_V2_UUID_OFFSET 48
104
102/* Although PTP V2 UUIDs are comprised a ClockIdentity (8) and PortNumber (2), 105/* 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 106 * 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 107 * reflect those, not the ones used in the standard. The standard permits
@@ -1011,7 +1014,7 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
1011 struct efx_nic *efx = channel->efx; 1014 struct efx_nic *efx = channel->efx;
1012 struct efx_ptp_data *ptp = efx->ptp_data; 1015 struct efx_ptp_data *ptp = efx->ptp_data;
1013 struct efx_ptp_match *match = (struct efx_ptp_match *)skb->cb; 1016 struct efx_ptp_match *match = (struct efx_ptp_match *)skb->cb;
1014 u8 *data; 1017 u8 *match_data_012, *match_data_345;
1015 unsigned int version; 1018 unsigned int version;
1016 1019
1017 match->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS); 1020 match->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS);
@@ -1025,21 +1028,35 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
1025 if (version != PTP_VERSION_V1) { 1028 if (version != PTP_VERSION_V1) {
1026 return false; 1029 return false;
1027 } 1030 }
1031
1032 /* PTP V1 uses all six bytes of the UUID to match the packet
1033 * to the timestamp
1034 */
1035 match_data_012 = skb->data + PTP_V1_UUID_OFFSET;
1036 match_data_345 = skb->data + PTP_V1_UUID_OFFSET + 3;
1028 } else { 1037 } else {
1029 if (skb->len < PTP_V2_MIN_LENGTH) { 1038 if (skb->len < PTP_V2_MIN_LENGTH) {
1030 return false; 1039 return false;
1031 } 1040 }
1032 version = skb->data[PTP_V2_VERSION_OFFSET]; 1041 version = skb->data[PTP_V2_VERSION_OFFSET];
1033
1034 BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2);
1035 BUILD_BUG_ON(PTP_V1_UUID_OFFSET != PTP_V2_MC_UUID_OFFSET);
1036 BUILD_BUG_ON(PTP_V1_UUID_LENGTH != PTP_V2_MC_UUID_LENGTH);
1037 BUILD_BUG_ON(PTP_V1_SEQUENCE_OFFSET != PTP_V2_SEQUENCE_OFFSET);
1038 BUILD_BUG_ON(PTP_V1_SEQUENCE_LENGTH != PTP_V2_SEQUENCE_LENGTH);
1039
1040 if ((version & PTP_VERSION_V2_MASK) != PTP_VERSION_V2) { 1042 if ((version & PTP_VERSION_V2_MASK) != PTP_VERSION_V2) {
1041 return false; 1043 return false;
1042 } 1044 }
1045
1046 /* The original V2 implementation uses bytes 2-7 of
1047 * the UUID to match the packet to the timestamp. This
1048 * discards two of the bytes of the MAC address used
1049 * to create the UUID (SF bug 33070). The PTP V2
1050 * enhanced mode fixes this issue and uses bytes 0-2
1051 * and byte 5-7 of the UUID.
1052 */
1053 match_data_345 = skb->data + PTP_V2_UUID_OFFSET + 5;
1054 if (ptp->mode == MC_CMD_PTP_MODE_V2) {
1055 match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 2;
1056 } else {
1057 match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 0;
1058 BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2_ENHANCED);
1059 }
1043 } 1060 }
1044 1061
1045 /* Does this packet require timestamping? */ 1062 /* Does this packet require timestamping? */
@@ -1052,14 +1069,19 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
1052 timestamps = skb_hwtstamps(skb); 1069 timestamps = skb_hwtstamps(skb);
1053 memset(timestamps, 0, sizeof(*timestamps)); 1070 memset(timestamps, 0, sizeof(*timestamps));
1054 1071
1072 /* We expect the sequence number to be in the same position in
1073 * the packet for PTP V1 and V2
1074 */
1075 BUILD_BUG_ON(PTP_V1_SEQUENCE_OFFSET != PTP_V2_SEQUENCE_OFFSET);
1076 BUILD_BUG_ON(PTP_V1_SEQUENCE_LENGTH != PTP_V2_SEQUENCE_LENGTH);
1077
1055 /* Extract UUID/Sequence information */ 1078 /* Extract UUID/Sequence information */
1056 data = skb->data + PTP_V1_UUID_OFFSET; 1079 match->words[0] = (match_data_012[0] |
1057 match->words[0] = (data[0] | 1080 (match_data_012[1] << 8) |
1058 (data[1] << 8) | 1081 (match_data_012[2] << 16) |
1059 (data[2] << 16) | 1082 (match_data_345[0] << 24));
1060 (data[3] << 24)); 1083 match->words[1] = (match_data_345[1] |
1061 match->words[1] = (data[4] | 1084 (match_data_345[2] << 8) |
1062 (data[5] << 8) |
1063 (skb->data[PTP_V1_SEQUENCE_OFFSET + 1085 (skb->data[PTP_V1_SEQUENCE_OFFSET +
1064 PTP_V1_SEQUENCE_LENGTH - 1] << 1086 PTP_V1_SEQUENCE_LENGTH - 1] <<
1065 16)); 1087 16));
@@ -1165,7 +1187,7 @@ static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init)
1165 * timestamped 1187 * timestamped
1166 */ 1188 */
1167 init->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; 1189 init->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
1168 new_mode = MC_CMD_PTP_MODE_V2; 1190 new_mode = MC_CMD_PTP_MODE_V2_ENHANCED;
1169 enable_wanted = true; 1191 enable_wanted = true;
1170 break; 1192 break;
1171 case HWTSTAMP_FILTER_PTP_V2_EVENT: 1193 case HWTSTAMP_FILTER_PTP_V2_EVENT:
@@ -1184,7 +1206,14 @@ static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init)
1184 if (init->tx_type != HWTSTAMP_TX_OFF) 1206 if (init->tx_type != HWTSTAMP_TX_OFF)
1185 enable_wanted = true; 1207 enable_wanted = true;
1186 1208
1209 /* Old versions of the firmware do not support the improved
1210 * UUID filtering option (SF bug 33070). If the firmware does
1211 * not accept the enhanced mode, fall back to the standard PTP
1212 * v2 UUID filtering.
1213 */
1187 rc = efx_ptp_change_mode(efx, enable_wanted, new_mode); 1214 rc = efx_ptp_change_mode(efx, enable_wanted, new_mode);
1215 if ((rc != 0) && (new_mode == MC_CMD_PTP_MODE_V2_ENHANCED))
1216 rc = efx_ptp_change_mode(efx, enable_wanted, MC_CMD_PTP_MODE_V2);
1188 if (rc != 0) 1217 if (rc != 0)
1189 return rc; 1218 return rc;
1190 1219