diff options
author | Michał Mirosław <mirq-linux@rere.qmqm.pl> | 2011-11-15 10:29:55 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-16 17:43:11 -0500 |
commit | 475414f6f20cb1211319f02a96ef241f716cfe1d (patch) | |
tree | b5d08f04077a789a03259172ee9abcfcde4f6b5f /net | |
parent | 9d921549b3902a4b011fe0d0e42f3546ede1797e (diff) |
ethtool: prepare for larger netdev_features_t type
v2: changed loop in ethtool_set_features() per Ben's suggestion
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/ethtool.c | 42 |
1 files changed, 26 insertions, 16 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 817ad4b2b9db..bbf84fe0096e 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -38,7 +38,7 @@ EXPORT_SYMBOL(ethtool_op_get_link); | |||
38 | 38 | ||
39 | /* Handlers for each ethtool command */ | 39 | /* Handlers for each ethtool command */ |
40 | 40 | ||
41 | #define ETHTOOL_DEV_FEATURE_WORDS 1 | 41 | #define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32) |
42 | 42 | ||
43 | static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = { | 43 | static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = { |
44 | [NETIF_F_SG_BIT] = "tx-scatter-gather", | 44 | [NETIF_F_SG_BIT] = "tx-scatter-gather", |
@@ -82,16 +82,20 @@ static int ethtool_get_features(struct net_device *dev, void __user *useraddr) | |||
82 | .cmd = ETHTOOL_GFEATURES, | 82 | .cmd = ETHTOOL_GFEATURES, |
83 | .size = ETHTOOL_DEV_FEATURE_WORDS, | 83 | .size = ETHTOOL_DEV_FEATURE_WORDS, |
84 | }; | 84 | }; |
85 | struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS] = { | 85 | struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS]; |
86 | { | ||
87 | .available = dev->hw_features, | ||
88 | .requested = dev->wanted_features, | ||
89 | .active = dev->features, | ||
90 | .never_changed = NETIF_F_NEVER_CHANGE, | ||
91 | }, | ||
92 | }; | ||
93 | u32 __user *sizeaddr; | 86 | u32 __user *sizeaddr; |
94 | u32 copy_size; | 87 | u32 copy_size; |
88 | int i; | ||
89 | |||
90 | /* in case feature bits run out again */ | ||
91 | BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS*sizeof(u32) > sizeof(netdev_features_t)); | ||
92 | |||
93 | for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) { | ||
94 | features[i].available = (u32)(dev->hw_features >> (32*i)); | ||
95 | features[i].requested = (u32)(dev->wanted_features >> (32*i)); | ||
96 | features[i].active = (u32)(dev->features >> (32*i)); | ||
97 | features[i].never_changed = (u32)(NETIF_F_NEVER_CHANGE >> (32*i)); | ||
98 | } | ||
95 | 99 | ||
96 | sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size); | 100 | sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size); |
97 | if (get_user(copy_size, sizeaddr)) | 101 | if (get_user(copy_size, sizeaddr)) |
@@ -113,7 +117,8 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr) | |||
113 | { | 117 | { |
114 | struct ethtool_sfeatures cmd; | 118 | struct ethtool_sfeatures cmd; |
115 | struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS]; | 119 | struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS]; |
116 | int ret = 0; | 120 | netdev_features_t wanted = 0, valid = 0; |
121 | int i, ret = 0; | ||
117 | 122 | ||
118 | if (copy_from_user(&cmd, useraddr, sizeof(cmd))) | 123 | if (copy_from_user(&cmd, useraddr, sizeof(cmd))) |
119 | return -EFAULT; | 124 | return -EFAULT; |
@@ -125,19 +130,24 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr) | |||
125 | if (copy_from_user(features, useraddr, sizeof(features))) | 130 | if (copy_from_user(features, useraddr, sizeof(features))) |
126 | return -EFAULT; | 131 | return -EFAULT; |
127 | 132 | ||
128 | if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) | 133 | for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) { |
134 | valid |= (netdev_features_t)features[i].valid << (32*i); | ||
135 | wanted |= (netdev_features_t)features[i].requested << (32*i); | ||
136 | } | ||
137 | |||
138 | if (valid & ~NETIF_F_ETHTOOL_BITS) | ||
129 | return -EINVAL; | 139 | return -EINVAL; |
130 | 140 | ||
131 | if (features[0].valid & ~dev->hw_features) { | 141 | if (valid & ~dev->hw_features) { |
132 | features[0].valid &= dev->hw_features; | 142 | valid &= dev->hw_features; |
133 | ret |= ETHTOOL_F_UNSUPPORTED; | 143 | ret |= ETHTOOL_F_UNSUPPORTED; |
134 | } | 144 | } |
135 | 145 | ||
136 | dev->wanted_features &= ~features[0].valid; | 146 | dev->wanted_features &= ~valid; |
137 | dev->wanted_features |= features[0].valid & features[0].requested; | 147 | dev->wanted_features |= wanted & valid; |
138 | __netdev_update_features(dev); | 148 | __netdev_update_features(dev); |
139 | 149 | ||
140 | if ((dev->wanted_features ^ dev->features) & features[0].valid) | 150 | if ((dev->wanted_features ^ dev->features) & valid) |
141 | ret |= ETHTOOL_F_WISH; | 151 | ret |= ETHTOOL_F_WISH; |
142 | 152 | ||
143 | return ret; | 153 | return ret; |