#include <linux/types.h>
#include <linux/if_ether.h>
+#include <linux/in6.h>
#include <asm/byteorder.h>
/**
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
#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
}
}
-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;
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;
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: