diff options
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r-- | net/core/ethtool.c | 85 |
1 files changed, 82 insertions, 3 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 29edf74846fc..daf04709dd3c 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -87,7 +87,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] | |||
87 | [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", | 87 | [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", |
88 | 88 | ||
89 | [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc", | 89 | [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc", |
90 | [NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp", | 90 | [NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp", |
91 | [NETIF_F_FCOE_MTU_BIT] = "fcoe-mtu", | 91 | [NETIF_F_FCOE_MTU_BIT] = "fcoe-mtu", |
92 | [NETIF_F_NTUPLE_BIT] = "rx-ntuple-filter", | 92 | [NETIF_F_NTUPLE_BIT] = "rx-ntuple-filter", |
93 | [NETIF_F_RXHASH_BIT] = "rx-hashing", | 93 | [NETIF_F_RXHASH_BIT] = "rx-hashing", |
@@ -191,6 +191,23 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr) | |||
191 | return ret; | 191 | return ret; |
192 | } | 192 | } |
193 | 193 | ||
194 | static int phy_get_sset_count(struct phy_device *phydev) | ||
195 | { | ||
196 | int ret; | ||
197 | |||
198 | if (phydev->drv->get_sset_count && | ||
199 | phydev->drv->get_strings && | ||
200 | phydev->drv->get_stats) { | ||
201 | mutex_lock(&phydev->lock); | ||
202 | ret = phydev->drv->get_sset_count(phydev); | ||
203 | mutex_unlock(&phydev->lock); | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | return -EOPNOTSUPP; | ||
209 | } | ||
210 | |||
194 | static int __ethtool_get_sset_count(struct net_device *dev, int sset) | 211 | static int __ethtool_get_sset_count(struct net_device *dev, int sset) |
195 | { | 212 | { |
196 | const struct ethtool_ops *ops = dev->ethtool_ops; | 213 | const struct ethtool_ops *ops = dev->ethtool_ops; |
@@ -204,6 +221,13 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset) | |||
204 | if (sset == ETH_SS_TUNABLES) | 221 | if (sset == ETH_SS_TUNABLES) |
205 | return ARRAY_SIZE(tunable_strings); | 222 | return ARRAY_SIZE(tunable_strings); |
206 | 223 | ||
224 | if (sset == ETH_SS_PHY_STATS) { | ||
225 | if (dev->phydev) | ||
226 | return phy_get_sset_count(dev->phydev); | ||
227 | else | ||
228 | return -EOPNOTSUPP; | ||
229 | } | ||
230 | |||
207 | if (ops->get_sset_count && ops->get_strings) | 231 | if (ops->get_sset_count && ops->get_strings) |
208 | return ops->get_sset_count(dev, sset); | 232 | return ops->get_sset_count(dev, sset); |
209 | else | 233 | else |
@@ -223,7 +247,17 @@ static void __ethtool_get_strings(struct net_device *dev, | |||
223 | sizeof(rss_hash_func_strings)); | 247 | sizeof(rss_hash_func_strings)); |
224 | else if (stringset == ETH_SS_TUNABLES) | 248 | else if (stringset == ETH_SS_TUNABLES) |
225 | memcpy(data, tunable_strings, sizeof(tunable_strings)); | 249 | memcpy(data, tunable_strings, sizeof(tunable_strings)); |
226 | else | 250 | else if (stringset == ETH_SS_PHY_STATS) { |
251 | struct phy_device *phydev = dev->phydev; | ||
252 | |||
253 | if (phydev) { | ||
254 | mutex_lock(&phydev->lock); | ||
255 | phydev->drv->get_strings(phydev, data); | ||
256 | mutex_unlock(&phydev->lock); | ||
257 | } else { | ||
258 | return; | ||
259 | } | ||
260 | } else | ||
227 | /* ops->get_strings is valid because checked earlier */ | 261 | /* ops->get_strings is valid because checked earlier */ |
228 | ops->get_strings(dev, stringset, data); | 262 | ops->get_strings(dev, stringset, data); |
229 | } | 263 | } |
@@ -235,7 +269,7 @@ static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd) | |||
235 | switch (eth_cmd) { | 269 | switch (eth_cmd) { |
236 | case ETHTOOL_GTXCSUM: | 270 | case ETHTOOL_GTXCSUM: |
237 | case ETHTOOL_STXCSUM: | 271 | case ETHTOOL_STXCSUM: |
238 | return NETIF_F_ALL_CSUM | NETIF_F_SCTP_CSUM; | 272 | return NETIF_F_CSUM_MASK | NETIF_F_SCTP_CRC; |
239 | case ETHTOOL_GRXCSUM: | 273 | case ETHTOOL_GRXCSUM: |
240 | case ETHTOOL_SRXCSUM: | 274 | case ETHTOOL_SRXCSUM: |
241 | return NETIF_F_RXCSUM; | 275 | return NETIF_F_RXCSUM; |
@@ -1401,6 +1435,47 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) | |||
1401 | return ret; | 1435 | return ret; |
1402 | } | 1436 | } |
1403 | 1437 | ||
1438 | static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr) | ||
1439 | { | ||
1440 | struct ethtool_stats stats; | ||
1441 | struct phy_device *phydev = dev->phydev; | ||
1442 | u64 *data; | ||
1443 | int ret, n_stats; | ||
1444 | |||
1445 | if (!phydev) | ||
1446 | return -EOPNOTSUPP; | ||
1447 | |||
1448 | n_stats = phy_get_sset_count(phydev); | ||
1449 | |||
1450 | if (n_stats < 0) | ||
1451 | return n_stats; | ||
1452 | WARN_ON(n_stats == 0); | ||
1453 | |||
1454 | if (copy_from_user(&stats, useraddr, sizeof(stats))) | ||
1455 | return -EFAULT; | ||
1456 | |||
1457 | stats.n_stats = n_stats; | ||
1458 | data = kmalloc_array(n_stats, sizeof(u64), GFP_USER); | ||
1459 | if (!data) | ||
1460 | return -ENOMEM; | ||
1461 | |||
1462 | mutex_lock(&phydev->lock); | ||
1463 | phydev->drv->get_stats(phydev, &stats, data); | ||
1464 | mutex_unlock(&phydev->lock); | ||
1465 | |||
1466 | ret = -EFAULT; | ||
1467 | if (copy_to_user(useraddr, &stats, sizeof(stats))) | ||
1468 | goto out; | ||
1469 | useraddr += sizeof(stats); | ||
1470 | if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64))) | ||
1471 | goto out; | ||
1472 | ret = 0; | ||
1473 | |||
1474 | out: | ||
1475 | kfree(data); | ||
1476 | return ret; | ||
1477 | } | ||
1478 | |||
1404 | static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) | 1479 | static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) |
1405 | { | 1480 | { |
1406 | struct ethtool_perm_addr epaddr; | 1481 | struct ethtool_perm_addr epaddr; |
@@ -1779,6 +1854,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1779 | case ETHTOOL_GSSET_INFO: | 1854 | case ETHTOOL_GSSET_INFO: |
1780 | case ETHTOOL_GSTRINGS: | 1855 | case ETHTOOL_GSTRINGS: |
1781 | case ETHTOOL_GSTATS: | 1856 | case ETHTOOL_GSTATS: |
1857 | case ETHTOOL_GPHYSTATS: | ||
1782 | case ETHTOOL_GTSO: | 1858 | case ETHTOOL_GTSO: |
1783 | case ETHTOOL_GPERMADDR: | 1859 | case ETHTOOL_GPERMADDR: |
1784 | case ETHTOOL_GUFO: | 1860 | case ETHTOOL_GUFO: |
@@ -1991,6 +2067,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1991 | case ETHTOOL_STUNABLE: | 2067 | case ETHTOOL_STUNABLE: |
1992 | rc = ethtool_set_tunable(dev, useraddr); | 2068 | rc = ethtool_set_tunable(dev, useraddr); |
1993 | break; | 2069 | break; |
2070 | case ETHTOOL_GPHYSTATS: | ||
2071 | rc = ethtool_get_phy_stats(dev, useraddr); | ||
2072 | break; | ||
1994 | default: | 2073 | default: |
1995 | rc = -EOPNOTSUPP; | 2074 | rc = -EOPNOTSUPP; |
1996 | } | 2075 | } |