diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2024-08-05 16:44:46 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2024-08-05 16:44:47 -0700 |
| commit | eec9de0354105527e31394c0ed4b8c54fb1fe1dd (patch) | |
| tree | e2b9b7af6bb75a604e6b5a9d4b6d7c5ee1ff6478 | |
| parent | e8fc78eb658a1ebcb871e93bbe4f18e9d51fdd3a (diff) | |
| parent | d17125fb0923228fb3cc1e03790de4ee88f7f95f (diff) | |
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.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fw.c | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c | 91 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/main.c | 6 | ||||
| -rw-r--r-- | include/linux/mlx5/device.h | 7 | ||||
| -rw-r--r-- | include/linux/mlx5/driver.h | 2 | ||||
| -rw-r--r-- | include/linux/mlx5/mlx5_ifc.h | 43 |
6 files changed, 149 insertions, 1 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index b61b7d966114..76ad46bf477d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -224,6 +224,7 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev) 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_0x9100_0x917F); + mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9180_0x91FF); } if (MLX5_CAP_GEN(dev, qcam_reg)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index 0361741632a6..b306ae79bf97 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -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); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 5b7e6f4b5c7e..4b88d969a66c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -923,6 +923,11 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev, } 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; err_clr_master: @@ -939,6 +944,7 @@ static void mlx5_pci_close(struct mlx5_core_dev *dev) * before removing the pci bars */ mlx5_drain_health_wq(dev); + pci_disable_ptm(dev->pdev); iounmap(dev->iseg); release_bar(dev->pdev); mlx5_pci_disable_device(dev); diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index ba875a619b97..a94bc9e3af96 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -1243,7 +1243,8 @@ enum mlx5_pcam_feature_groups { enum mlx5_mcam_reg_groups { MLX5_MCAM_REGS_FIRST_128 = 0x0, 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 { @@ -1392,6 +1393,10 @@ enum mlx5_qcam_feature_groups { MLX5_GET(mcam_reg, (mdev)->caps.mcam[MLX5_MCAM_REGS_0x9100_0x917F], \ 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) \ MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_feature_cap_mask.enhanced_features.fld) diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index a96438ded15f..9f42834f57c5 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -159,6 +159,8 @@ enum { MLX5_REG_MSECQ = 0x9155, MLX5_REG_MSEES = 0x9156, MLX5_REG_MIRC = 0x9162, + MLX5_REG_MTPTM = 0x9180, + MLX5_REG_MTCTR = 0x9181, MLX5_REG_SBCAM = 0xB01F, MLX5_REG_RESOURCE_DUMP = 0xC000, MLX5_REG_DTOR = 0xC00E, diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index cab228cf51c6..234ad6f16e92 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -10401,6 +10401,18 @@ struct mlx5_ifc_mcam_access_reg_bits2 { 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 { u8 reserved_at_0[0x8]; u8 feature_group[0x8]; @@ -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_bits1 access_regs1; struct mlx5_ifc_mcam_access_reg_bits2 access_regs2; + struct mlx5_ifc_mcam_access_reg_bits3 access_regs3; u8 reserved_at_0[0x80]; } mng_access_reg_cap_mask; @@ -11166,6 +11179,34 @@ struct mlx5_ifc_mtmp_reg_bits { 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 { struct mlx5_ifc_bufferx_reg_bits bufferx_reg; 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 { struct mlx5_ifc_mrtc_reg_bits mrtc_reg; struct mlx5_ifc_mtcap_reg_bits mtcap_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]; }; |
