net: ptp: introduce .supported_perout_flags to ptp_clock_info

The PTP_PEROUT_REQUEST2 ioctl has gained support for flags specifying
specific output behavior including PTP_PEROUT_ONE_SHOT,
PTP_PEROUT_DUTY_CYCLE, PTP_PEROUT_PHASE.

Driver authors are notorious for not checking the flags of the request.
This results in misinterpreting the request, generating an output signal
that does not match the requested value. It is anticipated that even more
flags will be added in the future, resulting in even more broken requests.

Expecting these issues to be caught during review or playing whack-a-mole
after the fact is not a great solution.

Instead, introduce the supported_perout_flags field in the ptp_clock_info
structure. Update the core character device logic to explicitly reject any
request which has a flag not on this list.

This ensures that drivers must 'opt in' to the flags they support. Drivers
which don't set the .supported_perout_flags field will not need to check
that unsupported flags aren't passed, as the core takes care of this.

Update the drivers which do support flags to set this new field.

Note the following driver files set n_per_out to a non-zero value but did
not check the flags at all:

 • drivers/ptp/ptp_clockmatrix.c
 • drivers/ptp/ptp_idt82p33.c
 • drivers/ptp/ptp_fc3.c
 • drivers/net/ethernet/ti/am65-cpts.c
 • drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
 • drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
 • drivers/net/dsa/sja1105/sja1105_ptp.c
 • drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c
 • drivers/net/ethernet/mscc/ocelot_vsc7514.c
 • drivers/net/ethernet/intel/i40e/i40e_ptp.c

Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
Link: https://patch.msgid.link/20250414-jk-supported-perout-flags-v2-2-f6b17d15475c@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jacob Keller 2025-04-14 14:26:31 -07:00 committed by Jakub Kicinski
parent 7c571ac57d
commit d9f3e9ecc4
15 changed files with 21 additions and 57 deletions

View File

