diff options
author | Sathya Perla <sathya.perla@emulex.com> | 2010-10-04 01:12:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-04 01:12:27 -0400 |
commit | 3abcdeda59c1d4cf2bf83311ed2d544355ec7c2d (patch) | |
tree | c259d095b583f7fd2183e3eec43f1a5668468248 /drivers/net/benet/be_ethtool.c | |
parent | 72829071269b19381173a13ea1b2ca2f4f9d4cec (diff) |
be2net: add multiple RX queue support
This patch adds multiple RX queue support to be2net. There are
upto 4 extra rx-queues per port into which TCP/UDP traffic can be hashed into.
Some of the ethtool stats are now displayed on a per queue basis.
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/benet/be_ethtool.c')
-rw-r--r-- | drivers/net/benet/be_ethtool.c | 174 |
1 files changed, 102 insertions, 72 deletions
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index d92063420c25..0f46366ecc48 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c | |||
@@ -26,14 +26,16 @@ struct be_ethtool_stat { | |||
26 | int offset; | 26 | int offset; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT, ERXSTAT}; | 29 | enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT}; |
30 | #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \ | 30 | #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \ |
31 | offsetof(_struct, field) | 31 | offsetof(_struct, field) |
32 | #define NETSTAT_INFO(field) #field, NETSTAT,\ | 32 | #define NETSTAT_INFO(field) #field, NETSTAT,\ |
33 | FIELDINFO(struct net_device_stats,\ | 33 | FIELDINFO(struct net_device_stats,\ |
34 | field) | 34 | field) |
35 | #define DRVSTAT_INFO(field) #field, DRVSTAT,\ | 35 | #define DRVSTAT_TX_INFO(field) #field, DRVSTAT_TX,\ |
36 | FIELDINFO(struct be_drvr_stats, field) | 36 | FIELDINFO(struct be_tx_stats, field) |
37 | #define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\ | ||
38 | FIELDINFO(struct be_rx_stats, field) | ||
37 | #define MISCSTAT_INFO(field) #field, MISCSTAT,\ | 39 | #define MISCSTAT_INFO(field) #field, MISCSTAT,\ |
38 | FIELDINFO(struct be_rxf_stats, field) | 40 | FIELDINFO(struct be_rxf_stats, field) |
39 | #define PORTSTAT_INFO(field) #field, PORTSTAT,\ | 41 | #define PORTSTAT_INFO(field) #field, PORTSTAT,\ |
@@ -51,21 +53,12 @@ static const struct be_ethtool_stat et_stats[] = { | |||
51 | {NETSTAT_INFO(tx_errors)}, | 53 | {NETSTAT_INFO(tx_errors)}, |
52 | {NETSTAT_INFO(rx_dropped)}, | 54 | {NETSTAT_INFO(rx_dropped)}, |
53 | {NETSTAT_INFO(tx_dropped)}, | 55 | {NETSTAT_INFO(tx_dropped)}, |
54 | {DRVSTAT_INFO(be_tx_reqs)}, | 56 | {DRVSTAT_TX_INFO(be_tx_rate)}, |
55 | {DRVSTAT_INFO(be_tx_stops)}, | 57 | {DRVSTAT_TX_INFO(be_tx_reqs)}, |
56 | {DRVSTAT_INFO(be_fwd_reqs)}, | 58 | {DRVSTAT_TX_INFO(be_tx_wrbs)}, |
57 | {DRVSTAT_INFO(be_tx_wrbs)}, | 59 | {DRVSTAT_TX_INFO(be_tx_stops)}, |
58 | {DRVSTAT_INFO(be_rx_polls)}, | 60 | {DRVSTAT_TX_INFO(be_tx_events)}, |
59 | {DRVSTAT_INFO(be_tx_events)}, | 61 | {DRVSTAT_TX_INFO(be_tx_compl)}, |
60 | {DRVSTAT_INFO(be_rx_events)}, | ||
61 | {DRVSTAT_INFO(be_tx_compl)}, | ||
62 | {DRVSTAT_INFO(be_rx_compl)}, | ||
63 | {DRVSTAT_INFO(be_rx_mcast_pkt)}, | ||
64 | {DRVSTAT_INFO(be_ethrx_post_fail)}, | ||
65 | {DRVSTAT_INFO(be_802_3_dropped_frames)}, | ||
66 | {DRVSTAT_INFO(be_802_3_malformed_frames)}, | ||
67 | {DRVSTAT_INFO(be_tx_rate)}, | ||
68 | {DRVSTAT_INFO(be_rx_rate)}, | ||
69 | {PORTSTAT_INFO(rx_unicast_frames)}, | 62 | {PORTSTAT_INFO(rx_unicast_frames)}, |
70 | {PORTSTAT_INFO(rx_multicast_frames)}, | 63 | {PORTSTAT_INFO(rx_multicast_frames)}, |
71 | {PORTSTAT_INFO(rx_broadcast_frames)}, | 64 | {PORTSTAT_INFO(rx_broadcast_frames)}, |
@@ -106,11 +99,24 @@ static const struct be_ethtool_stat et_stats[] = { | |||
106 | {MISCSTAT_INFO(rx_drops_too_many_frags)}, | 99 | {MISCSTAT_INFO(rx_drops_too_many_frags)}, |
107 | {MISCSTAT_INFO(rx_drops_invalid_ring)}, | 100 | {MISCSTAT_INFO(rx_drops_invalid_ring)}, |
108 | {MISCSTAT_INFO(forwarded_packets)}, | 101 | {MISCSTAT_INFO(forwarded_packets)}, |
109 | {MISCSTAT_INFO(rx_drops_mtu)}, | 102 | {MISCSTAT_INFO(rx_drops_mtu)} |
110 | {ERXSTAT_INFO(rx_drops_no_fragments)}, | ||
111 | }; | 103 | }; |
112 | #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) | 104 | #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) |
113 | 105 | ||
106 | /* Stats related to multi RX queues */ | ||
107 | static const struct be_ethtool_stat et_rx_stats[] = { | ||
108 | {DRVSTAT_RX_INFO(rx_bytes)}, | ||
109 | {DRVSTAT_RX_INFO(rx_pkts)}, | ||
110 | {DRVSTAT_RX_INFO(rx_rate)}, | ||
111 | {DRVSTAT_RX_INFO(rx_polls)}, | ||
112 | {DRVSTAT_RX_INFO(rx_events)}, | ||
113 | {DRVSTAT_RX_INFO(rx_compl)}, | ||
114 | {DRVSTAT_RX_INFO(rx_mcast_pkts)}, | ||
115 | {DRVSTAT_RX_INFO(rx_post_fail)}, | ||
116 | {ERXSTAT_INFO(rx_drops_no_fragments)} | ||
117 | }; | ||
118 | #define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats)) | ||
119 | |||
114 | static const char et_self_tests[][ETH_GSTRING_LEN] = { | 120 | static const char et_self_tests[][ETH_GSTRING_LEN] = { |
115 | "MAC Loopback test", | 121 | "MAC Loopback test", |
116 | "PHY Loopback test", | 122 | "PHY Loopback test", |
@@ -143,7 +149,7 @@ static int | |||
143 | be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) | 149 | be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) |
144 | { | 150 | { |
145 | struct be_adapter *adapter = netdev_priv(netdev); | 151 | struct be_adapter *adapter = netdev_priv(netdev); |
146 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | 152 | struct be_eq_obj *rx_eq = &adapter->rx_obj[0].rx_eq; |
147 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | 153 | struct be_eq_obj *tx_eq = &adapter->tx_eq; |
148 | 154 | ||
149 | coalesce->rx_coalesce_usecs = rx_eq->cur_eqd; | 155 | coalesce->rx_coalesce_usecs = rx_eq->cur_eqd; |
@@ -167,25 +173,49 @@ static int | |||
167 | be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) | 173 | be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) |
168 | { | 174 | { |
169 | struct be_adapter *adapter = netdev_priv(netdev); | 175 | struct be_adapter *adapter = netdev_priv(netdev); |
170 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | 176 | struct be_rx_obj *rxo; |
177 | struct be_eq_obj *rx_eq; | ||
171 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | 178 | struct be_eq_obj *tx_eq = &adapter->tx_eq; |
172 | u32 tx_max, tx_min, tx_cur; | 179 | u32 tx_max, tx_min, tx_cur; |
173 | u32 rx_max, rx_min, rx_cur; | 180 | u32 rx_max, rx_min, rx_cur; |
174 | int status = 0; | 181 | int status = 0, i; |
175 | 182 | ||
176 | if (coalesce->use_adaptive_tx_coalesce == 1) | 183 | if (coalesce->use_adaptive_tx_coalesce == 1) |
177 | return -EINVAL; | 184 | return -EINVAL; |
178 | 185 | ||
179 | /* if AIC is being turned on now, start with an EQD of 0 */ | 186 | for_all_rx_queues(adapter, rxo, i) { |
180 | if (rx_eq->enable_aic == 0 && | 187 | rx_eq = &rxo->rx_eq; |
181 | coalesce->use_adaptive_rx_coalesce == 1) { | 188 | |
182 | rx_eq->cur_eqd = 0; | 189 | if (!rx_eq->enable_aic && coalesce->use_adaptive_rx_coalesce) |
190 | rx_eq->cur_eqd = 0; | ||
191 | rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce; | ||
192 | |||
193 | rx_max = coalesce->rx_coalesce_usecs_high; | ||
194 | rx_min = coalesce->rx_coalesce_usecs_low; | ||
195 | rx_cur = coalesce->rx_coalesce_usecs; | ||
196 | |||
197 | if (rx_eq->enable_aic) { | ||
198 | if (rx_max > BE_MAX_EQD) | ||
199 | rx_max = BE_MAX_EQD; | ||
200 | if (rx_min > rx_max) | ||
201 | rx_min = rx_max; | ||
202 | rx_eq->max_eqd = rx_max; | ||
203 | rx_eq->min_eqd = rx_min; | ||
204 | if (rx_eq->cur_eqd > rx_max) | ||
205 | rx_eq->cur_eqd = rx_max; | ||
206 | if (rx_eq->cur_eqd < rx_min) | ||
207 | rx_eq->cur_eqd = rx_min; | ||
208 | } else { | ||
209 | if (rx_cur > BE_MAX_EQD) | ||
210 | rx_cur = BE_MAX_EQD; | ||
211 | if (rx_eq->cur_eqd != rx_cur) { | ||
212 | status = be_cmd_modify_eqd(adapter, rx_eq->q.id, | ||
213 | rx_cur); | ||
214 | if (!status) | ||
215 | rx_eq->cur_eqd = rx_cur; | ||
216 | } | ||
217 | } | ||
183 | } | 218 | } |
184 | rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce; | ||
185 | |||
186 | rx_max = coalesce->rx_coalesce_usecs_high; | ||
187 | rx_min = coalesce->rx_coalesce_usecs_low; | ||
188 | rx_cur = coalesce->rx_coalesce_usecs; | ||
189 | 219 | ||
190 | tx_max = coalesce->tx_coalesce_usecs_high; | 220 | tx_max = coalesce->tx_coalesce_usecs_high; |
191 | tx_min = coalesce->tx_coalesce_usecs_low; | 221 | tx_min = coalesce->tx_coalesce_usecs_low; |
@@ -199,27 +229,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) | |||
199 | tx_eq->cur_eqd = tx_cur; | 229 | tx_eq->cur_eqd = tx_cur; |
200 | } | 230 | } |
201 | 231 | ||
202 | if (rx_eq->enable_aic) { | ||
203 | if (rx_max > BE_MAX_EQD) | ||
204 | rx_max = BE_MAX_EQD; | ||
205 | if (rx_min > rx_max) | ||
206 | rx_min = rx_max; | ||
207 | rx_eq->max_eqd = rx_max; | ||
208 | rx_eq->min_eqd = rx_min; | ||
209 | if (rx_eq->cur_eqd > rx_max) | ||
210 | rx_eq->cur_eqd = rx_max; | ||
211 | if (rx_eq->cur_eqd < rx_min) | ||
212 | rx_eq->cur_eqd = rx_min; | ||
213 | } else { | ||
214 | if (rx_cur > BE_MAX_EQD) | ||
215 | rx_cur = BE_MAX_EQD; | ||
216 | if (rx_eq->cur_eqd != rx_cur) { | ||
217 | status = be_cmd_modify_eqd(adapter, rx_eq->q.id, | ||
218 | rx_cur); | ||
219 | if (!status) | ||
220 | rx_eq->cur_eqd = rx_cur; | ||
221 | } | ||
222 | } | ||
223 | return 0; | 232 | return 0; |
224 | } | 233 | } |
225 | 234 | ||
@@ -247,32 +256,25 @@ be_get_ethtool_stats(struct net_device *netdev, | |||
247 | struct ethtool_stats *stats, uint64_t *data) | 256 | struct ethtool_stats *stats, uint64_t *data) |
248 | { | 257 | { |
249 | struct be_adapter *adapter = netdev_priv(netdev); | 258 | struct be_adapter *adapter = netdev_priv(netdev); |
250 | struct be_drvr_stats *drvr_stats = &adapter->stats.drvr_stats; | 259 | struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va); |
251 | struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va); | ||
252 | struct be_rxf_stats *rxf_stats = &hw_stats->rxf; | ||
253 | struct be_port_rxf_stats *port_stats = | ||
254 | &rxf_stats->port[adapter->port_num]; | ||
255 | struct net_device_stats *net_stats = &netdev->stats; | ||
256 | struct be_erx_stats *erx_stats = &hw_stats->erx; | 260 | struct be_erx_stats *erx_stats = &hw_stats->erx; |
261 | struct be_rx_obj *rxo; | ||
257 | void *p = NULL; | 262 | void *p = NULL; |
258 | int i; | 263 | int i, j; |
259 | 264 | ||
260 | for (i = 0; i < ETHTOOL_STATS_NUM; i++) { | 265 | for (i = 0; i < ETHTOOL_STATS_NUM; i++) { |
261 | switch (et_stats[i].type) { | 266 | switch (et_stats[i].type) { |
262 | case NETSTAT: | 267 | case NETSTAT: |
263 | p = net_stats; | 268 | p = &netdev->stats; |
264 | break; | 269 | break; |
265 | case DRVSTAT: | 270 | case DRVSTAT_TX: |
266 | p = drvr_stats; | 271 | p = &adapter->tx_stats; |
267 | break; | 272 | break; |
268 | case PORTSTAT: | 273 | case PORTSTAT: |
269 | p = port_stats; | 274 | p = &hw_stats->rxf.port[adapter->port_num]; |
270 | break; | 275 | break; |
271 | case MISCSTAT: | 276 | case MISCSTAT: |
272 | p = rxf_stats; | 277 | p = &hw_stats->rxf; |
273 | break; | ||
274 | case ERXSTAT: /* Currently only one ERX stat is provided */ | ||
275 | p = (u32 *)erx_stats + adapter->rx_obj.q.id; | ||
276 | break; | 278 | break; |
277 | } | 279 | } |
278 | 280 | ||
@@ -280,19 +282,44 @@ be_get_ethtool_stats(struct net_device *netdev, | |||
280 | data[i] = (et_stats[i].size == sizeof(u64)) ? | 282 | data[i] = (et_stats[i].size == sizeof(u64)) ? |
281 | *(u64 *)p: *(u32 *)p; | 283 | *(u64 *)p: *(u32 *)p; |
282 | } | 284 | } |
285 | |||
286 | for_all_rx_queues(adapter, rxo, j) { | ||
287 | for (i = 0; i < ETHTOOL_RXSTATS_NUM; i++) { | ||
288 | switch (et_rx_stats[i].type) { | ||
289 | case DRVSTAT_RX: | ||
290 | p = (u8 *)&rxo->stats + et_rx_stats[i].offset; | ||
291 | break; | ||
292 | case ERXSTAT: | ||
293 | p = (u32 *)erx_stats + rxo->q.id; | ||
294 | break; | ||
295 | } | ||
296 | data[ETHTOOL_STATS_NUM + j * ETHTOOL_RXSTATS_NUM + i] = | ||
297 | (et_rx_stats[i].size == sizeof(u64)) ? | ||
298 | *(u64 *)p: *(u32 *)p; | ||
299 | } | ||
300 | } | ||
283 | } | 301 | } |
284 | 302 | ||
285 | static void | 303 | static void |
286 | be_get_stat_strings(struct net_device *netdev, uint32_t stringset, | 304 | be_get_stat_strings(struct net_device *netdev, uint32_t stringset, |
287 | uint8_t *data) | 305 | uint8_t *data) |
288 | { | 306 | { |
289 | int i; | 307 | struct be_adapter *adapter = netdev_priv(netdev); |
308 | int i, j; | ||
309 | |||
290 | switch (stringset) { | 310 | switch (stringset) { |
291 | case ETH_SS_STATS: | 311 | case ETH_SS_STATS: |
292 | for (i = 0; i < ETHTOOL_STATS_NUM; i++) { | 312 | for (i = 0; i < ETHTOOL_STATS_NUM; i++) { |
293 | memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN); | 313 | memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN); |
294 | data += ETH_GSTRING_LEN; | 314 | data += ETH_GSTRING_LEN; |
295 | } | 315 | } |
316 | for (i = 0; i < adapter->num_rx_qs; i++) { | ||
317 | for (j = 0; j < ETHTOOL_RXSTATS_NUM; j++) { | ||
318 | sprintf(data, "rxq%d: %s", i, | ||
319 | et_rx_stats[j].desc); | ||
320 | data += ETH_GSTRING_LEN; | ||
321 | } | ||
322 | } | ||
296 | break; | 323 | break; |
297 | case ETH_SS_TEST: | 324 | case ETH_SS_TEST: |
298 | for (i = 0; i < ETHTOOL_TESTS_NUM; i++) { | 325 | for (i = 0; i < ETHTOOL_TESTS_NUM; i++) { |
@@ -305,11 +332,14 @@ be_get_stat_strings(struct net_device *netdev, uint32_t stringset, | |||
305 | 332 | ||
306 | static int be_get_sset_count(struct net_device *netdev, int stringset) | 333 | static int be_get_sset_count(struct net_device *netdev, int stringset) |
307 | { | 334 | { |
335 | struct be_adapter *adapter = netdev_priv(netdev); | ||
336 | |||
308 | switch (stringset) { | 337 | switch (stringset) { |
309 | case ETH_SS_TEST: | 338 | case ETH_SS_TEST: |
310 | return ETHTOOL_TESTS_NUM; | 339 | return ETHTOOL_TESTS_NUM; |
311 | case ETH_SS_STATS: | 340 | case ETH_SS_STATS: |
312 | return ETHTOOL_STATS_NUM; | 341 | return ETHTOOL_STATS_NUM + |
342 | adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM; | ||
313 | default: | 343 | default: |
314 | return -EINVAL; | 344 | return -EINVAL; |
315 | } | 345 | } |
@@ -424,10 +454,10 @@ be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) | |||
424 | { | 454 | { |
425 | struct be_adapter *adapter = netdev_priv(netdev); | 455 | struct be_adapter *adapter = netdev_priv(netdev); |
426 | 456 | ||
427 | ring->rx_max_pending = adapter->rx_obj.q.len; | 457 | ring->rx_max_pending = adapter->rx_obj[0].q.len; |
428 | ring->tx_max_pending = adapter->tx_obj.q.len; | 458 | ring->tx_max_pending = adapter->tx_obj.q.len; |
429 | 459 | ||
430 | ring->rx_pending = atomic_read(&adapter->rx_obj.q.used); | 460 | ring->rx_pending = atomic_read(&adapter->rx_obj[0].q.used); |
431 | ring->tx_pending = atomic_read(&adapter->tx_obj.q.used); | 461 | ring->tx_pending = atomic_read(&adapter->tx_obj.q.used); |
432 | } | 462 | } |
433 | 463 | ||