mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-09 08:02:05 +00:00
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: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
b23ec2bd7b
23 changed files with 630 additions and 209 deletions
|
@ -7752,6 +7752,7 @@ F: include/linux/mii.h
|
||||||
F: include/linux/of_net.h
|
F: include/linux/of_net.h
|
||||||
F: include/linux/phy.h
|
F: include/linux/phy.h
|
||||||
F: include/linux/phy_fixed.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-bcm-unimac.h
|
||||||
F: include/linux/platform_data/mdio-gpio.h
|
F: include/linux/platform_data/mdio-gpio.h
|
||||||
F: include/trace/events/mdio.h
|
F: include/trace/events/mdio.h
|
||||||
|
|
|
@ -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 bonding *bond = netdev_priv(bond_dev);
|
||||||
struct mii_ioctl_data *mii = NULL;
|
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);
|
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;
|
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:
|
default:
|
||||||
res = -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd)
|
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;
|
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,
|
static int bond_ethtool_get_link_ksettings(struct net_device *bond_dev,
|
||||||
struct ethtool_link_ksettings *cmd)
|
struct ethtool_link_ksettings *cmd)
|
||||||
{
|
{
|
||||||
|
@ -5836,6 +5859,8 @@ static const struct net_device_ops bond_netdev_ops = {
|
||||||
.ndo_bpf = bond_xdp,
|
.ndo_bpf = bond_xdp,
|
||||||
.ndo_xdp_xmit = bond_xdp_xmit,
|
.ndo_xdp_xmit = bond_xdp_xmit,
|
||||||
.ndo_xdp_get_xmit_slave = bond_xdp_get_xmit_slave,
|
.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 = {
|
static const struct device_type bond_type = {
|
||||||
|
|
|
@ -698,9 +698,9 @@ struct fec_enet_private {
|
||||||
void fec_ptp_init(struct platform_device *pdev, int irq_idx);
|
void fec_ptp_init(struct platform_device *pdev, int irq_idx);
|
||||||
void fec_ptp_stop(struct platform_device *pdev);
|
void fec_ptp_stop(struct platform_device *pdev);
|
||||||
void fec_ptp_start_cyclecounter(struct net_device *ndev);
|
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 kernel_hwtstamp_config *config,
|
||||||
int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
|
struct netlink_ext_ack *extack);
|
||||||
int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
|
void fec_ptp_get(struct net_device *ndev, struct kernel_hwtstamp_config *config);
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
#endif /* FEC_H */
|
#endif /* FEC_H */
|
||||||
|
|
|
@ -3203,33 +3203,6 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
|
||||||
.self_test = net_selftest,
|
.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)
|
static void fec_enet_free_buffers(struct net_device *ndev)
|
||||||
{
|
{
|
||||||
struct fec_enet_private *fep = netdev_priv(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;
|
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 = {
|
static const struct net_device_ops fec_netdev_ops = {
|
||||||
.ndo_open = fec_enet_open,
|
.ndo_open = fec_enet_open,
|
||||||
.ndo_stop = fec_enet_close,
|
.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_validate_addr = eth_validate_addr,
|
||||||
.ndo_tx_timeout = fec_timeout,
|
.ndo_tx_timeout = fec_timeout,
|
||||||
.ndo_set_mac_address = fec_set_mac_address,
|
.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
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
.ndo_poll_controller = fec_poll_controller,
|
.ndo_poll_controller = fec_poll_controller,
|
||||||
#endif
|
#endif
|
||||||
.ndo_set_features = fec_set_features,
|
.ndo_set_features = fec_set_features,
|
||||||
.ndo_bpf = fec_enet_bpf,
|
.ndo_bpf = fec_enet_bpf,
|
||||||
.ndo_xdp_xmit = fec_enet_xdp_xmit,
|
.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[] = {
|
static const unsigned short offset_des_active_rxq[] = {
|
||||||
|
|
|
@ -605,28 +605,12 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int fec_ptp_set(struct net_device *ndev, struct kernel_hwtstamp_config *config,
|
||||||
* fec_ptp_disable_hwts - disable hardware time stamping
|
struct netlink_ext_ack *extack)
|
||||||
* @ndev: pointer to net_device
|
|
||||||
*/
|
|
||||||
void fec_ptp_disable_hwts(struct net_device *ndev)
|
|
||||||
{
|
{
|
||||||
struct fec_enet_private *fep = netdev_priv(ndev);
|
struct fec_enet_private *fep = netdev_priv(ndev);
|
||||||
|
|
||||||
fep->hwts_tx_en = 0;
|
switch (config->tx_type) {
|
||||||
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) {
|
|
||||||
case HWTSTAMP_TX_OFF:
|
case HWTSTAMP_TX_OFF:
|
||||||
fep->hwts_tx_en = 0;
|
fep->hwts_tx_en = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -637,33 +621,28 @@ int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (config.rx_filter) {
|
switch (config->rx_filter) {
|
||||||
case HWTSTAMP_FILTER_NONE:
|
case HWTSTAMP_FILTER_NONE:
|
||||||
fep->hwts_rx_en = 0;
|
fep->hwts_rx_en = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fep->hwts_rx_en = 1;
|
fep->hwts_rx_en = 1;
|
||||||
config.rx_filter = HWTSTAMP_FILTER_ALL;
|
config->rx_filter = HWTSTAMP_FILTER_ALL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
|
return 0;
|
||||||
-EFAULT : 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 fec_enet_private *fep = netdev_priv(ndev);
|
||||||
struct hwtstamp_config config;
|
|
||||||
|
|
||||||
config.flags = 0;
|
config->flags = 0;
|
||||||
config.tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
|
config->tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
|
||||||
config.rx_filter = (fep->hwts_rx_en ?
|
config->rx_filter = (fep->hwts_rx_en ?
|
||||||
HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);
|
HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);
|
||||||
|
|
||||||
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
|
|
||||||
-EFAULT : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -450,39 +450,46 @@ static int lan966x_port_get_parent_id(struct net_device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lan966x_port_ioctl(struct net_device *dev, struct ifreq *ifr,
|
static int lan966x_port_hwtstamp_get(struct net_device *dev,
|
||||||
int cmd)
|
struct kernel_hwtstamp_config *cfg)
|
||||||
|
{
|
||||||
|
struct lan966x_port *port = netdev_priv(dev);
|
||||||
|
|
||||||
|
if (!port->lan966x->ptp)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
lan966x_ptp_hwtstamp_get(port, cfg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lan966x_port_hwtstamp_set(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct lan966x_port *port = netdev_priv(dev);
|
struct lan966x_port *port = netdev_priv(dev);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (cmd == SIOCSHWTSTAMP) {
|
if (cfg->source != HWTSTAMP_SOURCE_NETDEV &&
|
||||||
err = lan966x_ptp_setup_traps(port, ifr);
|
cfg->source != HWTSTAMP_SOURCE_PHYLIB)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
err = lan966x_ptp_setup_traps(port, cfg);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
if (!phy_has_hwtstamp(dev->phydev) && port->lan966x->ptp) {
|
if (cfg->source == HWTSTAMP_SOURCE_NETDEV) {
|
||||||
switch (cmd) {
|
if (!port->lan966x->ptp)
|
||||||
case SIOCSHWTSTAMP:
|
return -EOPNOTSUPP;
|
||||||
err = lan966x_ptp_hwtstamp_set(port, ifr);
|
|
||||||
if (err)
|
err = lan966x_ptp_hwtstamp_set(port, cfg, extack);
|
||||||
|
if (err) {
|
||||||
lan966x_ptp_del_traps(port);
|
lan966x_ptp_del_traps(port);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
case SIOCGHWTSTAMP:
|
|
||||||
return lan966x_ptp_hwtstamp_get(port, ifr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev->phydev)
|
return 0;
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
err = phy_mii_ioctl(dev->phydev, ifr, cmd);
|
|
||||||
if (err && cmd == SIOCSHWTSTAMP)
|
|
||||||
lan966x_ptp_del_traps(port);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct net_device_ops lan966x_port_netdev_ops = {
|
static const struct net_device_ops lan966x_port_netdev_ops = {
|
||||||
|
@ -495,10 +502,12 @@ static const struct net_device_ops lan966x_port_netdev_ops = {
|
||||||
.ndo_get_stats64 = lan966x_stats_get,
|
.ndo_get_stats64 = lan966x_stats_get,
|
||||||
.ndo_set_mac_address = lan966x_port_set_mac_address,
|
.ndo_set_mac_address = lan966x_port_set_mac_address,
|
||||||
.ndo_get_port_parent_id = lan966x_port_get_parent_id,
|
.ndo_get_port_parent_id = lan966x_port_get_parent_id,
|
||||||
.ndo_eth_ioctl = lan966x_port_ioctl,
|
.ndo_eth_ioctl = phy_do_ioctl,
|
||||||
.ndo_setup_tc = lan966x_tc_setup,
|
.ndo_setup_tc = lan966x_tc_setup,
|
||||||
.ndo_bpf = lan966x_xdp,
|
.ndo_bpf = lan966x_xdp,
|
||||||
.ndo_xdp_xmit = lan966x_xdp_xmit,
|
.ndo_xdp_xmit = lan966x_xdp_xmit,
|
||||||
|
.ndo_hwtstamp_get = lan966x_port_hwtstamp_get,
|
||||||
|
.ndo_hwtstamp_set = lan966x_port_hwtstamp_set,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool lan966x_netdevice_check(const struct net_device *dev)
|
bool lan966x_netdevice_check(const struct net_device *dev)
|
||||||
|
@ -808,6 +817,7 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
|
||||||
NETIF_F_HW_VLAN_STAG_TX |
|
NETIF_F_HW_VLAN_STAG_TX |
|
||||||
NETIF_F_HW_TC;
|
NETIF_F_HW_TC;
|
||||||
dev->hw_features |= NETIF_F_HW_TC;
|
dev->hw_features |= NETIF_F_HW_TC;
|
||||||
|
dev->priv_flags |= IFF_SEE_ALL_HWTSTAMP_REQUESTS;
|
||||||
dev->needed_headroom = IFH_LEN_BYTES;
|
dev->needed_headroom = IFH_LEN_BYTES;
|
||||||
|
|
||||||
eth_hw_addr_gen(dev, lan966x->base_mac, p + 1);
|
eth_hw_addr_gen(dev, lan966x->base_mac, p + 1);
|
||||||
|
|
|
@ -298,7 +298,7 @@ struct lan966x_phc {
|
||||||
struct ptp_clock *clock;
|
struct ptp_clock *clock;
|
||||||
struct ptp_clock_info info;
|
struct ptp_clock_info info;
|
||||||
struct ptp_pin_desc pins[LAN966X_PHC_PINS_NUM];
|
struct ptp_pin_desc pins[LAN966X_PHC_PINS_NUM];
|
||||||
struct hwtstamp_config hwtstamp_config;
|
struct kernel_hwtstamp_config hwtstamp_config;
|
||||||
struct lan966x *lan966x;
|
struct lan966x *lan966x;
|
||||||
u8 index;
|
u8 index;
|
||||||
};
|
};
|
||||||
|
@ -578,8 +578,11 @@ void lan966x_mdb_restore_entries(struct lan966x *lan966x);
|
||||||
|
|
||||||
int lan966x_ptp_init(struct lan966x *lan966x);
|
int lan966x_ptp_init(struct lan966x *lan966x);
|
||||||
void lan966x_ptp_deinit(struct lan966x *lan966x);
|
void lan966x_ptp_deinit(struct lan966x *lan966x);
|
||||||
int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr);
|
int lan966x_ptp_hwtstamp_set(struct lan966x_port *port,
|
||||||
int lan966x_ptp_hwtstamp_get(struct lan966x_port *port, struct ifreq *ifr);
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
|
void lan966x_ptp_hwtstamp_get(struct lan966x_port *port,
|
||||||
|
struct kernel_hwtstamp_config *cfg);
|
||||||
void lan966x_ptp_rxtstamp(struct lan966x *lan966x, struct sk_buff *skb,
|
void lan966x_ptp_rxtstamp(struct lan966x *lan966x, struct sk_buff *skb,
|
||||||
u64 src_port, u64 timestamp);
|
u64 src_port, u64 timestamp);
|
||||||
int lan966x_ptp_txtstamp_request(struct lan966x_port *port,
|
int lan966x_ptp_txtstamp_request(struct lan966x_port *port,
|
||||||
|
@ -590,7 +593,8 @@ irqreturn_t lan966x_ptp_irq_handler(int irq, void *args);
|
||||||
irqreturn_t lan966x_ptp_ext_irq_handler(int irq, void *args);
|
irqreturn_t lan966x_ptp_ext_irq_handler(int irq, void *args);
|
||||||
u32 lan966x_ptp_get_period_ps(void);
|
u32 lan966x_ptp_get_period_ps(void);
|
||||||
int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
|
int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
|
||||||
int lan966x_ptp_setup_traps(struct lan966x_port *port, struct ifreq *ifr);
|
int lan966x_ptp_setup_traps(struct lan966x_port *port,
|
||||||
|
struct kernel_hwtstamp_config *cfg);
|
||||||
int lan966x_ptp_del_traps(struct lan966x_port *port);
|
int lan966x_ptp_del_traps(struct lan966x_port *port);
|
||||||
|
|
||||||
int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev);
|
int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev);
|
||||||
|
|
|
@ -248,29 +248,23 @@ int lan966x_ptp_del_traps(struct lan966x_port *port)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lan966x_ptp_setup_traps(struct lan966x_port *port, struct ifreq *ifr)
|
int lan966x_ptp_setup_traps(struct lan966x_port *port,
|
||||||
|
struct kernel_hwtstamp_config *cfg)
|
||||||
{
|
{
|
||||||
struct hwtstamp_config cfg;
|
if (cfg->rx_filter == HWTSTAMP_FILTER_NONE)
|
||||||
|
|
||||||
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (cfg.rx_filter == HWTSTAMP_FILTER_NONE)
|
|
||||||
return lan966x_ptp_del_traps(port);
|
return lan966x_ptp_del_traps(port);
|
||||||
else
|
else
|
||||||
return lan966x_ptp_add_traps(port);
|
return lan966x_ptp_add_traps(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr)
|
int lan966x_ptp_hwtstamp_set(struct lan966x_port *port,
|
||||||
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct lan966x *lan966x = port->lan966x;
|
struct lan966x *lan966x = port->lan966x;
|
||||||
struct hwtstamp_config cfg;
|
|
||||||
struct lan966x_phc *phc;
|
struct lan966x_phc *phc;
|
||||||
|
|
||||||
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
|
switch (cfg->tx_type) {
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
switch (cfg.tx_type) {
|
|
||||||
case HWTSTAMP_TX_ON:
|
case HWTSTAMP_TX_ON:
|
||||||
port->ptp_tx_cmd = IFH_REW_OP_TWO_STEP_PTP;
|
port->ptp_tx_cmd = IFH_REW_OP_TWO_STEP_PTP;
|
||||||
break;
|
break;
|
||||||
|
@ -284,7 +278,7 @@ int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cfg.rx_filter) {
|
switch (cfg->rx_filter) {
|
||||||
case HWTSTAMP_FILTER_NONE:
|
case HWTSTAMP_FILTER_NONE:
|
||||||
port->ptp_rx_cmd = false;
|
port->ptp_rx_cmd = false;
|
||||||
break;
|
break;
|
||||||
|
@ -303,7 +297,7 @@ int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr)
|
||||||
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
|
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
|
||||||
case HWTSTAMP_FILTER_NTP_ALL:
|
case HWTSTAMP_FILTER_NTP_ALL:
|
||||||
port->ptp_rx_cmd = true;
|
port->ptp_rx_cmd = true;
|
||||||
cfg.rx_filter = HWTSTAMP_FILTER_ALL;
|
cfg->rx_filter = HWTSTAMP_FILTER_ALL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
@ -312,20 +306,20 @@ int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr)
|
||||||
/* Commit back the result & save it */
|
/* Commit back the result & save it */
|
||||||
mutex_lock(&lan966x->ptp_lock);
|
mutex_lock(&lan966x->ptp_lock);
|
||||||
phc = &lan966x->phc[LAN966X_PHC_PORT];
|
phc = &lan966x->phc[LAN966X_PHC_PORT];
|
||||||
memcpy(&phc->hwtstamp_config, &cfg, sizeof(cfg));
|
phc->hwtstamp_config = *cfg;
|
||||||
mutex_unlock(&lan966x->ptp_lock);
|
mutex_unlock(&lan966x->ptp_lock);
|
||||||
|
|
||||||
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lan966x_ptp_hwtstamp_get(struct lan966x_port *port, struct ifreq *ifr)
|
void lan966x_ptp_hwtstamp_get(struct lan966x_port *port,
|
||||||
|
struct kernel_hwtstamp_config *cfg)
|
||||||
{
|
{
|
||||||
struct lan966x *lan966x = port->lan966x;
|
struct lan966x *lan966x = port->lan966x;
|
||||||
struct lan966x_phc *phc;
|
struct lan966x_phc *phc;
|
||||||
|
|
||||||
phc = &lan966x->phc[LAN966X_PHC_PORT];
|
phc = &lan966x->phc[LAN966X_PHC_PORT];
|
||||||
return copy_to_user(ifr->ifr_data, &phc->hwtstamp_config,
|
*cfg = phc->hwtstamp_config;
|
||||||
sizeof(phc->hwtstamp_config)) ? -EFAULT : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lan966x_ptp_classify(struct lan966x_port *port, struct sk_buff *skb)
|
static int lan966x_ptp_classify(struct lan966x_port *port, struct sk_buff *skb)
|
||||||
|
|
|
@ -205,7 +205,7 @@ enum sparx5_core_clockfreq {
|
||||||
struct sparx5_phc {
|
struct sparx5_phc {
|
||||||
struct ptp_clock *clock;
|
struct ptp_clock *clock;
|
||||||
struct ptp_clock_info info;
|
struct ptp_clock_info info;
|
||||||
struct hwtstamp_config hwtstamp_config;
|
struct kernel_hwtstamp_config hwtstamp_config;
|
||||||
struct sparx5 *sparx5;
|
struct sparx5 *sparx5;
|
||||||
u8 index;
|
u8 index;
|
||||||
};
|
};
|
||||||
|
@ -388,8 +388,11 @@ void sparx5_unregister_netdevs(struct sparx5 *sparx5);
|
||||||
/* sparx5_ptp.c */
|
/* sparx5_ptp.c */
|
||||||
int sparx5_ptp_init(struct sparx5 *sparx5);
|
int sparx5_ptp_init(struct sparx5 *sparx5);
|
||||||
void sparx5_ptp_deinit(struct sparx5 *sparx5);
|
void sparx5_ptp_deinit(struct sparx5 *sparx5);
|
||||||
int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr);
|
int sparx5_ptp_hwtstamp_set(struct sparx5_port *port,
|
||||||
int sparx5_ptp_hwtstamp_get(struct sparx5_port *port, struct ifreq *ifr);
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
|
void sparx5_ptp_hwtstamp_get(struct sparx5_port *port,
|
||||||
|
struct kernel_hwtstamp_config *cfg);
|
||||||
void sparx5_ptp_rxtstamp(struct sparx5 *sparx5, struct sk_buff *skb,
|
void sparx5_ptp_rxtstamp(struct sparx5 *sparx5, struct sk_buff *skb,
|
||||||
u64 timestamp);
|
u64 timestamp);
|
||||||
int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
|
int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
|
||||||
|
|
|
@ -210,22 +210,31 @@ static int sparx5_get_port_parent_id(struct net_device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sparx5_port_ioctl(struct net_device *dev, struct ifreq *ifr,
|
static int sparx5_port_hwtstamp_get(struct net_device *dev,
|
||||||
int cmd)
|
struct kernel_hwtstamp_config *cfg)
|
||||||
{
|
{
|
||||||
struct sparx5_port *sparx5_port = netdev_priv(dev);
|
struct sparx5_port *sparx5_port = netdev_priv(dev);
|
||||||
struct sparx5 *sparx5 = sparx5_port->sparx5;
|
struct sparx5 *sparx5 = sparx5_port->sparx5;
|
||||||
|
|
||||||
if (!phy_has_hwtstamp(dev->phydev) && sparx5->ptp) {
|
if (!sparx5->ptp)
|
||||||
switch (cmd) {
|
return -EOPNOTSUPP;
|
||||||
case SIOCSHWTSTAMP:
|
|
||||||
return sparx5_ptp_hwtstamp_set(sparx5_port, ifr);
|
|
||||||
case SIOCGHWTSTAMP:
|
|
||||||
return sparx5_ptp_hwtstamp_get(sparx5_port, ifr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return phy_mii_ioctl(dev->phydev, ifr, cmd);
|
sparx5_ptp_hwtstamp_get(sparx5_port, cfg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sparx5_port_hwtstamp_set(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
struct sparx5_port *sparx5_port = netdev_priv(dev);
|
||||||
|
struct sparx5 *sparx5 = sparx5_port->sparx5;
|
||||||
|
|
||||||
|
if (!sparx5->ptp)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
return sparx5_ptp_hwtstamp_set(sparx5_port, cfg, extack);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct net_device_ops sparx5_port_netdev_ops = {
|
static const struct net_device_ops sparx5_port_netdev_ops = {
|
||||||
|
@ -238,8 +247,10 @@ static const struct net_device_ops sparx5_port_netdev_ops = {
|
||||||
.ndo_validate_addr = eth_validate_addr,
|
.ndo_validate_addr = eth_validate_addr,
|
||||||
.ndo_get_stats64 = sparx5_get_stats64,
|
.ndo_get_stats64 = sparx5_get_stats64,
|
||||||
.ndo_get_port_parent_id = sparx5_get_port_parent_id,
|
.ndo_get_port_parent_id = sparx5_get_port_parent_id,
|
||||||
.ndo_eth_ioctl = sparx5_port_ioctl,
|
.ndo_eth_ioctl = phy_do_ioctl,
|
||||||
.ndo_setup_tc = sparx5_port_setup_tc,
|
.ndo_setup_tc = sparx5_port_setup_tc,
|
||||||
|
.ndo_hwtstamp_get = sparx5_port_hwtstamp_get,
|
||||||
|
.ndo_hwtstamp_set = sparx5_port_hwtstamp_set,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool sparx5_netdevice_check(const struct net_device *dev)
|
bool sparx5_netdevice_check(const struct net_device *dev)
|
||||||
|
|
|
@ -74,10 +74,11 @@ static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
|
int sparx5_ptp_hwtstamp_set(struct sparx5_port *port,
|
||||||
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct sparx5 *sparx5 = port->sparx5;
|
struct sparx5 *sparx5 = port->sparx5;
|
||||||
struct hwtstamp_config cfg;
|
|
||||||
struct sparx5_phc *phc;
|
struct sparx5_phc *phc;
|
||||||
|
|
||||||
/* For now don't allow to run ptp on ports that are part of a bridge,
|
/* For now don't allow to run ptp on ports that are part of a bridge,
|
||||||
|
@ -88,10 +89,7 @@ int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
|
||||||
if (test_bit(port->portno, sparx5->bridge_mask))
|
if (test_bit(port->portno, sparx5->bridge_mask))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
|
switch (cfg->tx_type) {
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
switch (cfg.tx_type) {
|
|
||||||
case HWTSTAMP_TX_ON:
|
case HWTSTAMP_TX_ON:
|
||||||
port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
|
port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
|
||||||
break;
|
break;
|
||||||
|
@ -105,7 +103,7 @@ int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cfg.rx_filter) {
|
switch (cfg->rx_filter) {
|
||||||
case HWTSTAMP_FILTER_NONE:
|
case HWTSTAMP_FILTER_NONE:
|
||||||
break;
|
break;
|
||||||
case HWTSTAMP_FILTER_ALL:
|
case HWTSTAMP_FILTER_ALL:
|
||||||
|
@ -122,7 +120,7 @@ int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
|
||||||
case HWTSTAMP_FILTER_PTP_V2_SYNC:
|
case HWTSTAMP_FILTER_PTP_V2_SYNC:
|
||||||
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
|
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
|
||||||
case HWTSTAMP_FILTER_NTP_ALL:
|
case HWTSTAMP_FILTER_NTP_ALL:
|
||||||
cfg.rx_filter = HWTSTAMP_FILTER_ALL;
|
cfg->rx_filter = HWTSTAMP_FILTER_ALL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
@ -131,20 +129,20 @@ int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
|
||||||
/* Commit back the result & save it */
|
/* Commit back the result & save it */
|
||||||
mutex_lock(&sparx5->ptp_lock);
|
mutex_lock(&sparx5->ptp_lock);
|
||||||
phc = &sparx5->phc[SPARX5_PHC_PORT];
|
phc = &sparx5->phc[SPARX5_PHC_PORT];
|
||||||
memcpy(&phc->hwtstamp_config, &cfg, sizeof(cfg));
|
phc->hwtstamp_config = *cfg;
|
||||||
mutex_unlock(&sparx5->ptp_lock);
|
mutex_unlock(&sparx5->ptp_lock);
|
||||||
|
|
||||||
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sparx5_ptp_hwtstamp_get(struct sparx5_port *port, struct ifreq *ifr)
|
void sparx5_ptp_hwtstamp_get(struct sparx5_port *port,
|
||||||
|
struct kernel_hwtstamp_config *cfg)
|
||||||
{
|
{
|
||||||
struct sparx5 *sparx5 = port->sparx5;
|
struct sparx5 *sparx5 = port->sparx5;
|
||||||
struct sparx5_phc *phc;
|
struct sparx5_phc *phc;
|
||||||
|
|
||||||
phc = &sparx5->phc[SPARX5_PHC_PORT];
|
phc = &sparx5->phc[SPARX5_PHC_PORT];
|
||||||
return copy_to_user(ifr->ifr_data, &phc->hwtstamp_config,
|
*cfg = phc->hwtstamp_config;
|
||||||
sizeof(phc->hwtstamp_config)) ? -EFAULT : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sparx5_ptp_classify(struct sparx5_port *port, struct sk_buff *skb,
|
static void sparx5_ptp_classify(struct sparx5_port *port, struct sk_buff *skb,
|
||||||
|
|
|
@ -868,31 +868,24 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int macvlan_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
static int macvlan_hwtstamp_get(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *cfg)
|
||||||
{
|
{
|
||||||
struct net_device *real_dev = macvlan_dev_real_dev(dev);
|
struct net_device *real_dev = macvlan_dev_real_dev(dev);
|
||||||
const struct net_device_ops *ops = real_dev->netdev_ops;
|
|
||||||
struct ifreq ifrr;
|
|
||||||
int err = -EOPNOTSUPP;
|
|
||||||
|
|
||||||
strscpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ);
|
return generic_hwtstamp_get_lower(real_dev, cfg);
|
||||||
ifrr.ifr_ifru = ifr->ifr_ifru;
|
}
|
||||||
|
|
||||||
|
static int macvlan_hwtstamp_set(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
struct net_device *real_dev = macvlan_dev_real_dev(dev);
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case SIOCSHWTSTAMP:
|
|
||||||
if (!net_eq(dev_net(dev), &init_net))
|
if (!net_eq(dev_net(dev), &init_net))
|
||||||
break;
|
return -EOPNOTSUPP;
|
||||||
fallthrough;
|
|
||||||
case SIOCGHWTSTAMP:
|
|
||||||
if (netif_device_present(real_dev) && ops->ndo_eth_ioctl)
|
|
||||||
err = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!err)
|
return generic_hwtstamp_set_lower(real_dev, cfg, extack);
|
||||||
ifr->ifr_ifru = ifrr.ifr_ifru;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1193,7 +1186,6 @@ static const struct net_device_ops macvlan_netdev_ops = {
|
||||||
.ndo_stop = macvlan_stop,
|
.ndo_stop = macvlan_stop,
|
||||||
.ndo_start_xmit = macvlan_start_xmit,
|
.ndo_start_xmit = macvlan_start_xmit,
|
||||||
.ndo_change_mtu = macvlan_change_mtu,
|
.ndo_change_mtu = macvlan_change_mtu,
|
||||||
.ndo_eth_ioctl = macvlan_eth_ioctl,
|
|
||||||
.ndo_fix_features = macvlan_fix_features,
|
.ndo_fix_features = macvlan_fix_features,
|
||||||
.ndo_change_rx_flags = macvlan_change_rx_flags,
|
.ndo_change_rx_flags = macvlan_change_rx_flags,
|
||||||
.ndo_set_mac_address = macvlan_set_mac_address,
|
.ndo_set_mac_address = macvlan_set_mac_address,
|
||||||
|
@ -1212,6 +1204,8 @@ static const struct net_device_ops macvlan_netdev_ops = {
|
||||||
#endif
|
#endif
|
||||||
.ndo_get_iflink = macvlan_dev_get_iflink,
|
.ndo_get_iflink = macvlan_dev_get_iflink,
|
||||||
.ndo_features_check = passthru_features_check,
|
.ndo_features_check = passthru_features_check,
|
||||||
|
.ndo_hwtstamp_get = macvlan_hwtstamp_get,
|
||||||
|
.ndo_hwtstamp_set = macvlan_hwtstamp_set,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void macvlan_dev_free(struct net_device *dev)
|
static void macvlan_dev_free(struct net_device *dev)
|
||||||
|
|
|
@ -14,6 +14,8 @@ endif
|
||||||
# dedicated loadable module, so we bundle them all together into libphy.ko
|
# dedicated loadable module, so we bundle them all together into libphy.ko
|
||||||
ifdef CONFIG_PHYLIB
|
ifdef CONFIG_PHYLIB
|
||||||
libphy-y += $(mdio-bus-y)
|
libphy-y += $(mdio-bus-y)
|
||||||
|
# the stubs are built-in whenever PHYLIB is built-in or module
|
||||||
|
obj-y += stubs.o
|
||||||
else
|
else
|
||||||
obj-$(CONFIG_MDIO_DEVICE) += mdio-bus.o
|
obj-$(CONFIG_MDIO_DEVICE) += mdio-bus.o
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -455,6 +455,40 @@ int phy_do_ioctl_running(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(phy_do_ioctl_running);
|
EXPORT_SYMBOL(phy_do_ioctl_running);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __phy_hwtstamp_get - Get hardware timestamping configuration from PHY
|
||||||
|
*
|
||||||
|
* @phydev: the PHY device structure
|
||||||
|
* @config: structure holding the timestamping configuration
|
||||||
|
*
|
||||||
|
* Query the PHY device for its current hardware timestamping configuration.
|
||||||
|
*/
|
||||||
|
int __phy_hwtstamp_get(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config)
|
||||||
|
{
|
||||||
|
if (!phydev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return phy_mii_ioctl(phydev, config->ifr, SIOCGHWTSTAMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __phy_hwtstamp_set - Modify PHY hardware timestamping configuration
|
||||||
|
*
|
||||||
|
* @phydev: the PHY device structure
|
||||||
|
* @config: structure holding the timestamping configuration
|
||||||
|
* @extack: netlink extended ack structure, for error reporting
|
||||||
|
*/
|
||||||
|
int __phy_hwtstamp_set(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
if (!phydev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return phy_mii_ioctl(phydev, config->ifr, SIOCSHWTSTAMP);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* phy_queue_state_machine - Trigger the state machine to run soon
|
* phy_queue_state_machine - Trigger the state machine to run soon
|
||||||
*
|
*
|
||||||
|
|
|
@ -27,9 +27,11 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
|
#include <linux/phylib_stubs.h>
|
||||||
#include <linux/phy_led_triggers.h>
|
#include <linux/phy_led_triggers.h>
|
||||||
#include <linux/pse-pd/pse.h>
|
#include <linux/pse-pd/pse.h>
|
||||||
#include <linux/property.h>
|
#include <linux/property.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
#include <linux/sfp.h>
|
#include <linux/sfp.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
@ -3447,11 +3449,29 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
|
||||||
.start_cable_test_tdr = phy_start_cable_test_tdr,
|
.start_cable_test_tdr = phy_start_cable_test_tdr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct phylib_stubs __phylib_stubs = {
|
||||||
|
.hwtstamp_get = __phy_hwtstamp_get,
|
||||||
|
.hwtstamp_set = __phy_hwtstamp_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void phylib_register_stubs(void)
|
||||||
|
{
|
||||||
|
phylib_stubs = &__phylib_stubs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void phylib_unregister_stubs(void)
|
||||||
|
{
|
||||||
|
phylib_stubs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init phy_init(void)
|
static int __init phy_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
ethtool_set_ethtool_phy_ops(&phy_ethtool_phy_ops);
|
ethtool_set_ethtool_phy_ops(&phy_ethtool_phy_ops);
|
||||||
|
phylib_register_stubs();
|
||||||
|
rtnl_unlock();
|
||||||
|
|
||||||
rc = mdio_bus_init();
|
rc = mdio_bus_init();
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -3474,7 +3494,10 @@ err_c45:
|
||||||
err_mdio_bus:
|
err_mdio_bus:
|
||||||
mdio_bus_exit();
|
mdio_bus_exit();
|
||||||
err_ethtool_phy_ops:
|
err_ethtool_phy_ops:
|
||||||
|
rtnl_lock();
|
||||||
|
phylib_unregister_stubs();
|
||||||
ethtool_set_ethtool_phy_ops(NULL);
|
ethtool_set_ethtool_phy_ops(NULL);
|
||||||
|
rtnl_unlock();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -3484,7 +3507,10 @@ static void __exit phy_exit(void)
|
||||||
phy_driver_unregister(&genphy_c45_driver);
|
phy_driver_unregister(&genphy_c45_driver);
|
||||||
phy_driver_unregister(&genphy_driver);
|
phy_driver_unregister(&genphy_driver);
|
||||||
mdio_bus_exit();
|
mdio_bus_exit();
|
||||||
|
rtnl_lock();
|
||||||
|
phylib_unregister_stubs();
|
||||||
ethtool_set_ethtool_phy_ops(NULL);
|
ethtool_set_ethtool_phy_ops(NULL);
|
||||||
|
rtnl_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
subsys_initcall(phy_init);
|
subsys_initcall(phy_init);
|
||||||
|
|
10
drivers/net/phy/stubs.c
Normal file
10
drivers/net/phy/stubs.c
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Stubs for PHY library functionality called by the core network stack.
|
||||||
|
* These are necessary because CONFIG_PHYLIB can be a module, and built-in
|
||||||
|
* code cannot directly call symbols exported by modules.
|
||||||
|
*/
|
||||||
|
#include <linux/phylib_stubs.h>
|
||||||
|
|
||||||
|
const struct phylib_stubs *phylib_stubs;
|
||||||
|
EXPORT_SYMBOL_GPL(phylib_stubs);
|
|
@ -5,12 +5,23 @@
|
||||||
|
|
||||||
#include <uapi/linux/net_tstamp.h>
|
#include <uapi/linux/net_tstamp.h>
|
||||||
|
|
||||||
|
enum hwtstamp_source {
|
||||||
|
HWTSTAMP_SOURCE_NETDEV,
|
||||||
|
HWTSTAMP_SOURCE_PHYLIB,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config
|
* struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config
|
||||||
*
|
*
|
||||||
* @flags: see struct hwtstamp_config
|
* @flags: see struct hwtstamp_config
|
||||||
* @tx_type: see struct hwtstamp_config
|
* @tx_type: see struct hwtstamp_config
|
||||||
* @rx_filter: see struct hwtstamp_config
|
* @rx_filter: see struct hwtstamp_config
|
||||||
|
* @ifr: pointer to ifreq structure from the original ioctl request, to pass to
|
||||||
|
* a legacy implementation of a lower driver
|
||||||
|
* @copied_to_user: request was passed to a legacy implementation which already
|
||||||
|
* copied the ioctl request back to user space
|
||||||
|
* @source: indication whether timestamps should come from the netdev or from
|
||||||
|
* an attached phylib PHY
|
||||||
*
|
*
|
||||||
* Prefer using this structure for in-kernel processing of hardware
|
* Prefer using this structure for in-kernel processing of hardware
|
||||||
* timestamping configuration, over the inextensible struct hwtstamp_config
|
* timestamping configuration, over the inextensible struct hwtstamp_config
|
||||||
|
@ -20,6 +31,9 @@ struct kernel_hwtstamp_config {
|
||||||
int flags;
|
int flags;
|
||||||
int tx_type;
|
int tx_type;
|
||||||
int rx_filter;
|
int rx_filter;
|
||||||
|
struct ifreq *ifr;
|
||||||
|
bool copied_to_user;
|
||||||
|
enum hwtstamp_source source;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kernel_cfg,
|
static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kernel_cfg,
|
||||||
|
@ -30,4 +44,20 @@ static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kern
|
||||||
kernel_cfg->rx_filter = cfg->rx_filter;
|
kernel_cfg->rx_filter = cfg->rx_filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void hwtstamp_config_from_kernel(struct hwtstamp_config *cfg,
|
||||||
|
const struct kernel_hwtstamp_config *kernel_cfg)
|
||||||
|
{
|
||||||
|
cfg->flags = kernel_cfg->flags;
|
||||||
|
cfg->tx_type = kernel_cfg->tx_type;
|
||||||
|
cfg->rx_filter = kernel_cfg->rx_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool kernel_hwtstamp_config_changed(const struct kernel_hwtstamp_config *a,
|
||||||
|
const struct kernel_hwtstamp_config *b)
|
||||||
|
{
|
||||||
|
return a->flags != b->flags ||
|
||||||
|
a->tx_type != b->tx_type ||
|
||||||
|
a->rx_filter != b->rx_filter;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _LINUX_NET_TIMESTAMPING_H_ */
|
#endif /* _LINUX_NET_TIMESTAMPING_H_ */
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
struct netpoll_info;
|
struct netpoll_info;
|
||||||
struct device;
|
struct device;
|
||||||
struct ethtool_ops;
|
struct ethtool_ops;
|
||||||
|
struct kernel_hwtstamp_config;
|
||||||
struct phy_device;
|
struct phy_device;
|
||||||
struct dsa_port;
|
struct dsa_port;
|
||||||
struct ip_tunnel_parm;
|
struct ip_tunnel_parm;
|
||||||
|
@ -1418,6 +1419,16 @@ struct netdev_net_notifier {
|
||||||
* Get hardware timestamp based on normal/adjustable time or free running
|
* Get hardware timestamp based on normal/adjustable time or free running
|
||||||
* cycle counter. This function is required if physical clock supports a
|
* cycle counter. This function is required if physical clock supports a
|
||||||
* free running cycle counter.
|
* free running cycle counter.
|
||||||
|
*
|
||||||
|
* int (*ndo_hwtstamp_get)(struct net_device *dev,
|
||||||
|
* struct kernel_hwtstamp_config *kernel_config);
|
||||||
|
* Get the currently configured hardware timestamping parameters for the
|
||||||
|
* NIC device.
|
||||||
|
*
|
||||||
|
* int (*ndo_hwtstamp_set)(struct net_device *dev,
|
||||||
|
* struct kernel_hwtstamp_config *kernel_config,
|
||||||
|
* struct netlink_ext_ack *extack);
|
||||||
|
* Change the hardware timestamping parameters for NIC device.
|
||||||
*/
|
*/
|
||||||
struct net_device_ops {
|
struct net_device_ops {
|
||||||
int (*ndo_init)(struct net_device *dev);
|
int (*ndo_init)(struct net_device *dev);
|
||||||
|
@ -1652,6 +1663,11 @@ struct net_device_ops {
|
||||||
ktime_t (*ndo_get_tstamp)(struct net_device *dev,
|
ktime_t (*ndo_get_tstamp)(struct net_device *dev,
|
||||||
const struct skb_shared_hwtstamps *hwtstamps,
|
const struct skb_shared_hwtstamps *hwtstamps,
|
||||||
bool cycles);
|
bool cycles);
|
||||||
|
int (*ndo_hwtstamp_get)(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *kernel_config);
|
||||||
|
int (*ndo_hwtstamp_set)(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *kernel_config,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdp_metadata_ops {
|
struct xdp_metadata_ops {
|
||||||
|
@ -1708,6 +1724,9 @@ struct xdp_metadata_ops {
|
||||||
* @IFF_TX_SKB_NO_LINEAR: device/driver is capable of xmitting frames with
|
* @IFF_TX_SKB_NO_LINEAR: device/driver is capable of xmitting frames with
|
||||||
* skb_headlen(skb) == 0 (data starts from frag0)
|
* skb_headlen(skb) == 0 (data starts from frag0)
|
||||||
* @IFF_CHANGE_PROTO_DOWN: device supports setting carrier via IFLA_PROTO_DOWN
|
* @IFF_CHANGE_PROTO_DOWN: device supports setting carrier via IFLA_PROTO_DOWN
|
||||||
|
* @IFF_SEE_ALL_HWTSTAMP_REQUESTS: device wants to see calls to
|
||||||
|
* ndo_hwtstamp_set() for all timestamp requests regardless of source,
|
||||||
|
* even if those aren't HWTSTAMP_SOURCE_NETDEV.
|
||||||
*/
|
*/
|
||||||
enum netdev_priv_flags {
|
enum netdev_priv_flags {
|
||||||
IFF_802_1Q_VLAN = 1<<0,
|
IFF_802_1Q_VLAN = 1<<0,
|
||||||
|
@ -1743,6 +1762,7 @@ enum netdev_priv_flags {
|
||||||
IFF_NO_ADDRCONF = BIT_ULL(30),
|
IFF_NO_ADDRCONF = BIT_ULL(30),
|
||||||
IFF_TX_SKB_NO_LINEAR = BIT_ULL(31),
|
IFF_TX_SKB_NO_LINEAR = BIT_ULL(31),
|
||||||
IFF_CHANGE_PROTO_DOWN = BIT_ULL(32),
|
IFF_CHANGE_PROTO_DOWN = BIT_ULL(32),
|
||||||
|
IFF_SEE_ALL_HWTSTAMP_REQUESTS = BIT_ULL(33),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
|
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
|
||||||
|
@ -3934,6 +3954,11 @@ int put_user_ifreq(struct ifreq *ifr, void __user *arg);
|
||||||
int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
|
int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
|
||||||
void __user *data, bool *need_copyout);
|
void __user *data, bool *need_copyout);
|
||||||
int dev_ifconf(struct net *net, struct ifconf __user *ifc);
|
int dev_ifconf(struct net *net, struct ifconf __user *ifc);
|
||||||
|
int generic_hwtstamp_get_lower(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *kernel_cfg);
|
||||||
|
int generic_hwtstamp_set_lower(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *kernel_cfg,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *userdata);
|
int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *userdata);
|
||||||
unsigned int dev_get_flags(const struct net_device *);
|
unsigned int dev_get_flags(const struct net_device *);
|
||||||
int __dev_change_flags(struct net_device *dev, unsigned int flags,
|
int __dev_change_flags(struct net_device *dev, unsigned int flags,
|
||||||
|
|
|
@ -298,6 +298,7 @@ static inline const char *phy_modes(phy_interface_t interface)
|
||||||
#define MII_BUS_ID_SIZE 61
|
#define MII_BUS_ID_SIZE 61
|
||||||
|
|
||||||
struct device;
|
struct device;
|
||||||
|
struct kernel_hwtstamp_config;
|
||||||
struct phylink;
|
struct phylink;
|
||||||
struct sfp_bus;
|
struct sfp_bus;
|
||||||
struct sfp_upstream_ops;
|
struct sfp_upstream_ops;
|
||||||
|
@ -1955,6 +1956,12 @@ int phy_ethtool_set_plca_cfg(struct phy_device *phydev,
|
||||||
int phy_ethtool_get_plca_status(struct phy_device *phydev,
|
int phy_ethtool_get_plca_status(struct phy_device *phydev,
|
||||||
struct phy_plca_status *plca_st);
|
struct phy_plca_status *plca_st);
|
||||||
|
|
||||||
|
int __phy_hwtstamp_get(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config);
|
||||||
|
int __phy_hwtstamp_set(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
|
|
||||||
static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
|
static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
|
||||||
{
|
{
|
||||||
struct phy_package_shared *shared = phydev->shared;
|
struct phy_package_shared *shared = phydev->shared;
|
||||||
|
|
68
include/linux/phylib_stubs.h
Normal file
68
include/linux/phylib_stubs.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* Stubs for the Network PHY library
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
struct kernel_hwtstamp_config;
|
||||||
|
struct netlink_ext_ack;
|
||||||
|
struct phy_device;
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_PHYLIB)
|
||||||
|
|
||||||
|
extern const struct phylib_stubs *phylib_stubs;
|
||||||
|
|
||||||
|
struct phylib_stubs {
|
||||||
|
int (*hwtstamp_get)(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config);
|
||||||
|
int (*hwtstamp_set)(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int phy_hwtstamp_get(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config)
|
||||||
|
{
|
||||||
|
/* phylib_register_stubs() and phylib_unregister_stubs()
|
||||||
|
* also run under rtnl_lock().
|
||||||
|
*/
|
||||||
|
ASSERT_RTNL();
|
||||||
|
|
||||||
|
if (!phylib_stubs)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
return phylib_stubs->hwtstamp_get(phydev, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int phy_hwtstamp_set(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
/* phylib_register_stubs() and phylib_unregister_stubs()
|
||||||
|
* also run under rtnl_lock().
|
||||||
|
*/
|
||||||
|
ASSERT_RTNL();
|
||||||
|
|
||||||
|
if (!phylib_stubs)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
return phylib_stubs->hwtstamp_set(phydev, config, extack);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int phy_hwtstamp_get(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int phy_hwtstamp_set(struct phy_device *phydev,
|
||||||
|
struct kernel_hwtstamp_config *config,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -354,6 +354,26 @@ out:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vlan_hwtstamp_get(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *cfg)
|
||||||
|
{
|
||||||
|
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
|
||||||
|
|
||||||
|
return generic_hwtstamp_get_lower(real_dev, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vlan_hwtstamp_set(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
|
||||||
|
|
||||||
|
if (!net_eq(dev_net(dev), dev_net(real_dev)))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
return generic_hwtstamp_set_lower(real_dev, cfg, extack);
|
||||||
|
}
|
||||||
|
|
||||||
static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
{
|
{
|
||||||
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
|
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
|
||||||
|
@ -365,14 +385,9 @@ static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
ifrr.ifr_ifru = ifr->ifr_ifru;
|
ifrr.ifr_ifru = ifr->ifr_ifru;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SIOCSHWTSTAMP:
|
|
||||||
if (!net_eq(dev_net(dev), dev_net(real_dev)))
|
|
||||||
break;
|
|
||||||
fallthrough;
|
|
||||||
case SIOCGMIIPHY:
|
case SIOCGMIIPHY:
|
||||||
case SIOCGMIIREG:
|
case SIOCGMIIREG:
|
||||||
case SIOCSMIIREG:
|
case SIOCSMIIREG:
|
||||||
case SIOCGHWTSTAMP:
|
|
||||||
if (netif_device_present(real_dev) && ops->ndo_eth_ioctl)
|
if (netif_device_present(real_dev) && ops->ndo_eth_ioctl)
|
||||||
err = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
|
err = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
|
||||||
break;
|
break;
|
||||||
|
@ -1081,6 +1096,8 @@ static const struct net_device_ops vlan_netdev_ops = {
|
||||||
.ndo_fix_features = vlan_dev_fix_features,
|
.ndo_fix_features = vlan_dev_fix_features,
|
||||||
.ndo_get_iflink = vlan_dev_get_iflink,
|
.ndo_get_iflink = vlan_dev_get_iflink,
|
||||||
.ndo_fill_forward_path = vlan_dev_fill_forward_path,
|
.ndo_fill_forward_path = vlan_dev_fill_forward_path,
|
||||||
|
.ndo_hwtstamp_get = vlan_hwtstamp_get,
|
||||||
|
.ndo_hwtstamp_set = vlan_hwtstamp_set,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vlan_dev_free(struct net_device *dev)
|
static void vlan_dev_free(struct net_device *dev)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
#include <linux/net_tstamp.h>
|
#include <linux/net_tstamp.h>
|
||||||
|
#include <linux/phylib_stubs.h>
|
||||||
#include <linux/wireless.h>
|
#include <linux/wireless.h>
|
||||||
#include <linux/if_bridge.h>
|
#include <linux/if_bridge.h>
|
||||||
#include <net/dsa_stubs.h>
|
#include <net/dsa_stubs.h>
|
||||||
|
@ -252,14 +253,118 @@ static int dev_eth_ioctl(struct net_device *dev,
|
||||||
return ops->ndo_eth_ioctl(dev, ifr, cmd);
|
return ops->ndo_eth_ioctl(dev, ifr, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_get_hwtstamp_phylib() - Get hardware timestamping settings of NIC
|
||||||
|
* or of attached phylib PHY
|
||||||
|
* @dev: Network device
|
||||||
|
* @cfg: Timestamping configuration structure
|
||||||
|
*
|
||||||
|
* Helper for enforcing a common policy that phylib timestamping, if available,
|
||||||
|
* should take precedence in front of hardware timestamping provided by the
|
||||||
|
* netdev.
|
||||||
|
*
|
||||||
|
* Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and
|
||||||
|
* there only exists a phydev->mii_ts->hwtstamp() method. So this will return
|
||||||
|
* -EOPNOTSUPP for phylib for now, which is still more accurate than letting
|
||||||
|
* the netdev handle the GET request.
|
||||||
|
*/
|
||||||
|
static int dev_get_hwtstamp_phylib(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *cfg)
|
||||||
|
{
|
||||||
|
if (phy_has_hwtstamp(dev->phydev))
|
||||||
|
return phy_hwtstamp_get(dev->phydev, cfg);
|
||||||
|
|
||||||
|
return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
|
static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
|
||||||
{
|
{
|
||||||
return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP);
|
const struct net_device_ops *ops = dev->netdev_ops;
|
||||||
|
struct kernel_hwtstamp_config kernel_cfg = {};
|
||||||
|
struct hwtstamp_config cfg;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!ops->ndo_hwtstamp_get)
|
||||||
|
return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP); /* legacy */
|
||||||
|
|
||||||
|
if (!netif_device_present(dev))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
kernel_cfg.ifr = ifr;
|
||||||
|
err = dev_get_hwtstamp_phylib(dev, &kernel_cfg);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* If the request was resolved through an unconverted driver, omit
|
||||||
|
* the copy_to_user(), since the implementation has already done that
|
||||||
|
*/
|
||||||
|
if (!kernel_cfg.copied_to_user) {
|
||||||
|
hwtstamp_config_from_kernel(&cfg, &kernel_cfg);
|
||||||
|
|
||||||
|
if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_set_hwtstamp_phylib() - Change hardware timestamping of NIC
|
||||||
|
* or of attached phylib PHY
|
||||||
|
* @dev: Network device
|
||||||
|
* @cfg: Timestamping configuration structure
|
||||||
|
* @extack: Netlink extended ack message structure, for error reporting
|
||||||
|
*
|
||||||
|
* Helper for enforcing a common policy that phylib timestamping, if available,
|
||||||
|
* should take precedence in front of hardware timestamping provided by the
|
||||||
|
* netdev. If the netdev driver needs to perform specific actions even for PHY
|
||||||
|
* timestamping to work properly (a switch port must trap the timestamped
|
||||||
|
* frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in
|
||||||
|
* dev->priv_flags.
|
||||||
|
*/
|
||||||
|
static int dev_set_hwtstamp_phylib(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
const struct net_device_ops *ops = dev->netdev_ops;
|
||||||
|
bool phy_ts = phy_has_hwtstamp(dev->phydev);
|
||||||
|
struct kernel_hwtstamp_config old_cfg = {};
|
||||||
|
bool changed = false;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV;
|
||||||
|
|
||||||
|
if (!phy_ts || (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) {
|
||||||
|
err = ops->ndo_hwtstamp_get(dev, &old_cfg);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = ops->ndo_hwtstamp_set(dev, cfg, extack);
|
||||||
|
if (err) {
|
||||||
|
if (extack->_msg)
|
||||||
|
netdev_err(dev, "%s\n", extack->_msg);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
changed = kernel_hwtstamp_config_changed(&old_cfg, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phy_ts) {
|
||||||
|
err = phy_hwtstamp_set(dev->phydev, cfg, extack);
|
||||||
|
if (err) {
|
||||||
|
if (changed)
|
||||||
|
ops->ndo_hwtstamp_set(dev, &old_cfg, NULL);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
|
static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
|
||||||
{
|
{
|
||||||
struct kernel_hwtstamp_config kernel_cfg;
|
const struct net_device_ops *ops = dev->netdev_ops;
|
||||||
|
struct kernel_hwtstamp_config kernel_cfg = {};
|
||||||
struct netlink_ext_ack extack = {};
|
struct netlink_ext_ack extack = {};
|
||||||
struct hwtstamp_config cfg;
|
struct hwtstamp_config cfg;
|
||||||
int err;
|
int err;
|
||||||
|
@ -268,6 +373,7 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
hwtstamp_config_to_kernel(&kernel_cfg, &cfg);
|
hwtstamp_config_to_kernel(&kernel_cfg, &cfg);
|
||||||
|
kernel_cfg.ifr = ifr;
|
||||||
|
|
||||||
err = net_hwtstamp_validate(&kernel_cfg);
|
err = net_hwtstamp_validate(&kernel_cfg);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -280,9 +386,81 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP);
|
if (!ops->ndo_hwtstamp_set)
|
||||||
|
return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP); /* legacy */
|
||||||
|
|
||||||
|
if (!netif_device_present(dev))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* The driver may have modified the configuration, so copy the
|
||||||
|
* updated version of it back to user space
|
||||||
|
*/
|
||||||
|
if (!kernel_cfg.copied_to_user) {
|
||||||
|
hwtstamp_config_from_kernel(&cfg, &kernel_cfg);
|
||||||
|
|
||||||
|
if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int generic_hwtstamp_ioctl_lower(struct net_device *dev, int cmd,
|
||||||
|
struct kernel_hwtstamp_config *kernel_cfg)
|
||||||
|
{
|
||||||
|
struct ifreq ifrr;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
strscpy_pad(ifrr.ifr_name, dev->name, IFNAMSIZ);
|
||||||
|
ifrr.ifr_ifru = kernel_cfg->ifr->ifr_ifru;
|
||||||
|
|
||||||
|
err = dev_eth_ioctl(dev, &ifrr, cmd);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
kernel_cfg->ifr->ifr_ifru = ifrr.ifr_ifru;
|
||||||
|
kernel_cfg->copied_to_user = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int generic_hwtstamp_get_lower(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *kernel_cfg)
|
||||||
|
{
|
||||||
|
const struct net_device_ops *ops = dev->netdev_ops;
|
||||||
|
|
||||||
|
if (!netif_device_present(dev))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (ops->ndo_hwtstamp_get)
|
||||||
|
return dev_get_hwtstamp_phylib(dev, kernel_cfg);
|
||||||
|
|
||||||
|
/* Legacy path: unconverted lower driver */
|
||||||
|
return generic_hwtstamp_ioctl_lower(dev, SIOCGHWTSTAMP, kernel_cfg);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(generic_hwtstamp_get_lower);
|
||||||
|
|
||||||
|
int generic_hwtstamp_set_lower(struct net_device *dev,
|
||||||
|
struct kernel_hwtstamp_config *kernel_cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
const struct net_device_ops *ops = dev->netdev_ops;
|
||||||
|
|
||||||
|
if (!netif_device_present(dev))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (ops->ndo_hwtstamp_set)
|
||||||
|
return dev_set_hwtstamp_phylib(dev, kernel_cfg, extack);
|
||||||
|
|
||||||
|
/* Legacy path: unconverted lower driver */
|
||||||
|
return generic_hwtstamp_ioctl_lower(dev, SIOCSHWTSTAMP, kernel_cfg);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(generic_hwtstamp_set_lower);
|
||||||
|
|
||||||
static int dev_siocbond(struct net_device *dev,
|
static int dev_siocbond(struct net_device *dev,
|
||||||
struct ifreq *ifr, unsigned int cmd)
|
struct ifreq *ifr, unsigned int cmd)
|
||||||
{
|
{
|
||||||
|
|
|
@ -665,9 +665,8 @@ const struct ethtool_phy_ops *ethtool_phy_ops;
|
||||||
|
|
||||||
void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops)
|
void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops)
|
||||||
{
|
{
|
||||||
rtnl_lock();
|
ASSERT_RTNL();
|
||||||
ethtool_phy_ops = ops;
|
ethtool_phy_ops = ops;
|
||||||
rtnl_unlock();
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ethtool_set_ethtool_phy_ops);
|
EXPORT_SYMBOL_GPL(ethtool_set_ethtool_phy_ops);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue