aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/ethtool.c
diff options
context:
space:
mode:
authorMichał Mirosław <mirq-linux@rere.qmqm.pl>2011-02-15 11:59:17 -0500
committerDavid S. Miller <davem@davemloft.net>2011-02-17 17:16:33 -0500
commit5455c6998d34dc983a8693500e4dffefc3682dc5 (patch)
treeb765aecf6d33d8c550cde78368ccc8654951ec07 /net/core/ethtool.c
parent0a417704777ed29d0e8c72b7274a328e61248e75 (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.c125
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
177static 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
210static 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
244static 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
175static int __ethtool_get_sset_count(struct net_device *dev, int sset) 282static 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
194static u32 ethtool_get_feature_mask(u32 eth_cmd) 308static 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: