Implement the three ethtool loopback ops for MAC-level loopback simulation: - get_loopback(): exact lookup by name ("mac") - get_loopback_by()_index: enumerate (single entry at index 0) - set_loopback(): update direction, return 1 if changed The MAC loopback entry announces support for both local and remote support by default. State is stored in nsim_ethtool.mac_lb and exposed via debugfs under ethtool/mac_lb/{supported,direction} for test inspection and control. Signed-off-by: Björn Töpel --- drivers/net/netdevsim/ethtool.c | 64 +++++++++++++++++++++++++++++++ drivers/net/netdevsim/netdevsim.h | 4 ++ 2 files changed, 68 insertions(+) diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c index 36a201533aae..39c681284700 100644 --- a/drivers/net/netdevsim/ethtool.c +++ b/drivers/net/netdevsim/ethtool.c @@ -195,6 +195,58 @@ nsim_get_fec_stats(struct net_device *dev, struct ethtool_fec_stats *fec_stats, values[2].per_lane[3] = 0; } +static void nsim_fill_mac_lb_entry(struct netdevsim *ns, + struct ethtool_loopback_entry *entry) +{ + memset(entry, 0, sizeof(*entry)); + entry->component = ETHTOOL_LOOPBACK_COMPONENT_MAC; + strscpy(entry->name, "mac", sizeof(entry->name)); + entry->supported = ns->ethtool.mac_lb.supported; + entry->direction = ns->ethtool.mac_lb.direction; +} + +static int nsim_get_loopback(struct net_device *dev, const char *name, + u32 id, struct ethtool_loopback_entry *entry) +{ + struct netdevsim *ns = netdev_priv(dev); + + if (strcmp(name, "mac")) + return -EOPNOTSUPP; + + nsim_fill_mac_lb_entry(ns, entry); + return 0; +} + +static int nsim_get_loopback_by_index(struct net_device *dev, u32 index, + struct ethtool_loopback_entry *entry) +{ + struct netdevsim *ns = netdev_priv(dev); + + if (index > 0) + return -EOPNOTSUPP; + + nsim_fill_mac_lb_entry(ns, entry); + return 0; +} + +static int nsim_set_loopback(struct net_device *dev, + const struct ethtool_loopback_entry *entry, + struct netlink_ext_ack *extack) +{ + struct netdevsim *ns = netdev_priv(dev); + + if (strcmp(entry->name, "mac")) { + NL_SET_ERR_MSG(extack, "Unknown MAC loopback name"); + return -EOPNOTSUPP; + } + + if (ns->ethtool.mac_lb.direction == entry->direction) + return 0; + + ns->ethtool.mac_lb.direction = entry->direction; + return 1; +} + static int nsim_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info) { @@ -222,6 +274,9 @@ static const struct ethtool_ops nsim_ethtool_ops = { .set_fecparam = nsim_set_fecparam, .get_fec_stats = nsim_get_fec_stats, .get_ts_info = nsim_get_ts_info, + .get_loopback = nsim_get_loopback, + .get_loopback_by_index = nsim_get_loopback_by_index, + .set_loopback = nsim_set_loopback, }; static void nsim_ethtool_ring_init(struct netdevsim *ns) @@ -270,4 +325,13 @@ void nsim_ethtool_init(struct netdevsim *ns) &ns->ethtool.ring.rx_mini_max_pending); debugfs_create_u32("tx_max_pending", 0600, dir, &ns->ethtool.ring.tx_max_pending); + + ns->ethtool.mac_lb.supported = ETHTOOL_LOOPBACK_DIRECTION_LOCAL | + ETHTOOL_LOOPBACK_DIRECTION_REMOTE; + + dir = debugfs_create_dir("mac_lb", ethtool); + debugfs_create_u32("supported", 0600, dir, + &ns->ethtool.mac_lb.supported); + debugfs_create_u32("direction", 0600, dir, + &ns->ethtool.mac_lb.direction); } diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index c904e14f6b3f..7a3382562287 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -90,6 +90,10 @@ struct nsim_ethtool { struct ethtool_coalesce coalesce; struct ethtool_ringparam ring; struct ethtool_fecparam fec; + struct { + u32 supported; + u32 direction; + } mac_lb; }; struct nsim_rq { -- 2.53.0