Skip to content

Commit 1880bc4

Browse files
Eran Ben ElishaSaeed Mahameed
authored andcommitted
net/mlx5e: Add TX port timestamp support
Transmitted packet timestamping accuracy can be improved when using timestamp from the port, instead of packet CQE creation timestamp, as it better reflects the actual time of a packet's transmit. TX port timestamping is supported starting from ConnectX6-DX hardware. Although at the original completion, only CQE timestamp can be attached, we are able to get TX port timestamping via an additional completion over a special CQ associated with the SQ (in addition to the regular CQ). Driver to ignore the original packet completion timestamp, and report back the timestamp of the special CQ completion. If the absolute timestamp diff between the two completions is greater than 1 / 128 second, ignore the TX port timestamp as it has a jitter which is too big. No skb will be generate out of the extra completion. Allocate additional CQ per ptpsq, to receive the TX port timestamp. Driver to hold an skb FIFO in order to map between transmitted skb to the two expected completions. When using ptpsq, hold double refcount on the skb, to gaurantee it will not get released before both completions arrive. Expose dedicated counters of the ptp additional CQ and connect it to the TX health reporter. This patch improves TX Hardware timestamping offset to be less than 40ns at a 100Gbps line rate, compared to 600ns before. With that, making our HW compliant with G.8273.2 class C, and allow Linux systems to be deployed in the 5G telco edge, where this standard is a must. Signed-off-by: Eran Ben Elisha <[email protected]> Reviewed-by: Tariq Toukan <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 145e563 commit 1880bc4

File tree

9 files changed

+262
-7
lines changed

9 files changed

