net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set()

New timestamping API was introduced in commit 66f7223039 ("net: add
NDOs for configuring hardware timestamping") from kernel v6.6. It is
time to convert DSA to the new API, so that the ndo_eth_ioctl() path can
be removed completely.

Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set()
calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and
dsa_user_hwtstamp_set().

Due to the fact that the underlying ifreq type changes to
kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end,
all hooked up directly or indirectly, must also be converted all at once.

The conversion also updates the comment from dsa_port_supports_hwtstamp(),
which is no longer true because kernel_hwtstamp_config is kernel memory
and does not need copy_to_user(). I've deliberated whether it is
necessary to also update "err != -EOPNOTSUPP" to a more general "!err",
but all drivers now either return 0 or -EOPNOTSUPP.

The existing logic from the ocelot_ioctl() function, to avoid
configuring timestamping if the PHY supports the operation, is obsoleted
by more advanced core logic in dev_set_hwtstamp_phylib().

This is only a partial preparation for proper PHY timestamping support.
None of these switch driver currently sets up PTP traps for PHY
timestamping, so setting dev->see_all_hwtstamp_requests is not yet
necessary and the conversion is relatively trivial.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Vladimir Oltean 2025-05-08 12:52:36 +03:00 committed by Jakub Kicinski
parent 0df6932485
commit 6c14058edf
18 changed files with 147 additions and 150 deletions

View File

@ -244,7 +244,7 @@ struct hellcreek_port_hwtstamp {
struct sk_buff *tx_skb;
/* Current timestamp configuration */
struct hwtstamp_config tstamp_config;
struct kernel_hwtstamp_config tstamp_config;
};
struct hellcreek_port {

View File

@ -40,7 +40,7 @@ int hellcreek_get_ts_info(struct dsa_switch *ds, int port,
* the user requested what is actually available or not
*/
static int hellcreek_set_hwtstamp_config(struct hellcreek *hellcreek, int port,
struct hwtstamp_config *config)
struct kernel_hwtstamp_config *config)
{
struct hellcreek_port_hwtstamp *ps =
&hellcreek->ports[port].port_hwtstamp;
@ -110,41 +110,35 @@ static int hellcreek_set_hwtstamp_config(struct hellcreek *hellcreek, int port,
}
int hellcreek_port_hwtstamp_set(struct dsa_switch *ds, int port,
struct ifreq *ifr)
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct hellcreek *hellcreek = ds->priv;
struct hellcreek_port_hwtstamp *ps;
struct hwtstamp_config config;
int err;
ps = &hellcreek->ports[port].port_hwtstamp;
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
err = hellcreek_set_hwtstamp_config(hellcreek, port, &config);
err = hellcreek_set_hwtstamp_config(hellcreek, port, config);
if (err)
return err;
/* Save the chosen configuration to be returned later */
memcpy(&ps->tstamp_config, &config, sizeof(config));
ps->tstamp_config = *config;
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
return 0;
}
int hellcreek_port_hwtstamp_get(struct dsa_switch *ds, int port,
struct ifreq *ifr)
struct kernel_hwtstamp_config *config)
{
struct hellcreek *hellcreek = ds->priv;
struct hellcreek_port_hwtstamp *ps;
struct hwtstamp_config *config;
ps = &hellcreek->ports[port].port_hwtstamp;
config = &ps->tstamp_config;
*config = ps->tstamp_config;
return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
-EFAULT : 0;
return 0;
}
/* Returns a pointer to the PTP header if the caller should time stamp, or NULL

View File

@ -38,9 +38,10 @@
#define TX_TSTAMP_TIMEOUT msecs_to_jiffies(40)
int hellcreek_port_hwtstamp_set(struct dsa_switch *ds, int port,
struct ifreq *ifr);
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
int hellcreek_port_hwtstamp_get(struct dsa_switch *ds, int port,
struct ifreq *ifr);
struct kernel_hwtstamp_config *config);
bool hellcreek_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);

View File

@ -142,7 +142,7 @@ struct ksz_port {
struct ksz_irq pirq;
u8 num;
#if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_PTP)
struct hwtstamp_config tstamp_config;
struct kernel_hwtstamp_config tstamp_config;
bool hwts_tx_en;
bool hwts_rx_en;
struct ksz_irq ptpirq;

View File

@ -319,22 +319,21 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port, struct kernel_ethtool_ts_in
return 0;
}
int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr)
int ksz_hwtstamp_get(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config)
{
struct ksz_device *dev = ds->priv;
struct hwtstamp_config *config;
struct ksz_port *prt;
prt = &dev->ports[port];
config = &prt->tstamp_config;
*config = prt->tstamp_config;
return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
-EFAULT : 0;
return 0;
}
static int ksz_set_hwtstamp_config(struct ksz_device *dev,
struct ksz_port *prt,
struct hwtstamp_config *config)
struct kernel_hwtstamp_config *config)
{
int ret;
@ -404,26 +403,21 @@ static int ksz_set_hwtstamp_config(struct ksz_device *dev,
return ksz_ptp_enable_mode(dev);
}
int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
int ksz_hwtstamp_set(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct ksz_device *dev = ds->priv;
struct hwtstamp_config config;
struct ksz_port *prt;
int ret;
prt = &dev->ports[port];
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
ret = ksz_set_hwtstamp_config(dev, prt, &config);
ret = ksz_set_hwtstamp_config(dev, prt, config);
if (ret)
return ret;
memcpy(&prt->tstamp_config, &config, sizeof(config));
if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
return -EFAULT;
prt->tstamp_config = *config;
return 0;
}

View File

@ -39,8 +39,11 @@ void ksz_ptp_clock_unregister(struct dsa_switch *ds);
int ksz_get_ts_info(struct dsa_switch *ds, int port,
struct kernel_ethtool_ts_info *ts);
int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr);
int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr);
int ksz_hwtstamp_get(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config);
int ksz_hwtstamp_set(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb);
void ksz_port_deferred_xmit(struct kthread_work *work);
bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb,

View File

@ -241,7 +241,7 @@ struct mv88e6xxx_port_hwtstamp {
u16 tx_seq_id;
/* Current timestamp configuration */
struct hwtstamp_config tstamp_config;
struct kernel_hwtstamp_config tstamp_config;
};
enum mv88e6xxx_policy_mapping {

View File

@ -89,7 +89,7 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
}
static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
struct hwtstamp_config *config)
struct kernel_hwtstamp_config *config)
{
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
@ -169,42 +169,38 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
}
int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
struct ifreq *ifr)
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
struct hwtstamp_config config;
int err;
if (!chip->info->ptp_support)
return -EOPNOTSUPP;
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
err = mv88e6xxx_set_hwtstamp_config(chip, port, &config);
err = mv88e6xxx_set_hwtstamp_config(chip, port, config);
if (err)
return err;
/* Save the chosen configuration to be returned later. */
memcpy(&ps->tstamp_config, &config, sizeof(config));
ps->tstamp_config = *config;
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
return 0;
}
int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
struct ifreq *ifr)
struct kernel_hwtstamp_config *config)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
struct hwtstamp_config *config = &ps->tstamp_config;
if (!chip->info->ptp_support)
return -EOPNOTSUPP;
return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
-EFAULT : 0;
*config = ps->tstamp_config;
return 0;
}
/* Returns a pointer to the PTP header if the caller should time stamp,

View File

@ -111,9 +111,10 @@
#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
struct ifreq *ifr);
struct kernel_hwtstamp_config *cfg,
struct netlink_ext_ack *extack);
int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
struct ifreq *ifr);
struct kernel_hwtstamp_config *cfg);
bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);
@ -132,14 +133,17 @@ int mv88e6165_global_disable(struct mv88e6xxx_chip *chip);
#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
static inline int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds,
int port, struct ifreq *ifr)
static inline int
mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
return -EOPNOTSUPP;
}
static inline int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds,
int port, struct ifreq *ifr)
static inline int
mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config)
{
return -EOPNOTSUPP;
}

View File

@ -1774,22 +1774,25 @@ static void felix_teardown(struct dsa_switch *ds)
}
static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
struct ifreq *ifr)
struct kernel_hwtstamp_config *config)
{
struct ocelot *ocelot = ds->priv;
return ocelot_hwstamp_get(ocelot, port, ifr);
ocelot_hwstamp_get(ocelot, port, config);
return 0;
}
static int felix_hwtstamp_set(struct dsa_switch *ds, int port,
struct ifreq *ifr)
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = ds->priv;
struct felix *felix = ocelot_to_felix(ocelot);
bool using_tag_8021q;
int err;
err = ocelot_hwstamp_set(ocelot, port, ifr);
err = ocelot_hwstamp_set(ocelot, port, config, extack);
if (err)
return err;

View File

@ -58,19 +58,17 @@ enum sja1105_ptp_clk_mode {
#define ptp_data_to_sja1105(d) \
container_of((d), struct sja1105_private, ptp_data)
int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
int sja1105_hwtstamp_set(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct sja1105_private *priv = ds->priv;
unsigned long hwts_tx_en, hwts_rx_en;
struct hwtstamp_config config;
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
hwts_tx_en = priv->hwts_tx_en;
hwts_rx_en = priv->hwts_rx_en;
switch (config.tx_type) {
switch (config->tx_type) {
case HWTSTAMP_TX_OFF:
hwts_tx_en &= ~BIT(port);
break;
@ -81,7 +79,7 @@ int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
return -ERANGE;
}
switch (config.rx_filter) {
switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
hwts_rx_en &= ~BIT(port);
break;
@ -92,32 +90,28 @@ int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
return -ERANGE;
}
if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
return -EFAULT;
priv->hwts_tx_en = hwts_tx_en;
priv->hwts_rx_en = hwts_rx_en;
return 0;
}
int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr)
int sja1105_hwtstamp_get(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config)
{
struct sja1105_private *priv = ds->priv;
struct hwtstamp_config config;
config.flags = 0;
config->flags = 0;
if (priv->hwts_tx_en & BIT(port))
config.tx_type = HWTSTAMP_TX_ON;
config->tx_type = HWTSTAMP_TX_ON;
else
config.tx_type = HWTSTAMP_TX_OFF;
config->tx_type = HWTSTAMP_TX_OFF;
if (priv->hwts_rx_en & BIT(port))
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
else
config.rx_filter = HWTSTAMP_FILTER_NONE;
config->rx_filter = HWTSTAMP_FILTER_NONE;
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
return 0;
}
int sja1105_get_ts_info(struct dsa_switch *ds, int port,

View File

@ -112,9 +112,12 @@ bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
void sja1105_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb);
int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr);
int sja1105_hwtstamp_get(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config);
int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr);
int sja1105_hwtstamp_set(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns,
struct ptp_system_timestamp *sts);

View File

@ -869,24 +869,31 @@ static int ocelot_set_features(struct net_device *dev,
}
static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
return phy_mii_ioctl(dev->phydev, ifr, cmd);
}
static int ocelot_port_hwtstamp_get(struct net_device *dev,
struct kernel_hwtstamp_config *cfg)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot *ocelot = priv->port.ocelot;
int port = priv->port.index;
/* If the attached PHY device isn't capable of timestamping operations,
* use our own (when possible).
*/
if (!phy_has_hwtstamp(dev->phydev) && ocelot->ptp) {
switch (cmd) {
case SIOCSHWTSTAMP:
return ocelot_hwstamp_set(ocelot, port, ifr);
case SIOCGHWTSTAMP:
return ocelot_hwstamp_get(ocelot, port, ifr);
}
}
ocelot_hwstamp_get(ocelot, port, cfg);
return phy_mii_ioctl(dev->phydev, ifr, cmd);
return 0;
}
static int ocelot_port_hwtstamp_set(struct net_device *dev,
struct kernel_hwtstamp_config *cfg,
struct netlink_ext_ack *extack)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot *ocelot = priv->port.ocelot;
int port = priv->port.index;
return ocelot_hwstamp_set(ocelot, port, cfg, extack);
}
static int ocelot_change_mtu(struct net_device *dev, int new_mtu)
@ -917,6 +924,8 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_set_features = ocelot_set_features,
.ndo_setup_tc = ocelot_setup_tc,
.ndo_eth_ioctl = ocelot_ioctl,
.ndo_hwtstamp_get = ocelot_port_hwtstamp_get,
.ndo_hwtstamp_set = ocelot_port_hwtstamp_set,
};
struct net_device *ocelot_port_to_netdev(struct ocelot *ocelot, int port)

