diff options
author | Michał Mirosław <mirq-linux@rere.qmqm.pl> | 2011-02-15 11:59:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-17 17:16:33 -0500 |
commit | 5455c6998d34dc983a8693500e4dffefc3682dc5 (patch) | |
tree | b765aecf6d33d8c550cde78368ccc8654951ec07 /net/core/ethtool.c | |
parent | 0a417704777ed29d0e8c72b7274a328e61248e75 (diff) |
net: Introduce new feature setting ops
This introduces a new framework to handle device features setting.
It consists of:
- new fields in struct net_device:
+ hw_features - features that hw/driver supports toggling
+ wanted_features - features that user wants enabled, when possible
- new netdev_ops:
+ feat = ndo_fix_features(dev, feat) - API checking constraints for
enabling features or their combinations
+ ndo_set_features(dev) - API updating hardware state to match
changed dev->features
- new ethtool commands:
+ ETHTOOL_GFEATURES/ETHTOOL_SFEATURES: get/set dev->wanted_features
and trigger device reconfiguration if resulting dev->features
changed
+ ETHTOOL_GSTRINGS(ETH_SS_FEATURES): get feature bits names (meaning)
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r-- | net/core/ethtool.c | 125 |
1 files changed, 123 insertions, 2 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index c3fb8f90de6d..95773960dc77 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -172,10 +172,120 @@ EXPORT_SYMBOL(ethtool_ntuple_flush); | |||
172 | 172 | ||
173 | /* Handlers for each ethtool command */ | 173 | /* Handlers for each ethtool command */ |
174 | 174 | ||
175 | #define ETHTOOL_DEV_FEATURE_WORDS 1 | ||
176 | |||
177 | static int ethtool_get_features(struct net_device *dev, void __user *useraddr) | ||
178 | { | ||
179 | struct ethtool_gfeatures cmd = { | ||
180 | .cmd = ETHTOOL_GFEATURES, | ||
181 | .size = ETHTOOL_DEV_FEATURE_WORDS, | ||
182 | }; | ||
183 | struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS] = { | ||
184 | { | ||
185 | .available = dev->hw_features, | ||
186 | .requested = dev->wanted_features, | ||
187 | .active = dev->features, | ||
188 | .never_changed = NETIF_F_NEVER_CHANGE, | ||
189 | }, | ||
190 | }; | ||
191 | u32 __user *sizeaddr; | ||
192 | u32 copy_size; | ||
193 | |||
194 | sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size); | ||
195 | if (get_user(copy_size, sizeaddr)) | ||
196 | return -EFAULT; | ||
197 | |||
198 | if (copy_size > ETHTOOL_DEV_FEATURE_WORDS) | ||
199 | copy_size = ETHTOOL_DEV_FEATURE_WORDS; | ||
200 | |||
201 | if (copy_to_user(useraddr, &cmd, sizeof(cmd))) | ||
202 | return -EFAULT; | ||
203 | useraddr += sizeof(cmd); | ||
204 | if (copy_to_user(useraddr, features, copy_size * sizeof(*features))) | ||
205 | return -EFAULT; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int ethtool_set_features(struct net_device *dev, void __user *useraddr) | ||
211 | { | ||
212 | struct ethtool_sfeatures cmd; | ||
213 | struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS]; | ||
214 | int ret = 0; | ||
215 | |||
216 | if (copy_from_user(&cmd, useraddr, sizeof(cmd))) | ||
217 | return -EFAULT; | ||
218 | useraddr += sizeof(cmd); | ||
219 | |||
220 | if (cmd.size != ETHTOOL_DEV_FEATURE_WORDS) | ||
221 | return -EINVAL; | ||
222 | |||
223 | if (copy_from_user(features, useraddr, sizeof(features))) | ||
224 | return -EFAULT; | ||
225 | |||
226 | if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) | ||
227 | return -EINVAL; | ||
228 | |||
229 | if (features[0].valid & ~dev->hw_features) { | ||
230 | features[0].valid &= dev->hw_features; | ||
231 | ret |= ETHTOOL_F_UNSUPPORTED; | ||
232 | } | ||
233 | |||
234 | dev->wanted_features &= ~features[0].valid; | ||
235 | dev->wanted_features |= features[0].valid & features[0].requested; | ||
236 | netdev_update_features(dev); | ||
237 | |||
238 | if ((dev->wanted_features ^ dev->features) & features[0].valid) | ||
239 | ret |= ETHTOOL_F_WISH; | ||
240 | |||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GSTRING_LEN] = { | ||
245 | /* NETIF_F_SG */ "tx-scatter-gather", | ||
246 | /* NETIF_F_IP_CSUM */ "tx-checksum-ipv4", | ||
247 | /* NETIF_F_NO_CSUM */ "tx-checksum-unneeded", | ||
248 | /* NETIF_F_HW_CSUM */ "tx-checksum-ip-generic", | ||
249 | /* NETIF_F_IPV6_CSUM */ "tx_checksum-ipv6", | ||
250 | /* NETIF_F_HIGHDMA */ "highdma", | ||
251 | /* NETIF_F_FRAGLIST */ "tx-scatter-gather-fraglist", | ||
252 | /* NETIF_F_HW_VLAN_TX */ "tx-vlan-hw-insert", | ||
253 | |||
254 | /* NETIF_F_HW_VLAN_RX */ "rx-vlan-hw-parse", | ||
255 | /* NETIF_F_HW_VLAN_FILTER */ "rx-vlan-filter", | ||
256 | /* NETIF_F_VLAN_CHALLENGED */ "vlan-challenged", | ||
257 | /* NETIF_F_GSO */ "tx-generic-segmentation", | ||
258 | /* NETIF_F_LLTX */ "tx-lockless", | ||
259 | /* NETIF_F_NETNS_LOCAL */ "netns-local", | ||
260 | /* NETIF_F_GRO */ "rx-gro", | ||
261 | /* NETIF_F_LRO */ "rx-lro", | ||
262 | |||
263 | /* NETIF_F_TSO */ "tx-tcp-segmentation", | ||
264 | /* NETIF_F_UFO */ "tx-udp-fragmentation", | ||
265 | /* NETIF_F_GSO_ROBUST */ "tx-gso-robust", | ||
266 | /* NETIF_F_TSO_ECN */ "tx-tcp-ecn-segmentation", | ||
267 | /* NETIF_F_TSO6 */ "tx-tcp6-segmentation", | ||
268 | /* NETIF_F_FSO */ "tx-fcoe-segmentation", | ||
269 | "", | ||
270 | "", | ||
271 | |||
272 | /* NETIF_F_FCOE_CRC */ "tx-checksum-fcoe-crc", | ||
273 | /* NETIF_F_SCTP_CSUM */ "tx-checksum-sctp", | ||
274 | /* NETIF_F_FCOE_MTU */ "fcoe-mtu", | ||
275 | /* NETIF_F_NTUPLE */ "rx-ntuple-filter", | ||
276 | /* NETIF_F_RXHASH */ "rx-hashing", | ||
277 | "", | ||
278 | "", | ||
279 | "", | ||
280 | }; | ||
281 | |||
175 | static int __ethtool_get_sset_count(struct net_device *dev, int sset) | 282 | static int __ethtool_get_sset_count(struct net_device *dev, int sset) |
176 | { | 283 | { |
177 | const struct ethtool_ops *ops = dev->ethtool_ops; | 284 | const struct ethtool_ops *ops = dev->ethtool_ops; |
178 | 285 | ||
286 | if (sset == ETH_SS_FEATURES) | ||
287 | return ARRAY_SIZE(netdev_features_strings); | ||
288 | |||
179 | if (ops && ops->get_sset_count && ops->get_strings) | 289 | if (ops && ops->get_sset_count && ops->get_strings) |
180 | return ops->get_sset_count(dev, sset); | 290 | return ops->get_sset_count(dev, sset); |
181 | else | 291 | else |
@@ -187,8 +297,12 @@ static void __ethtool_get_strings(struct net_device *dev, | |||
187 | { | 297 | { |
188 | const struct ethtool_ops *ops = dev->ethtool_ops; | 298 | const struct ethtool_ops *ops = dev->ethtool_ops; |
189 | 299 | ||
190 | /* ops->get_strings is valid because checked earlier */ | 300 | if (stringset == ETH_SS_FEATURES) |
191 | ops->get_strings(dev, stringset, data); | 301 | memcpy(data, netdev_features_strings, |
302 | sizeof(netdev_features_strings)); | ||
303 | else | ||
304 | /* ops->get_strings is valid because checked earlier */ | ||
305 | ops->get_strings(dev, stringset, data); | ||
192 | } | 306 | } |
193 | 307 | ||
194 | static u32 ethtool_get_feature_mask(u32 eth_cmd) | 308 | static u32 ethtool_get_feature_mask(u32 eth_cmd) |
@@ -1533,6 +1647,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1533 | case ETHTOOL_GRXCLSRLCNT: | 1647 | case ETHTOOL_GRXCLSRLCNT: |
1534 | case ETHTOOL_GRXCLSRULE: | 1648 | case ETHTOOL_GRXCLSRULE: |
1535 | case ETHTOOL_GRXCLSRLALL: | 1649 | case ETHTOOL_GRXCLSRLALL: |
1650 | case ETHTOOL_GFEATURES: | ||
1536 | break; | 1651 | break; |
1537 | default: | 1652 | default: |
1538 | if (!capable(CAP_NET_ADMIN)) | 1653 | if (!capable(CAP_NET_ADMIN)) |
@@ -1678,6 +1793,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1678 | case ETHTOOL_SRXFHINDIR: | 1793 | case ETHTOOL_SRXFHINDIR: |
1679 | rc = ethtool_set_rxfh_indir(dev, useraddr); | 1794 | rc = ethtool_set_rxfh_indir(dev, useraddr); |
1680 | break; | 1795 | break; |
1796 | case ETHTOOL_GFEATURES: | ||
1797 | rc = ethtool_get_features(dev, useraddr); | ||
1798 | break; | ||
1799 | case ETHTOOL_SFEATURES: | ||
1800 | rc = ethtool_set_features(dev, useraddr); | ||
1801 | break; | ||
1681 | case ETHTOOL_GTXCSUM: | 1802 | case ETHTOOL_GTXCSUM: |
1682 | case ETHTOOL_GSG: | 1803 | case ETHTOOL_GSG: |
1683 | case ETHTOOL_GTSO: | 1804 | case ETHTOOL_GTSO: |