diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index 214d732d18e9..7ad3baca99de 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -247,27 +247,24 @@ static bool mlx5_is_ptm_source_time_available(struct mlx5_core_dev *dev) return !!MLX5_GET(mtptm_reg, out, psta); } -static int mlx5_mtctr_syncdevicetime(ktime_t *device_time, - struct system_counterval_t *sys_counterval, - void *ctx) +static int mlx5_mtctr_read(struct mlx5_core_dev *mdev, + bool real_time_mode, + struct system_counterval_t *sys_counterval, + u64 *device) { 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; + u64 host; 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); + MLX5_MTCTR_REQUEST_FREE_RUNNING_COUNTER); - err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), MLX5_REG_MTCTR, - 0, 0); + err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), + MLX5_REG_MTCTR, 0, 0); if (err) return err; @@ -281,8 +278,26 @@ static int mlx5_mtctr_syncdevicetime(ktime_t *device_time, .cs_id = CSID_X86_ART, .use_nsecs = true, }; + *device = MLX5_GET64(mtctr_reg, out, second_clock_timestamp); + + return 0; +} + +static int mlx5_mtctr_syncdevicetime(ktime_t *device_time, + struct system_counterval_t *sys_counterval, + void *ctx) +{ + struct mlx5_core_dev *mdev = ctx; + bool real_time_mode; + u64 device; + int err; + + real_time_mode = mlx5_real_time_mode(mdev); + + err = mlx5_mtctr_read(mdev, real_time_mode, sys_counterval, &device); + if (err) + return err; - 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 @@ -291,6 +306,23 @@ static int mlx5_mtctr_syncdevicetime(ktime_t *device_time, return 0; } +static int +mlx5_mtctr_syncdevicecyclestime(ktime_t *device_time, + struct system_counterval_t *sys_counterval, + void *ctx) +{ + struct mlx5_core_dev *mdev = ctx; + u64 device; + int err; + + err = mlx5_mtctr_read(mdev, false, sys_counterval, &device); + if (err) + return err; + *device_time = ns_to_ktime(device); + + return 0; +} + static int mlx5_ptp_getcrosststamp(struct ptp_clock_info *ptp, struct system_device_crosststamp *cts) { @@ -315,6 +347,32 @@ unlock: mlx5_clock_unlock(clock); return err; } + +static int mlx5_ptp_getcrosscycles(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; + int err; + + mlx5_clock_lock(clock); + mdev = mlx5_clock_mdev_get(clock); + + if (!mlx5_is_ptm_source_time_available(mdev)) { + err = -EBUSY; + goto unlock; + } + + ktime_get_snapshot(&history_begin); + + err = get_device_system_crosststamp(mlx5_mtctr_syncdevicecyclestime, + mdev, &history_begin, cts); +unlock: + mlx5_clock_unlock(clock); + return err; +} #endif /* CONFIG_X86 */ static u64 mlx5_read_time(struct mlx5_core_dev *dev, @@ -513,6 +571,24 @@ out: return 0; } +static int mlx5_ptp_getcyclesx(struct ptp_clock_info *ptp, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, + ptp_info); + struct mlx5_core_dev *mdev; + u64 cycles; + + mlx5_clock_lock(clock); + mdev = mlx5_clock_mdev_get(clock); + + cycles = mlx5_read_time(mdev, sts, false); + *ts = ns_to_timespec64(cycles); + mlx5_clock_unlock(clock); + return 0; +} + static int mlx5_ptp_adjtime_real_time(struct mlx5_core_dev *mdev, s64 delta) { u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {}; @@ -1229,6 +1305,7 @@ static void mlx5_init_timer_max_freq_adjustment(struct mlx5_core_dev *mdev) static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev) { struct mlx5_clock *clock = mdev->clock; + bool expose_cycles; /* Configure the PHC */ clock->ptp_info = mlx5_ptp_clock_info; @@ -1236,12 +1313,22 @@ 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); + expose_cycles = !MLX5_CAP_GEN(mdev, disciplined_fr_counter) || + !mlx5_real_time_mode(mdev); + #ifdef CONFIG_X86 if (MLX5_CAP_MCAM_REG3(mdev, mtptm) && - MLX5_CAP_MCAM_REG3(mdev, mtctr) && boot_cpu_has(X86_FEATURE_ART)) + MLX5_CAP_MCAM_REG3(mdev, mtctr) && boot_cpu_has(X86_FEATURE_ART)) { clock->ptp_info.getcrosststamp = mlx5_ptp_getcrosststamp; + if (expose_cycles) + clock->ptp_info.getcrosscycles = + mlx5_ptp_getcrosscycles; + } #endif /* CONFIG_X86 */ + if (expose_cycles) + clock->ptp_info.getcyclesx64 = mlx5_ptp_getcyclesx; + mlx5_timecounter_init(mdev); mlx5_init_clock_info(mdev); mlx5_init_overflow_period(mdev); diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 4ca5a464a46a..e9719f365aab 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -285,17 +285,21 @@ static long ptp_enable_pps(struct ptp_clock *ptp, bool enable) return ops->enable(ops, &req, enable); } -static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg) +typedef int (*ptp_crosststamp_fn)(struct ptp_clock_info *, + struct system_device_crosststamp *); + +static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg, + ptp_crosststamp_fn crosststamp_fn) { struct ptp_sys_offset_precise precise_offset; struct system_device_crosststamp xtstamp; struct timespec64 ts; int err; - if (!ptp->info->getcrosststamp) + if (!crosststamp_fn) return -EOPNOTSUPP; - err = ptp->info->getcrosststamp(ptp->info, &xtstamp); + err = crosststamp_fn(ptp->info, &xtstamp); if (err) return err; @@ -313,12 +317,17 @@ static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg) return copy_to_user(arg, &precise_offset, sizeof(precise_offset)) ? -EFAULT : 0; } -static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg) +typedef int (*ptp_gettimex_fn)(struct ptp_clock_info *, + struct timespec64 *, + struct ptp_system_timestamp *); + +static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg, + ptp_gettimex_fn gettimex_fn) { struct ptp_sys_offset_extended *extoff __free(kfree) = NULL; struct ptp_system_timestamp sts; - if (!ptp->info->gettimex64) + if (!gettimex_fn) return -EOPNOTSUPP; extoff = memdup_user(arg, sizeof(*extoff)); @@ -346,7 +355,7 @@ static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg) struct timespec64 ts; int err; - err = ptp->info->gettimex64(ptp->info, &ts, &sts); + err = gettimex_fn(ptp->info, &ts, &sts); if (err) return err; @@ -497,11 +506,13 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd, case PTP_SYS_OFFSET_PRECISE: case PTP_SYS_OFFSET_PRECISE2: - return ptp_sys_offset_precise(ptp, argptr); + return ptp_sys_offset_precise(ptp, argptr, + ptp->info->getcrosststamp); case PTP_SYS_OFFSET_EXTENDED: case PTP_SYS_OFFSET_EXTENDED2: - return ptp_sys_offset_extended(ptp, argptr); + return ptp_sys_offset_extended(ptp, argptr, + ptp->info->gettimex64); case PTP_SYS_OFFSET: case PTP_SYS_OFFSET2: @@ -523,6 +534,13 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd, case PTP_MASK_EN_SINGLE: return ptp_mask_en_single(pccontext->private_clkdata, argptr); + case PTP_SYS_OFFSET_PRECISE_CYCLES: + return ptp_sys_offset_precise(ptp, argptr, + ptp->info->getcrosscycles); + + case PTP_SYS_OFFSET_EXTENDED_CYCLES: + return ptp_sys_offset_extended(ptp, argptr, + ptp->info->getcyclesx64); default: return -ENOTTY; } diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h index 18eefa6d93d6..65f187b5f0d0 100644 --- a/include/uapi/linux/ptp_clock.h +++ b/include/uapi/linux/ptp_clock.h @@ -245,6 +245,10 @@ struct ptp_pin_desc { _IOWR(PTP_CLK_MAGIC, 18, struct ptp_sys_offset_extended) #define PTP_MASK_CLEAR_ALL _IO(PTP_CLK_MAGIC, 19) #define PTP_MASK_EN_SINGLE _IOW(PTP_CLK_MAGIC, 20, unsigned int) +#define PTP_SYS_OFFSET_PRECISE_CYCLES \ + _IOWR(PTP_CLK_MAGIC, 21, struct ptp_sys_offset_precise) +#define PTP_SYS_OFFSET_EXTENDED_CYCLES \ + _IOWR(PTP_CLK_MAGIC, 22, struct ptp_sys_offset_extended) struct ptp_extts_event { struct ptp_clock_time t; /* Time event occurred. */