aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/vmxnet3/vmxnet3_ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/vmxnet3/vmxnet3_ethtool.c')
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c476
1 files changed, 273 insertions, 203 deletions
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 7e4b5a89165a..dc959fe27aa5 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -33,113 +33,82 @@ struct vmxnet3_stat_desc {
33}; 33};
34 34
35 35
36static u32
37vmxnet3_get_rx_csum(struct net_device *netdev)
38{
39 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
40 return adapter->rxcsum;
41}
42
43
44static int
45vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
46{
47 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
48
49 if (adapter->rxcsum != val) {
50 adapter->rxcsum = val;
51 if (netif_running(netdev)) {
52 if (val)
53 set_flag_le64(
54 &adapter->shared->devRead.misc.uptFeatures,
55 UPT1_F_RXCSUM);
56 else
57 reset_flag_le64(
58 &adapter->shared->devRead.misc.uptFeatures,
59 UPT1_F_RXCSUM);
60
61 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
62 VMXNET3_CMD_UPDATE_FEATURE);
63 }
64 }
65 return 0;
66}
67
68
69/* per tq stats maintained by the device */ 36/* per tq stats maintained by the device */
70static const struct vmxnet3_stat_desc 37static const struct vmxnet3_stat_desc
71vmxnet3_tq_dev_stats[] = { 38vmxnet3_tq_dev_stats[] = {
72 /* description, offset */ 39 /* description, offset */
73 { "TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) }, 40 { "Tx Queue#", 0 },
74 { "TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) }, 41 { " TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
75 { "ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) }, 42 { " TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
76 { "ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) }, 43 { " ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
77 { "mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) }, 44 { " ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) },
78 { "mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) }, 45 { " mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) },
79 { "bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) }, 46 { " mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) },
80 { "bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) }, 47 { " bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) },
81 { "pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) }, 48 { " bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) },
82 { "pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) }, 49 { " pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) },
50 { " pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) },
83}; 51};
84 52
85/* per tq stats maintained by the driver */ 53/* per tq stats maintained by the driver */
86static const struct vmxnet3_stat_desc 54static const struct vmxnet3_stat_desc
87vmxnet3_tq_driver_stats[] = { 55vmxnet3_tq_driver_stats[] = {
88 /* description, offset */ 56 /* description, offset */
89 {"drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats, 57 {" drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats,
90 drop_total) }, 58 drop_total) },
91 { " too many frags", offsetof(struct vmxnet3_tq_driver_stats, 59 { " too many frags", offsetof(struct vmxnet3_tq_driver_stats,
92 drop_too_many_frags) }, 60 drop_too_many_frags) },
93 { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats, 61 { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
94 drop_oversized_hdr) }, 62 drop_oversized_hdr) },
95 { " hdr err", offsetof(struct vmxnet3_tq_driver_stats, 63 { " hdr err", offsetof(struct vmxnet3_tq_driver_stats,
96 drop_hdr_inspect_err) }, 64 drop_hdr_inspect_err) },
97 { " tso", offsetof(struct vmxnet3_tq_driver_stats, 65 { " tso", offsetof(struct vmxnet3_tq_driver_stats,
98 drop_tso) }, 66 drop_tso) },
99 { "ring full", offsetof(struct vmxnet3_tq_driver_stats, 67 { " ring full", offsetof(struct vmxnet3_tq_driver_stats,
100 tx_ring_full) }, 68 tx_ring_full) },
101 { "pkts linearized", offsetof(struct vmxnet3_tq_driver_stats, 69 { " pkts linearized", offsetof(struct vmxnet3_tq_driver_stats,
102 linearized) }, 70 linearized) },
103 { "hdr cloned", offsetof(struct vmxnet3_tq_driver_stats, 71 { " hdr cloned", offsetof(struct vmxnet3_tq_driver_stats,
104 copy_skb_header) }, 72 copy_skb_header) },
105 { "giant hdr", offsetof(struct vmxnet3_tq_driver_stats, 73 { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
106 oversized_hdr) }, 74 oversized_hdr) },
107}; 75};
108 76
109/* per rq stats maintained by the device */ 77/* per rq stats maintained by the device */
110static const struct vmxnet3_stat_desc 78static const struct vmxnet3_stat_desc
111vmxnet3_rq_dev_stats[] = { 79vmxnet3_rq_dev_stats[] = {
112 { "LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) }, 80 { "Rx Queue#", 0 },
113 { "LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) }, 81 { " LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) },
114 { "ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) }, 82 { " LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) },
115 { "ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) }, 83 { " ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
116 { "mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) }, 84 { " ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) },
117 { "mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) }, 85 { " mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) },
118 { "bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) }, 86 { " mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
119 { "bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) }, 87 { " bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
120 { "pkts rx out of buf", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) }, 88 { " bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
121 { "pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) }, 89 { " pkts rx OOB", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
90 { " pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) },
122}; 91};
123 92
124/* per rq stats maintained by the driver */ 93/* per rq stats maintained by the driver */
125static const struct vmxnet3_stat_desc 94static const struct vmxnet3_stat_desc
126vmxnet3_rq_driver_stats[] = { 95vmxnet3_rq_driver_stats[] = {
127 /* description, offset */ 96 /* description, offset */
128 { "drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats, 97 { " drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats,
129 drop_total) }, 98 drop_total) },
130 { " err", offsetof(struct vmxnet3_rq_driver_stats, 99 { " err", offsetof(struct vmxnet3_rq_driver_stats,
131 drop_err) }, 100 drop_err) },
132 { " fcs", offsetof(struct vmxnet3_rq_driver_stats, 101 { " fcs", offsetof(struct vmxnet3_rq_driver_stats,
133 drop_fcs) }, 102 drop_fcs) },
134 { "rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats, 103 { " rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
135 rx_buf_alloc_failure) }, 104 rx_buf_alloc_failure) },
136}; 105};
137 106
138/* gloabl stats maintained by the driver */ 107/* gloabl stats maintained by the driver */
139static const struct vmxnet3_stat_desc 108static const struct vmxnet3_stat_desc
140vmxnet3_global_stats[] = { 109vmxnet3_global_stats[] = {
141 /* description, offset */ 110 /* description, offset */
142 { "tx timeout count", offsetof(struct vmxnet3_adapter, 111 { "tx timeout count", offsetof(struct vmxnet3_adapter,
143 tx_timeout_count) } 112 tx_timeout_count) }
144}; 113};
145 114
@@ -153,56 +122,60 @@ vmxnet3_get_stats(struct net_device *netdev)
153 struct UPT1_TxStats *devTxStats; 122 struct UPT1_TxStats *devTxStats;
154 struct UPT1_RxStats *devRxStats; 123 struct UPT1_RxStats *devRxStats;
155 struct net_device_stats *net_stats = &netdev->stats; 124 struct net_device_stats *net_stats = &netdev->stats;
125 unsigned long flags;
126 int i;
156 127
157 adapter = netdev_priv(netdev); 128 adapter = netdev_priv(netdev);
158 129
159 /* Collect the dev stats into the shared area */ 130 /* Collect the dev stats into the shared area */
131 spin_lock_irqsave(&adapter->cmd_lock, flags);
160 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); 132 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
161 133 spin_unlock_irqrestore(&adapter->cmd_lock, flags);
162 /* Assuming that we have a single queue device */
163 devTxStats = &adapter->tqd_start->stats;
164 devRxStats = &adapter->rqd_start->stats;
165
166 /* Get access to the driver stats per queue */
167 drvTxStats = &adapter->tx_queue.stats;
168 drvRxStats = &adapter->rx_queue.stats;
169 134
170 memset(net_stats, 0, sizeof(*net_stats)); 135 memset(net_stats, 0, sizeof(*net_stats));
136 for (i = 0; i < adapter->num_tx_queues; i++) {
137 devTxStats = &adapter->tqd_start[i].stats;
138 drvTxStats = &adapter->tx_queue[i].stats;
139 net_stats->tx_packets += devTxStats->ucastPktsTxOK +
140 devTxStats->mcastPktsTxOK +
141 devTxStats->bcastPktsTxOK;
142 net_stats->tx_bytes += devTxStats->ucastBytesTxOK +
143 devTxStats->mcastBytesTxOK +
144 devTxStats->bcastBytesTxOK;
145 net_stats->tx_errors += devTxStats->pktsTxError;
146 net_stats->tx_dropped += drvTxStats->drop_total;
147 }
171 148
172 net_stats->rx_packets = devRxStats->ucastPktsRxOK + 149 for (i = 0; i < adapter->num_rx_queues; i++) {
173 devRxStats->mcastPktsRxOK + 150 devRxStats = &adapter->rqd_start[i].stats;
174 devRxStats->bcastPktsRxOK; 151 drvRxStats = &adapter->rx_queue[i].stats;
175 152 net_stats->rx_packets += devRxStats->ucastPktsRxOK +
176 net_stats->tx_packets = devTxStats->ucastPktsTxOK + 153 devRxStats->mcastPktsRxOK +
177 devTxStats->mcastPktsTxOK + 154 devRxStats->bcastPktsRxOK;
178 devTxStats->bcastPktsTxOK;
179
180 net_stats->rx_bytes = devRxStats->ucastBytesRxOK +
181 devRxStats->mcastBytesRxOK +
182 devRxStats->bcastBytesRxOK;
183
184 net_stats->tx_bytes = devTxStats->ucastBytesTxOK +
185 devTxStats->mcastBytesTxOK +
186 devTxStats->bcastBytesTxOK;
187 155
188 net_stats->rx_errors = devRxStats->pktsRxError; 156 net_stats->rx_bytes += devRxStats->ucastBytesRxOK +
189 net_stats->tx_errors = devTxStats->pktsTxError; 157 devRxStats->mcastBytesRxOK +
190 net_stats->rx_dropped = drvRxStats->drop_total; 158 devRxStats->bcastBytesRxOK;
191 net_stats->tx_dropped = drvTxStats->drop_total;
192 net_stats->multicast = devRxStats->mcastPktsRxOK;
193 159
160 net_stats->rx_errors += devRxStats->pktsRxError;
161 net_stats->rx_dropped += drvRxStats->drop_total;
162 net_stats->multicast += devRxStats->mcastPktsRxOK;
163 }
194 return net_stats; 164 return net_stats;
195} 165}
196 166
197static int 167static int
198vmxnet3_get_sset_count(struct net_device *netdev, int sset) 168vmxnet3_get_sset_count(struct net_device *netdev, int sset)
199{ 169{
170 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
200 switch (sset) { 171 switch (sset) {
201 case ETH_SS_STATS: 172 case ETH_SS_STATS:
202 return ARRAY_SIZE(vmxnet3_tq_dev_stats) + 173 return (ARRAY_SIZE(vmxnet3_tq_dev_stats) +
203 ARRAY_SIZE(vmxnet3_tq_driver_stats) + 174 ARRAY_SIZE(vmxnet3_tq_driver_stats)) *
204 ARRAY_SIZE(vmxnet3_rq_dev_stats) + 175 adapter->num_tx_queues +
205 ARRAY_SIZE(vmxnet3_rq_driver_stats) + 176 (ARRAY_SIZE(vmxnet3_rq_dev_stats) +
177 ARRAY_SIZE(vmxnet3_rq_driver_stats)) *
178 adapter->num_rx_queues +
206 ARRAY_SIZE(vmxnet3_global_stats); 179 ARRAY_SIZE(vmxnet3_global_stats);
207 default: 180 default:
208 return -EOPNOTSUPP; 181 return -EOPNOTSUPP;
@@ -210,10 +183,16 @@ vmxnet3_get_sset_count(struct net_device *netdev, int sset)
210} 183}
211 184
212 185
186/* Should be multiple of 4 */
187#define NUM_TX_REGS 8
188#define NUM_RX_REGS 12
189
213static int 190static int
214vmxnet3_get_regs_len(struct net_device *netdev) 191vmxnet3_get_regs_len(struct net_device *netdev)
215{ 192{
216 return 20 * sizeof(u32); 193 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
194 return (adapter->num_tx_queues * NUM_TX_REGS * sizeof(u32) +
195 adapter->num_rx_queues * NUM_RX_REGS * sizeof(u32));
217} 196}
218 197
219 198
@@ -244,29 +223,37 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
244static void 223static void
245vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) 224vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
246{ 225{
226 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
247 if (stringset == ETH_SS_STATS) { 227 if (stringset == ETH_SS_STATS) {
248 int i; 228 int i, j;
249 229 for (j = 0; j < adapter->num_tx_queues; j++) {
250 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) { 230 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
251 memcpy(buf, vmxnet3_tq_dev_stats[i].desc, 231 memcpy(buf, vmxnet3_tq_dev_stats[i].desc,
252 ETH_GSTRING_LEN); 232 ETH_GSTRING_LEN);
253 buf += ETH_GSTRING_LEN; 233 buf += ETH_GSTRING_LEN;
254 } 234 }
255 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) { 235 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats);
256 memcpy(buf, vmxnet3_tq_driver_stats[i].desc, 236 i++) {
257 ETH_GSTRING_LEN); 237 memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
258 buf += ETH_GSTRING_LEN; 238 ETH_GSTRING_LEN);
259 } 239 buf += ETH_GSTRING_LEN;
260 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) { 240 }
261 memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
262 ETH_GSTRING_LEN);
263 buf += ETH_GSTRING_LEN;
264 } 241 }
265 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) { 242
266 memcpy(buf, vmxnet3_rq_driver_stats[i].desc, 243 for (j = 0; j < adapter->num_rx_queues; j++) {
267 ETH_GSTRING_LEN); 244 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
268 buf += ETH_GSTRING_LEN; 245 memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
246 ETH_GSTRING_LEN);
247 buf += ETH_GSTRING_LEN;
248 }
249 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats);
250 i++) {
251 memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
252 ETH_GSTRING_LEN);
253 buf += ETH_GSTRING_LEN;
254 }
269 } 255 }
256
270 for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) { 257 for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) {
271 memcpy(buf, vmxnet3_global_stats[i].desc, 258 memcpy(buf, vmxnet3_global_stats[i].desc,
272 ETH_GSTRING_LEN); 259 ETH_GSTRING_LEN);
@@ -275,29 +262,32 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
275 } 262 }
276} 263}
277 264
278static int 265int vmxnet3_set_features(struct net_device *netdev, u32 features)
279vmxnet3_set_flags(struct net_device *netdev, u32 data)
280{ 266{
281 struct vmxnet3_adapter *adapter = netdev_priv(netdev); 267 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
282 u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1; 268 unsigned long flags;
283 u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; 269 u32 changed = features ^ netdev->features;
284
285 if (data & ~ETH_FLAG_LRO)
286 return -EOPNOTSUPP;
287 270
288 if (lro_requested ^ lro_present) { 271 if (changed & (NETIF_F_RXCSUM|NETIF_F_LRO)) {
289 /* toggle the LRO feature*/ 272 if (features & NETIF_F_RXCSUM)
290 netdev->features ^= NETIF_F_LRO; 273 adapter->shared->devRead.misc.uptFeatures |=
274 UPT1_F_RXCSUM;
275 else
276 adapter->shared->devRead.misc.uptFeatures &=
277 ~UPT1_F_RXCSUM;
291 278
292 /* update harware LRO capability accordingly */ 279 /* update harware LRO capability accordingly */
293 if (lro_requested) 280 if (features & NETIF_F_LRO)
294 adapter->shared->devRead.misc.uptFeatures |= 281 adapter->shared->devRead.misc.uptFeatures |=
295 cpu_to_le64(UPT1_F_LRO); 282 UPT1_F_LRO;
296 else 283 else
297 adapter->shared->devRead.misc.uptFeatures &= 284 adapter->shared->devRead.misc.uptFeatures &=
298 cpu_to_le64(~UPT1_F_LRO); 285 ~UPT1_F_LRO;
286
287 spin_lock_irqsave(&adapter->cmd_lock, flags);
299 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, 288 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
300 VMXNET3_CMD_UPDATE_FEATURE); 289 VMXNET3_CMD_UPDATE_FEATURE);
290 spin_unlock_irqrestore(&adapter->cmd_lock, flags);
301 } 291 }
302 return 0; 292 return 0;
303} 293}
@@ -307,28 +297,41 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
307 struct ethtool_stats *stats, u64 *buf) 297 struct ethtool_stats *stats, u64 *buf)
308{ 298{
309 struct vmxnet3_adapter *adapter = netdev_priv(netdev); 299 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
300 unsigned long flags;
310 u8 *base; 301 u8 *base;
311 int i; 302 int i;
303 int j = 0;
312 304
305 spin_lock_irqsave(&adapter->cmd_lock, flags);
313 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); 306 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
307 spin_unlock_irqrestore(&adapter->cmd_lock, flags);
314 308
315 /* this does assume each counter is 64-bit wide */ 309 /* this does assume each counter is 64-bit wide */
310 for (j = 0; j < adapter->num_tx_queues; j++) {
311 base = (u8 *)&adapter->tqd_start[j].stats;
312 *buf++ = (u64)j;
313 for (i = 1; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
314 *buf++ = *(u64 *)(base +
315 vmxnet3_tq_dev_stats[i].offset);
316
317 base = (u8 *)&adapter->tx_queue[j].stats;
318 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
319 *buf++ = *(u64 *)(base +
320 vmxnet3_tq_driver_stats[i].offset);
321 }
316 322
317 base = (u8 *)&adapter->tqd_start->stats; 323 for (j = 0; j < adapter->num_tx_queues; j++) {
318 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) 324 base = (u8 *)&adapter->rqd_start[j].stats;
319 *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset); 325 *buf++ = (u64) j;
320 326 for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
321 base = (u8 *)&adapter->tx_queue.stats; 327 *buf++ = *(u64 *)(base +
322 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) 328 vmxnet3_rq_dev_stats[i].offset);
323 *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset); 329
324 330 base = (u8 *)&adapter->rx_queue[j].stats;
325 base = (u8 *)&adapter->rqd_start->stats; 331 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
326 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) 332 *buf++ = *(u64 *)(base +
327 *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset); 333 vmxnet3_rq_driver_stats[i].offset);
328 334 }
329 base = (u8 *)&adapter->rx_queue.stats;
330 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
331 *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset);
332 335
333 base = (u8 *)adapter; 336 base = (u8 *)adapter;
334 for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) 337 for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++)
@@ -341,6 +344,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
341{ 344{
342 struct vmxnet3_adapter *adapter = netdev_priv(netdev); 345 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
343 u32 *buf = p; 346 u32 *buf = p;
347 int i = 0, j = 0;
344 348
345 memset(p, 0, vmxnet3_get_regs_len(netdev)); 349 memset(p, 0, vmxnet3_get_regs_len(netdev));
346 350
@@ -349,30 +353,35 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
349 /* Update vmxnet3_get_regs_len if we want to dump more registers */ 353 /* Update vmxnet3_get_regs_len if we want to dump more registers */
350 354
351 /* make each ring use multiple of 16 bytes */ 355 /* make each ring use multiple of 16 bytes */
352 buf[0] = adapter->tx_queue.tx_ring.next2fill; 356 for (i = 0; i < adapter->num_tx_queues; i++) {
353 buf[1] = adapter->tx_queue.tx_ring.next2comp; 357 buf[j++] = adapter->tx_queue[i].tx_ring.next2fill;
354 buf[2] = adapter->tx_queue.tx_ring.gen; 358 buf[j++] = adapter->tx_queue[i].tx_ring.next2comp;
355 buf[3] = 0; 359 buf[j++] = adapter->tx_queue[i].tx_ring.gen;
356 360 buf[j++] = 0;
357 buf[4] = adapter->tx_queue.comp_ring.next2proc; 361
358 buf[5] = adapter->tx_queue.comp_ring.gen; 362 buf[j++] = adapter->tx_queue[i].comp_ring.next2proc;
359 buf[6] = adapter->tx_queue.stopped; 363 buf[j++] = adapter->tx_queue[i].comp_ring.gen;
360 buf[7] = 0; 364 buf[j++] = adapter->tx_queue[i].stopped;
361 365 buf[j++] = 0;
362 buf[8] = adapter->rx_queue.rx_ring[0].next2fill; 366 }
363 buf[9] = adapter->rx_queue.rx_ring[0].next2comp; 367
364 buf[10] = adapter->rx_queue.rx_ring[0].gen; 368 for (i = 0; i < adapter->num_rx_queues; i++) {
365 buf[11] = 0; 369 buf[j++] = adapter->rx_queue[i].rx_ring[0].next2fill;
366 370 buf[j++] = adapter->rx_queue[i].rx_ring[0].next2comp;
367 buf[12] = adapter->rx_queue.rx_ring[1].next2fill; 371 buf[j++] = adapter->rx_queue[i].rx_ring[0].gen;
368 buf[13] = adapter->rx_queue.rx_ring[1].next2comp; 372 buf[j++] = 0;
369 buf[14] = adapter->rx_queue.rx_ring[1].gen; 373
370 buf[15] = 0; 374 buf[j++] = adapter->rx_queue[i].rx_ring[1].next2fill;
371 375 buf[j++] = adapter->rx_queue[i].rx_ring[1].next2comp;
372 buf[16] = adapter->rx_queue.comp_ring.next2proc; 376 buf[j++] = adapter->rx_queue[i].rx_ring[1].gen;
373 buf[17] = adapter->rx_queue.comp_ring.gen; 377 buf[j++] = 0;
374 buf[18] = 0; 378
375 buf[19] = 0; 379 buf[j++] = adapter->rx_queue[i].comp_ring.next2proc;
380 buf[j++] = adapter->rx_queue[i].comp_ring.gen;
381 buf[j++] = 0;
382 buf[j++] = 0;
383 }
384
376} 385}
377 386
378 387
@@ -416,10 +425,10 @@ vmxnet3_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
416 ecmd->transceiver = XCVR_INTERNAL; 425 ecmd->transceiver = XCVR_INTERNAL;
417 426
418 if (adapter->link_speed) { 427 if (adapter->link_speed) {
419 ecmd->speed = adapter->link_speed; 428 ethtool_cmd_speed_set(ecmd, adapter->link_speed);
420 ecmd->duplex = DUPLEX_FULL; 429 ecmd->duplex = DUPLEX_FULL;
421 } else { 430 } else {
422 ecmd->speed = -1; 431 ethtool_cmd_speed_set(ecmd, -1);
423 ecmd->duplex = -1; 432 ecmd->duplex = -1;
424 } 433 }
425 return 0; 434 return 0;
@@ -437,8 +446,10 @@ vmxnet3_get_ringparam(struct net_device *netdev,
437 param->rx_mini_max_pending = 0; 446 param->rx_mini_max_pending = 0;
438 param->rx_jumbo_max_pending = 0; 447 param->rx_jumbo_max_pending = 0;
439 448
440 param->rx_pending = adapter->rx_queue.rx_ring[0].size; 449 param->rx_pending = adapter->rx_queue[0].rx_ring[0].size *
441 param->tx_pending = adapter->tx_queue.tx_ring.size; 450 adapter->num_rx_queues;
451 param->tx_pending = adapter->tx_queue[0].tx_ring.size *
452 adapter->num_tx_queues;
442 param->rx_mini_pending = 0; 453 param->rx_mini_pending = 0;
443 param->rx_jumbo_pending = 0; 454 param->rx_jumbo_pending = 0;
444} 455}
@@ -482,8 +493,8 @@ vmxnet3_set_ringparam(struct net_device *netdev,
482 sz) != 0) 493 sz) != 0)
483 return -EINVAL; 494 return -EINVAL;
484 495
485 if (new_tx_ring_size == adapter->tx_queue.tx_ring.size && 496 if (new_tx_ring_size == adapter->tx_queue[0].tx_ring.size &&
486 new_rx_ring_size == adapter->rx_queue.rx_ring[0].size) { 497 new_rx_ring_size == adapter->rx_queue[0].rx_ring[0].size) {
487 return 0; 498 return 0;
488 } 499 }
489 500
@@ -500,11 +511,12 @@ vmxnet3_set_ringparam(struct net_device *netdev,
500 511
501 /* recreate the rx queue and the tx queue based on the 512 /* recreate the rx queue and the tx queue based on the
502 * new sizes */ 513 * new sizes */
503 vmxnet3_tq_destroy(&adapter->tx_queue, adapter); 514 vmxnet3_tq_destroy_all(adapter);
504 vmxnet3_rq_destroy(&adapter->rx_queue, adapter); 515 vmxnet3_rq_destroy_all(adapter);
505 516
506 err = vmxnet3_create_queues(adapter, new_tx_ring_size, 517 err = vmxnet3_create_queues(adapter, new_tx_ring_size,
507 new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE); 518 new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE);
519
508 if (err) { 520 if (err) {
509 /* failed, most likely because of OOM, try default 521 /* failed, most likely because of OOM, try default
510 * size */ 522 * size */
@@ -537,6 +549,69 @@ out:
537} 549}
538 550
539 551
552static int
553vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info,
554 void *rules)
555{
556 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
557 switch (info->cmd) {
558 case ETHTOOL_GRXRINGS:
559 info->data = adapter->num_rx_queues;
560 return 0;
561 }
562 return -EOPNOTSUPP;
563}
564
565#ifdef VMXNET3_RSS
566static int
567vmxnet3_get_rss_indir(struct net_device *netdev,
568 struct ethtool_rxfh_indir *p)
569{
570 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
571 struct UPT1_RSSConf *rssConf = adapter->rss_conf;
572 unsigned int n = min_t(unsigned int, p->size, rssConf->indTableSize);
573
574 p->size = rssConf->indTableSize;
575 while (n--)
576 p->ring_index[n] = rssConf->indTable[n];
577 return 0;
578
579}
580
581static int
582vmxnet3_set_rss_indir(struct net_device *netdev,
583 const struct ethtool_rxfh_indir *p)
584{
585 unsigned int i;
586 unsigned long flags;
587 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
588 struct UPT1_RSSConf *rssConf = adapter->rss_conf;
589
590 if (p->size != rssConf->indTableSize)
591 return -EINVAL;
592 for (i = 0; i < rssConf->indTableSize; i++) {
593 /*
594 * Return with error code if any of the queue indices
595 * is out of range
596 */
597 if (p->ring_index[i] < 0 ||
598 p->ring_index[i] >= adapter->num_rx_queues)
599 return -EINVAL;
600 }
601
602 for (i = 0; i < rssConf->indTableSize; i++)
603 rssConf->indTable[i] = p->ring_index[i];
604
605 spin_lock_irqsave(&adapter->cmd_lock, flags);
606 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
607 VMXNET3_CMD_UPDATE_RSSIDT);
608 spin_unlock_irqrestore(&adapter->cmd_lock, flags);
609
610 return 0;
611
612}
613#endif
614
540static struct ethtool_ops vmxnet3_ethtool_ops = { 615static struct ethtool_ops vmxnet3_ethtool_ops = {
541 .get_settings = vmxnet3_get_settings, 616 .get_settings = vmxnet3_get_settings,
542 .get_drvinfo = vmxnet3_get_drvinfo, 617 .get_drvinfo = vmxnet3_get_drvinfo,
@@ -545,21 +620,16 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
545 .get_wol = vmxnet3_get_wol, 620 .get_wol = vmxnet3_get_wol,
546 .set_wol = vmxnet3_set_wol, 621 .set_wol = vmxnet3_set_wol,
547 .get_link = ethtool_op_get_link, 622 .get_link = ethtool_op_get_link,
548 .get_rx_csum = vmxnet3_get_rx_csum,
549 .set_rx_csum = vmxnet3_set_rx_csum,
550 .get_tx_csum = ethtool_op_get_tx_csum,
551 .set_tx_csum = ethtool_op_set_tx_hw_csum,
552 .get_sg = ethtool_op_get_sg,
553 .set_sg = ethtool_op_set_sg,
554 .get_tso = ethtool_op_get_tso,
555 .set_tso = ethtool_op_set_tso,
556 .get_strings = vmxnet3_get_strings, 623 .get_strings = vmxnet3_get_strings,
557 .get_flags = ethtool_op_get_flags,
558 .set_flags = vmxnet3_set_flags,
559 .get_sset_count = vmxnet3_get_sset_count, 624 .get_sset_count = vmxnet3_get_sset_count,
560 .get_ethtool_stats = vmxnet3_get_ethtool_stats, 625 .get_ethtool_stats = vmxnet3_get_ethtool_stats,
561 .get_ringparam = vmxnet3_get_ringparam, 626 .get_ringparam = vmxnet3_get_ringparam,
562 .set_ringparam = vmxnet3_set_ringparam, 627 .set_ringparam = vmxnet3_set_ringparam,
628 .get_rxnfc = vmxnet3_get_rxnfc,
629#ifdef VMXNET3_RSS
630 .get_rxfh_indir = vmxnet3_get_rss_indir,
631 .set_rxfh_indir = vmxnet3_set_rss_indir,
632#endif
563}; 633};
564 634
565void vmxnet3_set_ethtool_ops(struct net_device *netdev) 635void vmxnet3_set_ethtool_ops(struct net_device *netdev)