View File

@ -514,47 +514,42 @@ static int ocelot_ptp_tx_type_to_cmd(int tx_type, int *ptp_cmd)
return 0;
}
int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr)
void ocelot_hwstamp_get(struct ocelot *ocelot, int port,
struct kernel_hwtstamp_config *cfg)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
struct hwtstamp_config cfg = {};
switch (ocelot_port->ptp_cmd) {
case IFH_REW_OP_TWO_STEP_PTP:
cfg.tx_type = HWTSTAMP_TX_ON;
cfg->tx_type = HWTSTAMP_TX_ON;
break;
case IFH_REW_OP_ORIGIN_PTP:
cfg.tx_type = HWTSTAMP_TX_ONESTEP_SYNC;
cfg->tx_type = HWTSTAMP_TX_ONESTEP_SYNC;
break;
default:
cfg.tx_type = HWTSTAMP_TX_OFF;
cfg->tx_type = HWTSTAMP_TX_OFF;
break;
}
cfg.rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto);
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
cfg->rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto);
}
EXPORT_SYMBOL(ocelot_hwstamp_get);
int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
int ocelot_hwstamp_set(struct ocelot *ocelot, int port,
struct kernel_hwtstamp_config *cfg,
struct netlink_ext_ack *extack)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
int ptp_cmd, old_ptp_cmd = ocelot_port->ptp_cmd;
bool l2 = false, l4 = false;
struct hwtstamp_config cfg;
bool old_l2, old_l4;
int ptp_cmd;
int err;
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
return -EFAULT;
/* Tx type sanity check */
err = ocelot_ptp_tx_type_to_cmd(cfg.tx_type, &ptp_cmd);
err = ocelot_ptp_tx_type_to_cmd(cfg->tx_type, &ptp_cmd);
if (err)
return err;
switch (cfg.rx_filter) {
switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
@ -577,27 +572,15 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
return -ERANGE;
}
old_l2 = ocelot_port->trap_proto & OCELOT_PROTO_PTP_L2;
old_l4 = ocelot_port->trap_proto & OCELOT_PROTO_PTP_L4;
err = ocelot_setup_ptp_traps(ocelot, port, l2, l4);
if (err)
return err;
ocelot_port->ptp_cmd = ptp_cmd;
cfg.rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto);
if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg))) {
err = -EFAULT;
goto out_restore_ptp_traps;
}
cfg->rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto);
return 0;
out_restore_ptp_traps:
ocelot_setup_ptp_traps(ocelot, port, old_l2, old_l4);
ocelot_port->ptp_cmd = old_ptp_cmd;
return err;
}
EXPORT_SYMBOL(ocelot_hwstamp_set);

View File

@ -1131,9 +1131,10 @@ struct dsa_switch_ops {
* PTP functionality
*/
int (*port_hwtstamp_get)(struct dsa_switch *ds, int port,
struct ifreq *ifr);
struct kernel_hwtstamp_config *config);
int (*port_hwtstamp_set)(struct dsa_switch *ds, int port,
struct ifreq *ifr);
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
void (*port_txtstamp)(struct dsa_switch *ds, int port,
struct sk_buff *skb);
bool (*port_rxtstamp)(struct dsa_switch *ds, int port,

View File

@ -1073,8 +1073,11 @@ int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid,
int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged);
int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid);
int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr);
int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr);
void ocelot_hwstamp_get(struct ocelot *ocelot, int port,
struct kernel_hwtstamp_config *cfg);
int ocelot_hwstamp_set(struct ocelot *ocelot, int port,
struct kernel_hwtstamp_config *cfg,
struct netlink_ext_ack *extack);
int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
struct sk_buff *skb,
struct sk_buff **clone);

View File

@ -116,19 +116,15 @@ static bool dsa_port_can_configure_learning(struct dsa_port *dp)
bool dsa_port_supports_hwtstamp(struct dsa_port *dp)
{
struct kernel_hwtstamp_config config = {};
struct dsa_switch *ds = dp->ds;
struct ifreq ifr = {};
int err;
if (!ds->ops->port_hwtstamp_get || !ds->ops->port_hwtstamp_set)
return false;
/* "See through" shim implementations of the "get" method.
* Since we can't cook up a complete ioctl request structure, this will
* fail in copy_to_user() with -EFAULT, which hopefully is enough to
* detect a valid implementation.
*/
err = ds->ops->port_hwtstamp_get(ds, dp->index, &ifr);
/* "See through" shim implementations of the "get" method. */
err = ds->ops->port_hwtstamp_get(ds, dp->index, &config);
return err != -EOPNOTSUPP;
}

View File

@ -578,20 +578,6 @@ dsa_user_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
static int dsa_user_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct dsa_user_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->dp->ds;
int port = p->dp->index;
/* Pass through to switch driver if it supports timestamping */
switch (cmd) {
case SIOCGHWTSTAMP:
if (ds->ops->port_hwtstamp_get)
return ds->ops->port_hwtstamp_get(ds, port, ifr);
break;
case SIOCSHWTSTAMP:
if (ds->ops->port_hwtstamp_set)
return ds->ops->port_hwtstamp_set(ds, port, ifr);
break;
}
return phylink_mii_ioctl(p->dp->pl, ifr, cmd);
}
@ -2574,6 +2560,31 @@ static int dsa_user_fill_forward_path(struct net_device_path_ctx *ctx,
return 0;
}
static int dsa_user_hwtstamp_get(struct net_device *dev,
struct kernel_hwtstamp_config *cfg)
{
struct dsa_port *dp = dsa_user_to_port(dev);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->port_hwtstamp_get)
return -EOPNOTSUPP;
return ds->ops->port_hwtstamp_get(ds, dp->index, cfg);
}
static int dsa_user_hwtstamp_set(struct net_device *dev,
struct kernel_hwtstamp_config *cfg,
struct netlink_ext_ack *extack)
{
struct dsa_port *dp = dsa_user_to_port(dev);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->port_hwtstamp_set)
return -EOPNOTSUPP;
return ds->ops->port_hwtstamp_set(ds, dp->index, cfg, extack);
}
static const struct net_device_ops dsa_user_netdev_ops = {
.ndo_open = dsa_user_open,
.ndo_stop = dsa_user_close,
@ -2595,6 +2606,8 @@ static const struct net_device_ops dsa_user_netdev_ops = {
.ndo_vlan_rx_kill_vid = dsa_user_vlan_rx_kill_vid,
.ndo_change_mtu = dsa_user_change_mtu,
.ndo_fill_forward_path = dsa_user_fill_forward_path,
.ndo_hwtstamp_get = dsa_user_hwtstamp_get,
.ndo_hwtstamp_set = dsa_user_hwtstamp_set,
};
static const struct device_type dsa_type = {