+262
-7
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,7 @@ struct mlx5e_channel_stats {
718718
struct mlx5e_port_ptp_stats {
719719
struct mlx5e_ch_stats ch;
720720
struct mlx5e_sq_stats sq[MLX5E_MAX_NUM_TC];
721+
struct mlx5e_ptp_cq_stats cq[MLX5E_MAX_NUM_TC];
721722
} ____cacheline_aligned_in_smp;
722723

723724
enum {

drivers/net/ethernet/mellanox/mlx5/core/en/params.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct mlx5e_channel_param {
4444
struct mlx5e_create_sq_param {
4545
struct mlx5_wq_ctrl *wq_ctrl;
4646
u32 cqn;
47+
u32 ts_cqe_to_dest_cqn;
4748
u32 tisn;
4849
u8 tis_lst_sz;
4950
u8 min_inline_mode;

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

Lines changed: 171 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,115 @@
55
#include "en/txrx.h"
66
#include "lib/clock.h"
77

8+
struct mlx5e_skb_cb_hwtstamp {
9+
ktime_t cqe_hwtstamp;
10+
ktime_t port_hwtstamp;
11+
};
12+
13+
void mlx5e_skb_cb_hwtstamp_init(struct sk_buff *skb)
14+
{
15+
memset(skb->cb, 0, sizeof(struct mlx5e_skb_cb_hwtstamp));
16+
}
17+
18+
static struct mlx5e_skb_cb_hwtstamp *mlx5e_skb_cb_get_hwts(struct sk_buff *skb)
19+
{
20+
BUILD_BUG_ON(sizeof(struct mlx5e_skb_cb_hwtstamp) > sizeof(skb->cb));
21+
return (struct mlx5e_skb_cb_hwtstamp *)skb->cb;
22+
}
23+
24+
static void mlx5e_skb_cb_hwtstamp_tx(struct sk_buff *skb,
25+
struct mlx5e_ptp_cq_stats *cq_stats)
26+
{
27+
struct skb_shared_hwtstamps hwts = {};
28+
ktime_t diff;
29+
30+
diff = abs(mlx5e_skb_cb_get_hwts(skb)->port_hwtstamp -
31+
mlx5e_skb_cb_get_hwts(skb)->cqe_hwtstamp);
32+
33+
/* Maximal allowed diff is 1 / 128 second */
34+
if (diff > (NSEC_PER_SEC >> 7)) {
35+
cq_stats->abort++;
36+
cq_stats->abort_abs_diff_ns += diff;
37+
return;
38+
}
39+
40+
hwts.hwtstamp = mlx5e_skb_cb_get_hwts(skb)->port_hwtstamp;
41+
skb_tstamp_tx(skb, &hwts);
42+
}
43+
44+
void mlx5e_skb_cb_hwtstamp_handler(struct sk_buff *skb, int hwtstamp_type,
45+
ktime_t hwtstamp,
46+
struct mlx5e_ptp_cq_stats *cq_stats)
47+
{
48+
switch (hwtstamp_type) {
49+
case (MLX5E_SKB_CB_CQE_HWTSTAMP):
50+
mlx5e_skb_cb_get_hwts(skb)->cqe_hwtstamp = hwtstamp;
51+
break;
52+
case (MLX5E_SKB_CB_PORT_HWTSTAMP):
53+
mlx5e_skb_cb_get_hwts(skb)->port_hwtstamp = hwtstamp;
54+
break;
55+
}
56+
57+
/* If both CQEs arrive, check and report the port tstamp, and clear skb cb as
58+
* skb soon to be released.
59+
*/
60+
if (!mlx5e_skb_cb_get_hwts(skb)->cqe_hwtstamp ||
61+
!mlx5e_skb_cb_get_hwts(skb)->port_hwtstamp)
62+
return;
63+
64+
mlx5e_skb_cb_hwtstamp_tx(skb, cq_stats);
65+
memset(skb->cb, 0, sizeof(struct mlx5e_skb_cb_hwtstamp));
66+
}
67+
68+
static void mlx5e_ptp_handle_ts_cqe(struct mlx5e_ptpsq *ptpsq,
69+
struct mlx5_cqe64 *cqe,
70+
int budget)
71+
{
72+
struct sk_buff *skb = mlx5e_skb_fifo_pop(&ptpsq->skb_fifo);
73+
ktime_t hwtstamp;
74+
75+
if (unlikely(MLX5E_RX_ERR_CQE(cqe))) {
76+
ptpsq->cq_stats->err_cqe++;
77+
goto out;
78+
}
79+
80+
hwtstamp = mlx5_timecounter_cyc2time(ptpsq->txqsq.clock, get_cqe_ts(cqe));
81+
mlx5e_skb_cb_hwtstamp_handler(skb, MLX5E_SKB_CB_PORT_HWTSTAMP,
82+
hwtstamp, ptpsq->cq_stats);
83+
ptpsq->cq_stats->cqe++;
84+
85+
out:
86+
napi_consume_skb(skb, budget);
87+
}
88+
89+
static bool mlx5e_ptp_poll_ts_cq(struct mlx5e_cq *cq, int budget)
90+
{
91+
struct mlx5e_ptpsq *ptpsq = container_of(cq, struct mlx5e_ptpsq, ts_cq);
92+
struct mlx5_cqwq *cqwq = &cq->wq;
93+
struct mlx5_cqe64 *cqe;
94+
int work_done = 0;
95+
96+
if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &ptpsq->txqsq.state)))
97+
return false;
98+
99+
cqe = mlx5_cqwq_get_cqe(cqwq);
100+
if (!cqe)
101+
return false;
102+
103+
do {
104+
mlx5_cqwq_pop(cqwq);
105+
106+
mlx5e_ptp_handle_ts_cqe(ptpsq, cqe, budget);
107+
} while ((++work_done < budget) && (cqe = mlx5_cqwq_get_cqe(cqwq)));
108+
109+
mlx5_cqwq_update_db_record(cqwq);
110+
111+
/* ensure cq space is freed before enabling more cqes */
112+
wmb();
113+
114+
return work_done == budget;
115+
}
116+
8117
static int mlx5e_ptp_napi_poll(struct napi_struct *napi, int budget)
9118
{
10119
struct mlx5e_port_ptp *c = container_of(napi, struct mlx5e_port_ptp,
@@ -18,8 +127,10 @@ static int mlx5e_ptp_napi_poll(struct napi_struct *napi, int budget)
18127

19128
ch_stats->poll++;
20129

21-
for (i = 0; i < c->num_tc; i++)
130+
for (i = 0; i < c->num_tc; i++) {
22131
busy |= mlx5e_poll_tx_cq(&c->ptpsq[i].txqsq.cq, budget);
132+
busy |= mlx5e_ptp_poll_ts_cq(&c->ptpsq[i].ts_cq, budget);
133+
}
23134

24135
if (busy) {
25136
work_done = budget;
@@ -31,8 +142,10 @@ static int mlx5e_ptp_napi_poll(struct napi_struct *napi, int budget)
31142

32143
ch_stats->arm++;
33144

34-
for (i = 0; i < c->num_tc; i++)
145+
for (i = 0; i < c->num_tc; i++) {
35146
mlx5e_cq_arm(&c->ptpsq[i].txqsq.cq);
147+
mlx5e_cq_arm(&c->ptpsq[i].ts_cq);
148+
}
36149

37150
out:
38151
rcu_read_unlock();
@@ -96,6 +209,37 @@ static void mlx5e_ptp_destroy_sq(struct mlx5_core_dev *mdev, u32 sqn)
96209
mlx5_core_destroy_sq(mdev, sqn);
97210
}
98211

212+
static int mlx5e_ptp_alloc_traffic_db(struct mlx5e_ptpsq *ptpsq, int numa)
213+
{
214+
int wq_sz = mlx5_wq_cyc_get_size(&ptpsq->txqsq.wq);
215+
216+
ptpsq->skb_fifo.fifo = kvzalloc_node(array_size(wq_sz, sizeof(*ptpsq->skb_fifo.fifo)),
217+
GFP_KERNEL, numa);
218+
if (!ptpsq->skb_fifo.fifo)
219+
return -ENOMEM;
220+
221+
ptpsq->skb_fifo.pc = &ptpsq->skb_fifo_pc;
222+
ptpsq->skb_fifo.cc = &ptpsq->skb_fifo_cc;
223+
ptpsq->skb_fifo.mask = wq_sz - 1;
224+
225+
return 0;
226+
}
227+
228+
static void mlx5e_ptp_drain_skb_fifo(struct mlx5e_skb_fifo *skb_fifo)
229+
{
230+
while (*skb_fifo->pc != *skb_fifo->cc) {
231+
struct sk_buff *skb = mlx5e_skb_fifo_pop(skb_fifo);
232+
233+
dev_kfree_skb_any(skb);
234+
}
235+
}
236+
237+
static void mlx5e_ptp_free_traffic_db(struct mlx5e_skb_fifo *skb_fifo)
238+
{
239+
mlx5e_ptp_drain_skb_fifo(skb_fifo);
240+
kvfree(skb_fifo->fifo);
241+
}
242+
99243
static int mlx5e_ptp_open_txqsq(struct mlx5e_port_ptp *c, u32 tisn,
100244
int txq_ix, struct mlx5e_ptp_params *cparams,
101245
int tc, struct mlx5e_ptpsq *ptpsq)
@@ -115,11 +259,17 @@ static int mlx5e_ptp_open_txqsq(struct mlx5e_port_ptp *c, u32 tisn,
115259
csp.cqn = txqsq->cq.mcq.cqn;
116260
csp.wq_ctrl = &txqsq->wq_ctrl;
117261
csp.min_inline_mode = txqsq->min_inline_mode;
262+
csp.ts_cqe_to_dest_cqn = ptpsq->ts_cq.mcq.cqn;
118263

119264
err = mlx5e_create_sq_rdy(c->mdev, sqp, &csp, &txqsq->sqn);
120265
if (err)
121266
goto err_free_txqsq;
122267

268+
err = mlx5e_ptp_alloc_traffic_db(ptpsq,
269+
dev_to_node(mlx5_core_dma_dev(c->mdev)));
270+
if (err)
271+
goto err_free_txqsq;
272+
123273
return 0;
124274

125275
err_free_txqsq:
@@ -133,6 +283,7 @@ static void mlx5e_ptp_close_txqsq(struct mlx5e_ptpsq *ptpsq)
133283
struct mlx5e_txqsq *sq = &ptpsq->txqsq;
134284
struct mlx5_core_dev *mdev = sq->mdev;
135285

286+
mlx5e_ptp_free_traffic_db(&ptpsq->skb_fifo);
136287
cancel_work_sync(&sq->recover_work);
137288
mlx5e_ptp_destroy_sq(mdev, sq->sqn);
138289
mlx5e_free_txqsq_descs(sq);
@@ -200,8 +351,23 @@ static int mlx5e_ptp_open_cqs(struct mlx5e_port_ptp *c,
200351
goto out_err_txqsq_cq;
201352
}
202353

354+
for (tc = 0; tc < params->num_tc; tc++) {
355+
struct mlx5e_cq *cq = &c->ptpsq[tc].ts_cq;
356+
struct mlx5e_ptpsq *ptpsq = &c->ptpsq[tc];
357+
358+
err = mlx5e_open_cq(c->priv, ptp_moder, cq_param, &ccp, cq);
359+
if (err)
360+
goto out_err_ts_cq;
361+
362+
ptpsq->cq_stats = &c->priv->port_ptp_stats.cq[tc];
363+
}
364+
203365
return 0;
204366

367+
out_err_ts_cq:
368+
for (--tc; tc >= 0; tc--)
369+
mlx5e_close_cq(&c->ptpsq[tc].ts_cq);
370+
tc = params->num_tc;
205371
out_err_txqsq_cq:
206372
for (--tc; tc >= 0; tc--)
207373
mlx5e_close_cq(&c->ptpsq[tc].txqsq.cq);
@@ -213,6 +379,9 @@ static void mlx5e_ptp_close_cqs(struct mlx5e_port_ptp *c)
213379
{
214380
int tc;
215381

382+
for (tc = 0; tc < c->num_tc; tc++)
383+
mlx5e_close_cq(&c->ptpsq[tc].ts_cq);
384+
216385
for (tc = 0; tc < c->num_tc; tc++)
217386
mlx5e_close_cq(&c->ptpsq[tc].txqsq.cq);
218387
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010

1111
struct mlx5e_ptpsq {
1212
struct mlx5e_txqsq txqsq;
13+
struct mlx5e_cq ts_cq;
14+
u16 skb_fifo_cc;
15+
u16 skb_fifo_pc;
16+
struct mlx5e_skb_fifo skb_fifo;
17+
struct mlx5e_ptp_cq_stats *cq_stats;
1318
};
1419

1520
struct mlx5e_port_ptp {
@@ -45,4 +50,14 @@ void mlx5e_port_ptp_close(struct mlx5e_port_ptp *c);
4550
void mlx5e_ptp_activate_channel(struct mlx5e_port_ptp *c);
4651
void mlx5e_ptp_deactivate_channel(struct mlx5e_port_ptp *c);
4752

53+
enum {
54+
MLX5E_SKB_CB_CQE_HWTSTAMP = BIT(0),
55+
MLX5E_SKB_CB_PORT_HWTSTAMP = BIT(1),
56+
};
57+
58+
void mlx5e_skb_cb_hwtstamp_handler(struct sk_buff *skb, int hwtstamp_type,
59+
ktime_t hwtstamp,
60+
struct mlx5e_ptp_cq_stats *cq_stats);
61+
62+
void mlx5e_skb_cb_hwtstamp_init(struct sk_buff *skb);
4863
#endif /* __MLX5_EN_PTP_H__ */

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

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,19 @@ mlx5e_tx_reporter_build_diagnose_output_ptpsq(struct devlink_fmsg *fmsg,
228228
if (err)
229229
return err;
230230

231-
err = mlx5e_tx_reporter_build_diagnose_output_sq_common(fmsg,
232-
&ptpsq->txqsq,
233-
tc);
231+
err = mlx5e_tx_reporter_build_diagnose_output_sq_common(fmsg, &ptpsq->txqsq, tc);
232+
if (err)
233+
return err;
234+
235+
err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, "Port TS");
236+
if (err)
237+
return err;
238+
239+
err = mlx5e_health_cq_diag_fmsg(&ptpsq->ts_cq, fmsg);
240+
if (err)
241+
return err;
242+
243+
err = mlx5e_health_fmsg_named_obj_nest_end(fmsg);
234244
if (err)
235245
return err;
236246

@@ -270,6 +280,23 @@ mlx5e_tx_reporter_diagnose_generic_txqsq(struct devlink_fmsg *fmsg,
270280
return mlx5e_health_fmsg_named_obj_nest_end(fmsg);
271281
}
272282

283+
static int
284+
mlx5e_tx_reporter_diagnose_generic_tx_port_ts(struct devlink_fmsg *fmsg,
285+
struct mlx5e_ptpsq *ptpsq)
286+
{
287+
int err;
288+
289+
err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, "Port TS");
290+
if (err)
291+
return err;
292+
293+
err = mlx5e_health_cq_common_diag_fmsg(&ptpsq->ts_cq, fmsg);
294+
if (err)
295+
return err;
296+
297+
return mlx5e_health_fmsg_named_obj_nest_end(fmsg);
298+
}
299+
273300
static int
274301
mlx5e_tx_reporter_diagnose_common_config(struct devlink_health_reporter *reporter,
275302
struct devlink_fmsg *fmsg)
@@ -301,6 +328,10 @@ mlx5e_tx_reporter_diagnose_common_config(struct devlink_health_reporter *reporte
301328
if (err)
302329
return err;
303330

331+
err = mlx5e_tx_reporter_diagnose_generic_tx_port_ts(fmsg, generic_ptpsq);
332+
if (err)
333+
return err;
334+
304335
err = mlx5e_health_fmsg_named_obj_nest_end(fmsg);
305336
if (err)
306337
return err;

drivers/net/ethernet/mellanox/mlx5/core/en_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,7 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev,
12061206
MLX5_SET(sqc, sqc, tis_lst_sz, csp->tis_lst_sz);
12071207
MLX5_SET(sqc, sqc, tis_num_0, csp->tisn);
12081208
MLX5_SET(sqc, sqc, cqn, csp->cqn);
1209+
MLX5_SET(sqc, sqc, ts_cqe_to_dest_cqn, csp->ts_cqe_to_dest_cqn);
12091210

12101211
if (MLX5_CAP_ETH(mdev, wqe_inline_mode) == MLX5_CAP_INLINE_MODE_VPORT_CONTEXT)
12111212
MLX5_SET(sqc, sqc, min_wqe_inline_mode, csp->min_inline_mode);

drivers/net/ethernet/mellanox/mlx5/core/en_stats.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,13 @@ static const struct counter_desc ptp_ch_stats_desc[] = {
17331733
{ MLX5E_DECLARE_PTP_CH_STAT(struct mlx5e_ch_stats, eq_rearm) },
17341734
};
17351735

1736+
static const struct counter_desc ptp_cq_stats_desc[] = {
1737+
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, cqe) },
1738+
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, err_cqe) },
1739+
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, abort) },
1740+
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, abort_abs_diff_ns) },
1741+
};
1742+
17361743
#define NUM_RQ_STATS ARRAY_SIZE(rq_stats_desc)
17371744
#define NUM_SQ_STATS ARRAY_SIZE(sq_stats_desc)
17381745
#define NUM_XDPSQ_STATS ARRAY_SIZE(xdpsq_stats_desc)
@@ -1742,11 +1749,13 @@ static const struct counter_desc ptp_ch_stats_desc[] = {
17421749
#define NUM_CH_STATS ARRAY_SIZE(ch_stats_desc)
17431750
#define NUM_PTP_SQ_STATS ARRAY_SIZE(ptp_sq_stats_desc)
17441751
#define NUM_PTP_CH_STATS ARRAY_SIZE(ptp_ch_stats_desc)
1752+
#define NUM_PTP_CQ_STATS ARRAY_SIZE(ptp_cq_stats_desc)
17451753

17461754
static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(ptp)
17471755
{
17481756
return priv->port_ptp_opened ?
1749-
NUM_PTP_CH_STATS + (NUM_PTP_SQ_STATS * priv->max_opened_tc) :
1757+
NUM_PTP_CH_STATS +
1758+
((NUM_PTP_SQ_STATS + NUM_PTP_CQ_STATS) * priv->max_opened_tc) :
17501759
0;
17511760
}
17521761

@@ -1766,6 +1775,10 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(ptp)
17661775
sprintf(data + (idx++) * ETH_GSTRING_LEN,
17671776
ptp_sq_stats_desc[i].format, tc);
17681777

1778+
for (tc = 0; tc < priv->max_opened_tc; tc++)
1779+
for (i = 0; i < NUM_PTP_CQ_STATS; i++)
1780+
sprintf(data + (idx++) * ETH_GSTRING_LEN,
1781+
ptp_cq_stats_desc[i].format, tc);
17691782
return idx;
17701783
}
17711784

@@ -1787,6 +1800,12 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(ptp)
17871800
MLX5E_READ_CTR64_CPU(&priv->port_ptp_stats.sq[tc],
17881801
ptp_sq_stats_desc, i);
17891802

1803+
for (tc = 0; tc < priv->max_opened_tc; tc++)
1804+
for (i = 0; i < NUM_PTP_CQ_STATS; i++)
1805+
data[idx++] =
1806+
MLX5E_READ_CTR64_CPU(&priv->port_ptp_stats.cq[tc],
1807+
ptp_cq_stats_desc, i);
1808+
17901809
return idx;
17911810
}
17921811

0 commit comments

Comments
 (0)