Commit 13a4be41 authored by YiFei Zhu's avatar YiFei Zhu Committed by Tony Nguyen
Browse files

idpf: export RX hardware timestamping information to XDP



The logic is similar to idpf_rx_hwtstamp, but the data is exported
as a BPF kfunc instead of appended to an skb to support grabbing
timestamps in xsk packets.

A idpf_queue_has(PTP, rxq) condition is added to check the queue
supports PTP similar to idpf_rx_process_skb_fields.

Tested using an xsk connection and checking xdp timestamps are
retrievable in received packets.

Cc: intel-wired-lan@lists.osuosl.org
Signed-off-by: default avatarYiFei Zhu <zhuyifei@google.com>
Signed-off-by: default avatarMina Almasry <almasrymina@google.com>
Reviewed-by: default avatarAleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: default avatarAlexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 24f90786
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
/* Copyright (C) 2025 Intel Corporation */

#include "idpf.h"
#include "idpf_ptp.h"
#include "idpf_virtchnl.h"
#include "xdp.h"
#include "xsk.h"
@@ -398,8 +399,38 @@ static int idpf_xdpmo_rx_hash(const struct xdp_md *ctx, u32 *hash,
				    pt);
}

static int idpf_xdpmo_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp)
{
	const struct libeth_xdp_buff *xdp = (typeof(xdp))ctx;
	struct idpf_xdp_rx_desc desc __uninitialized;
	const struct idpf_rx_queue *rxq;
	u64 cached_time, ts_ns;
	u32 ts_high;

	rxq = libeth_xdp_buff_to_rq(xdp, typeof(*rxq), xdp_rxq);

	if (!idpf_queue_has(PTP, rxq))
		return -ENODATA;

	idpf_xdp_get_qw1(&desc, xdp->desc);

	if (!(idpf_xdp_rx_ts_low(&desc) & VIRTCHNL2_RX_FLEX_TSTAMP_VALID))
		return -ENODATA;

	cached_time = READ_ONCE(rxq->cached_phc_time);

	idpf_xdp_get_qw3(&desc, xdp->desc);

	ts_high = idpf_xdp_rx_ts_high(&desc);
	ts_ns = idpf_ptp_tstamp_extend_32b_to_64b(cached_time, ts_high);

	*timestamp = ts_ns;
	return 0;
}

static const struct xdp_metadata_ops idpf_xdpmo = {
	.xmo_rx_hash		= idpf_xdpmo_rx_hash,
	.xmo_rx_timestamp	= idpf_xdpmo_rx_timestamp,
};

void idpf_xdp_set_features(const struct idpf_vport *vport)
+20 −0
Original line number Diff line number Diff line
@@ -112,11 +112,13 @@ struct idpf_xdp_rx_desc {
	aligned_u64		qw1;
#define IDPF_XDP_RX_BUF		GENMASK_ULL(47, 32)
#define IDPF_XDP_RX_EOP		BIT_ULL(1)
#define IDPF_XDP_RX_TS_LOW	GENMASK_ULL(31, 24)

	aligned_u64		qw2;
#define IDPF_XDP_RX_HASH	GENMASK_ULL(31, 0)

	aligned_u64		qw3;
#define IDPF_XDP_RX_TS_HIGH	GENMASK_ULL(63, 32)
} __aligned(4 * sizeof(u64));
static_assert(sizeof(struct idpf_xdp_rx_desc) ==
	      sizeof(struct virtchnl2_rx_flex_desc_adv_nic_3));
@@ -128,6 +130,8 @@ static_assert(sizeof(struct idpf_xdp_rx_desc) ==
#define idpf_xdp_rx_buf(desc)	FIELD_GET(IDPF_XDP_RX_BUF, (desc)->qw1)
#define idpf_xdp_rx_eop(desc)	!!((desc)->qw1 & IDPF_XDP_RX_EOP)
#define idpf_xdp_rx_hash(desc)	FIELD_GET(IDPF_XDP_RX_HASH, (desc)->qw2)
#define idpf_xdp_rx_ts_low(desc)	FIELD_GET(IDPF_XDP_RX_TS_LOW, (desc)->qw1)
#define idpf_xdp_rx_ts_high(desc)	FIELD_GET(IDPF_XDP_RX_TS_HIGH, (desc)->qw3)

static inline void
idpf_xdp_get_qw0(struct idpf_xdp_rx_desc *desc,
@@ -149,6 +153,9 @@ idpf_xdp_get_qw1(struct idpf_xdp_rx_desc *desc,
	desc->qw1 = ((const typeof(desc))rxd)->qw1;
#else
	desc->qw1 = ((u64)le16_to_cpu(rxd->buf_id) << 32) |
		    ((u64)rxd->ts_low << 24) |
		    ((u64)rxd->fflags1 << 16) |
		    ((u64)rxd->status_err1 << 8) |
		    rxd->status_err0_qw1;
#endif
}
@@ -166,6 +173,19 @@ idpf_xdp_get_qw2(struct idpf_xdp_rx_desc *desc,
#endif
}

static inline void
idpf_xdp_get_qw3(struct idpf_xdp_rx_desc *desc,
		 const struct virtchnl2_rx_flex_desc_adv_nic_3 *rxd)
{
#ifdef __LIBETH_WORD_ACCESS
	desc->qw3 = ((const typeof(desc))rxd)->qw3;
#else
	desc->qw3 = ((u64)le32_to_cpu(rxd->ts_high) << 32) |
		    ((u64)le16_to_cpu(rxd->fmd6) << 16) |
		    le16_to_cpu(rxd->l2tag1);
#endif
}

void idpf_xdp_set_features(const struct idpf_vport *vport);

int idpf_xdp(struct net_device *dev, struct netdev_bpf *xdp);