mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-03 15:51:40 -04:00
net/mlx5: Implement PTM cross timestamping support
Expose Precision Time Measurement support through related PTP ioctl. The performance of PTM on ConnectX-7 was evaluated using both real-time (RTC) and free-running (FRC) clocks under traffic and no traffic conditions. Tests with phc2sys measured the maximum offset values at a 50Hz rate, with and without PTM. Results: 1. No traffic +-----+--------+--------+ | | No-PTM | PTM | +-----+--------+--------+ | FRC | 125 ns | <29 ns | +-----+--------+--------+ | RTC | 248 ns | <34 ns | +-----+--------+--------+ 2. With traffic +-----+--------+--------+ | | No-PTM | PTM | +-----+--------+--------+ | FRC | 254 ns | <40 ns | +-----+--------+--------+ | RTC | 255 ns | <45 ns | +-----+--------+--------+ Signed-off-by: Rahul Rameshbabu <rrameshbabu@nvidia.com> Co-developed-by: Carolina Jubran <cjubran@nvidia.com> Signed-off-by: Carolina Jubran <cjubran@nvidia.com> Signed-off-by: Tariq Toukan <tariqt@nvidia.com> Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com> Tested-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20240730134055.1835261-4-tariqt@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
bec6d85d43
commit
d17125fb09
@@ -38,6 +38,10 @@
|
||||
#include "lib/eq.h"
|
||||
#include "en.h"
|
||||
#include "clock.h"
|
||||
#ifdef CONFIG_X86
|
||||
#include <linux/timekeeping.h>
|
||||
#include <linux/cpufeature.h>
|
||||
#endif /* CONFIG_X86 */
|
||||
|
||||
enum {
|
||||
MLX5_PIN_MODE_IN = 0x0,
|
||||
@@ -148,6 +152,87 @@ static int mlx5_set_mtutc(struct mlx5_core_dev *dev, u32 *mtutc, u32 size)
|
||||
MLX5_REG_MTUTC, 0, 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
static bool mlx5_is_ptm_source_time_available(struct mlx5_core_dev *dev)
|
||||
{
|
||||
u32 out[MLX5_ST_SZ_DW(mtptm_reg)] = {0};
|
||||
u32 in[MLX5_ST_SZ_DW(mtptm_reg)] = {0};
|
||||
int err;
|
||||
|
||||
if (!MLX5_CAP_MCAM_REG3(dev, mtptm))
|
||||
return false;
|
||||
|
||||
err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), MLX5_REG_MTPTM,
|
||||
0, 0);
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
return !!MLX5_GET(mtptm_reg, out, psta);
|
||||
}
|
||||
|
||||
static int mlx5_mtctr_syncdevicetime(ktime_t *device_time,
|
||||
struct system_counterval_t *sys_counterval,
|
||||
void *ctx)
|
||||
{
|
||||
u32 out[MLX5_ST_SZ_DW(mtctr_reg)] = {0};
|
||||
u32 in[MLX5_ST_SZ_DW(mtctr_reg)] = {0};
|
||||
struct mlx5_core_dev *mdev = ctx;
|
||||
bool real_time_mode;
|
||||
u64 host, device;
|
||||
int err;
|
||||
|
||||
real_time_mode = mlx5_real_time_mode(mdev);
|
||||
|
||||
MLX5_SET(mtctr_reg, in, first_clock_timestamp_request,
|
||||
MLX5_MTCTR_REQUEST_PTM_ROOT_CLOCK);
|
||||
MLX5_SET(mtctr_reg, in, second_clock_timestamp_request,
|
||||
real_time_mode ? MLX5_MTCTR_REQUEST_REAL_TIME_CLOCK :
|
||||
MLX5_MTCTR_REQUEST_FREE_RUNNING_COUNTER);
|
||||
|
||||
err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), MLX5_REG_MTCTR,
|
||||
0, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!MLX5_GET(mtctr_reg, out, first_clock_valid) ||
|
||||
!MLX5_GET(mtctr_reg, out, second_clock_valid))
|
||||
return -EINVAL;
|
||||
|
||||
host = MLX5_GET64(mtctr_reg, out, first_clock_timestamp);
|
||||
*sys_counterval = (struct system_counterval_t) {
|
||||
.cycles = host,
|
||||
.cs_id = CSID_X86_ART,
|
||||
.use_nsecs = true,
|
||||
};
|
||||
|
||||
device = MLX5_GET64(mtctr_reg, out, second_clock_timestamp);
|
||||
if (real_time_mode)
|
||||
*device_time = ns_to_ktime(REAL_TIME_TO_NS(device >> 32, device & U32_MAX));
|
||||
else
|
||||
*device_time = mlx5_timecounter_cyc2time(&mdev->clock, device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5_ptp_getcrosststamp(struct ptp_clock_info *ptp,
|
||||
struct system_device_crosststamp *cts)
|
||||
{
|
||||
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
||||
struct system_time_snapshot history_begin = {0};
|
||||
struct mlx5_core_dev *mdev;
|
||||
|
||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
||||
|
||||
if (!mlx5_is_ptm_source_time_available(mdev))
|
||||
return -EBUSY;
|
||||
|
||||
ktime_get_snapshot(&history_begin);
|
||||
|
||||
return get_device_system_crosststamp(mlx5_mtctr_syncdevicetime, mdev,
|
||||
&history_begin, cts);
|
||||
}
|
||||
#endif /* CONFIG_X86 */
|
||||
|
||||
static u64 mlx5_read_time(struct mlx5_core_dev *dev,
|
||||
struct ptp_system_timestamp *sts,
|
||||
bool real_time)
|
||||
@@ -1034,6 +1119,12 @@ static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev)
|
||||
if (MLX5_CAP_MCAM_REG(mdev, mtutc))
|
||||
mlx5_init_timer_max_freq_adjustment(mdev);
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
if (MLX5_CAP_MCAM_REG3(mdev, mtptm) &&
|
||||
MLX5_CAP_MCAM_REG3(mdev, mtctr) && boot_cpu_has(X86_FEATURE_ART))
|
||||
clock->ptp_info.getcrosststamp = mlx5_ptp_getcrosststamp;
|
||||
#endif /* CONFIG_X86 */
|
||||
|
||||
mlx5_timecounter_init(mdev);
|
||||
mlx5_init_clock_info(mdev);
|
||||
mlx5_init_overflow_period(clock);
|
||||
|
||||
Reference in New Issue
Block a user