@ -737,10 +737,6 @@ static int sja1105_per_out_enable(struct sja1105_private *priv,
if (perout->index != 0) if (perout->index != 0)
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* Reject requests with unsupported flags */
if (perout->flags)
return -EOPNOTSUPP;
mutex_lock(&ptp_data->lock); mutex_lock(&ptp_data->lock);
rc = sja1105_change_ptp_clk_pin_func(priv, PTP_PF_PEROUT); rc = sja1105_change_ptp_clk_pin_func(priv, PTP_PF_PEROUT);

View File

@ -1797,9 +1797,6 @@ static int ice_ptp_cfg_perout(struct ice_pf *pf, struct ptp_perout_request *rq,
struct ice_hw *hw = &pf->hw; struct ice_hw *hw = &pf->hw;
int pin_desc_idx; int pin_desc_idx;
if (rq->flags & ~PTP_PEROUT_PHASE)
return -EOPNOTSUPP;
pin_desc_idx = ice_ptp_find_pin_idx(pf, PTP_PF_PEROUT, rq->index); pin_desc_idx = ice_ptp_find_pin_idx(pf, PTP_PF_PEROUT, rq->index);
if (pin_desc_idx < 0) if (pin_desc_idx < 0)
return -EIO; return -EIO;
@ -2735,6 +2732,7 @@ static void ice_ptp_set_caps(struct ice_pf *pf)
info->supported_extts_flags = PTP_RISING_EDGE | info->supported_extts_flags = PTP_RISING_EDGE |
PTP_FALLING_EDGE | PTP_FALLING_EDGE |
PTP_STRICT_FLAGS; PTP_STRICT_FLAGS;
info->supported_perout_flags = PTP_PEROUT_PHASE;
switch (pf->hw.mac_type) { switch (pf->hw.mac_type) {
case ICE_MAC_E810: case ICE_MAC_E810:

View File

@ -293,10 +293,6 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
return 0; return 0;
case PTP_CLK_REQ_PEROUT: case PTP_CLK_REQ_PEROUT:
/* Reject requests with unsupported flags */
if (rq->perout.flags)
return -EOPNOTSUPP;
if (on) { if (on) {
pin = ptp_find_pin(igc->ptp_clock, PTP_PF_PEROUT, pin = ptp_find_pin(igc->ptp_clock, PTP_PF_PEROUT,
rq->perout.index); rq->perout.index);

View File

@ -813,12 +813,6 @@ static int perout_conf_npps_real_time(struct mlx5_core_dev *mdev, struct ptp_clo
return 0; 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,
struct ptp_clock_request *rq, struct ptp_clock_request *rq,
int on) int on)
@ -854,12 +848,6 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
goto unlock; goto unlock;
} }
/* Reject requests with unsupported flags */
if (mlx5_perout_verify_flags(mdev, rq->perout.flags)) {
err = -EOPNOTSUPP;
goto unlock;
}
if (on) { if (on) {
pin_mode = MLX5_PIN_MODE_OUT; pin_mode = MLX5_PIN_MODE_OUT;
pattern = MLX5_OUT_PATTERN_PERIODIC; pattern = MLX5_OUT_PATTERN_PERIODIC;
@ -1031,6 +1019,9 @@ static void mlx5_init_pin_config(struct mlx5_core_dev *mdev)
PTP_FALLING_EDGE | PTP_FALLING_EDGE |
PTP_STRICT_FLAGS; PTP_STRICT_FLAGS;
if (mlx5_npps_real_time_supported(mdev))
clock->ptp_info.supported_perout_flags = PTP_PEROUT_DUTY_CYCLE;
for (i = 0; i < clock->ptp_info.n_pins; i++) { for (i = 0; i < clock->ptp_info.n_pins; i++) {
snprintf(clock->ptp_info.pin_config[i].name, snprintf(clock->ptp_info.pin_config[i].name,
sizeof(clock->ptp_info.pin_config[i].name), sizeof(clock->ptp_info.pin_config[i].name),

View File

@ -463,10 +463,6 @@ static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
struct lan743x_ptp_perout *perout = &ptp->perout[index]; struct lan743x_ptp_perout *perout = &ptp->perout[index];
int ret = 0; int ret = 0;
/* Reject requests with unsupported flags */
if (perout_request->flags & ~PTP_PEROUT_DUTY_CYCLE)
return -EOPNOTSUPP;
if (on) { if (on) {
perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT,
perout_request->index); perout_request->index);
@ -1540,6 +1536,7 @@ int lan743x_ptp_open(struct lan743x_adapter *adapter)
ptp->ptp_clock_info.supported_extts_flags = PTP_RISING_EDGE | ptp->ptp_clock_info.supported_extts_flags = PTP_RISING_EDGE |
PTP_FALLING_EDGE | PTP_FALLING_EDGE |
PTP_STRICT_FLAGS; PTP_STRICT_FLAGS;
ptp->ptp_clock_info.supported_perout_flags = PTP_PEROUT_DUTY_CYCLE;
ptp->ptp_clock_info.pin_config = ptp->pin_config; ptp->ptp_clock_info.pin_config = ptp->pin_config;
ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine; ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine;
ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime; ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime;

View File

@ -815,10 +815,6 @@ static int lan966x_ptp_perout(struct ptp_clock_info *ptp,
bool pps = false; bool pps = false;
int pin; int pin;
if (rq->perout.flags & ~(PTP_PEROUT_DUTY_CYCLE |
PTP_PEROUT_PHASE))
return -EOPNOTSUPP;
pin = ptp_find_pin(phc->clock, PTP_PF_PEROUT, rq->perout.index); pin = ptp_find_pin(phc->clock, PTP_PF_PEROUT, rq->perout.index);
if (pin == -1 || pin >= LAN966X_PHC_PINS_NUM) if (pin == -1 || pin >= LAN966X_PHC_PINS_NUM)
return -EINVAL; return -EINVAL;
@ -974,6 +970,8 @@ static struct ptp_clock_info lan966x_ptp_clock_info = {
.n_pins = LAN966X_PHC_PINS_NUM, .n_pins = LAN966X_PHC_PINS_NUM,
.supported_extts_flags = PTP_RISING_EDGE | .supported_extts_flags = PTP_RISING_EDGE |
PTP_STRICT_FLAGS, PTP_STRICT_FLAGS,
.supported_perout_flags = PTP_PEROUT_DUTY_CYCLE |
PTP_PEROUT_PHASE,
}; };
static int lan966x_ptp_phc_init(struct lan966x *lan966x, static int lan966x_ptp_phc_init(struct lan966x *lan966x,

View File

@ -211,11 +211,6 @@ int ocelot_ptp_enable(struct ptp_clock_info *ptp,
switch (rq->type) { switch (rq->type) {
case PTP_CLK_REQ_PEROUT: case PTP_CLK_REQ_PEROUT:
/* Reject requests with unsupported flags */
if (rq->perout.flags & ~(PTP_PEROUT_DUTY_CYCLE |
PTP_PEROUT_PHASE))
return -EOPNOTSUPP;
pin = ptp_find_pin(ocelot->ptp_clock, PTP_PF_PEROUT, pin = ptp_find_pin(ocelot->ptp_clock, PTP_PF_PEROUT,
rq->perout.index); rq->perout.index);
if (pin == 0) if (pin == 0)

View File

@ -108,6 +108,8 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {
.n_ext_ts = 0, .n_ext_ts = 0,
.n_per_out = OCELOT_PTP_PINS_NUM, .n_per_out = OCELOT_PTP_PINS_NUM,
.n_pins = OCELOT_PTP_PINS_NUM, .n_pins = OCELOT_PTP_PINS_NUM,
.supported_perout_flags = PTP_PEROUT_DUTY_CYCLE |
PTP_PEROUT_PHASE,
.pps = 0, .pps = 0,
.gettime64 = ocelot_ptp_gettime64, .gettime64 = ocelot_ptp_gettime64,
.settime64 = ocelot_ptp_settime64, .settime64 = ocelot_ptp_settime64,

View File

@ -206,10 +206,6 @@ static int ravb_ptp_perout(struct ptp_clock_info *ptp,
unsigned long flags; unsigned long flags;
int error = 0; int error = 0;
/* Reject requests with unsupported flags */
if (req->flags)
return -EOPNOTSUPP;
if (req->index) if (req->index)
return -EINVAL; return -EINVAL;

View File

@ -506,9 +506,6 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
return 0; return 0;
case PTP_CLK_REQ_PEROUT: case PTP_CLK_REQ_PEROUT:
/* Reject requests with unsupported flags */
if (rq->perout.flags)
return -EOPNOTSUPP;
if (rq->perout.index >= N_PER_OUT) if (rq->perout.index >= N_PER_OUT)
return -EINVAL; return -EINVAL;
return periodic_output(clock, rq, on, rq->perout.index); return periodic_output(clock, rq, on, rq->perout.index);

View File

@ -3236,10 +3236,6 @@ static int lan8814_ptp_perout(struct ptp_clock_info *ptpci,
int pulse_width; int pulse_width;
int pin, event; int pin, event;
/* Reject requests with unsupported flags */
if (rq->perout.flags & ~PTP_PEROUT_DUTY_CYCLE)
return -EOPNOTSUPP;
mutex_lock(&shared->shared_lock); mutex_lock(&shared->shared_lock);
event = rq->perout.index; event = rq->perout.index;
pin = ptp_find_pin(shared->ptp_clock, PTP_PF_PEROUT, event); pin = ptp_find_pin(shared->ptp_clock, PTP_PF_PEROUT, event);
@ -3915,6 +3911,7 @@ static int lan8814_ptp_probe_once(struct phy_device *phydev)
shared->ptp_clock_info.supported_extts_flags = PTP_RISING_EDGE | shared->ptp_clock_info.supported_extts_flags = PTP_RISING_EDGE |
PTP_FALLING_EDGE | PTP_FALLING_EDGE |
PTP_STRICT_FLAGS; PTP_STRICT_FLAGS;
shared->ptp_clock_info.supported_perout_flags = PTP_PEROUT_DUTY_CYCLE;
shared->ptp_clock_info.pin_config = shared->pin_config; shared->ptp_clock_info.pin_config = shared->pin_config;
shared->ptp_clock_info.n_per_out = LAN8814_PTP_PEROUT_NUM; shared->ptp_clock_info.n_per_out = LAN8814_PTP_PEROUT_NUM;
shared->ptp_clock_info.adjfine = lan8814_ptpci_adjfine; shared->ptp_clock_info.adjfine = lan8814_ptpci_adjfine;
@ -5066,9 +5063,6 @@ static int lan8841_ptp_perout(struct ptp_clock_info *ptp,
int pin; int pin;
int ret; int ret;
if (rq->perout.flags & ~PTP_PEROUT_DUTY_CYCLE)
return -EOPNOTSUPP;
pin = ptp_find_pin(ptp_priv->ptp_clock, PTP_PF_PEROUT, rq->perout.index); pin = ptp_find_pin(ptp_priv->ptp_clock, PTP_PF_PEROUT, rq->perout.index);
if (pin == -1 || pin >= LAN8841_PTP_GPIO_NUM) if (pin == -1 || pin >= LAN8841_PTP_GPIO_NUM)
return -EINVAL; return -EINVAL;
@ -5312,6 +5306,7 @@ static struct ptp_clock_info lan8841_ptp_clock_info = {
.n_per_out = LAN8841_PTP_GPIO_NUM, .n_per_out = LAN8841_PTP_GPIO_NUM,
.n_ext_ts = LAN8841_PTP_GPIO_NUM, .n_ext_ts = LAN8841_PTP_GPIO_NUM,
.n_pins = LAN8841_PTP_GPIO_NUM, .n_pins = LAN8841_PTP_GPIO_NUM,
.supported_perout_flags = PTP_PEROUT_DUTY_CYCLE,
}; };
#define LAN8841_OPERATION_MODE_STRAP_LOW_REGISTER 3 #define LAN8841_OPERATION_MODE_STRAP_LOW_REGISTER 3

View File

@ -224,10 +224,6 @@ static int mchp_rds_ptp_perout(struct ptp_clock_info *ptpci,
struct phy_device *phydev = clock->phydev; struct phy_device *phydev = clock->phydev;
int ret, event_pin, pulsewidth; int ret, event_pin, pulsewidth;
/* Reject requests with unsupported flags */
if (perout->flags & ~PTP_PEROUT_DUTY_CYCLE)
return -EOPNOTSUPP;
event_pin = ptp_find_pin(clock->ptp_clock, PTP_PF_PEROUT, event_pin = ptp_find_pin(clock->ptp_clock, PTP_PF_PEROUT,
perout->index); perout->index);
if (event_pin != clock->event_pin) if (event_pin != clock->event_pin)
@ -1259,6 +1255,7 @@ struct mchp_rds_ptp_clock *mchp_rds_ptp_probe(struct phy_device *phydev, u8 mmd,
clock->caps.pps = 0; clock->caps.pps = 0;
clock->caps.n_pins = MCHP_RDS_PTP_N_PIN; clock->caps.n_pins = MCHP_RDS_PTP_N_PIN;
clock->caps.n_per_out = MCHP_RDS_PTP_N_PEROUT; clock->caps.n_per_out = MCHP_RDS_PTP_N_PEROUT;
clock->caps.supported_perout_flags = PTP_PEROUT_DUTY_CYCLE;
clock->caps.pin_config = clock->pin_config; clock->caps.pin_config = clock->pin_config;
clock->caps.adjfine = mchp_rds_ptp_ltc_adjfine; clock->caps.adjfine = mchp_rds_ptp_ltc_adjfine;
clock->caps.adjtime = mchp_rds_ptp_ltc_adjtime; clock->caps.adjtime = mchp_rds_ptp_ltc_adjtime;

View File

@ -763,9 +763,6 @@ static int nxp_c45_perout_enable(struct nxp_c45_phy *priv,
struct phy_device *phydev = priv->phydev; struct phy_device *phydev = priv->phydev;
int pin; int pin;
if (perout->flags & ~PTP_PEROUT_PHASE)
return -EOPNOTSUPP;
pin = ptp_find_pin(priv->ptp_clock, PTP_PF_PEROUT, perout->index); pin = ptp_find_pin(priv->ptp_clock, PTP_PF_PEROUT, perout->index);
if (pin < 0) if (pin < 0)
return pin; return pin;
@ -959,6 +956,7 @@ static int nxp_c45_init_ptp_clock(struct nxp_c45_phy *priv)
.supported_extts_flags = PTP_RISING_EDGE | .supported_extts_flags = PTP_RISING_EDGE |
PTP_FALLING_EDGE | PTP_FALLING_EDGE |
PTP_STRICT_FLAGS, PTP_STRICT_FLAGS,
.supported_perout_flags = PTP_PEROUT_PHASE,
}; };
priv->ptp_clock = ptp_clock_register(&priv->caps, priv->ptp_clock = ptp_clock_register(&priv->caps,

View File

@ -324,6 +324,8 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
err = -EINVAL; err = -EINVAL;
break; break;
} }
if (req.perout.flags & ~ptp->info->supported_perout_flags)
return -EOPNOTSUPP;
req.type = PTP_CLK_REQ_PEROUT; req.type = PTP_CLK_REQ_PEROUT;
enable = req.perout.period.sec || req.perout.period.nsec; enable = req.perout.period.sec || req.perout.period.nsec;
if (mutex_lock_interruptible(&ptp->pincfg_mux)) if (mutex_lock_interruptible(&ptp->pincfg_mux))

View File

@ -69,6 +69,11 @@ struct ptp_system_timestamp {
* @n_pins: The number of programmable pins. * @n_pins: The number of programmable pins.
* @pps: Indicates whether the clock supports a PPS callback. * @pps: Indicates whether the clock supports a PPS callback.
* *
* @supported_perout_flags: The set of flags the driver supports for the
* PTP_PEROUT_REQUEST ioctl. The PTP core will
* reject a request with any flag not specified
* here.
*
* @supported_extts_flags: The set of flags the driver supports for the * @supported_extts_flags: The set of flags the driver supports for the
* PTP_EXTTS_REQUEST ioctl. The PTP core will use * PTP_EXTTS_REQUEST ioctl. The PTP core will use
* this list to reject unsupported requests. * this list to reject unsupported requests.
@ -185,6 +190,7 @@ struct ptp_clock_info {
int n_per_out; int n_per_out;
int n_pins; int n_pins;
int pps; int pps;
unsigned int supported_perout_flags;
unsigned int supported_extts_flags; unsigned int supported_extts_flags;
struct ptp_pin_desc *pin_config; struct ptp_pin_desc *pin_config;
int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm); int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm);