From: Gal Pressman <g...@mellanox.com> Currently ethtool only allows us to get device registers, in this patch we extend this functionality to also set device registers. ethtool -D DEVNAME [ file FILENAME ] is used to set registers in the device using vendor specific binary registers data provided via stdin/file. Changes made by this option can be queried using get regs -d flag.
Example: $ ethtool -D eth1 file /tmp/mlx5_regs Signed-off-by: Gal Pressman <g...@mellanox.com> Signed-off-by: Dmitry Teif <di...@mellanox.com> CC: John W. Linville <linvi...@tuxdriver.com> Signed-off-by: Saeed Mahameed <sae...@mellanox.com> --- include/linux/ethtool.h | 1 + include/uapi/linux/ethtool.h | 1 + net/core/ethtool.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 9ded8c6..c9f5d37 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -305,6 +305,7 @@ struct ethtool_ops { void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); int (*get_regs_len)(struct net_device *); void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); + int (*set_regs)(struct net_device *, struct ethtool_regs *, u8 *); void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); u32 (*get_msglevel)(struct net_device *); diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index f0db778..f81c6fd 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1330,6 +1330,7 @@ struct ethtool_per_queue_op { #define ETHTOOL_SLINKSETTINGS 0x0000004d /* Set ethtool_link_settings */ #define ETHTOOL_PHY_GTUNABLE 0x0000004e /* Get PHY tunable configuration */ #define ETHTOOL_PHY_STUNABLE 0x0000004f /* Set PHY tunable configuration */ +#define ETHTOOL_SREGS 0x00000050 /* Set NIC registers */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/net/core/ethtool.c b/net/core/ethtool.c index e23766c..5548565 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1424,6 +1424,34 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) return ret; } +static int ethtool_set_regs(struct net_device *dev, char __user *useraddr) +{ + void __user *userbuf = useraddr + offsetof(struct ethtool_regs, data); + const struct ethtool_ops *ops = dev->ethtool_ops; + struct ethtool_regs regs; + int ret = 0; + u8 *data; + + if (!ops->set_regs || !ops->get_regs_len) + return -EOPNOTSUPP; + if (copy_from_user(®s, useraddr, sizeof(regs))) + return -EFAULT; + + data = kmalloc(PAGE_SIZE, GFP_USER); + if (!data) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(data, userbuf, regs.len)) + goto out; + + ret = ops->set_regs(dev, ®s, data); + +out: + kfree(data); + return ret; +} + static int ethtool_reset(struct net_device *dev, char __user *useraddr) { struct ethtool_value reset; @@ -2597,6 +2625,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_GREGS: rc = ethtool_get_regs(dev, useraddr); break; + case ETHTOOL_SREGS: + rc = ethtool_set_regs(dev, useraddr); + break; case ETHTOOL_GWOL: rc = ethtool_get_wol(dev, useraddr); break; -- 2.7.4