Commit eec9de03 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlx5-ptm-cross-timestamping-support'

Tariq Toukan says:

====================
mlx5 PTM cross timestamping support

This patchset by Rahul and Carolina adds PTM (Precision Time Measurement)
support to the mlx5 driver.

PTM is a PCI extended capability introduced by PCI-SIG for providing an
accurate read of the device clock offset without being impacted by
asymmetric bus transfer rates.

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 |
+-----+--------+--------+

v2: https://lore.kernel.org/d1dba3e1-2ecc-4fdf-a23b-7696c4bccf45@gmail.com
====================

Link: https://patch.msgid.link/20240730134055.1835261-1-tariqt@nvidia.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents e8fc78eb d17125fb
...@@ -224,6 +224,7 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev) ...@@ -224,6 +224,7 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
if (MLX5_CAP_GEN(dev, mcam_reg)) { if (MLX5_CAP_GEN(dev, mcam_reg)) {
mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_FIRST_128); mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_FIRST_128);
mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9100_0x917F); mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9100_0x917F);
mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9180_0x91FF);
} }
if (MLX5_CAP_GEN(dev, qcam_reg)) if (MLX5_CAP_GEN(dev, qcam_reg))
......
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
#include "lib/eq.h" #include "lib/eq.h"
#include "en.h" #include "en.h"
#include "clock.h" #include "clock.h"
#ifdef CONFIG_X86
#include <linux/timekeeping.h>
#include <linux/cpufeature.h>
#endif /* CONFIG_X86 */
enum { enum {
MLX5_PIN_MODE_IN = 0x0, MLX5_PIN_MODE_IN = 0x0,
...@@ -148,6 +152,87 @@ static int mlx5_set_mtutc(struct mlx5_core_dev *dev, u32 *mtutc, u32 size) ...@@ -148,6 +152,87 @@ static int mlx5_set_mtutc(struct mlx5_core_dev *dev, u32 *mtutc, u32 size)
MLX5_REG_MTUTC, 0, 1); 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, static u64 mlx5_read_time(struct mlx5_core_dev *dev,
struct ptp_system_timestamp *sts, struct ptp_system_timestamp *sts,
bool real_time) bool real_time)
...@@ -1034,6 +1119,12 @@ static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev) ...@@ -1034,6 +1119,12 @@ static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev)
if (MLX5_CAP_MCAM_REG(mdev, mtutc)) if (MLX5_CAP_MCAM_REG(mdev, mtutc))
mlx5_init_timer_max_freq_adjustment(mdev); 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_timecounter_init(mdev);
mlx5_init_clock_info(mdev); mlx5_init_clock_info(mdev);
mlx5_init_overflow_period(clock); mlx5_init_overflow_period(clock);
......
...@@ -923,6 +923,11 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev, ...@@ -923,6 +923,11 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev,
} }
mlx5_pci_vsc_init(dev); mlx5_pci_vsc_init(dev);
err = pci_enable_ptm(pdev, NULL);
if (err)
mlx5_core_info(dev, "PTM is not supported by PCIe\n");
return 0; return 0;
err_clr_master: err_clr_master:
...@@ -939,6 +944,7 @@ static void mlx5_pci_close(struct mlx5_core_dev *dev) ...@@ -939,6 +944,7 @@ static void mlx5_pci_close(struct mlx5_core_dev *dev)
* before removing the pci bars * before removing the pci bars
*/ */
mlx5_drain_health_wq(dev); mlx5_drain_health_wq(dev);
pci_disable_ptm(dev->pdev);
iounmap(dev->iseg); iounmap(dev->iseg);
release_bar(dev->pdev); release_bar(dev->pdev);
mlx5_pci_disable_device(dev); mlx5_pci_disable_device(dev);
......
...@@ -1243,7 +1243,8 @@ enum mlx5_pcam_feature_groups { ...@@ -1243,7 +1243,8 @@ enum mlx5_pcam_feature_groups {
enum mlx5_mcam_reg_groups { enum mlx5_mcam_reg_groups {
MLX5_MCAM_REGS_FIRST_128 = 0x0, MLX5_MCAM_REGS_FIRST_128 = 0x0,
MLX5_MCAM_REGS_0x9100_0x917F = 0x2, MLX5_MCAM_REGS_0x9100_0x917F = 0x2,
MLX5_MCAM_REGS_NUM = 0x3, MLX5_MCAM_REGS_0x9180_0x91FF = 0x3,
MLX5_MCAM_REGS_NUM = 0x4,
}; };
enum mlx5_mcam_feature_groups { enum mlx5_mcam_feature_groups {
...@@ -1392,6 +1393,10 @@ enum mlx5_qcam_feature_groups { ...@@ -1392,6 +1393,10 @@ enum mlx5_qcam_feature_groups {
MLX5_GET(mcam_reg, (mdev)->caps.mcam[MLX5_MCAM_REGS_0x9100_0x917F], \ MLX5_GET(mcam_reg, (mdev)->caps.mcam[MLX5_MCAM_REGS_0x9100_0x917F], \
mng_access_reg_cap_mask.access_regs2.reg) mng_access_reg_cap_mask.access_regs2.reg)
#define MLX5_CAP_MCAM_REG3(mdev, reg) \
MLX5_GET(mcam_reg, (mdev)->caps.mcam[MLX5_MCAM_REGS_0x9180_0x91FF], \
mng_access_reg_cap_mask.access_regs3.reg)
#define MLX5_CAP_MCAM_FEATURE(mdev, fld) \ #define MLX5_CAP_MCAM_FEATURE(mdev, fld) \
MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_feature_cap_mask.enhanced_features.fld) MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_feature_cap_mask.enhanced_features.fld)
......
...@@ -159,6 +159,8 @@ enum { ...@@ -159,6 +159,8 @@ enum {
MLX5_REG_MSECQ = 0x9155, MLX5_REG_MSECQ = 0x9155,
MLX5_REG_MSEES = 0x9156, MLX5_REG_MSEES = 0x9156,
MLX5_REG_MIRC = 0x9162, MLX5_REG_MIRC = 0x9162,
MLX5_REG_MTPTM = 0x9180,
MLX5_REG_MTCTR = 0x9181,
MLX5_REG_SBCAM = 0xB01F, MLX5_REG_SBCAM = 0xB01F,
MLX5_REG_RESOURCE_DUMP = 0xC000, MLX5_REG_RESOURCE_DUMP = 0xC000,
MLX5_REG_DTOR = 0xC00E, MLX5_REG_DTOR = 0xC00E,
......
...@@ -10401,6 +10401,18 @@ struct mlx5_ifc_mcam_access_reg_bits2 { ...@@ -10401,6 +10401,18 @@ struct mlx5_ifc_mcam_access_reg_bits2 {
u8 regs_31_to_0[0x20]; u8 regs_31_to_0[0x20];
}; };
struct mlx5_ifc_mcam_access_reg_bits3 {
u8 regs_127_to_96[0x20];
u8 regs_95_to_64[0x20];
u8 regs_63_to_32[0x20];
u8 regs_31_to_2[0x1e];
u8 mtctr[0x1];
u8 mtptm[0x1];
};
struct mlx5_ifc_mcam_reg_bits { struct mlx5_ifc_mcam_reg_bits {
u8 reserved_at_0[0x8]; u8 reserved_at_0[0x8];
u8 feature_group[0x8]; u8 feature_group[0x8];
...@@ -10413,6 +10425,7 @@ struct mlx5_ifc_mcam_reg_bits { ...@@ -10413,6 +10425,7 @@ struct mlx5_ifc_mcam_reg_bits {
struct mlx5_ifc_mcam_access_reg_bits access_regs; struct mlx5_ifc_mcam_access_reg_bits access_regs;
struct mlx5_ifc_mcam_access_reg_bits1 access_regs1; struct mlx5_ifc_mcam_access_reg_bits1 access_regs1;
struct mlx5_ifc_mcam_access_reg_bits2 access_regs2; struct mlx5_ifc_mcam_access_reg_bits2 access_regs2;
struct mlx5_ifc_mcam_access_reg_bits3 access_regs3;
u8 reserved_at_0[0x80]; u8 reserved_at_0[0x80];
} mng_access_reg_cap_mask; } mng_access_reg_cap_mask;
...@@ -11166,6 +11179,34 @@ struct mlx5_ifc_mtmp_reg_bits { ...@@ -11166,6 +11179,34 @@ struct mlx5_ifc_mtmp_reg_bits {
u8 sensor_name_lo[0x20]; u8 sensor_name_lo[0x20];
}; };
struct mlx5_ifc_mtptm_reg_bits {
u8 reserved_at_0[0x10];
u8 psta[0x1];
u8 reserved_at_11[0xf];
u8 reserved_at_20[0x60];
};
enum {
MLX5_MTCTR_REQUEST_NOP = 0x0,
MLX5_MTCTR_REQUEST_PTM_ROOT_CLOCK = 0x1,
MLX5_MTCTR_REQUEST_FREE_RUNNING_COUNTER = 0x2,
MLX5_MTCTR_REQUEST_REAL_TIME_CLOCK = 0x3,
};
struct mlx5_ifc_mtctr_reg_bits {
u8 first_clock_timestamp_request[0x8];
u8 second_clock_timestamp_request[0x8];
u8 reserved_at_10[0x10];
u8 first_clock_valid[0x1];
u8 second_clock_valid[0x1];
u8 reserved_at_22[0x1e];
u8 first_clock_timestamp[0x40];
u8 second_clock_timestamp[0x40];
};
union mlx5_ifc_ports_control_registers_document_bits { union mlx5_ifc_ports_control_registers_document_bits {
struct mlx5_ifc_bufferx_reg_bits bufferx_reg; struct mlx5_ifc_bufferx_reg_bits bufferx_reg;
struct mlx5_ifc_eth_2819_cntrs_grp_data_layout_bits eth_2819_cntrs_grp_data_layout; struct mlx5_ifc_eth_2819_cntrs_grp_data_layout_bits eth_2819_cntrs_grp_data_layout;
...@@ -11230,6 +11271,8 @@ union mlx5_ifc_ports_control_registers_document_bits { ...@@ -11230,6 +11271,8 @@ union mlx5_ifc_ports_control_registers_document_bits {
struct mlx5_ifc_mrtc_reg_bits mrtc_reg; struct mlx5_ifc_mrtc_reg_bits mrtc_reg;
struct mlx5_ifc_mtcap_reg_bits mtcap_reg; struct mlx5_ifc_mtcap_reg_bits mtcap_reg;
struct mlx5_ifc_mtmp_reg_bits mtmp_reg; struct mlx5_ifc_mtmp_reg_bits mtmp_reg;
struct mlx5_ifc_mtptm_reg_bits mtptm_reg;
struct mlx5_ifc_mtctr_reg_bits mtctr_reg;
u8 reserved_at_0[0x60e0]; u8 reserved_at_0[0x60e0];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment