aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
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
commit0a417704777ed29d0e8c72b7274a328e61248e75 (patch)
tree2a9cd59d8a58faf0904d503e143547b8aacd63ef /net/core
parent340ae1654c0667e0cdd2a6d4dc16f7946e018881 (diff)
ethtool: factorize get/set_one_feature
This allows to enable GRO even if RX csum is disabled. GRO will not be used for packets without hardware checksum anyway. 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')
-rw-r--r--net/core/ethtool.c274
1 files changed, 132 insertions, 142 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 85aaeab862a8..c3fb8f90de6d 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -191,6 +191,109 @@ static void __ethtool_get_strings(struct net_device *dev,
191 ops->get_strings(dev, stringset, data); 191 ops->get_strings(dev, stringset, data);
192} 192}
193 193
194static u32 ethtool_get_feature_mask(u32 eth_cmd)
195{
196 /* feature masks of legacy discrete ethtool ops */
197
198 switch (eth_cmd) {
199 case ETHTOOL_GTXCSUM:
200 case ETHTOOL_STXCSUM:
201 return NETIF_F_ALL_CSUM | NETIF_F_SCTP_CSUM;
202 case ETHTOOL_GSG:
203 case ETHTOOL_SSG:
204 return NETIF_F_SG;
205 case ETHTOOL_GTSO:
206 case ETHTOOL_STSO:
207 return NETIF_F_ALL_TSO;
208 case ETHTOOL_GUFO:
209 case ETHTOOL_SUFO:
210 return NETIF_F_UFO;
211 case ETHTOOL_GGSO:
212 case ETHTOOL_SGSO:
213 return NETIF_F_GSO;
214 case ETHTOOL_GGRO:
215 case ETHTOOL_SGRO:
216 return NETIF_F_GRO;
217 default:
218 BUG();
219 }
220}
221
222static void *__ethtool_get_one_feature_actor(struct net_device *dev, u32 ethcmd)
223{
224 const struct ethtool_ops *ops = dev->ethtool_ops;
225
226 if (!ops)
227 return NULL;
228
229 switch (ethcmd) {
230 case ETHTOOL_GTXCSUM:
231 return ops->get_tx_csum;
232 case ETHTOOL_SSG:
233 return ops->get_sg;
234 case ETHTOOL_STSO:
235 return ops->get_tso;
236 case ETHTOOL_SUFO:
237 return ops->get_ufo;
238 default:
239 return NULL;
240 }
241}
242
243static int ethtool_get_one_feature(struct net_device *dev,
244 char __user *useraddr, u32 ethcmd)
245{
246 struct ethtool_value edata = {
247 .cmd = ethcmd,
248 .data = !!(dev->features & ethtool_get_feature_mask(ethcmd)),
249 };
250 u32 (*actor)(struct net_device *);
251
252 actor = __ethtool_get_one_feature_actor(dev, ethcmd);
253 if (actor)
254 edata.data = actor(dev);
255
256 if (copy_to_user(useraddr, &edata, sizeof(edata)))
257 return -EFAULT;
258 return 0;
259}
260
261static int __ethtool_set_tx_csum(struct net_device *dev, u32 data);
262static int __ethtool_set_sg(struct net_device *dev, u32 data);
263static int __ethtool_set_tso(struct net_device *dev, u32 data);
264static int __ethtool_set_ufo(struct net_device *dev, u32 data);
265
266static int ethtool_set_one_feature(struct net_device *dev,
267 void __user *useraddr, u32 ethcmd)
268{
269 struct ethtool_value edata;
270 u32 mask;
271
272 if (copy_from_user(&edata, useraddr, sizeof(edata)))
273 return -EFAULT;
274
275 switch (ethcmd) {
276 case ETHTOOL_STXCSUM:
277 return __ethtool_set_tx_csum(dev, edata.data);
278 case ETHTOOL_SSG:
279 return __ethtool_set_sg(dev, edata.data);
280 case ETHTOOL_STSO:
281 return __ethtool_set_tso(dev, edata.data);
282 case ETHTOOL_SUFO:
283 return __ethtool_set_ufo(dev, edata.data);
284 case ETHTOOL_SGSO:
285 case ETHTOOL_SGRO:
286 mask = ethtool_get_feature_mask(ethcmd);
287 if (edata.data)
288 dev->features |= mask;
289 else
290 dev->features &= ~mask;
291 return 0;
292 default:
293 return -EOPNOTSUPP;
294 }
295}
296
194static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) 297static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
195{ 298{
196 struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; 299 struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
@@ -1107,6 +1210,9 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
1107{ 1210{
1108 int err; 1211 int err;
1109 1212
1213 if (data && !(dev->features & NETIF_F_ALL_CSUM))
1214 return -EINVAL;
1215
1110 if (!data && dev->ethtool_ops->set_tso) { 1216 if (!data && dev->ethtool_ops->set_tso) {
1111 err = dev->ethtool_ops->set_tso(dev, 0); 1217 err = dev->ethtool_ops->set_tso(dev, 0);
1112 if (err) 1218 if (err)
@@ -1121,24 +1227,20 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
1121 return dev->ethtool_ops->set_sg(dev, data); 1227 return dev->ethtool_ops->set_sg(dev, data);
1122} 1228}
1123 1229
1124static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr) 1230static int __ethtool_set_tx_csum(struct net_device *dev, u32 data)
1125{ 1231{
1126 struct ethtool_value edata;
1127 int err; 1232 int err;
1128 1233
1129 if (!dev->ethtool_ops->set_tx_csum) 1234 if (!dev->ethtool_ops->set_tx_csum)
1130 return -EOPNOTSUPP; 1235 return -EOPNOTSUPP;
1131 1236
1132 if (copy_from_user(&edata, useraddr, sizeof(edata))) 1237 if (!data && dev->ethtool_ops->set_sg) {
1133 return -EFAULT;
1134
1135 if (!edata.data && dev->ethtool_ops->set_sg) {
1136 err = __ethtool_set_sg(dev, 0); 1238 err = __ethtool_set_sg(dev, 0);
1137 if (err) 1239 if (err)
1138 return err; 1240 return err;
1139 } 1241 }
1140 1242
1141 return dev->ethtool_ops->set_tx_csum(dev, edata.data); 1243 return dev->ethtool_ops->set_tx_csum(dev, data);
1142} 1244}
1143 1245
1144static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr) 1246static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr)
@@ -1157,108 +1259,28 @@ static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr)
1157 return dev->ethtool_ops->set_rx_csum(dev, edata.data); 1259 return dev->ethtool_ops->set_rx_csum(dev, edata.data);
1158} 1260}
1159 1261
1160static int ethtool_set_sg(struct net_device *dev, char __user *useraddr) 1262static int __ethtool_set_tso(struct net_device *dev, u32 data)
1161{
1162 struct ethtool_value edata;
1163
1164 if (!dev->ethtool_ops->set_sg)
1165 return -EOPNOTSUPP;
1166
1167 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1168 return -EFAULT;
1169
1170 if (edata.data &&
1171 !(dev->features & NETIF_F_ALL_CSUM))
1172 return -EINVAL;
1173
1174 return __ethtool_set_sg(dev, edata.data);
1175}
1176
1177static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
1178{ 1263{
1179 struct ethtool_value edata;
1180
1181 if (!dev->ethtool_ops->set_tso) 1264 if (!dev->ethtool_ops->set_tso)
1182 return -EOPNOTSUPP; 1265 return -EOPNOTSUPP;
1183 1266
1184 if (copy_from_user(&edata, useraddr, sizeof(edata))) 1267 if (data && !(dev->features & NETIF_F_SG))
1185 return -EFAULT;
1186
1187 if (edata.data && !(dev->features & NETIF_F_SG))
1188 return -EINVAL; 1268 return -EINVAL;
1189 1269
1190 return dev->ethtool_ops->set_tso(dev, edata.data); 1270 return dev->ethtool_ops->set_tso(dev, data);
1191} 1271}
1192 1272
1193static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) 1273static int __ethtool_set_ufo(struct net_device *dev, u32 data)
1194{ 1274{
1195 struct ethtool_value edata;
1196
1197 if (!dev->ethtool_ops->set_ufo) 1275 if (!dev->ethtool_ops->set_ufo)
1198 return -EOPNOTSUPP; 1276 return -EOPNOTSUPP;
1199 if (copy_from_user(&edata, useraddr, sizeof(edata))) 1277 if (data && !(dev->features & NETIF_F_SG))
1200 return -EFAULT;
1201 if (edata.data && !(dev->features & NETIF_F_SG))
1202 return -EINVAL; 1278 return -EINVAL;
1203 if (edata.data && !((dev->features & NETIF_F_GEN_CSUM) || 1279 if (data && !((dev->features & NETIF_F_GEN_CSUM) ||
1204 (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) 1280 (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
1205 == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) 1281 == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)))
1206 return -EINVAL; 1282 return -EINVAL;
1207 return dev->ethtool_ops->set_ufo(dev, edata.data); 1283 return dev->ethtool_ops->set_ufo(dev, data);
1208}
1209
1210static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
1211{
1212 struct ethtool_value edata = { ETHTOOL_GGSO };
1213
1214 edata.data = dev->features & NETIF_F_GSO;
1215 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1216 return -EFAULT;
1217 return 0;
1218}
1219
1220static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
1221{
1222 struct ethtool_value edata;
1223
1224 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1225 return -EFAULT;
1226 if (edata.data)
1227 dev->features |= NETIF_F_GSO;
1228 else
1229 dev->features &= ~NETIF_F_GSO;
1230 return 0;
1231}
1232
1233static int ethtool_get_gro(struct net_device *dev, char __user *useraddr)
1234{
1235 struct ethtool_value edata = { ETHTOOL_GGRO };
1236
1237 edata.data = dev->features & NETIF_F_GRO;
1238 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1239 return -EFAULT;
1240 return 0;
1241}
1242
1243static int ethtool_set_gro(struct net_device *dev, char __user *useraddr)
1244{
1245 struct ethtool_value edata;
1246
1247 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1248 return -EFAULT;
1249
1250 if (edata.data) {
1251 u32 rxcsum = dev->ethtool_ops->get_rx_csum ?
1252 dev->ethtool_ops->get_rx_csum(dev) :
1253 ethtool_op_get_rx_csum(dev);
1254
1255 if (!rxcsum)
1256 return -EINVAL;
1257 dev->features |= NETIF_F_GRO;
1258 } else
1259 dev->features &= ~NETIF_F_GRO;
1260
1261 return 0;
1262} 1284}
1263 1285
1264static int ethtool_self_test(struct net_device *dev, char __user *useraddr) 1286static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
@@ -1590,33 +1612,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1590 case ETHTOOL_SRXCSUM: 1612 case ETHTOOL_SRXCSUM:
1591 rc = ethtool_set_rx_csum(dev, useraddr); 1613 rc = ethtool_set_rx_csum(dev, useraddr);
1592 break; 1614 break;
1593 case ETHTOOL_GTXCSUM:
1594 rc = ethtool_get_value(dev, useraddr, ethcmd,
1595 (dev->ethtool_ops->get_tx_csum ?
1596 dev->ethtool_ops->get_tx_csum :
1597 ethtool_op_get_tx_csum));
1598 break;
1599 case ETHTOOL_STXCSUM:
1600 rc = ethtool_set_tx_csum(dev, useraddr);
1601 break;
1602 case ETHTOOL_GSG:
1603 rc = ethtool_get_value(dev, useraddr, ethcmd,
1604 (dev->ethtool_ops->get_sg ?
1605 dev->ethtool_ops->get_sg :
1606 ethtool_op_get_sg));
1607 break;
1608 case ETHTOOL_SSG:
1609 rc = ethtool_set_sg(dev, useraddr);
1610 break;
1611 case ETHTOOL_GTSO:
1612 rc = ethtool_get_value(dev, useraddr, ethcmd,
1613 (dev->ethtool_ops->get_tso ?
1614 dev->ethtool_ops->get_tso :
1615 ethtool_op_get_tso));
1616 break;
1617 case ETHTOOL_STSO:
1618 rc = ethtool_set_tso(dev, useraddr);
1619 break;
1620 case ETHTOOL_TEST: 1615 case ETHTOOL_TEST:
1621 rc = ethtool_self_test(dev, useraddr); 1616 rc = ethtool_self_test(dev, useraddr);
1622 break; 1617 break;
@@ -1632,21 +1627,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1632 case ETHTOOL_GPERMADDR: 1627 case ETHTOOL_GPERMADDR:
1633 rc = ethtool_get_perm_addr(dev, useraddr); 1628 rc = ethtool_get_perm_addr(dev, useraddr);
1634 break; 1629 break;
1635 case ETHTOOL_GUFO:
1636 rc = ethtool_get_value(dev, useraddr, ethcmd,
1637 (dev->ethtool_ops->get_ufo ?
1638 dev->ethtool_ops->get_ufo :
1639 ethtool_op_get_ufo));
1640 break;
1641 case ETHTOOL_SUFO:
1642 rc = ethtool_set_ufo(dev, useraddr);
1643 break;
1644 case ETHTOOL_GGSO:
1645 rc = ethtool_get_gso(dev, useraddr);
1646 break;
1647 case ETHTOOL_SGSO:
1648 rc = ethtool_set_gso(dev, useraddr);
1649 break;
1650 case ETHTOOL_GFLAGS: 1630 case ETHTOOL_GFLAGS:
1651 rc = ethtool_get_value(dev, useraddr, ethcmd, 1631 rc = ethtool_get_value(dev, useraddr, ethcmd,
1652 (dev->ethtool_ops->get_flags ? 1632 (dev->ethtool_ops->get_flags ?
@@ -1677,12 +1657,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1677 case ETHTOOL_SRXCLSRLINS: 1657 case ETHTOOL_SRXCLSRLINS:
1678 rc = ethtool_set_rxnfc(dev, ethcmd, useraddr); 1658 rc = ethtool_set_rxnfc(dev, ethcmd, useraddr);
1679 break; 1659 break;
1680 case ETHTOOL_GGRO:
1681 rc = ethtool_get_gro(dev, useraddr);
1682 break;
1683 case ETHTOOL_SGRO:
1684 rc = ethtool_set_gro(dev, useraddr);
1685 break;
1686 case ETHTOOL_FLASHDEV: 1660 case ETHTOOL_FLASHDEV:
1687 rc = ethtool_flash_device(dev, useraddr); 1661 rc = ethtool_flash_device(dev, useraddr);
1688 break; 1662 break;
@@ -1704,6 +1678,22 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1704 case ETHTOOL_SRXFHINDIR: 1678 case ETHTOOL_SRXFHINDIR:
1705 rc = ethtool_set_rxfh_indir(dev, useraddr); 1679 rc = ethtool_set_rxfh_indir(dev, useraddr);
1706 break; 1680 break;
1681 case ETHTOOL_GTXCSUM:
1682 case ETHTOOL_GSG:
1683 case ETHTOOL_GTSO:
1684 case ETHTOOL_GUFO:
1685 case ETHTOOL_GGSO:
1686 case ETHTOOL_GGRO:
1687 rc = ethtool_get_one_feature(dev, useraddr, ethcmd);
1688 break;
1689 case ETHTOOL_STXCSUM:
1690 case ETHTOOL_SSG:
1691 case ETHTOOL_STSO:
1692 case ETHTOOL_SUFO:
1693 case ETHTOOL_SGSO:
1694 case ETHTOOL_SGRO:
1695 rc = ethtool_set_one_feature(dev, useraddr, ethcmd);
1696 break;
1707 default: 1697 default:
1708 rc = -EOPNOTSUPP; 1698 rc = -EOPNOTSUPP;
1709 } 1699 }