Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177514317
D61430.1794597964.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
4 KB
Referenced Files
None
Subscribers
None
D61430.1794597964.diff
View Options
diff --git a/sys/dev/mlx5/mlx5_en/en.h b/sys/dev/mlx5/mlx5_en/en.h
--- a/sys/dev/mlx5/mlx5_en/en.h
+++ b/sys/dev/mlx5/mlx5_en/en.h
@@ -1055,6 +1055,7 @@
#include <dev/mlx5/mlx5_en/en_hw_tls_rx.h>
#define MLX5E_TSTMP_PREC 10
+#define MLX5E_TSTMP_SPLIT 20
struct mlx5e_clbr_point {
uint64_t base_curr;
@@ -1142,7 +1143,6 @@
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
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
@@ -5089,8 +5089,6 @@
&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
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
@@ -261,9 +261,8 @@
mlx5e_mbuf_tstmp(struct mlx5e_priv *priv, uint64_t hw_tstmp)
{
struct mlx5e_clbr_point *cp, dcp;
- 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 rt_cur_to_prev, res_ivl, res_hi, res_lo, res_hi_modulo, res;
uint64_t hw_clk_div;
u_int gen;
@@ -285,37 +284,46 @@
* 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.
+ * The plan is to first take out of the hw timestamp delta the
+ * whole calibration intervals it contains. Each of them
+ * converts to exactly (cur_time - prev_time), and what is left
+ * is shorter than one calibration interval, so the rest of the
+ * computation does not depend on how far the timestamp is from
+ * the calibration point.
*
- * 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.
+ * Then we split what is left into high and low parts at
+ * 2^MLX5E_TSTMP_SPLIT clocks, and operate on the two parts
+ * seperately, making sure to bring back the carry over from the
+ * high part when we divide. The low part is less than
+ * 2^MLX5E_TSTMP_SPLIT and is multiplied by the calibration
+ * interval in nanoseconds. The carry over is less than the
+ * calibration interval in clocks and is multiplied by
+ * 2^MLX5E_TSTMP_SPLIT. The split must be small enough to keep
+ * both products within uint64_t for fast clocks and long
+ * calibration intervals.
+ *
+ * hw_clk_div cannot be zero, mlx5e_calibration_callout() does
+ * not publish a calibration point unless the hw clock advanced.
*/
- 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 */
+ rt_cur_to_prev = dcp.base_curr - dcp.base_prev;
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;
+ hw_clocks = hw_tstmp - dcp.clbr_hw_prev;
+ /* Take out the whole calibration intervals */
+ res_ivl = (hw_clocks / hw_clk_div) * rt_cur_to_prev;
+ hw_clocks %= hw_clk_div;
+ /* Now split the rest and work with the parts separately */
+ res_hi = (hw_clocks >> MLX5E_TSTMP_SPLIT) * rt_cur_to_prev;
+ res_lo = (hw_clocks & ((1ULL << MLX5E_TSTMP_SPLIT) - 1)) *
+ rt_cur_to_prev;
+ /* Make sure to save the remainder from the high part divide */
+ res_hi_modulo = res_hi % hw_clk_div;
+ res_hi /= hw_clk_div;
+ /* Scale the remainder to where it should be and add it in */
+ res_lo += res_hi_modulo << MLX5E_TSTMP_SPLIT;
/* Now do the divide */
- res_n /= hw_clk_div;
- res_s *= priv->cclk;
- /* Recombine the two */
- res = res_s + res_n;
+ res_lo /= hw_clk_div;
+ /* Recombine the three */
+ res = res_ivl + (res_hi << MLX5E_TSTMP_SPLIT) + res_lo;
/* And now add in the base time to get to the real timestamp */
res += dcp.base_prev;
return (res);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 13, 7:26 PM (8 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41707405
Default Alt Text
D61430.1794597964.diff (4 KB)
Attached To
Mode
D61430: mlx5en: fix RX HW timestamp overflow with 1GHz clock
Attached
Detach File
Event Timeline