Commit f0462bc3 authored by Aya Levin's avatar Aya Levin Committed by Saeed Mahameed

net/mlx5: Add support for NPPS with real time mode

Add support for setting NPPS. NPPS is currently available in
REAL_TIME_CLOCK mode only. In addition allow the user to set the pulse
duration.

When NPPS pulse duration is not set explicitly by the user, driver set
it to 50% of the NPPS period.
Signed-off-by: default avatarAya Levin <ayal@nvidia.com>
Reviewed-by: default avatarEran Ben Elisha <eranbe@nvidia.com>
Reviewed-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent 976a859c
...@@ -65,6 +65,8 @@ enum { ...@@ -65,6 +65,8 @@ enum {
MLX5_MTPPS_FS_TIME_STAMP = BIT(0x4), MLX5_MTPPS_FS_TIME_STAMP = BIT(0x4),
MLX5_MTPPS_FS_OUT_PULSE_DURATION = BIT(0x5), MLX5_MTPPS_FS_OUT_PULSE_DURATION = BIT(0x5),
MLX5_MTPPS_FS_ENH_OUT_PER_ADJ = BIT(0x7), MLX5_MTPPS_FS_ENH_OUT_PER_ADJ = BIT(0x7),
MLX5_MTPPS_FS_NPPS_PERIOD = BIT(0x9),
MLX5_MTPPS_FS_OUT_PULSE_DURATION_NS = BIT(0xa),
}; };
static bool mlx5_real_time_mode(struct mlx5_core_dev *mdev) static bool mlx5_real_time_mode(struct mlx5_core_dev *mdev)
...@@ -72,6 +74,13 @@ static bool mlx5_real_time_mode(struct mlx5_core_dev *mdev) ...@@ -72,6 +74,13 @@ static bool mlx5_real_time_mode(struct mlx5_core_dev *mdev)
return (mlx5_is_real_time_rq(mdev) || mlx5_is_real_time_sq(mdev)); return (mlx5_is_real_time_rq(mdev) || mlx5_is_real_time_sq(mdev));
} }
static bool mlx5_npps_real_time_supported(struct mlx5_core_dev *mdev)
{
return (mlx5_real_time_mode(mdev) &&
MLX5_CAP_MCAM_FEATURE(mdev, npps_period) &&
MLX5_CAP_MCAM_FEATURE(mdev, out_pulse_duration_ns));
}
static bool mlx5_modify_mtutc_allowed(struct mlx5_core_dev *mdev) static bool mlx5_modify_mtutc_allowed(struct mlx5_core_dev *mdev)
{ {
return MLX5_CAP_MCAM_FEATURE(mdev, ptpcyc2realtime_modify); return MLX5_CAP_MCAM_FEATURE(mdev, ptpcyc2realtime_modify);
...@@ -459,9 +468,95 @@ static u64 perout_conf_internal_timer(struct mlx5_core_dev *mdev, s64 sec) ...@@ -459,9 +468,95 @@ static u64 perout_conf_internal_timer(struct mlx5_core_dev *mdev, s64 sec)
return find_target_cycles(mdev, target_ns); return find_target_cycles(mdev, target_ns);
} }
static u64 perout_conf_real_time(s64 sec) static u64 perout_conf_real_time(s64 sec, u32 nsec)
{
return (u64)nsec | (u64)sec << 32;
}
static int perout_conf_1pps(struct mlx5_core_dev *mdev, struct ptp_clock_request *rq,
u64 *time_stamp, bool real_time)
{
struct timespec64 ts;
s64 ns;
ts.tv_nsec = rq->perout.period.nsec;
ts.tv_sec = rq->perout.period.sec;
ns = timespec64_to_ns(&ts);
if ((ns >> 1) != 500000000LL)
return -EINVAL;
*time_stamp = real_time ? perout_conf_real_time(rq->perout.start.sec, 0) :
perout_conf_internal_timer(mdev, rq->perout.start.sec);
return 0;
}
#define MLX5_MAX_PULSE_DURATION (BIT(__mlx5_bit_sz(mtpps_reg, out_pulse_duration_ns)) - 1)
static int mlx5_perout_conf_out_pulse_duration(struct mlx5_core_dev *mdev,
struct ptp_clock_request *rq,
u32 *out_pulse_duration_ns)
{ {
return (u64)sec << 32; struct mlx5_pps *pps_info = &mdev->clock.pps_info;
u32 out_pulse_duration;
struct timespec64 ts;
if (rq->perout.flags & PTP_PEROUT_DUTY_CYCLE) {
ts.tv_sec = rq->perout.on.sec;
ts.tv_nsec = rq->perout.on.nsec;
out_pulse_duration = (u32)timespec64_to_ns(&ts);
} else {
/* out_pulse_duration_ns should be up to 50% of the
* pulse period as default
*/
ts.tv_sec = rq->perout.period.sec;
ts.tv_nsec = rq->perout.period.nsec;
out_pulse_duration = (u32)timespec64_to_ns(&ts) >> 1;
}
if (out_pulse_duration < pps_info->min_out_pulse_duration_ns ||
out_pulse_duration > MLX5_MAX_PULSE_DURATION) {
mlx5_core_err(mdev, "NPPS pulse duration %u is not in [%llu, %lu]\n",
out_pulse_duration, pps_info->min_out_pulse_duration_ns,
MLX5_MAX_PULSE_DURATION);
return -EINVAL;
}
*out_pulse_duration_ns = out_pulse_duration;
return 0;
}
static int perout_conf_npps_real_time(struct mlx5_core_dev *mdev, struct ptp_clock_request *rq,
u32 *field_select, u32 *out_pulse_duration_ns,
u64 *period, u64 *time_stamp)
{
struct mlx5_pps *pps_info = &mdev->clock.pps_info;
struct ptp_clock_time *time = &rq->perout.start;
struct timespec64 ts;
ts.tv_sec = rq->perout.period.sec;
ts.tv_nsec = rq->perout.period.nsec;
if (timespec64_to_ns(&ts) < pps_info->min_npps_period) {
mlx5_core_err(mdev, "NPPS period is lower than minimal npps period %llu\n",
pps_info->min_npps_period);
return -EINVAL;
}
*period = perout_conf_real_time(rq->perout.period.sec, rq->perout.period.nsec);
if (mlx5_perout_conf_out_pulse_duration(mdev, rq, out_pulse_duration_ns))
return -EINVAL;
*time_stamp = perout_conf_real_time(time->sec, time->nsec);
*field_select |= MLX5_MTPPS_FS_NPPS_PERIOD |
MLX5_MTPPS_FS_OUT_PULSE_DURATION_NS;
return 0;
}
static bool mlx5_perout_verify_flags(struct mlx5_core_dev *mdev, unsigned int flags)
{
return ((!mlx5_npps_real_time_supported(mdev) && flags) ||
(mlx5_npps_real_time_supported(mdev) && flags & ~PTP_PEROUT_DUTY_CYCLE));
} }
static int mlx5_perout_configure(struct ptp_clock_info *ptp, static int mlx5_perout_configure(struct ptp_clock_info *ptp,
...@@ -474,20 +569,20 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp, ...@@ -474,20 +569,20 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
container_of(clock, struct mlx5_core_dev, clock); container_of(clock, struct mlx5_core_dev, clock);
bool rt_mode = mlx5_real_time_mode(mdev); bool rt_mode = mlx5_real_time_mode(mdev);
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0}; u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
struct timespec64 ts; u32 out_pulse_duration_ns = 0;
u32 field_select = 0; u32 field_select = 0;
u64 npps_period = 0;
u64 time_stamp = 0; u64 time_stamp = 0;
u8 pin_mode = 0; u8 pin_mode = 0;
u8 pattern = 0; u8 pattern = 0;
int pin = -1; int pin = -1;
int err = 0; int err = 0;
s64 ns;
if (!MLX5_PPS_CAP(mdev)) if (!MLX5_PPS_CAP(mdev))
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* Reject requests with unsupported flags */ /* Reject requests with unsupported flags */
if (rq->perout.flags) if (mlx5_perout_verify_flags(mdev, rq->perout.flags))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (rq->perout.index >= clock->ptp_info.n_pins) if (rq->perout.index >= clock->ptp_info.n_pins)
...@@ -500,29 +595,25 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp, ...@@ -500,29 +595,25 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
if (on) { if (on) {
bool rt_mode = mlx5_real_time_mode(mdev); bool rt_mode = mlx5_real_time_mode(mdev);
s64 sec = rq->perout.start.sec;
if (rq->perout.start.nsec)
return -EINVAL;
pin_mode = MLX5_PIN_MODE_OUT; pin_mode = MLX5_PIN_MODE_OUT;
pattern = MLX5_OUT_PATTERN_PERIODIC; pattern = MLX5_OUT_PATTERN_PERIODIC;
ts.tv_sec = rq->perout.period.sec;
ts.tv_nsec = rq->perout.period.nsec;
ns = timespec64_to_ns(&ts);
if ((ns >> 1) != 500000000LL) if (rt_mode && rq->perout.start.sec > U32_MAX)
return -EINVAL; return -EINVAL;
if (rt_mode && sec > U32_MAX)
return -EINVAL;
time_stamp = rt_mode ? perout_conf_real_time(sec) :
perout_conf_internal_timer(mdev, sec);
field_select |= MLX5_MTPPS_FS_PIN_MODE | field_select |= MLX5_MTPPS_FS_PIN_MODE |
MLX5_MTPPS_FS_PATTERN | MLX5_MTPPS_FS_PATTERN |
MLX5_MTPPS_FS_TIME_STAMP; MLX5_MTPPS_FS_TIME_STAMP;
if (mlx5_npps_real_time_supported(mdev))
err = perout_conf_npps_real_time(mdev, rq, &field_select,
&out_pulse_duration_ns, &npps_period,
&time_stamp);
else
err = perout_conf_1pps(mdev, rq, &time_stamp, rt_mode);
if (err)
return err;
} }
MLX5_SET(mtpps_reg, in, pin, pin); MLX5_SET(mtpps_reg, in, pin, pin);
...@@ -531,7 +622,8 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp, ...@@ -531,7 +622,8 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
MLX5_SET(mtpps_reg, in, enable, on); MLX5_SET(mtpps_reg, in, enable, on);
MLX5_SET64(mtpps_reg, in, time_stamp, time_stamp); MLX5_SET64(mtpps_reg, in, time_stamp, time_stamp);
MLX5_SET(mtpps_reg, in, field_select, field_select); MLX5_SET(mtpps_reg, in, field_select, field_select);
MLX5_SET64(mtpps_reg, in, npps_period, npps_period);
MLX5_SET(mtpps_reg, in, out_pulse_duration_ns, out_pulse_duration_ns);
err = mlx5_set_mtpps(mdev, in, sizeof(in)); err = mlx5_set_mtpps(mdev, in, sizeof(in));
if (err) if (err)
return err; return err;
...@@ -687,6 +779,13 @@ static void mlx5_get_pps_caps(struct mlx5_core_dev *mdev) ...@@ -687,6 +779,13 @@ static void mlx5_get_pps_caps(struct mlx5_core_dev *mdev)
clock->ptp_info.n_per_out = MLX5_GET(mtpps_reg, out, clock->ptp_info.n_per_out = MLX5_GET(mtpps_reg, out,
cap_max_num_of_pps_out_pins); cap_max_num_of_pps_out_pins);
if (MLX5_CAP_MCAM_FEATURE(mdev, npps_period))
clock->pps_info.min_npps_period = 1 << MLX5_GET(mtpps_reg, out,
cap_log_min_npps_period);
if (MLX5_CAP_MCAM_FEATURE(mdev, out_pulse_duration_ns))
clock->pps_info.min_out_pulse_duration_ns = 1 << MLX5_GET(mtpps_reg, out,
cap_log_min_out_pulse_duration_ns);
clock->pps_info.pin_caps[0] = MLX5_GET(mtpps_reg, out, cap_pin_0_mode); clock->pps_info.pin_caps[0] = MLX5_GET(mtpps_reg, out, cap_pin_0_mode);
clock->pps_info.pin_caps[1] = MLX5_GET(mtpps_reg, out, cap_pin_1_mode); clock->pps_info.pin_caps[1] = MLX5_GET(mtpps_reg, out, cap_pin_1_mode);
clock->pps_info.pin_caps[2] = MLX5_GET(mtpps_reg, out, cap_pin_2_mode); clock->pps_info.pin_caps[2] = MLX5_GET(mtpps_reg, out, cap_pin_2_mode);
......
...@@ -698,6 +698,8 @@ struct mlx5_pps { ...@@ -698,6 +698,8 @@ struct mlx5_pps {
struct work_struct out_work; struct work_struct out_work;
u64 start[MAX_PIN_NUM]; u64 start[MAX_PIN_NUM];
u8 enabled; u8 enabled;
u64 min_npps_period;
u64 min_out_pulse_duration_ns;
}; };
struct mlx5_timer { struct mlx5_timer {
......
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