ethtool: add compat for devlink info
If driver did not fill the fw_version field, try to call into the new devlink get_info op and collect the versions that way. We assume ethtool was always reporting running versions. v4: - use IS_REACHABLE() to avoid problems with DEVLINK=m (kbuildbot). v3 (Jiri): - do a dump and then parse it instead of special handling; - concatenate all versions (well, all that fit :)). Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7c908f467d
commit
ddb6e99e2d
|
@ -972,4 +972,14 @@ devlink_info_version_running_put(struct devlink_info_req *req,
|
|||
}
|
||||
#endif
|
||||
|
||||
#if IS_REACHABLE(CONFIG_NET_DEVLINK)
|
||||
void devlink_compat_running_version(struct net_device *dev,
|
||||
char *buf, size_t len);
|
||||
#else
|
||||
static inline void
|
||||
devlink_compat_running_version(struct net_device *dev, char *buf, size_t len)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NET_DEVLINK_H_ */
|
||||
|
|
|
@ -5278,6 +5278,69 @@ unlock:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
|
||||
|
||||
static void __devlink_compat_running_version(struct devlink *devlink,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
const struct nlattr *nlattr;
|
||||
struct devlink_info_req req;
|
||||
struct sk_buff *msg;
|
||||
int rem, err;
|
||||
|
||||
if (!devlink->ops->info_get)
|
||||
return;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
req.msg = msg;
|
||||
err = devlink->ops->info_get(devlink, &req, NULL);
|
||||
if (err)
|
||||
goto free_msg;
|
||||
|
||||
nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
|
||||
const struct nlattr *kv;
|
||||
int rem_kv;
|
||||
|
||||
if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
|
||||
continue;
|
||||
|
||||
nla_for_each_nested(kv, nlattr, rem_kv) {
|
||||
if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
|
||||
continue;
|
||||
|
||||
strlcat(buf, nla_data(kv), len);
|
||||
strlcat(buf, " ", len);
|
||||
}
|
||||
}
|
||||
free_msg:
|
||||
nlmsg_free(msg);
|
||||
}
|
||||
|
||||
void devlink_compat_running_version(struct net_device *dev,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink *devlink;
|
||||
|
||||
mutex_lock(&devlink_mutex);
|
||||
list_for_each_entry(devlink, &devlink_list, list) {
|
||||
mutex_lock(&devlink->lock);
|
||||
list_for_each_entry(devlink_port, &devlink->port_list, list) {
|
||||
if (devlink_port->type == DEVLINK_PORT_TYPE_ETH ||
|
||||
devlink_port->type_dev == dev) {
|
||||
__devlink_compat_running_version(devlink,
|
||||
buf, len);
|
||||
mutex_unlock(&devlink->lock);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&devlink->lock);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&devlink_mutex);
|
||||
}
|
||||
|
||||
static int __init devlink_module_init(void)
|
||||
{
|
||||
return genl_register_family(&devlink_nl_family);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/rtnetlink.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/net.h>
|
||||
#include <net/devlink.h>
|
||||
#include <net/xdp_sock.h>
|
||||
|
||||
/*
|
||||
|
@ -803,6 +804,12 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
|
|||
if (ops->get_eeprom_len)
|
||||
info.eedump_len = ops->get_eeprom_len(dev);
|
||||
|
||||
rtnl_unlock();
|
||||
if (!info.fw_version[0])
|
||||
devlink_compat_running_version(dev, info.fw_version,
|
||||
sizeof(info.fw_version));
|
||||
rtnl_lock();
|
||||
|
||||
if (copy_to_user(useraddr, &info, sizeof(info)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue