Skip to content

Commit

Permalink
sfc: support PTP over IPv6/UDP
Browse files Browse the repository at this point in the history
commit bd4a269 ("sfc: use hardware tx timestamps for more than
PTP") added support for hardware timestamping on TX for cards of the
8000 series and newer, in an effort to provide support for other
transports other than IPv4/UDP.

However, timestamping was still not working on RX for these other
transports. This patch add support for PTP over IPv6/UDP.

Tested: sync as master and as slave is correct using ptp4l from linuxptp
package, both with IPv4 and IPv6.

Suggested-by: Edward Cree <[email protected]>
Signed-off-by: Íñigo Huguet <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
ihuguet authored and davem330 committed Sep 7, 2022
1 parent 313aa13 commit 621918c
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 12 deletions.
22 changes: 22 additions & 0 deletions drivers/net/ethernet/sfc/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/in6.h>
#include <asm/byteorder.h>

/**
Expand Down Expand Up @@ -223,6 +224,27 @@ efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
return 0;
}

/**
* efx_filter_set_ipv6_local - specify IPv6 host, transport protocol and port
* @spec: Specification to initialise
* @proto: Transport layer protocol number
* @host: Local host address (network byte order)
* @port: Local port (network byte order)
*/
static inline int
efx_filter_set_ipv6_local(struct efx_filter_spec *spec, u8 proto,
const struct in6_addr *host, __be16 port)
{
spec->match_flags |=
EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
spec->ether_type = htons(ETH_P_IPV6);
spec->ip_proto = proto;
memcpy(spec->loc_host, host, sizeof(spec->loc_host));
spec->loc_port = port;
return 0;
}

/**
* efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports
* @spec: Specification to initialise
Expand Down
61 changes: 49 additions & 12 deletions drivers/net/ethernet/sfc/ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,11 @@

#define PTP_MIN_LENGTH 63

#define PTP_RXFILTERS_LEN 2
#define PTP_RXFILTERS_LEN 4

#define PTP_ADDRESS 0xe0000181 /* 224.0.1.129 */
#define PTP_ADDR_IPV4 0xe0000181 /* 224.0.1.129 */
#define PTP_ADDR_IPV6 {0xff, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0x01, 0x81} /* ff0e::181 */
#define PTP_EVENT_PORT 319
#define PTP_GENERAL_PORT 320

Expand Down Expand Up @@ -1297,27 +1299,49 @@ static void efx_ptp_remove_multicast_filters(struct efx_nic *efx)
}
}

static int efx_ptp_insert_ipv4_filter(struct efx_nic *efx, u16 port)
static void efx_ptp_init_filter(struct efx_nic *efx,
struct efx_filter_spec *rxfilter)
{
struct efx_ptp_data *ptp = efx->ptp_data;
struct efx_filter_spec rxfilter;
int rc;
struct efx_channel *channel = efx->ptp_data->channel;
struct efx_rx_queue *queue = efx_channel_get_rx_queue(channel);

efx_filter_init_rx(&rxfilter, EFX_FILTER_PRI_REQUIRED, 0,
efx_rx_queue_index(
efx_channel_get_rx_queue(ptp->channel)));
efx_filter_init_rx(rxfilter, EFX_FILTER_PRI_REQUIRED, 0,
efx_rx_queue_index(queue));
}

efx_filter_set_ipv4_local(&rxfilter, IPPROTO_UDP, htonl(PTP_ADDRESS),
htons(port));
static int efx_ptp_insert_filter(struct efx_nic *efx,
struct efx_filter_spec *rxfilter)
{
struct efx_ptp_data *ptp = efx->ptp_data;

rc = efx_filter_insert_filter(efx, &rxfilter, true);
int rc = efx_filter_insert_filter(efx, rxfilter, true);
if (rc < 0)
return rc;
ptp->rxfilters[ptp->rxfilters_count] = rc;
ptp->rxfilters_count++;
return 0;
}

static int efx_ptp_insert_ipv4_filter(struct efx_nic *efx, u16 port)
{
struct efx_filter_spec rxfilter;

efx_ptp_init_filter(efx, &rxfilter);
efx_filter_set_ipv4_local(&rxfilter, IPPROTO_UDP, htonl(PTP_ADDR_IPV4),
htons(port));
return efx_ptp_insert_filter(efx, &rxfilter);
}

static int efx_ptp_insert_ipv6_filter(struct efx_nic *efx, u16 port)
{
const struct in6_addr addr = {{PTP_ADDR_IPV6}};
struct efx_filter_spec rxfilter;

efx_ptp_init_filter(efx, &rxfilter);
efx_filter_set_ipv6_local(&rxfilter, IPPROTO_UDP, &addr, htons(port));
return efx_ptp_insert_filter(efx, &rxfilter);
}

static int efx_ptp_insert_multicast_filters(struct efx_nic *efx)
{
struct efx_ptp_data *ptp = efx->ptp_data;
Expand All @@ -1337,6 +1361,19 @@ static int efx_ptp_insert_multicast_filters(struct efx_nic *efx)
if (rc < 0)
goto fail;

/* if the NIC supports hw timestamps by the MAC, we can support
* PTP over IPv6
*/
if (efx_ptp_use_mac_tx_timestamps(efx)) {
rc = efx_ptp_insert_ipv6_filter(efx, PTP_EVENT_PORT);
if (rc < 0)
goto fail;

rc = efx_ptp_insert_ipv6_filter(efx, PTP_GENERAL_PORT);
if (rc < 0)
goto fail;
}

return 0;

fail:
Expand Down

0 comments on commit 621918c

Please sign in to comment.