Skip to content

Commit ee7f122

Browse files
Eugenia EmantayevSaeed Mahameed
authored andcommitted
net/mlx5e: Implement 1PPS support
This patch enables the 1PPS IN and 1PPS OUT support according to the advertised HCA capability. Single pin may be configured to one of the above mutual exclusive functions via standard Linux tools and APIs. For example, testptp open source application. Signed-off-by: Eugenia Emantayev <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent f9a1ef7 commit ee7f122

File tree

3 files changed

+232
-1
lines changed

3 files changed

+232
-1
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ struct mlx5e_tstamp {
262262
struct mlx5_core_dev *mdev;
263263
struct ptp_clock *ptp;
264264
struct ptp_clock_info ptp_info;
265+
u8 *pps_pin_caps;
265266
};
266267

267268
enum {
@@ -780,6 +781,8 @@ void mlx5e_fill_hwstamp(struct mlx5e_tstamp *clock, u64 timestamp,
780781
struct skb_shared_hwtstamps *hwts);
781782
void mlx5e_timestamp_init(struct mlx5e_priv *priv);
782783
void mlx5e_timestamp_cleanup(struct mlx5e_priv *priv);
784+
void mlx5e_pps_event_handler(struct mlx5e_priv *priv,
785+
struct ptp_clock_event *event);
783786
int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr);
784787
int mlx5e_hwstamp_get(struct net_device *dev, struct ifreq *ifr);
785788
void mlx5e_modify_rx_cqe_compression(struct mlx5e_priv *priv, bool val);

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

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,22 @@ enum {
3737
MLX5E_CYCLES_SHIFT = 23
3838
};
3939

40+
enum {
41+
MLX5E_PIN_MODE_IN = 0x0,
42+
MLX5E_PIN_MODE_OUT = 0x1,
43+
};
44+
45+
enum {
46+
MLX5E_OUT_PATTERN_PULSE = 0x0,
47+
MLX5E_OUT_PATTERN_PERIODIC = 0x1,
48+
};
49+
50+
enum {
51+
MLX5E_EVENT_MODE_DISABLE = 0x0,
52+
MLX5E_EVENT_MODE_REPETETIVE = 0x1,
53+
MLX5E_EVENT_MODE_ONCE_TILL_ARM = 0x2,
54+
};
55+
4056
void mlx5e_fill_hwstamp(struct mlx5e_tstamp *tstamp, u64 timestamp,
4157
struct skb_shared_hwtstamps *hwts)
4258
{
@@ -189,6 +205,18 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
189205
int neg_adj = 0;
190206
struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
191207
ptp_info);
208+
struct mlx5e_priv *priv =
209+
container_of(tstamp, struct mlx5e_priv, tstamp);
210+
211+
if (MLX5_CAP_GEN(priv->mdev, pps_modify)) {
212+
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
213+
214+
/* For future use need to add a loop for finding all 1PPS out pins */
215+
MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_OUT);
216+
MLX5_SET(mtpps_reg, in, out_periodic_adjustment, delta & 0xFFFF);
217+
218+
mlx5_set_mtpps(priv->mdev, in, sizeof(in));
219+
}
192220

193221
if (delta < 0) {
194222
neg_adj = 1;
@@ -208,6 +236,124 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
208236
return 0;
209237
}
210238

239+
static int mlx5e_extts_configure(struct ptp_clock_info *ptp,
240+
struct ptp_clock_request *rq,
241+
int on)
242+
{
243+
struct mlx5e_tstamp *tstamp =
244+
container_of(ptp, struct mlx5e_tstamp, ptp_info);
245+
struct mlx5e_priv *priv =
246+
container_of(tstamp, struct mlx5e_priv, tstamp);
247+
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
248+
u8 pattern = 0;
249+
int pin = -1;
250+
int err = 0;
251+
252+
if (!MLX5_CAP_GEN(priv->mdev, pps) ||
253+
!MLX5_CAP_GEN(priv->mdev, pps_modify))
254+
return -EOPNOTSUPP;
255+
256+
if (rq->extts.index >= tstamp->ptp_info.n_pins)
257+
return -EINVAL;
258+
259+
if (on) {
260+
pin = ptp_find_pin(tstamp->ptp, PTP_PF_EXTTS, rq->extts.index);
261+
if (pin < 0)
262+
return -EBUSY;
263+
}
264+
265+
if (rq->extts.flags & PTP_FALLING_EDGE)
266+
pattern = 1;
267+
268+
MLX5_SET(mtpps_reg, in, pin, pin);
269+
MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_IN);
270+
MLX5_SET(mtpps_reg, in, pattern, pattern);
271+
MLX5_SET(mtpps_reg, in, enable, on);
272+
273+
err = mlx5_set_mtpps(priv->mdev, in, sizeof(in));
274+
if (err)
275+
return err;
276+
277+
return mlx5_set_mtppse(priv->mdev, pin, 0,
278+
MLX5E_EVENT_MODE_REPETETIVE & on);
279+
}
280+
281+
static int mlx5e_perout_configure(struct ptp_clock_info *ptp,
282+
struct ptp_clock_request *rq,
283+
int on)
284+
{
285+
struct mlx5e_tstamp *tstamp =
286+
container_of(ptp, struct mlx5e_tstamp, ptp_info);
287+
struct mlx5e_priv *priv =
288+
container_of(tstamp, struct mlx5e_priv, tstamp);
289+
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
290+
u64 nsec_now, nsec_delta, time_stamp;
291+
u64 cycles_now, cycles_delta;
292+
struct timespec64 ts;
293+
unsigned long flags;
294+
int pin = -1;
295+
s64 ns;
296+
297+
if (!MLX5_CAP_GEN(priv->mdev, pps_modify))
298+
return -EOPNOTSUPP;
299+
300+
if (rq->perout.index >= tstamp->ptp_info.n_pins)
301+
return -EINVAL;
302+
303+
if (on) {
304+
pin = ptp_find_pin(tstamp->ptp, PTP_PF_PEROUT,
305+
rq->perout.index);
306+
if (pin < 0)
307+
return -EBUSY;
308+
}
309+
310+
ts.tv_sec = rq->perout.period.sec;
311+
ts.tv_nsec = rq->perout.period.nsec;
312+
ns = timespec64_to_ns(&ts);
313+
if (on)
314+
if ((ns >> 1) != 500000000LL)
315+
return -EINVAL;
316+
ts.tv_sec = rq->perout.start.sec;
317+
ts.tv_nsec = rq->perout.start.nsec;
318+
ns = timespec64_to_ns(&ts);
319+
cycles_now = mlx5_read_internal_timer(tstamp->mdev);
320+
write_lock_irqsave(&tstamp->lock, flags);
321+
nsec_now = timecounter_cyc2time(&tstamp->clock, cycles_now);
322+
nsec_delta = ns - nsec_now;
323+
cycles_delta = div64_u64(nsec_delta << tstamp->cycles.shift,
324+
tstamp->cycles.mult);
325+
write_unlock_irqrestore(&tstamp->lock, flags);
326+
time_stamp = cycles_now + cycles_delta;
327+
MLX5_SET(mtpps_reg, in, pin, pin);
328+
MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_OUT);
329+
MLX5_SET(mtpps_reg, in, pattern, MLX5E_OUT_PATTERN_PERIODIC);
330+
MLX5_SET(mtpps_reg, in, enable, on);
331+
MLX5_SET64(mtpps_reg, in, time_stamp, time_stamp);
332+
333+
return mlx5_set_mtpps(priv->mdev, in, sizeof(in));
334+
}
335+
336+
static int mlx5e_ptp_enable(struct ptp_clock_info *ptp,
337+
struct ptp_clock_request *rq,
338+
int on)
339+
{
340+
switch (rq->type) {
341+
case PTP_CLK_REQ_EXTTS:
342+
return mlx5e_extts_configure(ptp, rq, on);
343+
case PTP_CLK_REQ_PEROUT:
344+
return mlx5e_perout_configure(ptp, rq, on);
345+
default:
346+
return -EOPNOTSUPP;
347+
}
348+
return 0;
349+
}
350+
351+
static int mlx5e_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
352+
enum ptp_pin_function func, unsigned int chan)
353+
{
354+
return (func == PTP_PF_PHYSYNC) ? -EOPNOTSUPP : 0;
355+
}
356+
211357
static const struct ptp_clock_info mlx5e_ptp_clock_info = {
212358
.owner = THIS_MODULE,
213359
.max_adj = 100000000,
@@ -221,6 +367,7 @@ static const struct ptp_clock_info mlx5e_ptp_clock_info = {
221367
.gettime64 = mlx5e_ptp_gettime,
222368
.settime64 = mlx5e_ptp_settime,
223369
.enable = NULL,
370+
.verify = NULL,
224371
};
225372

226373
static void mlx5e_timestamp_init_config(struct mlx5e_tstamp *tstamp)
@@ -229,6 +376,62 @@ static void mlx5e_timestamp_init_config(struct mlx5e_tstamp *tstamp)
229376
tstamp->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
230377
}
231378

379+
static int mlx5e_init_pin_config(struct mlx5e_tstamp *tstamp)
380+
{
381+
int i;
382+
383+
tstamp->ptp_info.pin_config =
384+
kzalloc(sizeof(*tstamp->ptp_info.pin_config) *
385+
tstamp->ptp_info.n_pins, GFP_KERNEL);
386+
if (!tstamp->ptp_info.pin_config)
387+
return -ENOMEM;
388+
tstamp->ptp_info.enable = mlx5e_ptp_enable;
389+
tstamp->ptp_info.verify = mlx5e_ptp_verify;
390+
391+
for (i = 0; i < tstamp->ptp_info.n_pins; i++) {
392+
snprintf(tstamp->ptp_info.pin_config[i].name,
393+
sizeof(tstamp->ptp_info.pin_config[i].name),
394+
"mlx5_pps%d", i);
395+
tstamp->ptp_info.pin_config[i].index = i;
396+
tstamp->ptp_info.pin_config[i].func = PTP_PF_NONE;
397+
tstamp->ptp_info.pin_config[i].chan = i;
398+
}
399+
400+
return 0;
401+
}
402+
403+
static void mlx5e_get_pps_caps(struct mlx5e_priv *priv,
404+
struct mlx5e_tstamp *tstamp)
405+
{
406+
u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
407+
408+
mlx5_query_mtpps(priv->mdev, out, sizeof(out));
409+
410+
tstamp->ptp_info.n_pins = MLX5_GET(mtpps_reg, out,
411+
cap_number_of_pps_pins);
412+
tstamp->ptp_info.n_ext_ts = MLX5_GET(mtpps_reg, out,
413+
cap_max_num_of_pps_in_pins);
414+
tstamp->ptp_info.n_per_out = MLX5_GET(mtpps_reg, out,
415+
cap_max_num_of_pps_out_pins);
416+
417+
tstamp->pps_pin_caps[0] = MLX5_GET(mtpps_reg, out, cap_pin_0_mode);
418+
tstamp->pps_pin_caps[1] = MLX5_GET(mtpps_reg, out, cap_pin_1_mode);
419+
tstamp->pps_pin_caps[2] = MLX5_GET(mtpps_reg, out, cap_pin_2_mode);
420+
tstamp->pps_pin_caps[3] = MLX5_GET(mtpps_reg, out, cap_pin_3_mode);
421+
tstamp->pps_pin_caps[4] = MLX5_GET(mtpps_reg, out, cap_pin_4_mode);
422+
tstamp->pps_pin_caps[5] = MLX5_GET(mtpps_reg, out, cap_pin_5_mode);
423+
tstamp->pps_pin_caps[6] = MLX5_GET(mtpps_reg, out, cap_pin_6_mode);
424+
tstamp->pps_pin_caps[7] = MLX5_GET(mtpps_reg, out, cap_pin_7_mode);
425+
}
426+
427+
void mlx5e_pps_event_handler(struct mlx5e_priv *priv,
428+
struct ptp_clock_event *event)
429+
{
430+
struct mlx5e_tstamp *tstamp = &priv->tstamp;
431+
432+
ptp_clock_event(tstamp->ptp, event);
433+
}
434+
232435
void mlx5e_timestamp_init(struct mlx5e_priv *priv)
233436
{
234437
struct mlx5e_tstamp *tstamp = &priv->tstamp;
@@ -272,6 +475,18 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv)
272475
tstamp->ptp_info = mlx5e_ptp_clock_info;
273476
snprintf(tstamp->ptp_info.name, 16, "mlx5 ptp");
274477

478+
/* Initialize 1PPS data structures */
479+
#define MAX_PIN_NUM 8
480+
tstamp->pps_pin_caps = kzalloc(sizeof(u8) * MAX_PIN_NUM, GFP_KERNEL);
481+
if (tstamp->pps_pin_caps) {
482+
if (MLX5_CAP_GEN(priv->mdev, pps))
483+
mlx5e_get_pps_caps(priv, tstamp);
484+
if (tstamp->ptp_info.n_pins)
485+
mlx5e_init_pin_config(tstamp);
486+
} else {
487+
mlx5_core_warn(priv->mdev, "1PPS initialization failed\n");
488+
}
489+
275490
tstamp->ptp = ptp_clock_register(&tstamp->ptp_info,
276491
&priv->mdev->pdev->dev);
277492
if (IS_ERR(tstamp->ptp)) {
@@ -293,5 +508,8 @@ void mlx5e_timestamp_cleanup(struct mlx5e_priv *priv)
293508
priv->tstamp.ptp = NULL;
294509
}
295510

511+
kfree(tstamp->pps_pin_caps);
512+
kfree(tstamp->ptp_info.pin_config);
513+
296514
cancel_delayed_work_sync(&tstamp->overflow_work);
297515
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
317317
enum mlx5_dev_event event, unsigned long param)
318318
{
319319
struct mlx5e_priv *priv = vpriv;
320+
struct ptp_clock_event ptp_event;
321+
struct mlx5_eqe *eqe = NULL;
320322

321323
if (!test_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLED, &priv->state))
322324
return;
@@ -326,7 +328,15 @@ static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
326328
case MLX5_DEV_EVENT_PORT_DOWN:
327329
queue_work(priv->wq, &priv->update_carrier_work);
328330
break;
329-
331+
case MLX5_DEV_EVENT_PPS:
332+
eqe = (struct mlx5_eqe *)param;
333+
ptp_event.type = PTP_CLOCK_EXTTS;
334+
ptp_event.index = eqe->data.pps.pin;
335+
ptp_event.timestamp =
336+
timecounter_cyc2time(&priv->tstamp.clock,
337+
be64_to_cpu(eqe->data.pps.time_stamp));
338+
mlx5e_pps_event_handler(vpriv, &ptp_event);
339+
break;
330340
default:
331341
break;
332342
}

0 commit comments

Comments
 (0)