drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
Extension
.c
Size
26806 bytes
Lines
1036
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mlx5e_ptp_fs {
	struct mlx5_flow_handle *l2_rule;
	struct mlx5_flow_handle *udp_v4_rule;
	struct mlx5_flow_handle *udp_v6_rule;
	bool valid;
};

struct mlx5e_ptp_params {
	struct mlx5e_params params;
	struct mlx5e_sq_param txq_sq_param;
	struct mlx5e_rq_param rq_param;
};

struct mlx5e_ptp_port_ts_cqe_tracker {
	u8 metadata_id;
	bool inuse : 1;
	struct list_head entry;
};

struct mlx5e_ptp_port_ts_cqe_list {
	struct mlx5e_ptp_port_ts_cqe_tracker *nodes;
	struct list_head tracker_list_head;
	/* Sync list operations in xmit and napi_poll contexts */
	spinlock_t tracker_list_lock;
};

static inline void
mlx5e_ptp_port_ts_cqe_list_add(struct mlx5e_ptp_port_ts_cqe_list *list, u8 metadata)
{
	struct mlx5e_ptp_port_ts_cqe_tracker *tracker = &list->nodes[metadata];

	WARN_ON_ONCE(tracker->inuse);
	tracker->inuse = true;
	spin_lock_bh(&list->tracker_list_lock);
	list_add_tail(&tracker->entry, &list->tracker_list_head);
	spin_unlock_bh(&list->tracker_list_lock);
}

static void
mlx5e_ptp_port_ts_cqe_list_remove(struct mlx5e_ptp_port_ts_cqe_list *list, u8 metadata)
{
	struct mlx5e_ptp_port_ts_cqe_tracker *tracker = &list->nodes[metadata];

	WARN_ON_ONCE(!tracker->inuse);
	tracker->inuse = false;
	spin_lock_bh(&list->tracker_list_lock);
	list_del(&tracker->entry);
	spin_unlock_bh(&list->tracker_list_lock);
}

void mlx5e_ptpsq_track_metadata(struct mlx5e_ptpsq *ptpsq, u8 metadata)
{
	mlx5e_ptp_port_ts_cqe_list_add(ptpsq->ts_cqe_pending_list, metadata);
}

struct mlx5e_skb_cb_hwtstamp {
	ktime_t cqe_hwtstamp;
	ktime_t port_hwtstamp;
};

void mlx5e_skb_cb_hwtstamp_init(struct sk_buff *skb)
{
	memset(skb->cb, 0, sizeof(struct mlx5e_skb_cb_hwtstamp));
}

static struct mlx5e_skb_cb_hwtstamp *mlx5e_skb_cb_get_hwts(struct sk_buff *skb)
{
	BUILD_BUG_ON(sizeof(struct mlx5e_skb_cb_hwtstamp) > sizeof(skb->cb));
	return (struct mlx5e_skb_cb_hwtstamp *)skb->cb;
}

static void mlx5e_skb_cb_hwtstamp_tx(struct sk_buff *skb,
				     struct mlx5e_ptpsq *ptpsq)
{
	struct skb_shared_hwtstamps hwts = {};
	ktime_t diff;

	diff = abs(mlx5e_skb_cb_get_hwts(skb)->port_hwtstamp -
		   mlx5e_skb_cb_get_hwts(skb)->cqe_hwtstamp);

	/* Maximal allowed diff is 1 / 128 second */
	if (diff > (NSEC_PER_SEC >> 7)) {
		struct mlx5e_txqsq *sq = &ptpsq->txqsq;

		ptpsq->cq_stats->abort++;
		ptpsq->cq_stats->abort_abs_diff_ns += diff;
		if (diff > (NSEC_PER_SEC >> 1) &&
		    !test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) {
			netdev_warn(sq->channel->netdev,
				    "PTP TX timestamp difference between CQE and port exceeds threshold: %lld ns, recovering SQ %u\n",

Annotation

Implementation Notes