Commit b23ec2bd authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'introduce-ndo_hwtstamp_get-and-ndo_hwtstamp_set'

Vladimir Oltean says:

====================
Introduce ndo_hwtstamp_get() and ndo_hwtstamp_set()

Based on previous RFCs from Maxim Georgiev:
https://lore.kernel.org/netdev/20230502043150.17097-1-glipus@gmail.com/

this series attempts to introduce new API for the hardware timestamping
control path (SIOCGHWTSTAMP and SIOCSHWTSTAMP handling).

I don't have any board with phylib hardware timestamping, so I would
appreciate testing (especially on lan966x, the most intricate
conversion). I was, however, able to test netdev level timestamping,
because I also have some more unsubmitted conversions in progress:

https://github.com/vladimiroltean/linux/commits/ndo-hwtstamp-v9

I hope that the concerns expressed in the comments of previous series
were addressed, and that Köry Maincent's series:
https://lore.kernel.org/netdev/20230406173308.401924-1-kory.maincent@bootlin.com/
can make progress in parallel with the conversion of the rest of drivers.
====================

Link: https://lore.kernel.org/r/20230801142824.1772134-1-vladimir.oltean@nxp.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 72c1a284 fd770e85
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7752,6 +7752,7 @@ F: include/linux/mii.h
F:	include/linux/of_net.h
F:	include/linux/phy.h
F:	include/linux/phy_fixed.h
F:	include/linux/phylib_stubs.h
F:	include/linux/platform_data/mdio-bcm-unimac.h
F:	include/linux/platform_data/mdio-gpio.h
F:	include/trace/events/mdio.h
+65 −40
Original line number Diff line number Diff line
@@ -4446,11 +4446,6 @@ static int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cm
{
	struct bonding *bond = netdev_priv(bond_dev);
	struct mii_ioctl_data *mii = NULL;
	const struct net_device_ops *ops;
	struct net_device *real_dev;
	struct hwtstamp_config cfg;
	struct ifreq ifrr;
	int res = 0;

	netdev_dbg(bond_dev, "bond_eth_ioctl: cmd=%d\n", cmd);

@@ -4477,44 +4472,11 @@ static int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cm
		}

		break;
	case SIOCSHWTSTAMP:
		if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
			return -EFAULT;

		if (!(cfg.flags & HWTSTAMP_FLAG_BONDED_PHC_INDEX))
			return -EOPNOTSUPP;

		fallthrough;
	case SIOCGHWTSTAMP:
		real_dev = bond_option_active_slave_get_rcu(bond);
		if (!real_dev)
			return -EOPNOTSUPP;

		strscpy_pad(ifrr.ifr_name, real_dev->name, IFNAMSIZ);
		ifrr.ifr_ifru = ifr->ifr_ifru;

		ops = real_dev->netdev_ops;
		if (netif_device_present(real_dev) && ops->ndo_eth_ioctl) {
			res = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
			if (res)
				return res;

			ifr->ifr_ifru = ifrr.ifr_ifru;
			if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
				return -EFAULT;

			/* Set the BOND_PHC_INDEX flag to notify user space */
			cfg.flags |= HWTSTAMP_FLAG_BONDED_PHC_INDEX;

			return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ?
				-EFAULT : 0;
		}
		fallthrough;
	default:
		res = -EOPNOTSUPP;
		return -EOPNOTSUPP;
	}

	return res;
	return 0;
}

static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd)
@@ -5688,6 +5650,67 @@ static u32 bond_mode_bcast_speed(struct slave *slave, u32 speed)
	return speed;
}

/* Set the BOND_PHC_INDEX flag to notify user space */
static int bond_set_phc_index_flag(struct kernel_hwtstamp_config *kernel_cfg)
{
	struct ifreq *ifr = kernel_cfg->ifr;
	struct hwtstamp_config cfg;

	if (kernel_cfg->copied_to_user) {
		/* Lower device has a legacy implementation */
		if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
			return -EFAULT;

		cfg.flags |= HWTSTAMP_FLAG_BONDED_PHC_INDEX;
		if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
			return -EFAULT;
	} else {
		kernel_cfg->flags |= HWTSTAMP_FLAG_BONDED_PHC_INDEX;
	}

	return 0;
}

static int bond_hwtstamp_get(struct net_device *dev,
			     struct kernel_hwtstamp_config *cfg)
{
	struct bonding *bond = netdev_priv(dev);
	struct net_device *real_dev;
	int err;

	real_dev = bond_option_active_slave_get_rcu(bond);
	if (!real_dev)
		return -EOPNOTSUPP;

	err = generic_hwtstamp_get_lower(real_dev, cfg);
	if (err)
		return err;

	return bond_set_phc_index_flag(cfg);
}

static int bond_hwtstamp_set(struct net_device *dev,
			     struct kernel_hwtstamp_config *cfg,
			     struct netlink_ext_ack *extack)
{
	struct bonding *bond = netdev_priv(dev);
	struct net_device *real_dev;
	int err;

	if (!(cfg->flags & HWTSTAMP_FLAG_BONDED_PHC_INDEX))
		return -EOPNOTSUPP;

	real_dev = bond_option_active_slave_get_rcu(bond);
	if (!real_dev)
		return -EOPNOTSUPP;

	err = generic_hwtstamp_set_lower(real_dev, cfg, extack);
	if (err)
		return err;

	return bond_set_phc_index_flag(cfg);
}

