aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Stewart <rrs@FreeBSD.org>2022-09-20 17:12:16 +0000
committerRandall Stewart <rrs@FreeBSD.org>2022-09-20 17:12:16 +0000
commit7cc3ea9c6f8b99315b671c7bd75a03f8f1cdc8e3 (patch)
treea9fbee0ab09c3a8a0a08399450740b01cec278f4
parent06a400d76be90bc0ccf6110a1e614d60bafb0f6c (diff)
downloadsrc-7cc3ea9c6f8b99315b671c7bd75a03f8f1cdc8e3.tar.gz
src-7cc3ea9c6f8b99315b671c7bd75a03f8f1cdc8e3.zip
mlx5 M_TSTMP accuracy looses quite a bit of precision so lets fix it.
The way that the clock is synchronized between the system and the current mlx5 for the purposes of the M_TSTMP being carried we loose a lot of precision. Instead lets change the math that calculates this to separate out the seconds/nanoseconds and operate on the two values so we don't get overflow instead of just shifting the value down and loosing precision. Reviewed by: kib, hselasky Sponsored by: Netflix Inc Differential Revision: https://reviews.freebsd.org/D36327
-rw-r--r--sys/dev/mlx5/mlx5_en/en.h1
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_main.c2
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_rx.c64
3 files changed, 52 insertions, 15 deletions
diff --git a/sys/dev/mlx5/mlx5_en/en.h b/sys/dev/mlx5/mlx5_en/en.h
index 9eeb8c1a396d..d24383f4c927 100644
--- a/sys/dev/mlx5/mlx5_en/en.h
+++ b/sys/dev/mlx5/mlx5_en/en.h
@@ -1144,6 +1144,7 @@ struct mlx5e_priv {
int clbr_curr;
struct mlx5e_clbr_point clbr_points[2];
u_int clbr_gen;
+ uint64_t cclk;
struct mlx5e_dcbx dcbx;
bool sw_is_port_buf_owner;
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
index 0cae0696a180..47bf627ed7af 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
@@ -4797,6 +4797,8 @@ mlx5e_create_ifp(struct mlx5_core_dev *mdev)
&priv->clbr_done, 0,
"RX timestamps calibration state");
callout_init(&priv->tstmp_clbr, 1);
+ /* Pull out the frequency of the clock in hz */
+ priv->cclk = (uint64_t)MLX5_CAP_GEN(mdev, device_frequency_khz) * 1000ULL;
mlx5e_reset_calibration_callout(priv);
pa.pa_version = PFIL_VERSION;
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
index 6d8c36299ca1..f6caddfdf933 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
@@ -214,7 +214,10 @@ static uint64_t
mlx5e_mbuf_tstmp(struct mlx5e_priv *priv, uint64_t hw_tstmp)
{
struct mlx5e_clbr_point *cp, dcp;
- uint64_t a1, a2, res;
+ uint64_t tstmp_sec, tstmp_nsec;
+ uint64_t hw_clocks;
+ uint64_t rt_cur_to_prev, res_s, res_n, res_s_modulo, res;
+ uint64_t hw_clk_div;
u_int gen;
do {
@@ -224,19 +227,49 @@ mlx5e_mbuf_tstmp(struct mlx5e_priv *priv, uint64_t hw_tstmp)
return (0);
dcp = *cp;
atomic_thread_fence_acq();
- } while (gen != cp->clbr_gen);
-
- a1 = (hw_tstmp - dcp.clbr_hw_prev) >> MLX5E_TSTMP_PREC;
- a2 = (dcp.base_curr - dcp.base_prev) >> MLX5E_TSTMP_PREC;
- res = (a1 * a2) << MLX5E_TSTMP_PREC;
-
+ } while (gen != dcp.clbr_gen);
/*
- * Divisor cannot be zero because calibration callback
- * checks for the condition and disables timestamping
- * if clock halted.
+ * Our goal here is to have a result that is:
+ *
+ * ( (cur_time - prev_time) )
+ * ((hw_tstmp - hw_prev) * ----------------------------- ) + prev_time
+ * ( (hw_cur - hw_prev) )
+ *
+ * With the constraints that we cannot use float and we
+ * don't want to overflow the uint64_t numbers we are using.
+ *
+ * The plan is to take the clocking value of the hw timestamps
+ * and split them into seconds and nanosecond equivalent portions.
+ * Then we operate on the two portions seperately making sure to
+ * bring back the carry over from the seconds when we divide.
+ *
+ * First up lets get the two divided into separate entities
+ * i.e. the seconds. We use the clock frequency for this.
+ * Note that priv->cclk was setup with the clock frequency
+ * in hz so we are all set to go.
*/
- res /= (dcp.clbr_hw_curr - dcp.clbr_hw_prev) >> MLX5E_TSTMP_PREC;
-
+ hw_clocks = hw_tstmp - dcp.clbr_hw_prev;
+ tstmp_sec = hw_clocks / priv->cclk;
+ tstmp_nsec = hw_clocks % priv->cclk;
+ /* Now work with them separately */
+ rt_cur_to_prev = (dcp.base_curr - dcp.base_prev);
+ res_s = tstmp_sec * rt_cur_to_prev;
+ res_n = tstmp_nsec * rt_cur_to_prev;
+ /* Now lets get our divider */
+ hw_clk_div = dcp.clbr_hw_curr - dcp.clbr_hw_prev;
+ /* Make sure to save the remainder from the seconds divide */
+ res_s_modulo = res_s % hw_clk_div;
+ res_s /= hw_clk_div;
+ /* scale the remainder to where it should be */
+ res_s_modulo *= priv->cclk;
+ /* Now add in the remainder */
+ res_n += res_s_modulo;
+ /* Now do the divide */
+ res_n /= hw_clk_div;
+ res_s *= priv->cclk;
+ /* Recombine the two */
+ res = res_s + res_n;
+ /* And now add in the base time to get to the real timestamp */
res += dcp.base_prev;
return (res);
}
@@ -370,10 +403,11 @@ mlx5e_build_rx_mbuf(struct mlx5_cqe64 *cqe,
tstmp &= ~MLX5_CQE_TSTMP_PTP;
mb->m_flags |= M_TSTMP_HPREC;
}
- mb->m_pkthdr.rcv_tstmp = tstmp;
- mb->m_flags |= M_TSTMP;
+ if (tstmp != 0) {
+ mb->m_pkthdr.rcv_tstmp = tstmp;
+ mb->m_flags |= M_TSTMP;
+ }
}
-
switch (get_cqe_tls_offload(cqe)) {
case CQE_TLS_OFFLOAD_DECRYPTED:
/* set proper checksum flag for decrypted packets */