diff options
author | Govindarajulu Varadarajan <_govind@gmx.com> | 2014-09-02 17:47:20 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-05 15:12:20 -0400 |
commit | f0db9b073415848709dd59a6394969882f517da9 (patch) | |
tree | f9d5de4b8528c4f5c55d04c5642ac4053489fe5e | |
parent | a03bb56e67c357980dae886683733dab5583dc14 (diff) |
ethtool: Add generic options for tunables
This patch adds new ethtool cmd, ETHTOOL_GTUNABLE & ETHTOOL_STUNABLE for getting
tunable values from driver.
Add get_tunable and set_tunable to ethtool_ops. Driver implements these
functions for getting/setting tunable value.
Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/ethtool.h | 4 | ||||
-rw-r--r-- | include/uapi/linux/ethtool.h | 28 | ||||
-rw-r--r-- | net/core/ethtool.c | 81 |
3 files changed, 113 insertions, 0 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index e658229fee39..c1a2d60dfb82 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h | |||
@@ -257,6 +257,10 @@ struct ethtool_ops { | |||
257 | struct ethtool_eeprom *, u8 *); | 257 | struct ethtool_eeprom *, u8 *); |
258 | int (*get_eee)(struct net_device *, struct ethtool_eee *); | 258 | int (*get_eee)(struct net_device *, struct ethtool_eee *); |
259 | int (*set_eee)(struct net_device *, struct ethtool_eee *); | 259 | int (*set_eee)(struct net_device *, struct ethtool_eee *); |
260 | int (*get_tunable)(struct net_device *, | ||
261 | const struct ethtool_tunable *, void *); | ||
262 | int (*set_tunable)(struct net_device *, | ||
263 | const struct ethtool_tunable *, const void *); | ||
260 | 264 | ||
261 | 265 | ||
262 | }; | 266 | }; |
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index e3c7a719c76b..7a364f2f3d3f 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h | |||
@@ -209,6 +209,32 @@ struct ethtool_value { | |||
209 | __u32 data; | 209 | __u32 data; |
210 | }; | 210 | }; |
211 | 211 | ||
212 | enum tunable_id { | ||
213 | ETHTOOL_ID_UNSPEC, | ||
214 | ETHTOOL_RX_COPYBREAK, | ||
215 | }; | ||
216 | |||
217 | enum tunable_type_id { | ||
218 | ETHTOOL_TUNABLE_UNSPEC, | ||
219 | ETHTOOL_TUNABLE_U8, | ||
220 | ETHTOOL_TUNABLE_U16, | ||
221 | ETHTOOL_TUNABLE_U32, | ||
222 | ETHTOOL_TUNABLE_U64, | ||
223 | ETHTOOL_TUNABLE_STRING, | ||
224 | ETHTOOL_TUNABLE_S8, | ||
225 | ETHTOOL_TUNABLE_S16, | ||
226 | ETHTOOL_TUNABLE_S32, | ||
227 | ETHTOOL_TUNABLE_S64, | ||
228 | }; | ||
229 | |||
230 | struct ethtool_tunable { | ||
231 | __u32 cmd; | ||
232 | __u32 id; | ||
233 | __u32 type_id; | ||
234 | __u32 len; | ||
235 | void *data[0]; | ||
236 | }; | ||
237 | |||
212 | /** | 238 | /** |
213 | * struct ethtool_regs - hardware register dump | 239 | * struct ethtool_regs - hardware register dump |
214 | * @cmd: Command number = %ETHTOOL_GREGS | 240 | * @cmd: Command number = %ETHTOOL_GREGS |
@@ -1152,6 +1178,8 @@ enum ethtool_sfeatures_retval_bits { | |||
1152 | 1178 | ||
1153 | #define ETHTOOL_GRSSH 0x00000046 /* Get RX flow hash configuration */ | 1179 | #define ETHTOOL_GRSSH 0x00000046 /* Get RX flow hash configuration */ |
1154 | #define ETHTOOL_SRSSH 0x00000047 /* Set RX flow hash configuration */ | 1180 | #define ETHTOOL_SRSSH 0x00000047 /* Set RX flow hash configuration */ |
1181 | #define ETHTOOL_GTUNABLE 0x00000048 /* Get tunable configuration */ | ||
1182 | #define ETHTOOL_STUNABLE 0x00000049 /* Set tunable configuration */ | ||
1155 | 1183 | ||
1156 | /* compatibility with older code */ | 1184 | /* compatibility with older code */ |
1157 | #define SPARC_ETH_GSET ETHTOOL_GSET | 1185 | #define SPARC_ETH_GSET ETHTOOL_GSET |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 17cb912793fa..27e61b886520 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -1621,6 +1621,80 @@ static int ethtool_get_module_eeprom(struct net_device *dev, | |||
1621 | modinfo.eeprom_len); | 1621 | modinfo.eeprom_len); |
1622 | } | 1622 | } |
1623 | 1623 | ||
1624 | static int ethtool_tunable_valid(const struct ethtool_tunable *tuna) | ||
1625 | { | ||
1626 | switch (tuna->id) { | ||
1627 | case ETHTOOL_RX_COPYBREAK: | ||
1628 | if (tuna->len != sizeof(u32) || | ||
1629 | tuna->type_id != ETHTOOL_TUNABLE_U32) | ||
1630 | return -EINVAL; | ||
1631 | break; | ||
1632 | default: | ||
1633 | return -EINVAL; | ||
1634 | } | ||
1635 | |||
1636 | return 0; | ||
1637 | } | ||
1638 | |||
1639 | static int ethtool_get_tunable(struct net_device *dev, void __user *useraddr) | ||
1640 | { | ||
1641 | int ret; | ||
1642 | struct ethtool_tunable tuna; | ||
1643 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
1644 | void *data; | ||
1645 | |||
1646 | if (!ops->get_tunable) | ||
1647 | return -EOPNOTSUPP; | ||
1648 | if (copy_from_user(&tuna, useraddr, sizeof(tuna))) | ||
1649 | return -EFAULT; | ||
1650 | ret = ethtool_tunable_valid(&tuna); | ||
1651 | if (ret) | ||
1652 | return ret; | ||
1653 | data = kmalloc(tuna.len, GFP_USER); | ||
1654 | if (!data) | ||
1655 | return -ENOMEM; | ||
1656 | ret = ops->get_tunable(dev, &tuna, data); | ||
1657 | if (ret) | ||
1658 | goto out; | ||
1659 | useraddr += sizeof(tuna); | ||
1660 | ret = -EFAULT; | ||
1661 | if (copy_to_user(useraddr, data, tuna.len)) | ||
1662 | goto out; | ||
1663 | ret = 0; | ||
1664 | |||
1665 | out: | ||
1666 | kfree(data); | ||
1667 | return ret; | ||
1668 | } | ||
1669 | |||
1670 | static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr) | ||
1671 | { | ||
1672 | int ret; | ||
1673 | struct ethtool_tunable tuna; | ||
1674 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
1675 | void *data; | ||
1676 | |||
1677 | if (!ops->set_tunable) | ||
1678 | return -EOPNOTSUPP; | ||
1679 | if (copy_from_user(&tuna, useraddr, sizeof(tuna))) | ||
1680 | return -EFAULT; | ||
1681 | ret = ethtool_tunable_valid(&tuna); | ||
1682 | if (ret) | ||
1683 | return ret; | ||
1684 | data = kmalloc(tuna.len, GFP_USER); | ||
1685 | if (!data) | ||
1686 | return -ENOMEM; | ||
1687 | useraddr += sizeof(tuna); | ||
1688 | ret = -EFAULT; | ||
1689 | if (copy_from_user(data, useraddr, tuna.len)) | ||
1690 | goto out; | ||
1691 | ret = ops->set_tunable(dev, &tuna, data); | ||
1692 | |||
1693 | out: | ||
1694 | kfree(data); | ||
1695 | return ret; | ||
1696 | } | ||
1697 | |||
1624 | /* The main entry point in this file. Called from net/core/dev_ioctl.c */ | 1698 | /* The main entry point in this file. Called from net/core/dev_ioctl.c */ |
1625 | 1699 | ||
1626 | int dev_ethtool(struct net *net, struct ifreq *ifr) | 1700 | int dev_ethtool(struct net *net, struct ifreq *ifr) |
@@ -1670,6 +1744,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1670 | case ETHTOOL_GCHANNELS: | 1744 | case ETHTOOL_GCHANNELS: |
1671 | case ETHTOOL_GET_TS_INFO: | 1745 | case ETHTOOL_GET_TS_INFO: |
1672 | case ETHTOOL_GEEE: | 1746 | case ETHTOOL_GEEE: |
1747 | case ETHTOOL_GTUNABLE: | ||
1673 | break; | 1748 | break; |
1674 | default: | 1749 | default: |
1675 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 1750 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
@@ -1857,6 +1932,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1857 | case ETHTOOL_GMODULEEEPROM: | 1932 | case ETHTOOL_GMODULEEEPROM: |
1858 | rc = ethtool_get_module_eeprom(dev, useraddr); | 1933 | rc = ethtool_get_module_eeprom(dev, useraddr); |
1859 | break; | 1934 | break; |
1935 | case ETHTOOL_GTUNABLE: | ||
1936 | rc = ethtool_get_tunable(dev, useraddr); | ||
1937 | break; | ||
1938 | case ETHTOOL_STUNABLE: | ||
1939 | rc = ethtool_set_tunable(dev, useraddr); | ||
1940 | break; | ||
1860 | default: | 1941 | default: |
1861 | rc = -EOPNOTSUPP; | 1942 | rc = -EOPNOTSUPP; |
1862 | } | 1943 | } |