Skip to content

Commit

Permalink
net/mlx5: Add cyc2time HW translation mode support
Browse files Browse the repository at this point in the history
Device timestamp can be in real time mode (cycles to time translation is
offloaded into the Hardware). With real time mode, HW provides timestamp
which is already translated into nanoseconds.

With this mode, driver adjusts both the HW and timecounter (to keep
clock_info_page updated) using callbacks: adjfreq, adjtime and settime.
HW clock modifications are done via MTUTC access reg commands. Driver is
allowed to modify HW real time clock only if MCAM ptpcyc2realtime_modify
capability is set.

Add MTUTC set function to be used for configuring the HW real time
clock. Modify existing code to support both internal timer (with
conversion via timecounter_cyc2time() and real time (no conversions).

Align the signatures of the helpers converting from timestamp to
nanoseconds. With that, when allocating a queue assign the corresponding
callback with respect to the capability.

Adjust 1PPS timestamp calculation flows based on the timestamp mode.

Cyc2time offload brings two major advantages:
- Improve MTAE (Max Time Absolute Error) for HW TS by up to 160 ns over a
  100% loaded CPU.
- Faster data-path timestamp to nanoseconds, as translation is
  lock-less and done in HW.

On real time mode, timestamp format is 32 high bits of seconds and 32
low bits of nanoseconds. On some flows, driver shall convert this format
into nanoseconds wall-clock with REAL_TIME_TO_NS macro.

HW supports a single clock, and it is shared by all functions on a
device. In case real time clock is used, it is recommended to use
a single GM to all device's functions.

Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com>
Signed-off-by: Aya Levin <ayal@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
  • Loading branch information
Aya Levin authored and Saeed Mahameed committed Feb 16, 2021
1 parent de19cd6 commit 432119d
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 38 deletions.
3 changes: 3 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "en/dcbnl.h"
#include "en/fs.h"
#include "lib/hv_vhca.h"
#include "lib/clock.h"

extern const struct net_device_ops mlx5e_netdev_ops;
struct page_pool;
Expand Down Expand Up @@ -389,6 +390,7 @@ struct mlx5e_txqsq {
u32 rate_limit;
struct work_struct recover_work;
struct mlx5e_ptpsq *ptpsq;
cqe_ts_to_ns ptp_cyc2time;
} ____cacheline_aligned_in_smp;

struct mlx5e_dma_info {
Expand Down Expand Up @@ -650,6 +652,7 @@ struct mlx5e_rq {

/* XDP read-mostly */
struct xdp_rxq_info xdp_rxq;
cqe_ts_to_ns ptp_cyc2time;
} ____cacheline_aligned_in_smp;

enum mlx5e_channel_state {
Expand Down
7 changes: 5 additions & 2 deletions drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#include "en/ptp.h"
#include "en/txrx.h"
#include "lib/clock.h"

struct mlx5e_skb_cb_hwtstamp {
ktime_t cqe_hwtstamp;
Expand Down Expand Up @@ -70,14 +69,15 @@ static void mlx5e_ptp_handle_ts_cqe(struct mlx5e_ptpsq *ptpsq,
int budget)
{
struct sk_buff *skb = mlx5e_skb_fifo_pop(&ptpsq->skb_fifo);
struct mlx5e_txqsq *sq = &ptpsq->txqsq;
ktime_t hwtstamp;

if (unlikely(MLX5E_RX_ERR_CQE(cqe))) {
ptpsq->cq_stats->err_cqe++;
goto out;
}

hwtstamp = mlx5_timecounter_cyc2time(ptpsq->txqsq.clock, get_cqe_ts(cqe));
hwtstamp = mlx5e_cqe_ts_to_ns(sq->ptp_cyc2time, sq->clock, get_cqe_ts(cqe));
mlx5e_skb_cb_hwtstamp_handler(skb, MLX5E_SKB_CB_PORT_HWTSTAMP,
hwtstamp, ptpsq->cq_stats);
ptpsq->cq_stats->cqe++;
Expand Down Expand Up @@ -183,6 +183,9 @@ static int mlx5e_ptp_alloc_txqsq(struct mlx5e_port_ptp *c, int txq_ix,
if (!MLX5_CAP_ETH(mdev, wqe_vlan_insert))
set_bit(MLX5E_SQ_STATE_VLAN_NEED_L2_INLINE, &sq->state);
sq->stop_room = param->stop_room;
sq->ptp_cyc2time = mlx5_is_real_time_sq(mdev) ?
mlx5_real_time_cyc2time :
mlx5_timecounter_cyc2time;

node = dev_to_node(mlx5_core_dma_dev(mdev));

Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@

#define MLX5E_RX_ERR_CQE(cqe) (get_cqe_opcode(cqe) != MLX5_CQE_RESP_SEND)

static inline
ktime_t mlx5e_cqe_ts_to_ns(cqe_ts_to_ns func, struct mlx5_clock *clock, u64 cqe_ts)
{
return INDIRECT_CALL_2(func, mlx5_real_time_cyc2time, mlx5_timecounter_cyc2time,
clock, cqe_ts);
}

enum mlx5e_icosq_wqe_type {
MLX5E_ICOSQ_WQE_NOP,
MLX5E_ICOSQ_WQE_UMR_RX,
Expand Down
18 changes: 17 additions & 1 deletion drivers/net/ethernet/mellanox/mlx5/core/en_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,9 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
rq->xdpsq = &c->rq_xdpsq;
rq->xsk_pool = xsk_pool;
rq->ptp_cyc2time = mlx5_is_real_time_rq(mdev) ?
mlx5_real_time_cyc2time :
mlx5_timecounter_cyc2time;

if (rq->xsk_pool)
rq->stats = &c->priv->channel_stats[c->ix].xskrq;
Expand Down Expand Up @@ -654,7 +657,7 @@ static int mlx5e_create_rq(struct mlx5e_rq *rq,
struct mlx5e_rq_param *param)
{
struct mlx5_core_dev *mdev = rq->mdev;

u8 ts_format;
void *in;
void *rqc;
void *wq;
Expand All @@ -667,13 +670,17 @@ static int mlx5e_create_rq(struct mlx5e_rq *rq,
if (!in)
return -ENOMEM;

ts_format = mlx5_is_real_time_rq(mdev) ?
MLX5_RQC_TIMESTAMP_FORMAT_REAL_TIME :
MLX5_RQC_TIMESTAMP_FORMAT_FREE_RUNNING;
rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
wq = MLX5_ADDR_OF(rqc, rqc, wq);

memcpy(rqc, param->rqc, sizeof(param->rqc));

MLX5_SET(rqc, rqc, cqn, rq->cq.mcq.cqn);
MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST);
MLX5_SET(rqc, rqc, ts_format, ts_format);
MLX5_SET(wq, wq, log_wq_pg_sz, rq->wq_ctrl.buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(wq, wq, dbr_addr, rq->wq_ctrl.db.dma);
Expand Down Expand Up @@ -1154,6 +1161,9 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
if (param->is_mpw)
set_bit(MLX5E_SQ_STATE_MPWQE, &sq->state);
sq->stop_room = param->stop_room;
sq->ptp_cyc2time = mlx5_is_real_time_sq(mdev) ?
mlx5_real_time_cyc2time :
mlx5_timecounter_cyc2time;

param->wq.db_numa_node = cpu_to_node(c->cpu);
err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, wq, &sq->wq_ctrl);
Expand Down Expand Up @@ -1187,6 +1197,7 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev,
struct mlx5e_create_sq_param *csp,
u32 *sqn)
{
u8 ts_format;
void *in;
void *sqc;
void *wq;
Expand All @@ -1199,6 +1210,9 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev,
if (!in)
return -ENOMEM;

ts_format = mlx5_is_real_time_sq(mdev) ?
MLX5_SQC_TIMESTAMP_FORMAT_REAL_TIME :
MLX5_SQC_TIMESTAMP_FORMAT_FREE_RUNNING;
sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
wq = MLX5_ADDR_OF(sqc, sqc, wq);

Expand All @@ -1207,6 +1221,8 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev,
MLX5_SET(sqc, sqc, tis_num_0, csp->tisn);
MLX5_SET(sqc, sqc, cqn, csp->cqn);
MLX5_SET(sqc, sqc, ts_cqe_to_dest_cqn, csp->ts_cqe_to_dest_cqn);
MLX5_SET(sqc, sqc, ts_format, ts_format);


if (MLX5_CAP_ETH(mdev, wqe_inline_mode) == MLX5_CAP_INLINE_MODE_VPORT_CONTEXT)
MLX5_SET(sqc, sqc, min_wqe_inline_mode, csp->min_inline_mode);
Expand Down
11 changes: 4 additions & 7 deletions drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
#include "fpga/ipsec.h"
#include "en_accel/ipsec_rxtx.h"
#include "en_accel/tls_rxtx.h"
#include "lib/clock.h"
#include "en/xdp.h"
#include "en/xsk/rx.h"
#include "en/health.h"
Expand Down Expand Up @@ -1066,9 +1065,8 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
}

if (unlikely(mlx5e_rx_hw_stamp(rq->tstamp)))
skb_hwtstamps(skb)->hwtstamp =
mlx5_timecounter_cyc2time(rq->clock, get_cqe_ts(cqe));

skb_hwtstamps(skb)->hwtstamp = mlx5e_cqe_ts_to_ns(rq->ptp_cyc2time,
rq->clock, get_cqe_ts(cqe));
skb_record_rx_queue(skb, rq->ix);

if (likely(netdev->features & NETIF_F_RXHASH))
Expand Down Expand Up @@ -1667,9 +1665,8 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
}

if (unlikely(mlx5e_rx_hw_stamp(tstamp)))
skb_hwtstamps(skb)->hwtstamp =
mlx5_timecounter_cyc2time(rq->clock, get_cqe_ts(cqe));

skb_hwtstamps(skb)->hwtstamp = mlx5e_cqe_ts_to_ns(rq->ptp_cyc2time,
rq->clock, get_cqe_ts(cqe));
skb_record_rx_queue(skb, rq->ix);

if (likely(netdev->features & NETIF_F_RXHASH))
Expand Down
3 changes: 1 addition & 2 deletions drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
#include "en/txrx.h"
#include "ipoib/ipoib.h"
#include "en_accel/en_accel.h"
#include "lib/clock.h"
#include "en/ptp.h"

static void mlx5e_dma_unmap_wqe_err(struct mlx5e_txqsq *sq, u8 num_dma)
Expand Down Expand Up @@ -774,7 +773,7 @@ static void mlx5e_consume_skb(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct skb_shared_hwtstamps hwts = {};
u64 ts = get_cqe_ts(cqe);

hwts.hwtstamp = mlx5_timecounter_cyc2time(sq->clock, ts);
hwts.hwtstamp = mlx5e_cqe_ts_to_ns(sq->ptp_cyc2time, sq->clock, ts);
if (sq->ptpsq)
mlx5e_skb_cb_hwtstamp_handler(skb, MLX5E_SKB_CB_CQE_HWTSTAMP,
hwts.hwtstamp, sq->ptpsq->cq_stats);
Expand Down
Loading

0 comments on commit 432119d

Please sign in to comment.