static int bond_ethtool_get_link_ksettings(struct net_device *bond_dev,
					   struct ethtool_link_ksettings *cmd)
{
@@ -5836,6 +5859,8 @@ static const struct net_device_ops bond_netdev_ops = {
	.ndo_bpf		= bond_xdp,
	.ndo_xdp_xmit           = bond_xdp_xmit,
	.ndo_xdp_get_xmit_slave = bond_xdp_get_xmit_slave,
	.ndo_hwtstamp_get	= bond_hwtstamp_get,
	.ndo_hwtstamp_set	= bond_hwtstamp_set,
};

static const struct device_type bond_type = {
+3 −3
Original line number Diff line number Diff line
@@ -698,9 +698,9 @@ struct fec_enet_private {
void fec_ptp_init(struct platform_device *pdev, int irq_idx);
void fec_ptp_stop(struct platform_device *pdev);
void fec_ptp_start_cyclecounter(struct net_device *ndev);
void fec_ptp_disable_hwts(struct net_device *ndev);
int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
int fec_ptp_set(struct net_device *ndev, struct kernel_hwtstamp_config *config,
		struct netlink_ext_ack *extack);
void fec_ptp_get(struct net_device *ndev, struct kernel_hwtstamp_config *config);

/****************************************************************************/
#endif /* FEC_H */
+34 −28
Original line number Diff line number Diff line
@@ -3203,33 +3203,6 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
	.self_test		= net_selftest,
};

static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
{
	struct fec_enet_private *fep = netdev_priv(ndev);
	struct phy_device *phydev = ndev->phydev;

	if (!netif_running(ndev))
		return -EINVAL;

	if (!phydev)
		return -ENODEV;

	if (fep->bufdesc_ex) {
		bool use_fec_hwts = !phy_has_hwtstamp(phydev);

		if (cmd == SIOCSHWTSTAMP) {
			if (use_fec_hwts)
				return fec_ptp_set(ndev, rq);
			fec_ptp_disable_hwts(ndev);
		} else if (cmd == SIOCGHWTSTAMP) {
			if (use_fec_hwts)
				return fec_ptp_get(ndev, rq);
		}
	}

	return phy_mii_ioctl(phydev, rq, cmd);
}

static void fec_enet_free_buffers(struct net_device *ndev)
{
	struct fec_enet_private *fep = netdev_priv(ndev);
@@ -3895,6 +3868,37 @@ static int fec_enet_xdp_xmit(struct net_device *dev,
	return sent_frames;
}

static int fec_hwtstamp_get(struct net_device *ndev,
			    struct kernel_hwtstamp_config *config)
{
	struct fec_enet_private *fep = netdev_priv(ndev);

	if (!netif_running(ndev))
		return -EINVAL;

	if (!fep->bufdesc_ex)
		return -EOPNOTSUPP;

	fec_ptp_get(ndev, config);

	return 0;
}

static int fec_hwtstamp_set(struct net_device *ndev,
			    struct kernel_hwtstamp_config *config,
			    struct netlink_ext_ack *extack)
{
	struct fec_enet_private *fep = netdev_priv(ndev);

	if (!netif_running(ndev))
		return -EINVAL;

	if (!fep->bufdesc_ex)
		return -EOPNOTSUPP;

	return fec_ptp_set(ndev, config, extack);
}

static const struct net_device_ops fec_netdev_ops = {
	.ndo_open		= fec_enet_open,
	.ndo_stop		= fec_enet_close,
@@ -3904,13 +3908,15 @@ static const struct net_device_ops fec_netdev_ops = {
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_tx_timeout		= fec_timeout,
	.ndo_set_mac_address	= fec_set_mac_address,
	.ndo_eth_ioctl		= fec_enet_ioctl,
	.ndo_eth_ioctl		= phy_do_ioctl_running,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= fec_poll_controller,
#endif
	.ndo_set_features	= fec_set_features,
	.ndo_bpf		= fec_enet_bpf,
	.ndo_xdp_xmit		= fec_enet_xdp_xmit,
	.ndo_hwtstamp_get	= fec_hwtstamp_get,
	.ndo_hwtstamp_set	= fec_hwtstamp_set,
};

static const unsigned short offset_des_active_rxq[] = {
+11 −32
Original line number Diff line number Diff line
@@ -605,28 +605,12 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
	}
}

/**
 * fec_ptp_disable_hwts - disable hardware time stamping
 * @ndev: pointer to net_device
 */
void fec_ptp_disable_hwts(struct net_device *ndev)
int fec_ptp_set(struct net_device *ndev, struct kernel_hwtstamp_config *config,
		struct netlink_ext_ack *extack)
{
	struct fec_enet_private *fep = netdev_priv(ndev);

	fep->hwts_tx_en = 0;
	fep->hwts_rx_en = 0;
}

int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr)
{
	struct fec_enet_private *fep = netdev_priv(ndev);

	struct hwtstamp_config config;

	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
		return -EFAULT;

	switch (config.tx_type) {
	switch (config->tx_type) {
	case HWTSTAMP_TX_OFF:
		fep->hwts_tx_en = 0;
		break;
@@ -637,33 +621,28 @@ int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr)
		return -ERANGE;
	}

	switch (config.rx_filter) {
	switch (config->rx_filter) {
	case HWTSTAMP_FILTER_NONE:
		fep->hwts_rx_en = 0;
		break;

	default:
		fep->hwts_rx_en = 1;
		config.rx_filter = HWTSTAMP_FILTER_ALL;
		config->rx_filter = HWTSTAMP_FILTER_ALL;
		break;
	}

	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
	    -EFAULT : 0;
	return 0;
}

int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr)
void fec_ptp_get(struct net_device *ndev, struct kernel_hwtstamp_config *config)
{
	struct fec_enet_private *fep = netdev_priv(ndev);
	struct hwtstamp_config config;

	config.flags = 0;
	config.tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
	config.rx_filter = (fep->hwts_rx_en ?
	config->flags = 0;
	config->tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
	config->rx_filter = (fep->hwts_rx_en ?
			     HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);

	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
		-EFAULT : 0;
}

/*
Loading